SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
lsfn.c File Reference

Detailed Description

Computes nth order polynomial least squares fit.

This file contains the implementation of the lsfn function, which computes a polynomial least squares fit of a specified order to given data points. It supports both weighted and unweighted fitting.

Author: Michael Borland, 1986.

Definition in file lsfn.c.

#include "matlib.h"
#include "mdb.h"

Go to the source code of this file.

Functions

int p_merror (char *message)
 
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.
 

Function Documentation

◆ 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.

This function performs an nth order polynomial least squares fit to the provided data. It supports both weighted and unweighted fitting based on the standard deviations provided.

Parameters
xdArray of x data points.
ydArray of y data points.
syArray of standard deviations of y data points. If NULL or all elements are equal, an unweighted fit is performed.
ndNumber of data points.
nfOrder of the polynomial fit (degree of the polynomial).
coefArray to store the computed coefficients of the polynomial.
s_coefArray to store the standard deviations of the coefficients.
chiPointer to store the reduced chi-squared value. If NULL, chi-squared is not computed.
diffArray to store the differences between fitted and actual y values. If NULL, differences are not stored.
Returns
Returns 1 on success, or 0 on error.

Definition at line 34 of file lsfn.c.

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
173cleanup:
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}