# Creare plugin aggiuntivi

&kst; ha un'interfaccia semplice e intuitiva che facilita la creazione facile di plugin aggiuntivi. In aggiunta a specificare i requisiti fondamentali dei plugin, le sezioni seguenti descrivono come fare uso dei file di intestazione preimpostati per creare certi tipi di plugin.

## Creare un plugin di base

Un plugin di &kst; consiste di due file: un file XML e un file oggetto condiviso.

### Il file XML

Il file XML fornisce le informazioni sul plugin e descrive i suoi input e output. Quello che segue è un esempio di file XML per un plugin di &kst;:

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

    <module>

    <intro>
    <modulename name="plugindiprova"/>    <!-- Il nome del modulo -->
    <author name="Rick Chern"/> <!-- Il nome dell'autore -->
    <description text="Un plugin di prova per me"/> <!-- Una descrizione del modulo -->
    <version minor="1" major="0"/>  <!-- Il numero di versione del modulo -->
    <state devstate="release"/>     <!-- Lo stato dello sviluppo del modulo (opzionale)-->
    </intro>

    <interface>

    <!--qui gli input-->
    <input>
    <table type="float" name="Vettore di input 1" descr="Il primo vettore di input" />
    </input>

    <input>
    <float name="Scalare di input 1" descr="Il primo scalare di input" />
    </input>

    <!--gli output qui-->
    <output>
    <table type="float" name="Vettore di output 1" descr="Il primo vettore di output" />
    </output>

    <output>
    <float name="Scalare di output 1" descr="Il primo scalare di output" />
    </output>

    </interface>

    </module>

Generalmente, puoi usare l'esempio qui sopra come modello e modificarne le sezioni a seconda dei tuoi bisogni. Come si può vedere dall'esempio, il file XML consiste di un nodo `module`. Il nodo `module` ha un nodo `intro` e un nodo `interface`. Dovresti modificare il nodo `intro` appropriatamente usando i commenti nel file XML sopra come guida. È importante che `modulename` abbia l'attributo `name` impostato allo stesso nome che sarà usato dal tuo file oggetto condiviso.

Il nodo `interface` descrive gli input e gli output del plugin. Ogni input è descritto da un nodo `input`, e ogni output da un nodo `output`. Ogni input o output dovrebbe avere un nodo o `table` o `float` come figlio. L'attributo `type` di un nodo `table` deve essere impostato a `"float"`. Nota come l'ordine degli input e degli output sia importante: l'ordine è usato per determinare i valori degli indici per ogni array di input e output del file oggetto, ed è lo stesso ordine usato per visualizzare i campi di input e output nell'interfaccia dei plugin di &kst;.

Una volta che hai completato il file XML, salvalo come `[nomemodulo].xml`, dove `[nomemodulo]` è il valore dell'attributo `name` del nodo `modulename`.

### Il file oggetto condiviso

Il file oggetto condiviso contiene la funzionalità vera e propria del plugin. In parole povere, determina come ottenere gli output dagli input dati. I requisiti del file oggetto condiviso sono i seguenti:

- L'oggetto deve esportare il seguente simbolo di collegamento C:

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

  dove simbolo deve essere il valore dell'attributo `name` del nodo `modulename` nel file XML. Questa è la sola funzione che sarà chiamata da &kst; (sebbene tu possa avere altre funzioni). Il seguito descrive ogni argomento di questa funzione:

  `const double *const inArrays[]`

    L'array degli array di input. Ogni array di input corrisponde a un vettore di input. Gli array sono nello stesso ordine dei vettori elencati nel file XML, quindi `inArrays[0]` è l'array che rappresenta il primo vettore di input, `inArrays[1]` è l'array che rappresenta il secondo vettore di input, e così via.

  `const int inArraysLens[]`

    L'array contenente le lunghezze degli array per ogni array di input. Le lunghezze sono conservate nello stesso ordine degli array in `inArrays[]` (per esempio `inArrayLens[0]` è la lunghezza di `inArray[0]`).

  `const double inScalars[]`

    L'array degli scalari di input. Gli scalari sono conservati nello stesso ordine in cui sono elencati nel file XML.

  `double *outArrays[]`

    L'array degli array di output. Ogni array di output corrisponde a un vettore di output, e gli array dovrebbero essere nello stesso ordine in cui i vettori di output sono elencati nel file XML.

  `int outArrayLens[]`

    L'array che dovrebbe contenere le lunghezze degli array di output. Le lunghezze dovrebbero essere conservate nello stesso ordine degli array in `outArrays[]`.

  `double outScalars[]`

    L'array degli scalari di output. Gli scalari dovrebbero essere nello stesso ordine in cui sono elencati nel file XML.

- La funzione deve restituire `0` se è eseguita con successo, e `-1` altrimenti.

- Il codice per il file oggetto deve poter gestire degli input inattesi, come vettori di input vuoti (nella maggior parte dei casi restituire un valore di `-1` dovrebbe essere sufficiente quando si incontra una situazione del genere).

- Il numero e il tipo di output deve essere esattamente come specificato dal file XML.

- Avrai probabilmente bisogno di ridimensionare gli array in `outArrays[]`. Per farlo, usa la funzione `realloc()`. Per esempio,

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

  allocherà spazio per cinque double per `outArrays[0]`. Non usare nessun allocatore di memoria che non sia `realloc()`.

- Gli argomenti di input devono rimanere costanti. Non farli diventare tipi non costanti.

Quello che segue è un esempio del codice sorgente del file oggetto condiviso per un plugin semplice:

    #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[])

    //Accetta 1 vettore e 1 scalare. Moltiplica tutti gli elementi del vettore per lo
    //scalare, e restituisci il vettore risultante. Restituisci anche lo scalare originale.
    {
            //Imposta gli output
            outArrayLens[0]=inArrayLens[0];

            //ridimensiona gli array di output
            outArrays[0]=(double*)realloc(outArrays[0], inArrayLens[0]*sizeof(double));

            //moltiplica ogni elemento del vettore di input
            //per lo scalare
            for (int i=0; i<inArrayLens[0]; i++)
            {
                    outArrays[0][i]=inArrays[0][i] * is[0];
            }

            //ora imposta lo scalare di output
            outScalars[0]=is[0];

            return 0;
    }

### Compilare il plugin

Se usi &gcc; per compilare il tuo plugin, compila semplicemente il tuo file oggetto:

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

e quindi crea la libreria condivisa:

    ld -o ilmioplugin.so -shared ilmioplugin.o

Il file `.so` risultante e il file `.xml` devono essere messi nella stessa cartella. Quando usi il gestore dei plugin di &kst; per caricare il file XML, esso cercherà automaticamente l'oggetto condiviso nella stessa cartella.

## Creare plugin di regressione lineare

Per creare plugin di regressione lineare, potresti implementare da te degli algoritmi di regressione e restituire i vettori appropriati. Tuttavia, &kst; è già equipaggiato con dei file di intestazione che ti facilitano l'implementazione di plugin di regressione lineare con il metodo dei minimi quadrati fornendo solo poche funzioni. Questa sezione descriverà come usare a tuo vantaggio questi file.

### File di intestazione

Sono forniti due file di intestazione per effettuare regressioni lineari, `linear.h` (per le regressioni lineari non pesate) e `linear_weighted.h` (per le regressioni lineari pesate). Sono entrambi situati sotto `kst/plugins/fits/` nel pacchetto sorgente di &kst;. Per usare questi file, includi solo uno di loro nel codice sorgente del tuo plugin:

    #include <../linear.h>

o

    #include <../linear_weighted.h>

(per convenzione, metteremo il codice sorgente del plugin una cartella sotto dove si trovano i file di intestazione).

### Implementazione delle funzioni richieste

Dato un modello lineare generico:

dove `y` è un vettore di `n` osservazioni, `X` è una matrice di `n` per `p` variabili di predizione, e `c` è il vettore di `p` parametri di regressione ottimale che devono essere stimati, i file di intestazione forniscono delle funzioni per stimare `c` per dei dati `y` e `X`. Per fornire `X`, deve essere implementata la funzione seguente nel codice sorgente del plugin:

    double calculate_matrix_entry( double dX, int iPos )

Questa funzione dovrebbe restituire il valore della voce nella colonna `iPos` della matrice delle variabili di predizione, usando il valore `dX` per `x`. Questa funzione sarà chiamata da linear.h o linear_weighted.h. L'implementazione di questa funzione dipende dal modello che vuoi usare per la regressione, ed è unico per ogni plugin di regressione regressione lineare. Per esempio, per regredire a un modello polinomiale, `calculate_matrix_entry` potrebbe essere implementata come segue:

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

### Chiamare le funzioni di regressione

Una volta che il file di intestazione appropriato è stato incluso e `calculate_matrix_entry` è stata implementata, chiama la funzione di regressione appropriata inclusa dal file di intestazione:

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

o

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

Ogni funzione restituirà `0` in caso di successo, o `-1` in caso d'errore, quindi è una buona idea impostare il valore restituito della funzione C esportata uguale al valore restituito dalla funzione di regressione. Per tenere le cose semplici, il codice del plugin può semplicemente passare gli argomenti dati alla funzione C esportata alla funzione di regressione. Nota, comunque, che inArrays deve essere strutturato come segue:

- `inArrays[0]` deve contenere l'array delle coordinate x dei punti dei dati

- `inArrays[1]` deve contenere l'array delle coordinate y dei punti dei dati

- `inArrays[2]` esiste solo se viene chiamata `kstfit_linear_weighted`, e deve contenerel'array di pesi da usare per la regressione.

Il modo più semplice di assicurarsi che inArrays sia strutturato correttamente è specificare l'ordine giusto di vettori di input nel file XML del plugin.

`iNumParams` è il numero di parametri usati nel modello di regressione, che dovrebbe essere uguale al numero di colonne nella matrice `X` delle variabili di predizione. `iNumParams` deve essere impostata correttamente prima che sia chiamata la funzione di regressione.

Dopo che è stata chiamata `kstfit_linear_unweighted` o `kstfit_linear_weighted`, `outArrays` e `outScalars` saranno impostate come segue:

- `outArrays[0]` conterrà l'array dei valori y regrediti.

- `outArrays[1]` conterrà l'array dei residui.

- `outArrays[2]` conterrà l'array dei parametri di regressione ottimale che sono stati stimati.

- `outArrays[3]` conterrà la matrice di covarianza, restituita riga dopo riga in un array.

- `outScalars[0]` conterrà chi²/nu, dove chi² è la somma pesata dei residui, e nu sono i gradi di libertà.

`outArrayLens` sarà impostata correttamente per indicare la lunghezza di ciascun array di output.

Assicurati che gli output specificati nel file XML corrispondano a quelli che la funzione C esportata restituisce (che nella maggior parte dei casi saranno semplicemente gli output restituiti dalla funzione di regressione).

### Esempio

Quello che segue è un esempio del codice sorgente di un plugin di regressione lineare.

    /*
     *  Plugin di regressione polinomiale per KST.
     *  Copyright 2004, Università della Columbia Britannica
     *  Distribuito sotto le condizioni della 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;
    }

## Creare plugin di regressione non lineare

&kst; fornisce file di intestazione progettati per semplificare la creazione di plugin di regressione non lineare con il metodo dei minimi quadrati. Le sezioni seguenti descrivono in dettaglio l'uso dei file di intestazione.

### File di intestazione e definizioni

I file di intestazione per le regressioni non lineari sono situati in `kst/plugins/fits_nonlinear` nel pacchetto sorgente di &kst;. I file sono chiamati `non_linear.h` e `non_linear_weighted.h` rispettivamente per le regressioni pesate e non. Per usare questi file, includi solo uno di loro nel codice sorgente del tuo plugin:

    #include <../non_linear.h>

o

    #include <../non_linear_weighted.h>

(per convenzione, metteremo il codice sorgente del plugin una cartella sotto dove sono i file di intestazione).

Siccome ogni regressione non lineare è un processo iterativo, devi anche definire il numero massimo di iterazioni che dovrebbero essere effettuate. L'algoritmo di regressione non lineare si fermerà quando almeno una delle condizioni seguenti sarà vera:

- È stato raggiunto il numero massimo di iterazioni.

- È stata raggiunta una precisione di 10-4.

Inoltre, devi definire il numero di parametri nel modello, perché non è passato esplicitamente alla funzione di regressione. Per definire questi due valori, includi ciò che segue in cima al tuo codice sorgente:

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

sostituendo `[num1]` con il numero di parametri nel modello, e `[num2]` con il numero massimo di iterazioni da eseguire.

### Implementazione delle funzioni richieste

Per usare i file di intestazione per le regressioni non lineari, devi fornire la funzione da usare come modello, le derivate parziali della funzione rispetto a ogni parametro, e le stime iniziali dei parametri di regressione ottimale. Per farlo, devono essere implementate tre funzioni. Queste funzioni sono descritte sotto.

`double function_calculate( double `dX`, double* `pdParameters` )`

  Questa funzione calcola il valore y del modello di regressione per un dato valore `dX` per x, usando l'array di parametri dato `pdParameters`. L'ordine dei parametri in `pdParameters` è arbitrario, ma dovrebbe essere consistente con le altre due funzioni implementate. Per esempio, per un modello esponenziale, `function_calculate` potrebbe essere implementata come segue:

      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` )`

  Questa funzione calcola le derivate parziali della funzione modello per un dato valore `dX` di x. Le derivate parziali dovrebbero essere restituite in `pdDerivatives`. L'ordine delle derivate parziali nell'array `pdDerivatives` dovrebbe corrispondere all'ordine dei parametri in `pdParameters` (cioè se `pdParameters[0]` contiene il parametro lambda per un modello esponenziale, `pdDerivatives[0]` dovrebbe contenere la derivata del modello rispetto a lambda.

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

  Questa funzione dà una stima iniziale dei parametri di regressione ottimale alla funzione di regressione. Gli array dei valori x e y dei punti dei dati sono dati rispettivamente in `pdX` e `pdY`, e il numero di punti di dati è dato da `iLength`. Puoi usare uno qualsiasi o tutti questi parametri a tua discrezione per calcolare la stima iniziale. La funzione dovrebbe mettere le stime iniziali calcolate in `pdParameterEstimates`, con l'ordine delle stime corrispondente all'ordine dei parametri in `pdParameters` di `function_calculate` e `function_derivative`. Tieni a mente che la stima iniziale è importante per determinare se la funzione di regressione converge a una soluzione o meno.

### Chiamare le funzioni di regressione

Una volta che sono state implementate tutte le funzioni necessarie, può essere chiamata la funzione di regressione dal file di intestazione incluso:

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

o

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

a seconda che tu stia implementando una regressione non pesata o pesata.

La funzione restituirà `0` in caso di successo, o `-1` in caso d'errore, quindi la cosa più semplice è impostare il valore restituito dalla funzione C come uguale al valore restituito dalla funzione di regressione. Per tenere le cose semplici, il codice per il plugin può semplicemente passare gli argomenti dati alla funzione C esportata alla funzione di regressione. Nota, comunque, che inArrays deve essere strutturata come segue:

- `inArrays[0]` deve contenere l'array delle coordinate x dei punti dei dati

- `inArrays[1]` deve contenere l'array delle coordinate y dei punti dei dati

- `inArrays[2]` esiste solo se viene chiamata `kstfit_linear_weighted`, e deve contenerel'array di pesi da usare per la regressione.

Il modo più semplice di assicurarsi che inArrays sia strutturato correttamente è specificare l'ordine giusto di vettori di input nel file XML del plugin.

Dopo che è stata chiamata `kstfit_linear_unweighted` o `kstfit_linear_weighted`, `outArrays` e `outScalars` saranno impostate come segue:

- `outArrays[0]` conterrà l'array dei valori y regrediti.

- `outArrays[1]` conterrà l'array dei residui.

- `outArrays[2]` conterrà l'array dei parametri di regressione ottimale che sono stati stimati.

- `outArrays[3]` conterrà la matrice di covarianza, restituita riga dopo riga in un array.

- `outScalars[0]` conterrà chi²/nu, dove chi² è la somma pesata dei residui, e nu sono i gradi di libertà.

`outArrayLens` sarà impostata correttamente per indicare la lunghezza di ciascun array di output.

Assicurati che gli output specificati nel file XML corrispondano a quelli che la funzione C esportata restituisce (che nella maggior parte dei casi saranno semplicemente gli output restituiti dalla funzione di regressione).

### Esempio

Quello che segue è un esempio di un plugin di regressione non lineare che effettua una regressione a un modello esponenziale.

    /*
     *  Plugin di regressione esponenziale per KST.
     *  Copyright 2004, Università della Columbia Britannica
     *  Rilasciato sotto le condizioni della 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_exponential(const double *const inArrays[], const int inArrayLens[],
                    const double inScalars[],
                    double *outArrays[], int outArrayLens[],
                    double outScalars[]);

    int kstfit_exponential(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 );
    }

## Creare plugin per filtri di passaggio

&kst; fornisce dei file di intestazione per semplificare l'implementazione dei plugin per filtri di passaggio. L'uso di questi file di intestazione è descritto sotto.

### File di intestazione

Il file di intestazione dei filtri di passaggio è situato in `kst/plugins/pass_filters` del pacchetto sorgente di &kst;. Il file è chiamato `filters.h`. Per usare questo file, includilo nel codice sorgente del tuo plugin:

    #include <../filters.h>

(per convenzione, metteremo il codice sorgente del plugin una cartella sotto dove si trovano i file di intestazione).

### Funzioni richieste

Il file di intestazione `filters.h` contiene una sola funzione che calcola la trasformata di Fourier di una funzione data, applica il filtro dato alla trasformata di Fourier, e quindi calcola la trasformata di Fourier inversa della trasformata di Fourier filtrata. Per fornire il filtro, la seguente funzione deve essere implementata nel codice sorgente del tuo plugin:

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

Questa funzione dovrebbe calcolare l'ampiezza filtrata per la frequenza `dFreqValue`. `inScalars[]` conterrà gli scalari di input inalterati per il plugin, specificati nel file XML. Molto probabilmente `inScalars[]` conterrà frequenze di taglio o altre proprietà del filtro. Per esempio, un'implementazione di un filtro passa-alto di Butterworth, `filter_calculate` potrebbe essere implementata come segue:

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

### Chiamare la funzione di filtro

Una volta che la `filter_calculate` richiesta sarà stata implementata, potrà essere chiamata la funzione di filtraggio dal file di intestazione:

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

Gli argomenti dati alla funzione C esportata possono normalmente essere passati a `kst_pass_filter` senza modifiche. Tuttavia, ci sono delle restrizioni sugli argomenti:

- `inArrays[0]` deve contenere l'array di dati da filtrare.

- `inScalars` dovrebbe contenere i parametri specifici del filtro che la funzione `filter_calculate` deve usare.

Dopo la chiamata della funzione, `outArrays[0]` conterrà l'array di dati filtrati, e `outArrayLens` sarà impostato appropriatamente. La funzione `kst_pass_filter` non usa `outScalars`.

### Esempio

Quello che segue è un esempio di plugin di filtro di passaggio che implementa il filtro passa-alto di Butterworth.

    /*
     *  Plugin per il filtro passa-basso di Butterworth per KST.
     *  Copyright 2004, Università della Columbia Britannica
     *  Rilasciato sotto le condizioni della 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;
    }