use std::collections::VecDeque;
use std::convert::AsRef;
use nalgebra::base::Scalar;
use nalgebra::DVector;
use num_traits::{One, Zero};
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq)]
pub struct FilterCoeff<T>(DVector<T>)
where
T: Copy + Scalar + One + Zero;
#[allow(dead_code)]
impl<T> FilterCoeff<T>
where
T: Copy + Scalar + One + Zero,
{
pub fn from_slice<S>(h: S) -> Self
where
S: AsRef<[T]>,
{
let inp = h.as_ref();
FilterCoeff(DVector::from_iterator(inp.len(), inp.iter().copied()))
}
pub fn from_identity(len: usize) -> Self {
let mut out = FilterCoeff(DVector::from_iterator(
len,
std::iter::repeat(T::zero()).take(len),
));
out.0[0] = T::one();
out
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn filter<W, In, Out>(&self, history: W) -> Out
where
W: IntoIterator<Item = In>,
W::IntoIter: DoubleEndedIterator,
In: Copy + Scalar + std::ops::Mul<T, Output = Out>,
Out: Copy + Scalar + Zero + std::ops::AddAssign,
{
multiply_accumulate(history, self.as_ref())
}
pub fn identity(&mut self) {
for coeff in self.0.iter_mut() {
*coeff = T::zero();
}
self.0[0] = T::one();
}
#[inline]
pub fn as_slice(&self) -> &[T] {
self.0.as_slice()
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
self.0.as_mut_slice()
}
#[inline]
pub fn inner(&self) -> &DVector<T> {
&self.0
}
#[inline]
pub fn inner_mut(&mut self) -> &mut DVector<T> {
&mut self.0
}
}
impl<T> AsRef<[T]> for FilterCoeff<T>
where
T: Copy + Scalar + One + Zero,
{
#[inline]
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> AsMut<[T]> for FilterCoeff<T>
where
T: Copy + Scalar + One + Zero,
{
#[inline]
fn as_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T> std::ops::Index<usize> for FilterCoeff<T>
where
T: Copy + Scalar + One + Zero,
{
type Output = T;
#[inline]
fn index(&self, ind: usize) -> &T {
self.0.index(ind)
}
}
impl<T> std::ops::IndexMut<usize> for FilterCoeff<T>
where
T: Copy + Scalar + One + Zero,
{
#[inline]
fn index_mut(&mut self, ind: usize) -> &mut T {
self.0.index_mut(ind)
}
}
#[derive(Clone, Debug)]
pub struct Window<T>(VecDeque<T>)
where
T: Copy + Scalar + Zero;
#[allow(dead_code)]
impl<T> Window<T>
where
T: Copy + Scalar + Zero,
{
pub fn new(len: usize) -> Self {
let mut q = VecDeque::with_capacity(len);
q.resize(len, T::zero());
Self(q)
}
pub fn reset(&mut self) {
for s in &mut self.0 {
*s = T::zero()
}
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn push<S>(&mut self, input: S)
where
S: AsRef<[T]>,
{
let input = input.as_ref();
let input = if input.len() > self.0.len() {
let start = input.len() - self.0.len();
&input[start..]
} else {
input
};
std::mem::drop(self.0.drain(0..input.len()));
self.0.extend(input.as_ref());
}
#[inline]
pub fn push_scalar(&mut self, input: T) -> T {
let out = self.0.pop_front().unwrap_or(T::zero());
self.0.push_back(input);
out
}
pub fn iter(&self) -> <&Window<T> as IntoIterator>::IntoIter {
self.into_iter()
}
pub fn to_vec(&self) -> Vec<T> {
self.iter().collect()
}
pub fn inner(&self) -> &VecDeque<T> {
&self.0
}
#[inline]
pub fn back(&self) -> T {
*self.0.back().unwrap()
}
#[inline]
pub fn front(&self) -> T {
*self.0.front().unwrap()
}
}
impl<'a, T> IntoIterator for &'a Window<T>
where
T: Copy + Scalar + Zero,
{
type Item = T;
type IntoIter = std::iter::Copied<std::collections::vec_deque::Iter<'a, T>>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter().copied()
}
}
fn multiply_accumulate<W, In, Coeff, Out>(history: W, coeff: &[Coeff]) -> Out
where
W: IntoIterator<Item = In>,
W::IntoIter: DoubleEndedIterator,
In: Copy + Scalar + std::ops::Mul<Coeff, Output = Out>,
Coeff: Copy + Scalar,
Out: Copy + Scalar + Zero + std::ops::AddAssign,
{
let history = history.into_iter();
let mut out = Out::zero();
for (hi, co) in history.rev().zip(coeff.iter()) {
out += hi * *co;
}
out
}
#[cfg(test)]
mod tests {
use super::*;
use assert_approx_eq::assert_approx_eq;
use num_complex::Complex;
#[test]
fn test_multiply_accumulate() {
let out = multiply_accumulate(&[0.0f32; 0], &[0.0f32; 0]);
assert_eq!(0.0f32, out);
let out = multiply_accumulate(&[20.0f32, 1.0f32], &[1.0f32]);
assert_eq!(1.0f32, out);
let out = multiply_accumulate(&[1.0f32], &[1.0f32, 20.0f32]);
assert_eq!(1.0f32, out);
let out = multiply_accumulate(&[20.0f32, 20.0f32], &[1.0f32, -1.0f32]);
assert_approx_eq!(0.0f32, out);
}
#[test]
fn test_filter_cplx() {
const INPUT: &[Complex<f32>] = &[Complex {
re: 0.5f32,
im: 0.5f32,
}];
let filter = FilterCoeff::from_slice(&[2.0f32, 0.0f32, 0.0f32]);
let out = filter.filter(INPUT);
assert_approx_eq!(out.re, 1.0f32);
assert_approx_eq!(out.im, 1.0f32);
}
#[test]
fn test_filter_identity() {
const EXPECT: &[f32] = &[1.0f32, 0.0f32, 0.0f32, 0.0f32];
let mut filter = FilterCoeff::<f32>::from_identity(4);
assert_eq!(EXPECT, filter.as_ref());
assert_eq!(10.0f32, filter.filter(&[10.0f32]));
filter[3] = 5.0f32;
filter.identity();
assert_eq!(EXPECT, filter.as_ref());
}
#[test]
fn test_window() {
let mut wind: Window<f32> = Window::new(4);
assert_eq!(4, wind.len());
assert_eq!(vec![0.0f32, 0.0f32, 0.0f32, 0.0f32], wind.to_vec());
wind.push(&[1.0f32]);
assert_eq!(vec![0.0f32, 0.0f32, 0.0f32, 1.0f32], wind.to_vec());
wind.push(&[]);
assert_eq!(vec![0.0f32, 0.0f32, 0.0f32, 1.0f32], wind.to_vec());
wind.push(&[2.0f32]);
assert_eq!(vec![0.0f32, 0.0f32, 1.0f32, 2.0f32], wind.to_vec());
wind.push(&[-1.0f32, -2.0f32, 1.0f32, 2.0f32, 3.0f32, 4.0f32]);
assert_eq!(vec![1.0f32, 2.0f32, 3.0f32, 4.0f32], wind.to_vec());
assert_eq!(4.0f32, wind.back());
assert_eq!(1.0f32, wind.front());
assert_eq!(4, wind.len());
assert_eq!(1.0f32, wind.push_scalar(10.0f32));
assert_eq!(4, wind.len());
assert_eq!(vec![2.0f32, 3.0f32, 4.0f32, 10.0f32], wind.to_vec());
wind.push(&[5.0f32, 4.0f32, 3.0f32, 2.0f32]);
assert_eq!(vec![5.0f32, 4.0f32, 3.0f32, 2.0f32], wind.to_vec());
wind.reset();
assert_eq!(4, wind.len());
assert_eq!(vec![0.0f32, 0.0f32, 0.0f32, 0.0f32], wind.to_vec());
}
}