SDDS ToolKit Programs and Libraries for C and Python
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
MATRIX *X = NULL, *Y = NULL, *Yp = NULL, *C = NULL, *C_1 = NULL, *Xt = NULL, *A = NULL, *Ca = NULL, *XtC = NULL, *XtCX = NULL, *T = NULL, *Tt = NULL, *TC = NULL;
45
long
status = 0;
46
47
nt = nf + 1;
48
if
(nd < nt) {
49
printf(
"error: insufficient data for requested order of fit\n"
);
50
printf(
"(%ld data points, %ld terms in fit)\n"
, nd, nt);
51
exit(1);
52
}
53
54
unweighted = 1;
55
if
(sy)
56
for
(i = 1; i < nd; i++)
57
if
(sy[i] != sy[0]) {
58
unweighted = 0;
59
break
;
60
}
61
62
/* allocate matrices */
63
m_alloc(&X, nd, nt);
64
m_alloc(&Y, nd, 1);
65
m_alloc(&Yp, nd, 1);
66
m_alloc(&Xt, nt, nd);
67
if
(!unweighted) {
68
m_alloc(&C, nd, nd);
69
m_alloc(&C_1, nd, nd);
70
m_zero(C);
71
m_zero(C_1);
72
}
73
m_alloc(&A, nt, 1);
74
m_alloc(&Ca, nt, nt);
75
m_alloc(&XtC, nt, nd);
76
m_alloc(&XtCX, nt, nt);
77
m_alloc(&T, nt, nd);
78
m_alloc(&Tt, nd, nt);
79
m_alloc(&TC, nt, nd);
80
81
/* Compute X, Y, C, C_1. X[i][j] = (xd[i])^j. Y[i][0] = yd[i].
82
* C = delta(i,j)*sy[i]^2 (covariance matrix of yd)
83
* C_1 = INV(C)
84
*/
85
for
(i = 0; i < nd; i++) {
86
x_i = X->a[i];
87
x0 = xd[i];
88
xp = 1.0;
89
Y->a[i][0] = yd[i];
90
if
(!unweighted) {
91
C->a[i][i] = sqr(sy[i]);
92
C_1->a[i][i] = 1 / C->a[i][i];
93
}
94
for
(j = 0; j < nt; j++) {
95
x_i[j] = xp;
96
xp *= x0;
97
}
98
}
99
100
/* Compute A, the matrix of coefficients.
101
* Weighted least-squares solution is A = INV(Xt.INV(C).X).Xt.INV(C).y
102
* Unweighted solution is A = INV(Xt.X).Xt.y
103
*/
104
if
(unweighted) {
105
/* eliminating 2 matrix operations makes this much faster than a weighted fit
106
* if there are many data points.
107
*/
108
if
(!m_trans(Xt, X))
109
{ status = p_merror(
"transposing X"
);
goto
cleanup; }
110
if
(!m_mult(XtCX, Xt, X))
111
{ status = p_merror(
"multiplying Xt.X"
);
goto
cleanup; }
112
if
(!m_invert(XtCX, XtCX))
113
{ status = p_merror(
"inverting XtCX"
);
goto
cleanup; }
114
if
(!m_mult(T, XtCX, Xt))
115
{ status = p_merror(
"multiplying XtX.Xt"
);
goto
cleanup; }
116
if
(!m_mult(A, T, Y))
117
{ status = p_merror(
"multiplying T.Y"
);
goto
cleanup; }
118
119
/* Compute covariance matrix of A, Ca = (T.Tt)*C[0][0] */
120
if
(!m_trans(Tt, T))
121
{ status = p_merror(
"computing transpose of T"
);
goto
cleanup; }
122
if
(!m_mult(Ca, T, Tt))
123
{ status = p_merror(
"multiplying T.Tt"
);
goto
cleanup; }
124
if
(!m_scmul(Ca, Ca, sy ? sqr(sy[0]) : 1))
125
{ status = p_merror(
"multiplying T.Tt by scalar"
);
goto
cleanup; }
126
}
else
{
127
if
(!m_trans(Xt, X))
128
{ status = p_merror(
"transposing X"
);
goto
cleanup; }
129
if
(!m_mult(XtC, Xt, C_1))
130
{ status = p_merror(
"multiplying Xt.C_1"
);
goto
cleanup; }
131
if
(!m_mult(XtCX, XtC, X))
132
{ status = p_merror(
"multiplying XtC.X"
);
goto
cleanup; }
133
if
(!m_invert(XtCX, XtCX))
134
{ status = p_merror(
"inverting XtCX"
);
goto
cleanup; }
135
if
(!m_mult(T, XtCX, XtC))
136
{ status = p_merror(
"multiplying XtCX.XtC"
);
goto
cleanup; }
137
if
(!m_mult(A, T, Y))
138
{ status = p_merror(
"multiplying T.Y"
);
goto
cleanup; }
139
140
/* Compute covariance matrix of A, Ca = T.C.Tt */
141
if
(!m_mult(TC, T, C))
142
{ status = p_merror(
"multiplying T.C"
);
goto
cleanup; }
143
if
(!m_trans(Tt, T))
144
{ status = p_merror(
"computing transpose of T"
);
goto
cleanup; }
145
if
(!m_mult(Ca, TC, Tt))
146
{ status = p_merror(
"multiplying TC.Tt"
);
goto
cleanup; }
147
}
148
149
for
(i = 0; i < nt; i++) {
150
coef[i] = A->a[i][0];
151
if
(s_coef)
152
s_coef[i] = sqrt(Ca->a[i][i]);
153
}
154
155
/* Compute Yp = X.A, use to compute chi-squared */
156
if
(chi) {
157
if
(!m_mult(Yp, X, A))
158
{ status = p_merror(
"multiplying X.A"
);
goto
cleanup; }
159
*chi = 0;
160
for
(i = 0; i < nd; i++) {
161
xp = (Yp->a[i][0] - yd[i]);
162
if
(diff != NULL)
163
diff[i] = xp;
164
xp /= sy ? sy[i] : 1;
165
*chi += xp * xp;
166
}
167
if
(nd != nt)
168
*chi /= (nd - nt);
169
}
170
171
status = 1;
172
173
cleanup:
174
m_free(&X);
175
m_free(&Y);
176
m_free(&Yp);
177
m_free(&Xt);
178
if
(!unweighted) {
179
m_free(&C);
180
m_free(&C_1);
181
}
182
m_free(&A);
183
m_free(&Ca);
184
m_free(&XtC);
185
m_free(&XtCX);
186
m_free(&T);
187
m_free(&Tt);
188
m_free(&TC);
189
return
(status);
190
}
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