annotate test/TestCQFrequency.cpp @ 139:1aef2b746c64

More (failing) tests
author Chris Cannam <c.cannam@qmul.ac.uk>
date Mon, 19 May 2014 17:46:40 +0100
parents cb0f0e317a33
children 9bf76fc43844
rev   line source
c@131 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@131 2
c@131 3 #include "cq/CQSpectrogram.h"
c@131 4
c@131 5 #include "dsp/Window.h"
c@131 6
c@131 7 #include <cmath>
c@131 8 #include <vector>
c@132 9 #include <iostream>
c@131 10
c@131 11 using std::vector;
c@132 12 using std::cerr;
c@132 13 using std::endl;
c@131 14
c@131 15 #define BOOST_TEST_DYN_LINK
c@131 16 #define BOOST_TEST_MAIN
c@131 17
c@131 18 #include <boost/test/unit_test.hpp>
c@131 19
c@131 20 BOOST_AUTO_TEST_SUITE(TestCQFrequency)
c@131 21
c@131 22 // The principle here is to feed a single windowed sinusoid into a
c@131 23 // small CQ transform and check that the output has its peak bin at
c@133 24 // the correct frequency.
c@131 25
c@131 26 // Set up fs/2 = 50, frequency range 10 -> 40 i.e. 2 octaves, fixed
c@131 27 // duration of 2 seconds
c@131 28 static const double sampleRate = 100;
c@139 29 static const double cqmin = 11.8921;
c@131 30 static const double cqmax = 40;
c@131 31 static const double bpo = 4;
c@131 32 static const int duration = sampleRate * 2;
c@131 33
c@132 34 // Threshold below which to ignore a column completely
c@131 35 static const double threshold = 0.08;
c@131 36
c@132 37 int
c@132 38 binForFrequency(double freq)
c@132 39 {
c@139 40 int bin = (bpo * 2) - round(bpo * log2(freq / cqmin)) - 1;
c@132 41 return bin;
c@132 42 }
c@132 43
c@131 44 void
c@135 45 checkCQFreqColumn(int i, vector<double> column,
c@135 46 double freq, CQSpectrogram::Interpolation interp)
c@131 47 {
c@132 48 double maxval = 0.0;
c@132 49 int maxidx = -1;
c@132 50 int height = column.size();
c@139 51
c@139 52 int nonZeroHeight = ((i % 2 == 1) ? height/2 : height);
c@139 53
c@139 54 for (int j = 0; j < nonZeroHeight; ++j) {
c@132 55 if (j == 0 || column[j] > maxval) {
c@132 56 maxval = column[j];
c@132 57 maxidx = j;
c@132 58 }
c@132 59 }
c@135 60
c@132 61 int expected = binForFrequency(freq);
c@132 62 if (maxval < threshold) {
c@132 63 return; // ignore these columns at start and end
c@135 64 } else if (expected < nonZeroHeight && maxidx != expected) {
c@139 65 cerr << "ERROR: In column " << i << " with interpolation " << interp
c@139 66 << ", maximum value for frequency " << freq
c@139 67 << "\n found at index " << maxidx
c@139 68 << " (expected index " << expected << ")" << endl;
c@135 69 cerr << "column contains: ";
c@135 70 for (int j = 0; j < height; ++j) {
c@135 71 cerr << column[j] << " ";
c@133 72 }
c@135 73 cerr << endl;
c@132 74 BOOST_CHECK_EQUAL(maxidx, expected);
c@132 75 }
c@131 76 }
c@131 77
c@131 78 void
c@131 79 testCQFrequency(double freq)
c@131 80 {
c@135 81 vector<CQSpectrogram::Interpolation> interpolationTypes;
c@135 82 interpolationTypes.push_back(CQSpectrogram::InterpolateZeros);
c@135 83 interpolationTypes.push_back(CQSpectrogram::InterpolateHold);
c@135 84 interpolationTypes.push_back(CQSpectrogram::InterpolateLinear);
c@131 85
c@135 86 for (int k = 0; k < int(interpolationTypes.size()); ++k) {
c@132 87
c@135 88 CQSpectrogram::Interpolation interp = interpolationTypes[k];
c@131 89
c@135 90 CQParameters params(sampleRate, cqmin, cqmax, bpo);
c@135 91 CQSpectrogram cq(params, interp);
c@131 92
c@139 93 cerr << "cq freq " << freq << ", binForFrequency " << binForFrequency(freq) << endl;
c@139 94
c@139 95 cerr << "bin freqs: ";
c@139 96 for (int i = 0; i < cq.getBinsPerOctave() * cq.getOctaves(); ++i) {
c@139 97 cerr << i << ": " << cq.getBinFrequency(i) << ", ";
c@139 98 }
c@139 99 cerr << endl;
c@139 100
c@135 101 BOOST_CHECK_EQUAL(cq.getBinsPerOctave(), bpo);
c@135 102 BOOST_CHECK_EQUAL(cq.getOctaves(), 2);
c@139 103 BOOST_CHECK_CLOSE(cq.getBinFrequency(0), 40, 1e-10);
c@139 104 BOOST_CHECK_CLOSE(cq.getBinFrequency(4), 20, 1e-10);
c@139 105 BOOST_CHECK_CLOSE(cq.getBinFrequency(7), cqmin, 1e-3);
c@132 106
c@135 107 vector<double> input;
c@135 108 for (int i = 0; i < duration; ++i) {
c@135 109 input.push_back(sin((i * 2 * M_PI * freq) / sampleRate));
c@135 110 }
c@135 111 Window<double>(HanningWindow, duration).cut(input.data());
c@135 112
c@135 113 CQSpectrogram::RealBlock output = cq.process(input);
c@135 114 CQSpectrogram::RealBlock rest = cq.getRemainingOutput();
c@135 115 output.insert(output.end(), rest.begin(), rest.end());
c@135 116
c@135 117 BOOST_CHECK_EQUAL(output[0].size(),
c@135 118 cq.getBinsPerOctave() * cq.getOctaves());
c@135 119
c@135 120 for (int i = 0; i < int(output.size()); ++i) {
c@135 121 checkCQFreqColumn(i, output[i], freq, interp);
c@135 122 }
c@132 123 }
c@131 124 }
c@131 125
c@133 126 BOOST_AUTO_TEST_CASE(freq_11) { testCQFrequency(11); }
c@139 127 BOOST_AUTO_TEST_CASE(freq_16) { testCQFrequency(16); }
c@139 128 BOOST_AUTO_TEST_CASE(freq_23) { testCQFrequency(23); }
c@139 129 BOOST_AUTO_TEST_CASE(freq_27) { testCQFrequency(27); }
c@139 130 BOOST_AUTO_TEST_CASE(freq_33) { testCQFrequency(33); }
c@131 131 BOOST_AUTO_TEST_CASE(freq_40) { testCQFrequency(40); }
c@131 132
c@131 133 BOOST_AUTO_TEST_SUITE_END()
c@131 134