Lav plugin for ikke-lineær indstilling

Kst sørger for deklarationsfiler for at forenkle implementeringen af plugin med ikke-lineære mindste kvadrat tilpasning. Brugen af deklarationsfilerne beskrives nedenfor.

Deklarationsfiler og definitioner

Deklarationsfilerne for ikke-lineær indstilling er under kst(plugins/fits_nonlinear/ i kildekodearkivet for Kst. Filerne hedder non_linear.h og non_linear_weighted.h for henholdsvis uvægtede og vægtede tilpasninger. For at bruge filerne, inkluderes kun en af dem i dit plugins kildekode:

#include <../non_linear.h>
eller
#include <../non_linear_weighted.h>
(pr konvention placerer vi kildekoden for pluginnet et mappeniveau under stedet hvor deklarationsfilerne er).

Eftersom ikke-lineær tilpasning er en iterativ proces, skal du også definere et maksimalt antal iterationer som skal udføres. Algoritmen for ikke-lineær indstilling stopper når mindst en af følgende betingelser er sand:

  • Maksimalt antal iterationer er opnået.

  • Præcisionen 10-4 er opnået.

Desuden skal du definere antal parametre i modellen, eftersom de ikke eksplicit sendes til tilpasningsfunktionen. For at definere disse to værdier, inkluderes følgende længst oppe i din kildekode:

#define NUM_PARAMS [num1]
#define MAX_NUM_ITERATIONS [num2]

som erstatter [num1] med antal parametre i modellen, og [num2] med maksimalt antal iterationer at udføre.

Implementér nødvendige funktioner

For at bruge deklarationsfilen for ikke-lineær tilpasning, skal du sørge for funktionen som skal bruges som model, partielle afledede for funktionen med hensyn til hver parameter og de oprindelige estimater for parametrene for bedste tilpasning. For at gøre dette skal tre funktioner implementeres. Disse funktioner beskrives nedenfor.

double function_calculate( double dX, double* pdParameters )

Denne funktion beregner Y-værdien for tilpasningsmodellen for en given X-værdi dX, med det felt der sørges for med parametre pdParameters. Parametrenes rækkefølge i pdParameters er vilkårlig, men skal stemme overens med de to andre implementerede funktioner. For eksempel for en eksponentiel model, vil function_calculate kunne implementeres på følgende måde:

double function_calculate( double dX, double* pdParameters ) {
  double dScale         = pdParameters[0];
  double dLambda = pdParameters[1];
  double dOffset = pdParameters[2];
  double dY;

  dY  = ( dScale * exp( -dLambda * dX ) ) + dOffset;

  return dY;
}
void function_derivative( double dX, double* pdParameters, double* pdDerivatives )

Denne funktion beregner partielle afledede for modelfunktionen for en givet X-værdi dX. De partielle afledede skal returneres i pdDerivatives. Rækkefølgen af de partielle afledede i feltet pdDerivatives skal svare til rækkefølgen af parametrene i pdParameters (dvs. hvis pdParameters[0] indeholder parameteren lambda for en eksponentialmodel, skal pdDerivatives[0] indeholde den afledede for modellen med hensyn til lambda).

void function_initial_estimate( const double* pdX, const double* pdY, int iLength, double* pdParameterEstimates )

Denne funktion sørger for et oprindelig estimat af parametrene for bedste tilpasning for tilpasningsfunktionen. Feltet med X- og Y-værdier for datapunkterne er henholdsvis i pdX og pdY, og antal datapunkter angives af iLength. Du kan bruge alle eller ingen af parametrene efter behag til at beregne det oprindelige estimat. Funktionen skal placere de beregnede oprindelige estimater i pdParameterEstimates, og lade estimaternes rækkefølge stemme med rækkefølgen for parametrene i pdParameters i function_calculate og function_derivative. Husk at det oprindelige estimat er vigtigt for at afgøre om tilpasningsfunktionen konvergerer mod en løsning.

Kalde tilpasningfunktionerne

Når alle nødvendige funktioner er implementeret, kan tilpasningsfunktionen fra den inkluderede deklarationsfil kaldes:

kstfit_nonlinear( inArrays, inArrayLens,
                  inScalars, outArrays,
                  outArrayLens, outScalars );
eller
kstfit_nonlinear_weighted( inArrays, inArrayLens,
                           inScalars, outArrays,
                           outArrayLens, outScalars );
afhængig af om du implementerer en uvægtet tilpasning eller en vægtet tilpasning.

Funktionen returnerer 0 når det lykkes, eller -1 ved en fejl, så det er nemmest at lade returværdien for den eksporterede C-funktion være den samme som returværdien for tilpasningsfunktionen. For at holde det enkelt, kan koden for pluginnet blot sende argumenterne som gives videre til den eksporterede C-funktion til tilpasningsfunktionen. Bemærk dog at inArrays skal have følgende struktur:

  • inArrays[0] skal indeholde feltet med x-koordinater for datapunkterne

  • inArrays[1] skal indeholde feltet med y-koordinater for datapunkterne

  • inArrays[2] er der kun hvis kstfit_linear_weighted kaldes, og skal indeholde feltet med vægtninger for tilpasningen.

Den nemmeste måde at sikre at inArrays er rigtigt struktureret er at angive de n rigtige rækkefølge for inddatavektorer i pluginnets XML-fil.

Efter funktionen kstfit_linear_unweighted eller kstfit_linear_weighted er kaldet, er outArrays og outScalars blevet tildelt følgende:

  • outArrays[0] vil indeholde feltet med tilpassede y-værdier.

  • outArrays[1] vil indeholde feltet med rester.

  • outArrays[2] vil indeholde feltet med estimerede parametre for bedste tilpasning.

  • outArrays[3] vil indeholde kovariansmatricen, returneret linje for linje i feltet.

  • outScalars[0] vil indeholde chi^2/nu, hvor chi^2 er den vægtede sum af kvadratresternes, og nu frihedsgraderne.

outArrayLens vil have den rigtige værdi til at angive længden for hvert uddatafelt.

Sørg for at angiven uddata i XML-filen passer sammen med dem som de eksporterede C-funktioner returnerer (hvilket i de fleste tilfælde simpelthen er uddata fra tilpasningsfunktionen).

Eksempel

Det følgende er et eksempel på et ikke-lineært tilpasningsplugin som udfører en tilpasning til en eksponentiel model.

/*
 *  Exponential fit plugin for KST.
 *  Copyright 2004, The University of British Columbia
 *  Released under the terms of the GPL.
 */

#define NUM_PARAMS 3
#define MAX_NUM_ITERATIONS 500

#include "../non_linear.h"

void function_initial_estimate( const double* pdX, const double* pdY,
                                int iLength, double* pdParameterEstimates ) {
  KST_UNUSED( pdX )
  KST_UNUSED( pdY )
  KST_UNUSED( iLength )

  pdParameterEstimates[0] =  1.0;
  pdParameterEstimates[1] =  0.0;
  pdParameterEstimates[2] =  0.0;
}

double function_calculate( double dX, double* pdParameters ) {
  double dScale         = pdParameters[0];
  double dLambda = pdParameters[1];
  double dOffset = pdParameters[2];
  double dY;

  dY  = ( dScale * exp( -dLambda * dX ) ) + dOffset;

  return dY;
}

void function_derivative( double dX, double* pdParameters, double* pdDerivatives ) {
  double dScale         = pdParameters[0];
  double dLambda = pdParameters[1];
  double dExp;  
  double ddScale;
  double ddLambda;
  double ddOffset;
  
  dExp     = exp( -dLambda * dX );
  ddScale  = dExp;
  ddLambda = -dX * dScale * dExp;
  ddOffset = 1.0;

  pdDerivatives[0] = ddScale;
  pdDerivatives[1] = ddLambda;
  pdDerivatives[2] = ddOffset;
}

extern "C" int kstfit_eksponential(const double *const inArrays[], const int inArrayLens[],
                const double inScalars[],
                double *outArrays[], int outArrayLens[],
                double outScalars[]);

int kstfit_eksponential(const double *const inArrays[], const int inArrayLens[],
                const double inScalars[],
                double *outArrays[], int outArrayLens[],
                double outScalars[])
{
  return kstfit_nonlinear( inArrays, inArrayLens,
                           inScalars, outArrays,
                           outArrayLens, outScalars );
}