embedded_dsp/
resampling.rs1pub struct CicDecimator<const STAGES: usize> {
5 r: usize, integrator_state: [i32; STAGES],
7 comb_state: [i32; STAGES],
8 sample_counter: usize,
9}
10
11impl<const STAGES: usize> CicDecimator<STAGES> {
12 pub fn new(r: usize) -> Self {
14 Self {
15 r,
16 integrator_state: [0; STAGES],
17 comb_state: [0; STAGES],
18 sample_counter: 0,
19 }
20 }
21
22 pub fn gain(&self) -> u64 {
24 let mut g: u64 = 1;
25 for _ in 0..STAGES {
26 g = g.saturating_mul(self.r as u64);
27 }
28 g
29 }
30
31 pub fn gain_bits(&self) -> u32 {
33 let g = self.gain();
34 if g <= 1 {
35 0
36 } else {
37 64 - (g - 1).leading_zeros()
38 }
39 }
40
41 pub fn process_sample(&mut self, input: i32) -> Option<i32> {
43 let mut val = input;
45 for i in 0..STAGES {
46 self.integrator_state[i] = self.integrator_state[i].wrapping_add(val);
47 val = self.integrator_state[i];
48 }
49
50 self.sample_counter += 1;
51 if self.sample_counter >= self.r {
52 self.sample_counter = 0;
53
54 for i in 0..STAGES {
56 let diff = val.wrapping_sub(self.comb_state[i]);
57 self.comb_state[i] = val;
58 val = diff;
59 }
60 Some(val)
61 } else {
62 None
63 }
64 }
65
66 pub fn process_sample_scaled(&mut self, input: i32) -> Option<i32> {
68 self.process_sample(input).map(|out| {
69 let shift = self.gain_bits();
70 if shift > 0 {
71 out >> shift
72 } else {
73 out
74 }
75 })
76 }
77}
78
79pub struct CicInterpolator<const STAGES: usize> {
81 r: usize, comb_state: [i32; STAGES],
83 integrator_state: [i32; STAGES],
84}
85
86impl<const STAGES: usize> CicInterpolator<STAGES> {
87 pub fn new(r: usize) -> Self {
89 Self {
90 r,
91 comb_state: [0; STAGES],
92 integrator_state: [0; STAGES],
93 }
94 }
95
96 pub fn gain(&self) -> u64 {
98 if STAGES <= 1 {
99 return 1;
100 }
101 let mut g: u64 = 1;
102 for _ in 0..(STAGES - 1) {
103 g = g.saturating_mul(self.r as u64);
104 }
105 g
106 }
107
108 pub fn gain_bits(&self) -> u32 {
110 let g = self.gain();
111 if g <= 1 {
112 0
113 } else {
114 64 - (g - 1).leading_zeros()
115 }
116 }
117
118 pub fn process_sample(&mut self, input: i32, out_buf: &mut [i32]) {
120 assert!(
121 out_buf.len() >= self.r,
122 "out_buf must hold at least R samples"
123 );
124
125 let mut val = input;
127 for i in 0..STAGES {
128 let diff = val.wrapping_sub(self.comb_state[i]);
129 self.comb_state[i] = val;
130 val = diff;
131 }
132
133 for step in 0..self.r {
135 let in_step = if step == 0 { val } else { 0 };
136 let mut stage_val = in_step;
137
138 for i in 0..STAGES {
139 self.integrator_state[i] = self.integrator_state[i].wrapping_add(stage_val);
140 stage_val = self.integrator_state[i];
141 }
142
143 out_buf[step] = stage_val;
144 }
145 }
146}
147
148use crate::types::q15;
153
154pub fn polyphase_decimate_q15(
160 src: &[q15],
161 coeffs: &[q15],
162 decimation_factor: usize,
163 dst: &mut [q15],
164) -> usize {
165 if decimation_factor == 0 || coeffs.is_empty() || src.is_empty() {
166 return 0;
167 }
168 let num_taps = coeffs.len();
169 let out_len = dst.len().min(if src.len() >= num_taps { (src.len() - num_taps) / decimation_factor + 1 } else { 0 });
170
171 for i in 0..out_len {
172 let src_offset = i * decimation_factor;
173 let mut acc: i64 = 0;
174 for k in 0..num_taps {
175 acc += (src[src_offset + k] as i64 * coeffs[k] as i64) >> 15;
176 }
177 dst[i] = acc.clamp(i16::MIN as i64, i16::MAX as i64) as q15;
178 }
179
180 out_len
181}
182
183pub fn polyphase_interpolate_q15(
189 src: &[q15],
190 coeffs: &[q15],
191 interpolation_factor: usize,
192 dst: &mut [q15],
193) -> usize {
194 let l = interpolation_factor;
195 if l == 0 || coeffs.is_empty() || src.is_empty() || coeffs.len() % l != 0 {
196 return 0;
197 }
198 let taps_per_phase = coeffs.len() / l;
199 let max_in_samples = if src.len() >= taps_per_phase { src.len() - taps_per_phase + 1 } else { 0 };
200 let out_len = dst.len().min(max_in_samples * l);
201
202 for in_idx in 0..max_in_samples {
203 for phase in 0..l {
204 let out_idx = in_idx * l + phase;
205 if out_idx >= dst.len() {
206 break;
207 }
208 let mut acc: i64 = 0;
209 for k in 0..taps_per_phase {
210 let coeff = coeffs[k * l + phase] as i64;
211 let sample = src[in_idx + k] as i64;
212 acc += (sample * coeff) >> 15;
213 }
214 dst[out_idx] = (acc * l as i64).clamp(i16::MIN as i64, i16::MAX as i64) as q15;
215 }
216 }
217
218 out_len
219}
220
221pub fn resample_linear_q15(src: &[q15], dst: &mut [q15], ratio_q16: i32) {
224 if src.is_empty() || dst.is_empty() || ratio_q16 <= 0 {
225 return;
226 }
227
228 let mut phase_acc: i64 = 0;
229 for i in 0..dst.len() {
230 let idx0 = (phase_acc >> 16) as usize;
231 let frac = (phase_acc & 0xFFFF) as i32; if idx0 >= src.len() {
234 dst[i] = src[src.len() - 1];
235 } else {
236 let s0 = src[idx0] as i32;
237 let s1 = if idx0 + 1 < src.len() { src[idx0 + 1] as i32 } else { s0 };
238 let diff = s1 - s0;
239 let interp = s0 + ((diff * frac) >> 16);
240 dst[i] = interp.clamp(i16::MIN as i32, i16::MAX as i32) as q15;
241 }
242
243 phase_acc += ratio_q16 as i64;
244 }
245}
246
247pub fn resample_linear_f32(src: &[f32], dst: &mut [f32], ratio: f32) {
250 if src.is_empty() || dst.is_empty() || ratio <= 0.0 {
251 return;
252 }
253
254 for i in 0..dst.len() {
255 let src_idx_float = i as f32 * ratio;
256 let idx0 = src_idx_float as usize;
257 let idx1 = (idx0 + 1).min(src.len() - 1);
258
259 if idx0 >= src.len() {
260 dst[i] = src[src.len() - 1];
261 continue;
262 }
263
264 let frac = src_idx_float - idx0 as f32;
265 dst[i] = src[idx0] * (1.0 - frac) + src[idx1] * frac;
266 }
267}
268
269#[cfg(feature = "transform")]
270use crate::transform::cfft_f32;
271#[cfg(feature = "transform")]
272use crate::types::Status;
273
274#[cfg(feature = "transform")]
281pub fn spectral_interpolate_2x_f32(src: &[f32], dst: &mut [f32]) -> Status {
282 let n = src.len();
283 if n < 4 || (n & (n - 1)) != 0 {
284 return Status::ArgumentError;
285 }
286 if dst.len() < 2 * n {
287 return Status::LengthError;
288 }
289 if 4 * n > 1024 {
290 return Status::LengthError; }
292
293 let mut c_buf = [0.0f32; 1024];
294
295 for i in 0..n {
297 c_buf[2 * i] = src[i];
298 c_buf[2 * i + 1] = 0.0;
299 }
300
301 cfft_f32(&mut c_buf[..2 * n], n, 0, 1);
303
304 let nyq_re = 0.5 * c_buf[n];
306 let nyq_im = 0.5 * c_buf[n + 1];
307 c_buf[n] = nyq_re;
308 c_buf[n + 1] = nyq_im;
309
310 let mut expanded = [0.0f32; 1024];
312 for i in 0..=(n / 2) {
314 expanded[2 * i] = c_buf[2 * i];
315 expanded[2 * i + 1] = c_buf[2 * i + 1];
316 }
317 expanded[2 * (3 * n / 2)] = nyq_re;
319 expanded[2 * (3 * n / 2) + 1] = nyq_im;
320
321 for i in (n / 2 + 1)..n {
323 expanded[2 * (i + n)] = c_buf[2 * i];
324 expanded[2 * (i + n) + 1] = c_buf[2 * i + 1];
325 }
326
327 cfft_f32(&mut expanded[..4 * n], 2 * n, 1, 1);
329
330 for i in 0..(2 * n) {
332 dst[i] = 2.0 * expanded[2 * i];
333 }
334
335 Status::Success
336}