Buchempfehlung
Windows-Programmierung. Das Entwicklerhandbuch zur WIN32-API
Windows-Programmierung. Das Entwicklerhandbuch zur WIN32-API
"Der" Petzold, das über 1000 Seiten starke Standardwerk zum Win32-API - besonders nützlich u. a. bei der GUI-Programmierung in FreeBASIC! [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Code-Beispiel

Code-Beispiele » Mathematik

X/Y-Regressionsanalyse

Lizenz:Erster Autor:Letzte Bearbeitung:
k. A.MitgliedTJF 08.11.2011
Anwendungsbeispiel Konturliniengrafik
Vergrößern
Anwendungsbeispiel Konturliniengrafik

Dieses Beispiel betrifft das mathematische Verfahren der Externer Link!Regressionsanalyse von Messdaten (auch Anpassung, Parameterschätzung, Ausgleichsrechnung oder Fitting genannt).

Aus einer Anzahl von diskreten Messwerten y_i an den Stellen x_i wird eine Fitting-Funktion y = F(x) berechnet, welche für weitere mathematische Bearbeitungen verwendet werden kann, z.B. zur Interpolation in Bereichen ohne Messdaten oder auch zur Bildung von Ableitungen der Messdaten. Übliche Verfahren betreffen entweder die Abhängigkeit von nur einer Eingangsgröße (y = F(x)) oder wenige Verfahren betreffen mehrere Eingangsgrößen (y = F(x1, x2, ..., xn) mit ausschließlich linearer Abhängigkeit der Eingangsgrößen, vgl. auch fbmath - Kap. 14.

Das hier vorgestellte Verfahren verwendet zwei Eingangsgrößen (x1, x2) und erzeugt eine Fitting-Funktion y = F(x1, x2) mit beliebiger Ordnung (= Potenz der Ansatzfunktionen, beliebig im Rahmen der Rechengenauigkeit).

Als Anwendungsbeispiel sei auf die Karten der Wettervorhersage verwiesen. Dort sind Linien eingezeichnet, die Hoch- und Tiefdruckgebiete kennzeichnen. Diese Isobaren werden aus Messwerten ermittelt, welche an diskreten Orten bestimmt werden. Es sind also Druckmesswerte P an den Orten (X, Y) verfügbar, aus denen dann der Verlauf der Isobaren ermittelt wird, also P(X, Y) = F(x1, x2) = y.

Alle Ausgleichsrechnungen lassen sich durch Variationsprobleme beschreiben, bei denen die Gewichtung von Ansatzfunktionen durch Parameter so gewählt wird, dass die Abweichung von den Messwerten minimal wird. Im Falle von mehreren Eingangsgrößen ist es jedoch nicht möglich, beliebige Ansatzfunktionen zu wählen, da sonst ggf. das Variationsproblem singulär wird, also unlösbar ist.

In diesem Code-Beispiel wird ein Produktansatz von Legendre Polynomen verwendet, welche im Intervall -1 bis 1 orthogonal sind. Daher ist bei hinreichender Verteilung der Messdaten das Variationsproblem immer lösbar. (Jedoch ist eine Koordinatentransformation unvermeidbar und die Fitting-Funktion sollte nur in dem zuvor definierten Gültigkeitsbereich angewendet werden.)

Zunächst der Quelltext für die Struktur XYRegression. Er verwendet das Code-Beispiel Legendre Polynome, welches wiederum libFBla verwendet. Der Quelltext sollte unter dem Namen "XYRegression.bas" gespeichert werden.

' This is file "XYRegression.bas"
' (C) LGPLv2 by Thomas[ dot ]Freiherr{ at }gmx{ dot }net

#INCLUDE ONCE "LegendrePolynom.bas"

#DEFINE XYR_INDEX(_L_,_H_) _L_ += 1 : IF _L_ >= Basis THEN _L_ = 0 : _H_ += 1

TYPE XYRegression
  AS STRING Err_
  AS LA_S StdDev '                                standard deviation
  DECLARE CONSTRUCTOR(BYVAL O AS UINTEGER, BYVAL V AS LA_M PTR, _
                      BYVAL ChX1 AS UINTEGER = 0, _
                      BYVAL ChX2 AS UINTEGER = 1, _
                      BYVAL ChY AS UINTEGER = 2, _
                      BYVAL StAbw AS UINTEGER = 0, _
                      BYVAL Xn AS LA_S = 0.0, BYVAL Xx AS LA_S = 0.0, _
                      BYVAL Yn AS LA_S = 0.0, BYVAL Yx AS LA_S = 0.0)
  DECLARE DESTRUCTOR()
  DECLARE FUNCTION Val_(BYVAL X AS LA_S, BYVAL Y AS LA_S) AS LA_S
  DECLARE FUNCTION Abw_(BYVAL V AS LA_M PTR, _
                        BYVAL ChX1 AS UINTEGER = 0, _
                        BYVAL ChX2 AS UINTEGER = 1, _
                        BYVAL ChY AS UINTEGER = 2) AS LA_S
Private:
  AS LegendrePolynom PTR Leg '                       polynoms to use
  AS LA_V Res '                           vector to store parameters
  AS LA_S Xmin, Ymin, Dx, Dy '   for transformation interval [-1, 1]
  AS UINTEGER Basis, Lines, C1, C2, Cy '                for indexing
  DECLARE SUB Fit_(BYVAL V AS LA_M PTR, BYVAL Mo AS INTEGER = 0)
END TYPE

' computes the Regression of Order from values V
' ChX1, ChX2 = columns of X values (defaults to 0, 1)
' ChY = column of Y values (defaults to 2)
' StAbw: if <> 0 then calculate the standard deviation
' Xn, Xm: minimum and maximum X1 values
' Yn, Ym: minimum and maximum X2 values (if Yn = Ym -> find extrema in V)
CONSTRUCTOR XYRegression(BYVAL Order AS UINTEGER, BYVAL V AS LA_M PTR, _
                         BYVAL ChX1 AS UINTEGER = 0, _
                         BYVAL ChX2 AS UINTEGER = 1, _
                         BYVAL ChY AS UINTEGER = 2, _
                         BYVAL StAbw AS UINTEGER = 0, _
                         BYVAL Xn AS LA_S = 0.0, BYVAL Xx AS LA_S = 0.0, _
                         BYVAL Yn AS LA_S = 0.0, BYVAL Yx AS LA_S = 0.0)
  Basis = Order + 1
  C1 = ChX1
  C2 = ChX2
  Cy = ChY

  VAR az = V->Row_() + 1
  Lines = Basis ^ 2
  IF az < Lines THEN Err_ = "not enough values" : EXIT CONSTRUCTOR

  VAR i = V->Col_()
  IF i < C1 ORELSE _
     i < C2 ORELSE _
     i < Cy THEN Err_ = "column missmatch" : EXIT CONSTRUCTOR

  IF Yn = Yx THEN '                                    search extrema
    Xmin = V->Val_(0, C1) : Ymin = V->Val_(0, C2)
    VAR Xmax = Xmin, Ymax = Ymin
    FOR i AS INTEGER = 1 TO V->Row_
      IF V->Val_(i, C1) < Xmin THEN Xmin = V->Val_(i, C1)
      IF V->Val_(i, C1) > Xmax THEN Xmax = V->Val_(i, C1)
      IF V->Val_(i, C2) < Ymin THEN Ymin = V->Val_(i, C2)
      IF V->Val_(i, C2) > Ymax THEN Ymax = V->Val_(i, C2)
    NEXT
    Dx = Xmax - Xmin : IF Dx THEN Dx = 2.0 / Dx
    Dy = Ymax - Ymin : IF Dy THEN Dy = 2.0 / Dy
  ELSE '                                       compute transformation
    Xmin = Xn : Ymin = Yn
    Dx = Xx - Xn : IF Dx THEN Dx = 2 / Dx
    Dy = Yx - Yn : IF Dy THEN Dy = 2 / Dy
  END IF
  IF Dx = 0 THEN Err_ = "no X difference" : EXIT CONSTRUCTOR
  IF Dy = 0 THEN Err_ = "no Y difference" : EXIT CONSTRUCTOR

  Leg = NEW LegendrePolynom(Basis - 1)
  VAR w = LA_M(Lines, Lines), r = LA_V(Lines)
  Lines -= 1

  VAR x = LA_V(az), y = LA_V(az)
  az -= 1 : Xmin += 1 / Dx : Ymin += 1 / Dy
  FOR i = 0 TO az '                            transform into [-1, 1]
    x.Val_(i) = (V->Val_(i, C1) - Xmin) * Dx
    y.Val_(i) = (V->Val_(i, C2) - Ymin) * Dy
  NEXT

  VAR m = 0, n = 0
  DIM AS LA_S sum
  FOR i = 0 TO Lines '                  build linear equation system
    VAR j = 0, k = 0, p = 0, q = 0
    FOR k = 0 TO Lines '                                   left side
      sum = 0.0
      FOR j = 0 TO az
        sum += Leg->Val_(x.Val_(j), n) * Leg->Val_(y.Val_(j), m) * _
               Leg->Val_(x.Val_(j), p) * Leg->Val_(y.Val_(j), q)
      NEXT : w.Set_(i, k, sum / j)
      XYR_INDEX(p, q)
    NEXT
    sum = 0.0
    FOR j = 0 TO az '                                     right side
      sum += Leg->Val_(x.Val_(j), n) * Leg->Val_(y.Val_(j), m) * _
             V->Val_(j, Cy)
    NEXT : r.Val_(i) = sum / j
    XYR_INDEX(n, m)
  NEXT
  Res = r / w '                                       solve system
  IF StdDev THEN StdDev = Abw_(V, C1, C2, Cy)
END CONSTRUCTOR

DESTRUCTOR XYRegression()
  IF Leg THEN DELETE Leg
END DESTRUCTOR

FUNCTION XYRegression.Val_(BYVAL X AS LA_S, BYVAL Y AS LA_S) AS LA_S
  VAR xx = (X - Xmin) * Dx, yy = (Y - Ymin) * Dy, r = 0.0
  VAR n = 0, m = 0
  FOR i AS INTEGER = 0 TO Lines
    r += Res.Val_(i) * Leg->Val_(xx, n) * Leg->Val_(yy, m)
    XYR_INDEX(n, m)
  NEXT : RETURN r
END FUNCTION

FUNCTION XYRegression.Abw_(BYVAL V AS LA_M PTR, _
                           BYVAL ChX1 AS UINTEGER = 0, _
                           BYVAL ChX2 AS UINTEGER = 1, _
                           BYVAL ChY AS UINTEGER = 2) AS LA_S
  VAR i = V->Col_()
  IF i < ChX1 ORELSE _
     i < ChX2 ORELSE _
     i < ChY THEN Err_ = "column missmatch" : RETURN 0.0
  DIM AS LA_S sum = 0.0
  FOR i = 0 TO V->Row_()
    sum += (V->Val_(i, ChY) - Val_(V->Val_(i, ChX1), V->Val_(i, ChX2))) ^ 2
  NEXT : RETURN sum / i
END FUNCTION

Anwendung

Beispiel

Beim Programmstart wird eine Fitting-Funktion vom Grad 4 berechnet. Nachdem das Bild aufgebaut wurde und die Meßpunkte sichtbar sind, kann mit den Tasten 0 bis 6 eine Neuberechnung mit entsprechendem Polynomgrad gestartet werden (Esc = Abbruch).

' This is file "XYRegressionTest.bas"
' (C) GPLv3 by Thomas[ dot ]Freiherr{ at }gmx{ dot }net

#INCLUDE ONCE "XYRegression.bas"

' grazy function to generate some test values
FUNCTION fn(BYVAL x1 AS DOUBLE, BYVAL x2 AS DOUBLE) AS DOUBLE
  VAR x = (x1 - 379) / 319, y = (x2 - 112) / 199
  RETURN 3 * EXP(-(x * x + y * y)) * SIN(x * y + 3)
END FUNCTION


' prepare graphics window
CONST ScW = 639, ScH = 399
SCREENRES ScW + 1, ScH + 1

' Prepare some test values, V() has 3 coloumns: x1, x2, y
RANDOMIZE TIMER
CONST Anzahl = 69 '     play with this number to see the differences
VAR V = LA_M(Anzahl + 1, 3), kx1 = 0, kx2 = 1, ky = 2
VAR mx = V.Val_(0, ky), mn = mx
FOR i AS INTEGER = 0 TO Anzahl
  VAR x1 = RND * ScW
  VAR x2 = RND * ScH
  VAR yy = fn(x1, x2)
  V.Set_(i, kx1, x1)
  V.Set_(i, kx2, x2)
  V.Set_(i, ky, yy)
  IF yy > mx THEN mx = yy '             check extrema (for coloring)
  IF yy < mn THEN mn = yy
NEXT
VAR f = mx - mn : IF f THEN f = 15 / f '       scale of colored area

VAR Order = 4, OrderMax = 6
DO
  ' Compute regression analysis
  VAR test = XYRegression(Order, @V, kx1, kx2, ky, 1, 0.0, ScW, 0.0, ScH)
  IF LEN(test.Err_) THEN _ '                                  on error
    ?"Fehler: "; test.Err_ : EXIT DO

  WINDOWTITLE "Order " & Order & _
            ": (Grey colors valid, others are inaccurat)"
  FOR x AS INTEGER = 0 TO ScW '             draw regression analysis
    FOR y AS INTEGER = 0 TO ScH
      VAR col = 16 + CUINT((test.Val_(x, y) - mn) * f)
      PSET (x, y), col
    NEXT
  NEXT

  FOR i AS INTEGER = 0 TO Anzahl '           draw measurement points
    CIRCLE (V.Val_(i, kx1), V.Val_(i, kx2)), 3, 12, , , ,F
  NEXT
  WINDOWTITLE "Order " & Order & _
            ": Standard deviation: " & test.StdDev

  ' wait for key press to compute next step / warten auf Tastendruck
  SLEEP
  SELECT CASE INKEY
  CASE CHR(27) : EXIT DO
  CASE "0" : Order = 0
  CASE "1" : Order = 1
  CASE "2" : Order = 2
  CASE "3" : Order = 3
  CASE "4" : Order = 4
  CASE "5" : Order = 5
  CASE "6" : Order = 6
  CASE CHR(255, 75), CHR(255, 80)
    Order -= 1 : IF Order < 0 THEN Order = OrderMax
  CASE ELSE
    Order += 1 : IF Order > OrderMax THEN Order = 0
  END SELECT
LOOP

English

See Externer Link!English forum.


Zusätzliche Informationen und Funktionen
  • Das Code-Beispiel wurde am 29.04.2011 von MitgliedTJF angelegt.
  • Die aktuellste Version wurde am 08.11.2011 von MitgliedTJF gespeichert.
  Bearbeiten Bearbeiten  

  Versionen Versionen