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