[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

39 Base Spline

Esse capítulo descreve funções para o cálculo de suavisação de splines base (B-splines). Um spline suavisada difere de um spline interpolada na curva resultante onde não é requerido que a mesma passe através de cada ponto de dados. Veja Veja seção Interpolação, para informação sobre interpolação de splines.

O arquivo de cabeçalho ‘gsl_bspline.h’ contém os protótipos para as funções bspline e declarações relacionadas.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

39.1 Visão Geral

B-splines são comumente usadas como funções base para ajustar curvas planas para grandes conjuntos de dados. Para fazer isso, o eixo das abscissas é quebrado em algum número de intervalos, onde as extremidades de cada intervalo são chamadas pontos de parada. Esses pontos de parada são então convertidos para nós impondo-se várias condições de continuidade e suavisação em cada interface. Dado um não decrescente vetor de nós t = {t_0, t_1, …, t_{n+k-1}}, as n splines base de ordem k são definidas por

Bi,1(x) =



1,
ti ≤ x < ti+1
0,
outros

Bi,k(x) = (x − ti)

(ti+k−1 − ti)
Bi,k−1(x) + (ti+k − x)

(ti+k − ti+1)
Bi+1,k−1(x)
para i = 0, …, n-1. O caso comum de B-splines cúbicas é dado por k = 4. A relação de recorrência acima pode ser avaliada de uma forma numericamente estável pelo algoritmo de Boor.

Se definirmos nós apropriados sobre um intervalo [a,b] então as funções B-spline base formam um completo conjunto sobre aquele intervalo. Todavia podemos expandir uma função de suavisação como

f(x) = n−1

i=0 
ci Bi,k(x)
dados suficientes pares de dados (x_j, f(x_j)). Os coeficientes c_i podem ser prontamente obtidos a partir de um ajuste por mínimos quadrados.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

39.2 Inicializando o resolvedor de B-spline

O cálculo de funções B-spline requerem um pré-alocado espaço de trabalho do tipo gsl_bspline_workspace. Se derivadas de B-spline forem também requeridas, um adicional é necessário gsl_bspline_deriv_workspace.

Function: gsl_bspline_workspace * gsl_bspline_alloc (const size_t k, const size_t nbreak)

Essa função aloca um espaço de trabalho para calcular B-splines de ordem k. O número de pontos de parada é dado por nbreak. Isso conduz a n = nbreak + k - 2 funções base. B-splines cúbicas são especificadas por k = 4. O tamanho do espaço de trabalho é O(5k + nbreak).

Function: void gsl_bspline_free (gsl_bspline_workspace * w)

Essa função libera a memória associada ao espaço de trabalho w.

Function: gsl_bspline_deriv_workspace * gsl_bspline_deriv_alloc (const size_t k)

Essa função aloca um espaço de trabalho para calcular as derivadas de uma função B-spline base de ordem k. O tamanho do espaço de trabalho é O(2k^2).

Function: void gsl_bspline_deriv_free (gsl_bspline_deriv_workspace * w)

Essa função libera a memória associada ao espaço de trabalho de derivadas w.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

39.3 Construindo o vetor de nós

Function: int gsl_bspline_knots (const gsl_vector * breakpts, gsl_bspline_workspace * w)

Essa função calcula os nós associados aos dados pontos de parada e armazena-os internamente em w->knots.

Function: int gsl_bspline_knots_uniform (const double a, const double b, gsl_bspline_workspace * w)

Essa função assume pontos de parada uniformemente espaçados no intervalo [a,b] e constrói o correspondente vetor de nós usando o préviamente especificado parâmetro nbreak. Os nós são armazenados em w->knots.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

39.4 Avaliação de B-slpines

Function: int gsl_bspline_eval (const double x, gsl_vector * B, gsl_bspline_workspace * w)

Essa função avalia todas funções B-spline base na posição x e armazena-as no vetor B, de forma que o i-ésimo elemento é B_i(x). O vetor B deve ser de comprimento n = nbreak + k - 2. Esse valor pode também ser obtido chamando gsl_bspline_ncoeffs. Calculando todas as funções de base uma única vez é mais eficiente que calculá-las individualmente, devido à natureza de definir relações de recorrência.

Function: int gsl_bspline_eval_nonzero (const double x, gsl_vector * Bk, size_t * istart, size_t * iend, gsl_bspline_workspace * w)

Essa função avalia todos potencialmente não nulas funções B-spline base na posição x e armazena-as em um vetor Bk, de forma que o i-ésimo elemento seja B_(istart+i)(x). O último elemento de Bk é B_(iend)(x). O vetor Bk deve ser de comprimento k. Por meio do retorno de somente funções de base não nulas, essa função permite que quantidades envolvendo combinações lineares de B_i(x) sejam calculadas sem termos desnecessários (tal combinação linear ocorre, por exemplo, quando avalia-se uma função interpolada).

Function: size_t gsl_bspline_ncoeffs (gsl_bspline_workspace * w)

Essa função retorna o número de coeficientes de B-spline dado por n = nbreak + k - 2.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

39.5 Avaliação de derivadas B-spline

Function: int gsl_bspline_deriv_eval (const double x, const size_t nderiv, gsl_matrix * dB, gsl_bspline_workspace * w, gsl_bspline_deriv_workspace * dw)

Essa função avalia todas as derivadas de funções B-spline base de ordem 0 até a ordem nderiv (inclusive) na posição x e armazena-as na matriz dB. O (i,j)-ésimo elemento de dB é d^jB_i(x)/dx^j. A matriz dB deve ser de tamanho n = nbreak + k - 2 por nderiv + 1. O valor n pode também ser obtida chamando gsl_bspline_ncoeffs. Note que funções de avaliações são incluídas como a derivada de zero-ésima ordem em dB. calculando todas as derivadas de função base de uma vez é mais eficiente que calculá-las individualmente, devido à natureza da definição da relação de recorrência.

Function: int gsl_bspline_deriv_eval_nonzero (const double x, const size_t nderiv, gsl_matrix * dB, size_t * istart, size_t * iend, gsl_bspline_workspace * w, gsl_bspline_deriv_workspace * dw)

Essa função avalia todas as potencialmente não nulas derivadas de funções B-spline base de ordem 0 até a ordem nderiv (inclusive) na posição x e armazena-as na matriz dB. O (i,j)-ésimo elemento de dB é d^j/dx^j B_(istart+i)(x). A última linha de dB contém d^j/dx^j B_(iend)(x). A matriz dB deve ser de tamanho k o qual deve ser pelo menos nderiv + 1. Note que avaliações de função são incluídas como derivadas de zero-ésima ordem em dB. Por meio do retorno somente as funções base não nulas, essa função permite que quantidades envolvendo combinações lineares dos B_i(x) com suas derivadas sejam calculadas sem termos desnecessários.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

39.6 Abscissas de Greville - Trabalhando

As abscissas de Greville são definidas para serem a localização média de k-1 nós consecutivos no vetor de nós para cada função spline base de ordem k. Com o primeiro e últimos nós no vetor de nós no gsl_bspline_workspace excluídos, existem gsl_bspline_ncoeffs abscissas de Greville para qualquer dado B-spline base. Esses valores são muitas vezes usados em aplicações de colocação de B-spline e pode também serem chamados pontos de Marsden-Schoenberg.

Function: double gsl_bspline_greville_abscissa (size_t i, gsl_bspline_workspace *w);

Retorna a localização da i-ésima abscissa de Greville para a dada B-spline base. Para o pior caso sendo k=1, a implementação escolhe retornar o ponto médio entre dois pontos de parada.


[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

39.7 Exemplos

O seguinte programa calcula um ajuste linear por mínimos quadrados para dados usando funções de B-splines base cúbicas com pontos de parada uniforme. Os dados são gerados a partir da curva y(x) = \cos{(x)} \exp{(-x/10)} sobre o intervalo [0, 15] com ruído de Gauss adicionado.

#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() */

A saída pode ser mostrada com o 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

bspline

[ << ] [ < ] [ Acima ] [ > ] [ >> ]         [Topo] [Conteúdo] [Índice] [ ? ]

39.8 Referências e Leituras Adicionais

Informação adicional sobre os algoritmos descritos nessa seção pode ser encontrado no seguinte livro,

Informação adicional sobre as abscissas de Greville e colocação de B-spline pode ser encontrado no seguinte artigo,

Uma grande coleção de rotinas B-spline está disponivel na biblioteca PPPACK disponível em http://www.netlib.org/pppack, que é também parte de SLATEC.


[ << ] [ >> ]           [Topo] [Conteúdo] [Índice] [ ? ]

Esse documento foi gerado em 23 de Julho de 2013 usando texi2html 5.0.