unit Unit2; { function y = ae^(bx)+c calculate a,b,c from [x1,y1] , [x2,y2] , ...., [xn,yn] } interface uses sysutils; type Tpnt = record x,y : double; end; Tpoints = array[1..10] of Tpnt; procedure makeExpFunction; procedure GetParams(var pa,pb,pc : double); function getXY(nr : byte; var pdx,pdy, pcx, pdq : double) : boolean; implementation uses unit1,unit3,unit4; const FlString : string = '####0.0#####'; scaleDy = 1; var Epoints : TPoints; a,b,c : double; //y = a*e(bx)+c dx,dy : array[1..10] of double; cx : array[1..10] of double; //center between x values dq : array[1..10] of double; //differential quotient maxpnt : byte; //number of points //testmode helpers procedure GetParams(var pa,pb,pc : double); begin pa := a; pb := b; pc := c; end; function getXY(nr : byte; var pdx,pdy, pcx, pdq : double) : boolean; begin result := nr < maxpnt; if result then begin pdx := dx[nr]; pdy := dy[nr]; pcx := cx[nr]; pdq := dq[nr]; end; end; //---- procedure makeXYarrays; var i : byte; begin for i := 1 to maxpnt-1 do begin dx[i] := epoints[i+1].x - epoints[i].x; dy[i] := epoints[i+1].y - epoints[i].y; cx[i] := (epoints[i].x + epoints[i+1].x)/2; dq[i] := dy[i]/dx[i]; end; end; function Deviation(cc : double; var af : boolean) : double; //calculate variation in growth factors after c asymptote correction //called for fine tuning c in ae^(bx)+c formula //cc: y value (asymptote); af : abort flag...abort if intersection var i : byte; avG,ee : double; growthfactor : array[1..40] of double; begin result := 0; avG := 0; for i := 1 to maxpnt-1 do begin ee := (Epoints[i].y-cc);//denominator if ee <> 0 then ee := (Epoints[i+1].y-cc)/ee; if ee <= 0 then //test for intersection of asymptote and function begin af := true;//abort flag exit; end; ee := ln(ee); avG := avG + ee; growthfactor[i] := exp(ee/dx[i]);//save end; af := false; avG := exp(avG /(Epoints[maxpnt].x-Epoints[1].x));//exp added ee := 0; for i := 1 to maxpnt-1 do ee := ee + abs(avG-growthFactor[i]); result := ee; end; procedure morepointsExp(var code : byte); //called for >= 3 points var Sum,deltaC,Bvar1,Bvar2 : double; i : byte; w : word; abort : boolean; begin //approximate value of b ....growthfactor e^b try sum := 0; for i := 1 to maxpnt-2 do Sum := Sum + ln(dq[i+1]/dq[i])/(cx[i+1]-cx[i]); b := Sum / (maxpnt - 2); if testmode then testreport(2); //approximate value of a Sum := 0; for i := 1 to maxpnt-1 do Sum := Sum + dy[i]/(exp(b*epoints[i+1].x) - exp(b*epoints[i].x)); a := Sum / (maxpnt - 1); if testmode then testreport(3); //approximate value of c sum := 0; for i := 1 to maxpnt do sum := sum + epoints[i].y-a*exp(b*epoints[i].x); c := sum / maxpnt; if testmode then testreport(4); except code := 1; exit; end; if a > 0 then deltaC := -scaledY //move away from asymptote first else deltaC := scaledY; if testmode then begin testreport(5); testreportDC(deltaC); end; repeat Bvar1 := Deviation(c,abort); if abort then c := c + deltaC; if testmode then testreportDCA(Bvar1,c,deltaC,abort); until not abort; w := 0; deltaC := -deltaC;//towards asymptote first if testmode then testreport(6); repeat inc(w); Bvar2 := Deviation(c + deltaC,abort); if abort then deltaC := deltaC/2 //half distance in same direction else if Bvar2 < Bvar1 then begin Bvar1 := Bvar2; //if better result c := c + deltaC; end else deltaC := -deltaC/2; if testmode then testreportDCA(Bvar1,c,deltaC,abort); until (abs(deltaC) <= 1e-8) or (w > 100); if abort then begin code := 1; exit; end; if w > 100 then begin code := 2; exit; end; if testmode then testreport(7); //call least square procedure to make best a,b for i := 1 to maxpnt do epoints[i].y := ln(abs(epoints[i].y-c)); buildexp12(epoints,maxpnt); //call least square unit if a < 0 then a := -exp(epoints[1].y) else a := exp(epoints[1].y); b := epoints[2].y; if testmode then testreport(8); end; //--- main call --- procedure makeExpFunction; var i,code : byte; //0:OK 1,2: error s : string; begin maxpnt := pcount; for i := 1 to maxpnt do //get points begin Epoints[i].x := points[i].x; Epoints[i].y := points[i].y; end; // makeXYarrays; if testmode then testreport(1); code := 0; morePointsExp(code); case code of 0 : begin aa := a; bb := exp(b); cc := c; //ae^(bx)+c ....> ab^x + c setparamsOK(true); s := 'a,b,c calculated'; end; 1 : begin setparamsOK(false); s := 'no exponential function'; end; 2 : begin setparamsOK(false); s := 'points out of range'; end; else s := ''; end; form1.msgtext.Caption := s; end; end.