home *** CD-ROM | disk | FTP | other *** search
- (* ------------------------------------------------------ *)
- (* LINFIT.PAS *)
- (* Robust Fitting in Turbo Pascal 4/5 *)
- (* (c) TOOLBOX & Peter Kurzweil *)
- (* ------------------------------------------------------ *)
- PROGRAM RobustFitting;
- USES Crt;
- CONST
- npt = 200; { Zahl der Meßpunkte }
- spread = 1.0; { Streuung }
- TYPE
- {$IFDEF CPU87}
- REAL = Extended;
- {$ENDIF}
- Vector = ARRAY[1..npt] OF REAL;
- VAR
- a, b, da, db, r, xm, ym, sx,
- sy, xo, dy, phi, xmin, xmax : REAL;
- x, y : Vector;
- i, k, i1, i2 : WORD;
-
- FUNCTION Log10(x : REAL) : REAL; { dek. Logarithmus }
- BEGIN
- IF x <> 0 THEN
- Log10 := Ln(Abs(x)) / Ln(10.0)
- ELSE
- Log10 := 0;
- END;
-
- FUNCTION Exp10(x : REAL) : REAL; { 10 hoch x }
- BEGIN
- Exp10 := Exp(x * Ln(10));
- END;
-
- PROCEDURE ProduceOutliers; { Ausreißer aufprägen }
- BEGIN
- IF spread <> 0 THEN BEGIN
- FOR k := 1 TO (npt DIV 10) DO BEGIN
- i := Random(npt); { Punkt auswählen... }
- x[i] := ((i - 1) * (xmax - xmin) / npt + xmin) *
- (Random - 0.5);
- { ...und verunstalten }
- y[i] := Sin(x[i]) * (xmax - xmin) * b + a;
- END;
- END;
- END;
-
- FUNCTION StdAbw(z : Vector; k1, k2 : WORD) : REAL;
- { Standardabweichung }
- VAR
- s, zs, zz : REAL;
- i, n : WORD;
- BEGIN
- IF k1 > k2 THEN BEGIN
- i := k1; k1 := k2; k2 := i;
- END;
- n := k2 - k1 + 1;
- zz := 0;
- zs := 0;
- FOR i := k1 TO k2 DO BEGIN
- zs := zs + z[i];
- zz := zz + Sqr(z[i]);
- END;
- s := Sqrt((zz - zs * zs/n) / (n - 1));
- StdAbw := s;
- END;
-
- FUNCTION Mittel(z : Vector; k1, k2 : WORD) : REAL;
- { Mittelwert }
- VAR
- i, n : WORD;
- s : REAL;
- BEGIN
- IF k1 > k2 THEN BEGIN
- i := k1; k1 := k2; k2 := i;
- END;
- n := k2 - k1 + 1;
- s := 0;
- FOR i := k1 TO k2 DO s := s + z[i];
- Mittel := s/n;
- END;
-
- PROCEDURE LinFit(x, y : Vector; k1, k2 : WORD;
- VAR a, b, r, da, db,
- dy, xo, xm, ym, sx, sy : REAL);
- VAR
- xs, ys, xx, yy, xy,
- r1, r2, a1, a2, b1, b2 : REAL;
- i, n : WORD;
- BEGIN
- IF k1 > k2 THEN BEGIN
- n := k1; k1 := k2; k2 := n;
- END;
- n := k2 - k1 + 1; { Zahl der Punkte }
- da := 0; db := 0; r := 1;
- sx := 0; sy := 0;
- CASE n OF
- 0 : Exit; { sinnlos }
- 1 : BEGIN { Gerade durch Ursprung }
- a := y[k1]; b := y[k1];
- xm := x[k1]; ym := y[k1];
- IF x[k1] <> 0 THEN b := y[k1] / x[k1];
- END;
- 2 : BEGIN { Gerade durch zwei Punkte }
- b1 := y[k2] - y[k1];
- b2 := x[k2] - x[k1];
- IF b2 = 0 THEN BEGIN
- b := 99999;
- a := 0; xo := x[k1]; { Vertikale }
- END ELSE BEGIN
- b := b1 / b2;
- xm := (x[k1] + x[k2]) / 2;
- ym := (y[k1] + y[k2]) / 2;
- a := ym - b * xm;
- IF b <> 0 THEN xo := -a / b ELSE xo := -0;
- sx := StdAbw(x, k1, k2);
- sy := StdAbw(y, k1, k2);
- END;
- END;
- ELSE BEGIN { Ausgleichsgerade }
- xs := 0; ys := 0;
- xx := 0; yy := 0; xy := 0;
- FOR i := k1 TO k2 DO BEGIN { Gauß-Summen }
- xs := xs + x[i]; ys := ys + y[i];
- xx := xx + x[i]*x[i]; yy := yy + y[i]*y[i];
- xy := xy + x[i]*y[i];
- END;
- a1 := ys*xx - xy*xs; a2 := n*xx - xs*xs;
- b1 := n*xy - ys*xs;
- IF a2 = 0 THEN BEGIN
- a := a1; b := 99999; r := 1;
- xo := x[k1]; { Vertikale }
- END ELSE BEGIN
- a := a1/a2;
- b := b1/a2;
- r1 := xy - xs * ys / n;
- r2 := Abs((xx - xs * xs / n)*(yy - ys * ys / n));
- IF r2 <> 0 THEN r := r1 / Sqrt(r2) ELSE r := 1;
- IF b <> 0 THEN xo := -a / b ELSE xo := 0;
- END;
- dy := Sqrt(Abs((yy - a*ys - b*xy)/(n-2)));
- { Fehler }
- da := dy * Sqrt(Abs(xx/(n*xx - xs*xs)));
- db := dy * Sqrt(Abs(n/(n*xx - xs*xs)));
- xm := Mittel(x, k1, k2);
- ym := Mittel(y, k1, k2);
- { Statistisches }
- sx := StdAbw(x, k1, k2);
- sy := StdAbw(y, k1, k2);
- END;
- END;
- END;
-
- PROCEDURE HeapSort(VAR a : Vector; n : WORD);
- { Zahlen aufsteigend sortieren }
- VAR
- l, j, k, i : WORD;
- h : REAL;
- BEGIN
- l := (n DIV 2) + 1; k := n;
- WHILE TRUE DO BEGIN
- IF l > 1 THEN BEGIN
- l := l - 1;
- h := a[l];
- END ELSE BEGIN
- h := a[k]; a[k] := a[1]; k := k - 1;
- IF k = 1 THEN BEGIN
- a[1] := h; Exit;
- END;
- END;
- i := l; j := l + l;
- WHILE j <= k DO BEGIN
- IF j < k THEN IF a[j] < a[j+1] THEN j := j + 1;
- IF h < a[j] THEN BEGIN
- a[i] := a[j]; i := j; j := j + j;
- END ELSE j := k + 1;
- END;
- a[i] := h;
- END;
- END;
-
- PROCEDURE RobustLinFit(x, y : Vector; k1, k2 : WORD;
- VAR a, b, da, db, dy : REAL);
- LABEL 9;
- VAR
- i, k, n : WORD;
- xs, ys, xy, xx, f, f1, f2, b1, b2, d, chi2, h : REAL;
-
- FUNCTION Theory(b : REAL; VAR a, dy : REAL) : REAL;
- { Rechte Seite von Gl. (1) }
- VAR
- d, s : REAL;
- i, k, n, n1, n2 : WORD;
- f : Vector;
- BEGIN
- n := k2 - k1 + 1;
- n2 := (n+1) DIV 2;
- n1 := (n+1) - n2; i := 0;
- FOR k := k1 TO k2 DO BEGIN
- i := i + 1; f[i] := y[k] - b * x[k];
- END;
- HeapSort(f, n);
- a := 0.5*(f[n2] + f[n1]); { Bestimmung des Medians }
- s := 0; i:=0; dy:=0;
- FOR i := k1 to k2 DO BEGIN
- d := y[i] - (b * x[i] + a);
- dy := dy + Abs(d);
- IF d > 0 THEN s := s + x[i] ELSE s := s - x[i];
- END;
- Theory := s;
- END;
-
- BEGIN
- IF k1 > k2 THEN BEGIN
- n := k1; k1 := k2; k2 := n;
- END;
- n := k2 - k1 + 1; { Stützstellenzahl }
- xs := 0; ys := 0;
- xy := 0; xx := 0; chi2:=0;
- FOR i := k1 TO k2 DO BEGIN { Gauß-Summen }
- xs := xs + x[i]; xy := xy + x[i] * y[i];
- ys := ys + y[i]; xx := xx + x[i] * x[i];
- END;
- d := n*xx - xs*xs;
- a := (xx*ys - xs*xy)/d;
- b := (n*xy - xs*ys)/d;
- FOR i := k1 TO k2 DO
- chi2 := chi2 + Sqr(y[i] - (a + b * x[i]));
- { Fehlerquadratsumme }
- h := Sqrt(chi2/d);
- b1 := b;
- f1 := Theory(b1, a, dy);
- IF f1 > 0 THEN
- b2 := b + Abs(3 * h)
- ELSE
- b2 := b - Abs(3 * h);
- f2 := Theory(b2, a, dy);
- WHILE ((f1 * f2 > 0) AND (f1 <> f2)) DO BEGIN
- { Löse Gl. (2) für versch. b }
- b := 2 * b2 - b1;
- b1 := b2; f1 := f2;
- b2 := b; f2 := Theory(b2, a, dy);
- END;
- h := 0.01 * h;
- WHILE Abs(b2 - b1) > h DO BEGIN { Nullstellensuche }
- b := 0.5 * (b1 + b2);
- IF ((b = b1) OR (b = b2)) THEN GOTO 9;
- f := Theory(b, a, dy);
- IF f * f1 >= 0 THEN BEGIN
- f1 := f; b1 := b;
- END ELSE BEGIN
- f2 := f; b2 := b;
- END;
- END;
- 9:
- dy := dy/n; { Fehler des Fits }
- da := dy * Sqrt(Abs(xx / (n * xx - xs * xs)));
- db := dy * Sqrt(Abs(n / (n * xx - xs * xs)));
- END;
-
- PROCEDURE LinearFit;
- { Treiberroutine und Ausgabe der Ergebnisse }
- BEGIN
- ClrScr;
- WriteLn('A u s g l e i c h s g e r a d e',
- ' y = b x + a');
- WriteLn;
- LinFit(x,y, i1,i2, a,b,r,da,db,dy,xo,xm,ym,sx,sy);
- phi := ArcTan(b) * 180 / Pi;
- WriteLn('Routine LINFIT',#13#10);
- WriteLn('Steigung: b = ',
- b:12:6,' ± ',db:12:6);
- WriteLn('- ',
- phi:12:6,'°');
- WriteLn('Achsenabschnitt: a = ',
- a:12:6,' ± ',da:12:6);
- WriteLn('Regression: r = ',
- (r*100):12:6,' %');
- WriteLn('Absolute Abweichung der y-Werte: dy = ',
- dy:12:6);
- WriteLn('Schnittpunkt mit der x-Achse: xo = ',
- xo:12:6);
- WriteLn('x-Werte: Mittel, Standardabweichung: xm = ',
- xm:12:6,' ± ',sx:12:6);
- WriteLn('y-Werte: - - ym = ',
- ym:12:6,' ± ',sy:12:6);
- WriteLn;
- WriteLn('Routine ROBUSTLINFIT: Einen ',
- 'Moment Geduld...',#13#10);
- RobustLinFit(x,y, i1,i2, a,b,da,db,dy);
- phi := ArcTan(b) * 180 / Pi;
- WriteLn('Steigung: b = ',
- b:12:6,' ± ',db:12:6);
- WriteLn('- ',
- phi:12:6,'°');
- WriteLn('Achsenabschnitt: a = ',
- a:12:6,' ± ',da:12:6);
- WriteLn('Absolute Abweichung der y-Werte: dy = ',
- dy:12:6);
- Writeln('Schnittpunkt mit der x-Achse: xo = ',
- (-a/b):12:6);
- WriteLn;
- WriteLn('Weiter mit RETURN');
- ReadLn;
- END;
-
- {----------------------- Beispiele ------------------------}
- BEGIN
- Randomize; { Beispiel 1 }
- xmin := -10;
- xmax := +10; { x-Intervall der Stützstellen }
- b := 0.75;
- a := -2; { Steigung b, Achsenabschnitt a }
- FOR i := 1 TO npt DO BEGIN { Verrauschter Meßdatensatz }
- x[i] := (i - 1) * (xmax - xmin) / npt + xmin;
- y[i] := (b * x[i] + a) + spread * 2 * (Random-0.5);
- END;
- ProduceOutliers; { Ausreißer aufprägen }
- i1 := 1; { Anfangspunkt }
- i2 := npt; { Endpunkt }
- LinearFit;
- { Beispiel 2 - Radioaktiver Zerfall }
- xmin := 0; xmax := 10; { Zeitachse }
- b := 1.5; { b = ln 2/τ }
- a := 100; { Anfangsmenge }
- FOR i := 1 TO npt DO BEGIN { Verrauschter Meßdatensatz }
- x[i] := (i - 1) * (xmax - xmin) / npt + xmin;
- y[i] := a * Exp(-b * x[i]); { Zerfallsgesetz }
- y[i] := y[i] + spread * 2 * (Random - 0.5);
- { Rauschen aufgeben }
- END;
- ProduceOutliers; { Ausreißer aufprägen }
- i1 := 1; { Anfangspunkt }
- i2 := npt; { Endpunkt }
- FOR i := i1 TO i2 DO y[i] := Log10(y[i]); { Vorskalieren }
- LinearFit;
- ClrScr;
- WriteLn('Ausgleichsfunktion y = a` + ',
- 'EXP(b` x) ');
- WriteLn;
- WriteLn('Steigung: b` = 2.303 b = ',
- (Ln(10)*b):12:6);
- WriteLn('Achsenabschnitt: a` = 10^a = ',
- (Exp10(a)):12:6);
- WriteLn('Halbwertszeit: τ = -ln 2/b` = ',
- (-Ln(2)/Ln(10)/b):12:6);
- WriteLn('Anfangsmenge: No = a` = ',
- (Exp10(a)):12:6);
- WriteLn;
- END.
- (* ------------------------------------------------------ *)
- (* Ende von LINFIT.PAS *)