Mercurial > hg > cepstral-pitchtracker
changeset 42:45b4401136f6
More peak location bits & bobs
| author | Chris Cannam |
|---|---|
| date | Fri, 20 Jul 2012 21:37:09 +0100 |
| parents | 16908c2bd781 |
| children | 53260757fc9f |
| files | PeakInterpolator.cpp PeakInterpolator.h test/TestPeakInterpolator.cpp |
| diffstat | 3 files changed, 62 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/PeakInterpolator.cpp Fri Jul 20 19:08:38 2012 +0100 +++ b/PeakInterpolator.cpp Fri Jul 20 21:37:09 2012 +0100 @@ -40,12 +40,27 @@ } double +PeakInterpolator::findPeakLocation(const double *data, int size) +{ + double maxval; + int maxidx = 0; + int i; + for (i = 0; i < size; ++i) { + if (i == 0 || data[i] > maxval) { + maxval = data[i]; + maxidx = i; + } + } + return findPeakLocation(data, size, maxidx); +} + +double PeakInterpolator::findPeakLocation(const double *data, int size, int peakIndex) { - std::cerr << "findPeakLocation: size " << size << ", peakIndex " << peakIndex << std::endl; +// std::cerr << "findPeakLocation: size " << size << ", peakIndex " << peakIndex << std::endl; if (peakIndex < 1 || peakIndex > size - 2) { - std::cerr << "returning " << peakIndex << ", data too short" << std::endl; +// std::cerr << "returning " << peakIndex << ", data too short" << std::endl; return peakIndex; } @@ -63,11 +78,11 @@ } else { y[3] = y[2]; } - std::cerr << "a y: " << y[0] << " " << y[1] << " " << y[2] << " " << y[3] << std::endl; +// std::cerr << "a y: " << y[0] << " " << y[1] << " " << y[2] << " " << y[3] << std::endl; for (int i = 0; i < divisions; ++i) { double probe = double(i) / double(divisions); double value = cubicInterpolate(y, probe); - std::cerr << "probe = " << probe << ", value = " << value << " for location " << peakIndex + probe << std::endl; +// std::cerr << "probe = " << probe << ", value = " << value << " for location " << peakIndex + probe << std::endl; if (value > maxval) { maxval = value; location = peakIndex + probe; @@ -82,18 +97,18 @@ } else { y[0] = y[1]; } - std::cerr << "b y: " << y[0] << " " << y[1] << " " << y[2] << " " << y[3] << std::endl; +// std::cerr << "b y: " << y[0] << " " << y[1] << " " << y[2] << " " << y[3] << std::endl; for (int i = 0; i < divisions; ++i) { double probe = double(i) / double(divisions); double value = cubicInterpolate(y, probe); - std::cerr << "probe = " << probe << ", value = " << value << " for location " << peakIndex - 1 + probe << std::endl; +// std::cerr << "probe = " << probe << ", value = " << value << " for location " << peakIndex - 1 + probe << std::endl; if (value > maxval) { maxval = value; location = peakIndex - 1 + probe; } } - std::cerr << "returning " << location << std::endl; +// std::cerr << "returning " << location << std::endl; return location; }
--- a/PeakInterpolator.h Fri Jul 20 19:08:38 2012 +0100 +++ b/PeakInterpolator.h Fri Jul 20 21:37:09 2012 +0100 @@ -32,9 +32,27 @@ ~PeakInterpolator() { } /** + * Return the interpolated location (i.e. possibly between sample + * point indices) of the peak in the given sampled range. + * + * "The peak" is defined as the (approximate) location of the + * maximum of a function interpolating between the points + * neighbouring the sample index with the maximum value in the + * range. + * + * If multiple local peak samples in the input range are equal, + * i.e. there is more than one apparent peak in the range, the one + * with the lowest index will be used. This is the case even if a + * later peak would be of superior height after interpolation. + */ + double findPeakLocation(const double *data, int size); + + /** * Return the interpolated location (i.e. between sample point - * indices) of the peak whose sample is found at peakIndex in a - * series of size samples. + * indices) of the peak whose nearest sample is found at peakIndex + * in the given sampled range. This method allows you to specify + * which peak to find, if local rather than global peaks are of + * interest. */ double findPeakLocation(const double *data, int size, int peakIndex); };
--- a/test/TestPeakInterpolator.cpp Fri Jul 20 19:08:38 2012 +0100 +++ b/test/TestPeakInterpolator.cpp Fri Jul 20 21:37:09 2012 +0100 @@ -37,6 +37,8 @@ PeakInterpolator p; double result = p.findPeakLocation(data, 3, 1); BOOST_CHECK_EQUAL(result, 1.0); + result = p.findPeakLocation(data, 3); + BOOST_CHECK_EQUAL(result, 1.0); } BOOST_AUTO_TEST_CASE(peakAtSample_N5) @@ -45,6 +47,8 @@ PeakInterpolator p; double result = p.findPeakLocation(data, 5, 2); BOOST_CHECK_EQUAL(result, 2.0); + result = p.findPeakLocation(data, 5); + BOOST_CHECK_EQUAL(result, 2.0); } BOOST_AUTO_TEST_CASE(flat) @@ -53,6 +57,8 @@ PeakInterpolator p; double result = p.findPeakLocation(data, 5, 2); BOOST_CHECK_EQUAL(result, 2.0); + result = p.findPeakLocation(data, 5); + BOOST_CHECK_EQUAL(result, 0.0); } BOOST_AUTO_TEST_CASE(multiPeak) @@ -61,6 +67,8 @@ PeakInterpolator p; double result = p.findPeakLocation(data, 5, 3); BOOST_CHECK_EQUAL(result, 3.0); + result = p.findPeakLocation(data, 5); + BOOST_CHECK_EQUAL(result, 1.0); } BOOST_AUTO_TEST_CASE(start) @@ -80,6 +88,10 @@ PeakInterpolator p; double result = p.findPeakLocation(data, 4, 3); BOOST_CHECK_EQUAL(result, 3.0); + // But when running without a peak location, we expect idx 2 to be + // picked as peak, not idx 3, so that will result in interpolation + result = p.findPeakLocation(data, 4); + BOOST_CHECK(result > 2.0 && result < 3.0); } BOOST_AUTO_TEST_CASE(longHalfway) @@ -88,6 +100,8 @@ PeakInterpolator p; double result = p.findPeakLocation(data, 8, 4); BOOST_CHECK_EQUAL(result, 3.5); + result = p.findPeakLocation(data, 8); + BOOST_CHECK_EQUAL(result, 3.5); } BOOST_AUTO_TEST_CASE(shortHalfway) @@ -96,6 +110,8 @@ PeakInterpolator p; double result = p.findPeakLocation(data, 4, 1); BOOST_CHECK_EQUAL(result, 1.5); + result = p.findPeakLocation(data, 4); + BOOST_CHECK_EQUAL(result, 1.5); } BOOST_AUTO_TEST_CASE(aboveHalfway) @@ -104,6 +120,8 @@ PeakInterpolator p; double result = p.findPeakLocation(data, 4, 2); BOOST_CHECK(result > 1.5 && result < 2.0); + result = p.findPeakLocation(data, 4); + BOOST_CHECK(result > 1.5 && result < 2.0); } BOOST_AUTO_TEST_CASE(belowHalfway) @@ -112,6 +130,8 @@ PeakInterpolator p; double result = p.findPeakLocation(data, 4, 1); BOOST_CHECK(result > 1.0 && result < 1.5); + result = p.findPeakLocation(data, 4); + BOOST_CHECK(result > 1.0 && result < 1.5); } BOOST_AUTO_TEST_SUITE_END()