c@119
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
c@119
|
2 /*
|
c@119
|
3 Constant-Q library
|
c@119
|
4 Copyright (c) 2013-2014 Queen Mary, University of London
|
c@119
|
5
|
c@119
|
6 Permission is hereby granted, free of charge, to any person
|
c@119
|
7 obtaining a copy of this software and associated documentation
|
c@119
|
8 files (the "Software"), to deal in the Software without
|
c@119
|
9 restriction, including without limitation the rights to use, copy,
|
c@119
|
10 modify, merge, publish, distribute, sublicense, and/or sell copies
|
c@119
|
11 of the Software, and to permit persons to whom the Software is
|
c@119
|
12 furnished to do so, subject to the following conditions:
|
c@119
|
13
|
c@119
|
14 The above copyright notice and this permission notice shall be
|
c@119
|
15 included in all copies or substantial portions of the Software.
|
c@119
|
16
|
c@119
|
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
c@119
|
18 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
c@119
|
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
c@119
|
20 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
c@119
|
21 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
c@119
|
22 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
c@119
|
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
c@119
|
24
|
c@119
|
25 Except as contained in this notice, the names of the Centre for
|
c@119
|
26 Digital Music; Queen Mary, University of London; and Chris Cannam
|
c@119
|
27 shall not be used in advertising or otherwise to promote the sale,
|
c@119
|
28 use or other dealings in this Software without prior written
|
c@119
|
29 authorization.
|
c@119
|
30 */
|
c@119
|
31
|
c@119
|
32 #include "MathUtilities.h"
|
c@119
|
33
|
c@119
|
34 #include <iostream>
|
c@119
|
35 #include <algorithm>
|
c@119
|
36 #include <vector>
|
c@119
|
37 #include <cmath>
|
c@119
|
38
|
c@119
|
39
|
c@119
|
40 double MathUtilities::mod(double x, double y)
|
c@119
|
41 {
|
c@119
|
42 double a = floor( x / y );
|
c@119
|
43
|
c@119
|
44 double b = x - ( y * a );
|
c@119
|
45 return b;
|
c@119
|
46 }
|
c@119
|
47
|
c@119
|
48 double MathUtilities::princarg(double ang)
|
c@119
|
49 {
|
c@119
|
50 double ValOut;
|
c@119
|
51
|
c@119
|
52 ValOut = mod( ang + M_PI, -2 * M_PI ) + M_PI;
|
c@119
|
53
|
c@119
|
54 return ValOut;
|
c@119
|
55 }
|
c@119
|
56
|
c@119
|
57 void MathUtilities::getAlphaNorm(const double *data, unsigned int len, unsigned int alpha, double* ANorm)
|
c@119
|
58 {
|
c@119
|
59 unsigned int i;
|
c@119
|
60 double temp = 0.0;
|
c@119
|
61 double a=0.0;
|
c@119
|
62
|
c@119
|
63 for( i = 0; i < len; i++)
|
c@119
|
64 {
|
c@119
|
65 temp = data[ i ];
|
c@119
|
66
|
c@119
|
67 a += ::pow( fabs(temp), double(alpha) );
|
c@119
|
68 }
|
c@119
|
69 a /= ( double )len;
|
c@119
|
70 a = ::pow( a, ( 1.0 / (double) alpha ) );
|
c@119
|
71
|
c@119
|
72 *ANorm = a;
|
c@119
|
73 }
|
c@119
|
74
|
c@119
|
75 double MathUtilities::getAlphaNorm( const std::vector <double> &data, unsigned int alpha )
|
c@119
|
76 {
|
c@119
|
77 unsigned int i;
|
c@119
|
78 unsigned int len = data.size();
|
c@119
|
79 double temp = 0.0;
|
c@119
|
80 double a=0.0;
|
c@119
|
81
|
c@119
|
82 for( i = 0; i < len; i++)
|
c@119
|
83 {
|
c@119
|
84 temp = data[ i ];
|
c@119
|
85
|
c@119
|
86 a += ::pow( fabs(temp), double(alpha) );
|
c@119
|
87 }
|
c@119
|
88 a /= ( double )len;
|
c@119
|
89 a = ::pow( a, ( 1.0 / (double) alpha ) );
|
c@119
|
90
|
c@119
|
91 return a;
|
c@119
|
92 }
|
c@119
|
93
|
c@119
|
94 double MathUtilities::round(double x)
|
c@119
|
95 {
|
c@119
|
96 if (x < 0) {
|
c@119
|
97 return -floor(-x + 0.5);
|
c@119
|
98 } else {
|
c@119
|
99 return floor(x + 0.5);
|
c@119
|
100 }
|
c@119
|
101 }
|
c@119
|
102
|
c@119
|
103 double MathUtilities::median(const double *src, unsigned int len)
|
c@119
|
104 {
|
c@119
|
105 if (len == 0) return 0;
|
c@119
|
106
|
c@119
|
107 std::vector<double> scratch;
|
c@126
|
108 for (int i = 0; i < (int)len; ++i) scratch.push_back(src[i]);
|
c@119
|
109 std::sort(scratch.begin(), scratch.end());
|
c@119
|
110
|
c@119
|
111 int middle = len/2;
|
c@119
|
112 if (len % 2 == 0) {
|
c@119
|
113 return (scratch[middle] + scratch[middle - 1]) / 2;
|
c@119
|
114 } else {
|
c@119
|
115 return scratch[middle];
|
c@119
|
116 }
|
c@119
|
117 }
|
c@119
|
118
|
c@119
|
119 double MathUtilities::sum(const double *src, unsigned int len)
|
c@119
|
120 {
|
c@119
|
121 unsigned int i ;
|
c@119
|
122 double retVal =0.0;
|
c@119
|
123
|
c@119
|
124 for( i = 0; i < len; i++)
|
c@119
|
125 {
|
c@119
|
126 retVal += src[ i ];
|
c@119
|
127 }
|
c@119
|
128
|
c@119
|
129 return retVal;
|
c@119
|
130 }
|
c@119
|
131
|
c@119
|
132 double MathUtilities::mean(const double *src, unsigned int len)
|
c@119
|
133 {
|
c@119
|
134 double retVal =0.0;
|
c@119
|
135
|
c@119
|
136 if (len == 0) return 0;
|
c@119
|
137
|
c@119
|
138 double s = sum( src, len );
|
c@119
|
139
|
c@119
|
140 retVal = s / (double)len;
|
c@119
|
141
|
c@119
|
142 return retVal;
|
c@119
|
143 }
|
c@119
|
144
|
c@119
|
145 double MathUtilities::mean(const std::vector<double> &src,
|
c@119
|
146 unsigned int start,
|
c@119
|
147 unsigned int count)
|
c@119
|
148 {
|
c@119
|
149 double sum = 0.;
|
c@119
|
150
|
c@119
|
151 if (count == 0) return 0;
|
c@119
|
152
|
c@119
|
153 for (int i = 0; i < (int)count; ++i)
|
c@119
|
154 {
|
c@119
|
155 sum += src[start + i];
|
c@119
|
156 }
|
c@119
|
157
|
c@119
|
158 return sum / count;
|
c@119
|
159 }
|
c@119
|
160
|
c@119
|
161 void MathUtilities::getFrameMinMax(const double *data, unsigned int len, double *min, double *max)
|
c@119
|
162 {
|
c@119
|
163 unsigned int i;
|
c@119
|
164 double temp = 0.0;
|
c@119
|
165
|
c@119
|
166 if (len == 0) {
|
c@119
|
167 *min = *max = 0;
|
c@119
|
168 return;
|
c@119
|
169 }
|
c@119
|
170
|
c@119
|
171 *min = data[0];
|
c@119
|
172 *max = data[0];
|
c@119
|
173
|
c@119
|
174 for( i = 0; i < len; i++)
|
c@119
|
175 {
|
c@119
|
176 temp = data[ i ];
|
c@119
|
177
|
c@119
|
178 if( temp < *min )
|
c@119
|
179 {
|
c@119
|
180 *min = temp ;
|
c@119
|
181 }
|
c@119
|
182 if( temp > *max )
|
c@119
|
183 {
|
c@119
|
184 *max = temp ;
|
c@119
|
185 }
|
c@119
|
186
|
c@119
|
187 }
|
c@119
|
188 }
|
c@119
|
189
|
c@119
|
190 int MathUtilities::getMax( double* pData, unsigned int Length, double* pMax )
|
c@119
|
191 {
|
c@119
|
192 unsigned int index = 0;
|
c@119
|
193 unsigned int i;
|
c@119
|
194 double temp = 0.0;
|
c@119
|
195
|
c@119
|
196 double max = pData[0];
|
c@119
|
197
|
c@119
|
198 for( i = 0; i < Length; i++)
|
c@119
|
199 {
|
c@119
|
200 temp = pData[ i ];
|
c@119
|
201
|
c@119
|
202 if( temp > max )
|
c@119
|
203 {
|
c@119
|
204 max = temp ;
|
c@119
|
205 index = i;
|
c@119
|
206 }
|
c@119
|
207
|
c@119
|
208 }
|
c@119
|
209
|
c@119
|
210 if (pMax) *pMax = max;
|
c@119
|
211
|
c@119
|
212
|
c@119
|
213 return index;
|
c@119
|
214 }
|
c@119
|
215
|
c@119
|
216 int MathUtilities::getMax( const std::vector<double> & data, double* pMax )
|
c@119
|
217 {
|
c@119
|
218 unsigned int index = 0;
|
c@119
|
219 unsigned int i;
|
c@119
|
220 double temp = 0.0;
|
c@119
|
221
|
c@119
|
222 double max = data[0];
|
c@119
|
223
|
c@119
|
224 for( i = 0; i < data.size(); i++)
|
c@119
|
225 {
|
c@119
|
226 temp = data[ i ];
|
c@119
|
227
|
c@119
|
228 if( temp > max )
|
c@119
|
229 {
|
c@119
|
230 max = temp ;
|
c@119
|
231 index = i;
|
c@119
|
232 }
|
c@119
|
233
|
c@119
|
234 }
|
c@119
|
235
|
c@119
|
236 if (pMax) *pMax = max;
|
c@119
|
237
|
c@119
|
238
|
c@119
|
239 return index;
|
c@119
|
240 }
|
c@119
|
241
|
c@119
|
242 void MathUtilities::circShift( double* pData, int length, int shift)
|
c@119
|
243 {
|
c@119
|
244 shift = shift % length;
|
c@119
|
245 double temp;
|
c@119
|
246 int i,n;
|
c@119
|
247
|
c@119
|
248 for( i = 0; i < shift; i++)
|
c@119
|
249 {
|
c@119
|
250 temp=*(pData + length - 1);
|
c@119
|
251
|
c@119
|
252 for( n = length-2; n >= 0; n--)
|
c@119
|
253 {
|
c@119
|
254 *(pData+n+1)=*(pData+n);
|
c@119
|
255 }
|
c@119
|
256
|
c@119
|
257 *pData = temp;
|
c@119
|
258 }
|
c@119
|
259 }
|
c@119
|
260
|
c@119
|
261 int MathUtilities::compareInt (const void * a, const void * b)
|
c@119
|
262 {
|
c@119
|
263 return ( *(int*)a - *(int*)b );
|
c@119
|
264 }
|
c@119
|
265
|
c@119
|
266 void MathUtilities::normalise(double *data, int length, NormaliseType type)
|
c@119
|
267 {
|
c@119
|
268 switch (type) {
|
c@119
|
269
|
c@119
|
270 case NormaliseNone: return;
|
c@119
|
271
|
c@119
|
272 case NormaliseUnitSum:
|
c@119
|
273 {
|
c@119
|
274 double sum = 0.0;
|
c@119
|
275 for (int i = 0; i < length; ++i) {
|
c@119
|
276 sum += data[i];
|
c@119
|
277 }
|
c@119
|
278 if (sum != 0.0) {
|
c@119
|
279 for (int i = 0; i < length; ++i) {
|
c@119
|
280 data[i] /= sum;
|
c@119
|
281 }
|
c@119
|
282 }
|
c@119
|
283 }
|
c@119
|
284 break;
|
c@119
|
285
|
c@119
|
286 case NormaliseUnitMax:
|
c@119
|
287 {
|
c@119
|
288 double max = 0.0;
|
c@119
|
289 for (int i = 0; i < length; ++i) {
|
c@119
|
290 if (fabs(data[i]) > max) {
|
c@119
|
291 max = fabs(data[i]);
|
c@119
|
292 }
|
c@119
|
293 }
|
c@119
|
294 if (max != 0.0) {
|
c@119
|
295 for (int i = 0; i < length; ++i) {
|
c@119
|
296 data[i] /= max;
|
c@119
|
297 }
|
c@119
|
298 }
|
c@119
|
299 }
|
c@119
|
300 break;
|
c@119
|
301
|
c@119
|
302 }
|
c@119
|
303 }
|
c@119
|
304
|
c@119
|
305 void MathUtilities::normalise(std::vector<double> &data, NormaliseType type)
|
c@119
|
306 {
|
c@119
|
307 switch (type) {
|
c@119
|
308
|
c@119
|
309 case NormaliseNone: return;
|
c@119
|
310
|
c@119
|
311 case NormaliseUnitSum:
|
c@119
|
312 {
|
c@119
|
313 double sum = 0.0;
|
c@119
|
314 for (int i = 0; i < (int)data.size(); ++i) sum += data[i];
|
c@119
|
315 if (sum != 0.0) {
|
c@119
|
316 for (int i = 0; i < (int)data.size(); ++i) data[i] /= sum;
|
c@119
|
317 }
|
c@119
|
318 }
|
c@119
|
319 break;
|
c@119
|
320
|
c@119
|
321 case NormaliseUnitMax:
|
c@119
|
322 {
|
c@119
|
323 double max = 0.0;
|
c@119
|
324 for (int i = 0; i < (int)data.size(); ++i) {
|
c@119
|
325 if (fabs(data[i]) > max) max = fabs(data[i]);
|
c@119
|
326 }
|
c@119
|
327 if (max != 0.0) {
|
c@119
|
328 for (int i = 0; i < (int)data.size(); ++i) data[i] /= max;
|
c@119
|
329 }
|
c@119
|
330 }
|
c@119
|
331 break;
|
c@119
|
332
|
c@119
|
333 }
|
c@119
|
334 }
|
c@119
|
335
|
c@119
|
336 void MathUtilities::adaptiveThreshold(std::vector<double> &data)
|
c@119
|
337 {
|
c@119
|
338 int sz = int(data.size());
|
c@119
|
339 if (sz == 0) return;
|
c@119
|
340
|
c@119
|
341 std::vector<double> smoothed(sz);
|
c@119
|
342
|
c@119
|
343 int p_pre = 8;
|
c@119
|
344 int p_post = 7;
|
c@119
|
345
|
c@119
|
346 for (int i = 0; i < sz; ++i) {
|
c@119
|
347
|
c@119
|
348 int first = std::max(0, i - p_pre);
|
c@119
|
349 int last = std::min(sz - 1, i + p_post);
|
c@119
|
350
|
c@119
|
351 smoothed[i] = mean(data, first, last - first + 1);
|
c@119
|
352 }
|
c@119
|
353
|
c@119
|
354 for (int i = 0; i < sz; i++) {
|
c@119
|
355 data[i] -= smoothed[i];
|
c@119
|
356 if (data[i] < 0.0) data[i] = 0.0;
|
c@119
|
357 }
|
c@119
|
358 }
|
c@119
|
359
|
c@119
|
360 bool
|
c@119
|
361 MathUtilities::isPowerOfTwo(int x)
|
c@119
|
362 {
|
c@119
|
363 if (x < 1) return false;
|
c@119
|
364 if (x & (x-1)) return false;
|
c@119
|
365 return true;
|
c@119
|
366 }
|
c@119
|
367
|
c@119
|
368 int
|
c@119
|
369 MathUtilities::nextPowerOfTwo(int x)
|
c@119
|
370 {
|
c@119
|
371 if (isPowerOfTwo(x)) return x;
|
c@119
|
372 if (x < 1) return 1;
|
c@119
|
373 int n = 1;
|
c@119
|
374 while (x) { x >>= 1; n <<= 1; }
|
c@119
|
375 return n;
|
c@119
|
376 }
|
c@119
|
377
|
c@119
|
378 int
|
c@119
|
379 MathUtilities::previousPowerOfTwo(int x)
|
c@119
|
380 {
|
c@119
|
381 if (isPowerOfTwo(x)) return x;
|
c@119
|
382 if (x < 1) return 1;
|
c@119
|
383 int n = 1;
|
c@119
|
384 x >>= 1;
|
c@119
|
385 while (x) { x >>= 1; n <<= 1; }
|
c@119
|
386 return n;
|
c@119
|
387 }
|
c@119
|
388
|
c@119
|
389 int
|
c@119
|
390 MathUtilities::nearestPowerOfTwo(int x)
|
c@119
|
391 {
|
c@119
|
392 if (isPowerOfTwo(x)) return x;
|
c@119
|
393 int n0 = previousPowerOfTwo(x), n1 = nextPowerOfTwo(x);
|
c@119
|
394 if (x - n0 < n1 - x) return n0;
|
c@119
|
395 else return n1;
|
c@119
|
396 }
|
c@119
|
397
|
c@119
|
398 double
|
c@119
|
399 MathUtilities::factorial(int x)
|
c@119
|
400 {
|
c@119
|
401 if (x < 0) return 0;
|
c@119
|
402 double f = 1;
|
c@119
|
403 for (int i = 1; i <= x; ++i) {
|
c@119
|
404 f = f * i;
|
c@119
|
405 }
|
c@119
|
406 return f;
|
c@119
|
407 }
|
c@119
|
408
|
c@119
|
409 int
|
c@119
|
410 MathUtilities::gcd(int a, int b)
|
c@119
|
411 {
|
c@119
|
412 int c = a % b;
|
c@119
|
413 if (c == 0) {
|
c@119
|
414 return b;
|
c@119
|
415 } else {
|
c@119
|
416 return gcd(b, c);
|
c@119
|
417 }
|
c@119
|
418 }
|
c@119
|
419
|