Mercurial > hg > svcore
comparison data/model/test/TestFFTModel.h @ 1105:a27b1ce86e4f 3.0-integration
Merge from branch simple-fft-model
author | Chris Cannam |
---|---|
date | Fri, 26 Jun 2015 14:07:25 +0100 |
parents | 393134235fa0 |
children | 457a1a619c5f |
comparison
equal
deleted
inserted
replaced
1088:5fab8e4f5f19 | 1105:a27b1ce86e4f |
---|---|
38 void test(DenseTimeValueModel *model, | 38 void test(DenseTimeValueModel *model, |
39 WindowType window, int windowSize, int windowIncrement, int fftSize, | 39 WindowType window, int windowSize, int windowIncrement, int fftSize, |
40 int columnNo, vector<vector<complex<float>>> expectedValues, | 40 int columnNo, vector<vector<complex<float>>> expectedValues, |
41 int expectedWidth) { | 41 int expectedWidth) { |
42 for (int ch = 0; in_range_for(expectedValues, ch); ++ch) { | 42 for (int ch = 0; in_range_for(expectedValues, ch); ++ch) { |
43 for (int polar = 0; polar <= 1; ++polar) { | 43 FFTModel fftm(model, ch, window, windowSize, windowIncrement, fftSize); |
44 FFTModel fftm(model, ch, window, windowSize, windowIncrement, | 44 QCOMPARE(fftm.getWidth(), expectedWidth); |
45 fftSize, bool(polar)); | 45 int hs1 = fftSize/2 + 1; |
46 QCOMPARE(fftm.getWidth(), expectedWidth); | 46 QCOMPARE(fftm.getHeight(), hs1); |
47 int hs1 = fftSize/2 + 1; | 47 vector<float> reals(hs1 + 1, 0.f); |
48 QCOMPARE(fftm.getHeight(), hs1); | 48 vector<float> imags(hs1 + 1, 0.f); |
49 vector<float> reals(hs1 + 1, 0.f); | 49 reals[hs1] = 999.f; // overrun guards |
50 vector<float> imags(hs1 + 1, 0.f); | 50 imags[hs1] = 999.f; |
51 reals[hs1] = 999.f; // overrun guards | 51 for (int stepThrough = 0; stepThrough <= 1; ++stepThrough) { |
52 imags[hs1] = 999.f; | 52 if (stepThrough) { |
53 // Read through the columns in order instead of | |
54 // randomly accessing the one we want. This is to | |
55 // exercise the case where the FFT model saves | |
56 // part of each input frame and moves along by | |
57 // only the non-overlapping distance | |
58 for (int sc = 0; sc < columnNo; ++sc) { | |
59 fftm.getValuesAt(sc, &reals[0], &imags[0]); | |
60 } | |
61 } | |
53 fftm.getValuesAt(columnNo, &reals[0], &imags[0]); | 62 fftm.getValuesAt(columnNo, &reals[0], &imags[0]); |
54 for (int i = 0; i < hs1; ++i) { | 63 for (int i = 0; i < hs1; ++i) { |
55 float eRe = expectedValues[ch][i].real(); | 64 float eRe = expectedValues[ch][i].real(); |
56 float eIm = expectedValues[ch][i].imag(); | 65 float eIm = expectedValues[ch][i].imag(); |
57 if (reals[i] != eRe || imags[i] != eIm) { | 66 float thresh = 1e-5f; |
67 if (abs(reals[i] - eRe) > thresh || | |
68 abs(imags[i] - eIm) > thresh) { | |
58 cerr << "ERROR: output is not as expected for column " | 69 cerr << "ERROR: output is not as expected for column " |
59 << i << " in channel " << ch << " (polar store = " | 70 << i << " in channel " << ch << " (stepThrough = " |
60 << polar << ")" << endl; | 71 << stepThrough << ")" << endl; |
61 cerr << "expected : "; | 72 cerr << "expected : "; |
62 for (int j = 0; j < hs1; ++j) { | 73 for (int j = 0; j < hs1; ++j) { |
63 cerr << expectedValues[ch][j] << " "; | 74 cerr << expectedValues[ch][j] << " "; |
64 } | 75 } |
65 cerr << "\nactual : "; | 76 cerr << "\nactual : "; |
66 for (int j = 0; j < hs1; ++j) { | 77 for (int j = 0; j < hs1; ++j) { |
67 cerr << complex<float>(reals[j], imags[j]) << " "; | 78 cerr << complex<float>(reals[j], imags[j]) << " "; |
68 } | 79 } |
69 cerr << endl; | 80 cerr << endl; |
70 } | 81 } |
71 QCOMPARE(reals[i], eRe); | 82 COMPARE_FUZZIER_F(reals[i], eRe); |
72 QCOMPARE(imags[i], eIm); | 83 COMPARE_FUZZIER_F(imags[i], eIm); |
73 } | 84 } |
74 QCOMPARE(reals[hs1], 999.f); | 85 QCOMPARE(reals[hs1], 999.f); |
75 QCOMPARE(imags[hs1], 999.f); | 86 QCOMPARE(imags[hs1], 999.f); |
76 } | 87 } |
77 } | 88 } |
78 } | 89 } |
79 | 90 |
80 private slots: | 91 private slots: |
81 | 92 |
82 // NB. FFTModel columns are centred on the sample frame, and in | 93 // NB. FFTModel columns are centred on the sample frame, and in |
83 // particular this means column 0 is centred at sample 0 (i.e. it | 94 // particular this means column 0 is centred at sample 0 (i.e. it |
84 // contains only half the window-size worth of real samples, the | 95 // contains only half the window-size worth of real samples, the |
86 // these tests we are padding our signal with half a window of | 97 // these tests we are padding our signal with half a window of |
87 // zeros, in order that the result for column 0 is all zeros | 98 // zeros, in order that the result for column 0 is all zeros |
88 // (rather than something with a step in it that is harder to | 99 // (rather than something with a step in it that is harder to |
89 // reason about the FFT of) and the results for subsequent columns | 100 // reason about the FFT of) and the results for subsequent columns |
90 // are those of our expected signal. | 101 // are those of our expected signal. |
91 | 102 |
92 void dc_simple_rect() { | 103 void dc_simple_rect() { |
93 MockWaveModel mwm({ DC }, 16, 4); | 104 MockWaveModel mwm({ DC }, 16, 4); |
94 test(&mwm, RectangularWindow, 8, 8, 8, 0, | 105 test(&mwm, RectangularWindow, 8, 8, 8, 0, |
95 { { {}, {}, {}, {}, {} } }, 4); | 106 { { {}, {}, {}, {}, {} } }, 4); |
96 test(&mwm, RectangularWindow, 8, 8, 8, 1, | 107 test(&mwm, RectangularWindow, 8, 8, 8, 1, |
97 { { { 4.f, 0.f }, {}, {}, {}, {} } }, 4); | 108 { { { 4.f, 0.f }, {}, {}, {}, {} } }, 4); |
98 test(&mwm, RectangularWindow, 8, 8, 8, 2, | 109 test(&mwm, RectangularWindow, 8, 8, 8, 2, |
99 { { { 4.f, 0.f }, {}, {}, {}, {} } }, 4); | 110 { { { 4.f, 0.f }, {}, {}, {}, {} } }, 4); |
100 test(&mwm, RectangularWindow, 8, 8, 8, 3, | 111 test(&mwm, RectangularWindow, 8, 8, 8, 3, |
101 { { { }, {}, {}, {}, {} } }, 4); | 112 { { {}, {}, {}, {}, {} } }, 4); |
102 } | 113 } |
103 | 114 |
104 void dc_simple_hann() { | 115 void dc_simple_hann() { |
105 // The Hann window function is a simple sinusoid with period | 116 // The Hann window function is a simple sinusoid with period |
106 // equal to twice the window size, and it halves the DC energy | 117 // equal to twice the window size, and it halves the DC energy |
110 test(&mwm, HanningWindow, 8, 8, 8, 1, | 121 test(&mwm, HanningWindow, 8, 8, 8, 1, |
111 { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 4); | 122 { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 4); |
112 test(&mwm, HanningWindow, 8, 8, 8, 2, | 123 test(&mwm, HanningWindow, 8, 8, 8, 2, |
113 { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 4); | 124 { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 4); |
114 test(&mwm, HanningWindow, 8, 8, 8, 3, | 125 test(&mwm, HanningWindow, 8, 8, 8, 3, |
115 { { { }, {}, {}, {}, {} } }, 4); | 126 { { {}, {}, {}, {}, {} } }, 4); |
127 } | |
128 | |
129 void dc_simple_hann_halfoverlap() { | |
130 MockWaveModel mwm({ DC }, 16, 4); | |
131 test(&mwm, HanningWindow, 8, 4, 8, 0, | |
132 { { {}, {}, {}, {}, {} } }, 7); | |
133 test(&mwm, HanningWindow, 8, 4, 8, 2, | |
134 { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 7); | |
135 test(&mwm, HanningWindow, 8, 4, 8, 3, | |
136 { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 7); | |
137 test(&mwm, HanningWindow, 8, 4, 8, 6, | |
138 { { {}, {}, {}, {}, {} } }, 7); | |
139 } | |
140 | |
141 void sine_simple_rect() { | |
142 MockWaveModel mwm({ Sine }, 16, 4); | |
143 // Sine: output is purely imaginary. Note the sign is flipped | |
144 // (normally the first half of the output would have negative | |
145 // sign for a sine starting at 0) because the model does an | |
146 // FFT shift to centre the phase | |
147 test(&mwm, RectangularWindow, 8, 8, 8, 0, | |
148 { { {}, {}, {}, {}, {} } }, 4); | |
149 test(&mwm, RectangularWindow, 8, 8, 8, 1, | |
150 { { {}, { 0.f, 2.f }, {}, {}, {} } }, 4); | |
151 test(&mwm, RectangularWindow, 8, 8, 8, 2, | |
152 { { {}, { 0.f, 2.f }, {}, {}, {} } }, 4); | |
153 test(&mwm, RectangularWindow, 8, 8, 8, 3, | |
154 { { {}, {}, {}, {}, {} } }, 4); | |
155 } | |
156 | |
157 void cosine_simple_rect() { | |
158 MockWaveModel mwm({ Cosine }, 16, 4); | |
159 // Cosine: output is purely real. Note the sign is flipped | |
160 // because the model does an FFT shift to centre the phase | |
161 test(&mwm, RectangularWindow, 8, 8, 8, 0, | |
162 { { {}, {}, {}, {}, {} } }, 4); | |
163 test(&mwm, RectangularWindow, 8, 8, 8, 1, | |
164 { { {}, { -2.f, 0.f }, {}, {}, {} } }, 4); | |
165 test(&mwm, RectangularWindow, 8, 8, 8, 2, | |
166 { { {}, { -2.f, 0.f }, {}, {}, {} } }, 4); | |
167 test(&mwm, RectangularWindow, 8, 8, 8, 3, | |
168 { { {}, {}, {}, {}, {} } }, 4); | |
169 } | |
170 | |
171 void twochan_simple_rect() { | |
172 MockWaveModel mwm({ Sine, Cosine }, 16, 4); | |
173 // Test that the two channels are read and converted separately | |
174 test(&mwm, RectangularWindow, 8, 8, 8, 0, | |
175 { | |
176 { {}, {}, {}, {}, {} }, | |
177 { {}, {}, {}, {}, {} } | |
178 }, 4); | |
179 test(&mwm, RectangularWindow, 8, 8, 8, 1, | |
180 { | |
181 { {}, { 0.f, 2.f }, {}, {}, {} }, | |
182 { {}, { -2.f, 0.f }, {}, {}, {} } | |
183 }, 4); | |
184 test(&mwm, RectangularWindow, 8, 8, 8, 2, | |
185 { | |
186 { {}, { 0.f, 2.f }, {}, {}, {} }, | |
187 { {}, { -2.f, 0.f }, {}, {}, {} } | |
188 }, 4); | |
189 test(&mwm, RectangularWindow, 8, 8, 8, 3, | |
190 { | |
191 { {}, {}, {}, {}, {} }, | |
192 { {}, {}, {}, {}, {} } | |
193 }, 4); | |
194 } | |
195 | |
196 void nyquist_simple_rect() { | |
197 MockWaveModel mwm({ Nyquist }, 16, 4); | |
198 // Again, the sign is flipped. This has the same amount of | |
199 // energy as the DC example | |
200 test(&mwm, RectangularWindow, 8, 8, 8, 0, | |
201 { { {}, {}, {}, {}, {} } }, 4); | |
202 test(&mwm, RectangularWindow, 8, 8, 8, 1, | |
203 { { {}, {}, {}, {}, { -4.f, 0.f } } }, 4); | |
204 test(&mwm, RectangularWindow, 8, 8, 8, 2, | |
205 { { {}, {}, {}, {}, { -4.f, 0.f } } }, 4); | |
206 test(&mwm, RectangularWindow, 8, 8, 8, 3, | |
207 { { {}, {}, {}, {}, {} } }, 4); | |
208 } | |
209 | |
210 void dirac_simple_rect() { | |
211 MockWaveModel mwm({ Dirac }, 16, 4); | |
212 // The window scales by 0.5 and some signs are flipped. Only | |
213 // column 1 has any data (the single impulse). | |
214 test(&mwm, RectangularWindow, 8, 8, 8, 0, | |
215 { { {}, {}, {}, {}, {} } }, 4); | |
216 test(&mwm, RectangularWindow, 8, 8, 8, 1, | |
217 { { { 0.5f, 0.f }, { -0.5f, 0.f }, { 0.5f, 0.f }, { -0.5f, 0.f }, { 0.5f, 0.f } } }, 4); | |
218 test(&mwm, RectangularWindow, 8, 8, 8, 2, | |
219 { { {}, {}, {}, {}, {} } }, 4); | |
220 test(&mwm, RectangularWindow, 8, 8, 8, 3, | |
221 { { {}, {}, {}, {}, {} } }, 4); | |
222 } | |
223 | |
224 void dirac_simple_rect_2() { | |
225 MockWaveModel mwm({ Dirac }, 16, 8); | |
226 // With 8 samples padding, the FFT shift places the first | |
227 // Dirac impulse at the start of column 1, thus giving all | |
228 // positive values | |
229 test(&mwm, RectangularWindow, 8, 8, 8, 0, | |
230 { { {}, {}, {}, {}, {} } }, 5); | |
231 test(&mwm, RectangularWindow, 8, 8, 8, 1, | |
232 { { { 0.5f, 0.f }, { 0.5f, 0.f }, { 0.5f, 0.f }, { 0.5f, 0.f }, { 0.5f, 0.f } } }, 5); | |
233 test(&mwm, RectangularWindow, 8, 8, 8, 2, | |
234 { { {}, {}, {}, {}, {} } }, 5); | |
235 test(&mwm, RectangularWindow, 8, 8, 8, 3, | |
236 { { {}, {}, {}, {}, {} } }, 5); | |
237 test(&mwm, RectangularWindow, 8, 8, 8, 4, | |
238 { { {}, {}, {}, {}, {} } }, 5); | |
239 } | |
240 | |
241 void dirac_simple_rect_halfoverlap() { | |
242 MockWaveModel mwm({ Dirac }, 16, 4); | |
243 test(&mwm, RectangularWindow, 8, 4, 8, 0, | |
244 { { {}, {}, {}, {}, {} } }, 7); | |
245 test(&mwm, RectangularWindow, 8, 4, 8, 1, | |
246 { { { 0.5f, 0.f }, { 0.5f, 0.f }, { 0.5f, 0.f }, { 0.5f, 0.f }, { 0.5f, 0.f } } }, 7); | |
247 test(&mwm, RectangularWindow, 8, 4, 8, 2, | |
248 { { { 0.5f, 0.f }, { -0.5f, 0.f }, { 0.5f, 0.f }, { -0.5f, 0.f }, { 0.5f, 0.f } } }, 7); | |
249 test(&mwm, RectangularWindow, 8, 4, 8, 3, | |
250 { { {}, {}, {}, {}, {} } }, 7); | |
116 } | 251 } |
117 | 252 |
118 }; | 253 }; |
119 | 254 |
120 #endif | 255 #endif |