annotate maths/Polyfit.h @ 374:3e5f13ac984f

Add bandwidth, snr parameters
author Chris Cannam <c.cannam@qmul.ac.uk>
date Fri, 18 Oct 2013 14:57:48 +0100
parents 31f22daeba64
children f4bb0bce64d4
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@325 127 if(npoints != (int)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