comparison dsp/transforms/FFT.cpp @ 129:6ec45e85ed81 kissfft

Drop in kissfft to replace the "old" fft, and add tests for newly-supported sizes
author Chris Cannam
date Tue, 15 Oct 2013 11:38:18 +0100
parents f6ccde089491
children a586888bc06c
comparison
equal deleted inserted replaced
128:5023f521732c 129:6ec45e85ed81
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