SDDSlib
Loading...
Searching...
No Matches
SDDS
mdbcommon
lsfn.c
Go to the documentation of this file.
1
/**
2
* @file lsfn.c
3
* @brief Computes nth order polynomial least squares fit.
4
*
5
* This file contains the implementation of the `lsfn` function,
6
* which computes a polynomial least squares fit of a specified order
7
* to given data points. It supports both weighted and unweighted fitting.
8
*
9
* Author: Michael Borland, 1986.
10
*/
11
12
#include "matlib.h"
13
#include "mdb.h"
14
15
int
p_merror(
char
*message);
16
17
/**
18
* @brief Computes nth order polynomial least squares fit.
19
*
20
* This function performs an nth order polynomial least squares fit to the provided data.
21
* It supports both weighted and unweighted fitting based on the standard deviations provided.
22
*
23
* @param xd Array of x data points.
24
* @param yd Array of y data points.
25
* @param sy Array of standard deviations of y data points. If NULL or all elements are equal, an unweighted fit is performed.
26
* @param nd Number of data points.
27
* @param nf Order of the polynomial fit (degree of the polynomial).
28
* @param coef Array to store the computed coefficients of the polynomial.
29
* @param s_coef Array to store the standard deviations of the coefficients.
30
* @param chi Pointer to store the reduced chi-squared value. If NULL, chi-squared is not computed.
31
* @param diff Array to store the differences between fitted and actual y values. If NULL, differences are not stored.
32
* @return Returns 1 on success, or 0 on error.
33
*/
34
long
lsfn
(
double
*xd,
double
*yd,
double
*sy,
/* data */
35
long
nd,
/* number of data points */
36
long
nf,
/* y = a_0 + a_1*x ... a_nf*x^nf */
37
double
*coef,
/* place to put co-efficients */
38
double
*s_coef,
/* and their sigmas */
39
double
*chi,
/* place to put reduced chi-squared */
40
double
*diff
/* place to put difference table */
41
) {
42
long
i, j, nt, unweighted;
43
double
xp, *x_i, x0;
44
static
MATRIX *X, *Y, *Yp, *C, *C_1, *Xt, *A, *Ca, *XtC, *XtCX, *T, *Tt, *TC;
45
46
nt = nf + 1;
47
if
(nd < nt) {
48
printf(
"error: insufficient data for requested order of fit\n"
);
49
printf(
"(%ld data points, %ld terms in fit)\n"
, nd, nt);
50
exit(1);
51
}
52
53
unweighted = 1;
54
if
(sy)
55
for
(i = 1; i < nd; i++)
56
if
(sy[i] != sy[0]) {
57
unweighted = 0;
58
break
;
59
}
60
61
/* allocate matrices */
62
m_alloc(&X, nd, nt);
63
m_alloc(&Y, nd, 1);
64
m_alloc(&Yp, nd, 1);
65
m_alloc(&Xt, nt, nd);
66
if
(!unweighted) {
67
m_alloc(&C, nd, nd);
68
m_alloc(&C_1, nd, nd);
69
m_zero(C);
70
m_zero(C_1);
71
}
72
m_alloc(&A, nt, 1);
73
m_alloc(&Ca, nt, nt);
74
m_alloc(&XtC, nt, nd);
75
m_alloc(&XtCX, nt, nt);
76
m_alloc(&T, nt, nd);
77
m_alloc(&Tt, nd, nt);
78
m_alloc(&TC, nt, nd);
79
80
/* Compute X, Y, C, C_1. X[i][j] = (xd[i])^j. Y[i][0] = yd[i].
81
* C = delta(i,j)*sy[i]^2 (covariance matrix of yd)
82
* C_1 = INV(C)
83
*/
84
for
(i = 0; i < nd; i++) {
85
x_i = X->a[i];
86
x0 = xd[i];
87
xp = 1.0;
88
Y->a[i][0] = yd[i];
89
if
(!unweighted) {
90
C->a[i][i] = sqr(sy[i]);
91
C_1->a[i][i] = 1 / C->a[i][i];
92
}
93
for
(j = 0; j < nt; j++) {
94
x_i[j] = xp;
95
xp *= x0;
96
}
97
}
98
99
/* Compute A, the matrix of coefficients.
100
* Weighted least-squares solution is A = INV(Xt.INV(C).X).Xt.INV(C).y
101
* Unweighted solution is A = INV(Xt.X).Xt.y
102
*/
103
if
(unweighted) {
104
/* eliminating 2 matrix operations makes this much faster than a weighted fit
105
* if there are many data points.
106
*/
107
if
(!m_trans(Xt, X))
108
return
(p_merror(
"transposing X"
));
109
if
(!m_mult(XtCX, Xt, X))
110
return
(p_merror(
"multiplying Xt.X"
));
111
if
(!m_invert(XtCX, XtCX))
112
return
(p_merror(
"inverting XtCX"
));
113
if
(!m_mult(T, XtCX, Xt))
114
return
(p_merror(
"multiplying XtX.Xt"
));
115
if
(!m_mult(A, T, Y))
116
return
(p_merror(
"multiplying T.Y"
));
117
118
/* Compute covariance matrix of A, Ca = (T.Tt)*C[0][0] */
119
if
(!m_trans(Tt, T))
120
return
(p_merror(
"computing transpose of T"
));
121
if
(!m_mult(Ca, T, Tt))
122
return
(p_merror(
"multiplying T.Tt"
));
123
if
(!m_scmul(Ca, Ca, sy ? sqr(sy[0]) : 1))
124
return
(p_merror(
"multiplying T.Tt by scalar"
));
125
}
else
{
126
if
(!m_trans(Xt, X))
127
return
(p_merror(
"transposing X"
));
128
if
(!m_mult(XtC, Xt, C_1))
129
return
(p_merror(
"multiplying Xt.C_1"
));
130
if
(!m_mult(XtCX, XtC, X))
131
return
(p_merror(
"multiplying XtC.X"
));
132
if
(!m_invert(XtCX, XtCX))
133
return
(p_merror(
"inverting XtCX"
));
134
if
(!m_mult(T, XtCX, XtC))
135
return
(p_merror(
"multiplying XtCX.XtC"
));
136
if
(!m_mult(A, T, Y))
137
return
(p_merror(
"multiplying T.Y"
));
138
139
/* Compute covariance matrix of A, Ca = T.C.Tt */
140
if
(!m_mult(TC, T, C))
141
return
(p_merror(
"multiplying T.C"
));
142
if
(!m_trans(Tt, T))
143
return
(p_merror(
"computing transpose of T"
));
144
if
(!m_mult(Ca, TC, Tt))
145
return
(p_merror(
"multiplying TC.Tt"
));
146
}
147
148
for
(i = 0; i < nt; i++) {
149
coef[i] = A->a[i][0];
150
if
(s_coef)
151
s_coef[i] = sqrt(Ca->a[i][i]);
152
}
153
154
/* Compute Yp = X.A, use to compute chi-squared */
155
if
(chi) {
156
if
(!m_mult(Yp, X, A))
157
return
(p_merror(
"multiplying X.A"
));
158
*chi = 0;
159
for
(i = 0; i < nd; i++) {
160
xp = (Yp->a[i][0] - yd[i]);
161
if
(diff != NULL)
162
diff[i] = xp;
163
xp /= sy ? sy[i] : 1;
164
*chi += xp * xp;
165
}
166
if
(nd != nt)
167
*chi /= (nd - nt);
168
}
169
170
m_free(&X);
171
m_free(&Y);
172
m_free(&Yp);
173
m_free(&Xt);
174
if
(!unweighted) {
175
m_free(&C);
176
m_free(&C_1);
177
}
178
m_free(&A);
179
m_free(&Ca);
180
m_free(&XtC);
181
m_free(&XtCX);
182
m_free(&T);
183
m_free(&Tt);
184
m_free(&TC);
185
return
(1);
186
}
lsfn
long lsfn(double *xd, double *yd, double *sy, long nd, long nf, double *coef, double *s_coef, double *chi, double *diff)
Computes nth order polynomial least squares fit.
Definition
lsfn.c:34
Generated by
1.12.0