<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 — 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 ><?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> </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 >"float"</literal >. 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;. </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 <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; } </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 <../linear.h> </screen > ou <screen> #include <../linear_weighted.h> </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 > 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 <../non_linear.h> </screen > ou <screen> #include <../non_linear_weighted.h> </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 <../filters.h> </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 <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; }</screen> </informalexample> </sect2> </sect1> </appendix>