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