annotate maths/Polyfit.h @ 96:88f3cfcff55f

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