Mercurial > hg > silvet
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 |