Warning, /graphics/kst-plot/docbook/kst/creatingplugins-chapter.docbook is written in an unsupported language. File is not indexed.
0001 <appendix id="creatingplugins">
0002 <title>Creating Additional Plugins</title>
0003 <para>
0004 &kst; has a simple and standardized interface that facilitates easy creation of additional plugins.
0005 In addition to detailing basic requirements for plugins, the following sections describe how to make
0006 use of pre-written header files to create certain types of plugins.
0007 </para>
0008
0009 <sect1 id="creatingbasicplugin">
0010 <title>Creating a Basic Plugin</title>
0011 <para>
0012 A &kst; plugin consists of two files—an XML file and a shared object file.
0013 </para>
0014
0015 <sect2 id="creatingbasicpluginxmlfile">
0016 <title>The XML File</title>
0017 <para>
0018 The XML file provide information about the plugin and describes its
0019 inputs and outputs. The following is an example of an XML
0020 file for a &kst; plugin:
0021 </para>
0022
0023 <informalexample>
0024 <screen><?xml version="1.0" encoding="UTF-8"?>
0025 <!DOCTYPE Module SYSTEM "file:/Repository/Level2/Soft/ProC/moduledef.dtd">
0026
0027 <module>
0028
0029 <intro>
0030 <modulename name="testplugin"/> <!-- The name of the module -->
0031 <author name="Rick Chern"/> <!-- The name of the author -->
0032 <description text="A test plugin for me"/> <!-- A description of the module -->
0033 <version minor="1" major="0"/> <!-- The version number of the module -->
0034 <state devstate="release"/> <!-- The development state of the module (optional)-->
0035 </intro>
0036
0037 <interface>
0038
0039 <!--inputs here-->
0040 <input>
0041 <table type="float" name="Input Vector 1" descr="The first input vector" />
0042 </input>
0043
0044 <input>
0045 <float name="Input Scalar 1" descr="The first input scalar" />
0046 </input>
0047
0048 <!--outputs here-->
0049 <output>
0050 <table type="float" name="Output Vector 1" descr="The first output vector" />
0051 </output>
0052
0053 <output>
0054 <float name="Output Scalar 1" descr="The first output scalar" />
0055 </output>
0056
0057 </interface>
0058
0059 </module>
0060 </screen>
0061 </informalexample>
0062
0063 <para>
0064 Generally, you can use the example above as a template and modify sections to fit your needs.
0065 As can be seen from the example, the XML file consists of one <literal>module</literal>
0066 node. The <literal>module</literal> node has an <literal>intro</literal> node and an
0067 <literal>interface</literal> node. You should modify the <literal>intro</literal> node
0068 appropriately using the comments in the above XML file as guides. It is important that
0069 <literal>modulename</literal> has the <literal>name</literal> attribute set to the same name
0070 that your shared object file will use.
0071 </para>
0072
0073 <para>
0074 The <literal>interface</literal> node describes the actual inputs and outputs of the plugin.
0075 Each input is described by an <literal>input</literal> node, and each output is described
0076 by an <literal>output</literal> node. Each input or output should have either a
0077 <literal>table</literal> or a <literal>float</literal> node as a child. The <literal>type</literal>
0078 attribute of a <literal>table</literal> must be set to <literal>"float"</literal>.
0079 Note that the order of the inputs and outputs matters—the order is used to determine
0080 the index values for each input and output array of the object file, and is the same order
0081 used to display the input and output fields in the &kst; plugin interface.
0082 </para>
0083
0084 <para>
0085 Once you have completed the XML file, save it as <filename>[modulename].xml</filename>, where
0086 <filename>[modulename]</filename> is the value of the <literal>name</literal> attribute
0087 of the <literal>modulename</literal> node.
0088 </para>
0089
0090 </sect2>
0091
0092 <sect2 id="creatingbasicpluginobjectfile">
0093 <title>The Shared Object File</title>
0094 <para>
0095 The shared object file contains the actual functionality of the plugin. In other words,
0096 it determines how to derive the outputs from the given inputs. The following are the
0097 requirements for the shared object file:
0098 </para>
0099
0100 <itemizedlist>
0101
0102 <listitem>
0103 <para>
0104 The object must export the following C linkage symbol:
0105 <literallayout><function><returnvalue>int</returnvalue> symbol(const double *const <parameter>inArrays[]</parameter>,
0106 const int <parameter>inArrayLens[]</parameter>,
0107 const double <parameter>inScalars[]</parameter>,
0108 double *<parameter>outArrays[]</parameter>,
0109 int <parameter>outArrayLens[]</parameter>,
0110 double <parameter>outScalars[]</parameter>)</function></literallayout>
0111 </para>
0112 <para>
0113 where <replaceable>symbol</replaceable> must be the value of the <literal>name</literal> attribute
0114 of the <literal>modulename</literal> node in the XML file. This is the only
0115 function that will be called by &kst; (although you may have other functions).
0116 The following describes each argument of this function:
0117 </para>
0118
0119 <variablelist>
0120 <varlistentry>
0121 <term><varname>const double *const inArrays[]</varname></term>
0122 <listitem>
0123 <para>
0124 The array of input arrays. Each input array corresponds to an input vector.
0125 The arrays are in the same order as the vectors are listed in the XML file, so
0126 <literal>inArrays[0]</literal> is the array representing the first input vector,
0127 <literal>inArrays[1]</literal> is the array representing the second input vector,
0128 and so on.
0129 </para>
0130 </listitem>
0131 </varlistentry>
0132
0133 <varlistentry>
0134 <term><varname>const int inArraysLens[]</varname></term>
0135 <listitem>
0136 <para>
0137 The array containing array lengths for each input array. The lengths are stored
0138 in the same order as the arrays in <literal>inArrays[]</literal> (e.g.
0139 <literal>inArrayLens[0]</literal> is the length of <literal>inArrays[0]</literal>).
0140 </para>
0141 </listitem>
0142 </varlistentry>
0143
0144 <varlistentry>
0145 <term><varname>const double inScalars[]</varname></term>
0146 <listitem>
0147 <para>
0148 The array of input scalars. The scalars are stored in the same order as they
0149 are listed in the XML file.
0150 </para>
0151 </listitem>
0152 </varlistentry>
0153
0154 <varlistentry>
0155 <term><varname>double *outArrays[]</varname></term>
0156 <listitem>
0157 <para>
0158 The array of output arrays. Each output array corresponds to an output vector,
0159 and the arrays should be in the same order as the output vectors are listed in the
0160 XML file.
0161 </para>
0162 </listitem>
0163 </varlistentry>
0164
0165 <varlistentry>
0166 <term><varname>int outArrayLens[]</varname></term>
0167 <listitem>
0168 <para>
0169 The array that should contain lengths of the output arrays. The lengths should be
0170 stored in the same order as the arrays in <literal>outArrays[]</literal>.
0171 </para>
0172 </listitem>
0173 </varlistentry>
0174
0175 <varlistentry>
0176 <term><varname>double outScalars[]</varname></term>
0177 <listitem>
0178 <para>
0179 The array of output scalars. The scalars should be in the same order they are
0180 listed in the XML file.
0181 </para>
0182 </listitem>
0183 </varlistentry>
0184 </variablelist>
0185
0186
0187 </listitem>
0188
0189 <listitem>
0190 <para>
0191 The function must return <literal>0</literal> if it executed successfully, and
0192 <literal>-1</literal> otherwise.
0193 </para>
0194 </listitem>
0195
0196 <listitem>
0197 <para>
0198 The code for the object file must handle unexpected inputs, such as empty input arrays
0199 (in most cases a return value of <literal>-1</literal> would be sufficient when such
0200 situations are encountered).
0201 </para>
0202 </listitem>
0203
0204 <listitem>
0205 <para>
0206 The number and type of outputs must be exactly as specified by the XML file.
0207 </para>
0208 </listitem>
0209
0210 <listitem>
0211 <para>
0212 You will probably need to resize the arrays in <varname>outArrays[]</varname>.
0213 To do so, use the <function>realloc()</function> function. E.g.,
0214 </para>
0215 <informalexample>
0216 <screen>
0217 outArrays[0]=(double*)realloc(outArrays[0], 5*sizeof(double));
0218 </screen>
0219 </informalexample>
0220 <para>
0221 will allocate space for 5 doubles for <varname>outArrays[0]</varname>. Do not
0222 use any memory allocator other than <function>realloc()</function>.
0223 </para>
0224 </listitem>
0225
0226 <listitem>
0227 <para>
0228 The input arguments must remain constant. Do not cast them to non-constant types.
0229 </para>
0230 </listitem>
0231
0232 </itemizedlist>
0233
0234 <para>
0235 The following is an example of the shared object file source code for a simple
0236 plugin:
0237 </para>
0238 <informalexample>
0239 <screen>
0240 #include <stdlib.h>
0241
0242 extern "C" int testplugin(const double *const inArrays[], const int inArrayLens[],
0243 const double is[],
0244 double *outArrays[], int outArrayLens[],
0245 double outScalars[]);
0246
0247 int testplugin(const double *const inArrays[], const int inArrayLens[],
0248 const double is[],
0249 double *outArrays[], int outArrayLens[],
0250 double outScalars[])
0251
0252 //Accept 1 vector and 1 scalar. Multiply all elements of the vector by the
0253 //scalar, and output the resulting vector. Also output the original scalar.
0254 {
0255 //Set the outputs
0256 outArrayLens[0]=inArrayLens[0];
0257
0258 //resize the output arrays
0259 outArrays[0]=(double*)realloc(outArrays[0], inArrayLens[0]*sizeof(double));
0260
0261 //multiply each element of the input vector
0262 //by the scalar
0263 for (int i=0; i<inArrayLens[0]; i++)
0264 {
0265 outArrays[0][i]=inArrays[0][i] * is[0];
0266 }
0267
0268 //now set the output scalar
0269 outScalars[0]=is[0];
0270
0271 return 0;
0272 }
0273 </screen>
0274 </informalexample>
0275 </sect2>
0276
0277
0278 <sect2 id="compilingplugin">
0279 <title>Compiling the Plugin</title>
0280 <para>
0281 If you are using &gcc; to compile your plugin, simply compile the object file:
0282 <screen><userinput><command>cc -Wall -c -o myplugin.o myplugin.c -fPIC -DPIC</command></userinput></screen>
0283 </para>
0284 <para>and then create the shared library:
0285 <screen><userinput><command>ld -o myplugin.so -shared myplugin.o</command></userinput></screen>
0286 </para>
0287 <para>
0288 The resulting <filename>*.so</filename> file and <filename>*.xml</filename> file must be put in the same
0289 directory. When you use &kst;'s Plugin Manager to load the XML file, it will automatically look for the
0290 shared object file in the same directory.
0291 </para>
0292
0293 </sect2>
0294 </sect1>
0295
0296 <sect1 id="creatinglinearfittingplugins">
0297 <title>Creating Linear Fit Plugins</title>
0298 <para>
0299 To create a linear fit plugin, you could implement your own fitting algorithms and output the appropriate
0300 vectors. However, &kst; already comes with header files that make it easy for you to implement linear
0301 least-squares fit plugins by just providing a few functions.
0302 This section will describe how to take advantage of these files.
0303 </para>
0304
0305 <sect2 id="headerslinearfittingplugins">
0306 <title>Header Files</title>
0307 <para>
0308 Two header files are provided for performing linear fits, <filename>linear.h</filename>
0309 (for unweighted linear fits) and
0310 <filename>linear_weighted.h</filename> (for weighted linear fits). They are both located under
0311 <filename>kst/plugins/fits/</filename> in the &kst; source tarball. To use these files, include only one
0312 of them in the source code for your plugin:
0313 <screen>
0314 #include <../linear.h>
0315 </screen>
0316 or
0317 <screen>
0318 #include <../linear_weighted.h>
0319 </screen>
0320 (by convention, we will place the source code for the plugin one directory below where the header files
0321 are).
0322 </para>
0323
0324 </sect2>
0325
0326 <sect2 id="reqfunctionsfittingplugins">
0327 <title>Implementing Required Functions</title>
0328 <para>
0329 Given a general linear model:
0330 </para>
0331 <para>
0332 <inlinemediaobject>
0333 <imageobject>
0334 <imagedata fileref="Formula-kst-generallinearmodel.png" format="PNG"/>
0335 </imageobject>
0336 </inlinemediaobject>
0337 </para>
0338 <para>
0339 where <literal>y</literal> is a vector of <literal>n</literal> observations, <literal>X</literal>
0340 is an <literal>n</literal> by <literal>p</literal> matrix of predictor variables, and <literal>c</literal>
0341 is the vector of <literal>p</literal> best-fit parameters that are to be estimated, the header files
0342 provide functions for estimating <literal>c</literal> for a given <literal>y</literal> and
0343 <literal>X</literal>. To provide <literal>X</literal>, the following function needs to be
0344 implemented in the source code for the plugin:
0345 <literallayout><function><returnvalue>double</returnvalue> calculate_matrix_entry( double <parameter>dX</parameter>, int <parameter>iPos</parameter> )</function></literallayout>
0346 </para>
0347 <para>
0348 This function should return the value of the entry in column <literal>iPos</literal>
0349 of the matrix of predictor variables, using <literal>x</literal> value <literal>dX</literal>.
0350 This function will be called by linear.h or linear_weighted.h. The implementation of this function
0351 depends on the model you wish to use for the fit, and is unique to each linear fit plugin.
0352 For example, to fit to a polynomial model, <function>calculate_matrix_entry</function> could
0353 be implemented as follows:
0354 <informalexample>
0355 <screen>
0356 double calculate_matrix_entry( double dX, int iPos ) {
0357 double dY;
0358 dY = pow( dX, (double)iPos );
0359 return dY;
0360 }
0361 </screen>
0362 </informalexample>
0363 </para>
0364
0365 </sect2>
0366
0367 <sect2 id="callingfittingfunctionslinearfittingplugins">
0368 <title>Calling the Fitting Functions</title>
0369 <para>
0370 Once the appropriate header file has been included and <function>calculate_matrix_entry</function>
0371 has been implemented, call the appropriate fitting function included from the header file:
0372 <screen>
0373 <function>kstfit_linear_unweighted( <parameter>inArrays</parameter>, <parameter>inArrayLens</parameter>,
0374 <parameter>outArrays</parameter>, <parameter>outArrayLens</parameter>,
0375 <parameter>outScalars</parameter>, <parameter>iNumParams</parameter> )</function>;
0376 </screen>
0377 or
0378 <screen>
0379 <function>kstfit_linear_weighted( <parameter>inArrays</parameter>, <parameter>inArrayLens</parameter>,
0380 <parameter>outArrays</parameter>, <parameter>outArrayLens</parameter>,
0381 <parameter>outScalars</parameter>, <parameter>iNumParams</parameter> )</function>;
0382 </screen>
0383 </para>
0384 <para>
0385 Each function will return <literal>0</literal> on success, or <literal>-1</literal> on
0386 error, so it is a good idea to set the return value of the exported C function to be equal to the return
0387 value of the fitting function. To maintain simplicity, the code for the plugin can simply pass the
0388 arguments given to the exported C function to the fitting function. Note, however, that inArrays must
0389 be structured as follows:
0390 </para>
0391 <itemizedlist>
0392 <listitem>
0393 <para>
0394 <varname>inArrays[0]</varname> must contain the array of x coordinates of the data points
0395 </para>
0396 </listitem>
0397
0398 <listitem>
0399 <para>
0400 <varname>inArrays[1]</varname> must contain the array of y coordinates of the data points
0401 </para>
0402 </listitem>
0403
0404 <listitem>
0405 <para>
0406 <varname>inArrays[2]</varname> only exists if <function>kstfit_linear_weighted</function>
0407 is being called, and must contain the array of weights to use for the fit.
0408 </para>
0409 </listitem>
0410 </itemizedlist>
0411 <para>
0412 The easiest way to ensure that inArrays is structured correctly is to specify the correct
0413 order of input vectors in the XML file for the plugin.
0414 </para>
0415 <para>
0416 <varname>iNumParams</varname> is the number of parameters in the fitting model used, which
0417 should be equal to the number of columns in the matrix <literal>X</literal> of
0418 predictor variables. <varname>iNumParams</varname> must be set correctly before the fitting
0419 function is called.
0420 </para>
0421 <para>
0422 After <function>kstfit_linear_unweighted</function> or <function>kstfit_linear_weighted</function>
0423 is called, <varname>outArrays</varname> and <varname>outScalars</varname>
0424 will be set as follows:
0425 </para>
0426 <itemizedlist>
0427 <listitem>
0428 <para>
0429 <varname>outArrays[0]</varname> will contain the array of fitted y values.
0430 </para>
0431 </listitem>
0432
0433 <listitem>
0434 <para>
0435 <varname>outArrays[1]</varname> will contain the array of residuals.
0436 </para>
0437 </listitem>
0438
0439 <listitem>
0440 <para>
0441 <varname>outArrays[2]</varname> will contain the array of best-fit parameters that were estimated.
0442 </para>
0443 </listitem>
0444
0445 <listitem>
0446 <para>
0447 <varname>outArrays[3]</varname> will contain the covariance matrix, returned row after row in an array.
0448 </para>
0449 </listitem>
0450
0451 <listitem>
0452 <para>
0453 <varname>outScalars[0]</varname> will contain chi^2/nu, where chi^2 is the weighted sum of squares of the residuals,
0454 and nu is the degrees of freedom.
0455 </para>
0456 </listitem>
0457 </itemizedlist>
0458 <para>
0459 <varname>outArrayLens</varname> will be correctly set to indicate the length of each output array.
0460 </para>
0461
0462 <para>
0463 Ensure that the specified outputs in the XML file match those that the exported C function returns (which
0464 in most cases will simply be the outputs returned by the fitting function).
0465 </para>
0466
0467
0468 </sect2>
0469
0470 <sect2 id="examplelinearfittingplugins">
0471 <title>Example</title>
0472 <para>
0473 The following is an example of the source code for a linear fit plugin.
0474 </para>
0475 <informalexample>
0476 <screen>
0477 /*
0478 * Polynomial fitting plugin for KST.
0479 * Copyright 2004, The University of British Columbia
0480 * Released under the terms of the GPL.
0481 */
0482
0483 #include "../linear.h"
0484
0485 double calculate_matrix_entry( double dX, int iPos ) {
0486 double dY;
0487
0488 dY = pow( dX, (double)iPos );
0489
0490 return dY;
0491 }
0492
0493 extern "C" int kstfit_polynomial_unweighted(
0494 const double *const inArrays[],
0495 const int inArrayLens[],
0496 const double inScalars[],
0497 double *outArrays[], int outArrayLens[],
0498 double outScalars[]);
0499
0500 int kstfit_polynomial_unweighted(
0501 const double *const inArrays[],
0502 const int inArrayLens[],
0503 const double inScalars[],
0504 double *outArrays[], int outArrayLens[],
0505 double outScalars[])
0506 {
0507 int iRetVal = -1;
0508 int iNumParams;
0509
0510 iNumParams = 1 + (int)floor( inScalars[0] );
0511 if( iNumParams > 0 ) {
0512 iRetVal = kstfit_linear_unweighted( inArrays, inArrayLens,
0513 outArrays, outArrayLens,
0514 outScalars, iNumParams );
0515 }
0516
0517 return iRetVal;
0518 }
0519 </screen>
0520 </informalexample>
0521 </sect2>
0522
0523 </sect1>
0524
0525 <sect1 id="creatingnonlinearfitplugin">
0526 <title>Creating Non-linear Fit Plugins</title>
0527 <para>
0528 &kst; provides header files designed to simplify the creation of non-linear least-squares fit plugins.
0529 The following sections detail the use of the header files.
0530 </para>
0531
0532 <sect2 id="headersnonlinearfittingplugins">
0533 <title>Header Files and Definitions</title>
0534 <para>
0535 The non-linear fit header files are located in <filename>kst/plugins/fits_nonlinear</filename> of
0536 the &kst; source tarball. The files are named <filename>non_linear.h</filename> and
0537 <filename>non_linear_weighted.h</filename> for unweighted and weighted fits, respectively.
0538 To use these files, include only one of them in the source code for your plugin:
0539 <screen>
0540 #include <../non_linear.h>
0541 </screen>
0542 or
0543 <screen>
0544 #include <../non_linear_weighted.h>
0545 </screen>
0546 (by convention, we will place the source code for the plugin one directory below where the header files
0547 are).
0548 </para>
0549
0550 <para>
0551 As non-linear fitting is an iterative process, you must also define the maximum number of iterations
0552 that should be performed. The non-linear fitting algorithm will stop when at least one of the following
0553 conditions is true:
0554 </para>
0555 <itemizedlist>
0556 <listitem>
0557 <para>
0558 The maximum number of iterations has been reached.
0559 </para>
0560 </listitem>
0561 <listitem>
0562 <para>
0563 A precision of 10<superscript>-4</superscript> has been reached.
0564 </para>
0565 </listitem>
0566 </itemizedlist>
0567 <para>
0568 In addition, you need to define the number of parameters in the model, as it is not passed to the fitting
0569 function explicitly. To define these two values, include the following at the top of your source code:
0570 </para>
0571 <screen>
0572 #define NUM_PARAMS [num1]
0573 #define MAX_NUM_ITERATIONS [num2]
0574 </screen>
0575 <para>
0576 replacing <literal>[num1]</literal> with the number of parameters in the model, and <literal>[num2]</literal>
0577 with the maximum number of iterations to perform.
0578 </para>
0579 </sect2>
0580
0581 <sect2 id="reqfunctionsnonlinearfittingplugins">
0582 <title>Implementing Required Functions</title>
0583 <para>
0584 To use the header files for non-linear fits, you must provide the function to use as the model,
0585 the partial derivatives of the function with respect to each parameter, and initial estimates
0586 of the best-fit parameters.
0587 To do this, three functions must be implemented. These functions
0588 are described below.
0589 </para>
0590 <variablelist>
0591 <varlistentry>
0592 <term><function><returnvalue>double</returnvalue> function_calculate( double <parameter>dX</parameter>, double* <parameter>pdParameters</parameter> )</function></term>
0593 <listitem>
0594 <para>
0595 This function calculates the y value of the fitting model for a given x value <literal>dX</literal>,
0596 using the supplied array of parameters <varname>pdParameters</varname>. The order of parameters in
0597 <varname>pdParameters</varname> is arbitrary, but should be consistent with the other two
0598 implemented functions.
0599 For example, for an exponential model,
0600 <function>function_calculate</function> could be implemented as follows:
0601 </para>
0602 <informalexample>
0603 <screen>
0604 double function_calculate( double dX, double* pdParameters ) {
0605 double dScale = pdParameters[0];
0606 double dLambda = pdParameters[1];
0607 double dOffset = pdParameters[2];
0608 double dY;
0609
0610 dY = ( dScale * exp( -dLambda * dX ) ) + dOffset;
0611
0612 return dY;
0613 }
0614 </screen>
0615 </informalexample>
0616 </listitem>
0617 </varlistentry>
0618
0619 <varlistentry>
0620 <term><function><returnvalue>void</returnvalue> function_derivative( double <parameter>dX</parameter>, double* <parameter>pdParameters</parameter>, double* <parameter>pdDerivatives</parameter> )</function></term>
0621 <listitem>
0622 <para>
0623 This function calculates the partial derivatives of the model function for
0624 a give value of x <literal>dX</literal>. The partial derivatives should be returned in
0625 <varname>pdDerivatives</varname>. The order of the partial derivatives in the array
0626 <varname>pdDerivatives</varname> should correspond to the order of the parameters
0627 in <varname>pdParameters</varname> (i.e. if <varname>pdParameters[0]</varname> contains
0628 the parameter lambda for an exponential model, <varname>pdDerivatives[0]</varname> should
0629 contain the derivative of the model with respect to lambda).
0630 </para>
0631 </listitem>
0632 </varlistentry>
0633
0634 <varlistentry>
0635 <term><function><returnvalue>void</returnvalue> function_initial_estimate(
0636 const double* <parameter>pdX</parameter>, const double* <parameter>pdY</parameter>,
0637 int <parameter>iLength</parameter>, double* <parameter>pdParameterEstimates</parameter> )</function></term>
0638 <listitem>
0639 <para>
0640 This function provides an initial estimate of the best-fit parameters to the fitting function. The array of
0641 x values and y values of the data points are provided in <varname>pdX</varname> and <varname>pdY</varname>
0642 respectively, and the number of data points is provided by <varname>iLength</varname>. You can use any or
0643 none of these parameters at your discretion to calculate the initial estimate. The function should put the
0644 calculated initial estimates in <varname>pdParameterEstimates</varname>, with the order of the estimates
0645 corresponding to the order of the parameters in <varname>pdParameters</varname> of
0646 <function>function_calculate</function> and <function>function_derivative</function>. Keep in mind that the
0647 initial estimate is important in determining whether or not the fitting function converges to a solution.
0648 </para>
0649 </listitem>
0650 </varlistentry>
0651
0652 </variablelist>
0653
0654 </sect2>
0655
0656 <sect2 id="callingnonlinearfittingplugins">
0657 <title>Calling the Fitting Functions</title>
0658 <para>
0659 Once all the required functions have been implemented, the fitting function from the included header file
0660 can be called:
0661 <screen>
0662 kstfit_nonlinear( <parameter>inArrays</parameter>, <parameter>inArrayLens</parameter>,
0663 <parameter>inScalars</parameter>, <parameter>outArrays</parameter>,
0664 <parameter>outArrayLens</parameter>, <parameter>outScalars</parameter> );
0665 </screen>
0666 or
0667 <screen>
0668 kstfit_nonlinear_weighted( <parameter>inArrays</parameter>, <parameter>inArrayLens</parameter>,
0669 <parameter>inScalars</parameter>, <parameter>outArrays</parameter>,
0670 <parameter>outArrayLens</parameter>, <parameter>outScalars</parameter> );
0671 </screen>
0672 depending on whether you are implementing a non-weighted fit or a weighted fit.
0673 </para>
0674
0675 <para>
0676 The function will return <literal>0</literal> on success, or <literal>-1</literal> on
0677 error, so it is simplest to set the return value of the exported C function to be equal to the return
0678 value of the fitting function. To maintain simplicity, the code for the plugin can simply pass the
0679 arguments given to the exported C function to the fitting function. Note, however, that inArrays must
0680 be structured as follows:
0681 </para>
0682 <itemizedlist>
0683 <listitem>
0684 <para>
0685 <varname>inArrays[0]</varname> must contain the array of x coordinates of the data points
0686 </para>
0687 </listitem>
0688
0689 <listitem>
0690 <para>
0691 <varname>inArrays[1]</varname> must contain the array of y coordinates of the data points
0692 </para>
0693 </listitem>
0694
0695 <listitem>
0696 <para>
0697 <varname>inArrays[2]</varname> only exists if <function>kstfit_linear_weighted</function>
0698 is being called, and must contain the array of weights to use for the fit.
0699 </para>
0700 </listitem>
0701 </itemizedlist>
0702 <para>
0703 The easiest way to ensure that inArrays is structured correctly is to specify the correct
0704 order of input vectors in the XML file for the plugin.
0705 </para>
0706 <para>
0707 After <function>kstfit_linear_unweighted</function> or <function>kstfit_linear_weighted</function>
0708 is called, <varname>outArrays</varname> and <varname>outScalars</varname>
0709 will be set as follows:
0710 </para>
0711 <itemizedlist>
0712 <listitem>
0713 <para>
0714 <varname>outArrays[0]</varname> will contain the array of fitted y values.
0715 </para>
0716 </listitem>
0717
0718 <listitem>
0719 <para>
0720 <varname>outArrays[1]</varname> will contain the array of residuals.
0721 </para>
0722 </listitem>
0723
0724 <listitem>
0725 <para>
0726 <varname>outArrays[2]</varname> will contain the array of best-fit parameters that were estimated.
0727 </para>
0728 </listitem>
0729
0730 <listitem>
0731 <para>
0732 <varname>outArrays[3]</varname> will contain the covariance matrix, returned row after row in an array.
0733 </para>
0734 </listitem>
0735
0736 <listitem>
0737 <para>
0738 <varname>outScalars[0]</varname> will contain chi^2/nu, where chi^2 is the weighted sum of squares of the residuals,
0739 and nu is the degrees of freedom.
0740 </para>
0741 </listitem>
0742 </itemizedlist>
0743 <para>
0744 <varname>outArrayLens</varname> will be correctly set to indicate the length of each output array.
0745 </para>
0746
0747 <para>
0748 Ensure that the specified outputs in the XML file match those that the exported C function returns (which
0749 in most cases will simply be the outputs returned by the fitting function).
0750 </para>
0751
0752 </sect2>
0753
0754 <sect2 id="nonlinearfittingpluginexample">
0755 <title>Example</title>
0756 <para>The following is an example of a non-linear fit plugin that performs a fit to an exponential model.</para>
0757 <informalexample>
0758 <screen>
0759 /*
0760 * Exponential fit plugin for KST.
0761 * Copyright 2004, The University of British Columbia
0762 * Released under the terms of the GPL.
0763 */
0764
0765 #define NUM_PARAMS 3
0766 #define MAX_NUM_ITERATIONS 500
0767
0768 #include "../non_linear.h"
0769
0770 void function_initial_estimate( const double* pdX, const double* pdY,
0771 int iLength, double* pdParameterEstimates ) {
0772 KST_UNUSED( pdX )
0773 KST_UNUSED( pdY )
0774 KST_UNUSED( iLength )
0775
0776 pdParameterEstimates[0] = 1.0;
0777 pdParameterEstimates[1] = 0.0;
0778 pdParameterEstimates[2] = 0.0;
0779 }
0780
0781 double function_calculate( double dX, double* pdParameters ) {
0782 double dScale = pdParameters[0];
0783 double dLambda = pdParameters[1];
0784 double dOffset = pdParameters[2];
0785 double dY;
0786
0787 dY = ( dScale * exp( -dLambda * dX ) ) + dOffset;
0788
0789 return dY;
0790 }
0791
0792 void function_derivative( double dX, double* pdParameters, double* pdDerivatives ) {
0793 double dScale = pdParameters[0];
0794 double dLambda = pdParameters[1];
0795 double dExp;
0796 double ddScale;
0797 double ddLambda;
0798 double ddOffset;
0799
0800 dExp = exp( -dLambda * dX );
0801 ddScale = dExp;
0802 ddLambda = -dX * dScale * dExp;
0803 ddOffset = 1.0;
0804
0805 pdDerivatives[0] = ddScale;
0806 pdDerivatives[1] = ddLambda;
0807 pdDerivatives[2] = ddOffset;
0808 }
0809
0810 extern "C" int kstfit_exponential(const double *const inArrays[], const int inArrayLens[],
0811 const double inScalars[],
0812 double *outArrays[], int outArrayLens[],
0813 double outScalars[]);
0814
0815 int kstfit_exponential(const double *const inArrays[], const int inArrayLens[],
0816 const double inScalars[],
0817 double *outArrays[], int outArrayLens[],
0818 double outScalars[])
0819 {
0820 return kstfit_nonlinear( inArrays, inArrayLens,
0821 inScalars, outArrays,
0822 outArrayLens, outScalars );
0823 }
0824 </screen>
0825 </informalexample>
0826
0827 </sect2>
0828 </sect1>
0829
0830 <sect1 id="creatingpassfilterplugins">
0831 <title>Creating Pass Filter Plugins</title>
0832 <para>
0833 &kst; provides header files to simplify the implementation of pass filter plugins. The use of these
0834 header files is described below.
0835 </para>
0836 <sect2 id="creatingpassfilterpluginsheaderfiles">
0837 <title>Header Files</title>
0838 <para>
0839 The pass filter header file is located in <filename>kst/plugins/pass_filters</filename> of
0840 the &kst; source tarball. The file is named <filename>filters.h</filename>
0841 To use this file, include it in the source code for your plugin:
0842 <screen>
0843 #include <../filters.h>
0844 </screen>
0845 (by convention, we will place the source code for the plugin one directory below where the header files
0846 are).
0847 </para>
0848 </sect2>
0849
0850 <sect2 id="creatingpassfilterpluginsrequirements">
0851 <title>Required Functions</title>
0852 <para>
0853 The <filename>filters.h</filename> header file contains a single function that calculates the Fourier
0854 transform of a supplied function, applies the supplied filter to the Fourier transform, and then calculates
0855 the inverse Fourier transform of the filtered Fourier transform. To supply the filter, the following
0856 function needs to be implemented in the source code for your plugin:
0857 </para>
0858 <para><function><returnvalue>double</returnvalue> filter_calculate( double <parameter>dFreqValue</parameter>, const double <parameter>inScalars[]</parameter> )</function></para>
0859 <para>
0860 This function should calculate the filtered amplitude for the frequency <literal>dFreqValue</literal>.
0861 <literal>inScalars[]</literal> will contain the unaltered input scalars for the plugin, specified in the
0862 XML file. Most likely <literal>inScalars[]</literal> will contain cutoff frequencies or other
0863 properties of the filter. For example, to implement a Butterworth high-pass filter,
0864 <function>filter_calculate</function> could be implemented as follows:
0865 </para>
0866 <informalexample>
0867 <screen>
0868 double filter_calculate( double dFreqValue, const double inScalars[] ) {
0869 double dValue;
0870 if( dFreqValue > 0.0 ) {
0871 dValue = 1.0 / ( 1.0 +
0872 pow( inScalars[1] / dFreqValue, 2.0 * (double)inScalars[0] ) );
0873 } else {
0874 dValue = 0.0;
0875 }
0876 return dValue;
0877 }
0878 </screen>
0879 </informalexample>
0880 </sect2>
0881
0882 <sect2 id="creatingpassfilterpluginscallingfunction">
0883 <title>Calling the Filter Function</title>
0884 <para>
0885 Once the required <function>filter_calculate</function> has been implemented, the filter function
0886 from the header file can be called:
0887 </para>
0888 <literallayout><function>kst_pass_filter( <parameter>inArrays</parameter>,
0889 <parameter>inArrayLens</parameter>,
0890 <parameter>inScalars</parameter>,
0891 <parameter>outArrays</parameter>,
0892 <parameter>outArrayLens</parameter>,
0893 <parameter>outScalars</parameter> );</function></literallayout>
0894 <para>
0895 The arguments supplied to the exported C function can usually be passed to
0896 <function>kst_pass_filter</function> without modification. However, there are a few restrictions
0897 on the arguments:
0898 </para>
0899 <itemizedlist>
0900 <listitem>
0901 <para>
0902 <varname>inArrays[0]</varname> must contain the array of data to filter.
0903 </para>
0904 </listitem>
0905
0906 <listitem>
0907 <para>
0908 <varname>inScalars</varname> should contain the filter-specific parameters to be used by
0909 the <function>filter_calculate</function> function.
0910 </para>
0911 </listitem>
0912 </itemizedlist>
0913 <para>
0914 After the function call, <varname>outArrays[0]</varname> will contain the filtered array of data, and
0915 <varname>outArrayLens</varname> will be set appropriately. The <function>kst_pass_filter</function>
0916 function does not use <varname>outScalars</varname>.
0917 </para>
0918 </sect2>
0919
0920 <sect2 id="creatingpassfilterpluginsexample">
0921 <title>Example</title>
0922 <para>
0923 The following is an example of a pass filter plugin that implements the Butterworth high-pass filter.
0924 </para>
0925 <informalexample>
0926 <screen>/*
0927 * Butterworth low pass filter plugin for KST.
0928 * Copyright 2004, The University of British Columbia
0929 * Released under the terms of the GPL.
0930 */
0931
0932 #include <stdlib.h>
0933 #include <math.h>
0934 #include "../filters.h"
0935
0936 extern "C" int butterworth_highpass(const double *const inArrays[], const int inArrayLens[],
0937 const double inScalars[],
0938 double *outArrays[], int outArrayLens[],
0939 double outScalars[]);
0940
0941 int butterworth_highpass(const double *const inArrays[], const int inArrayLens[],
0942 const double inScalars[],
0943 double *outArrays[], int outArrayLens[],
0944 double outScalars[])
0945 {
0946 int iReturn;
0947
0948 iReturn = kst_pass_filter( inArrays,
0949 inArrayLens,
0950 inScalars,
0951 outArrays,
0952 outArrayLens,
0953 outScalars );
0954
0955 return iReturn;
0956 }
0957
0958 double filter_calculate( double dFreqValue, const double inScalars[] ) {
0959 double dValue;
0960
0961 if( dFreqValue > 0.0 ) {
0962 dValue = 1.0 / ( 1.0 + pow( inScalars[1] / dFreqValue, 2.0 * (double)inScalars[0] ) );
0963 } else {
0964 dValue = 0.0;
0965 }
0966
0967 return dValue;
0968 }</screen>
0969 </informalexample>
0970 </sect2>
0971
0972 </sect1>
0973 </appendix>
0974
0975
0976 <!-- Keep this comment at the end of the file
0977 Local variables:
0978 mode: xml
0979 sgml-omittag:nil
0980 sgml-shorttag:nil
0981 sgml-namecase-general:nil
0982 sgml-general-insert-case:lower
0983 sgml-minimize-attributes:nil
0984 sgml-always-quote-attributes:t
0985 sgml-indent-step:0
0986 sgml-indent-data:true
0987 sgml-parent-document:("index.docbook" "book" "appendix")
0988 sgml-exposed-tags:nil
0989 sgml-local-catalogs:nil
0990 sgml-local-ecat-files:nil
0991 End:
0992 -->