1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(feature = "std"), no_std)]
3pub mod fir;
4pub mod fractional_delay;
5pub mod iir;
6pub mod median;
7pub mod sos;
8
9use core::ops::{Index, IndexMut};
10use crunchy::unroll;
11pub use fir::SisoFirFilter;
12pub use fractional_delay::polynomial_fractional_delay;
13pub use iir::SisoIirFilter;
14pub use median::MedianFilter;
15pub use sos::SisoSosFilter;
16
17pub mod generated;
18pub use generated::butter::butter1::butter1;
19pub use generated::butter::butter2::butter2;
20pub use generated::butter::butter3::butter3;
21pub use generated::butter::butter4::butter4;
22pub use generated::butter::butter5::butter5;
23pub use generated::butter::butter6::butter6;
24
25use num_traits::{MulAdd, Num};
26
27#[derive(Clone, Copy, Debug)]
30#[repr(align(8))]
31pub struct AlignedArray<T, const N: usize>([T; N]);
32
33impl<T: Copy + Num, const N: usize> Default for AlignedArray<T, N> {
34 fn default() -> Self {
35 Self([T::zero(); N])
36 }
37}
38
39impl<T: Copy + Num + MulAdd<Output = T>, const N: usize> AlignedArray<T, N> {
40 #[inline]
45 pub fn dot(&self, buf: &Ring<T, N>, start: T) -> T {
46 const { assert!(N < 129, "N > 128 not supported") }
47
48 let other = buf.buf();
53 let mut acc = start;
54
55 #[cfg(not(feature = "fma"))]
56 unroll! {
57 for i < 128 in 0..N {
58 acc = acc + self.0[i] * other[i];
59 }
60 }
61
62 #[cfg(feature = "fma")]
63 unroll! {
64 for i < 128 in 0..N {
65 acc = self.0[i].mul_add(other[i], acc);
66 }
67 }
68
69 acc
70 }
71}
72
73impl<T, const N: usize> Index<usize> for AlignedArray<T, N> {
74 type Output = T;
75 #[inline]
76 fn index(&self, idx: usize) -> &Self::Output {
77 &self.0[idx]
78 }
79}
80
81impl<T, const N: usize> IndexMut<usize> for AlignedArray<T, N> {
82 #[inline]
83 fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
84 &mut self.0[idx]
85 }
86}
87
88#[derive(Clone, Copy, Default, Debug)]
91#[repr(transparent)]
92pub struct Ring<T: Num + Copy, const N: usize> {
93 buf: AlignedArray<T, N>,
94}
95
96impl<T: Num + Copy, const N: usize> Ring<T, N> {
97 pub fn new(value: T) -> Self {
99 Self {
100 buf: AlignedArray([value; N]),
101 }
102 }
103
104 pub fn push(&mut self, value: T) {
110 unroll! {
111 for i < 128 in 0..(N-1) {
112 self.buf.0[i] = self.buf.0[i + 1];
113 }
114 }
115 self.buf.0[N - 1] = value;
116 }
117
118 fn buf(&self) -> &[T; N] {
120 &self.buf.0
121 }
122}
123
124#[cfg(test)]
129#[cfg(not(feature = "std"))]
130mod test {
131 #[test]
132 fn require_std_for_tests() {
133 panic!("`std` feature is required for tests")
134 }
135}
136
137#[cfg(feature = "std")]
138#[cfg(test)]
139mod test {
140 #[test]
142 fn test_initialize() {
143 let e = core::f64::consts::E as f32;
144 let mut f = super::butter2(0.2).unwrap();
145 f.set_steady_state(e);
146 assert!((e - f.update(e)).abs() / e < 1e-6);
147 }
148}