use crate::SisoFirFilter;
use crunchy::unroll;
use num_traits::{MulAdd, Num};
pub fn polynomial_fractional_delay_taps<
const ORDER: usize,
T: Num + From<u8> + Copy + MulAdd<Output = T>,
>(
delay: T,
) -> [T; ORDER] {
let mut taps = [T::zero(); ORDER];
const {
assert!(
ORDER <= 10,
"Polynomial fractional delay filter not supported for order > 10"
);
assert!(
ORDER >= 2,
"Fractional delay filter order less than 2 is meaningless"
);
}
unroll! {
for k < 11 in 0..ORDER {
let mut coeff = T::one();
let kv = T::from(k as u8);
unroll! {
for m < 11 in 0..ORDER {
let mv = T::from(m as u8);
if m != k {
coeff = coeff * (delay - mv) / (kv - mv);
}
}
}
taps[k] = coeff;
}
}
let tapsum = taps.iter().fold(T::zero(), |acc, &x| acc + x);
taps.iter_mut().for_each(|x| *x = *x / tapsum);
taps.reverse();
taps
}
pub fn polynomial_fractional_delay<
const ORDER: usize,
T: Num + From<u8> + Copy + MulAdd<Output = T>,
>(
delay: T,
) -> SisoFirFilter<ORDER, T> {
let taps: [T; ORDER] = polynomial_fractional_delay_taps(delay);
SisoFirFilter::new(&taps)
}
#[cfg(test)]
mod test {
use super::polynomial_fractional_delay;
#[test]
fn test_polynomial_fractional_delay_filter() {
let vals = [1.0_f32, 1.0, 1.0, 1.0];
let mut filter: crate::SisoFirFilter<2, f32> = polynomial_fractional_delay(0.5);
vals.iter().for_each(|v| {
filter.update(*v);
});
assert_eq!(filter.y(), 1.0);
let vals = [4.0_f32, 3.0, 2.0, 1.0];
let mut filter: crate::SisoFirFilter<2, f32> = polynomial_fractional_delay(0.5);
vals.iter().for_each(|v| {
filter.update(*v);
});
assert_eq!(filter.y(), 1.5);
let mut filter: crate::SisoFirFilter<3, f32> = polynomial_fractional_delay(0.5);
vals.iter().for_each(|v| {
filter.update(*v);
});
assert_eq!(filter.y(), 1.5);
let mut filter: crate::SisoFirFilter<4, f32> = polynomial_fractional_delay(0.5);
vals.iter().for_each(|v| {
filter.update(*v);
});
assert_eq!(filter.y(), 1.5);
let func = |x: f32| 0.3 + 0.18 * x - 0.5 * x.powf(2.0) + 0.7 * x.powf(3.0);
let vals = [func(0.0), func(1.0), func(2.0), func(3.0)];
let mut filter: crate::SisoFirFilter<4, f32> = polynomial_fractional_delay(0.2);
vals.iter().for_each(|v| {
filter.update(*v);
});
let err = (filter.y() - func(2.8)).abs();
assert!(err < 1e-6);
}
}