comparison data/model/test/TestFFTModel.h @ 1091:bdebff3265ae simple-fft-model

Simplest naive FFTModel implementation (+ fill in tests)
author Chris Cannam
date Fri, 12 Jun 2015 18:08:57 +0100
parents 655cd4e68e9a
children 0c351e061945
comparison
equal deleted inserted replaced
1090:420fc961c0c4 1091:bdebff3265ae
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 fftm.getValuesAt(columnNo, &reals[0], &imags[0]);
52 imags[hs1] = 999.f; 52 for (int i = 0; i < hs1; ++i) {
53 fftm.getValuesAt(columnNo, &reals[0], &imags[0]); 53 float eRe = expectedValues[ch][i].real();
54 for (int i = 0; i < hs1; ++i) { 54 float eIm = expectedValues[ch][i].imag();
55 float eRe = expectedValues[ch][i].real(); 55 float thresh = 1e-5f;
56 float eIm = expectedValues[ch][i].imag(); 56 if (abs(reals[i] - eRe) > thresh ||
57 if (reals[i] != eRe || imags[i] != eIm) { 57 abs(imags[i] - eIm) > thresh) {
58 cerr << "ERROR: output is not as expected for column " 58 cerr << "ERROR: output is not as expected for column "
59 << i << " in channel " << ch << " (polar store = " 59 << i << " in channel " << ch << endl;
60 << polar << ")" << endl; 60 cerr << "expected : ";
61 cerr << "expected : "; 61 for (int j = 0; j < hs1; ++j) {
62 for (int j = 0; j < hs1; ++j) { 62 cerr << expectedValues[ch][j] << " ";
63 cerr << expectedValues[ch][j] << " ";
64 }
65 cerr << "\nactual : ";
66 for (int j = 0; j < hs1; ++j) {
67 cerr << complex<float>(reals[j], imags[j]) << " ";
68 }
69 cerr << endl;
70 } 63 }
71 QCOMPARE(reals[i], eRe); 64 cerr << "\nactual : ";
72 QCOMPARE(imags[i], eIm); 65 for (int j = 0; j < hs1; ++j) {
66 cerr << complex<float>(reals[j], imags[j]) << " ";
67 }
68 cerr << endl;
73 } 69 }
74 QCOMPARE(reals[hs1], 999.f); 70 COMPARE_FUZZIER_F(reals[i], eRe);
75 QCOMPARE(imags[hs1], 999.f); 71 COMPARE_FUZZIER_F(imags[i], eIm);
76 } 72 }
73 QCOMPARE(reals[hs1], 999.f);
74 QCOMPARE(imags[hs1], 999.f);
77 } 75 }
78 } 76 }
79 77
80 private slots: 78 private slots:
81 79
115 { { {}, {}, {}, {}, {} } }, 4); 113 { { {}, {}, {}, {}, {} } }, 4);
116 } 114 }
117 115
118 void sine_simple_rect() { 116 void sine_simple_rect() {
119 MockWaveModel mwm({ Sine }, 16, 4); 117 MockWaveModel mwm({ Sine }, 16, 4);
118 // Sine: output is purely imaginary. Note the sign is flipped
119 // (normally the first half of the output would have negative
120 // sign for a sine starting at 0) because the model does an
121 // FFT shift to centre the phase
120 test(&mwm, RectangularWindow, 8, 8, 8, 0, 122 test(&mwm, RectangularWindow, 8, 8, 8, 0,
121 { { {}, {}, {}, {}, {} } }, 4); 123 { { {}, {}, {}, {}, {} } }, 4);
122 test(&mwm, RectangularWindow, 8, 8, 8, 1, 124 test(&mwm, RectangularWindow, 8, 8, 8, 1,
123 { { {}, { 0.f, 2.f }, {}, {}, {} } }, 4); 125 { { {}, { 0.f, 2.f }, {}, {}, {} } }, 4);
124 test(&mwm, RectangularWindow, 8, 8, 8, 2, 126 test(&mwm, RectangularWindow, 8, 8, 8, 2,
127 { { {}, {}, {}, {}, {} } }, 4); 129 { { {}, {}, {}, {}, {} } }, 4);
128 } 130 }
129 131
130 void cosine_simple_rect() { 132 void cosine_simple_rect() {
131 MockWaveModel mwm({ Cosine }, 16, 4); 133 MockWaveModel mwm({ Cosine }, 16, 4);
134 // Cosine: output is purely real. Note the sign is flipped
135 // because the model does an FFT shift to centre the phase
132 test(&mwm, RectangularWindow, 8, 8, 8, 0, 136 test(&mwm, RectangularWindow, 8, 8, 8, 0,
133 { { {}, {}, {}, {}, {} } }, 4); 137 { { {}, {}, {}, {}, {} } }, 4);
134 test(&mwm, RectangularWindow, 8, 8, 8, 1, 138 test(&mwm, RectangularWindow, 8, 8, 8, 1,
135 { { {}, { 2.f, 0.f }, {}, {}, {} } }, 4); 139 { { {}, { -2.f, 0.f }, {}, {}, {} } }, 4);
136 test(&mwm, RectangularWindow, 8, 8, 8, 2, 140 test(&mwm, RectangularWindow, 8, 8, 8, 2,
137 { { {}, { 2.f, 0.f }, {}, {}, {} } }, 4); 141 { { {}, { -2.f, 0.f }, {}, {}, {} } }, 4);
138 test(&mwm, RectangularWindow, 8, 8, 8, 3, 142 test(&mwm, RectangularWindow, 8, 8, 8, 3,
139 { { {}, {}, {}, {}, {} } }, 4); 143 { { {}, {}, {}, {}, {} } }, 4);
140 } 144 }
141 145
142 void nyquist_simple_rect() { 146 void nyquist_simple_rect() {
143 MockWaveModel mwm({ Nyquist }, 16, 4); 147 MockWaveModel mwm({ Nyquist }, 16, 4);
148 // Again, the sign is flipped. This has the same amount of
149 // energy as the DC example
144 test(&mwm, RectangularWindow, 8, 8, 8, 0, 150 test(&mwm, RectangularWindow, 8, 8, 8, 0,
145 { { {}, {}, {}, {}, {} } }, 4); 151 { { {}, {}, {}, {}, {} } }, 4);
146 test(&mwm, RectangularWindow, 8, 8, 8, 1, 152 test(&mwm, RectangularWindow, 8, 8, 8, 1,
147 { { {}, {}, {}, {}, { 2.f, 0.f } } }, 4); 153 { { {}, {}, {}, {}, { -4.f, 0.f } } }, 4);
148 test(&mwm, RectangularWindow, 8, 8, 8, 2, 154 test(&mwm, RectangularWindow, 8, 8, 8, 2,
149 { { {}, {}, {}, {}, { 2.f, 0.f } } }, 4); 155 { { {}, {}, {}, {}, { -4.f, 0.f } } }, 4);
150 test(&mwm, RectangularWindow, 8, 8, 8, 3, 156 test(&mwm, RectangularWindow, 8, 8, 8, 3,
151 { { {}, {}, {}, {}, {} } }, 4); 157 { { {}, {}, {}, {}, {} } }, 4);
152 } 158 }
153 159
154 void dirac_simple_rect() { 160 void dirac_simple_rect() {
155 MockWaveModel mwm({ Dirac }, 16, 4); 161 MockWaveModel mwm({ Dirac }, 16, 4);
162 // The window scales by 0.5 and some signs are flipped. Only
163 // column 1 has any data (the single impulse).
156 test(&mwm, RectangularWindow, 8, 8, 8, 0, 164 test(&mwm, RectangularWindow, 8, 8, 8, 0,
157 { { {}, {}, {}, {}, {} } }, 4); 165 { { {}, {}, {}, {}, {} } }, 4);
158 test(&mwm, RectangularWindow, 8, 8, 8, 1, 166 test(&mwm, RectangularWindow, 8, 8, 8, 1,
159 { { { 1.f, 0.f }, { 1.f, 0.f }, { 1.f, 0.f }, { 1.f, 0.f }, { 1.f, 0.f } } }, 4); 167 { { { 0.5f, 0.f }, { -0.5f, 0.f }, { 0.5f, 0.f }, { -0.5f, 0.f }, { 0.5f, 0.f } } }, 4);
160 test(&mwm, RectangularWindow, 8, 8, 8, 2, 168 test(&mwm, RectangularWindow, 8, 8, 8, 2,
161 { { { 1.f, 0.f }, { 1.f, 0.f }, { 1.f, 0.f }, { 1.f, 0.f }, { 1.f, 0.f } } }, 4); 169 { { {}, {}, {}, {}, {} } }, 4);
162 test(&mwm, RectangularWindow, 8, 8, 8, 3, 170 test(&mwm, RectangularWindow, 8, 8, 8, 3,
163 { { {}, {}, {}, {}, {} } }, 4); 171 { { {}, {}, {}, {}, {} } }, 4);
172 }
173
174 void dirac_simple_rect_2() {
175 MockWaveModel mwm({ Dirac }, 16, 8);
176 // With 8 samples padding, the FFT shift places the first
177 // Dirac impulse at the start of column 1, thus giving all
178 // positive values
179 test(&mwm, RectangularWindow, 8, 8, 8, 0,
180 { { {}, {}, {}, {}, {} } }, 5);
181 test(&mwm, RectangularWindow, 8, 8, 8, 1,
182 { { { 0.5f, 0.f }, { 0.5f, 0.f }, { 0.5f, 0.f }, { 0.5f, 0.f }, { 0.5f, 0.f } } }, 5);
183 test(&mwm, RectangularWindow, 8, 8, 8, 2,
184 { { {}, {}, {}, {}, {} } }, 5);
185 test(&mwm, RectangularWindow, 8, 8, 8, 3,
186 { { {}, {}, {}, {}, {} } }, 5);
187 test(&mwm, RectangularWindow, 8, 8, 8, 4,
188 { { {}, {}, {}, {}, {} } }, 5);
164 } 189 }
165 190
166 }; 191 };
167 192
168 #endif 193 #endif