Mercurial > hg > qm-dsp
comparison dsp/transforms/FFT.cpp @ 355:3c7338aff6a8
Drop in kissfft to replace the "old" fft, and add tests for newly-supported sizes
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Tue, 15 Oct 2013 11:38:18 +0100 |
parents | 9c8ee77db9de |
children | a586888bc06c |
comparison
equal
deleted
inserted
replaced
354:8519e43841df | 355:3c7338aff6a8 |
---|---|
9 | 9 |
10 #include "FFT.h" | 10 #include "FFT.h" |
11 | 11 |
12 #include "maths/MathUtilities.h" | 12 #include "maths/MathUtilities.h" |
13 | 13 |
14 #include "kiss_fft.h" | |
15 #include "kiss_fftr.h" | |
16 | |
14 #include <cmath> | 17 #include <cmath> |
15 | 18 |
16 #include <iostream> | 19 #include <iostream> |
17 | 20 |
21 #include <stdexcept> | |
22 | |
23 class FFT::D | |
24 { | |
25 public: | |
26 D(int n) : m_n(n) { | |
27 m_planf = kiss_fft_alloc(m_n, 0, NULL, NULL); | |
28 m_plani = kiss_fft_alloc(m_n, 1, NULL, NULL); | |
29 m_kin = new kiss_fft_cpx[m_n]; | |
30 m_kout = new kiss_fft_cpx[m_n]; | |
31 } | |
32 | |
33 ~D() { | |
34 kiss_fft_free(m_planf); | |
35 kiss_fft_free(m_plani); | |
36 delete[] m_kin; | |
37 delete[] m_kout; | |
38 } | |
39 | |
40 void process(bool inverse, | |
41 const double *ri, | |
42 const double *ii, | |
43 double *ro, | |
44 double *io) { | |
45 | |
46 for (int i = 0; i < m_n; ++i) { | |
47 m_kin[i].r = ri[i]; | |
48 m_kin[i].i = (ii ? ii[i] : 0.0); | |
49 } | |
50 | |
51 if (!inverse) { | |
52 | |
53 kiss_fft(m_planf, m_kin, m_kout); | |
54 | |
55 for (int i = 0; i < m_n; ++i) { | |
56 ro[i] = m_kout[i].r; | |
57 io[i] = m_kout[i].i; | |
58 } | |
59 | |
60 } else { | |
61 | |
62 kiss_fft(m_plani, m_kin, m_kout); | |
63 | |
64 double scale = 1.0 / m_n; | |
65 | |
66 for (int i = 0; i < m_n; ++i) { | |
67 ro[i] = m_kout[i].r * scale; | |
68 io[i] = m_kout[i].i * scale; | |
69 } | |
70 } | |
71 } | |
72 | |
73 private: | |
74 int m_n; | |
75 kiss_fft_cfg m_planf; | |
76 kiss_fft_cfg m_plani; | |
77 kiss_fft_cpx *m_kin; | |
78 kiss_fft_cpx *m_kout; | |
79 }; | |
80 | |
18 FFT::FFT(int n) : | 81 FFT::FFT(int n) : |
19 m_n(n) | 82 m_d(new D(n)) |
20 { | 83 { |
21 if( !MathUtilities::isPowerOfTwo(m_n) ) | |
22 { | |
23 std::cerr << "ERROR: FFT: Non-power-of-two FFT size " | |
24 << m_n << " not supported in this implementation" | |
25 << std::endl; | |
26 return; | |
27 } | |
28 } | 84 } |
29 | 85 |
30 FFT::~FFT() | 86 FFT::~FFT() |
31 { | 87 { |
32 | 88 delete m_d; |
33 } | 89 } |
34 | 90 |
91 void | |
92 FFT::process(bool inverse, | |
93 const double *p_lpRealIn, const double *p_lpImagIn, | |
94 double *p_lpRealOut, double *p_lpImagOut) | |
95 { | |
96 m_d->process(inverse, | |
97 p_lpRealIn, p_lpImagIn, | |
98 p_lpRealOut, p_lpImagOut); | |
99 } | |
100 | |
101 class FFTReal::D | |
102 { | |
103 public: | |
104 D(int n) : m_n(n) { | |
105 if (n % 2) { | |
106 throw std::invalid_argument | |
107 ("nsamples must be even in FFTReal constructor"); | |
108 } | |
109 m_planf = kiss_fftr_alloc(m_n, 0, NULL, NULL); | |
110 m_plani = kiss_fftr_alloc(m_n, 1, NULL, NULL); | |
111 m_c = new kiss_fft_cpx[m_n]; | |
112 } | |
113 | |
114 ~D() { | |
115 kiss_fftr_free(m_planf); | |
116 kiss_fftr_free(m_plani); | |
117 delete[] m_c; | |
118 } | |
119 | |
120 void forward(const double *ri, double *ro, double *io) { | |
121 | |
122 kiss_fftr(m_planf, ri, m_c); | |
123 | |
124 for (int i = 0; i <= m_n/2; ++i) { | |
125 ro[i] = m_c[i].r; | |
126 io[i] = m_c[i].i; | |
127 } | |
128 | |
129 for (int i = 0; i + 1 < m_n/2; ++i) { | |
130 ro[m_n - i - 1] = ro[i + 1]; | |
131 io[m_n - i - 1] = -io[i + 1]; | |
132 } | |
133 } | |
134 | |
135 void inverse(const double *ri, const double *ii, double *ro) { | |
136 | |
137 for (int i = 0; i < m_n; ++i) { | |
138 m_c[i].r = ri[i]; | |
139 m_c[i].i = ii[i]; | |
140 } | |
141 | |
142 kiss_fftri(m_plani, m_c, ro); | |
143 | |
144 double scale = 1.0 / m_n; | |
145 | |
146 for (int i = 0; i < m_n; ++i) { | |
147 ro[i] *= scale; | |
148 } | |
149 } | |
150 | |
151 private: | |
152 int m_n; | |
153 kiss_fftr_cfg m_planf; | |
154 kiss_fftr_cfg m_plani; | |
155 kiss_fft_cpx *m_c; | |
156 }; | |
157 | |
35 FFTReal::FFTReal(int n) : | 158 FFTReal::FFTReal(int n) : |
36 m_n(n), | 159 m_d(new D(n)) |
37 m_fft(new FFT(n)), | |
38 m_r(new double[n]), | |
39 m_i(new double[n]), | |
40 m_discard(new double[n]) | |
41 { | 160 { |
42 for (int i = 0; i < n; ++i) { | |
43 m_r[i] = 0; | |
44 m_i[i] = 0; | |
45 m_discard[i] = 0; | |
46 } | |
47 } | 161 } |
48 | 162 |
49 FFTReal::~FFTReal() | 163 FFTReal::~FFTReal() |
50 { | 164 { |
51 delete m_fft; | 165 delete m_d; |
52 delete[] m_discard; | |
53 delete[] m_r; | |
54 delete[] m_i; | |
55 } | 166 } |
56 | 167 |
57 void | 168 void |
58 FFTReal::forward(const double *realIn, | 169 FFTReal::forward(const double *ri, double *ro, double *io) |
59 double *realOut, double *imagOut) | |
60 { | 170 { |
61 m_fft->process(false, realIn, 0, realOut, imagOut); | 171 m_d->forward(ri, ro, io); |
62 } | 172 } |
63 | 173 |
64 void | 174 void |
65 FFTReal::inverse(const double *realIn, const double *imagIn, | 175 FFTReal::inverse(const double *ri, const double *ii, double *ro) |
66 double *realOut) | |
67 { | 176 { |
68 for (int i = 0; i < m_n/2 + 1; ++i) { | 177 m_d->inverse(ri, ii, ro); |
69 m_r[i] = realIn[i]; | |
70 m_i[i] = imagIn[i]; | |
71 if (i > 0 && i < m_n/2) { | |
72 m_r[m_n - i] = realIn[i]; | |
73 m_i[m_n - i] = -imagIn[i]; | |
74 } | |
75 } | |
76 m_fft->process(true, m_r, m_i, realOut, m_discard); | |
77 } | 178 } |
78 | 179 |
79 static int numberOfBitsNeeded(int p_nSamples) | |
80 { | |
81 int i; | |
82 | 180 |
83 if( p_nSamples < 2 ) | 181 |
84 { | |
85 return 0; | |
86 } | |
87 | |
88 for ( i=0; ; i++ ) | |
89 { | |
90 if( p_nSamples & (1 << i) ) return i; | |
91 } | |
92 } | |
93 | |
94 static int reverseBits(int p_nIndex, int p_nBits) | |
95 { | |
96 int i, rev; | |
97 | |
98 for(i=rev=0; i < p_nBits; i++) | |
99 { | |
100 rev = (rev << 1) | (p_nIndex & 1); | |
101 p_nIndex >>= 1; | |
102 } | |
103 | |
104 return rev; | |
105 } | |
106 | |
107 void | |
108 FFT::process(bool p_bInverseTransform, | |
109 const double *p_lpRealIn, const double *p_lpImagIn, | |
110 double *p_lpRealOut, double *p_lpImagOut) | |
111 { | |
112 if (!p_lpRealIn || !p_lpRealOut || !p_lpImagOut) return; | |
113 | |
114 // std::cerr << "FFT::process(" << m_n << "," << p_bInverseTransform << ")" << std::endl; | |
115 | |
116 int NumBits; | |
117 int i, j, k, n; | |
118 int BlockSize, BlockEnd; | |
119 | |
120 double angle_numerator = 2.0 * M_PI; | |
121 double tr, ti; | |
122 | |
123 if( !MathUtilities::isPowerOfTwo(m_n) ) | |
124 { | |
125 std::cerr << "ERROR: FFT::process: Non-power-of-two FFT size " | |
126 << m_n << " not supported in this implementation" | |
127 << std::endl; | |
128 return; | |
129 } | |
130 | |
131 if( p_bInverseTransform ) angle_numerator = -angle_numerator; | |
132 | |
133 NumBits = numberOfBitsNeeded ( m_n ); | |
134 | |
135 | |
136 | |
137 for( i=0; i < m_n; i++ ) | |
138 { | |
139 j = reverseBits ( i, NumBits ); | |
140 p_lpRealOut[j] = p_lpRealIn[i]; | |
141 p_lpImagOut[j] = (p_lpImagIn == 0) ? 0.0 : p_lpImagIn[i]; | |
142 } | |
143 | |
144 | |
145 BlockEnd = 1; | |
146 for( BlockSize = 2; BlockSize <= m_n; BlockSize <<= 1 ) | |
147 { | |
148 double delta_angle = angle_numerator / (double)BlockSize; | |
149 double sm2 = -sin ( -2 * delta_angle ); | |
150 double sm1 = -sin ( -delta_angle ); | |
151 double cm2 = cos ( -2 * delta_angle ); | |
152 double cm1 = cos ( -delta_angle ); | |
153 double w = 2 * cm1; | |
154 double ar[3], ai[3]; | |
155 | |
156 for( i=0; i < m_n; i += BlockSize ) | |
157 { | |
158 | |
159 ar[2] = cm2; | |
160 ar[1] = cm1; | |
161 | |
162 ai[2] = sm2; | |
163 ai[1] = sm1; | |
164 | |
165 for ( j=i, n=0; n < BlockEnd; j++, n++ ) | |
166 { | |
167 | |
168 ar[0] = w*ar[1] - ar[2]; | |
169 ar[2] = ar[1]; | |
170 ar[1] = ar[0]; | |
171 | |
172 ai[0] = w*ai[1] - ai[2]; | |
173 ai[2] = ai[1]; | |
174 ai[1] = ai[0]; | |
175 | |
176 k = j + BlockEnd; | |
177 tr = ar[0]*p_lpRealOut[k] - ai[0]*p_lpImagOut[k]; | |
178 ti = ar[0]*p_lpImagOut[k] + ai[0]*p_lpRealOut[k]; | |
179 | |
180 p_lpRealOut[k] = p_lpRealOut[j] - tr; | |
181 p_lpImagOut[k] = p_lpImagOut[j] - ti; | |
182 | |
183 p_lpRealOut[j] += tr; | |
184 p_lpImagOut[j] += ti; | |
185 | |
186 } | |
187 } | |
188 | |
189 BlockEnd = BlockSize; | |
190 | |
191 } | |
192 | |
193 | |
194 if( p_bInverseTransform ) | |
195 { | |
196 double denom = (double)m_n; | |
197 | |
198 for ( i=0; i < m_n; i++ ) | |
199 { | |
200 p_lpRealOut[i] /= denom; | |
201 p_lpImagOut[i] /= denom; | |
202 } | |
203 } | |
204 } | |
205 |