# Lav yderligere plugin

&kst; har en enkel og standardiseret grænseflade som tillader nemt at lave oprette yderligere plugin. Udover at give detaljer om grundlæggende krav for plugin, beskriver følgende afsnit hvordan færdigskrevne deklarationsfiler kan bruges til at lave visse slags plugin.

## Lav et basalt plugin

Et &kst;-plugin består af to filer: en XML-fil og en delt objektfil.

### XML-filen

XML-filen sørger for information om plugin og beskriver dets inddata og uddata. Det følgende er et eksempel på en XML-fil for et &kst;-plugin:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE Module SYSTEM "file:/Repository/Level2/Soft/ProC/moduledef.dtd">

    <module>

    <intro>
    <moduletame name="testplugin"/>    <!-- Modulets navn -->
    <author name="Rick Chern"/> <!-- Forfatterens navn -->
    <description text="Et testplugin for mig"/> <!-- En beskrivelse af modulet -->
    <version minor="1" major="0"/>  <!-- Modulets versionsnummer -->
    <state devstate="release"/>     <!-- Udviklingstilstanden for modulet (valgfrit)-->
    </intro>

    <interface>

    <!--inputs here-->
    <input>
    <table type="float" name="Input Vector 1" descr="Den første inddatavektor" />
    </input>

    <input>
    <float name="Input Scalar 1" descr="Den første inddataskalar" />
    </input>

    <!--outputs here-->
    <output>
    <table type="float" name="Output Vector 1" descr="Den første uddatavektor" />
    </output>

    <output>
    <float name="Output Scalar 1" descr="Den første uddataskalar" />
    </output>

    </interface>

    </module>

I almindelighed kan du bruge eksemplet ovenfor som en skabelon og ændre dele af det til at passe med dine behov. Som det ses i eksemplet, består XML-filen af knuden `module`. Knuden `module` indeholder knuderne `intro` og `interface`. Du skal ændre knuden `intro` på passende måde ved at bruge kommentarerne i XML-filen ovenfor som guider. Det er vigtigt at `moduletame` har egenskaben `name` sat til det samme navn som din delte objektfil vil bruge.

Knuden `interface` beskriver pluginnets egentlige inddata og uddata. Hver inddataværdi beskrives af knuden `input`, og hver uddataværdi beskrives af knuden `output`. Hver inddataværdi eller uddataværdi skal enten have delknuden `table` eller `float`. Egenskaben `type` i en `table` skal være sat til `"float"`. Bemærk at rækkefølgen for inddata og uddata spiller en rolle: Rækkefølgen bruges til at afgøre indelsværdien for hver inddataværdi og uddataværdi i objektfilen, og er samme rækkefølge som de inddatafelter og uddatafelter der burges til at vise grænsefladen for plugin i &kst;.

Når du er klar med XML-filen, gemmes den som `[modulnavn].xml`, hvor `[modulnavn]` er værdien for egenskaben `name` i knuden `moduletame`.

### Den delte objektfil

Den delte objektfil indeholder selve pluginnets funktion. Med andre ord afgør den hvordan uddata skal laves ud fra givne inddata. Følgende krav gælder for den delte objektfil:

- Objektet skal eksportere følgende C-link-symboler:

      int symbol(const double *const inArrays[],
                 const int inArrayLens[],
                 const double inScalars[],
                 double *outArrays[],
                 int outArrayLens[],
                 double outScalars[])

  hvor `symbol` skal være værdien på egenskaben `name` i knuden `moduletame` i XML-filen. Dette er den eneste funktion som vil blive kaldet af &kst; (selv om du kan have flere funktioner). Det følgende beskriver hvert argument for funktionen:

  `const double *const inArrays[]`

- Feltet med inddatafelt. Hvert inddatafelt svarer til en inddatavektor. Felterne er i samme rækkefølge som vektorerne på listen i XML-filen, så `inArrays[0]` er feltet som representerer den første inddatavektor, `inArrays[1]` er feltet som representerer den andre inddatavektor, og så videre.

`const int inArraysLens[]`

- Feltet som indeholder feltlængderne for hvert inddatafelt. Længderne opbevares i samme rækkefølge som felterne i `inArrays[]` (f.eks. er `inArrayLens[0]` længden på `inArrays[0]`).

`const double inScalars[]`

- Feltet med inddataskalarer. Skalarerne opbevares i samme rækkefølge som de er på listen i XML-filen.

`double *outArrays[]`

- Feltet med uddatafelt. Hvert uddatafelt svarer til en uddatavektor, og felterne skal være i samme rækkefølge som uddatavektorerne er på listen i XML-filen.

`int outArrayLens[]`

- Feltet som skal indeholde længderne på uddatafelterne. Længderne skal opbevares i samme rækkefølge som i felterne i `outArrays[]`.

`double outScalars[]`

- Feltet med uddataskalarer. Skalarerne skal være i samme rækkefølge som de er på listen i XML-filen.

- Funktionen skal returnere `0` hvis det lykkes at udføre den, og `-1` ellers.

- Koden i objektfilen skal håndtere uventede inddata, såsom tomme inddatafelter (i de fleste tilfælde er returværdien `-1` tilstrækkelig når sådanne situationer opstår).

- Antal og type af uddata skal være nøjagtigt som det angives i XML-filen.

- Du skal formodentlig ændre størrelse på felterne i `outArrays[]`. For at gøre det, bruges funktionen `realloc()`. For eksempel

      outArrays[0]=(double*)realloc(outArrays[0], 5*sizeof(double));

  allokerer plads til fem dobbelte decimaltal i `outArrays[0]`. Brug ikke anden hukommelsesallokering end `realloc()`.

- Inddataargumenterne skal forblive konstante. Konvertér dem ikke til ikke-konstante typer.

Følgende er et eksempel på den delte objektfils kildekode for et enkelt plugin:

    #include <stdlib.h>

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

    int testplugin(const double *const inArrays[], const int inArrayLens[],
                    const double is[],
                    double *outArrays[], int outArrayLens[],
                    double outScalars[])

    //Accept 1 vector and 1 scalar. Multiply all elements of the vector by the
    //scalar, and output the resulting vector. Also output the original scalar.
    {
            //Set the outputs
            outArrayLens[0]=inArrayLens[0];

            //resize the output arrays
            outArrays[0]=(double*)realloc(outArrays[0], inArrayLens[0]*sizeof(double));

            //multiply each element of the input vector
            //by the scalar
            for (int i=0; i<inArrayLens[0]; i++)
            {
                    outArrays[0][i]=inArrays[0][i] * is[0];
            }

            //now set the output scalar
            outScalars[0]=is[0];

            return 0;
    }

### Kompilér pluginnet

Hvis du bruger &gcc; til at kompilere pluginnet, kompileres objektfilen blot:

    cc -Wall -c -o myplugin.o myplugin.c -fPIC -DPIC

og derefter oprettes det delte bibliotek:

    ld -o myplugin.so -shared myplugin.o

De resulterende filer `*.so` og `*.xml` skal placeres i samme mappe. Når du bruger plugin-håndteringen i &kst; til at indlæse XML-filen, kigger den automatisk efter den delte objektfil i samme mappe.

## Lav et plugin for lineærindstilling

For at lave et plugin for lineærindstilling, kan du implementere dine egne indstillingsalgoritmer og give passende vektorer som uddata. &kst; levereres dog allerede med deklarationsfiler som gør det enkelt for dig at implementere plugin for lineær mindste kvadratindstilling ved kun at sørge for nogle få funktioner. Dette afsnit beskriver hvordan man får nytte af disse filer.

### Deklarationsfiler

Der sørges for to deklarationsfiler til at udføre lineærindstillinger, `linear.h` (for uvægtede lineærindstillinger) og `linear_weighted.h` (for vægtede lineærindstillinger). Begge findes under `kst(plugins/fits/` i kildekodearkivet for &kst;. For at bruge filerne, inkluderes blot en af dem i dit plugins kildekode:

    #include <../linear.h>

eller

    #include <../linear_weighted.h>

(pr konvention placerer vi kildekoden for pluginnet et mappeniveau under stedet hvor deklarationsfilerne er).

### Implementér nødvendige funktioner

Givet en generel lineær model:

hvor `y` er en vektor med `n` observationer, `X` er en matrix med størrelsen `n` gange `p` med prediktorvariabler, og `c` er vektoren med `p` parametre for bedste indstilling som skal estimeres. Deklarationsfilen sørger for funktioner til at estimere `c` for et givet `y` og `X`. For at sørge for `X`, skal følgende funktion implementeres i pluginnets kildekode:

    double calculate_matrix_entry( double dX, int iPos )

Funktionen skal returnere værdien af resultatet i søjle `iPos` fra matricen med prediktorvariabler, ved at bruge `x`-værdien `dX`. Funktionen kaldes af linear.h eller linear_weighted.h. Implementeringen af funktionen afhænger af modellen du vil bruge til indstillingen, og er entydig for hvert plugin for lineærindstilling. For eksempel for at tilpasse en polynommodel, vil funktionen `calculate_matrix_entry` kunne implementeres på følgende måde:

    double calculate_matrix_entry( double dX, int iPos ) {
      double dY;
      dY = pow( dX, (double)iPos );
      return dY;
    }

### Kalde tilpasningfunktionerne

Når en passende deklarationsfil er inkluderet og funktionen `calculate_matrix_entry` er implementeret, kaldes en passende indstillingsfunktion som inkluderes fra deklarationsfilen:

    kstfit_linear_unweighted( inArrays, inArrayLens,
                              outArrays, outArrayLens,
                              outScalars, iNumParams );

eller

    kstfit_linear_weighted( inArrays, inArrayLens,
                            outArrays, outArrayLens,
                            outScalars, iNumParams );

Hver funktion returnerer `0` når det lykkes, eller `-1` ved fejl, så det er en god idé at lade returværdien for den eksporterede C-funktion være den samme som returværdien for indstillingsfunktionen. For at holde det enkelt, kan koden for pluginnet blot sende argumenterne videre som gives 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.

`iNumParams` er antal parametre som indgår i den brugte tilpasningsmodel, hvilket skal være lig med antal søjler i matricen `X` med prediktorvariabler. `iNumParams` skal angives rigtigt før tilpasningsfunktionen kaldes.

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å kildekoden for et plugin for lineærindstilling.

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

    #include "../linear.h"

    double calculate_matrix_entry( double dX, int iPos ) {
      double dY;

      dY = pow( dX, (double)iPos );

      return dY;
    }

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

    int kstfit_polynomial_unweighted(
      const double *const inArrays[],
      const int inArrayLens[],
            const double inScalars[],
            double *outArrays[], int outArrayLens[],
            double outScalars[])
    {
      int iRetVal = -1;
      int iNumParams;

      iNumParams = 1 + (int)floor( inScalars[0] );
      if( iNumParams > 0 ) {
        iRetVal = kstfit_linear_unweighted( inArrays, inArrayLens,
                                            outArrays, outArrayLens,
                                            outScalars, iNumParams );
      }

      return iRetVal;
    }

## 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 );
    }

## Lav plugin for passfilter

&kst; sørger for deklarationsfiler for at forenkle implementeringen af plugin med passfilter. Brugen af deklarationsfilerne beskrives nedenfor.

### Deklarationsfiler

Deklarationsfilen for passfiltret er i `kst/plugins/pass_filters` i kildekodearkivet for &kst;. Filen hedder `filters.h`. For at bruge filen, inkluderes den i dit plugins kildekode:

    #include <../filters.h>

(pr konvention placerer vi kildekoden for pluginnet et mappeniveau under stedet hvor deklarationsfilerne er).

### Nødvendige funktioner

Deklarationsfilen `filters.h` indeholder en enkelt funktion som beregner Fouriertransformationen for en funktion der sørges for, anvender det filter der er sørget for på Fouriertransformationen og derefter beregner den inverse Fouriertransformation for den filtrerede transformen. For at sørge for filtret, skal følgende funktion implementeres i dit plugins kildekode:

`double filter_calculate( double `dFreqValue`, const double `inScalars[]` )`

Funktionen skal beregne filtreret amplitude for frekvensen `dFreqValue`. `inScalars[]` indeholder de uændrede inddataskalarer for pluginnet, som angives i XML-filen. Sandsynligvis indeholder `inScalars[]` afskæringsfrekvenser eller andre egenskaber for filtret. For eksempel for at implementere et Butterworth højpassfilter, kan funktionen `filter_calculate` implementeres som følger:

    double filter_calculate( double dFreqValue, const double inScalars[] ) {
      double dValue;
      if( dFreqValue > 0.0 ) {
        dValue = 1.0 / ( 1.0 +
                        pow( inScalars[1] / dFreqValue, 2.0 * (double)inScalars[0] ) );
      } else {
        dValue = 0.0;
      }
      return dValue;
    }

### Kald filterfunktionen

Så snart den nødvendige `filter_calculate` er implementeret, kan filterfunktionen fra deklarationsfilen kaldes:

    kst_pass_filter( inArrays,
                     inArrayLens,
                     inScalars,
                     outArrays,
                     outArrayLens,
                     outScalars );

Argumenterne som sendes til den eksporterede C-funktion kan sædvanligvis sendes til `kst_pass_filter` uden ændringer. Der er dog nogle begrænsninger for argumenterne:

- `inArrays[0]` skal indeholde feltet med data der skal filtreres.

- `inScalars` skal indeholde filterspecifikke parametre som skal bruges af funktionen `filter_calculate`.

Efter funktionskaldet kommer `outArrays[0]` til at indeholde det filtrerede datafelt, og `outArrayLens` vil blive sat passende. Funktionen `kst_pass_filter` bruger ikke `outScalars`.

### Eksempel

Det følgende er et eksempel på et plugin med et passfilter som implementerer Butterworth højpassfiltrering.

    /*
     *  Butterworth low pass filter plugin for KST.
     *  Copyright 2004, The University of British Columbia
     *  Released under the terms of the GPL.
     */

    #include <stdlib.h>
    #include <math.h>
    #include "../filters.h"

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

    int butterworth_highpass(const double *const inArrays[], const int inArrayLens[],
                    const double inScalars[],
                    double *outArrays[], int outArrayLens[],
                    double outScalars[])
    {
      int iReturn;

      iReturn = kst_pass_filter( inArrays,
                                 inArrayLens,
                                 inScalars,
                                 outArrays,
                                 outArrayLens,
                                 outScalars );

      return iReturn;
    }

    double filter_calculate( double dFreqValue, const double inScalars[] ) {
      double dValue;

      if( dFreqValue > 0.0 ) {
        dValue = 1.0 / ( 1.0 + pow( inScalars[1] / dFreqValue, 2.0 * (double)inScalars[0] ) );
      } else {
        dValue = 0.0;
      }

      return dValue;
    }