annotate data/model/test/TestFFTModel.h @ 1088:5fab8e4f5f19

Start making the FFT model tests into proper tests
author Chris Cannam
date Fri, 12 Jun 2015 12:41:19 +0100
parents 9f4505ac9072
children 655cd4e68e9a 1517d4c60e88
rev   line source
Chris@1086 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1086 2
Chris@1086 3 /*
Chris@1086 4 Sonic Visualiser
Chris@1086 5 An audio file viewer and annotation editor.
Chris@1086 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1086 7
Chris@1086 8 This program is free software; you can redistribute it and/or
Chris@1086 9 modify it under the terms of the GNU General Public License as
Chris@1086 10 published by the Free Software Foundation; either version 2 of the
Chris@1086 11 License, or (at your option) any later version. See the file
Chris@1086 12 COPYING included with this distribution for more information.
Chris@1086 13 */
Chris@1086 14
Chris@1086 15 #ifndef TEST_FFT_MODEL_H
Chris@1086 16 #define TEST_FFT_MODEL_H
Chris@1086 17
Chris@1086 18 #include "../FFTModel.h"
Chris@1086 19
Chris@1086 20 #include "MockWaveModel.h"
Chris@1086 21
Chris@1086 22 #include "Compares.h"
Chris@1086 23
Chris@1086 24 #include <QObject>
Chris@1086 25 #include <QtTest>
Chris@1086 26 #include <QDir>
Chris@1086 27
Chris@1086 28 #include <iostream>
Chris@1088 29 #include <complex>
Chris@1086 30
Chris@1086 31 using namespace std;
Chris@1086 32
Chris@1086 33 class TestFFTModel : public QObject
Chris@1086 34 {
Chris@1086 35 Q_OBJECT
Chris@1086 36
Chris@1088 37 private:
Chris@1088 38 void test(DenseTimeValueModel *model,
Chris@1088 39 WindowType window, int windowSize, int windowIncrement, int fftSize,
Chris@1088 40 int columnNo, vector<vector<complex<float>>> expectedValues,
Chris@1088 41 int expectedWidth) {
Chris@1088 42 for (int ch = 0; in_range_for(expectedValues, ch); ++ch) {
Chris@1088 43 for (int polar = 0; polar <= 1; ++polar) {
Chris@1088 44 FFTModel fftm(model, ch, window, windowSize, windowIncrement,
Chris@1088 45 fftSize, bool(polar));
Chris@1088 46 QCOMPARE(fftm.getWidth(), expectedWidth);
Chris@1088 47 int hs1 = fftSize/2 + 1;
Chris@1088 48 QCOMPARE(fftm.getHeight(), hs1);
Chris@1088 49 vector<float> reals(hs1 + 1, 0.f);
Chris@1088 50 vector<float> imags(hs1 + 1, 0.f);
Chris@1088 51 reals[hs1] = 999.f; // overrun guards
Chris@1088 52 imags[hs1] = 999.f;
Chris@1088 53 fftm.getValuesAt(columnNo, &reals[0], &imags[0]);
Chris@1088 54 for (int i = 0; i < hs1; ++i) {
Chris@1088 55 float eRe = expectedValues[ch][i].real();
Chris@1088 56 float eIm = expectedValues[ch][i].imag();
Chris@1088 57 if (reals[i] != eRe || imags[i] != eIm) {
Chris@1088 58 cerr << "ERROR: output is not as expected for column "
Chris@1088 59 << i << " in channel " << ch << " (polar store = "
Chris@1088 60 << polar << ")" << endl;
Chris@1088 61 cerr << "expected : ";
Chris@1088 62 for (int j = 0; j < hs1; ++j) {
Chris@1088 63 cerr << expectedValues[ch][j] << " ";
Chris@1088 64 }
Chris@1088 65 cerr << "\nactual : ";
Chris@1088 66 for (int j = 0; j < hs1; ++j) {
Chris@1088 67 cerr << complex<float>(reals[j], imags[j]) << " ";
Chris@1088 68 }
Chris@1088 69 cerr << endl;
Chris@1088 70 }
Chris@1088 71 QCOMPARE(reals[i], eRe);
Chris@1088 72 QCOMPARE(imags[i], eIm);
Chris@1088 73 }
Chris@1088 74 QCOMPARE(reals[hs1], 999.f);
Chris@1088 75 QCOMPARE(imags[hs1], 999.f);
Chris@1088 76 }
Chris@1088 77 }
Chris@1088 78 }
Chris@1088 79
Chris@1086 80 private slots:
Chris@1086 81
Chris@1088 82 // NB. FFTModel columns are centred on the sample frame, and in
Chris@1088 83 // particular this means column 0 is centred at sample 0 (i.e. it
Chris@1088 84 // contains only half the window-size worth of real samples, the
Chris@1088 85 // others are 0-valued from before the origin). Generally in
Chris@1088 86 // these tests we are padding our signal with half a window of
Chris@1088 87 // zeros, in order that the result for column 0 is all zeros
Chris@1088 88 // (rather than something with a step in it that is harder to
Chris@1088 89 // reason about the FFT of) and the results for subsequent columns
Chris@1088 90 // are those of our expected signal.
Chris@1088 91
Chris@1088 92 void dc_simple_rect() {
Chris@1088 93 MockWaveModel mwm({ DC }, 16, 4);
Chris@1088 94 test(&mwm, RectangularWindow, 8, 8, 8, 0,
Chris@1088 95 { { {}, {}, {}, {}, {} } }, 4);
Chris@1088 96 test(&mwm, RectangularWindow, 8, 8, 8, 1,
Chris@1088 97 { { { 4.f, 0.f }, {}, {}, {}, {} } }, 4);
Chris@1088 98 test(&mwm, RectangularWindow, 8, 8, 8, 2,
Chris@1088 99 { { { 4.f, 0.f }, {}, {}, {}, {} } }, 4);
Chris@1088 100 test(&mwm, RectangularWindow, 8, 8, 8, 3,
Chris@1088 101 { { { }, {}, {}, {}, {} } }, 4);
Chris@1088 102 }
Chris@1088 103
Chris@1088 104 void dc_simple_hann() {
Chris@1088 105 // The Hann window function is a simple sinusoid with period
Chris@1088 106 // equal to twice the window size, and it halves the DC energy
Chris@1088 107 MockWaveModel mwm({ DC }, 16, 4);
Chris@1088 108 test(&mwm, HanningWindow, 8, 8, 8, 0,
Chris@1088 109 { { {}, {}, {}, {}, {} } }, 4);
Chris@1088 110 test(&mwm, HanningWindow, 8, 8, 8, 1,
Chris@1088 111 { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 4);
Chris@1088 112 test(&mwm, HanningWindow, 8, 8, 8, 2,
Chris@1088 113 { { { 4.f, 0.f }, { 2.f, 0.f }, {}, {}, {} } }, 4);
Chris@1088 114 test(&mwm, HanningWindow, 8, 8, 8, 3,
Chris@1088 115 { { { }, {}, {}, {}, {} } }, 4);
Chris@1086 116 }
Chris@1086 117
Chris@1086 118 };
Chris@1086 119
Chris@1086 120 #endif