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