Skip to main content

rustradio/
iir_filter.rs

1//! Infinite impulse response filter.
2//!
3//! This module doesn't contain any blocks. It only has the IIR specific code.
4//! Although when an IIR filter block is written, this module is likely where
5//! it'll end up.
6//!
7//! For blocks, see [`SinglePoleIirFilter`](crate::blocks::SinglePoleIirFilter).
8use std::collections::VecDeque;
9
10use crate::{Float, Sample};
11
12/// Ability to call `.clamp()`.
13///
14/// Needed for `ClampedFilter`.
15pub trait Clamp {
16    /// Return clamped value.
17    #[must_use]
18    fn clamp(&self, mi: Self, mx: Self) -> Self;
19}
20impl Clamp for Float {
21    fn clamp(&self, mi: Float, mx: Float) -> Self {
22        Float::clamp(*self as Float, mi, mx)
23    }
24}
25
26/// General IIR filter.
27///
28/// TODO: also add `filter_n`?
29pub trait Filter<T: Sample>: Send {
30    /// Filter from one input sample.
31    fn filter(&mut self, input: T) -> T;
32
33    /// Fill filter history with the given value.
34    fn fill(&mut self, s: T);
35}
36
37/// A `ClampedFilter` is like a regular filter, but clamps the output value to be
38/// between the minimum and the maximum.
39///
40/// TODO: also add `filter_n`?
41pub trait ClampedFilter<T: Sample + Clamp>: Filter<T> {
42    /// Filter from one input sample, but with clamped output.
43    fn filter_clamped(&mut self, input: T, mi: T, mx: T) -> T;
44}
45
46/// Finite impulse response filter.
47///
48/// An IIR filter is like a FIR but feeds back the output, meaning while
49/// intended to dampen, it never full loses its "history". Hence "infinite".
50///
51/// IIR filters are a bit more complicated than FIR filters, but can also be
52/// more efficient.
53///
54/// For more info see <https://en.wikipedia.org/wiki/Infinite_impulse_response>.
55pub struct IirFilter<T: Sample> {
56    taps: Vec<T>,
57    buf: VecDeque<T>,
58}
59
60impl<T> IirFilter<T>
61where
62    T: Sample + std::ops::Mul<T, Output = T> + std::ops::Add<T, Output = T>,
63{
64    /// Create new IIR from the provided taps.
65    pub fn new(taps: &[T]) -> Self {
66        Self {
67            taps: taps.to_vec(),
68            buf: VecDeque::new(),
69        }
70    }
71}
72
73impl<T> Filter<T> for IirFilter<T>
74where
75    T: Sample
76        + std::ops::Mul<T, Output = T>
77        + std::ops::Add<T, Output = T>
78        + Send
79        + std::fmt::Debug,
80{
81    fn filter(&mut self, sample: T) -> T {
82        let mut ret = self.taps[0] * sample;
83        for (i, s) in self.buf.iter().rev().enumerate() {
84            ret = ret + *s * self.taps[i + 1];
85        }
86        self.buf.push_back(ret);
87        if self.buf.len() == self.taps.len() {
88            self.buf.pop_front();
89        }
90        ret
91    }
92
93    fn fill(&mut self, s: T) {
94        for _ in 0..(self.taps.len() - 1) {
95            self.buf.push_back(s);
96        }
97    }
98}
99
100impl<T> ClampedFilter<T> for IirFilter<T>
101where
102    T: Sample
103        + std::ops::Mul<T, Output = T>
104        + std::ops::Add<T, Output = T>
105        + Clamp
106        + Send
107        + std::fmt::Debug,
108{
109    fn filter_clamped(&mut self, sample: T, mi: T, mx: T) -> T {
110        let mut ret = self.taps[0] * sample;
111        for (i, s) in self.buf.iter().rev().enumerate() {
112            ret = ret + *s * self.taps[i + 1];
113        }
114        ret = ret.clamp(mi, mx);
115        self.buf.push_back(ret);
116        if self.buf.len() == self.taps.len() {
117            self.buf.pop_front();
118        }
119        ret
120    }
121}
122
123#[cfg(test)]
124#[cfg_attr(coverage_nightly, coverage(off))]
125mod tests {
126    use super::*;
127    use crate::Result;
128
129    #[test]
130    fn zero_pole() -> Result<()> {
131        let mut f = IirFilter::new(&[1.0]);
132        assert_eq!(f.filter(123.0), 123.0);
133        assert_eq!(f.filter(123.0), 123.0);
134        let mut f = IirFilter::new(&[-0.5]);
135        assert_eq!(f.filter(402.0), -201.0);
136        assert_eq!(f.filter(402.0), -201.0);
137        Ok(())
138    }
139
140    #[test]
141    fn single_pole() -> Result<()> {
142        let mut f = IirFilter::new(&[1.0, 0.0]);
143        assert_eq!(f.filter(10.0), 10.0);
144        assert_eq!(f.filter(10.0), 10.0);
145        assert_eq!(f.filter(10.0), 10.0);
146
147        let mut f = IirFilter::new(&[0.9f32, 0.1]);
148        assert_eq!(f.filter(100.0), 90.0);
149        assert_eq!(f.filter(100.0), 99.0);
150        assert_eq!(f.filter(100.0), 99.9);
151        assert!((f.filter(100.0) - 99.99).abs() < 0.00001);
152
153        Ok(())
154    }
155
156    #[test]
157    fn single_pole_clamped() -> Result<()> {
158        let mut f = IirFilter::new(&[1.0, 0.0]);
159        assert_eq!(f.filter_clamped(10.0, 0.0, 1.0), 1.0);
160        assert_eq!(f.filter_clamped(10.0, 0.0, 1.0), 1.0);
161        assert_eq!(f.filter_clamped(10.0, 0.0, 1.0), 1.0);
162
163        Ok(())
164    }
165
166    #[test]
167    fn multi_pole() -> Result<()> {
168        let mut f = IirFilter::new(&[1.0, 0.0, 0.0]);
169        assert_eq!(f.filter(10.0), 10.0);
170        assert_eq!(f.filter(10.0), 10.0);
171        assert_eq!(f.filter(10.0), 10.0);
172        assert_eq!(f.filter(10.0), 10.0);
173
174        let mut f = IirFilter::new(&[1.0f32, 0.9, 0.1]);
175        assert_eq!(f.filter(100.0), 100.0);
176        assert_eq!(f.filter(100.0), 190.0);
177        assert_eq!(f.filter(100.0), 281.0);
178        assert_eq!(f.filter(100.0), 371.9);
179
180        Ok(())
181    }
182
183    #[test]
184    fn filled() -> Result<()> {
185        let mut f = IirFilter::new(&[1.0f32, 0.9, 0.1]);
186        f.fill(100.0);
187        assert_eq!(f.filter(100.0), 200.0);
188        assert_eq!(f.filter(100.0), 290.0);
189        assert_eq!(f.filter(200.0), 481.0);
190        Ok(())
191    }
192}