Mercurial > hg > qm-dsp
comparison tests/TestFFT.cpp @ 347:e3dedded9c4d
Merge from pvoc branch
author | Chris Cannam <c.cannam@qmul.ac.uk> |
---|---|
date | Fri, 04 Oct 2013 16:43:44 +0100 |
parents | 24d8ea972643 |
children | 6ec45e85ed81 |
comparison
equal
deleted
inserted
replaced
336:f665f9ce2fd1 | 347:e3dedded9c4d |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
1 | 2 |
2 #include "dsp/transforms/FFT.h" | 3 #include "dsp/transforms/FFT.h" |
3 | 4 |
4 #define BOOST_TEST_DYN_LINK | 5 #define BOOST_TEST_DYN_LINK |
5 #define BOOST_TEST_MAIN | 6 #define BOOST_TEST_MAIN |
16 #define COMPARE_ARRAY(a, b) \ | 17 #define COMPARE_ARRAY(a, b) \ |
17 for (int cmp_i = 0; cmp_i < (int)(sizeof(a)/sizeof(a[0])); ++cmp_i) { \ | 18 for (int cmp_i = 0; cmp_i < (int)(sizeof(a)/sizeof(a[0])); ++cmp_i) { \ |
18 BOOST_CHECK_SMALL(a[cmp_i] - b[cmp_i], 1e-14); \ | 19 BOOST_CHECK_SMALL(a[cmp_i] - b[cmp_i], 1e-14); \ |
19 } | 20 } |
20 | 21 |
21 BOOST_AUTO_TEST_CASE(dc) | 22 //!!! need at least one test with complex time-domain signal |
22 { | |
23 // DC-only signal. The DC bin is purely real | |
24 double in[] = { 1, 1, 1, 1 }; | |
25 double re[4], im[4]; | |
26 FFT(4).process(false, in, 0, re, im); | |
27 BOOST_CHECK_EQUAL(re[0], 4.0); | |
28 BOOST_CHECK_EQUAL(re[1], 0.0); | |
29 BOOST_CHECK_EQUAL(re[2], 0.0); | |
30 COMPARE_CONST(im, 0.0); | |
31 double back[4]; | |
32 double backim[4]; | |
33 FFT(4).process(true, re, im, back, backim); | |
34 COMPARE_ARRAY(back, in); | |
35 } | |
36 | |
37 BOOST_AUTO_TEST_CASE(sine) | |
38 { | |
39 // Sine. Output is purely imaginary | |
40 double in[] = { 0, 1, 0, -1 }; | |
41 double re[4], im[4]; | |
42 FFT(4).process(false, in, 0, re, im); | |
43 COMPARE_CONST(re, 0.0); | |
44 BOOST_CHECK_EQUAL(im[0], 0.0); | |
45 BOOST_CHECK_EQUAL(im[1], -2.0); | |
46 BOOST_CHECK_EQUAL(im[2], 0.0); | |
47 double back[4]; | |
48 double backim[4]; | |
49 FFT(4).process(true, re, im, back, backim); | |
50 COMPARE_ARRAY(back, in); | |
51 } | |
52 | |
53 BOOST_AUTO_TEST_CASE(cosine) | |
54 { | |
55 // Cosine. Output is purely real | |
56 double in[] = { 1, 0, -1, 0 }; | |
57 double re[4], im[4]; | |
58 FFT(4).process(false, in, 0, re, im); | |
59 BOOST_CHECK_EQUAL(re[0], 0.0); | |
60 BOOST_CHECK_EQUAL(re[1], 2.0); | |
61 BOOST_CHECK_EQUAL(re[2], 0.0); | |
62 COMPARE_CONST(im, 0.0); | |
63 double back[4]; | |
64 double backim[4]; | |
65 FFT(4).process(true, re, im, back, backim); | |
66 COMPARE_ARRAY(back, in); | |
67 } | |
68 | |
69 BOOST_AUTO_TEST_CASE(sineCosine) | |
70 { | |
71 // Sine and cosine mixed | |
72 double in[] = { 0.5, 1, -0.5, -1 }; | |
73 double re[4], im[4]; | |
74 FFT(4).process(false, in, 0, re, im); | |
75 BOOST_CHECK_EQUAL(re[0], 0.0); | |
76 BOOST_CHECK_CLOSE(re[1], 1.0, 1e-12); | |
77 BOOST_CHECK_EQUAL(re[2], 0.0); | |
78 BOOST_CHECK_EQUAL(im[0], 0.0); | |
79 BOOST_CHECK_CLOSE(im[1], -2.0, 1e-12); | |
80 BOOST_CHECK_EQUAL(im[2], 0.0); | |
81 double back[4]; | |
82 double backim[4]; | |
83 FFT(4).process(true, re, im, back, backim); | |
84 COMPARE_ARRAY(back, in); | |
85 } | |
86 | |
87 BOOST_AUTO_TEST_CASE(nyquist) | |
88 { | |
89 double in[] = { 1, -1, 1, -1 }; | |
90 double re[4], im[4]; | |
91 FFT(4).process(false, in, 0, re, im); | |
92 BOOST_CHECK_EQUAL(re[0], 0.0); | |
93 BOOST_CHECK_EQUAL(re[1], 0.0); | |
94 BOOST_CHECK_EQUAL(re[2], 4.0); | |
95 COMPARE_CONST(im, 0.0); | |
96 double back[4]; | |
97 double backim[4]; | |
98 FFT(4).process(true, re, im, back, backim); | |
99 COMPARE_ARRAY(back, in); | |
100 } | |
101 | |
102 BOOST_AUTO_TEST_CASE(dirac) | |
103 { | |
104 double in[] = { 1, 0, 0, 0 }; | |
105 double re[4], im[4]; | |
106 FFT(4).process(false, in, 0, re, im); | |
107 BOOST_CHECK_EQUAL(re[0], 1.0); | |
108 BOOST_CHECK_EQUAL(re[1], 1.0); | |
109 BOOST_CHECK_EQUAL(re[2], 1.0); | |
110 COMPARE_CONST(im, 0.0); | |
111 double back[4]; | |
112 double backim[4]; | |
113 FFT(4).process(true, re, im, back, backim); | |
114 COMPARE_ARRAY(back, in); | |
115 } | |
116 | 23 |
117 BOOST_AUTO_TEST_CASE(forwardArrayBounds) | 24 BOOST_AUTO_TEST_CASE(forwardArrayBounds) |
118 { | 25 { |
119 // initialise bins to something recognisable, so we can tell | 26 // initialise bins to something recognisable, so we can tell |
120 // if they haven't been written | 27 // if they haven't been written |
127 BOOST_CHECK_EQUAL(im[0], 999.0); | 34 BOOST_CHECK_EQUAL(im[0], 999.0); |
128 BOOST_CHECK_EQUAL(re[5], 999.0); | 35 BOOST_CHECK_EQUAL(re[5], 999.0); |
129 BOOST_CHECK_EQUAL(im[5], 999.0); | 36 BOOST_CHECK_EQUAL(im[5], 999.0); |
130 } | 37 } |
131 | 38 |
39 BOOST_AUTO_TEST_CASE(r_forwardArrayBounds) | |
40 { | |
41 // initialise bins to something recognisable, so we can tell | |
42 // if they haven't been written | |
43 double in[] = { 1, 1, -1, -1 }; | |
44 double re[] = { 999, 999, 999, 999, 999, 999 }; | |
45 double im[] = { 999, 999, 999, 999, 999, 999 }; | |
46 FFTReal(4).forward(in, re+1, im+1); | |
47 // And check we haven't overrun the arrays | |
48 BOOST_CHECK_EQUAL(re[0], 999.0); | |
49 BOOST_CHECK_EQUAL(im[0], 999.0); | |
50 BOOST_CHECK_EQUAL(re[5], 999.0); | |
51 BOOST_CHECK_EQUAL(im[5], 999.0); | |
52 } | |
53 | |
132 BOOST_AUTO_TEST_CASE(inverseArrayBounds) | 54 BOOST_AUTO_TEST_CASE(inverseArrayBounds) |
55 { | |
56 // initialise bins to something recognisable, so we can tell | |
57 // if they haven't been written | |
58 double re[] = { 0, 1, 0, 1 }; | |
59 double im[] = { 0, -2, 0, 2 }; | |
60 double outre[] = { 999, 999, 999, 999, 999, 999 }; | |
61 double outim[] = { 999, 999, 999, 999, 999, 999 }; | |
62 FFT(4).process(true, re, im, outre+1, outim+1); | |
63 // And check we haven't overrun the arrays | |
64 BOOST_CHECK_EQUAL(outre[0], 999.0); | |
65 BOOST_CHECK_EQUAL(outim[0], 999.0); | |
66 BOOST_CHECK_EQUAL(outre[5], 999.0); | |
67 BOOST_CHECK_EQUAL(outim[5], 999.0); | |
68 } | |
69 | |
70 BOOST_AUTO_TEST_CASE(r_inverseArrayBounds) | |
133 { | 71 { |
134 // initialise bins to something recognisable, so we can tell | 72 // initialise bins to something recognisable, so we can tell |
135 // if they haven't been written | 73 // if they haven't been written |
136 double re[] = { 0, 1, 0 }; | 74 double re[] = { 0, 1, 0 }; |
137 double im[] = { 0, -2, 0 }; | 75 double im[] = { 0, -2, 0 }; |
138 double outre[] = { 999, 999, 999, 999, 999, 999 }; | 76 double outre[] = { 999, 999, 999, 999, 999, 999 }; |
139 double outim[] = { 999, 999, 999, 999, 999, 999 }; | 77 FFTReal(4).inverse(re, im, outre+1); |
140 FFT(4).process(false, re, im, outre+1, outim+1); | |
141 // And check we haven't overrun the arrays | 78 // And check we haven't overrun the arrays |
142 BOOST_CHECK_EQUAL(outre[0], 999.0); | 79 BOOST_CHECK_EQUAL(outre[0], 999.0); |
143 BOOST_CHECK_EQUAL(outim[0], 999.0); | |
144 BOOST_CHECK_EQUAL(outre[5], 999.0); | 80 BOOST_CHECK_EQUAL(outre[5], 999.0); |
145 BOOST_CHECK_EQUAL(outim[5], 999.0); | 81 } |
82 | |
83 BOOST_AUTO_TEST_CASE(dc) | |
84 { | |
85 // DC-only signal. The DC bin is purely real | |
86 double in[] = { 1, 1, 1, 1 }; | |
87 double re[] = { 999, 999, 999, 999 }; | |
88 double im[] = { 999, 999, 999, 999 }; | |
89 FFT(4).process(false, in, 0, re, im); | |
90 BOOST_CHECK_EQUAL(re[0], 4.0); | |
91 BOOST_CHECK_EQUAL(re[1], 0.0); | |
92 BOOST_CHECK_EQUAL(re[2], 0.0); | |
93 BOOST_CHECK_EQUAL(re[3], 0.0); | |
94 COMPARE_CONST(im, 0.0); | |
95 double back[4]; | |
96 double backim[4]; | |
97 FFT(4).process(true, re, im, back, backim); | |
98 COMPARE_ARRAY(back, in); | |
99 COMPARE_CONST(backim, 0.0); | |
100 } | |
101 | |
102 BOOST_AUTO_TEST_CASE(r_dc) | |
103 { | |
104 // DC-only signal. The DC bin is purely real | |
105 double in[] = { 1, 1, 1, 1 }; | |
106 double re[] = { 999, 999, 999, 999 }; | |
107 double im[] = { 999, 999, 999, 999 }; | |
108 FFTReal(4).forward(in, re, im); | |
109 BOOST_CHECK_EQUAL(re[0], 4.0); | |
110 BOOST_CHECK_EQUAL(re[1], 0.0); | |
111 BOOST_CHECK_EQUAL(re[2], 0.0); | |
112 BOOST_CHECK_EQUAL(re[3], 0.0); | |
113 COMPARE_CONST(im, 0.0); | |
114 double back[4]; | |
115 // check conjugates are reconstructed | |
116 re[3] = 999; | |
117 im[3] = 999; | |
118 FFTReal(4).inverse(re, im, back); | |
119 COMPARE_ARRAY(back, in); | |
120 } | |
121 | |
122 BOOST_AUTO_TEST_CASE(sine) | |
123 { | |
124 // Sine. Output is purely imaginary | |
125 double in[] = { 0, 1, 0, -1 }; | |
126 double re[] = { 999, 999, 999, 999 }; | |
127 double im[] = { 999, 999, 999, 999 }; | |
128 FFT(4).process(false, in, 0, re, im); | |
129 COMPARE_CONST(re, 0.0); | |
130 BOOST_CHECK_EQUAL(im[0], 0.0); | |
131 BOOST_CHECK_EQUAL(im[1], -2.0); | |
132 BOOST_CHECK_EQUAL(im[2], 0.0); | |
133 BOOST_CHECK_EQUAL(im[3], 2.0); | |
134 double back[4]; | |
135 double backim[4]; | |
136 FFT(4).process(true, re, im, back, backim); | |
137 COMPARE_ARRAY(back, in); | |
138 COMPARE_CONST(backim, 0.0); | |
139 } | |
140 | |
141 BOOST_AUTO_TEST_CASE(r_sine) | |
142 { | |
143 // Sine. Output is purely imaginary | |
144 double in[] = { 0, 1, 0, -1 }; | |
145 double re[] = { 999, 999, 999, 999 }; | |
146 double im[] = { 999, 999, 999, 999 }; | |
147 FFTReal(4).forward(in, re, im); | |
148 COMPARE_CONST(re, 0.0); | |
149 BOOST_CHECK_EQUAL(im[0], 0.0); | |
150 BOOST_CHECK_EQUAL(im[1], -2.0); | |
151 BOOST_CHECK_EQUAL(im[2], 0.0); | |
152 BOOST_CHECK_EQUAL(im[3], 2.0); | |
153 double back[4]; | |
154 // check conjugates are reconstructed | |
155 re[3] = 999; | |
156 im[3] = 999; | |
157 FFTReal(4).inverse(re, im, back); | |
158 COMPARE_ARRAY(back, in); | |
159 } | |
160 | |
161 BOOST_AUTO_TEST_CASE(cosine) | |
162 { | |
163 // Cosine. Output is purely real | |
164 double in[] = { 1, 0, -1, 0 }; | |
165 double re[] = { 999, 999, 999, 999 }; | |
166 double im[] = { 999, 999, 999, 999 }; | |
167 FFT(4).process(false, in, 0, re, im); | |
168 BOOST_CHECK_EQUAL(re[0], 0.0); | |
169 BOOST_CHECK_EQUAL(re[1], 2.0); | |
170 BOOST_CHECK_EQUAL(re[2], 0.0); | |
171 BOOST_CHECK_EQUAL(re[3], 2.0); | |
172 COMPARE_CONST(im, 0.0); | |
173 double back[4]; | |
174 double backim[4]; | |
175 FFT(4).process(true, re, im, back, backim); | |
176 COMPARE_ARRAY(back, in); | |
177 COMPARE_CONST(backim, 0.0); | |
178 } | |
179 | |
180 BOOST_AUTO_TEST_CASE(r_cosine) | |
181 { | |
182 // Cosine. Output is purely real | |
183 double in[] = { 1, 0, -1, 0 }; | |
184 double re[] = { 999, 999, 999, 999 }; | |
185 double im[] = { 999, 999, 999, 999 }; | |
186 FFTReal(4).forward(in, re, im); | |
187 BOOST_CHECK_EQUAL(re[0], 0.0); | |
188 BOOST_CHECK_EQUAL(re[1], 2.0); | |
189 BOOST_CHECK_EQUAL(re[2], 0.0); | |
190 BOOST_CHECK_EQUAL(re[3], 2.0); | |
191 COMPARE_CONST(im, 0.0); | |
192 double back[4]; | |
193 // check conjugates are reconstructed | |
194 re[3] = 999; | |
195 im[3] = 999; | |
196 FFTReal(4).inverse(re, im, back); | |
197 COMPARE_ARRAY(back, in); | |
198 } | |
199 | |
200 BOOST_AUTO_TEST_CASE(sineCosine) | |
201 { | |
202 // Sine and cosine mixed | |
203 double in[] = { 0.5, 1, -0.5, -1 }; | |
204 double re[] = { 999, 999, 999, 999 }; | |
205 double im[] = { 999, 999, 999, 999 }; | |
206 FFT(4).process(false, in, 0, re, im); | |
207 BOOST_CHECK_EQUAL(re[0], 0.0); | |
208 BOOST_CHECK_CLOSE(re[1], 1.0, 1e-12); | |
209 BOOST_CHECK_EQUAL(re[2], 0.0); | |
210 BOOST_CHECK_CLOSE(re[3], 1.0, 1e-12); | |
211 BOOST_CHECK_EQUAL(im[0], 0.0); | |
212 BOOST_CHECK_CLOSE(im[1], -2.0, 1e-12); | |
213 BOOST_CHECK_EQUAL(im[2], 0.0); | |
214 BOOST_CHECK_CLOSE(im[3], 2.0, 1e-12); | |
215 double back[4]; | |
216 double backim[4]; | |
217 FFT(4).process(true, re, im, back, backim); | |
218 COMPARE_ARRAY(back, in); | |
219 COMPARE_CONST(backim, 0.0); | |
220 } | |
221 | |
222 BOOST_AUTO_TEST_CASE(r_sineCosine) | |
223 { | |
224 // Sine and cosine mixed | |
225 double in[] = { 0.5, 1, -0.5, -1 }; | |
226 double re[] = { 999, 999, 999, 999 }; | |
227 double im[] = { 999, 999, 999, 999 }; | |
228 FFTReal(4).forward(in, re, im); | |
229 BOOST_CHECK_EQUAL(re[0], 0.0); | |
230 BOOST_CHECK_CLOSE(re[1], 1.0, 1e-12); | |
231 BOOST_CHECK_EQUAL(re[2], 0.0); | |
232 BOOST_CHECK_CLOSE(re[3], 1.0, 1e-12); | |
233 BOOST_CHECK_EQUAL(im[0], 0.0); | |
234 BOOST_CHECK_CLOSE(im[1], -2.0, 1e-12); | |
235 BOOST_CHECK_EQUAL(im[2], 0.0); | |
236 BOOST_CHECK_CLOSE(im[3], 2.0, 1e-12); | |
237 double back[4]; | |
238 // check conjugates are reconstructed | |
239 re[3] = 999; | |
240 im[3] = 999; | |
241 FFTReal(4).inverse(re, im, back); | |
242 COMPARE_ARRAY(back, in); | |
243 } | |
244 | |
245 BOOST_AUTO_TEST_CASE(nyquist) | |
246 { | |
247 double in[] = { 1, -1, 1, -1 }; | |
248 double re[] = { 999, 999, 999, 999 }; | |
249 double im[] = { 999, 999, 999, 999 }; | |
250 FFT(4).process(false, in, 0, re, im); | |
251 BOOST_CHECK_EQUAL(re[0], 0.0); | |
252 BOOST_CHECK_EQUAL(re[1], 0.0); | |
253 BOOST_CHECK_EQUAL(re[2], 4.0); | |
254 BOOST_CHECK_EQUAL(re[3], 0.0); | |
255 COMPARE_CONST(im, 0.0); | |
256 double back[4]; | |
257 double backim[4]; | |
258 FFT(4).process(true, re, im, back, backim); | |
259 COMPARE_ARRAY(back, in); | |
260 COMPARE_CONST(backim, 0.0); | |
261 } | |
262 | |
263 BOOST_AUTO_TEST_CASE(r_nyquist) | |
264 { | |
265 double in[] = { 1, -1, 1, -1 }; | |
266 double re[] = { 999, 999, 999, 999 }; | |
267 double im[] = { 999, 999, 999, 999 }; | |
268 FFTReal(4).forward(in, re, im); | |
269 BOOST_CHECK_EQUAL(re[0], 0.0); | |
270 BOOST_CHECK_EQUAL(re[1], 0.0); | |
271 BOOST_CHECK_EQUAL(re[2], 4.0); | |
272 BOOST_CHECK_EQUAL(re[3], 0.0); | |
273 COMPARE_CONST(im, 0.0); | |
274 double back[4]; | |
275 // check conjugates are reconstructed | |
276 re[3] = 999; | |
277 im[3] = 999; | |
278 FFTReal(4).inverse(re, im, back); | |
279 COMPARE_ARRAY(back, in); | |
280 } | |
281 | |
282 BOOST_AUTO_TEST_CASE(dirac) | |
283 { | |
284 double in[] = { 1, 0, 0, 0 }; | |
285 double re[] = { 999, 999, 999, 999 }; | |
286 double im[] = { 999, 999, 999, 999 }; | |
287 FFT(4).process(false, in, 0, re, im); | |
288 BOOST_CHECK_EQUAL(re[0], 1.0); | |
289 BOOST_CHECK_EQUAL(re[1], 1.0); | |
290 BOOST_CHECK_EQUAL(re[2], 1.0); | |
291 BOOST_CHECK_EQUAL(re[3], 1.0); | |
292 COMPARE_CONST(im, 0.0); | |
293 double back[4]; | |
294 double backim[4]; | |
295 FFT(4).process(true, re, im, back, backim); | |
296 COMPARE_ARRAY(back, in); | |
297 COMPARE_CONST(backim, 0.0); | |
298 } | |
299 | |
300 BOOST_AUTO_TEST_CASE(r_dirac) | |
301 { | |
302 double in[] = { 1, 0, 0, 0 }; | |
303 double re[] = { 999, 999, 999, 999 }; | |
304 double im[] = { 999, 999, 999, 999 }; | |
305 FFTReal(4).forward(in, re, im); | |
306 BOOST_CHECK_EQUAL(re[0], 1.0); | |
307 BOOST_CHECK_EQUAL(re[1], 1.0); | |
308 BOOST_CHECK_EQUAL(re[2], 1.0); | |
309 BOOST_CHECK_EQUAL(re[3], 1.0); | |
310 COMPARE_CONST(im, 0.0); | |
311 double back[4]; | |
312 // check conjugates are reconstructed | |
313 re[3] = 999; | |
314 im[3] = 999; | |
315 FFTReal(4).inverse(re, im, back); | |
316 COMPARE_ARRAY(back, in); | |
146 } | 317 } |
147 | 318 |
148 BOOST_AUTO_TEST_SUITE_END() | 319 BOOST_AUTO_TEST_SUITE_END() |
149 | 320 |