home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / image144.sit / LeastSquares.p < prev    next >
Encoding:
Text File  |  1992-02-28  |  6.5 KB  |  295 lines

  1. unit LeastSquares;
  2. {This unit is based on the Simplex curve fitting routine described in the article " Fitting Curves to Data "}
  3. {in the May 1984 issue of Byte magazine, pages 340-362.}
  4.  
  5. interface
  6.  
  7.     uses
  8.         QuickDraw, Palettes, PrintTraps, globals, Utilities, graphics;
  9.  
  10.  
  11.     const
  12.         nvpp = 2;
  13.         maxn = 6;
  14.         maxnp = 20;
  15.         alpha = 1.0;
  16.         beta = 0.5;
  17.         gamma = 2.0;
  18.         lw = 5;
  19.         root2 = 1.414214;
  20.         MaxError = 1e-7;
  21.  
  22.  
  23.     type
  24.         ColumnVector = array[1..maxnp] of extended;
  25.  
  26.         vector = array[1..maxn] of extended;
  27.         datarow = array[1..nvpp] of extended;
  28.         index = 0..255;
  29.  
  30.  
  31.     var
  32.         m, n: integer;
  33.         done: boolean;
  34.         maxx, maxy: extended;
  35.         i, j: index;
  36.         h, l: array[1..maxn] of index;
  37.         np, npmax, niter, maxiter: integer;
  38.         next, center, smean, error, maxerr, p, q, step: vector;
  39.         simp: array[1..maxn] of vector;
  40.         data: array[1..maxnp] of datarow;
  41.         filename, newname: string;
  42.         datafile: text;
  43.         yoffset: integer;
  44.  
  45.  
  46.     procedure DoSimplexFit (nStandards, nCoefficients: integer; xdata, ydata: ColumnVector; var Coefficients: CoefficientArray; var residuals: ColumnVector);
  47.  
  48.  
  49. implementation
  50.  
  51.  
  52.     function f (p: vector; d: datarow): extended;
  53.         var
  54.             x, y, ex: extended;
  55.     begin
  56.         x := d[1];
  57.         case info^.fit of
  58.             StraightLine: 
  59.                 f := p[1] + p[2] * x;
  60.             Poly2: 
  61.                 f := p[1] + p[2] * x + p[3] * x * x;
  62.             Poly3: 
  63.                 f := p[1] + p[2] * x + p[3] * x * x + p[4] * x * x * x;
  64.             Poly4: 
  65.                 f := p[1] + p[2] * x + p[3] * x * x + p[4] * x * x * x + p[5] * x * x * x * x;
  66.             ExpoFit: 
  67.                 f := p[1] * exp(p[2] * x);
  68.             PowerFit: 
  69.                 if x = 0.0 then
  70.                     f := 0.0
  71.                 else
  72.                     f := p[1] * exp(p[2] * ln(x)); {y=ax^b}
  73.             LogFit:  begin
  74.                     if x = 0.0 then
  75.                         x := 0.5;
  76.                     f := p[1] * ln(p[2] * x)
  77.                 end;
  78.             RodbardFit:  begin
  79.                     if x = 0.0 then
  80.                         ex := 0.0
  81.                     else
  82.                         ex := exp(ln(x / p[3]) * p[2]);
  83.                     y := p[1] - p[4];
  84.                     y := y / (1 + ex);
  85.                     f := y + p[4];
  86.                 end; {Rodbard fit}
  87.         end; {case}
  88.     end;
  89.  
  90.  
  91.     procedure order;
  92.         var
  93.             i, j: index;
  94.     begin
  95.         for j := 1 to n do begin
  96.                 for i := 1 to n do begin
  97.                         if simp[i, j] < simp[l[j], j] then
  98.                             l[j] := i;
  99.                         if simp[i, j] > simp[h[j], j] then
  100.                             h[j] := i
  101.                     end
  102.             end
  103.     end;
  104.  
  105.  
  106.     procedure sum_of_residuals (var x: vector);
  107.  
  108.         var
  109.             i: index;
  110.     begin
  111.         x[n] := 0.0;
  112.         for i := 1 to np do
  113.             x[n] := x[n] + sqr(f(x, data[i]) - data[i, 2])
  114.     end;
  115.  
  116.  
  117.     procedure Initialize;
  118.         var
  119.             i, j: index;
  120.             firstx, firsty, lastx, lasty, xmean, ymean, slope, yintercept: extended;
  121.     begin
  122.         firstx := data[1, 1];
  123.         firsty := data[1, 2];
  124.         lastx := data[np, 1];
  125.         lasty := data[np, 2];
  126.         xmean := (firstx + lastx) / 2.0;
  127.         ymean := (firsty + lasty) / 2.0;
  128.         if (lastx - firstx) <> 0.0 then
  129.             slope := (lasty - firsty) / (lastx - firstx)
  130.         else
  131.             slope := 1.0;
  132.         yintercept := firsty - slope * firstx;
  133.         case info^.fit of
  134.             StraightLine:  begin
  135.                     simp[1, 1] := yintercept;
  136.                     simp[1, 2] := slope;
  137.                 end;
  138.             Poly2:  begin
  139.                     simp[1, 1] := yintercept;
  140.                     simp[1, 2] := slope;
  141.                     simp[1, 3] := 0.0;
  142.                 end;
  143.             Poly3:  begin
  144.                     simp[1, 1] := yintercept;
  145.                     simp[1, 2] := slope;
  146.                     simp[1, 3] := 0.0;
  147.                     simp[1, 4] := 0.0;
  148.                 end;
  149.             Poly4:  begin
  150.                     simp[1, 1] := yintercept;
  151.                     simp[1, 2] := slope;
  152.                     simp[1, 3] := 0.0;
  153.                     simp[1, 4] := 0.0;
  154.                     simp[1, 5] := 0.0;
  155.                 end;
  156.             ExpoFit:  begin
  157.                     simp[1, 1] := 0.1;
  158.                     simp[1, 2] := 0.01;
  159.                 end;
  160.             PowerFit:  begin
  161.                     simp[1, 1] := 0.0;
  162.                     simp[1, 2] := 1.0;
  163.                 end;
  164.             LogFit:  begin
  165.                     simp[1, 1] := 0.5;
  166.                     simp[1, 2] := 0.05;
  167.                 end;
  168.             RodbardFit:  begin
  169.                     simp[1, 1] := firsty;
  170.                     simp[1, 2] := 1.0;
  171.                     simp[1, 3] := xmean;
  172.                     simp[1, 4] := lasty;
  173.                 end;
  174.         end;
  175.         maxiter := 100 * m * m;
  176.         n := m + 1;
  177.         for i := 1 to m do begin
  178.                 step[i] := simp[1, i] / 2.0;
  179.                 if step[i] = 0.0 then
  180.                     step[i] := 0.01;
  181.             end;
  182.         for i := 1 to n do
  183.             maxerr[i] := MaxError;
  184.         sum_of_residuals(simp[1]);
  185.         for i := 1 to m do begin
  186.                 p[i] := step[i] * (sqrt(n) + m - 1) / (m * root2);
  187.                 q[i] := step[i] * (sqrt(n) - 1) / (m * root2)
  188.             end;
  189.         for i := 2 to n do begin
  190.                 for j := 1 to m do
  191.                     simp[i, j] := simp[i - 1, j] + q[j];
  192.                 simp[i, i - 1] := simp[i, i - 1] + p[i - 1];
  193.                 sum_of_residuals(simp[i])
  194.             end;
  195.         for i := 1 to n do begin
  196.                 l[i] := 1;
  197.                 h[i] := 1
  198.             end;
  199.         order;
  200.         maxx := 255;
  201.     end;
  202.  
  203.  
  204.     procedure new_vertex;
  205.         var
  206.             i: index;
  207.     begin
  208.         for i := 1 to n do
  209.             simp[h[n], i] := next[i]
  210.     end;
  211.  
  212.  
  213.     procedure DoSimplexFit (nStandards, nCoefficients: integer; xdata, ydata: ColumnVector; var Coefficients: CoefficientArray; var residuals: ColumnVector);
  214.         var
  215.             i, j: integer;
  216.             d: datarow;
  217.     begin
  218.         np := nStandards;
  219.         m := nCoefficients;
  220.         for i := 1 to np do begin
  221.                 data[i, 1] := xdata[i];
  222.                 data[i, 2] := ydata[i];
  223.             end;
  224.         Initialize;
  225.         niter := 0;
  226.         repeat
  227.             done := true;
  228.             niter := succ(niter);
  229.             for i := 1 to n do
  230.                 center[i] := 0.0;
  231.             for i := 1 to n do
  232.                 if i <> h[n] then
  233.                     for j := 1 to m do
  234.                         center[j] := center[j] + simp[i, j];
  235.             for i := 1 to n do begin
  236.                     center[i] := center[i] / m;
  237.                     next[i] := (1.0 + alpha) * center[i] - alpha * simp[h[n], i]
  238.                 end;
  239.             sum_of_residuals(next);
  240.             if next[n] <= simp[l[n], n] then begin
  241.                     new_vertex;
  242.                     for i := 1 to m do
  243.                         next[i] := gamma * simp[h[n], i] + (1.0 - gamma) * center[i];
  244.                     sum_of_residuals(next);
  245.                     if next[n] <= simp[l[n], n] then
  246.                         new_vertex
  247.                 end
  248.             else begin
  249.                     if next[n] <= simp[h[n], n] then
  250.                         new_vertex
  251.                     else begin
  252.                             for i := 1 to m do
  253.                                 next[i] := beta * simp[h[n], i] + (1.0 - beta) * center[i];
  254.                             sum_of_residuals(next);
  255.                             if (next[n] <= simp[h[n], n]) then
  256.                                 new_vertex
  257.                             else begin
  258.                                     for i := 1 to n do begin
  259.                                             for j := 1 to m do
  260.                                                 simp[i, j] := (simp[i, j] + simp[l[n], j]) * beta;
  261.                                             sum_of_residuals(simp[i])
  262.                                         end
  263.                                 end
  264.                         end
  265.                 end;
  266.             order;
  267.             for j := 1 to n do begin
  268.                     if (simp[h[j], j] - simp[l[j], j]) = 0 then
  269.                         error[j] := 0
  270.                     else if simp[h[j], j] <> 0 then
  271.                         error[j] := (simp[h[j], j] - simp[l[j], j]) / simp[h[j], j]
  272.                     else
  273.                         error[j] := (simp[h[j], j] - simp[l[j], j]) / simp[l[j], j];
  274.                     if done then
  275.                         if abs(error[j]) > maxerr[j] then
  276.                             done := false
  277.                 end;
  278.         until (done or (niter = maxiter));
  279.         ShowMessage(concat('interations=', long2str(niter), cr, 'max interations=', long2str(maxiter)));
  280.         for i := 1 to n do begin
  281.                 smean[i] := 0;
  282.                 for j := 1 to n do
  283.                     smean[i] := smean[i] + simp[j, i];
  284.                 smean[i] := smean[i] / n;
  285.             end;
  286.         for i := 1 to m do
  287.             Coefficients[i] := smean[i];
  288.         for i := 1 to nstandards do begin
  289.                 d[1] := xdata[i];
  290.                 Residuals[i] := ydata[i] - f(smean, d);
  291.             end;
  292.     end;
  293.  
  294.  
  295. end.