1use alloc::boxed::Box;
2use alloc::collections::VecDeque;
3
4use crate::fir_filter::{hamming, lowpass_fir_filter, scale_lowpass_filter};
5
6use itertools::{zip, Itertools};
7
8pub struct InterpolationFilter {
9 factor: u8,
10 filter: Box<[f64]>,
11 window: VecDeque<f64>,
12}
13
14impl InterpolationFilter {
15 pub fn new(half_window_len: u32, factor: u8) -> Self {
16 let mut filter: Box<[f64]> =
17 lowpass_fir_filter(half_window_len * 2 * u32::from(factor) + 1, 1.0 / f64::from(factor), hamming).collect();
18 scale_lowpass_filter(&mut filter);
19 let window = VecDeque::with_capacity(filter.len());
20 Self { factor, filter, window }
21 }
22
23 pub fn window_len(&self) -> usize {
24 (self.filter.len() - 1) / usize::from(self.factor)
25 }
26
27 pub fn interpolate<'a>(&'a mut self, values: impl IntoIterator<Item = f64> + 'a) -> impl Iterator<Item = f64> + 'a {
28 let factor = self.factor as f64;
29 let scaled = values.into_iter().map(move |value| value * factor);
30 let mut extended = Itertools::intersperse(scaled, 0.0);
31
32 self.window.clear();
33 self.window.extend(extended.by_ref().take(self.filter.len() - 1));
34
35 let interpolated = extended.map(move |value| {
36 if self.window.len() == self.filter.len() {
37 self.window.pop_front();
38 }
39 self.window.push_back(value);
40 zip(self.window.iter().rev(), &*self.filter).map(|(x, y)| x * y).sum()
41 });
42 interpolated
43 }
44}