home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / MATH / DELP.ZIP / DELP.PAS
Encoding:
Pascal/Delphi Source File  |  1991-09-30  |  13.9 KB  |  334 lines

  1. {**************************************************************************}
  2. {*                                                                        *}
  3. {*                @@@@@     @@@@@@  @        @@@@@                        *}
  4. {*                @    @    @       @        @    @                       *}
  5. {*                @     @   @@@@    @        @    @                       *}
  6. {*                @    @    @       @        @@@@@                        *}
  7. {*                @@@@@     @@@@@@  @@@@@@   @                            *}
  8. {*                                                                        *}
  9. { Differential Equation Legendre Polynomial - method of determining the    }
  10. { best fit linear homogeneous differential equation with constant coeffi-  }
  11. { cients,  by solving explicitly for the coefficients of its characteristic}
  12. { equation. It is demonstrated here to find the (real) rate constants of a }
  13. { function that is a sum of exponentials.                                  }
  14. { MUCH ABRIDGED DEMONSTRATION VERSION-full version on request to DJM       }  
  15. {**************************************************************************}
  16.  
  17. { Devised by Dr J Martin, Dept Physics, Kings College, Strand,             }
  18. { LONDON WC2R 2LS,  and implemented by DJ Maconochie, Washington University}
  19. { BOX 8054, 660 S Euclid, St Louis MO 63110 (to whom correspondence may be }
  20. { initially addressed.                                                     }
  21. { E-mail DJM@morpheus.wustl.edu                                            }
  22. {                                                                          }
  23. { Feel free to use the procedures in this program, but please reference    }
  24. { Martin and Maconochie (1989) J Physiol 418:9P7 in any publications that  }
  25. { analysed data using this algorithm.                                      }
  26. {                                                                          }
  27. { The following are available on application to DJM  a full mathematical   }
  28. { treatment of method in the form of a paper,  a data analysis suite       }
  29. { writen in Borland PASCAL Turbo 5 that incorporates this method in an op- }
  30. { timised form,  (limited) free advice on how best to use this algorithm   }
  31. {to fit sums  of closely spaced exponentials to your data.                 }
  32. {**************************************************************************}
  33.  
  34. PROGRAM DELP;
  35.  
  36. {**} Uses crt, graph, mygraph;  { Routines specific to Turbo Pascal or DJM }
  37.  
  38. CONST maxData             = 2000;        { Maximum number of data points   }
  39.       maxSeriesSize       = 50;          { Maximum size of Legendre series }   
  40.       maxIntegrationLevel = 8;           { Max. number exponential cmpts.  }
  41.  
  42. TYPE  Tdata          = array[0..maxData] of real;
  43.       TdataPTR       = ^Tdata;
  44.       Tcomplex       = RECORD Re : real; Im : real; END;
  45.  
  46.  
  47. VAR   LegendreSeries   : array[0..maxSeriesSize] of real; 
  48.       SeriesSize       : integer;
  49.       IntegratedSeries : array[0..maxIntegrationLevel] of
  50.                          array[0..maxSeriesSize] of real;
  51.       IntegrationLevel : integer;
  52.  
  53.       CalcMatrix      : array[0..maxIntegrationLevel] of
  54.                          array[0..maxIntegrationLevel] of real;
  55.       Exponents        : array[1..maxIntegrationLevel] of Tcomplex;
  56.  
  57.       dataPTR          : TdataPTR;  { Points to memory containing data     }
  58.       solutionPTR      : TdataPTR;  { Memory used to store polynomial fit  }
  59.       StartFit         : integer;   { Start using data from here           }
  60.       EndFit           : integer;
  61.       FitPoints        : integer;
  62.  
  63.       i, j             : integer;
  64.  
  65. PROCEDURE even_number_points; { Data "x" range must be symmetrical about 0 }
  66. begin
  67.   FitPoints := EndFit-StartFit;
  68.   if (FitPoints mod 2 = 1) then
  69.     EndFit := EndFit-1;
  70.   FitPoints := EndFit-StartFit;
  71. end;
  72.  
  73. PROCEDURE dummy_data(L1, L2, G : real); { Create some artificial data: two }
  74. var m : integer;                     { exponential components plus noise   }
  75. begin
  76.                    { First the noise, partly correlated from point to point}
  77.   dataPTR^[startFit] := 0;
  78.   for m := StartFit+1 to EndFit do
  79.              dataPTR^[m] :=
  80.                0.1*dataPTR^[m-1] + G*exp(random*2)*cos(random*PI);
  81.                                         { Now add the exponential function }
  82.   for m := StartFit to EndFit do
  83.     dataPTR^[m] := dataPTR^[m] + 5000*exp(-L1*2*(m/FitPoints))
  84.            - 5000*exp(-L2*2*(m/FitPoints));
  85. end; { of procedure dummy_data }
  86.  
  87. PROCEDURE Get_Legendre_series{(SeriesSize : integer)}; { Fits the first    }
  88. { SeriesSize members of the Legendre series of polynomial functions to the }
  89. { data.  Considerable economy of computational time may be achieved by     }
  90. { declaring a number of local variables, and doing many of the calculations}
  91. { only once.                                                               }
  92. var r,m : integer;
  93.     x,s : real;
  94.     p : array[0..maxSeriesSize] of real;
  95.  
  96. begin
  97.   for r := 0 to maxSeriesSize do
  98.     LegendreSeries[r] := 0;
  99.   s := 8/3;
  100.   for m := startFit to endFit do begin    { Integrate over all data points }
  101.     x := -1+2*(m-startFit)/(FitPoints);   { Normalise "x" to -1 to +1      }
  102.     s := 4-s;                             { Toggles between 8/3 and 12/3   }
  103.     p[0] := s/FitPoints;                  { First two Legendre polynomials }
  104.     p[1] := x*p[0];                       { must be given explicitly       }
  105.  
  106.     if (m=startFit) or (m=endFit) then begin   { These two points are      }
  107.       p[0] := 2/(3*FitPoints);   { special: Simpson's rule for integration }
  108.       p[1] := x*p[0];
  109.     end;
  110.  
  111.     for r := 2 to SeriesSize  do         { Find the other polynomials from }
  112.       p[r] := ((2*r-1)*x*p[r-1]-(r-1)*p[r-2])/r; { this recurrence relation}
  113.  
  114. { Standard formula for finding the expansion of F as an infinite orthogonal}
  115. { series.  (This is similar to taking a Fourier transform)                 }
  116.     for r := 0 to SeriesSize do
  117.       LegendreSeries[r] := LegendreSeries[r]+         {      ··⌠+1····     }
  118.                            (r+0.5)*p[r]*(dataPTR^[m]) {  (r+½).│···F.Pr.dx·}
  119.   end;                                                {    ····⌡-1····     }
  120. END; { of procedure Get_Legendre_Series }
  121.  
  122. PROCEDURE Legendre_fit{(SeriesSize : integer)};
  123. { This procedure creates  a curve corresponding to the truncated Legendre  }
  124. { series, to overlay the data. It is stored in the memory at solutionPTR.  }
  125.  
  126. var r,m : integer;
  127.     f,x,s : real;
  128.     p : array[0..maxSeriesSize] of real;
  129.  
  130. begin
  131.  
  132.   p[0] := 1;                             { The first Legendre polynomial   }
  133.   for m := startFit to endFit do begin
  134.  
  135.     x := -1+2*(m-startFit)/FitPoints;    { Normalise "x" range to -1 to +1 }
  136.     p[1] := x;                           { The second Legendre polynomial  }
  137.  
  138.     for r := 2 to SeriesSize do          { Find the other polynomials from }
  139.       p[r] := ((2*r-1)*x*p[r-1]-(r-1)*p[r-2])/r; { recurrence relation     }
  140.  
  141.     f := 0;
  142.     for r := 0 to SeriesSize do     { Add up the contribution, at each "x" }
  143.       f := f+LegendreSeries[r]*p[r];{ of each  Legendre coefficent p(r)    }
  144.  
  145.     solutionPTR^[m] := f;           { Write to memory location solutionPTR }
  146.   end;
  147. END;{ of procedure Legendre_fit }
  148.  
  149. PROCEDURE Integrate_Legendre_Series; { The integral of a Legendre series   }
  150. { another Legendre series. The coefficients of the integrated series are   }
  151. { related by a recurrence relation to the un-integrated series.            }
  152. var l,r : integer;
  153.  
  154. begin
  155.   for r := 0 to maxSeriesSize do            { Zero the matrix containing   }
  156.     for l := 0 to maxIntegrationLevel do    { the integrated series        }
  157.       IntegratedSeries[l,r] := 0;
  158.  
  159.   for r := 0 to SeriesSize do             { enter the un-integrated series }
  160.     IntegratedSeries[0,r] := LegendreSeries[r];
  161.  
  162.   for l := 1 to IntegrationLevel do   { integrate "IntegrationLevel" times }
  163.     for r := l to SeriesSize - l do
  164.       IntegratedSeries[l,r] := IntegratedSeries[l-1,r-1]/(2*r-1)
  165.                              - IntegratedSeries[l-1,r+1]/(2*r+3);
  166.  
  167. END;{ of procedure Integrate_Legendre_Series }
  168.  
  169. PROCEDURE accumulate_matrix(k : integer);
  170. { This procedure builds up the matrix representing "IntegrationLevel"      }
  171. { simultaneous equations, whose solution is the set of coefficients of the }
  172. { auxiliary equation of the Integral/Differential equation, that is the    }
  173. { best least squares fit to the data.                                      }
  174.  
  175. var i,j : integer;
  176.  
  177. begin
  178.  
  179.   for i := 0 to IntegrationLevel do
  180.     for j := 0 to IntegrationLevel do
  181.       CalcMatrix[i,j] := CalcMatrix[i,j]
  182.             +IntegratedSeries[i,k]*IntegratedSeries[j,k]/(k+0.5);
  183.  
  184. END;{ of procedure accumulate_matrix }
  185.  
  186. PROCEDURE Solve(n : integer);
  187. { This procedure solve a set of "n" simultaneous equations decribed by the }
  188. { matrix "CalcMatrix"                                                      }
  189.  
  190. var i,j,k        : integer;
  191.     temp         : real;
  192.  
  193. begin
  194.     j := n;
  195.     for j := n downto 1 do begin
  196.       i := j-1;
  197.       for i := j-1 downto 0 do begin
  198.         temp := CalcMatrix[i,j]/CalcMatrix[j,j];
  199.         if j=1 then
  200.           CalcMatrix[i,0] := CalcMatrix[i,0]-CalcMatrix[j,0]*temp
  201.         else
  202.           for k := 0 to j-1 do
  203.             CalcMatrix[i,k] := CalcMatrix[i,k]-CalcMatrix[j,k]*temp;
  204.       end;
  205.     end;
  206.  
  207.     for i := 1 to n do begin
  208.       for j := 0 to i-1 do
  209.         CalcMatrix[i,j] := CalcMatrix[i,j]/CalcMatrix[i,i];
  210.     end;
  211.  
  212.     for j := 1 to n-1 do begin
  213.       for i := j+1 to n do
  214.         CalcMatrix[i,0] := CalcMatrix[i,0]-CalcMatrix[j,0]*CalcMatrix[i,j];
  215.     end;
  216. { The solutions are: 1, and the coefficients "CalcMatrix[i,0]"            }
  217. END;{ of procedure solve }
  218.  
  219. PROCEDURE Find_Integral_Equation;
  220.  
  221. var l, i, j : integer;
  222.  
  223. begin
  224.   for i := 0 to maxIntegrationLevel do
  225.     for j := 0 to maxIntegrationLevel do begin
  226.       CalcMatrix[i,j] := 0;
  227.     end;
  228.  
  229.   for l := IntegrationLevel +1 to SeriesSize - IntegrationLevel do
  230.     accumulate_matrix(l);        { Get together the simultaneous equations }
  231.   solve(IntegrationLevel);       { Solve them.                             }
  232. END; { of procedure Find_Integral_Equation }
  233.  
  234. PROCEDURE find_roots; { This routine is only for demonstration of real     }
  235. var a, b, ac : real;  { single and double exponential fits. For anything   }
  236.                       { else, you will need a routine for finding the      }
  237.                       { roots of a general polynomial.                     }
  238. begin
  239.   if IntegrationLevel = 1 then begin
  240.     Exponents[1].Re := CalcMatrix[1,0];
  241.     Exponents[1].Im := 0;
  242.     writeln('Single root only:',Exponents[1].Re:6:2);
  243.   end;
  244.   if IntegrationLevel = 2 then begin
  245.     b  := CalcMatrix[1,0];
  246.     a  := -1;
  247.     ac := a*CalcMatrix[2,0];
  248.     Exponents[1].Re := -0.5*(-b+sqrt(sqr(b)-4*ac));
  249.     Exponents[2].Re := -0.5*(-b-sqrt(sqr(b)-4*ac));
  250.     Exponents[1].Im := 0;
  251.     Exponents[2].Im := 0;
  252.     writeln('Real roots only, L1:',Exponents[1].Re:6:2,
  253.                            '  L2:',Exponents[2].Re:6:2);
  254.   end;
  255.   if
  256.   IntegrationLevel > 2 then begin
  257.     writeln('You need a routine for finding the "n" roots of an equation');
  258.     writeln('this one substitutes a Borland Turbo Pascal routine');
  259.   end;
  260. END; { of procedure find_roots. Don't forget to replace this with a more   }
  261. { general numerical routine.                                               }
  262.  
  263. BEGIN; { main program body }
  264.   randomize;
  265.   New(dataPTR);           { Get memory allocations at "dataPTR" and        }
  266.                           { solutionPTR (to hold data and solution).       }
  267.   New(solutionPTR);
  268.  
  269.   StartFit := 1; EndFit := 1000;  { These parameters can be varied.        }
  270.   SeriesSize := 6;                { SeriesSize rarely needs to be more than}
  271.   IntegrationLevel := 2;          { ten, and for well behaved data can be  }
  272.                                   { the equal to 2*(n+1) where n is the    }
  273.                                   { number of exponentials being fitted -  }
  274.                                   { defined here as IntegrationLevel.      }
  275.   even_number_points;
  276.   dummy_data(3,2,10);             { Creates a double exponential function  }
  277.                                   { with constants -3 and -2, and arbitr-  }
  278.                                   { ary noise factor 1.                    }
  279.   Get_Legendre_Series;            { Get finite Legendre representation of  }
  280.                                   { data.                                  }
  281.  
  282.   clrscr;
  283.   for i := 0 to SeriesSize do
  284.      writeln('LegendreSeries[',i,']:',LegendreSeries[i]);
  285.   readln;
  286.  
  287.   Legendre_Fit;
  288.   Integrate_Legendre_Series;
  289.  
  290.   clrscr;
  291.   writeln('Integrated Legendre Series');
  292.   for i := 0 to SeriesSize do begin
  293.     for j := 0 to IntegrationLevel do begin
  294.       GoToXY(1+j*12,4+i);
  295.       write(IntegratedSeries[j,i]:6:2);
  296.     end;
  297.   end;
  298.   readln;
  299.  
  300.   startgraph(true,0,0,0,0); { Substitute appropriate graphics              }
  301.                         {initialisation, and graph plotting routines here. }
  302.   For i := Startfit to EndFit do
  303.        PutPixel(i,round(DataPTR^[i]/10)+screen_height div 2,15);
  304.   For i := Startfit to EndFit do
  305.        LineTo(i,round(SolutionPTR^[i]/10)+screen_height div 2);
  306.   readln;
  307.   restoreCRTmode;
  308.  
  309.   Find_Integral_Equation;
  310.  
  311.   writeln('This is the matrix used for finding the coefficients of the integral');
  312.   writeln('equation: the coefficients are -1 and the first row of the matrix.');
  313.   writeln;
  314.   writeln('These are also necessarily the coefficients of the characteristic');
  315.   writeln('equation of the linear homogeneous differential equation with constant');
  316.   writeln('coefficients whose time dependent solution is the sum of exponentials.');
  317.   for i := 0 to IntegrationLevel do begin
  318.     for j := 0 to IntegrationLevel do begin
  319.       GoToXY(1+j*24,8+i);
  320.       write(CalcMatrix[j,i]:6:4);
  321.     end;
  322.   end;
  323.   readln;
  324.  
  325.   find_roots;
  326.  
  327.   dispose(dataPTR);
  328.   dispose(solutionPTR);
  329.   solutionPTR := NIL;
  330.   dataPTR     := NIL;
  331.   readln;
  332. end.
  333. 
  334.