use interface::{Data, Read, UniqueIdentifier, Update, Write};
use std::collections::VecDeque;
use std::ops::{Mul, Sub};
#[derive(Debug, Clone)]
pub struct IIRFilter<T> {
b_coeffs: Vec<T>,
a_coeffs: Vec<T>,
filter_dim: usize,
x_history: Vec<VecDeque<T>>,
y_history: Vec<VecDeque<T>>,
}
impl<T: Default + Clone> IIRFilter<T> {
pub fn new(b_coeffs: Vec<T>, a_coeffs: Vec<T>, filter_dim: usize) -> Self {
let x_history = vec![VecDeque::from(vec![T::default(); b_coeffs.len()]); filter_dim];
let y_history = vec![VecDeque::from(vec![T::default(); a_coeffs.len()]); filter_dim];
Self {
b_coeffs,
a_coeffs,
filter_dim,
x_history,
y_history,
}
}
pub fn reset(&mut self) {
self.x_history
.iter_mut()
.flat_map(|queue| queue.iter_mut())
.chain(self.y_history.iter_mut().flat_map(|queue| queue.iter_mut()))
.for_each(|val| *val = T::default());
}
pub fn resize(&mut self, new_filter_dim: usize) {
if new_filter_dim == self.filter_dim {
return;
}
self.filter_dim = new_filter_dim;
self.x_history =
vec![VecDeque::from(vec![T::default(); self.b_coeffs.len()]); new_filter_dim];
self.y_history =
vec![VecDeque::from(vec![T::default(); self.a_coeffs.len()]); new_filter_dim];
}
}
impl<T> Update for IIRFilter<T>
where
T: Send + Sync + Sub<Output = T> + Mul<Output = T> + Copy + std::iter::Sum,
{
fn update(&mut self) {
for dim in 0..self.filter_dim {
let feed_forward = self
.b_coeffs
.iter()
.zip(self.x_history[dim].iter())
.map(|(&b, &x)| b * x)
.sum::<T>();
let feedback = self
.a_coeffs
.iter()
.zip(self.y_history[dim].iter())
.map(|(&a, &y)| a * y)
.sum::<T>();
let y_i = feed_forward - feedback;
self.y_history[dim].pop_back();
self.y_history[dim].push_front(y_i);
}
}
}
impl<T, U> Read<U> for IIRFilter<T>
where
T: Send + Sync + Sub<Output = T> + Mul<Output = T> + Copy + std::iter::Sum,
U: UniqueIdentifier<DataType = Vec<T>>,
{
fn read(&mut self, data: Data<U>) {
let x = data.into_arc();
assert_eq!(
x.len(),
self.filter_dim,
"gmt_dos-clients::IIR filter input size error:\nexpected {}, found {}!",
self.filter_dim,
x.len()
);
for dim in 0..self.filter_dim {
self.x_history[dim].pop_back();
self.x_history[dim].push_front(x[dim]);
}
}
}
impl<T, U> Write<U> for IIRFilter<T>
where
T: Copy + Send + Sync + Sub<Output = T> + Mul<Output = T> + std::iter::Sum,
U: UniqueIdentifier<DataType = Vec<T>>,
{
fn write(&mut self) -> Option<Data<U>> {
let y: Vec<T> = self.y_history.iter().map(|y| y[0]).collect();
Some(Data::new(y))
}
}