Sophie

Sophie

distrib > Mandriva > 10.2 > i586 > media > contrib > by-pkgid > eb2ca3fa8cac6766aebe2c4233348281 > files > 330

kst-1.0-4mdk.i586.rpm

<appendix id="creatingplugins">
<title
>Criar 'Plugins' Adicionais</title>
<para
>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'. </para>

<sect1 id="creatingbasicplugin">
<title
>Criar um 'Plugin' Básico</title>
<para
>Um 'plugin' do &kst; consiste em dois ficheiros &mdash; um ficheiro em XML e um ficheiro-objecto dinâmico. </para>

<sect2 id="creatingbasicpluginxmlfile">
<title
>O Ficheiro XML</title>
<para
>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;: </para>

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

&lt;module&gt;

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

&lt;interface&gt;

&lt;!--inputs here--&gt;
&lt;input&gt;
&lt;table type="float" name="Input Vector 1" descr="The first input vector" /&gt;
&lt;/input&gt;

&lt;input&gt;
&lt;float name="Input Scalar 1" descr="The first input scalar" /&gt;
&lt;/input&gt;

&lt;!--outputs here--&gt;
&lt;output&gt;
&lt;table type="float" name="Output Vector 1" descr="The first output vector" /&gt;
&lt;/output&gt;

&lt;output&gt;
&lt;float name="Output Scalar 1" descr="The first output scalar" /&gt;
&lt;/output&gt;

&lt;/interface&gt;

&lt;/module&gt;
</screen>
</informalexample>

<para
>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ó <literal
>module</literal
>. O nó <literal
>module</literal
> tem um nó <literal
>intro</literal
> e um nó <literal
>interface</literal
>. Deverá modificar o nó <literal
>intro</literal
> apropriadamente, usando os comentários do ficheiro XML acima como guias. É importante que o <literal
>modulename</literal
> tenha o atributo <literal
>name</literal
> igual ao mesmo nome que o seu ficheiro-objecto dinâmico irá usar. </para>

<para
>O nó <literal
>interface</literal
> descreve as entradas e saídas actuais do 'plugin'. Cada entrada é descrita através de um nó <literal
>input</literal
>, enquanto cada saída é descrita por um nó <literal
>output</literal
>. Cada entrada ou saída deverá ter um nó <literal
>table</literal
> ou <literal
>float</literal
> como filho. O atributo <literal
>type</literal
> de um elemento <literal
>table</literal
> deverá ser igual a <literal
>&quot;float&quot;</literal
>. Repare que a ordem das entradas e saídas interessa &mdash; 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;. </para>

<para
>Logo que tenha terminado o ficheiro XML, grave-o como <filename
>[nomemodulo].xml</filename
>, em que o <filename
>[nomemodulo]</filename
> é o valor do atributo <literal
>name</literal
> do nó <literal
>modulename</literal
>. </para>

</sect2>

<sect2 id="creatingbasicpluginobjectfile">
<title
>O Ficheiro com o Objecto Partilhado</title>
<para
>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: </para>

<itemizedlist>

<listitem>
<para
>O objecto terá de exportar o seguinte símbolo de ligação ao C: <literallayout
><function
><returnvalue
>int</returnvalue
> symbol(const double *const <parameter
>inArrays[]</parameter
>,
           const int <parameter
>inArrayLens[]</parameter
>,
           const double <parameter
>inScalars[]</parameter
>,
           double *<parameter
>outArrays[]</parameter
>,
           int <parameter
>outArrayLens[]</parameter
>,
           double <parameter
>outScalars[]</parameter
>)</function
></literallayout>
</para>
<para
>em que o <replaceable
>symbol</replaceable
> deverá ser o valor do atributo <literal
>name</literal
> do nó <literal
>modulename</literal
> 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: </para>

<variablelist>
<varlistentry>
<term
><varname
>const double *const inArrays[]</varname
></term>
<listitem>
<para
>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 <literal
>inArrays[0]</literal
> é a lista que representa o primeiro vector de entrada, o <literal
>inArrays[1]</literal
> é a lista que representa o segundo vector de entrada e assim por diante. </para>
</listitem>
</varlistentry>

<varlistentry>
<term
><varname
>const int inArraysLens[]</varname
></term>
<listitem>
<para
>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 <literal
>inArrays[]</literal
> (p.ex. o <literal
>inArrayLens[0]</literal
> é o tamanho da lista <literal
>inArrays[0]</literal
>). </para>
</listitem>
</varlistentry>

<varlistentry>
<term
><varname
>const double inScalars[]</varname
></term>
<listitem>
<para
>A lista de valores escalares de entrada. Os valores escalares são armazenados pela mesma ordem em que se encontram no ficheiro XML. </para>
</listitem>
</varlistentry>

<varlistentry>
<term
><varname
>double *outArrays[]</varname
></term>
<listitem>
<para
>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. </para>
</listitem>
</varlistentry>

<varlistentry>
<term
><varname
>int outArrayLens[]</varname
></term>
<listitem>
<para
>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 <literal
>outArrays[]</literal
>. </para>
</listitem>
</varlistentry>

<varlistentry>
<term
><varname
>double outScalars[]</varname
></term>
<listitem>
<para
>A lista de valores escalares de saída. Os valores deverão estar pela mesma ordem pela qual aparecem listados no ficheiro XML. </para>
</listitem>
</varlistentry>
</variablelist>


</listitem>

<listitem>
<para
>A função deverá devolver <literal
>0</literal
> se foi executada com sucesso e <literal
>-1</literal
> caso contrário. </para>
</listitem>

<listitem>
<para
>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 <literal
>-1</literal
> seria o suficiente no caso de estas situações serem encontradas). </para>
</listitem>

<listitem>
<para
>O número e o tipo da saída deverá ser exactamente igual ao indicado no ficheiro XML. </para>
</listitem>

<listitem>
<para
>Você provavelmente irá necessitar de redimensionar as listas em <varname
>outArrays[]</varname
>. Para o fazer, use a função <function
>realloc()</function
>. P.ex., o </para>
<informalexample>
<screen
>outArrays[0]=(double*)realloc(outArrays[0], 5*sizeof(double));
</screen>
</informalexample>
<para
>irá alocar espaço para 5 números de precisão dupla ('doubles') para o <varname
>outArrays[0]</varname
>. Não use outro alocador de memória que não seja o <function
>realloc()</function
>. </para>
</listitem>

<listitem>
<para
>Os argumentos de entrada deverão permanecer constantes. Não os converta para tipos não constantes. </para>
</listitem>

</itemizedlist>

<para
>O seguinte é um exemplo do ficheiro-objecto dinâmico para um 'plugin' simples: </para>
<informalexample>
<screen
>#include &lt;stdlib.h&gt;

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&lt;inArrayLens[0]; i++)
        {
                outArrays[0][i]=inArrays[0][i] * is[0];
        }

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

        return 0;
}
</screen>
</informalexample>
</sect2>


<sect2 id="compilingplugin">
<title
>Compilar o 'Plugin'</title>
<para
>Se está a usar o &gcc; para compilar o seu 'plugin', compile simplesmente o ficheiro-objecto: <screen
><userinput
><command
>cc -Wall -c -o omeuplugin.o omeuplugin.c -fPIC -DPIC</command
></userinput
></screen>
</para>
<para
>e crie então a biblioteca dinâmica: <screen
><userinput
><command
>ld -o omeuplugin.so -shared omeuplugin.o</command
></userinput
></screen>
</para>
<para
>Os ficheiros <filename
>*.so</filename
> e <filename
>*.xml</filename
> 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. </para>

</sect2>
</sect1>

<sect1 id="creatinglinearfittingplugins">
<title
>Criar 'Plugins' de Ajuste Linear</title>
<para
>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. </para>

<sect2 id="headerslinearfittingplugins">
<title
>Ficheiros de Inclusão</title>
<para
>São oferecidos dois ficheiros de inclusão para efectuar ajustes lineares, o <filename
>linear.h</filename
> (para os ajustes lineares sem pesos) e o <filename
>linear_weighted.h</filename
> (para os ajustes lineares com pesos de ponderação). Localizam-se ambos em <filename
>kst/plugins/fits/</filename
> no pacote de código do &kst;. Para usar estes ficheiros, inclua apenas um deles no ficheiro de código do seu 'plugin': <screen>
#include &lt;../linear.h&gt;
</screen
> ou <screen>
#include &lt;../linear_weighted.h&gt;
</screen
> (por convenção, iremos colocar o código-fonte do 'plugin' uma pasta abaixo do local onde os ficheiros de inclusão se encontram). </para>

</sect2>

<sect2 id="reqfunctionsfittingplugins">
<title
>Implementar as Funções Necessárias</title>
<para
>Dado um modelo linear geral: </para>
<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="Formula-kst-generallinearmodel.png" format="PNG"/>
</imageobject>
</inlinemediaobject>
</para>
<para
>em que o <literal
>y</literal
> é um vector com <literal
>n</literal
> observações, o <literal
>X</literal
> é uma matriz de <literal
>n</literal
> por <literal
>p</literal
> variáveis de predicção e o <literal
>c</literal
> é o vector de <literal
>p</literal
> parâmetros óptimos de ajuste que serão estimados, os ficheiros de inclusão oferecem funções para estimar o <literal
>c</literal
> para um dado <literal
>y</literal
> e <literal
>X</literal
>. Para fornecer o <literal
>X</literal
>, a seguinte função necessita ser implementada no código-fonte do 'plugin': <literallayout
><function
><returnvalue
>double</returnvalue
> calculate_matrix_entry( double <parameter
>dX</parameter
>, int <parameter
>iPos</parameter
> )</function
></literallayout>
</para>
<para
>Esta função deverá devolver o valor do elemento na coluna <literal
>iPos</literal
> da matriz de variáveis de predicção, usando o valor de <literal
>x</literal
> <literal
>dX</literal
>. 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 <function
>calculate_matrix_entry</function
> poderá ser implementado da seguinte forma: <informalexample
> <screen
>double calculate_matrix_entry( double dX, int iPos ) {
  double dY;
  dY = pow( dX, (double)iPos );
  return dY;
}
</screen>
</informalexample>
</para>

</sect2>

<sect2 id="callingfittingfunctionslinearfittingplugins">
<title
>Invocar as Funções de Ajuste</title>
<para
>Logo que o ficheiro de inclusão apropriado tenha sido incluído e o <function
>calculate_matrix_entry</function
> tenha sido implementado, chame a função de ajuste apropriada que existe no ficheiro de inclusão: <screen>
<function
>kstfit_linear_unweighted( <parameter
>inArrays</parameter
>, <parameter
>inArrayLens</parameter
>,
                          <parameter
>outArrays</parameter
>, <parameter
>outArrayLens</parameter
>,
                          <parameter
>outScalars</parameter
>, <parameter
>iNumParams</parameter
> )</function
>;
</screen
> ou <screen
><function
>kstfit_linear_weighted( <parameter
>inArrays</parameter
>, <parameter
>inArrayLens</parameter
>,
                        <parameter
>outArrays</parameter
>, <parameter
>outArrayLens</parameter
>,
                        <parameter
>outScalars</parameter
>, <parameter
>iNumParams</parameter
> )</function
>;
</screen>
</para>
<para
>Cada função irá devolver <literal
>0</literal
> em caso de sucesso ou <literal
>-1</literal
> 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: </para>
<itemizedlist>
<listitem>
<para
>O <varname
>inArrays[0]</varname
> deverá conter a lista de coordenadas em X dos pontos de dados. </para>
</listitem>

<listitem>
<para
>O <varname
>inArrays[1]</varname
> deverá conter a lista de coordenadas em Y dos pontos de dados </para>
</listitem>

<listitem>
<para
>O <varname
>inArrays[2]</varname
> só existe se o <function
>kstfit_linear_weighted</function
> for invocado e deverá conter a lista de pesos a usar como ponderação para o ajuste. </para>
</listitem>
</itemizedlist>
<para
>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'. </para>
<para
>O <varname
>iNumParams</varname
> é o número de parâmetros no modelo de ajuste usado, o qual deverá ser igual ao número de colunas a matriz <literal
>X</literal
> de variáveis de predicção. O <varname
>iNumParams</varname
> deverá estar configurado correctamente antes de a função de ajuste ser chamada. </para>
<para
>Depois de o <function
>kstfit_linear_unweighted</function
> ou o <function
>kstfit_linear_weighted</function
> terem sido chamados, o <varname
>outArrays</varname
> e o <varname
>outScalars</varname
> serão definidos da seguinte forma: </para>
<itemizedlist>
<listitem>
<para
>O <varname
>outArrays[0]</varname
> irá conter a lista de valores ajustados em Y. </para>
</listitem>

<listitem>
<para
>O <varname
>outArrays[1]</varname
> irá conter a lista dos valores residuais. </para>
</listitem>

<listitem>
<para
>O <varname
>outArrays[2]</varname
> irá conter a lista dos parâmetros de ajuste óptimo que foram estimados. </para>
</listitem>

<listitem>
<para
>O <varname
>outArrays[3]</varname
> irá conter a matriz de covariância, devolvida linha após linha numa lista. </para>
</listitem>

<listitem>
<para
>O <varname
>outScalars[0]</varname
> 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. </para>
</listitem>
</itemizedlist>
<para
>O <varname
>outArrayLens</varname
> será configurado correctamente para indicar o tamanho de cada lista à saída. </para>

<para
>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). </para>


</sect2>

<sect2 id="examplelinearfittingplugins">
<title
>Exemplo</title>
<para
>Segue-se um exemplo do código-fonte para um 'plugin' de ajuste linear. </para>
<informalexample>
<screen
>/*
 *  '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 &gt; 0 ) {
    iRetVal = kstfit_linear_unweighted( inArrays, inArrayLens,
                                        outArrays, outArrayLens,
                                        outScalars, iNumParams );
  }

  return iRetVal;
}
</screen>
</informalexample>
</sect2>

</sect1>

<sect1 id="creatingnonlinearfitplugin">
<title
>Criar 'Plugins' de Ajuste Não-Linear</title>
<para
>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. </para>

<sect2 id="headersnonlinearfittingplugins">
<title
>Ficheiros de Inclusão e Definições</title>
<para
>Os ficheiros de inclusão localizam-se na pasta <filename
>kst/plugins/fits_nonlinear</filename
> do pacote de código-fonte do &kst;. Os ficheiros chamam-se <filename
>non_linear.h</filename
> e <filename
>non_linear_weighted.h</filename
> 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': <screen>
#include &lt;../non_linear.h&gt;
</screen
> ou <screen>
#include &lt;../non_linear_weighted.h&gt;
</screen
> (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). </para>

<para
>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: </para>
<itemizedlist>
<listitem>
<para
>O número máximo de iterações foi atingido. </para>
</listitem>
<listitem>
<para
>Foi atingida uma precisão de 10<superscript
>-4</superscript
>. </para>
</listitem>
</itemizedlist>
<para
>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: </para>
<screen
>#define NUM_PARAMS [num1]
#define MAX_NUM_ITERATIONS [num2]
</screen>
<para
>substituindo o <literal
>[num1]</literal
> pelo número de parâmetros do modelo e o <literal
>[num2]</literal
> pelo número máximo de iterações a efectuar. </para>
</sect2>

<sect2 id="reqfunctionsnonlinearfittingplugins">
<title
>Implementar as Funções Necessárias</title>
<para
>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. </para>
<variablelist>
<varlistentry>
<term
><function
><returnvalue
>double</returnvalue
> function_calculate( double <parameter
>dX</parameter
>, double* <parameter
>pdParameters</parameter
> )</function
></term>
<listitem>
<para
>Esta função calcula o valor do Y do modelo de ajuste para um dado valor de X <literal
>dX</literal
>, usando a lista fornecida de parâmetros <varname
>pdParameters</varname
>. A ordem dos parâmetros em <varname
>pdParameters</varname
> é arbitrária, mas deverá ser consistente com as outras duas funções implementadas. Por exemplo, para um modelo exponencial, o <function
>function_calculate</function
> poderia ser implementado da seguinte forma: </para>
<informalexample>
<screen
>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;
}
</screen>
</informalexample>
</listitem>
</varlistentry>

<varlistentry>
<term
><function
><returnvalue
>void</returnvalue
> function_derivative( double <parameter
>dX</parameter
>, double* <parameter
>pdParameters</parameter
>, double* <parameter
>pdDerivatives</parameter
> )</function
></term>
<listitem>
<para
>Esta função calcula as derivadas parciais da função do modelo para um valor indicado para o X, o <literal
>dX</literal
>. As derivadas parciais deverão ser devolvidas em <varname
>pdDerivatives</varname
>. A ordem das derivadas parciais na lista <varname
>pdDerivatives</varname
> deverá corresponder à ordem dos parâmetros em <varname
>pdParameters</varname
> (i.e. se o <varname
>pdParameters[0]</varname
> contiver o parâmetro 'lambda' de um modelo exponencial, o <varname
>pdDerivatives[0]</varname
> deverá conter a derivada do modelo respeitante ao 'lambda'). </para>
</listitem>
</varlistentry>

<varlistentry>
<term
><function
><returnvalue
>void</returnvalue
> function_initial_estimate( const double* <parameter
>pdX</parameter
>, const double* <parameter
>pdY</parameter
>, int <parameter
>iLength</parameter
>, double* <parameter
>pdParameterEstimates</parameter
> )</function
></term>
<listitem>
<para
>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 <varname
>pdX</varname
> e <varname
>pdY</varname
> respectivamente e o número de pontos de dados é indicado em <varname
>iLength</varname
>. 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 <varname
>pdParameterEstimates</varname
>, com a ordem das estimativas correspondente à ordem dos parâmetros em <varname
>pdParameters</varname
> do <function
>function_calculate</function
> e <function
>function_derivative</function
>. Tenha em mente que a estimativa inicial é importante para determinar se a função de ajuste converge para uma solução ou não. </para>
</listitem>
</varlistentry>

</variablelist>

</sect2>

<sect2 id="callingnonlinearfittingplugins">
<title
>Invocar as Funções de Ajuste</title>
<para
>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: <screen>
kstfit_nonlinear( <parameter
>inArrays</parameter
>, <parameter
>inArrayLens</parameter
>,
                  <parameter
>inScalars</parameter
>, <parameter
>outArrays</parameter
>,
                  <parameter
>outArrayLens</parameter
>, <parameter
>outScalars</parameter
> );
</screen
> ou <screen>
kstfit_nonlinear_weighted( <parameter
>inArrays</parameter
>, <parameter
>inArrayLens</parameter
>,
                           <parameter
>inScalars</parameter
>, <parameter
>outArrays</parameter
>,
                           <parameter
>outArrayLens</parameter
>, <parameter
>outScalars</parameter
> );
</screen
> dependendo se você está ou não a usar um ajuste ponderado. </para>

<para
>A função irá devolver <literal
>0</literal
> em caso de sucesso ou <literal
>-1</literal
> 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: </para>
<itemizedlist>
<listitem>
<para
>O <varname
>inArrays[0]</varname
> deverá conter a lista de coordenadas em X dos pontos de dados. </para>
</listitem>

<listitem>
<para
>O <varname
>inArrays[1]</varname
> deverá conter a lista de coordenadas em Y dos pontos de dados </para>
</listitem>

<listitem>
<para
>O <varname
>inArrays[2]</varname
> só existe se o <function
>kstfit_linear_weighted</function
> for invocado e deverá conter a lista de pesos a usar como ponderação para o ajuste. </para>
</listitem>
</itemizedlist>
<para
>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'. </para>
<para
>Depois de o <function
>kstfit_linear_unweighted</function
> ou o <function
>kstfit_linear_weighted</function
> terem sido chamados, o <varname
>outArrays</varname
> e o <varname
>outScalars</varname
> serão definidos da seguinte forma: </para>
<itemizedlist>
<listitem>
<para
>O <varname
>outArrays[0]</varname
> irá conter a lista de valores ajustados em Y. </para>
</listitem>

<listitem>
<para
>O <varname
>outArrays[1]</varname
> irá conter a lista dos valores residuais. </para>
</listitem>

<listitem>
<para
>O <varname
>outArrays[2]</varname
> irá conter a lista dos parâmetros de ajuste óptimo que foram estimados. </para>
</listitem>

<listitem>
<para
>O <varname
>outArrays[3]</varname
> irá conter a matriz de covariância, devolvida linha após linha numa lista. </para>
</listitem>

<listitem>
<para
>O <varname
>outScalars[0]</varname
> 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. </para>
</listitem>
</itemizedlist>
<para
>O <varname
>outArrayLens</varname
> será configurado correctamente para indicar o tamanho de cada lista à saída. </para>

<para
>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). </para>

</sect2>

<sect2 id="nonlinearfittingpluginexample">
<title
>Exemplo</title>
<para
>Segue-se um exemplo de um 'plugin' de ajuste não-linear que efectue um ajuste a um modelo exponencial.</para>
<informalexample>
<screen
>/*
 *  '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 );
}
</screen>
</informalexample>

</sect2>
</sect1>

<sect1 id="creatingpassfilterplugins">
<title
>Criar 'Plugins' para Filtros</title>
<para
>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. </para>
<sect2 id="creatingpassfilterpluginsheaderfiles">
<title
>Ficheiros de Inclusão</title>
<para
>O ficheiro de inclusão para a implementação de filtros está localizada na pasta <filename
>kst/plugins/pass_filters</filename
> do pacote de código do &kst;. O ficheiro chama-se <filename
>filters.h</filename
>. Para usar este ficheiro, inclua-o no ficheiro de código-fonte do seu 'plugin': <screen>
#include &lt;../filters.h&gt;
</screen
> (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). </para>
</sect2>

<sect2 id="creatingpassfilterpluginsrequirements">
<title
>Funções Necessárias</title>
<para
>O ficheiro de inclusão <filename
>filters.h</filename
> 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': </para>
<para
><function
><returnvalue
>double</returnvalue
> filter_calculate( double <parameter
>dFreqValue</parameter
>, const double <parameter
>inScalars[]</parameter
> )</function
></para>
<para
>Esta função deverá calcular a amplitude filtada para a frequência <literal
>dFreqValue</literal
>. O <literal
>inScalars[]</literal
> irá conter os valores escalares inalterados para o 'plugin', indicados no ficheiro XML. Muito provavelmente, o <literal
>inScalars[]</literal
> irá conter as frequências de cortes ou outras propriedades do filtro. Por exemplo para implementar um filtro Butterworth passa-alto, o <function
>filter_calculate</function
> poderia ser implementado da seguinte forma: </para>
<informalexample>
<screen
>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;
}
</screen>
</informalexample>
</sect2>

<sect2 id="creatingpassfilterpluginscallingfunction">
<title
>Chamar a Função de Filtragem</title>
<para
>Logo que o <function
>filter_calculate</function
> necessário tenha sido implementado, a função de filtragem do ficheiro de inclusão poderá ser invocada: </para>
<literallayout
><function
>kst_pass_filter( <parameter
>inArrays</parameter
>,
                 <parameter
>inArrayLens</parameter
>,
                 <parameter
>inScalars</parameter
>,
                 <parameter
>outArrays</parameter
>,
                 <parameter
>outArrayLens</parameter
>,
                 <parameter
>outScalars</parameter
> );</function
></literallayout>
<para
>Os argumentos fornecidos à função em C exportada poderão ser normalmente passados ao <function
>kst_pass_filter</function
> sem nenhuma modificação. Contudo, existem algumas restrições para os argumentos: </para>
<itemizedlist>
<listitem>
<para
>O <varname
>inArrays[0]</varname
> precisa de conter a lista de dados a filtrar. </para>
</listitem>

<listitem>
<para
>O <varname
>inScalars</varname
> deverá conter os parâmetros específicos do filtro a serem usados pela função <function
>filter_calculate</function
>. </para>
</listitem>
</itemizedlist>
<para
>Depois da chamada da função, o <varname
>outArrays[0]</varname
> irá conter a lista de dados filtrada e o <varname
>outArrayLens</varname
> será configurado convenientemente. A função <function
>kst_pass_filter</function
> não usa o <varname
>outScalars</varname
>. </para>
</sect2>

<sect2 id="creatingpassfilterpluginsexample">
<title
>Exemplo</title>
<para
>Segue-se um exemplo de um 'plugin' de um filtro passa-alto Butterworth. </para>
<informalexample>
<screen
>/*
 *  '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 &lt;stdlib.h&gt;
#include &lt;math.h&gt;
#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 &gt; 0.0 ) {
    dValue = 1.0 / ( 1.0 + pow( inScalars[1] / dFreqValue, 2.0 * (double)inScalars[0] ) );
  } else {
    dValue = 0.0;
  }

  return dValue;
}</screen>
</informalexample>
</sect2>

</sect1>
</appendix>