# Criar 'Plugins' Adicionais

O &kst; tem uma interface simples e normalizada que facilita a criação de 'plugins' adicionais. Para além de detalhar os requisitos básicos para os 'plugins', as secções seguintes descrevem como tirar partido dos ficheiros de inclusão pré-gravados para criar certos tipos de 'plugins'.

## Criar um 'Plugin' Básico

Um 'plugin' do &kst; consiste em dois ficheiros — um ficheiro em XML e um ficheiro-objecto dinâmico.

### O Ficheiro XML

O ficheiro XML oferece informações sobre o 'plugin' e descreve as suas entradas e saídas. O seguinte é um exemplo de um ficheiro XML para um 'plugin' do &kst;:

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

    <module>

    <intro>
    <modulename name="pluginteste"/>    <!-- O nome do módulo -->
    <author name="José Pires"/> <!-- O nome do autor -->
    <description text="Um plugin de teste para mim"/> <!-- Uma descrição do módulo -->
    <version minor="1" major="0"/>  <!-- O número de versão do módulo -->
    <state devstate="release"/>     <!-- O estado de desenvolvimento do módulo (opcional) -->
    </intro>

    <interface>

    <!--inputs here-->
    <input>
    <table type="float" name="Input Vector 1" descr="The first input vector" />
    </input>

    <input>
    <float name="Input Scalar 1" descr="The first input scalar" />
    </input>

    <!--outputs here-->
    <output>
    <table type="float" name="Output Vector 1" descr="The first output vector" />
    </output>

    <output>
    <float name="Output Scalar 1" descr="The first output scalar" />
    </output>

    </interface>

    </module>

Geralmente, você poderá usar o exemplo acima como um modelo e modificar as secções de acordo com as suas necessidades. Como pode ser visto no exemplo, o ficheiro XML consiste num nó `module`. O nó `module` tem um nó `intro` e um nó `interface`. Deverá modificar o nó `intro` apropriadamente, usando os comentários do ficheiro XML acima como guias. É importante que o `modulename` tenha o atributo `name` igual ao mesmo nome que o seu ficheiro-objecto dinâmico irá usar.

O nó `interface` descreve as entradas e saídas actuais do 'plugin'. Cada entrada é descrita através de um nó `input`, enquanto cada saída é descrita por um nó `output`. Cada entrada ou saída deverá ter um nó `table` ou `float` como filho. O atributo `type` de um elemento `table` deverá ser igual a `"float"`. Repare que a ordem das entradas e saídas interessa — a ordem é usada para determinar os valores de índices para cada lista de entrada e saída do ficheiro de objecto e é a mesma ordem usada para mostrar os campos de entrada e saída da interface do 'plugin' do &kst;.

Logo que tenha terminado o ficheiro XML, grave-o como `[nomemodulo].xml`, em que o `[nomemodulo]` é o valor do atributo `name` do nó `modulename`.

### O Ficheiro com o Objecto Partilhado

O ficheiro-objecto dinâmico contém a funcionalidade real do 'plugin'. Por outras palavras, ele determina como derivar as saídas a partir das entradas indicadas. O seguinte corresponde aos requisitos do ficheiro-objecto dinâmico:

- O objecto terá de exportar o seguinte símbolo de ligação ao C:

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

  em que o symbol deverá ser o valor do atributo `name` do nó `modulename` do ficheiro XML. Esta é a única função que será chamada pelo &kst; (ainda que possa ter outras funções). O seguinte texto descreve cada argumento desta função:

  `const double *const inArrays[]`

    A lista de listas de entrada. Cada lista de entrada corresponde a um vector de entrada. As listas estão pela mesma ordem que os vectores se encontram no ficheiro XML, de modo que o `inArrays[0]` é a lista que representa o primeiro vector de entrada, o `inArrays[1]` é a lista que representa o segundo vector de entrada e assim por diante.

  `const int inArraysLens[]`

    A lista que contém os tamanhos das listas para cada lista de entrada. Os tamanhos são armazenados pela mesma ordem que as listas no `inArrays[]` (p.ex. o `inArrayLens[0]` é o tamanho da lista `inArrays[0]`).

  `const double inScalars[]`

    A lista de valores escalares de entrada. Os valores escalares são armazenados pela mesma ordem em que se encontram no ficheiro XML.

  `double *outArrays[]`

    A lista de listas de saída. Cada lista de saída corresponde a um vector de saída. As listas estão pela mesma ordem que os vectores se encontram no ficheiro XML.

  `int outArrayLens[]`

    A lista que contém os tamanhos das listas para cada lista de saída. Os tamanhos são armazenados pela mesma ordem que as listas no `outArrays[]`.

  `double outScalars[]`

    A lista de valores escalares de saída. Os valores deverão estar pela mesma ordem pela qual aparecem listados no ficheiro XML.

- A função deverá devolver `0` se foi executada com sucesso e `-1` caso contrário.

- O código para o ficheiro-objecto deverá lidar com as entradas inesperadas, como por exemplo as listas de entrada em branco (na maior parte dos casos, um valor devolvido igual a `-1` seria o suficiente no caso de estas situações serem encontradas).

- O número e o tipo da saída deverá ser exactamente igual ao indicado no ficheiro XML.

- Você provavelmente irá necessitar de redimensionar as listas em `outArrays[]`. Para o fazer, use a função `realloc()`. P.ex., o

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

  irá alocar espaço para 5 números de precisão dupla ('doubles') para o `outArrays[0]`. Não use outro alocador de memória que não seja o `realloc()`.

- Os argumentos de entrada deverão permanecer constantes. Não os converta para tipos não constantes.

O seguinte é um exemplo do ficheiro-objecto dinâmico para um 'plugin' simples:

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

    //Aceita 1 vector e 1 escalar. Multiplica todos os elementos de um vector pelo
    //escalar, e devolve o vector resultante. Devolve também o valor escalar original.
    {
            //Configura a saída
            outArrayLens[0]=inArrayLens[0];

            //Redimensiona as listas de saída
            outArrays[0]=(double*)realloc(outArrays[0], inArrayLens[0]*sizeof(double));

            //Multiplica cada elemento do vector de entrada pelo valor escalar
            for (int i=0; i<inArrayLens[0]; i++)
            {
                    outArrays[0][i]=inArrays[0][i] * is[0];
            }

            //Agora configura o escalar à saída
            outScalars[0]=is[0];

            return 0;
    }

### Compilar o 'Plugin'

Se está a usar o &gcc; para compilar o seu 'plugin', compile simplesmente o ficheiro-objecto:

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

e crie então a biblioteca dinâmica:

    ld -o omeuplugin.so -shared omeuplugin.o

Os ficheiros `*.so` e `*.xml` resultantes deverão ser colocados na mesma pasta. Quando você usar o Gestor de 'Plugins' do &kst; para carregar o ficheiro XML, ele irá ver automaticamente o ficheiro-objecto partilhado para a mesma pasta.

## Criar 'Plugins' de Ajuste Linear

Para criar um 'plugin' de ajuste linear, você poderia implementar os seus próprios algoritmos de ajuste e devolver como resultado os vectores apropriados. Contudo, o &kst; já vem com ficheiros de inclusão que lhe facilitam a implementação de 'plugins' de ajuste aos quadrados mínimos, oferecendo apenas algumas funções. Esta secção irá descrever como tirar partido destes ficheiros.

### Ficheiros de Inclusão

São oferecidos dois ficheiros de inclusão para efectuar ajustes lineares, o `linear.h` (para os ajustes lineares sem pesos) e o `linear_weighted.h` (para os ajustes lineares com pesos de ponderação). Localizam-se ambos em `kst/plugins/fits/` no pacote de código do &kst;. Para usar estes ficheiros, inclua apenas um deles no ficheiro de código do seu 'plugin':

    #include <../linear.h>

ou

    #include <../linear_weighted.h>

(por convenção, iremos colocar o código-fonte do 'plugin' uma pasta abaixo do local onde os ficheiros de inclusão se encontram).

### Implementar as Funções Necessárias

Dado um modelo linear geral:

em que o `y` é um vector com `n` observações, o `X` é uma matriz de `n` por `p` variáveis de predicção e o `c` é o vector de `p` parâmetros óptimos de ajuste que serão estimados, os ficheiros de inclusão oferecem funções para estimar o `c` para um dado `y` e `X`. Para fornecer o `X`, a seguinte função necessita ser implementada no código-fonte do 'plugin':

    double calculate_matrix_entry( double dX, int iPos )

Esta função deverá devolver o valor do elemento na coluna `iPos` da matriz de variáveis de predicção, usando o valor de `x` `dX`. Esta função será chamada pelo linear.h ou pelo linear_weighted.h. A implementação desta função depende do modelo que deseja usar para o ajuste e é única para cada 'plugin' de ajuste linear. Por exemplo, para se ajustar a um modelo polinomial, o `calculate_matrix_entry` poderá ser implementado da seguinte forma:

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

### Invocar as Funções de Ajuste

Logo que o ficheiro de inclusão apropriado tenha sido incluído e o `calculate_matrix_entry` tenha sido implementado, chame a função de ajuste apropriada que existe no ficheiro de inclusão:

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

ou

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

Cada função irá devolver `0` em caso de sucesso ou `-1` em caso de erro, por isso é uma boa ideia definir o valor devolvido pela função de C exportada como sendo igual ao valor devolvido pela função de ajuste. Para manter a simplicidade, o código do 'plugin' poderá simplesmente passar os argumentos indicados na função exportada para C para a função de ajuste. Repare, contudo, que o 'inArrays' deverá estar estruturado da seguinte forma:

- O `inArrays[0]` deverá conter a lista de coordenadas em X dos pontos de dados.

- O `inArrays[1]` deverá conter a lista de coordenadas em Y dos pontos de dados

- O `inArrays[2]` só existe se o `kstfit_linear_weighted` for invocado e deverá conter a lista de pesos a usar como ponderação para o ajuste.

A forma mais simples de garantir que o 'inArrays' está estruturado correctamente é indicar a ordem correcta dos vectores de entrada no ficheiro XML para o 'plugin'.

O `iNumParams` é o número de parâmetros no modelo de ajuste usado, o qual deverá ser igual ao número de colunas a matriz `X` de variáveis de predicção. O `iNumParams` deverá estar configurado correctamente antes de a função de ajuste ser chamada.

Depois de o `kstfit_linear_unweighted` ou o `kstfit_linear_weighted` terem sido chamados, o `outArrays` e o `outScalars` serão definidos da seguinte forma:

- O `outArrays[0]` irá conter a lista de valores ajustados em Y.

- O `outArrays[1]` irá conter a lista dos valores residuais.

- O `outArrays[2]` irá conter a lista dos parâmetros de ajuste óptimo que foram estimados.

- O `outArrays[3]` irá conter a matriz de covariância, devolvida linha após linha numa lista.

- O `outScalars[0]` irá conter o chi^2/nu, em que o chi^2 é a soma ponderada dos quadrados dos valores residuais, enquanto o nu é o número de graus de liberdade.

O `outArrayLens` será configurado correctamente para indicar o tamanho de cada lista à saída.

Garanta que os resultados indicados no ficheiro XML correspondem aos que a função em C exportada devolve (o que, na maioria dos casos, será simplesmente os valores à saída devolvidos pela função de ajuste).

### Exemplo

Segue-se um exemplo do código-fonte para um 'plugin' de ajuste linear.

    /*
     *  'Plugin' de ajuste polinomial para o KST.
     *  Copyright 2004, The University of British Columbia
     *  Lançado segundo os termos da 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;
    }

## Criar 'Plugins' de Ajuste Não-Linear

O &kst; oferece ficheiros de inclusão desenhados para simplificar a criação dos 'plugins' de ajuste dos quadrados mínimos. As secções seguintes entram em detalhe na utilização dos ficheiros de inclusão.

### Ficheiros de Inclusão e Definições

Os ficheiros de inclusão localizam-se na pasta `kst/plugins/fits_nonlinear` do pacote de código-fonte do &kst;. Os ficheiros chamam-se `non_linear.h` e `non_linear_weighted.h` para os ajustes não-ponderados e ponderados, respectivamente. Para usar estes ficheiros, inclua apenas um deles no ficheiro de código do seu 'plugin':

    #include <../non_linear.h>

ou

    #include <../non_linear_weighted.h>

(por convenção, será colocado o código-fonte para o 'plugin' uma pasta abaixo do local em que os ficheiros de inclusão se encontram).

Dado que o ajuste não-linear é um processo iterativo, você precisa de definir também o número máximo de iterações que deverão ser efectuadas. O algoritmo de ajuste não-linear irá parar quando pelo menos uma das condições for verdadeira:

- O número máximo de iterações foi atingido.

- Foi atingida uma precisão de 10-4.

Para além disso, o utilizador precisa de definir o número de parâmetros do modelo, dado que não é passado explicitamente ao algoritmo de ajuste da função. Para definir estes dois valores, inclua o seguinte no cimo do seu ficheiro de código:

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

substituindo o `[num1]` pelo número de parâmetros do modelo e o `[num2]` pelo número máximo de iterações a efectuar.

### Implementar as Funções Necessárias

Para usar os ficheiros de inclusão para os ajustes não-lineares, o utilizador deverá fornecer a função a usar como o modelo, as derivadas parciais da função respeitantes a cada parâmetro e as estimativas iniciais dos parâmetros de ajuste óptimo. Para o fazer, deverão ser implementadas três funções. Estas estão descritas em baixo.

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

  Esta função calcula o valor do Y do modelo de ajuste para um dado valor de X `dX`, usando a lista fornecida de parâmetros `pdParameters`. A ordem dos parâmetros em `pdParameters` é arbitrária, mas deverá ser consistente com as outras duas funções implementadas. Por exemplo, para um modelo exponencial, o `function_calculate` poderia ser implementado da seguinte forma:

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

  Esta função calcula as derivadas parciais da função do modelo para um valor indicado para o X, o `dX`. As derivadas parciais deverão ser devolvidas em `pdDerivatives`. A ordem das derivadas parciais na lista `pdDerivatives` deverá corresponder à ordem dos parâmetros em `pdParameters` (i.e. se o `pdParameters[0]` contiver o parâmetro 'lambda' de um modelo exponencial, o `pdDerivatives[0]` deverá conter a derivada do modelo respeitante ao 'lambda').

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

  Esta função oferece uma estimativa inicial dos parâmetros de ajuste óptimos para a função de ajuste. A lista de valores em X e Y dos pontos de dados são oferecidas em `pdX` e `pdY` respectivamente e o número de pontos de dados é indicado em `iLength`. Você poderá usar qualquer um ou mesmo nenhum destes parâmetros à sua discrição para calcular a estimativa inicial. A função deverá colocar as estimativas iniciais calculadas em `pdParameterEstimates`, com a ordem das estimativas correspondente à ordem dos parâmetros em `pdParameters` do `function_calculate` e `function_derivative`. Tenha em mente que a estimativa inicial é importante para determinar se a função de ajuste converge para uma solução ou não.

### Invocar as Funções de Ajuste

Logo que todas as funções necessárias tenham sido implementadas, a função de ajuste do ficheiro de inclusão usado poderá ser chamada:

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

ou

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

dependendo se você está ou não a usar um ajuste ponderado.

A função irá devolver `0` em caso de sucesso ou `-1` em caso de erro, por isso é mais simples atribuir o valor devolvido pela função em C exportada como sendo igual ao valor devolvido pela função de ajuste. Para manter a simplicidade, o código do 'plugin' poderá simplesmente passar os argumentos indicados à função em C exportada para a função de ajuste. Repare, contudo, que o 'inArrays' deverá estar estruturado da seguinte forma:

- O `inArrays[0]` deverá conter a lista de coordenadas em X dos pontos de dados.

- O `inArrays[1]` deverá conter a lista de coordenadas em Y dos pontos de dados

- O `inArrays[2]` só existe se o `kstfit_linear_weighted` for invocado e deverá conter a lista de pesos a usar como ponderação para o ajuste.

A forma mais simples de garantir que o 'inArrays' está estruturado correctamente é indicar a ordem correcta dos vectores de entrada no ficheiro XML para o 'plugin'.

Depois de o `kstfit_linear_unweighted` ou o `kstfit_linear_weighted` terem sido chamados, o `outArrays` e o `outScalars` serão definidos da seguinte forma:

- O `outArrays[0]` irá conter a lista de valores ajustados em Y.

- O `outArrays[1]` irá conter a lista dos valores residuais.

- O `outArrays[2]` irá conter a lista dos parâmetros de ajuste óptimo que foram estimados.

- O `outArrays[3]` irá conter a matriz de covariância, devolvida linha após linha numa lista.

- O `outScalars[0]` irá conter o chi^2/nu, em que o chi^2 é a soma ponderada dos quadrados dos valores residuais, enquanto o nu é o número de graus de liberdade.

O `outArrayLens` será configurado correctamente para indicar o tamanho de cada lista à saída.

Garanta que os resultados indicados no ficheiro XML correspondem aos que a função em C exportada devolve (o que, na maioria dos casos, será simplesmente os valores à saída devolvidos pela função de ajuste).

### Exemplo

Segue-se um exemplo de um 'plugin' de ajuste não-linear que efectue um ajuste a um modelo exponencial.

    /*
     *  'Plugin' de ajuste exponencial para o KST.
     *  Copyright 2004, The University of British Columbia
     *  Lançado segundo os termos da 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 );
    }

## Criar 'Plugins' para Filtros

O &kst; oferece ficheiros de inclusão para simplificar a implementação de filtros. A utilização destes ficheiros de inclusão está descrita em baixo.

### Ficheiros de Inclusão

O ficheiro de inclusão para a implementação de filtros está localizada na pasta `kst/plugins/pass_filters` do pacote de código do &kst;. O ficheiro chama-se `filters.h`. Para usar este ficheiro, inclua-o no ficheiro de código-fonte do seu 'plugin':

    #include <../filters.h>

(por convenção, será colocado o ficheiro de código-fonte para o 'plugin' uma pasta abaixo do local em que se encontram os ficheiros de inclusão).

### Funções Necessárias

O ficheiro de inclusão `filters.h` contém uma únic afunção que calcula a transformada de Fourier para uma dada função, aplica o filtro fornecido a essa transformações e depois calcula a transformada inversa de Fourier para o sinal previamente transformado. Para fornecer o filtro, a seguinte função deverá ser implementada no código-fonte do seu 'plugin':

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

Esta função deverá calcular a amplitude filtada para a frequência `dFreqValue`. O `inScalars[]` irá conter os valores escalares inalterados para o 'plugin', indicados no ficheiro XML. Muito provavelmente, o `inScalars[]` irá conter as frequências de cortes ou outras propriedades do filtro. Por exemplo para implementar um filtro Butterworth passa-alto, o `filter_calculate` poderia ser implementado da seguinte forma:

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

### Chamar a Função de Filtragem

Logo que o `filter_calculate` necessário tenha sido implementado, a função de filtragem do ficheiro de inclusão poderá ser invocada:

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

Os argumentos fornecidos à função em C exportada poderão ser normalmente passados ao `kst_pass_filter` sem nenhuma modificação. Contudo, existem algumas restrições para os argumentos:

- O `inArrays[0]` precisa de conter a lista de dados a filtrar.

- O `inScalars` deverá conter os parâmetros específicos do filtro a serem usados pela função `filter_calculate`.

Depois da chamada da função, o `outArrays[0]` irá conter a lista de dados filtrada e o `outArrayLens` será configurado convenientemente. A função `kst_pass_filter` não usa o `outScalars`.

### Exemplo

Segue-se um exemplo de um 'plugin' de um filtro passa-alto Butterworth.

    /*
     *  'Plugin' de um filtro passa-baixo Butterworth para o KST.
     *  Copyright 2004, The University of British Columbia
     *  Lançado segundo os termos da 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;
    }