annotate constant-q-cpp/test/TestCQTime.cpp @ 372:af71cbdab621 tip

Update bqvec code
author Chris Cannam
date Tue, 19 Nov 2019 10:13:32 +0000
parents 5d0a2ebb4d17
children
rev   line source
Chris@366 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@366 2
Chris@366 3 #include "cq/CQSpectrogram.h"
Chris@366 4
Chris@366 5 #include "dsp/Window.h"
Chris@366 6
Chris@366 7 #include <cmath>
Chris@366 8 #include <vector>
Chris@366 9 #include <iostream>
Chris@366 10
Chris@366 11 using std::vector;
Chris@366 12 using std::cerr;
Chris@366 13 using std::endl;
Chris@366 14
Chris@366 15 #define BOOST_TEST_DYN_LINK
Chris@366 16 #define BOOST_TEST_MAIN
Chris@366 17
Chris@366 18 #include <boost/test/unit_test.hpp>
Chris@366 19
Chris@366 20 BOOST_AUTO_TEST_SUITE(TestCQTime)
Chris@366 21
Chris@366 22 // Principle: Run a Dirac impulse through the CQ transform and check
Chris@366 23 // that its output has all the peak bins aligned correctly in time.
Chris@366 24
Chris@366 25 // Set up fs/2 = 50, frequency range 10 -> 40 i.e. 2 octaves, fixed
Chris@366 26 // duration of 2 seconds
Chris@366 27 static const double sampleRate = 100;
Chris@366 28 static const double cqmin = 10;
Chris@366 29 static const double cqmax = 40;
Chris@366 30 static const double bpo = 4;
Chris@366 31 static const int duration = sampleRate * 2;
Chris@366 32
Chris@366 33 // Threshold below which to ignore a column completely
Chris@366 34 static const double threshold = 0.08;
Chris@366 35
Chris@366 36 void
Chris@366 37 testCQTime(double t)
Chris@366 38 {
Chris@366 39 vector<CQSpectrogram::Interpolation> interpolationTypes;
Chris@366 40 interpolationTypes.push_back(CQSpectrogram::InterpolateZeros);
Chris@366 41 interpolationTypes.push_back(CQSpectrogram::InterpolateHold);
Chris@366 42 interpolationTypes.push_back(CQSpectrogram::InterpolateLinear);
Chris@366 43
Chris@366 44 for (int k = 0; k < int(interpolationTypes.size()); ++k) {
Chris@366 45
Chris@366 46 CQSpectrogram::Interpolation interp = interpolationTypes[k];
Chris@366 47
Chris@366 48 CQParameters params(sampleRate, cqmin, cqmax, bpo);
Chris@366 49 CQSpectrogram cq(params, interp);
Chris@366 50
Chris@366 51 BOOST_CHECK_EQUAL(cq.getBinsPerOctave(), bpo);
Chris@366 52 BOOST_CHECK_EQUAL(cq.getOctaves(), 2);
Chris@366 53
Chris@366 54 vector<double> input(duration, 0.0);
Chris@366 55 int ix = int(floor(t * sampleRate));
Chris@366 56 if (ix >= duration) ix = duration-1;
Chris@366 57 input[ix] = 1.0;
Chris@366 58
Chris@366 59 CQSpectrogram::RealBlock output = cq.process(input);
Chris@366 60 CQSpectrogram::RealBlock rest = cq.getRemainingOutput();
Chris@366 61 output.insert(output.end(), rest.begin(), rest.end());
Chris@366 62
Chris@366 63 BOOST_CHECK_EQUAL(output[0].size(),
Chris@366 64 cq.getBinsPerOctave() * cq.getOctaves());
Chris@366 65
Chris@366 66 vector<int> peaks;
Chris@366 67 double eps = 1e-8;
Chris@366 68
Chris@366 69 for (int j = 0; j < int(output[0].size()); ++j) {
Chris@366 70
Chris@366 71 int maxidx = -1;
Chris@366 72 double max = 0.0;
Chris@366 73 for (int i = 0; i < int(output.size()); ++i) {
Chris@366 74 double value = output[i][j];
Chris@366 75 if (i == 0 || value + eps > max) {
Chris@366 76 max = value;
Chris@366 77 maxidx = i;
Chris@366 78 }
Chris@366 79 }
Chris@366 80
Chris@366 81 peaks.push_back(maxidx);
Chris@366 82 }
Chris@366 83
Chris@366 84 for (int j = 1; j < int(peaks.size()); ++j) {
Chris@366 85 int oct = j / bpo;
Chris@366 86 int spacing = (1 << oct);
Chris@366 87 int actual = peaks[j]/spacing;
Chris@366 88 int expected = int(round(double(peaks[0])/spacing));
Chris@366 89 if (actual != expected) {
Chris@366 90 cerr << "ERROR: In row " << j << " (bin freq "
Chris@366 91 << cq.getBinFrequency(j) << "), interpolation " << interp
Chris@366 92 << ", maximum value for time " << t
Chris@366 93 << "\n found at index " << peaks[j]
Chris@366 94 << " of " << output.size() << " which does not align with"
Chris@366 95 << " highest frequency\n bin peak at " << peaks[0]
Chris@366 96 << " given octave spacing of " << spacing
Chris@366 97 << "\n [latency = " << cq.getLatency()
Chris@366 98 << ", hop = " << cq.getColumnHop() << ", duration = "
Chris@366 99 << duration << ", ix = " << ix << "]" << endl;
Chris@366 100 cerr << "row contains: ";
Chris@366 101 for (int i = 0; i < int(output.size()); ++i) {
Chris@366 102 if (i == expected * spacing) cerr << "*";
Chris@366 103 if (i == peaks[j]) cerr << "**";
Chris@366 104 cerr << output[i][j] << " ";
Chris@366 105 }
Chris@366 106 cerr << endl;
Chris@366 107
Chris@366 108 BOOST_CHECK_EQUAL(actual, expected);
Chris@366 109 }
Chris@366 110 }
Chris@366 111 }
Chris@366 112 }
Chris@366 113
Chris@366 114 BOOST_AUTO_TEST_CASE(time_zero) { testCQTime(0); }
Chris@366 115 BOOST_AUTO_TEST_CASE(time_half) { testCQTime(0.5); }
Chris@366 116 BOOST_AUTO_TEST_CASE(time_one) { testCQTime(1.0); }
Chris@366 117 BOOST_AUTO_TEST_CASE(time_two) { testCQTime(2.0); }
Chris@366 118
Chris@366 119 BOOST_AUTO_TEST_SUITE_END()
Chris@366 120