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