comparison constant-q-cpp/test/TestCQFrequency.cpp @ 366:5d0a2ebb4d17

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