#![feature(conservative_impl_trait)]
use std::ops::{Add, Mul, Deref, DerefMut};
pub trait FirCoefs: Default + Deref<Target = [<Self as FirCoefs>::Sample]> + DerefMut {
type Sample: Copy + Clone + Default + Add<Output = Self::Sample> +
Mul<f32, Output = Self::Sample>;
fn size() -> usize;
fn coefs() -> &'static [f32];
fn verify_symmetry() {
for i in 0..Self::size() / 2 {
assert_eq!(Self::coefs()[i], Self::coefs()[Self::size() - i - 1]);
}
}
}
#[macro_export]
macro_rules! impl_fir {
($name:ident, $sample:ty, $size:expr, $coefs:expr) => {
pub struct $name([$sample; $size]);
impl $crate::FirCoefs for $name {
type Sample = $sample;
fn size() -> usize { $size }
fn coefs() -> &'static [f32] {
static COEFS: [f32; $size] = $coefs;
&COEFS[..]
}
}
impl Default for $name {
fn default() -> Self {
$name([<Self as $crate::FirCoefs>::Sample::default(); $size])
}
}
impl std::ops::Deref for $name {
type Target = [$sample];
fn deref(&self) -> &Self::Target { &self.0[..] }
}
impl std::ops::DerefMut for $name {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0[..] }
}
};
}
pub struct FirFilter<C: FirCoefs> {
inner: C,
idx: usize,
}
impl<C: FirCoefs> FirFilter<C> {
pub fn new() -> FirFilter<C> {
FirFilter {
inner: C::default(),
idx: 0,
}
}
pub fn feed(&mut self, sample: C::Sample) -> C::Sample {
self.inner[self.idx] = sample;
self.idx += 1;
self.idx %= C::size();
self.calc()
}
fn calc(&self) -> C::Sample {
let (hleft, hright) = self.inner.split_at(self.idx);
let (cleft, cright) = C::coefs().split_at(C::size() - self.idx);
cleft.iter().zip(hright)
.fold(C::Sample::default(), |s, (&c, &x)| s + x * c) +
cright.iter().zip(hleft)
.fold(C::Sample::default(), |s, (&c, &x)| s + x * c)
}
#[inline]
pub fn history<'a>(&'a self) -> impl Iterator<Item = &'a C::Sample> {
let (left, right) = self.inner.split_at(self.idx);
right.iter().chain(left.iter())
}
pub fn history_unordered<'a>(&'a self) -> impl Iterator<Item = &'a C::Sample> {
self.inner.iter()
}
}
#[cfg(test)]
mod test {
use super::*;
impl_fir!(TestFIR, f32, 4, [
1.0,
0.0,
2.0,
0.0,
]);
impl_fir!(SymmetricOddFIR, f32, 5, [
0.2,
0.4,
1.0,
0.4,
0.2,
]);
impl_fir!(SymmetricEvenFIR, f32, 6, [
0.2,
0.4,
1.0,
1.0,
0.4,
0.2,
]);
impl_fir!(NonSymmetricOddFIR, f32, 5, [
0.2,
0.4,
1.0,
0.5,
0.2,
]);
impl_fir!(NonSymmetricEvenFIR, f32, 6, [
0.2,
0.4,
1.0,
1.0,
0.5,
0.2,
]);
#[test]
fn test_fir() {
let mut f = FirFilter::<TestFIR>::new();
assert!(f.feed(100.0) == 0.0);
assert!(f.feed(200.0) == 200.0);
assert!(f.feed(300.0) == 400.0);
assert!(f.feed(400.0) == 700.0);
assert!(f.feed(0.0) == 1000.0);
assert!(f.feed(0.0) == 300.0);
assert!(f.feed(0.0) == 400.0);
assert!(f.feed(0.0) == 0.0);
assert!(f.feed(0.0) == 0.0);
assert!(f.feed(100.0) == 0.0);
assert!(f.feed(200.0) == 200.0);
assert!(f.feed(300.0) == 400.0);
assert!(f.feed(400.0) == 700.0);
let mut iter = f.history();
assert_eq!(iter.next().unwrap(), &100.0);
assert_eq!(iter.next().unwrap(), &200.0);
assert_eq!(iter.next().unwrap(), &300.0);
assert_eq!(iter.next().unwrap(), &400.0);
let mut iter = f.history_unordered();
assert_eq!(iter.next().unwrap(), &400.0);
assert_eq!(iter.next().unwrap(), &100.0);
assert_eq!(iter.next().unwrap(), &200.0);
assert_eq!(iter.next().unwrap(), &300.0);
}
#[test]
fn test_verify_symmetry() {
SymmetricOddFIR::verify_symmetry();
SymmetricEvenFIR::verify_symmetry();
}
#[test]
#[should_panic]
fn test_verify_nonsymmetry_odd() {
NonSymmetricOddFIR::verify_symmetry();
}
#[test]
#[should_panic]
fn test_verify_nonsymmetry_even() {
NonSymmetricEvenFIR::verify_symmetry();
}
}