<appendix id="creatingplugins">
<title
>Het maken van extra plugins</title>
<para
>&kst; heeft een eenvoudige en gestandaardiseerde interface waarmee het maken van extra plugins eenvoudiger wordt. Naast het beschrijven van de basisvereisten voor plugins vindt u in de volgende secties hoe u reeds bestaande header-bestanden kunt gebruiken voor het maken van bepaalde typen van plugins. </para>

<sect1 id="creatingbasicplugin">
<title
>Het maken van een eenvoudige plugin</title>
<para
>Een plugin voor &kst; bestaat uit twee bestanden&mdash;een XML-bestand en een zogenaamde "shared object file". </para>

<sect2 id="creatingbasicpluginxmlfile">
<title
>Het XML-bestand</title>
<para
>Het XML-bestand geeft informatie over de plugin en beschrijft de invoer en de uitvoer ervan. Het volgende is een voorbeeld van een XML-bestand voor een plugin in &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="testplugin"/&gt;    &lt;!-- De naam van de module --&gt;
&lt;author name="Rick Chern"/&gt; &lt;!-- De naam van de schrijver --&gt;
&lt;description text="Een testplugin voor mijzelf"/&gt; &lt;!-- Een beschrijving van de module --&gt;
&lt;version minor="1" major="0"/&gt;  &lt;!-- Het versienummer van de module --&gt;
&lt;state devstate="release"/&gt;     &lt;!-- De ontwikkelingsstatus van de module (optioneel)--&gt;
&lt;/intro&gt;

&lt;interface&gt;

&lt;!--Hier de invoer--&gt;
&lt;input&gt;
&lt;table type="float" name="Invoervector 1" descr="De eerste invoervector" /&gt;
&lt;/input&gt;

&lt;input&gt;
&lt;float name="Invoerscalair 1" descr="De eerste invoerscalair" /&gt;
&lt;/input&gt;

&lt;!--outputs here--&gt;
&lt;output&gt;
&lt;table type="float" name="Uitvoervector 1" descr="De eerste uitvoervector" /&gt;
&lt;/output&gt;

&lt;output&gt;
&lt;float name="Uitvoerscalair 1" descr="De eerste uitvoerscalar" /&gt;
&lt;/output&gt;

&lt;/interface&gt;

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

<para
>In het algemeen kunt u het bovenstaande voorbeeld gebruiken als een sjabloon en onderdelen ervan aanpassen naar uw wensen. Zoals u in het voorbeeld kunt zien bestaat het XML-bestand uit een <literal
>module</literal
>-"node". De <literal
>module</literal
>-node heeft een <literal
>intro</literal
>-node en een <literal
>interface</literal
> node. U moet de <literal
>intro</literal
>-node aanpassen waarbij u het commentaar in het bovenstaande XML-bestand kunt gebruiken als leiddraad. Het is belangrijk dat de <literal
>modulename</literal
> en het <literal
>name</literal
>-attribuut van de bijbehorende "shared object file" aan elkaar gelijk zijn. </para>

<para
>De <literal
>interface</literal
>-node geeft een beschrijving van de werkelijke invoer en uitvoer van de plugin. Elke invoer wordt beschreven in een <literal
>input</literal
>-node en elke uitvoer in een <literal
>output</literal
>-node. Bij elke invoer of uitvoer moet er een <literal
>table</literal
>- of een <literal
>float</literal
>-node worden opgegeven als een "child". Het <literal
>type</literal
>-attribuut van een <literal
>table</literal
> moet <literal
>&quot;float&quot;</literal
> zijn. Merk op dat de volgorde van de invoer en de uitvoer belangrijk is&mdash;de volgorde bepaalt de indexwaarden van elke invoer- en uitvoer"array" in de "object file", en wordt in de plugin-interface van &kst; gebruikt voor het tonen van de in- en uitvoervelden. </para>

<para
>Als u klaar bent met het XML-bestand bewaart u het als <filename
>[modulenaam].xml</filename
> waarin <filename
>[modulenaam]</filename
> gelijk is aan het <literal
>name</literal
>-attribuut van de <literal
>modulename</literal
>-node. </para>

</sect2>

<sect2 id="creatingbasicpluginobjectfile">
<title
>De "Shared Object File"</title>
<para
>De "shared object file" bevat de feitelijke functionaliteit van de plugin. In andere woorden: deze bepaalt hoe de uitvoer wordt verkregen uit de gegeven invoer. De shared object file moet aan de volgende eisen voldoen:  </para>

<itemizedlist>

<listitem>
<para
>Het object moet de volgende "C linkage symbol" exporteren: <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
>waarin <replaceable
>symbol</replaceable
> gelijk moet zijn aan het <literal
>name</literal
>-attribuut van de <literal
>modulename</literal
>-node in het XML-bestand. Dit is de enige functie die door &kst; wordt aangeroepen (call) (hoewel u andere functies kunt hebben). In het volgende een beschrijving van elk argument van deze functie: </para>

<variablelist>
<varlistentry>
<term
><varname
>const double *const inArrays[]</varname
></term>
<listitem>
<para
>De "array" van invoer-"arrays". Elke invoer-array hoort bij een invoervector. De arrays hebben dezelfde volgorde als de in het XML-bestand genoemde vectoren, zodat <literal
>inArrays[0]</literal
> de array is die de eerste invoervector vertegenwoordigt, <literal
>inArrays[1]</literal
> de array die de tweede invoervector vertegenwoordigt, en zo verder. </para>
</listitem>
</varlistentry>

<varlistentry>
<term
><varname
>const int inArraysLens[]</varname
></term>
<listitem>
<para
>De array met de arraylengtes van elke invoer-array. De lengtes worden in dezelfde volgorde opgeslagen als de arrays in <literal
>inArrays[]</literal
> (bijv. <literal
>inArrayLens[0]</literal
> is de lengte van <literal
>inArrays[0]</literal
>). </para>
</listitem>
</varlistentry>

<varlistentry>
<term
><varname
>const double inScalars[]</varname
></term>
<listitem>
<para
>De array van invoerscalairen. De scalairen worden in dezelfde volgorde opgeslagen als in het XML-bestand. </para>
</listitem>
</varlistentry>

<varlistentry>
<term
><varname
>double *outArrays[]</varname
></term>
<listitem>
<para
>De array van uitvoer-arrays. Elke uitvoer-array hoort bij een uitvoervector, en de arrays moeten dezelfde volgorde hebben als de uitvoervectoren in het XML-bestand. </para>
</listitem>
</varlistentry>

<varlistentry>
<term
><varname
>int outArrayLens[]</varname
></term>
<listitem>
<para
>Deze array moet de lengtes bevatten van de uitvoer-arrays. De volgorde van de lengtes moet dezelfde zijn als die van de arrays in <literal
>outArrays[]</literal
>. </para>
</listitem>
</varlistentry>

<varlistentry>
<term
><varname
>double outScalars[]</varname
></term>
<listitem>
<para
>De array van de uitvoerscalairen. De volgorde van de scalairen moet gelijk zijn aan die in het XML-bestand. </para>
</listitem>
</varlistentry>
</variablelist>


</listitem>

<listitem>
<para
>De functie moet <literal
>0</literal
> retourneren indien met succes uitgevoerd, en anders <literal
>-1</literal
>. </para>
</listitem>

<listitem>
<para
>In de code van de "object file" moet een onverwachte invoer goed worden verwerkt, zoals lege invoer-arrays (meestal is het in dergelijke gevallen voldoende <literal
>-1</literal
> te retourneren). </para>
</listitem>

<listitem>
<para
>Het aantal en type van de uitvoer moet precies overeenkomen met die in het XML-bestand. </para>
</listitem>

<listitem>
<para
>Het zal waarschijnlijk nodig zijn de afmetingen van de arrays in <varname
>outArrays[]</varname
> te wijzigen. Hiervoor kunt u de functie <function
>realloc()</function
> gebruiken. Bijv.: </para>
<informalexample>
<screen
>outArrays[0]=(double*)realloc(outArrays[0], 5*sizeof(double));
</screen>
</informalexample>
<para
>zal (geheugen)ruimte voor 5 "doubles" aan <varname
>outArrays[0]</varname
> beschikbaar stellen (allocate). Gebruik voor het toewijzen van geheugen geen andere functie dan <function
>realloc()</function
>. </para>
</listitem>

<listitem>
<para
>De invoerargumenten moeten constanten blijven. Verander (cast) die niet naar niet-constante typen. </para>
</listitem>

</itemizedlist>

<para
>Hier volgt een voorbeeld van de broncode voor de shared object file van een eenvoudige plugin: </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[])

//Accepteer 1 vector en 1 scalair. Vermenigvuldig alle elementen van de vector met de
//scalair, en voer de resulaatvector uit. Voor ook de originele scalair uit.
{
        //De uitvoer instellen
        outArrayLens[0]=inArrayLens[0];

        //afmetingen wijzigen uitvoer-arrays
        outArrays[0]=(double*)realloc(outArrays[0], inArrayLens[0]*sizeof(double));

        //elk element van de invoervector vermenigvuldigen
        //met de scalair
        for (int i=0; i&lt;inArrayLens[0]; i++)
        {
                outArrays[0][i]=inArrays[0][i] * is[0];
        }

        //nu de uitvoerscalair instellen
        outScalars[0]=is[0];

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


<sect2 id="compilingplugin">
<title
>De plugin compileren</title>
<para
>Als u voor het compileren van uw plugin &gcc; gebruikt kunt u het objectbestand eenvoudig compileren met: <screen
><userinput
><command
>cc -Wall -c -o mijnplugin.o mijnplugin.c -fPIC -DPIC</command
></userinput
></screen>
</para>
<para
>en daarna de gedeelde bibliotheek maken: <screen
><userinput
><command
>ld -o mijnplugin.so -shared mijnplugin.o</command
></userinput
></screen>
</para>
<para
>Het zo verkregen <filename
>*.so</filename
>-bestand en <filename
>*.xml</filename
>-bestand moeten in dezelfde map worden geplaatst. Wanneer u wilt dat de pluginbeheerder (Plugin Manager) van &kst; het XML-bestand inleest, zal die automatisch in dezelfde map naar de shared object file zoeken. </para>

</sect2>
</sect1>

<sect1 id="creatinglinearfittingplugins">
<title
>Het maken van plugins voor lineaire aanpassing (linear fit)</title>
<para
>Om een plugin te maken voor lineaire aanpassing kunt u uw eigen aanpassingsalgoritmen gebruiken en de geëigende vectoren uitvoeren. In &kst; zijn echter reeds de nodige header-bestanden beschikbaar die het voor u eenvoudig maken om plugins te implementeren voor de lineaire aanpassing met behulp van de methode van de kleinste kwadraten, gewoon door u een paar functies ter beschikking te stellen. In deze sectie leest u hoe u deze bestanden kunt gebruiken. </para>

<sect2 id="headerslinearfittingplugins">
<title
>Header-bestanden</title>
<para
>Voor lineaire aanpassing zijn twee header-bestanden aanwezig, <filename
>linear.h</filename
> (voor ongewogen lineaire aanpassing) en <filename
>linear_weighted.h</filename
> (voor gewogen lineaire aanpassing). U kunt beiden vinden in de map<filename
>kst/plugins/fits/</filename
> in de "tarball" (ingepakt archiefbestand met extensie .tar.gz) met de broncode van &kst;. Om deze bestanden te gebruiken moet een ervan worden opgenomen (include) in de broncode van uw plugin: <screen>
#include &lt;../linear.h&gt;
</screen
> of <screen>
#include &lt;../linear_weighted.h&gt;
</screen
> (volgens afspraak plaatsen we de broncode voor de plugin in een submap van de map met de header-bestanden). </para>

</sect2>

<sect2 id="reqfunctionsfittingplugins">
<title
>Implementeren van de vereiste functies</title>
<para
>Gegeven is een algemeen lineair model: </para>
<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="Formula-kst-generallinearmodel.png" format="PNG"/>
</imageobject>
</inlinemediaobject>
</para>
<para
>met <literal
>y</literal
> een vector van <literal
>n</literal
> waarnemingen, <literal
>X</literal
> een <literal
>n</literal
> bij <literal
>p</literal
> matrix van onafhankelijke variabelen (voorspellers, predictors) en <literal
>c</literal
> de vector van<literal
>p</literal
> aan te passen parameters. De header-bestanden verschaffen de functies voor het afschatten van c voor een gegeven <literal
>y</literal
> en <literal
>X</literal
>. Voor het verkrijgen van <literal
>X</literal
> moet de volgende functie worden geïmplementeerd in de broncode van de plugin: <literallayout
><function
><returnvalue
>double</returnvalue
> calculate_matrix_entry( double <parameter
>dX</parameter
>, int <parameter
>iPos</parameter
> )</function
></literallayout>
</para>
<para
>Deze functie moet de waarde van de "entry" (ingang) retourneren in de kolom <literal
>iPos</literal
> van de matrix van onafhankelijke variabelen (predictors, voorspellers), met gebruik van de <literal
>x</literal
>-waarde <literal
>dX</literal
>. Deze functie wordt aangeroepen (call) door linear.h of linear_weighted.h. De implementatie van de functie is afhankelijk van het het model dat u voor de aanpassing wilt gebruiken, en is uniek voor elke plugin voor lineaire aanpassing. Bijvoorbeeld, voor de aanpassing aan een veelterm-model kan <function
>calculate_matrix_entry</function
> als volgt worden geïmplementeerd: <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
>Het aanroepen (calling) van de aanpassingsfuncties (fitting functions)</title>
<para
>Als het goede headerbestand "included" is en <function
>calculate_matrix_entry</function
> is geïmplementeerd kunt u de aanpassingsfunctie die in het header-bestand aanwezig is aanroepen: <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
> of <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
>Elke functie retourneert bij een succesvolle uitvoering <literal
>0</literal
> en als er een fout optreedt <literal
>-1</literal
>, het is dus een goed idee om de retourwaarde van de geëxporteerde C-functie gelijk te maken aan die van de aanpassingsfunctie. Voor de eenvoud kan de code voor de plugin de argumenten van de geëxporteerde C-functie gewoon doorgeven aan de aanpassingsfunctie. Maar let erop dat inArrays de volgende structuur moet hebben: </para>
<itemizedlist>
<listitem>
<para
><varname
>inArrays[0]</varname
> moet de array van x-coördinaten bevatten van de gegeven punten </para>
</listitem>

<listitem>
<para
><varname
>inArrays[1]</varname
> moet de array van y-coördinaten bevatten van de gegeven punten </para>
</listitem>

<listitem>
<para
><varname
>inArrays[2]</varname
> bestaat alleen als<function
>kstfit_linear_weighted</function
> wordt aangeroepen, en moet de array van gewichten bevatten die bij de aanpassing worden gebruikt. </para>
</listitem>
</itemizedlist>
<para
>De gemakkelijkste manier om er voor te zorgen dat de structuur van inArray in orde is, is het in de goede volgorde opgeven van de invoervectoren in het XML-bestand van de plugin. </para>
<para
><varname
>iNumParams</varname
> is het aantal van de parameters in het gebruikte aanpassingsmodel en moet gelijk zijn aan het aantal kolommen in de matrix <literal
>X</literal
> van onafhankelijke variabelen. <varname
>iNumParams</varname
> moet de juiste waarde hebben voordat de aanpassingsfunctie wordt aangeroepen. </para>
<para
>Na het aanroepen van <function
>kstfit_linear_unweighted</function
> of <function
>kstfit_linear_weighted</function
> krijgen <varname
>outArrays</varname
> en <varname
>outScalars</varname
> de volgende waarden: </para>
<itemizedlist>
<listitem>
<para
><varname
>outArrays[0]</varname
> bevat dan de array van aangepaste y-waarden. </para>
</listitem>

<listitem>
<para
><varname
>outArrays[1]</varname
> bevat dan de array van restwaarden (residuen). </para>
</listitem>

<listitem>
<para
><varname
>outArrays[2]</varname
> bevat dan de array van de geschatte parameters voor de beste aanpassing (best-fit parameters). </para>
</listitem>

<listitem>
<para
><varname
>outArrays[3]</varname
> bevat dan de covariantiematrix, rij na rij in een array geretourneerd. </para>
</listitem>

<listitem>
<para
><varname
>outScalars[0]</varname
> bevat dan chi^2/nu, met chi^2 de gewogen som van de kwadraten van de restwaarden, en nu het aantal vrijheidsgraden. </para>
</listitem>
</itemizedlist>
<para
><varname
>outArrayLens</varname
> bevat dan de lengten van elke uitvoer-array. </para>

<para
>Zorg ervoor dat de opgegeven uitvoer in het XML-bestand overeenkomt met de uitvoer die door de geëxporteerde C-functie wordt geretourneerd (wat in de meeste gevallen gewoon de uitvoer is die door de aanpassingsfunctie wordt geretourneerd). </para>


</sect2>

<sect2 id="examplelinearfittingplugins">
<title
>Voorbeeld</title>
<para
>Hier volgt een voorbeeld van de broncode voor een plugin voor een lineaire aanpassing (linear fit). </para>
<informalexample>
<screen
>/*
 *  Veelterm aanpassingsplugin voor KST.
 *  Copyright 2004, The University of British Columbia
 *  Beschikbaar onder de GPL-voorwaarden.
 */

#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
>Het maken van plugins voor niet-lineaire aanpassing (non-linear fit)</title>
<para
>&kst; heeft header-bestanden die het maken van plugins voor een niet-lineaire kleinste kwadraten-aanpassing (non-linear least squares fit) vereenvoudigen. In de volgende secties vindt u een beschrijving van het gebruik van deze header-bestanden. </para>

<sect2 id="headersnonlinearfittingplugins">
<title
>Header-bestanden en definities</title>
<para
>Voor niet-lineaire aanpassing zijn twee header-bestanden aanwezig, <filename
>non-linear.h</filename
> (voor ongewogen niet-lineaire aanpassing) en <filename
>non-linear_weighted.h</filename
> (voor gewogen niet-lineaire aanpassing). U kunt beiden vinden in de map<filename
>kst/plugins/fits_nonlinear/</filename
> in de "tarball" (ingepakt archiefbestand met extensie .tar.gz) met de broncode van &kst;. Om deze bestanden te gebruiken moet een ervan worden opgenomen (include) in de broncode van uw plugin: <screen>
#include &lt;../non-linear.h&gt;
</screen
> of <screen>
#include &lt;../non-linear_weighted.h&gt;
</screen
> (volgens afspraak plaatsen we de broncode voor de plugin in een submap van de map met de header-bestanden). </para>

<para
>Omdat het niet-lineair aanpassen een iteratief (herhaald) proces is moet u ook het maximum aantal iteraties opgeven. Het algoritme voor de niet-lineaire aanpassing stopt als er aan minstens een van de volgende condities wordt voldaan: </para>
<itemizedlist>
<listitem>
<para
>Het maximum aantal iteraties (herhalingen) is bereikt. </para>
</listitem>
<listitem>
<para
>Een nauwkeurigheid van 10<superscript
>-4</superscript
> is bereikt. </para>
</listitem>
</itemizedlist>
<para
>Bovendien moet u het aantal parameters in het model opgeven omdat die niet expliciet wordt doorgegeven naar de aanpassingsfunctie. Om deze twee waarden op te geven neemt u die op bovenin uw broncode: </para>
<screen
>#define NUM_PARAMS [num1]
#define MAX_NUM_ITERATIONS [num2]
</screen>
<para
>waarbij u <literal
>[num1]</literal
> vervangt door het aantal parameters in het model en <literal
>[num2]</literal
> door het maximale aantal iteraties. </para>
</sect2>

<sect2 id="reqfunctionsnonlinearfittingplugins">
<title
>Implementeren van de vereiste functies</title>
<para
>Om de header-bestanden te gebruiken voor niet-lineaire aanpassing moet u de te gebruiken functie leveren voor het model, de partiële afgeleiden van de functie naar elke parameter en de geschatte beginwaarden voor de aan te passen parameters. Om dit te doen moeten er drie functies worden geïmplementeerd. Deze functies worden hieronder beschreven. </para>
<variablelist>
<varlistentry>
<term
><function
><returnvalue
>double</returnvalue
> function_calculate( double <parameter
>dX</parameter
>, double* <parameter
>pdParameters</parameter
> )</function
></term>
<listitem>
<para
>Deze functie berekent de y-waarde van het aanpassingsmodel voor een gegeven x-waarde <literal
>dX</literal
> met gebruik van de opgegeven array van parameters <varname
>pdParameters</varname
>. De volgorde van de parameters in <varname
>pdParameters</varname
> is willekeurig maar moet wel kloppen met de andere twee geïmplementeerde functies. Bijvoorbeeld, voor een exponentieel model kan <function
>function_calculate</function
> als volgt worden geïmplementeerd: </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
>Deze functie berekent de partiële afgeleide waarden van de modelfunctie voor een gegeven x-waarde <literal
>dX</literal
>. De partiële afgeleide waarden moeten worden geretourneerd in <varname
>pdDerivatives</varname
>. De volgorde van de partiële afgeleide waarden in <varname
>pdDerivatives</varname
> moet overeenstemmen met de volgorde van de parameters in <varname
>pdParameters</varname
> (bijv. als <varname
>pdParameters[0]</varname
> de parameter lambda bevat van een exponentieel model moet <varname
>pdDerivatives[0]</varname
> de afgeleide waarde bevatten van het model naar 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
>Deze functie levert een eerste afschatting voor de best passende parameters van de aanpassingsfunctie. De arrays van x- en y-waarden van de gegeven punten worden gegeven in <varname
>pdX</varname
> en <varname
>pdY</varname
>, en het aantal gegeven punten in <varname
>iLength</varname
>. Het is aan u of u die al of niet gebruikt voor de berekening van de beginwaarden. De functie moet de berekende beginwaarden plaatsen in <varname
>pdParameterEstimates</varname
>, waarbij de volgorde overeen moet komen met die van de parameters in <varname
>pdParameters</varname
> van <function
>function_calculate</function
> en <function
>function_derivative</function
>. Vergeet niet dat de beginwaarden belangrijk zijn voor het al of niet convergeren naar een oplossing van de aanpassingsfunctie. </para>
</listitem>
</varlistentry>

</variablelist>

</sect2>

<sect2 id="callingnonlinearfittingplugins">
<title
>Het aanroepen (calling) van de aanpassingsfuncties (fitting functions)</title>
<para
>Als de vereiste functies zijn geïmplementeerd, kan de aanpassingsfunctie in het header-bestand worden aangeroepen: <screen>
kstfit_nonlinear( <parameter
>inArrays</parameter
>, <parameter
>inArrayLens</parameter
>,
                  <parameter
>inScalars</parameter
>, <parameter
>outArrays</parameter
>,
                  <parameter
>outArrayLens</parameter
>, <parameter
>outScalars</parameter
> );
</screen
> of <screen>
kstfit_nonlinear_weighted( <parameter
>inArrays</parameter
>, <parameter
>inArrayLens</parameter
>,
                           <parameter
>inScalars</parameter
>, <parameter
>outArrays</parameter
>,
                           <parameter
>outArrayLens</parameter
>, <parameter
>outScalars</parameter
> );
</screen
> afhankelijk van of u een ongewogen of gewogen aanpassing wilt. </para>

<para
>De functie retourneert bij succes <literal
>0</literal
> of <literal
>-1</literal
> als er een fout optreedt, dus is het het eenvoudigst als de retourwaarde van de geëxporteerde C-functie gelijk wordt gesteld aan de retourwaarde van de aanpassingsfunctie. Voor de eenvoud kan de code van de plugin gewoon de argumenten van de geëxporteerde C-functie doorgeven aan de aanpassingsfunctie. Maar let erop dat inArrays als volgt moet worden gestructureerd: </para>
<itemizedlist>
<listitem>
<para
><varname
>inArrays[0]</varname
> moet de array van x-coördinaten bevatten van de gegeven punten </para>
</listitem>

<listitem>
<para
><varname
>inArrays[1]</varname
> moet de array van y-coördinaten bevatten van de gegeven punten </para>
</listitem>

<listitem>
<para
><varname
>inArrays[2]</varname
> bestaat alleen als<function
>kstfit_linear_weighted</function
> wordt aangeroepen, en moet de array van gewichten bevatten die bij de aanpassing worden gebruikt. </para>
</listitem>
</itemizedlist>
<para
>De gemakkelijkste manier om er voor te zorgen dat de structuur van inArray in orde is, is het in de goede volgorde opgeven van de invoervectoren in het XML-bestand van de plugin. </para>
<para
>Na het aanroepen van <function
>kstfit_linear_unweighted</function
> of <function
>kstfit_linear_weighted</function
> krijgen <varname
>outArrays</varname
> en <varname
>outScalars</varname
> de volgende waarden: </para>
<itemizedlist>
<listitem>
<para
><varname
>outArrays[0]</varname
> bevat dan de array van aangepaste y-waarden. </para>
</listitem>

<listitem>
<para
><varname
>outArrays[1]</varname
> bevat dan de array van restwaarden (residuen). </para>
</listitem>

<listitem>
<para
><varname
>outArrays[2]</varname
> bevat dan de array van de geschatte parameters voor de beste aanpassing (best-fit parameters). </para>
</listitem>

<listitem>
<para
><varname
>outArrays[3]</varname
> bevat dan de covariantiematrix, rij na rij in een array geretourneerd. </para>
</listitem>

<listitem>
<para
><varname
>outScalars[0]</varname
> bevat dan chi^2/nu, met chi^2 de gewogen som van de kwadraten van de restwaarden, en nu het aantal vrijheidsgraden. </para>
</listitem>
</itemizedlist>
<para
><varname
>outArrayLens</varname
> bevat dan de lengten van elke uitvoer-array. </para>

<para
>Zorg ervoor dat de opgegeven uitvoer in het XML-bestand overeenkomt met de uitvoer die door de geëxporteerde C-functie wordt geretourneerd (wat in de meeste gevallen gewoon de uitvoer is die door de aanpassingsfunctie wordt geretourneerd). </para>

</sect2>

<sect2 id="nonlinearfittingpluginexample">
<title
>Voorbeeld</title>
<para
>Het volgende is een voorbeeld van een niet-lineaire aanpassingsplugin voor een aanpassing (fit) aan een exponentieel model:</para>
<informalexample>
<screen
>/*
 *  Exponentiële aanpassingsplugin voor KST.
 *  Copyright 2004, The University of British Columbia
 *  Beschikbaar onder de GPL-voorwaarden.
 */

#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
>Het maken van plugins voor doorlaatfilters</title>
<para
>&kst; heeft header-bestanden waardoor het implementeren van doorlaatfilters wordt vereenvoudigd. Hieronder wordt het gebruik van deze header-bestanden beschreven. </para>
<sect2 id="creatingpassfilterpluginsheaderfiles">
<title
>Header-bestanden</title>
<para
>Het header-bestand voor doorlaatfilters bevindt zich in de map <filename
>kst/plugins/pass_filters</filename
> van de "tarball" (ingepakt archiefbestand met extensie .tar.gz) van de broncode van &kst;. Het bestand heet <filename
>filters.h</filename
>. Om dit bestand te gebruiken neemt u het op (include) in de broncode van uw plugin: <screen>
#include &lt;../filters.h&gt;
</screen
> (volgens afspraak plaatsen we de broncode voor de plugin in een submap van de map met de header-bestanden). </para>
</sect2>

<sect2 id="creatingpassfilterpluginsrequirements">
<title
>Vereiste functies</title>
<para
>Het header-bestand <filename
>filters.h</filename
> bevat een enkele functie die de Fouriertransformatie berekent van een aangeleverde functie, het geleverde filter toepast op de Fouriertransformatie, en daarna de inverse Fouriertransformatie berekent van de gefilterde Fouriertransformatie. Om het filter te leveren moet de volgende functie worden geïmplementeerd in de broncode van uw plugin: </para>
<para
><function
><returnvalue
>double</returnvalue
> filter_calculate( double <parameter
>dFreqValue</parameter
>, const double <parameter
>inScalars[]</parameter
> )</function
></para>
<para
>Deze functie moet de gefilterde amplitude berekenen voor de frequentie <literal
>dFreqValue</literal
>. <literal
>inScalars[]</literal
> bevat dan de ongewijzigde invoerscalairen van de plugin die zijn opgegeven in het XML-bestand. Hoogstwaarschijnlijk zal <literal
>inScalars[]</literal
> de afkapfrequenties of andere eigenschappen bevatten van het filter. Bijvoorbeeld, voor het implementeren van het Butterworth hoogdoorlaatfilter kan de functie <function
>filter_calculate</function
> als volgt worden geïmplementeerd: </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
>Het aanroepen (calling) van de filterfunctie</title>
<para
>Als de nodige <function
>filter_calculate</function
> is geïmplementeerd kan de filterfunctie in het header-bestand als volgt worden aangeroepen: </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
>De argumenten voor de geëxporteerde C-functie kunnen gewoonlijk zonder wijzigingen aan <function
>kst_pass_filter</function
> worden doorgegeven. Echter, er zijn een paar beperkingen voor de argumenten: </para>
<itemizedlist>
<listitem>
<para
><varname
>inArrays[0]</varname
> moet de array van te filteren gegevens bevatten. </para>
</listitem>

<listitem>
<para
><varname
>inScalars</varname
> moet de door de functie <function
>filter_calculate</function
> te gebruiken parameters bevatten die eigen zijn aan het filter. </para>
</listitem>
</itemizedlist>
<para
>Na het aanroepen van de functie bevat <varname
>outArrays[0]</varname
> de array van gefilterde gegevens en zal <varname
>outArrayLens</varname
> daaraan zijn aangepast. De functie <function
>kst_pass_filter</function
> maakt geen gebruik van <varname
>outScalars</varname
>. </para>
</sect2>

<sect2 id="creatingpassfilterpluginsexample">
<title
>Voorbeeld</title>
<para
>Het volgende is een voorbeeld van een plugin voor een Butterworth hoogdoorlaatfilter:  </para>
<informalexample>
<screen
>/*
 *  Butterworth hoogdoorlaatfilter plugin voor KST.
 *  Copyright 2004, The University of British Columbia
 *  Beschikbaar onder de GPL-voorwaarden.
 */

#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>