1 /***************************************************************************
2 File : PolynomialFit.cpp
3 Project : QtiPlot
4 --------------------------------------------------------------------
5 Copyright : (C) 2006 by Ion Vasilief
6 Email (use @ for *) : ion_vasilief*yahoo.fr
7 Description : Polynomial Fit and Linear Fit classes
8
9 ***************************************************************************/
10
11 /***************************************************************************
12 * *
13 * This program is free software; you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation; either version 2 of the License, or *
16 * (at your option) any later version. *
17 * *
18 * This program is distributed in the hope that it will be useful, *
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
21 * GNU General Public License for more details. *
22 * *
23 * You should have received a copy of the GNU General Public License *
24 * along with this program; if not, write to the Free Software *
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
26 * Boston, MA 02110-1301 USA *
27 * *
28 ***************************************************************************/
29 #include "PolynomialFit.h"
30
31 #include <QMessageBox>
32 #include <QLocale>
33
34 #include <gsl/gsl_multifit.h>
35 #include <gsl/gsl_fit.h>
36
PolynomialFit(ApplicationWindow * parent,Graph * g,int order,bool legend)37 PolynomialFit::PolynomialFit(ApplicationWindow *parent, Graph *g, int order, bool legend)
38 : Fit(parent, g), d_order(order), show_legend(legend)
39 {
40 init();
41 }
42
PolynomialFit(ApplicationWindow * parent,QwtPlotCurve * c,int order,bool legend)43 PolynomialFit::PolynomialFit(ApplicationWindow *parent, QwtPlotCurve *c, int order, bool legend)
44 : Fit(parent, c), d_order(order), show_legend(legend)
45 {
46 init();
47 setDataFromCurve(c);
48 }
49
PolynomialFit(ApplicationWindow * parent,QwtPlotCurve * c,double start,double end,int order,bool legend)50 PolynomialFit::PolynomialFit(ApplicationWindow *parent, QwtPlotCurve *c, double start, double end, int order, bool legend)
51 : Fit(parent, c), d_order(order), show_legend(legend)
52 {
53 init();
54 setDataFromCurve(c, start, end);
55 }
56
PolynomialFit(ApplicationWindow * parent,Graph * g,QString & curveTitle,int order,bool legend)57 PolynomialFit::PolynomialFit(ApplicationWindow *parent, Graph *g, QString& curveTitle, int order, bool legend)
58 : Fit(parent, g), d_order(order), show_legend(legend)
59 {
60 init();
61 setDataFromCurve(curveTitle);
62 }
63
PolynomialFit(ApplicationWindow * parent,Graph * g,QString & curveTitle,double start,double end,int order,bool legend)64 PolynomialFit::PolynomialFit(ApplicationWindow *parent, Graph *g, QString& curveTitle, double start, double end, int order, bool legend)
65 : Fit(parent, g), d_order(order), show_legend(legend)
66 {
67 init();
68 setDataFromCurve(curveTitle, start, end);
69 }
70
PolynomialFit(ApplicationWindow * parent,Table * t,const QString & xCol,const QString & yCol,int startRow,int endRow,int order,bool legend)71 PolynomialFit::PolynomialFit(ApplicationWindow *parent, Table *t, const QString& xCol, const QString& yCol, int startRow, int endRow, int order, bool legend)
72 : Fit(parent, t), d_order(order), show_legend(legend)
73 {
74 init();
75 setDataFromTable(t, xCol, yCol, startRow, endRow);
76 }
77
init()78 void PolynomialFit::init()
79 {
80 setObjectName(tr("Polynomial"));
81 is_non_linear = false;
82 d_explanation = tr("Polynomial Fit");
83 setOrder(d_order);
84 d_scale_errors = false;
85 }
86
setOrder(int order)87 void PolynomialFit::setOrder(int order)
88 {
89 d_order = order;
90 d_p = d_order + 1;
91
92 freeWorkspace();
93 initWorkspace(d_p);
94
95 d_formula = generateFormula(d_order);
96 d_param_names = generateParameterList(d_order);
97
98 d_param_explain.clear();
99 for (int i=0; i<d_p; i++)
100 d_param_explain << "";
101 }
102
generateFormula(int order)103 QString PolynomialFit::generateFormula(int order)
104 {
105 QString formula = QString::null;
106 for (int i = 0; i < order+1; i++){
107 QString par = "a" + QString::number(i);
108 formula += par;
109 if (i>0)
110 formula +="*x";
111 if (i>1)
112 formula += "^"+QString::number(i);
113 if (i != order)
114 formula += "+";
115 }
116 return formula;
117 }
118
generateParameterList(int order)119 QStringList PolynomialFit::generateParameterList(int order)
120 {
121 QStringList lst;
122 for (int i = 0; i < order+1; i++)
123 lst << "a" + QString::number(i);
124 return lst;
125 }
126
calculateFitCurveData(double * X,double * Y)127 void PolynomialFit::calculateFitCurveData(double *X, double *Y)
128 {
129 if (d_gen_function){
130 double X0 = d_x[0];
131 double step = (d_x[d_n-1]-X0)/(d_points-1);
132 for (int i=0; i<d_points; i++){
133 double x = X0+i*step;
134 X[i] = x;
135 double yi = 0.0;
136 for (int j=0; j<d_p;j++)
137 yi += d_results[j]*pow(x, j);
138 Y[i] = yi;
139 }
140 } else {
141 for (int i=0; i<d_points; i++) {
142 double x = d_x[i];
143 X[i] = x;
144 double yi = 0.0;
145 for (int j=0; j<d_p; j++)
146 yi += d_results[j]*pow(x, j);
147 Y[i] = yi;
148 }
149 }
150 }
151
eval(double * par,double x)152 double PolynomialFit::eval(double *par, double x)
153 {
154 double y = 0.0;
155 for (int j=0; j<d_p; j++)
156 y += par[j]*pow(x, j);
157 return y;
158 }
159
fit()160 void PolynomialFit::fit()
161 {
162 if (d_init_err)
163 return;
164
165 if (d_p > d_n){
166 QMessageBox::critical((ApplicationWindow *)parent(), tr("QtiPlot - Fit Error"),
167 tr("You need at least %1 data points for this fit operation. Operation aborted!").arg(d_p));
168 return;
169 }
170
171 gsl_matrix *X = gsl_matrix_alloc (d_n, d_p);
172
173 for (int i = 0; i <d_n; i++){
174 for (int j= 0; j < d_p; j++)
175 gsl_matrix_set (X, i, j, pow(d_x[i],j));
176 }
177
178 gsl_vector_view y = gsl_vector_view_array (d_y, d_n);
179 gsl_vector_view w = gsl_vector_view_array (d_w, d_n);
180 gsl_multifit_linear_workspace * work = gsl_multifit_linear_alloc (d_n, d_p);
181
182 if (d_weighting == NoWeighting)
183 gsl_multifit_linear (X, &y.vector, d_param_init, covar, &chi_2, work);
184 else
185 gsl_multifit_wlinear (X, &w.vector, &y.vector, d_param_init, covar, &chi_2, work);
186
187 for (int i = 0; i < d_p; i++)
188 d_results[i] = gsl_vector_get(d_param_init, i);
189
190 gsl_multifit_linear_free (work);
191 gsl_matrix_free (X);
192
193 generateFitCurve();
194
195 if (show_legend)
196 showLegend();
197
198 ApplicationWindow *app = (ApplicationWindow *)parent();
199 if (app->writeFitResultsToLog)
200 app->updateLog(logFitInfo(0, 0));
201 }
202
legendInfo()203 QString PolynomialFit::legendInfo()
204 {
205 ApplicationWindow *app = (ApplicationWindow *)parent();
206 QLocale locale = app->locale();
207 QString legend = "Y=" + locale.toString(d_results[0], 'g', d_prec);
208 for (int j = 1; j < d_p; j++){
209 double cj = d_results[j];
210 if (cj>0 && !legend.isEmpty())
211 legend += "+";
212
213 QString s;
214 s.sprintf("%.5f",cj);
215 if (s != "1.00000")
216 legend += locale.toString(cj, 'g', d_prec);
217
218 legend += "X";
219 if (j>1)
220 legend += "<sup>" + QString::number(j) + "</sup>";
221 }
222 return legend;
223 }
224
225 /*****************************************************************************
226 *
227 * Class LinearFit
228 *
229 *****************************************************************************/
230
LinearFit(ApplicationWindow * parent,QwtPlotCurve * c)231 LinearFit::LinearFit(ApplicationWindow *parent, QwtPlotCurve *c)
232 : Fit(parent, c)
233 {
234 init();
235 setDataFromCurve(c);
236 }
237
LinearFit(ApplicationWindow * parent,QwtPlotCurve * c,double start,double end)238 LinearFit::LinearFit(ApplicationWindow *parent, QwtPlotCurve *c, double start, double end)
239 : Fit(parent, c)
240 {
241 init();
242 setDataFromCurve(c, start, end);
243 }
244
LinearFit(ApplicationWindow * parent,Graph * g)245 LinearFit::LinearFit(ApplicationWindow *parent, Graph *g)
246 : Fit(parent, g)
247 {
248 init();
249 }
250
LinearFit(ApplicationWindow * parent,Graph * g,const QString & curveTitle)251 LinearFit::LinearFit(ApplicationWindow *parent, Graph *g, const QString& curveTitle)
252 : Fit(parent, g)
253 {
254 init();
255 setDataFromCurve(curveTitle);
256 }
257
LinearFit(ApplicationWindow * parent,Graph * g,const QString & curveTitle,double start,double end)258 LinearFit::LinearFit(ApplicationWindow *parent, Graph *g, const QString& curveTitle, double start, double end)
259 : Fit(parent, g)
260 {
261 init();
262 setDataFromCurve(curveTitle, start, end);
263 }
264
LinearFit(ApplicationWindow * parent,Table * t,const QString & xCol,const QString & yCol,int startRow,int endRow)265 LinearFit::LinearFit(ApplicationWindow *parent, Table *t, const QString& xCol, const QString& yCol, int startRow, int endRow)
266 : Fit(parent, t)
267 {
268 init();
269 setDataFromTable(t, xCol, yCol, startRow, endRow);
270 }
271
init()272 void LinearFit::init()
273 {
274 d_scale_errors = false;
275
276 d_p = 2;
277 d_min_points = d_p;
278
279 covar = gsl_matrix_alloc (d_p, d_p);
280 d_results = new double[d_p];
281
282 d_param_init = gsl_vector_alloc(d_p);
283 gsl_vector_set_all (d_param_init, 1.0);
284
285 is_non_linear = false;
286 d_formula = "A*x+B";
287 d_param_names << "B" << "A";
288 d_param_explain << "y-intercept" << "slope";
289 d_explanation = tr("Linear Regression");
290 setObjectName(tr("Linear"));
291 }
292
fit()293 void LinearFit::fit()
294 {
295 if (d_init_err)
296 return;
297
298 if (d_p > d_n){
299 QMessageBox::critical((ApplicationWindow *)parent(), tr("QtiPlot - Fit Error"),
300 tr("You need at least %1 data points for this fit operation. Operation aborted!").arg(d_p));
301 return;
302 }
303
304 double c0, c1, cov00, cov01, cov11;
305 if (d_weighting == NoWeighting)
306 gsl_fit_linear(d_x, 1, d_y, 1, d_n, &c0, &c1, &cov00, &cov01, &cov11, &chi_2);
307 else
308 gsl_fit_wlinear(d_x, 1, d_w, 1, d_y, 1, d_n, &c0, &c1, &cov00, &cov01, &cov11, &chi_2);
309
310 d_results[0] = c0;
311 d_results[1] = c1;
312
313 gsl_matrix_set(covar, 0, 0, cov00);
314 gsl_matrix_set(covar, 0, 1, cov01);
315 gsl_matrix_set(covar, 1, 1, cov11);
316 gsl_matrix_set(covar, 1, 0, cov01);
317
318 generateFitCurve();
319
320 ApplicationWindow *app = (ApplicationWindow *)parent();
321 if (app->writeFitResultsToLog)
322 app->updateLog(logFitInfo(0, 0));
323 }
324
calculateFitCurveData(double * X,double * Y)325 void LinearFit::calculateFitCurveData(double *X, double *Y)
326 {
327 if (d_gen_function){
328 double X0 = d_x[0];
329 double step = (d_x[d_n-1]-X0)/(d_points-1);
330 for (int i=0; i<d_points; i++){
331 double x = X0+i*step;
332 X[i] = x;
333 Y[i] = d_results[0] + d_results[1]*x;
334 }
335 } else {
336 for (int i=0; i<d_points; i++) {
337 double x = d_x[i];
338 X[i] = x;
339 Y[i] = d_results[0] + d_results[1]*x;
340 }
341 }
342 }
343
344
345 /*****************************************************************************
346 *
347 * Class LinearSlopeFit
348 *
349 *****************************************************************************/
350
LinearSlopeFit(ApplicationWindow * parent,Graph * g)351 LinearSlopeFit::LinearSlopeFit(ApplicationWindow *parent, Graph *g)
352 : Fit(parent, g)
353 {
354 init();
355 }
356
LinearSlopeFit(ApplicationWindow * parent,Graph * g,const QString & curveTitle)357 LinearSlopeFit::LinearSlopeFit(ApplicationWindow *parent, Graph *g, const QString& curveTitle)
358 : Fit(parent, g)
359 {
360 init();
361 setDataFromCurve(curveTitle);
362 }
363
LinearSlopeFit(ApplicationWindow * parent,Graph * g,const QString & curveTitle,double start,double end)364 LinearSlopeFit::LinearSlopeFit(ApplicationWindow *parent, Graph *g, const QString& curveTitle, double start, double end)
365 : Fit(parent, g)
366 {
367 init();
368 setDataFromCurve(curveTitle, start, end);
369 }
370
LinearSlopeFit(ApplicationWindow * parent,Table * t,const QString & xCol,const QString & yCol,int startRow,int endRow)371 LinearSlopeFit::LinearSlopeFit(ApplicationWindow *parent, Table *t, const QString& xCol, const QString& yCol, int startRow, int endRow)
372 : Fit(parent, t)
373 {
374 init();
375 setDataFromTable(t, xCol, yCol, startRow, endRow);
376 }
377
init()378 void LinearSlopeFit::init()
379 {
380 d_scale_errors = false;
381
382 d_p = 1;
383 d_min_points = d_p;
384
385 covar = gsl_matrix_alloc (d_p, d_p);
386 d_results = new double[d_p];
387
388 d_param_init = gsl_vector_alloc(d_p);
389 gsl_vector_set_all (d_param_init, 1.0);
390
391 is_non_linear = false;
392 d_formula = "A*x";
393 d_param_names << "A";
394 d_param_explain << "slope";
395 d_explanation = tr("Linear Regression");
396 setObjectName(tr("LinearSlope"));
397 }
398
fit()399 void LinearSlopeFit::fit()
400 {
401 if (d_init_err)
402 return;
403
404 if (d_p > d_n){
405 QMessageBox::critical((ApplicationWindow *)parent(), tr("QtiPlot - Fit Error"),
406 tr("You need at least %1 data points for this fit operation. Operation aborted!").arg(d_p));
407 return;
408 }
409
410 double c1, cov11;
411 if (d_weighting == NoWeighting)
412 gsl_fit_mul(d_x, 1, d_y, 1, d_n, &c1, &cov11, &chi_2);
413 else
414 gsl_fit_wmul(d_x, 1, d_w, 1, d_y, 1, d_n, &c1, &cov11, &chi_2);
415
416 d_results[0] = c1;
417
418 gsl_matrix_set(covar, 0, 0, cov11);
419 generateFitCurve();
420
421 ApplicationWindow *app = (ApplicationWindow *)parent();
422 if (app->writeFitResultsToLog)
423 app->updateLog(logFitInfo(0, 0));
424 }
425
calculateFitCurveData(double * X,double * Y)426 void LinearSlopeFit::calculateFitCurveData(double *X, double *Y)
427 {
428 if (d_gen_function){
429 double X0 = d_x[0];
430 double step = (d_x[d_n-1] - X0)/(d_points - 1);
431 for (int i=0; i<d_points; i++){
432 double x = X0 + i*step;
433 X[i] = x;
434 Y[i] = d_results[0]*x;
435 }
436 } else {
437 for (int i=0; i<d_points; i++) {
438 double x = d_x[i];
439 X[i] = x;
440 Y[i] = d_results[0]*x;
441 }
442 }
443 }
444