1use core::ops::AddAssign;
2
3use num_traits::{AsPrimitive, Num, Pow, WrappingAdd, WrappingSub};
4
5#[derive(Clone, Debug)]
9pub struct Cic<T, const N: usize> {
10 rate: u32,
14 index: u32,
16 zoh: T,
20 combs: [T; N],
22 integrators: [T; N],
24}
25
26impl<T, const N: usize> Cic<T, N>
27where
28 T: Num + AddAssign + WrappingAdd + WrappingSub + Pow<usize, Output = T> + Copy + 'static,
29 u32: AsPrimitive<T>,
30{
31 pub fn new(rate: u32) -> Self {
33 Self {
34 rate,
35 index: 0,
36 zoh: T::zero(),
37 combs: [T::zero(); N],
38 integrators: [T::zero(); N],
39 }
40 }
41
42 pub const fn order(&self) -> usize {
51 N
52 }
53
54 pub const fn rate(&self) -> u32 {
58 self.rate
59 }
60
61 pub fn set_rate(&mut self, rate: u32) {
65 self.rate = rate;
66 }
67
68 pub fn clear(&mut self) {
70 *self = Self::new(self.rate);
71 }
72
73 pub const fn tick(&self) -> bool {
78 self.index == 0
79 }
80
81 pub fn get_interpolate(&self) -> T {
83 self.integrators.last().copied().unwrap_or(self.zoh)
84 }
85
86 pub fn get_decimate(&self) -> T {
88 self.zoh
89 }
90
91 pub fn gain(&self) -> T {
93 (self.rate.as_() + T::one()).pow(N)
94 }
95
96 pub const fn gain_log2(&self) -> u32 {
101 (u32::BITS - self.rate.leading_zeros()) * N as u32
102 }
103
104 pub const fn response_length(&self) -> usize {
106 self.rate as usize * N
107 }
108
109 pub fn settle_interpolate(&mut self, x: T) {
111 self.clear();
112 if let Some(c) = self.combs.first_mut() {
113 *c = x;
114 } else {
115 self.zoh = x;
116 }
117 let g = self.gain();
118 if let Some(i) = self.integrators.last_mut() {
119 *i = x * g;
120 }
121 }
122
123 pub fn settle_decimate(&mut self, x: T) {
127 self.clear();
128 self.zoh = x * self.gain();
129 unimplemented!();
130 }
131
132 pub fn interpolate(&mut self, x: Option<T>) -> T {
137 if let Some(x) = x {
138 debug_assert_eq!(self.index, 0);
139 self.index = self.rate;
140 let x = self.combs.iter_mut().fold(x, |x, c| {
141 let y = x - *c;
142 *c = x;
143 y
144 });
145 self.zoh = x;
146 } else {
147 self.index -= 1;
148 }
149 self.integrators.iter_mut().fold(self.zoh, |x, i| {
150 *i += x;
152 *i
153 })
154 }
155
156 pub fn decimate(&mut self, x: T) -> Option<T> {
158 let x = self.integrators.iter_mut().fold(x, |x, i| {
159 *i = i.wrapping_add(&x);
161 *i
162 });
163 if let Some(index) = self.index.checked_sub(1) {
164 self.index = index;
165 None
166 } else {
167 self.index = self.rate;
168 let x = self.combs.iter_mut().fold(x, |x, c| {
169 let y = x.wrapping_sub(c);
170 *c = x;
171 y
172 });
173 self.zoh = x;
174 Some(self.zoh)
175 }
176 }
177}
178
179#[cfg(test)]
180mod test {
181 use core::cmp::Ordering;
182
183 use super::*;
184 use quickcheck_macros::quickcheck;
185
186 #[quickcheck]
187 fn new(rate: u32) {
188 let _ = Cic::<i64, 3>::new(rate);
189 }
190
191 #[quickcheck]
192 fn identity_dec(x: Vec<i64>) {
193 let mut dec = Cic::<_, 3>::new(0);
194 for x in x {
195 assert_eq!(x, dec.decimate(x).unwrap());
196 assert_eq!(x, dec.get_decimate());
197 }
198 }
199
200 #[quickcheck]
201 fn identity_int(x: Vec<i64>) {
202 const N: usize = 3;
203 let mut int = Cic::<_, N>::new(0);
204 for x in x {
205 assert_eq!(x >> N, int.interpolate(Some(x >> N)));
206 assert_eq!(x >> N, int.get_interpolate());
207 }
208 }
209
210 #[quickcheck]
211 fn response_length_gain_settle(x: Vec<i32>, rate: u32) {
212 let mut int = Cic::<_, 3>::new(rate);
213 let shift = int.gain_log2();
214 if shift >= 32 {
215 return;
216 }
217 assert!(int.gain() <= 1 << shift);
218 for x in x {
219 while !int.tick() {
220 int.interpolate(None);
221 }
222 let y_last = int.get_interpolate();
223 let y_want = x as i64 * int.gain();
224 for i in 0..2 * int.response_length() {
225 let y = int.interpolate(if int.tick() { Some(x as i64) } else { None });
226 assert_eq!(y, int.get_interpolate());
227 if i < int.response_length() {
228 match y_want.cmp(&y_last) {
229 Ordering::Greater => assert!((y_last..y_want).contains(&y)),
230 Ordering::Less => assert!((y_want..y_last).contains(&(y - 1))),
231 Ordering::Equal => assert_eq!(y_want, y),
232 }
233 } else {
234 assert_eq!(y, y_want);
235 }
236 }
237 }
238 }
239
240 #[quickcheck]
241 fn settle(rate: u32, x: i32) {
242 let mut int = Cic::<i64, 3>::new(rate);
243 if int.gain_log2() >= 32 {
244 return;
245 }
246 int.settle_interpolate(x as _);
247 for _ in 0..100 {
250 let y = int.interpolate(if int.tick() { Some(x as _) } else { None });
251 assert_eq!(y, x as i64 * int.gain());
252 assert_eq!(y, int.get_interpolate());
253 }
258 }
259}