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