cic_fixed/
lib.rs

1//! # cic-fixed
2//!
3//! A CIC filter implementation for fixed point numbers.  
4//! Implemented for use in converting PDM to PCM.  
5//!
6//! ## Example
7//!
8//! ```rust
9//! use cic_fixed::CicDecimationFilter;
10//!
11//! let mut filter = CicDecimationFilter::<4, 2>::new();
12//! let result = filter.process_sample(&0);
13//! assert!(result.is_none());
14//! let result = filter.process_sample(&1);
15//! assert!(result.is_none());
16//! let result = filter.process_sample(&2);
17//! assert!(result.is_none());
18//! let result = filter.process_sample(&3);
19//! assert!(result.is_some());
20//! assert_eq!(result.unwrap(), 10);
21//! ```
22//!
23#![cfg_attr(not(test), no_std)]
24
25mod decimator;
26mod differentiator;
27mod integrator;
28
29/// CIC decimation filter.  
30/// - `M` - Decimation factor  
31/// - `N` - Number of stages  
32pub struct CicDecimationFilter<const M: usize, const N: usize> {
33    decimator: decimator::Decimator<M>,
34    integrators: [integrator::Integrator; N],
35    differentiators: [differentiator::Differentiator; N],
36}
37
38impl<const M: usize, const N: usize> CicDecimationFilter<M, N> {
39    pub const fn new() -> Self {
40        assert!(M > 0, "M (decimation factor) must be greater than 0. Without decimation, the CIC filter does not perform as an LPF.");
41        assert!(N > 0, "N (number of stages) must be greater than 0");
42
43        Self {
44            decimator: decimator::Decimator::new(),
45            integrators: [integrator::Integrator::new(); N],
46            differentiators: [differentiator::Differentiator::new(); N],
47        }
48    }
49
50    /// Process the input and return the output when the decimator is ready to output a value.     
51    ///
52    /// # Arguments
53    ///
54    /// * `input` - The input to filter.
55    ///
56    /// # Returns
57    ///
58    /// The output of the filter.  
59    /// The output range is Input range * (M^N). For example, if Input range is +/-1, M is 4, and N is 2, the output range is +/-16.  
60    /// When the decimator is ready to output a value, it will return some(input). Otherwise, it will return None.      
61    #[inline]
62    #[must_use]
63    pub fn process_sample(&mut self, input: &i32) -> Option<i32> {
64        let mut output = *input;
65        for integrator in self.integrators.iter_mut() {
66            output = integrator.integrate(output);
67        }
68
69        if let Some(output) = self.decimator.decimate(output) {
70            let mut v = output;
71            for differentiator in self.differentiators.iter_mut() {
72                v = differentiator.differentiate(v);
73            }
74            Some(v)
75        } else {
76            None
77        }
78    }
79
80    /// Returns the number of bits increased by passing through the CIC decimation filter.  
81    /// The bit increase by the CIC decimation filter can be expressed by the following equation.  
82    /// log2(M)*N  
83    /// M is the decimation factor and N is the number of stages.  
84    #[must_use]
85    pub const fn bit_growth(&self) -> u32 {
86        M.ilog2() * N as u32
87    }
88}
89
90impl<const M: usize, const N: usize> Default for CicDecimationFilter<M, N> {
91    fn default() -> Self {
92        Self::new()
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn cic_decimation_test() {
102        let mut filter = CicDecimationFilter::<4, 2>::new();
103        let result = filter.process_sample(&0);
104        assert!(result.is_none());
105        let result = filter.process_sample(&1);
106        assert!(result.is_none());
107        let result = filter.process_sample(&2);
108        assert!(result.is_none());
109        let result = filter.process_sample(&3);
110        assert!(result.is_some());
111        assert_eq!(result.unwrap(), 10);
112
113        let result = filter.process_sample(&2);
114        assert!(result.is_none());
115        let result = filter.process_sample(&-1);
116        assert!(result.is_none());
117        let result = filter.process_sample(&-2);
118        assert!(result.is_none());
119        let result = filter.process_sample(&1);
120        assert!(result.is_some());
121        assert_eq!(result.unwrap(), 16);
122
123        let result = filter.process_sample(&2);
124        assert!(result.is_none());
125        let result = filter.process_sample(&-1);
126        assert!(result.is_none());
127        let result = filter.process_sample(&-2);
128        assert!(result.is_none());
129        let result = filter.process_sample(&1);
130        assert!(result.is_some());
131        assert_eq!(result.unwrap(), 0);
132
133        let result = filter.process_sample(&2);
134        assert!(result.is_none());
135        let result = filter.process_sample(&-1);
136        assert!(result.is_none());
137        let result = filter.process_sample(&-2);
138        assert!(result.is_none());
139        let result = filter.process_sample(&1);
140        assert!(result.is_some());
141        assert_eq!(result.unwrap(), 0);
142
143        let result = filter.process_sample(&0);
144        assert!(result.is_none());
145        let result = filter.process_sample(&1);
146        assert!(result.is_none());
147        let result = filter.process_sample(&2);
148        assert!(result.is_none());
149        let result = filter.process_sample(&3);
150        assert!(result.is_some());
151        assert_eq!(result.unwrap(), 8);
152
153        let result = filter.process_sample(&3);
154        assert!(result.is_none());
155        let result = filter.process_sample(&3);
156        assert!(result.is_none());
157        let result = filter.process_sample(&-2);
158        assert!(result.is_none());
159        let result = filter.process_sample(&1);
160        assert!(result.is_some());
161        assert_eq!(result.unwrap(), 32);
162    }
163
164    #[test]
165    fn overflow_test() {
166        let mut filter = CicDecimationFilter::<4, 2>::new();
167
168        for _ in 0..1000 {
169            let _ = filter.process_sample(&i32::MAX);
170        }
171    }
172
173    // 出力範囲のテスト
174    // CICフィルターはMが4, Nが2とする。
175    // 最大出力はM^N = 4^2 = 16倍される。
176    // 入力範囲が-1~1の場合、出力範囲は-16~16
177    #[test]
178    fn output_range_test() {
179        let mut filter = CicDecimationFilter::<4, 2>::new();
180
181        for _ in 0..1000 {
182            let _result = filter.process_sample(&1);
183        }
184
185        for _ in 0..10 {
186            if let Some(output) = filter.process_sample(&1) {
187                println!("{}", output);
188                assert!(output == 16); //4^2
189            }
190        }
191
192        for _ in 0..1000 {
193            let _result = filter.process_sample(&-1);
194        }
195
196        for _ in 0..10 {
197            if let Some(output) = filter.process_sample(&-1) {
198                println!("{}", output);
199                assert!(output == -16); //4^2
200            }
201        }
202    }
203
204    #[test]
205    fn bit_growth_test() {
206        let filter = CicDecimationFilter::<64, 3>::new();
207        assert_eq!(filter.bit_growth(), 18);
208
209        let filter = CicDecimationFilter::<32, 5>::new();
210        assert_eq!(filter.bit_growth(), 25);
211
212        let filter = CicDecimationFilter::<8, 5>::new();
213        assert_eq!(filter.bit_growth(), 15);
214    }
215}