Skip to main content

fixed_dsp/transform/
rfft.rs

1use crate::common::tables::{REAL_COEF_A_U16, REAL_COEF_A_U32, REAL_COEF_B_U16, REAL_COEF_B_U32};
2
3use super::{CfftI16, CfftI32};
4
5const REAL_COEF_MODULUS: usize = 8192;
6
7#[inline]
8fn i32_mul(a: i32, b: i32) -> i32 {
9    (((a as i64 * b as i64) + 0x8000_0000) >> 32) as i32
10}
11
12/// Real-valued Fast Fourier Transform (RFFT) and its inverse (RIFFT) implementations for 16-bit fixed-point data.
13///
14/// Input and Output formats for RFFT Q15
15/// | RFFT Size  | Input Format  | Output Format  | Number of bits to upscale |
16/// | ---------: | ------------: | -------------: | ------------------------: |
17/// | 32         | 1.15          | 6.10           | 5                         |
18/// | 64         | 1.15          | 7.9            | 6                         |
19/// | 128        | 1.15          | 8.8            | 7                         |
20/// | 256        | 1.15          | 9.7            | 8                         |
21/// | 512        | 1.15          | 10.6           | 9                         |
22/// | 1024       | 1.15          | 11.5           | 10                        |
23/// | 2048       | 1.15          | 12.4           | 11                        |
24/// | 4096       | 1.15          | 13.3           | 12                        |
25/// | 8192       | 1.15          | 14.2           | 13                        |
26///
27/// Input and Output formats for RIFFT Q15
28/// | RFFT Size  | Input Format  | Output Format  | Number of bits to upscale |
29/// | ---------: | ------------: | -------------: | ------------------------: |
30/// | 32         | 1.15          | 6.10           | 0                         |
31/// | 64         | 1.15          | 7.9            | 0                         |
32/// | 128        | 1.15          | 8.8            | 0                         |
33/// | 256        | 1.15          | 9.7            | 0                         |
34/// | 512        | 1.15          | 10.6           | 0                         |
35/// | 1024       | 1.15          | 11.5           | 0                         |
36/// | 2048       | 1.15          | 12.4           | 0                         |
37/// | 4096       | 1.15          | 13.3           | 0                         |
38/// | 8192       | 1.15          | 14.2           | 0                         |
39pub struct RfftI16 {
40    pub n_fft_real: usize,
41    pub ifft_flag: bool,
42    pub bit_reverse_flag: bool,
43    pub re_table: &'static [u16],
44    pub im_table: &'static [u16],
45}
46
47impl RfftI16 {
48    pub const fn new(n_fft_real: usize, ifft_flag: bool, bit_reverse_flag: bool) -> Self {
49        assert!(n_fft_real.is_power_of_two(), "n_fft must be a power of two");
50        assert!(
51            32 <= n_fft_real && n_fft_real <= 4096,
52            "n_fft must be in [32, 4096]",
53        );
54
55        let re_table: &'static [u16] = &REAL_COEF_A_U16;
56        let im_table: &'static [u16] = &REAL_COEF_B_U16;
57
58        Self {
59            n_fft_real,
60            ifft_flag,
61            bit_reverse_flag,
62            re_table,
63            im_table,
64        }
65    }
66
67    fn split_rfft_i16(
68        input: &[i16],
69        n_fft: usize,
70        re_table: &[u16],
71        im_table: &[u16],
72        output: &mut [i16],
73        modifier: usize,
74    ) {
75        for i in 1..n_fft {
76            let src1 = 2 * i;
77            let src2 = (2 * n_fft) - (2 * i);
78            let coef = 2 * i * modifier;
79
80            let a0 = re_table[coef] as i16 as i32;
81            let a1 = re_table[coef + 1] as i16 as i32;
82            let b0 = im_table[coef] as i16 as i32;
83            let b1 = im_table[coef + 1] as i16 as i32;
84
85            let s1r = input[src1] as i32;
86            let s1i = input[src1 + 1] as i32;
87            let s2r = input[src2] as i32;
88            let s2i = input[src2 + 1] as i32;
89
90            let out_r = ((s1r * a0) - (s1i * a1) + (s2r * b0) + (s2i * b1)) >> 16;
91            let out_i = ((s2r * b1) - (s2i * b0) + (s1i * a0) + (s1r * a1)) >> 16;
92
93            output[2 * i] = out_r as i16;
94            output[2 * i + 1] = out_i as i16;
95
96            let conj = (4 * n_fft) - src1;
97            output[conj] = out_r as i16;
98            output[conj + 1] = (out_i as i16).wrapping_neg();
99        }
100
101        output[2 * n_fft] = ((input[0] as i32 - input[1] as i32) >> 1) as i16;
102        output[2 * n_fft + 1] = 0;
103
104        output[0] = ((input[0] as i32 + input[1] as i32) >> 1) as i16;
105        output[1] = 0;
106    }
107
108    fn split_rifft_i16(
109        input: &[i16],
110        n_fft: usize,
111        re_table: &[u16],
112        im_table: &[u16],
113        output: &mut [i16],
114        modifier: usize,
115    ) {
116        for i in 0..n_fft {
117            let src1 = 2 * i;
118            let src2 = (2 * n_fft) - (2 * i);
119            let coef = 2 * i * modifier;
120
121            let a0 = re_table[coef] as i16 as i32;
122            let a1 = re_table[coef + 1] as i16 as i32;
123            let b0 = im_table[coef] as i16 as i32;
124            let b1 = im_table[coef + 1] as i16 as i32;
125
126            let s1r = input[src1] as i32;
127            let s1i = input[src1 + 1] as i32;
128            let s2r = input[src2] as i32;
129            let s2i = input[src2 + 1] as i32;
130
131            let out_r = ((s2r * b0) - (s2i * b1) + (s1r * a0) + (s1i * a1)) >> 16;
132            let out_i = ((s1i * a0) - (s1r * a1) - (s2r * b1) - (s2i * b0)) >> 16;
133
134            output[src1] = out_r as i16;
135            output[src1 + 1] = out_i as i16;
136        }
137    }
138
139    pub fn run(&self, input: &mut [i16], output: &mut [i16]) {
140        let n_fft = self.n_fft_real >> 1;
141        let modifier = REAL_COEF_MODULUS / self.n_fft_real;
142
143        if self.ifft_flag {
144            assert_eq!(
145                input.len(),
146                self.n_fft_real * 2,
147                "RIFFT input length must be 2 * n_fft_real"
148            );
149            assert_eq!(
150                output.len(),
151                self.n_fft_real,
152                "RIFFT output length must be n_fft_real"
153            );
154
155            Self::split_rifft_i16(input, n_fft, self.re_table, self.im_table, output, modifier);
156
157            CfftI16::new(n_fft, true, self.bit_reverse_flag).run(output);
158
159            for sample in output.iter_mut() {
160                let v = (*sample as i32) << 1;
161                *sample = v.clamp(i16::MIN as i32, i16::MAX as i32) as i16;
162            }
163        } else {
164            assert_eq!(
165                input.len(),
166                self.n_fft_real,
167                "RFFT input length must be n_fft_real"
168            );
169            assert_eq!(
170                output.len(),
171                self.n_fft_real * 2,
172                "RFFT output length must be 2 * n_fft_real"
173            );
174
175            CfftI16::new(n_fft, false, self.bit_reverse_flag).run(input);
176
177            Self::split_rfft_i16(input, n_fft, self.re_table, self.im_table, output, modifier);
178        }
179    }
180}
181
182/// Real-valued Fast Fourier Transform (RFFT) and its inverse (RIFFT) implementations for 32-bit fixed-point data.
183
184/// Input and Output formats for RFFT Q31
185/// | RFFT Size  | Input Format  | Output Format  | Number of bits to upscale |
186/// | ---------: | ------------: | -------------: | ------------------------: |
187/// | 32         | 1.31          | 6.26           | 5                         |
188/// | 64         | 1.31          | 7.25           | 6                         |
189/// | 128        | 1.31          | 8.24           | 7                         |
190/// | 256        | 1.31          | 9.23           | 8                         |
191/// | 512        | 1.31          | 10.22          | 9                         |
192/// | 1024       | 1.31          | 11.21          | 10                        |
193/// | 2048       | 1.31          | 12.20          | 11                        |
194/// | 4096       | 1.31          | 13.19          | 12                        |
195/// | 8192       | 1.31          | 14.18          | 13                        |
196///
197/// Input and Output formats for RIFFT Q31
198/// | RIFFT Size  | Input Format  | Output Format  | Number of bits to upscale |
199/// | ----------: | ------------: | -------------: | ------------------------: |
200/// | 32          | 1.31          | 6.26           | 0                         |
201/// | 64          | 1.31          | 7.25           | 0                         |
202/// | 128         | 1.31          | 8.24           | 0                         |
203/// | 256         | 1.31          | 9.23           | 0                         |
204/// | 512         | 1.31          | 10.22          | 0                         |
205/// | 1024        | 1.31          | 11.21          | 0                         |
206/// | 2048        | 1.31          | 12.20          | 0                         |
207/// | 4096        | 1.31          | 13.19          | 0                         |
208/// | 8192        | 1.31          | 14.18          | 0                         |
209pub struct RfftI32 {
210    pub n_fft_real: usize,
211    pub ifft_flag: bool,
212    pub bit_reverse_flag: bool,
213    pub re_table: &'static [u32],
214    pub im_table: &'static [u32],
215}
216
217impl RfftI32 {
218    pub const fn new(n_fft_real: usize, ifft_flag: bool, bit_reverse_flag: bool) -> Self {
219        assert!(n_fft_real.is_power_of_two(), "n_fft must be a power of two");
220        assert!(
221            32 <= n_fft_real && n_fft_real <= 8192,
222            "n_fft must be in [32, 8192]",
223        );
224
225        let re_table: &'static [u32] = &REAL_COEF_A_U32;
226        let im_table: &'static [u32] = &REAL_COEF_B_U32;
227
228        Self {
229            n_fft_real,
230            ifft_flag,
231            bit_reverse_flag,
232            re_table,
233            im_table,
234        }
235    }
236
237    fn split_rfft_i32(
238        input: &[i32],
239        n_fft: usize,
240        re_table: &[u32],
241        im_table: &[u32],
242        output: &mut [i32],
243        modifier: usize,
244    ) {
245        for i in 1..n_fft {
246            let src1 = 2 * i;
247            let src2 = (2 * n_fft) - (2 * i);
248            let coef = 2 * i * modifier;
249
250            let a0 = re_table[coef] as i32;
251            let a1 = re_table[coef + 1] as i32;
252            let b0 = im_table[coef] as i32;
253            let b1 = im_table[coef + 1] as i32;
254
255            let s1r = input[src1];
256            let s1i = input[src1 + 1];
257            let s2r = input[src2];
258            let s2i = input[src2 + 1];
259
260            let out_r = i32_mul(s1r, a0)
261                .wrapping_sub(i32_mul(s1i, a1))
262                .wrapping_add(i32_mul(s2r, b0))
263                .wrapping_add(i32_mul(s2i, b1));
264            let out_i = i32_mul(s2r, b1)
265                .wrapping_sub(i32_mul(s2i, b0))
266                .wrapping_add(i32_mul(s1i, a0))
267                .wrapping_add(i32_mul(s1r, a1));
268
269            output[2 * i] = out_r;
270            output[2 * i + 1] = out_i;
271
272            let conj = (4 * n_fft) - src1;
273            output[conj] = out_r;
274            output[conj + 1] = out_i.wrapping_neg();
275        }
276
277        output[2 * n_fft] = (input[0] - input[1]) >> 1;
278        output[2 * n_fft + 1] = 0;
279
280        output[0] = (input[0] + input[1]) >> 1;
281        output[1] = 0;
282    }
283
284    fn split_rifft_i32(
285        input: &[i32],
286        n_fft: usize,
287        re_table: &[u32],
288        im_table: &[u32],
289        output: &mut [i32],
290        modifier: usize,
291    ) {
292        for i in 0..n_fft {
293            let src1 = 2 * i;
294            let src2 = (2 * n_fft) - (2 * i);
295            let coef = 2 * i * modifier;
296
297            let a0 = re_table[coef] as i32;
298            let a1 = re_table[coef + 1] as i32;
299            let b0 = im_table[coef] as i32;
300            let b1 = im_table[coef + 1] as i32;
301
302            let s1r = input[src1];
303            let s1i = input[src1 + 1];
304            let s2r = input[src2];
305            let s2i = input[src2 + 1];
306
307            let out_r = i32_mul(s2r, b0)
308                .wrapping_sub(i32_mul(s2i, b1))
309                .wrapping_add(i32_mul(s1r, a0))
310                .wrapping_add(i32_mul(s1i, a1));
311            let out_i = i32_mul(s1i, a0)
312                .wrapping_sub(i32_mul(s1r, a1))
313                .wrapping_sub(i32_mul(s2r, b1))
314                .wrapping_sub(i32_mul(s2i, b0));
315
316            output[src1] = out_r;
317            output[src1 + 1] = out_i;
318        }
319    }
320
321    pub fn run(&self, input: &mut [i32], output: &mut [i32]) {
322        let n_fft = self.n_fft_real >> 1;
323        let modifier = REAL_COEF_MODULUS / self.n_fft_real;
324
325        if self.ifft_flag {
326            assert_eq!(
327                input.len(),
328                self.n_fft_real * 2,
329                "RIFFT input length must be 2 * n_fft_real"
330            );
331            assert_eq!(
332                output.len(),
333                self.n_fft_real,
334                "RIFFT output length must be n_fft_real"
335            );
336
337            Self::split_rifft_i32(input, n_fft, self.re_table, self.im_table, output, modifier);
338
339            CfftI32::new(n_fft, true, self.bit_reverse_flag).run(output);
340
341            for sample in output.iter_mut() {
342                *sample = sample.wrapping_shl(1);
343            }
344        } else {
345            assert_eq!(
346                input.len(),
347                self.n_fft_real,
348                "RFFT input length must be n_fft_real"
349            );
350            assert_eq!(
351                output.len(),
352                self.n_fft_real * 2,
353                "RFFT output length must be 2 * n_fft_real"
354            );
355
356            CfftI32::new(n_fft, false, self.bit_reverse_flag).run(input);
357
358            Self::split_rfft_i32(input, n_fft, self.re_table, self.im_table, output, modifier);
359        }
360    }
361}