annotate maths/Polyfit.h @ 321:f1e6be2de9a5

A threshold (delta) is added in the peak picking parameters structure (PPickParams). It is used as an offset when computing the smoothed detection function. A constructor for the structure PPickParams is also added to set the parameters to 0 when a structure instance is created. Hence programmes using the peak picking parameter structure and which do not set the delta parameter (e.g. QM Vamp note onset detector) won't be affected by the modifications. Functions modified: - dsp/onsets/PeakPicking.cpp - dsp/onsets/PeakPicking.h - dsp/signalconditioning/DFProcess.cpp - dsp/signalconditioning/DFProcess.h
author mathieub <mathieu.barthet@eecs.qmul.ac.uk>
date Mon, 20 Jun 2011 19:01:48 +0100
parents 9aedf5ea8c35
children 31f22daeba64
rev   line source
c@241 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@241 2 //---------------------------------------------------------------------------
c@241 3
c@241 4 #ifndef PolyfitHPP
c@241 5 #define PolyfitHPP
c@241 6 //---------------------------------------------------------------------------
c@241 7 // Least-squares curve fitting class for arbitrary data types
c@241 8 /*
c@241 9
c@241 10 { ******************************************
c@241 11 **** Scientific Subroutine Library ****
c@241 12 **** for C++ Builder ****
c@241 13 ******************************************
c@241 14
c@241 15 The following programs were written by Allen Miller and appear in the
c@241 16 book entitled "Pascal Programs For Scientists And Engineers" which is
c@241 17 published by Sybex, 1981.
c@241 18 They were originally typed and submitted to MTPUG in Oct. 1982
c@241 19 Juergen Loewner
c@241 20 Hoher Heckenweg 3
c@241 21 D-4400 Muenster
c@241 22 They have had minor corrections and adaptations for Turbo Pascal by
c@241 23 Jeff Weiss
c@241 24 1572 Peacock Ave.
c@241 25 Sunnyvale, CA 94087.
c@241 26
c@241 27
c@241 28 2000 Oct 28 Updated for Delphi 4, open array parameters.
c@241 29 This allows the routine to be generalised so that it is no longer
c@241 30 hard-coded to make a specific order of best fit or work with a
c@241 31 specific number of points.
c@241 32 2001 Jan 07 Update Web site address
c@241 33
c@241 34 Copyright © David J Taylor, Edinburgh and others listed above
c@241 35 Web site: www.satsignal.net
c@241 36 E-mail: davidtaylor@writeme.com
c@241 37 }*/
c@241 38
c@241 39 ///////////////////////////////////////////////////////////////////////////////
c@241 40 // Modified by CLandone for VC6 Aug 2004
c@241 41 ///////////////////////////////////////////////////////////////////////////////
c@241 42
c@268 43 #include <iostream>
c@241 44
c@241 45 using std::vector;
c@241 46
c@241 47 class TPolyFit
c@241 48 {
c@241 49 typedef vector<vector<double> > Matrix;
c@241 50 public:
c@241 51
c@241 52 static double PolyFit2 (const vector<double> &x, // does the work
c@241 53 const vector<double> &y,
c@241 54 vector<double> &coef);
c@241 55
c@241 56
c@241 57 private:
c@241 58 TPolyFit &operator = (const TPolyFit &); // disable assignment
c@241 59 TPolyFit(); // and instantiation
c@241 60 TPolyFit(const TPolyFit&); // and copying
c@241 61
c@241 62
c@241 63 static void Square (const Matrix &x, // Matrix multiplication routine
c@241 64 const vector<double> &y,
c@241 65 Matrix &a, // A = transpose X times X
c@241 66 vector<double> &g, // G = Y times X
c@241 67 const int nrow, const int ncol);
c@241 68 // Forms square coefficient matrix
c@241 69
c@241 70 static bool GaussJordan (Matrix &b, // square matrix of coefficients
c@241 71 const vector<double> &y, // constant vector
c@241 72 vector<double> &coef); // solution vector
c@241 73 // returns false if matrix singular
c@241 74
c@241 75 static bool GaussJordan2(Matrix &b,
c@241 76 const vector<double> &y,
c@241 77 Matrix &w,
c@241 78 vector<vector<int> > &index);
c@241 79 };
c@241 80
c@241 81 // some utility functions
c@241 82
c@241 83 namespace NSUtility
c@241 84 {
c@241 85 inline void swap(double &a, double &b) {double t = a; a = b; b = t;}
c@241 86 void zeroise(vector<double> &array, int n);
c@241 87 void zeroise(vector<int> &array, int n);
c@241 88 void zeroise(vector<vector<double> > &matrix, int m, int n);
c@241 89 void zeroise(vector<vector<int> > &matrix, int m, int n);
c@241 90 inline double sqr(const double &x) {return x * x;}
c@241 91 };
c@241 92
c@241 93 //---------------------------------------------------------------------------
c@241 94 // Implementation
c@241 95 //---------------------------------------------------------------------------
c@241 96 using namespace NSUtility;
c@241 97 //------------------------------------------------------------------------------------------
c@241 98
c@241 99
c@241 100 // main PolyFit routine
c@241 101
c@241 102 double TPolyFit::PolyFit2 (const vector<double> &x,
c@241 103 const vector<double> &y,
c@241 104 vector<double> &coefs)
c@241 105 // nterms = coefs.size()
c@241 106 // npoints = x.size()
c@241 107 {
c@241 108 int i, j;
c@241 109 double xi, yi, yc, srs, sum_y, sum_y2;
c@241 110 Matrix xmatr; // Data matrix
c@241 111 Matrix a;
c@241 112 vector<double> g; // Constant vector
c@241 113 const int npoints(x.size());
c@241 114 const int nterms(coefs.size());
c@241 115 double correl_coef;
c@241 116 zeroise(g, nterms);
c@241 117 zeroise(a, nterms, nterms);
c@241 118 zeroise(xmatr, npoints, nterms);
c@268 119 if (nterms < 1) {
c@268 120 std::cerr << "ERROR: PolyFit called with less than one term" << std::endl;
c@268 121 return 0;
c@268 122 }
c@268 123 if(npoints < 2) {
c@268 124 std::cerr << "ERROR: PolyFit called with less than two points" << std::endl;
c@268 125 return 0;
c@268 126 }
c@268 127 if(npoints != y.size()) {
c@268 128 std::cerr << "ERROR: PolyFit called with x and y of unequal size" << std::endl;
c@268 129 return 0;
c@268 130 }
c@241 131 for(i = 0; i < npoints; ++i)
c@241 132 {
c@241 133 // { setup x matrix }
c@241 134 xi = x[i];
c@241 135 xmatr[i][0] = 1.0; // { first column }
c@241 136 for(j = 1; j < nterms; ++j)
c@241 137 xmatr[i][j] = xmatr [i][j - 1] * xi;
c@241 138 }
c@241 139 Square (xmatr, y, a, g, npoints, nterms);
c@241 140 if(!GaussJordan (a, g, coefs))
c@241 141 return -1;
c@241 142 sum_y = 0.0;
c@241 143 sum_y2 = 0.0;
c@241 144 srs = 0.0;
c@241 145 for(i = 0; i < npoints; ++i)
c@241 146 {
c@241 147 yi = y[i];
c@241 148 yc = 0.0;
c@241 149 for(j = 0; j < nterms; ++j)
c@241 150 yc += coefs [j] * xmatr [i][j];
c@241 151 srs += sqr (yc - yi);
c@241 152 sum_y += yi;
c@241 153 sum_y2 += yi * yi;
c@241 154 }
c@241 155
c@241 156 // If all Y values are the same, avoid dividing by zero
c@241 157 correl_coef = sum_y2 - sqr (sum_y) / npoints;
c@241 158 // Either return 0 or the correct value of correlation coefficient
c@241 159 if (correl_coef != 0)
c@241 160 correl_coef = srs / correl_coef;
c@241 161 if (correl_coef >= 1)
c@241 162 correl_coef = 0.0;
c@241 163 else
c@241 164 correl_coef = sqrt (1.0 - correl_coef);
c@241 165 return correl_coef;
c@241 166 }
c@241 167
c@241 168
c@241 169 //------------------------------------------------------------------------
c@241 170
c@241 171 // Matrix multiplication routine
c@241 172 // A = transpose X times X
c@241 173 // G = Y times X
c@241 174
c@241 175 // Form square coefficient matrix
c@241 176
c@241 177 void TPolyFit::Square (const Matrix &x,
c@241 178 const vector<double> &y,
c@241 179 Matrix &a,
c@241 180 vector<double> &g,
c@241 181 const int nrow,
c@241 182 const int ncol)
c@241 183 {
c@241 184 int i, k, l;
c@241 185 for(k = 0; k < ncol; ++k)
c@241 186 {
c@241 187 for(l = 0; l < k + 1; ++l)
c@241 188 {
c@241 189 a [k][l] = 0.0;
c@241 190 for(i = 0; i < nrow; ++i)
c@241 191 {
c@241 192 a[k][l] += x[i][l] * x [i][k];
c@241 193 if(k != l)
c@241 194 a[l][k] = a[k][l];
c@241 195 }
c@241 196 }
c@241 197 g[k] = 0.0;
c@241 198 for(i = 0; i < nrow; ++i)
c@241 199 g[k] += y[i] * x[i][k];
c@241 200 }
c@241 201 }
c@241 202 //---------------------------------------------------------------------------------
c@241 203
c@241 204
c@241 205 bool TPolyFit::GaussJordan (Matrix &b,
c@241 206 const vector<double> &y,
c@241 207 vector<double> &coef)
c@241 208 //b square matrix of coefficients
c@241 209 //y constant vector
c@241 210 //coef solution vector
c@241 211 //ncol order of matrix got from b.size()
c@241 212
c@241 213
c@241 214 {
c@241 215 /*
c@241 216 { Gauss Jordan matrix inversion and solution }
c@241 217
c@241 218 { B (n, n) coefficient matrix becomes inverse }
c@241 219 { Y (n) original constant vector }
c@241 220 { W (n, m) constant vector(s) become solution vector }
c@241 221 { DETERM is the determinant }
c@241 222 { ERROR = 1 if singular }
c@241 223 { INDEX (n, 3) }
c@241 224 { NV is number of constant vectors }
c@241 225 */
c@241 226
c@241 227 int ncol(b.size());
c@241 228 int irow, icol;
c@241 229 vector<vector<int> >index;
c@241 230 Matrix w;
c@241 231
c@241 232 zeroise(w, ncol, ncol);
c@241 233 zeroise(index, ncol, 3);
c@241 234
c@241 235 if(!GaussJordan2(b, y, w, index))
c@241 236 return false;
c@241 237
c@241 238 // Interchange columns
c@241 239 int m;
c@241 240 for (int i = 0; i < ncol; ++i)
c@241 241 {
c@241 242 m = ncol - i - 1;
c@241 243 if(index [m][0] != index [m][1])
c@241 244 {
c@241 245 irow = index [m][0];
c@241 246 icol = index [m][1];
c@241 247 for(int k = 0; k < ncol; ++k)
c@241 248 swap (b[k][irow], b[k][icol]);
c@241 249 }
c@241 250 }
c@241 251
c@241 252 for(int k = 0; k < ncol; ++k)
c@241 253 {
c@241 254 if(index [k][2] != 0)
c@241 255 {
c@268 256 std::cerr << "ERROR: Error in PolyFit::GaussJordan: matrix is singular" << std::endl;
c@268 257 return false;
c@241 258 }
c@241 259 }
c@241 260
c@241 261 for( int i = 0; i < ncol; ++i)
c@241 262 coef[i] = w[i][0];
c@241 263
c@241 264
c@241 265 return true;
c@241 266 } // end; { procedure GaussJordan }
c@241 267 //----------------------------------------------------------------------------------------------
c@241 268
c@241 269
c@241 270 bool TPolyFit::GaussJordan2(Matrix &b,
c@241 271 const vector<double> &y,
c@241 272 Matrix &w,
c@241 273 vector<vector<int> > &index)
c@241 274 {
c@241 275 //GaussJordan2; // first half of GaussJordan
c@241 276 // actual start of gaussj
c@241 277
c@241 278 double big, t;
c@241 279 double pivot;
c@241 280 double determ;
c@241 281 int irow, icol;
c@241 282 int ncol(b.size());
c@241 283 int nv = 1; // single constant vector
c@241 284 for(int i = 0; i < ncol; ++i)
c@241 285 {
c@241 286 w[i][0] = y[i]; // copy constant vector
c@241 287 index[i][2] = -1;
c@241 288 }
c@241 289 determ = 1.0;
c@241 290 for(int i = 0; i < ncol; ++i)
c@241 291 {
c@241 292 // Search for largest element
c@241 293 big = 0.0;
c@241 294 for(int j = 0; j < ncol; ++j)
c@241 295 {
c@241 296 if(index[j][2] != 0)
c@241 297 {
c@241 298 for(int k = 0; k < ncol; ++k)
c@241 299 {
c@268 300 if(index[k][2] > 0) {
c@268 301 std::cerr << "ERROR: Error in PolyFit::GaussJordan2: matrix is singular" << std::endl;
c@268 302 return false;
c@268 303 }
c@241 304
c@241 305 if(index[k][2] < 0 && fabs(b[j][k]) > big)
c@241 306 {
c@241 307 irow = j;
c@241 308 icol = k;
c@241 309 big = fabs(b[j][k]);
c@241 310 }
c@241 311 } // { k-loop }
c@241 312 }
c@241 313 } // { j-loop }
c@241 314 index [icol][2] = index [icol][2] + 1;
c@241 315 index [i][0] = irow;
c@241 316 index [i][1] = icol;
c@241 317
c@241 318 // Interchange rows to put pivot on diagonal
c@241 319 // GJ3
c@241 320 if(irow != icol)
c@241 321 {
c@241 322 determ = -determ;
c@241 323 for(int m = 0; m < ncol; ++m)
c@241 324 swap (b [irow][m], b[icol][m]);
c@241 325 if (nv > 0)
c@241 326 for (int m = 0; m < nv; ++m)
c@241 327 swap (w[irow][m], w[icol][m]);
c@241 328 } // end GJ3
c@241 329
c@241 330 // divide pivot row by pivot column
c@241 331 pivot = b[icol][icol];
c@241 332 determ *= pivot;
c@241 333 b[icol][icol] = 1.0;
c@241 334
c@241 335 for(int m = 0; m < ncol; ++m)
c@241 336 b[icol][m] /= pivot;
c@241 337 if(nv > 0)
c@241 338 for(int m = 0; m < nv; ++m)
c@241 339 w[icol][m] /= pivot;
c@241 340
c@241 341 // Reduce nonpivot rows
c@241 342 for(int n = 0; n < ncol; ++n)
c@241 343 {
c@241 344 if(n != icol)
c@241 345 {
c@241 346 t = b[n][icol];
c@241 347 b[n][icol] = 0.0;
c@241 348 for(int m = 0; m < ncol; ++m)
c@241 349 b[n][m] -= b[icol][m] * t;
c@241 350 if(nv > 0)
c@241 351 for(int m = 0; m < nv; ++m)
c@241 352 w[n][m] -= w[icol][m] * t;
c@241 353 }
c@241 354 }
c@241 355 } // { i-loop }
c@241 356 return true;
c@241 357 }
c@241 358 //----------------------------------------------------------------------------------------------
c@241 359
c@241 360 //------------------------------------------------------------------------------------
c@241 361
c@241 362 // Utility functions
c@241 363 //--------------------------------------------------------------------------
c@241 364
c@241 365 // fills a vector with zeros.
c@241 366 void NSUtility::zeroise(vector<double> &array, int n)
c@241 367 {
c@241 368 array.clear();
c@241 369 for(int j = 0; j < n; ++j)
c@241 370 array.push_back(0);
c@241 371 }
c@241 372 //--------------------------------------------------------------------------
c@241 373
c@241 374 // fills a vector with zeros.
c@241 375 void NSUtility::zeroise(vector<int> &array, int n)
c@241 376 {
c@241 377 array.clear();
c@241 378 for(int j = 0; j < n; ++j)
c@241 379 array.push_back(0);
c@241 380 }
c@241 381 //--------------------------------------------------------------------------
c@241 382
c@241 383 // fills a (m by n) matrix with zeros.
c@241 384 void NSUtility::zeroise(vector<vector<double> > &matrix, int m, int n)
c@241 385 {
c@241 386 vector<double> zero;
c@241 387 zeroise(zero, n);
c@241 388 matrix.clear();
c@241 389 for(int j = 0; j < m; ++j)
c@241 390 matrix.push_back(zero);
c@241 391 }
c@241 392 //--------------------------------------------------------------------------
c@241 393
c@241 394 // fills a (m by n) matrix with zeros.
c@241 395 void NSUtility::zeroise(vector<vector<int> > &matrix, int m, int n)
c@241 396 {
c@241 397 vector<int> zero;
c@241 398 zeroise(zero, n);
c@241 399 matrix.clear();
c@241 400 for(int j = 0; j < m; ++j)
c@241 401 matrix.push_back(zero);
c@241 402 }
c@241 403 //--------------------------------------------------------------------------
c@241 404
c@241 405
c@241 406 #endif
c@241 407