Example programs for B-splines - GNU Scientific Library -- Reference Manual
Description: GNU Scientific Library -- Reference Manual

Next: References and Further Reading, Previous: Obtaining Greville abscissae for B-spline basis functions, Up: Basis Splines

### 39.7 Examples

The following program computes a linear least squares fit to data using cubic B-spline basis functions with uniform breakpoints. The data is generated from the curve y(x) = \cos(x) \exp(-x/10) on the interval [0, 15] with gaussian noise added.

         #include <stdio.h>
         #include <stdlib.h>
         #include <math.h>
         #include <gsl/gsl_bspline.h>
         #include <gsl/gsl_multifit.h>
         #include <gsl/gsl_rng.h>
         #include <gsl/gsl_randist.h>
         #include <gsl/gsl_statistics.h>

         /* number of data points to fit */
         #define N        200

         /* number of fit coefficients */
         #define NCOEFFS  12

         /* nbreak = ncoeffs + 2 - k = ncoeffs - 2 since k = 4 */
         #define NBREAK   (NCOEFFS - 2)

         int
         main (void)
         {
           const size_t n = N;
           const size_t ncoeffs = NCOEFFS;
           const size_t nbreak = NBREAK;
           size_t i, j;
           gsl_bspline_workspace *bw;
           gsl_vector *B;
           double dy;
           gsl_rng *r;
           gsl_vector *c, *w;
           gsl_vector *x, *y;
           gsl_matrix *X, *cov;
           gsl_multifit_linear_workspace *mw;
           double chisq, Rsq, dof, tss;

           gsl_rng_env_setup();
           r = gsl_rng_alloc(gsl_rng_default);

           /* allocate a cubic bspline workspace (k = 4) */
           bw = gsl_bspline_alloc(4, nbreak);
           B = gsl_vector_alloc(ncoeffs);

           x = gsl_vector_alloc(n);
           y = gsl_vector_alloc(n);
           X = gsl_matrix_alloc(n, ncoeffs);
           c = gsl_vector_alloc(ncoeffs);
           w = gsl_vector_alloc(n);
           cov = gsl_matrix_alloc(ncoeffs, ncoeffs);
           mw = gsl_multifit_linear_alloc(n, ncoeffs);

           printf("#m=0,S=0\n");
           /* this is the data to be fitted */
           for (i = 0; i < n; ++i)
             {
               double sigma;
               double xi = (15.0 / (N - 1)) * i;
               double yi = cos(xi) * exp(-0.1 * xi);

               sigma = 0.1 * yi;
               dy = gsl_ran_gaussian(r, sigma);
               yi += dy;

               gsl_vector_set(x, i, xi);
               gsl_vector_set(y, i, yi);
               gsl_vector_set(w, i, 1.0 / (sigma * sigma));

               printf("%f %f\n", xi, yi);
             }

           /* use uniform breakpoints on [0, 15] */
           gsl_bspline_knots_uniform(0.0, 15.0, bw);

           /* construct the fit matrix X */
           for (i = 0; i < n; ++i)
             {
               double xi = gsl_vector_get(x, i);

               /* compute B_j(xi) for all j */
               gsl_bspline_eval(xi, B, bw);

               /* fill in row i of X */
               for (j = 0; j < ncoeffs; ++j)
                 {
                   double Bj = gsl_vector_get(B, j);
                   gsl_matrix_set(X, i, j, Bj);
                 }
             }

           /* do the fit */
           gsl_multifit_wlinear(X, w, y, c, cov, &chisq, mw);

           dof = n - ncoeffs;
           tss = gsl_stats_wtss(w->data, 1, y->data, 1, y->size);
           Rsq = 1.0 - chisq / tss;

           fprintf(stderr, "chisq/dof = %e, Rsq = %f\n",
                            chisq / dof, Rsq);

           /* output the smoothed curve */
           {
             double xi, yi, yerr;

             printf("#m=1,S=0\n");
             for (xi = 0.0; xi < 15.0; xi += 0.1)
               {
                 gsl_bspline_eval(xi, B, bw);
                 gsl_multifit_linear_est(B, c, cov, &yi, &yerr);
                 printf("%f %f\n", xi, yi);
               }
           }

           gsl_rng_free(r);
           gsl_bspline_free(bw);
           gsl_vector_free(B);
           gsl_vector_free(x);
           gsl_vector_free(y);
           gsl_matrix_free(X);
           gsl_vector_free(c);
           gsl_vector_free(w);
           gsl_matrix_free(cov);
           gsl_multifit_linear_free(mw);

           return 0;
         } /* main() */

The output can be plotted with gnu `graph`.

         $ ./a.out > bspline.dat
         chisq/dof = 1.118217e+00, Rsq = 0.989771
         $ graph -T ps -X x -Y y -x 0 15 -y -1 1.3 < bspline.dat > bspline.ps

The GNU Scientific Library - a free numerical library licensed under the GNU GPL
Back to the GNU Scientific Library Homepage