annotate test/TestCQFrequency.cpp @ 132:c188cade44f8

Tests (not quite correct yet)
author Chris Cannam <c.cannam@qmul.ac.uk>
date Mon, 19 May 2014 12:03:04 +0100
parents 6b13f9c694a8
children 16822c41b9af
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@131 24 // the correct frequency. We can repeat for different frequencies both
c@131 25 // inside and outside the frequency range supported by the CQ. We
c@131 26 // should also repeat for CQSpectrogram outputs as well as the raw CQ.
c@131 27
c@131 28 // Set up fs/2 = 50, frequency range 10 -> 40 i.e. 2 octaves, fixed
c@131 29 // duration of 2 seconds
c@131 30 static const double sampleRate = 100;
c@131 31 static const double cqmin = 10;
c@131 32 static const double cqmax = 40;
c@131 33 static const double bpo = 4;
c@131 34 static const int duration = sampleRate * 2;
c@131 35
c@132 36 // Threshold below which to ignore a column completely
c@131 37 static const double threshold = 0.08;
c@131 38
c@132 39 int
c@132 40 binForFrequency(double freq)
c@132 41 {
c@132 42 int bin = (2 * bpo) - round(bpo * log2(freq / cqmin));
c@132 43 cerr << "binForFrequency: " << freq << " -> " << bin << endl;
c@132 44 return bin;
c@132 45 }
c@132 46
c@131 47 void
c@132 48 checkCQFreqColumn(int i, vector<double> column, double freq)
c@131 49 {
c@132 50 double maxval = 0.0;
c@132 51 int maxidx = -1;
c@132 52 int height = column.size();
c@132 53 for (int j = 0; j < height; ++j) {
c@132 54 if (j == 0 || column[j] > maxval) {
c@132 55 maxval = column[j];
c@132 56 maxidx = j;
c@132 57 }
c@132 58 }
c@132 59 cerr << "maxval = " << maxval << " at " << maxidx << endl;
c@132 60 int expected = binForFrequency(freq);
c@132 61 if (maxval < threshold) {
c@132 62 return; // ignore these columns at start and end
c@132 63 } else if (expected < 0 || expected >= height) {
c@132 64 cerr << "maxval = " << maxval << endl;
c@132 65 BOOST_CHECK(maxval < threshold);
c@132 66 } else {
c@132 67 BOOST_CHECK_EQUAL(maxidx, expected);
c@132 68 }
c@131 69 }
c@131 70
c@131 71 void
c@131 72 testCQFrequency(double freq)
c@131 73 {
c@131 74 CQParameters params(sampleRate, cqmin, cqmax, bpo);
c@131 75 CQSpectrogram cq(params, CQSpectrogram::InterpolateLinear);
c@131 76
c@132 77 BOOST_CHECK_EQUAL(cq.getBinsPerOctave(), bpo);
c@132 78 BOOST_CHECK_EQUAL(cq.getOctaves(), 2);
c@132 79
c@131 80 vector<double> input;
c@131 81 for (int i = 0; i < duration; ++i) {
c@131 82 input.push_back(sin((i * 2 * M_PI * freq) / sampleRate));
c@131 83 }
c@131 84 Window<double>(HanningWindow, duration).cut(input.data());
c@131 85
c@131 86 CQSpectrogram::RealBlock output = cq.process(input);
c@131 87 CQSpectrogram::RealBlock rest = cq.getRemainingOutput();
c@131 88 output.insert(output.end(), rest.begin(), rest.end());
c@131 89
c@132 90 BOOST_CHECK_EQUAL(output[0].size(), cq.getBinsPerOctave() * cq.getOctaves());
c@132 91
c@132 92 for (int i = 0; i < int(output.size()); ++i) {
c@132 93 checkCQFreqColumn(i, output[i], freq);
c@132 94 }
c@131 95 }
c@131 96
c@131 97 BOOST_AUTO_TEST_CASE(freq_5) { testCQFrequency(5); }
c@131 98 BOOST_AUTO_TEST_CASE(freq_10) { testCQFrequency(10); }
c@131 99 BOOST_AUTO_TEST_CASE(freq_15) { testCQFrequency(15); }
c@131 100 BOOST_AUTO_TEST_CASE(freq_20) { testCQFrequency(20); }
c@131 101 BOOST_AUTO_TEST_CASE(freq_25) { testCQFrequency(25); }
c@131 102 BOOST_AUTO_TEST_CASE(freq_30) { testCQFrequency(30); }
c@131 103 BOOST_AUTO_TEST_CASE(freq_35) { testCQFrequency(35); }
c@131 104 BOOST_AUTO_TEST_CASE(freq_40) { testCQFrequency(40); }
c@131 105 BOOST_AUTO_TEST_CASE(freq_45) { testCQFrequency(45); }
c@131 106 BOOST_AUTO_TEST_CASE(freq_50) { testCQFrequency(50); }
c@131 107
c@131 108 BOOST_AUTO_TEST_SUITE_END()
c@131 109