comparison Peaks.h @ 4:c06cf6f7cb04

Bring in Peaks code from BeatRoot
author Chris Cannam
date Mon, 19 Sep 2011 15:48:26 +0100
parents
children 887c629502a9
comparison
equal deleted inserted replaced
3:a821f49c42f0 4:c06cf6f7cb04
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Vamp feature extraction plugin for the BeatRoot beat tracker.
5
6 Centre for Digital Music, Queen Mary, University of London.
7 This file copyright 2011 Simon Dixon, Chris Cannam and QMUL.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information.
14 */
15
16 #ifndef _BEATROOT_PEAKS_H_
17 #define _BEATROOT_PEAKS_H_
18
19 #include <vector>
20 #include <cmath>
21
22 using std::vector;
23
24 class Peaks
25 {
26 protected:
27 static int pre;
28 static int post;
29
30 public:
31 /** General peak picking method for finding n local maxima in an array
32 * @param data input data
33 * @param peaks list of peak indexes
34 * @param width minimum distance between peaks
35 */
36 static int findPeaks(const vector<double> &data, vector<int> peaks, int width) {
37 int peakCount = 0;
38 int maxp = 0;
39 int mid = 0;
40 int end = data.size();
41 while (mid < end) {
42 int i = mid - width;
43 if (i < 0)
44 i = 0;
45 int stop = mid + width + 1;
46 if (stop > data.size())
47 stop = data.size();
48 maxp = i;
49 for (i++; i < stop; i++)
50 if (data[i] > data[maxp])
51 maxp = i;
52 if (maxp == mid) {
53 int j;
54 for (j = peakCount; j > 0; j--) {
55 if (data[maxp] <= data[peaks[j-1]])
56 break;
57 else if (j < peaks.size())
58 peaks[j] = peaks[j-1];
59 }
60 if (j != peaks.size())
61 peaks[j] = maxp;
62 if (peakCount != peaks.size())
63 peakCount++;
64 }
65 mid++;
66 }
67 return peakCount;
68 } // findPeaks()
69
70 /** General peak picking method for finding local maxima in an array
71 * @param data input data
72 * @param width minimum distance between peaks
73 * @param threshold minimum value of peaks
74 * @return list of peak indexes
75 */
76 static vector<int> findPeaks(const vector<double> &data, int width,
77 double threshold) {
78 return findPeaks(data, width, threshold, 0, false);
79 } // findPeaks()
80
81 /** General peak picking method for finding local maxima in an array
82 * @param data input data
83 * @param width minimum distance between peaks
84 * @param threshold minimum value of peaks
85 * @param decayRate how quickly previous peaks are forgotten
86 * @param isRelative minimum value of peaks is relative to local average
87 * @return list of peak indexes
88 */
89 static vector<int> findPeaks(const vector<double> &data, int width,
90 double threshold, double decayRate, bool isRelative) {
91 vector<int> peaks;
92 int maxp = 0;
93 int mid = 0;
94 int end = data.size();
95 double av = data[0];
96 while (mid < end) {
97 av = decayRate * av + (1 - decayRate) * data[mid];
98 if (av < data[mid])
99 av = data[mid];
100 int i = mid - width;
101 if (i < 0)
102 i = 0;
103 int stop = mid + width + 1;
104 if (stop > data.size())
105 stop = data.size();
106 maxp = i;
107 for (i++; i < stop; i++)
108 if (data[i] > data[maxp])
109 maxp = i;
110 if (maxp == mid) {
111 if (overThreshold(data, maxp, width, threshold, isRelative,av)){
112 peaks.push_back(maxp);
113 }
114 }
115 mid++;
116 }
117 return peaks;
118 } // findPeaks()
119
120 static double expDecayWithHold(double av, double decayRate,
121 const vector<double> &data, int start, int stop) {
122 while (start < stop) {
123 av = decayRate * av + (1 - decayRate) * data[start];
124 if (av < data[start])
125 av = data[start];
126 start++;
127 }
128 return av;
129 } // expDecayWithHold()
130
131 static bool overThreshold(const vector<double> &data, int index, int width,
132 double threshold, bool isRelative,
133 double av) {
134 if (data[index] < av)
135 return false;
136 if (isRelative) {
137 int iStart = index - pre * width;
138 if (iStart < 0)
139 iStart = 0;
140 int iStop = index + post * width;
141 if (iStop > data.size())
142 iStop = data.size();
143 double sum = 0;
144 int count = iStop - iStart;
145 while (iStart < iStop)
146 sum += data[iStart++];
147 return (data[index] > sum / count + threshold);
148 } else
149 return (data[index] > threshold);
150 } // overThreshold()
151
152 static void normalise(vector<double> &data) {
153 double sx = 0;
154 double sxx = 0;
155 for (int i = 0; i < data.size(); i++) {
156 sx += data[i];
157 sxx += data[i] * data[i];
158 }
159 double mean = sx / data.size();
160 double sd = sqrt((sxx - sx * mean) / data.size());
161 if (sd == 0)
162 sd = 1; // all data[i] == mean -> 0; avoids div by 0
163 for (int i = 0; i < data.size(); i++) {
164 data[i] = (data[i] - mean) / sd;
165 }
166 } // normalise()
167
168 /** Uses an n-point linear regression to estimate the slope of data.
169 * @param data input data
170 * @param hop spacing of data points
171 * @param n length of linear regression
172 * @param slope output data
173 */
174 static void getSlope(const vector<double> &data, double hop, int n,
175 vector<double> &slope) {
176 int i = 0, j = 0;
177 double t;
178 double sx = 0, sxx = 0, sy = 0, sxy = 0;
179 for ( ; i < n; i++) {
180 t = i * hop;
181 sx += t;
182 sxx += t * t;
183 sy += data[i];
184 sxy += t * data[i];
185 }
186 double delta = n * sxx - sx * sx;
187 for ( ; j < n / 2; j++)
188 slope[j] = (n * sxy - sx * sy) / delta;
189 for ( ; j < data.size() - (n + 1) / 2; j++, i++) {
190 slope[j] = (n * sxy - sx * sy) / delta;
191 sy += data[i] - data[i - n];
192 sxy += hop * (n * data[i] - sy);
193 }
194 for ( ; j < data.size(); j++)
195 slope[j] = (n * sxy - sx * sy) / delta;
196 } // getSlope()
197
198 static double min(const vector<double> &arr) { return arr[imin(arr)]; }
199
200 static double max(const vector<double> &arr) { return arr[imax(arr)]; }
201
202 static int imin(const vector<double> &arr) {
203 int i = 0;
204 for (int j = 1; j < arr.size(); j++)
205 if (arr[j] < arr[i])
206 i = j;
207 return i;
208 } // imin()
209
210 static int imax(const vector<double> &arr) {
211 int i = 0;
212 for (int j = 1; j < arr.size(); j++)
213 if (arr[j] > arr[i])
214 i = j;
215 return i;
216 } // imax()
217
218 }; // class Peaks
219
220 #endif