MF_multiNonlinfit MD_multiNonlinfit ME_multiNonlinfit
MF_multiNonlinfitwW MD_multiNonlinfitwW ME_multiNonlinfitwW
Funktionaus mehreren X-Y-Z-Datensätzen gleichzeitig die Parameter einer gemeinsamen nicht-linearen Modell-Funktion anpassen
Syntax C/C++#include <MFstd.h>
float MF_multiNonlinfit( fVector A, iVector AStatus, unsigned npars,
    MF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
    void (*modelfunc)(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y, unsigned iexperiment),
    void (*derivatives)(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, unsigned iexperiment),
    VF_NONLINFITOPTIONS *FitOpts,
    MF_NONLINFITWORKSPACE *WorkSpace );

float MF_multiNonlinfitwW( fVector A, fMatrix Covar, iVector AStatus, unsigned npars,
    MF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
    void (*modelfunc)(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y, unsigned iexperiment ),
    void (*derivatives)(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, unsigned iexperiment),
    VF_NONLINFITOPTIONS *FitOpts,
    MF_NONLINFITWORKSPACE *WorkSpace );

Syntax C/C++ vereinfacht#include <MFstd.h>
float MF_multiNonlinfit( fVector A, iVector AStatus, unsigned npars,
    MF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
    void (*modelfunc)(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y, unsigned iexperiment),
    void (*derivatives)(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, unsigned iexperiment) );

float MF_multiNonlinfitwW( fVector A, fMatrix Covar, iVector AStatus, unsigned npars,
    MF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
    void (*modelfunc)(fMatrix ZModel, ui htZ, ui lenZ, fVector X, fVector Y, unsigned iexperiment ),
    void (*derivatives)(fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, unsigned iexperiment) );

Pascal/Delphiuses MFmnlfit;
function MF_multiNonlinfit( A: fVector; AStatus: iVector; nParameters: UInt;
    ListOfExperiments: PMF_EXPERIMENT; nexperiments: UInt;
    ModelFunc, Derivatives: Pointer;
    FitOpts: PVF_NONLINFITOPTIONS; WorkSpace: PMF_NONLINFITWORKSPACE ): Single;

function MF_multiNonlinfitwW( A: fVector; Covar: fMatrix; AStatus: iVector; nParameters: UInt;
    ListOfExperiments: PMF_EXPERIMENT; nexperiments: UInt;
    ModelFunc, Derivatives: Pointer;
    FitOpts: PVF_NONLINFITOPTIONS; WorkSpace: PMF_NONLINFITWORKSPACE ): Single;

Pascal/Delphi vereinfachtuses VFmnlfit;
function MF_multiNonlinfit( A: fVector; AStatus: iVector; nParameters: UInt;
    ListOfExperiments: PMF_EXPERIMENT; nexperiments: UInt;
    ModelFunc, Derivatives: Pointer ): Single;

function MF_multiNonlinfitwW( A: fVector; Covar: fMatrix; AStatus: iVector; nParameters: UInt;
    ListOfExperiments: PMF_EXPERIMENT; nexperiments: UInt;
    ModelFunc, Derivatives: Pointer ): Single;

BeschreibungDie in ListOfExperiments enthaltenen Eingabe-Daten werden benutzt, um die Parameter ai einer allgemeinen nicht-linearen Modell-Funktion z = f(x, y) zu bestimmen. Die Parameter ai werden in dem Vektor A zurückgegeben.

Argumente:
AVektor der Länge npars; gibt die berechneten Koeffizienten zurück
CovarMatrix der Dimensionen [npars, npars]; gibt die Kovarianzen der Koeffizenten zurück
AStatusVektor der Länge npars; entscheidet darüber, welche Parameter frei oder eingefroren sind
nparsGesamtzahl der Parameter
ListOfExperimentsEingabedaten, siehe Kap. 13.4
nexperimentsAnzahl der Datensätze in ListOfExperiments
modelfuncBenutzer-definierte Modell-Funktion
derivativesBenutzer-definierte Funktion, die die partiellen Ableitungen der Modellfunktion nach den einzelnen Parametern berechnet
FitOptsZeiger auf eine Struktur mit Fit-Optionen, siehe chap. 13.3
WorkSpaceZeiger auf eine Struktur mit internen Variablen, siehe chap. 13.3
 
Die Modell-Funktion (und damit der Parameter-Vektor) kann mehr Parameter enthalten als tatsächlich angepaßt werden sollen. Daher muß ein zusätzlicher Vektor AStatus die Information darüber enthalten, welche Parameter bei ihren Eingabe-Werten eingefroren bleiben sollen (AStatus[i] = 0) und welche anzupassen sind (AStatus[i] = 1). Alle Parameter (nicht nur die eingefrorenen!) müssen in A vor dem Aufruf von VF_multiNonlinfit initialisiert sein. npars bezeichnet die Gesamtzahl der Parameter in A (also nicht nur die freien Parameter!).

Die Eingabe-Daten müssen in Sätzen des Typs MF_EXPERIMENT zusammengefaßt werden. Angenommen, man habe zwei X-Y-Z-Datensätze, jeweils bestehend aus den Vektoren X und Y für die unabhängigen Variablen, die Matrix Z für die z=f(x, y)-Werte und, für MF_multiLinfitwW, die Einzelpunkt-Wichtungen in MInvVar. Hieraus hat man die Experimenten-Liste zusammenzustellen wie im folgenden Beispiel:

Experimenten-Liste in C/C++ konstruieren MF_EXPERIMENT ExpList[2];
ExpList[0].X = X1;  ExpList[0].Y = Y1;  
ExpList[0].MZ = MZ1;
ExpList[0].htZ = htZ1;  ExpList[0].lenZ = lenZ1;
ExpList[1].X = X1;  ExpList[1].Y = Y2;  
ExpList[1].MZ = MZ2;
ExpList[1].htZ = htZ2;  ExpList[1].lenZ = lenZ2;
/* für die Variante mit Einzelpunkt-Wichtung außerdem: */
ExpList[0].MInvVar = MInvVar1;  
ExpList[0].WeightOfExperiment = wt1;
ExpList[1].MInvVar = MInvVar2;  
ExpList[1].WeightOfExperiment = wt2;
 
Experimenten-Liste in Pascal/Delphi konstruieren var ExpList: array[0..1] of MF_EXPERIMENT;
begin
  ...
  ExpList[0].X := X1;  ExpList[0].Y := Y1;  
  ExpList[0].MZ := MZ1;
  ExpList[0].htZ := htZ1;  ExpList[0].lenZ := lenZ1;
  ExpList[1].X := X2;  ExpList[1].Y := Y2;  
  ExpList[1].MZ := MZ2;
  ExpList[1].htZ := htZ2;  ExpList[1].lenZ := lenZ2;
    (* für die Variante mit Einzelpunkt-Wichtung außerdem: *)
  ExpList[0].MInvVar := MInvVar1;  
  ExpList[0].WeightOfExperiment := wt1;
  ExpList[1].MInvVar := MInvVar2;  
  ExpList[1].WeightOfExperiment := wt2;
  ...
end;

 
Sowohl C/C++ als auch Pascal/Delphi

Die Modell-Funktion "funcs" ist vom Anwender zu schreiben. Sie hat für gegebene X-Y-Vektorpaare die entsprechenden theoretischen MZ-Werte zu berechnen.
In C/C++ muß sie wie folgt geschrieben werden:
 

Modell-Funktion für C/C++ void _cdecl MyFunc( fMatrix Z, ui htZ, ui lenZ, fVector X, fVector Y, unsigned iexperiment )
{
  for(ui i=0; i<htZ; i++ )
    for(ui j=0; j<lenZ; j++ )
      MZ[i][j] = f( X[j], Y[i] );
}

Dabei ist f( X[j], Y[i] ) eine beliebige Funktion, die so kompliziert sein darf, wie es Ihre Anwendung erfordert. Sie darf aber keine Singularitäten besitzen, zumindest innerhalb der ggf. spezifizierten Unter- und Obergrenzen der Parameter (siehe NONLINFITOPTIONS).

Das Argument iexperiment, mit dem MyFunc intern von MF_multiNonlinfit aus aufgerufen werden wird, erlaubt die Unterscheidung zwischen Parametern, die allen Experimenten gemeinsam sind, und solchen, die individuell zu den einzelnen Experimenten gehören. Z.B. könnten die MZ-Werte mit einen für jedes Experiment verschiedenen Wert C skaliert sein. In diesem Falle muß A so viele Skalierungs-Faktoren enthalten, wie es Experimente gibt. In MyFunc hätte man dies in der folgenden Weise zu berücksichtigen:
  if( iexperiment == 0 ) MZ[i][j] *= A[5];  else MZ[i][j] *= A[6];

Zusätzlich zu der Modell-Funktion benötigt MF_multiNonlinfit die partiellen Ableitungen von MZ nach allen Parametern A[ipar] entsprechend dem gewählten Modell. Falls sie zumindest zum Teil analytisch bekannt sind, solte man eine Funktion MyDerivs schreiben. Dabei können diejenigen partiellen Ableitungen, die man doch nicht kennt, durch Aufruf von MF_multiNonlinfit_autoDeriv numerisch berechnet werden.

Partielle Ableitungen für C/C++ MF_NONLINFITWORKSPACE WorkSpace; /* sollte eine globale Variable sein, dieselbe, die an MF_multiNonlinfit übergeben wird */

void _cdecl MyDerivs( fMatrix dZdAi, ui htZ, ui lenZ, fVector X, fVector Y, unsigned ipar, unsigned iexperiment )
{
  ui i;
  switch( ipar )
  {
    case 0:
    for(i=0; i<htZ; i++ )
      for( j=0; j<lenZ; j++ )
        dZdAi[i][j] = part_Abl_MZ_nach_A0( X[j], Y[i] );
    break;
    case 1:
    for(i=0; i<htZ; i++ )
      for( j=0; j<lenZ; j++ )
        dZdAi[i][j] = part_Abl_MZ_nach_A1( X[j], Y[i] );
    break;
    default: /* für alle unbekannten Ableitungen: */
      MF_multiNonlinfit_autoDeriv(
          dZdAi, htZ, lenZ, X, Y, ipar, iexperiment, &WorkSpace );
  }
}

Wiederum erlaubt es das Argument iexperiment, die für die einzelnen Experimente individuellen Parameter anders als die allen Experimenten gemeinsamen zu behandeln.
Ein Aufruf von MF_multiNonlinfit wird dann etwa so aussehen:
MF_multiNonlinfit( A, AStatus, npars, ExpList, 2, MyFunc, MyDerivs, &FitOpts, &WorkSpace );
oder in vereinfachter Syntax:
MF_multiNonlinfit( A, AStatus, npars, ExpList, 2, MyFunc, MyDerivs );
Falls überhaupt keine der partiellen Ableitungen analytisch bekannt sind, definiere man auch MyDerivs nicht, sondern setze derivatives = NULL im Aufruf von MF_multiNonlinfit:
MF_multiNonlinfit( A, AStatus, npars, ExpList, 2, MyFunc, NULL );
 

Modell-Funktion für Pascal/Delphi In Pascal/Delphi muß die Modell-Funktion wie folgt geschrieben werden:
procedure MyFunc( MZ:fMatrix; htZ, lenZ:UIntSize; X, Y:fVector; iexperiment:UInt );
var i, j:UIntSize;
begin
  for i:=0 to htZ-1 do
    for j:=0 to lenZ-1 do
      MF_Pelement( MZ, htZ, lenZ, i, j )^ :=
        f( VF_element( X, j ), VF_element( Y, i ) );
end;

Dabei ist f( Xj, Yi ) eine beliebige Funktion, die so kompliziert sein darf, wie es Ihre Anwendung erfordert. Sie darf aber keine Singularitäten besitzen, zumindest innerhalb der ggf. spezifizierten Unter- und Obergrenzen der Parameter (siehe NONLINFITOPTIONS).

Das Argument iexperiment, mit dem MyFunc intern von MF_multiNonlinfit aus aufgerufen werden wird, erlaubt die Unterscheidung zwischen Parametern, die allen Experimenten gemeinsam sind, und solchen, die individuell zu den einzelnen Experimenten gehören. Z.B. könnten die MZ-Werte mit einen für jedes Experiment verschiedenen Wert C skaliert sein. In diesem Falle muß A so viele Skalierungs-Faktoren enthalten, wie es Experimente gibt. In MyFunc hätte man dies in der folgenden Weise zu berücksichtigen:
  if iexperiment = 0 then
         MF_Pelement(MZ, htZ, lenZ, i, j)^ :=
         MF_element(MZ, htZ, lenZ, i, j) * VF_element(A,5)
  else MF_Pelement(MZ, htZ, lenZ, i, j)^ :=
         MF_element(MZ, htZ, lenZ, i, j) * VF_element(A,6);

Zusätzlich zu der Modell-Funktion benötigt MF_multiNonlinfit die partiellen Ableitungen von MZ nach allen Parametern A[ipar] entsprechend dem gewählten Modell. Falls sie zumindest zum Teil analytisch bekannt sind, solte man eine Funktion MyDerivs schreiben. Dabei können diejenigen partiellen Ableitungen, die man doch nicht kennt, durch Aufruf von MF_multiNonlinfit_autoDeriv numerisch berechnet werden.

Partielle Ableitungen für Pascal/Delphi var WorkSpace: MF_NONLINFITWORKSPACE; (* sollte eine globale Variable sein, dieselbe, die an MF_multiNonlinfit übergeben wird *)

procedure MyDerivs( dZdAi:fMatrix; htZ, lenZ:UIntSize; X, Y:fVector; ipar, iexperiment:UInt );
var i, j:UIntSize;
begin
  case ipar of
    0: begin
      for i:=0 to ht-1 do
        for j:=0 to len-1 do
          MF_Pelement( dZdAi, htZ, lenZ, i, j )^ :=
          part_Abl_MZ_nach_A0(VF_element( X, j ),
                              VF_element( Y, i ));
       end;
    1: begin
      for i:=0 to ht-1 do
        for j:=0 to len-1 do
          MF_Pelement( dZdAi, htZ, lenZ, i, j )^ :=
          part_Abl_MZ_nach_A1(VF_element( X, j ),
                              VF_element( Y, i ));
       end;
  else (* für alle unbekannten Ableitungen: *)
    MF_multiNonlinfit_autoDeriv(
          dZdAi, htZ, lenZ, X, Y, ipar, @WorkSpace );
  end;
end;

Wiederum erlaubt es das Argument iexperiment, die für die einzelnen Experimente individuellen Parameter anders als die allen Experimenten gemeinsamen zu behandeln.
Ein Aufruf von MF_multiNonlinfit wird dann etwa so aussehen:
MF_multiNonlinfit( A, AStatus, npars, @ExpList, 2, @MyFunc, @MyDerivs, @FitOpts, @WorkSpace );
oder in vereinfachter Syntax:
MF_multiNonlinfit( A, AStatus, npars, @ExpList, 2, @MyFunc, @MyDerivs );
Man beachte die Adress-Operatoren vor "ExpList", "MyFunc " und "MyDerivs". Falls überhaupt keine der partiellen Ableitungen analytisch bekannt sind, definiere man auch MyDerivs nicht, sondern setze derivatives := nil im Aufruf von MF_multiNonlinfit:
MF_multiNonlinfit( A, AStatus, npars, @ExpList, 2, @MyFunc, nil );

In der gewichteten Variante MF_multiNonlinfitwW muß die Matrix ExpList[i].MInvVar jedes Experimentes den Kehrwert der Varianzen der einzelnen X-Y-Z-Datenpunkte enthalten, und die Matrix MCovar gibt die Kovarianzen der Parameter ai zurück: MCovari,j = covariance( ai, aj ).
 

Sowohl C/C++ als auch Pascal/Delphi: Bezüglich der vielen verschieden Optionen zur Steuerung der nicht-linearen Datenapassungs-Routinen von OptiVec lese man Kap. 13.3. Hilfsfunktionen zum Abbruch überlang laufender Anpassungen und zur Überwachung des Fortganges dieser oft sehr zeitaufwendigen Prozeduren sind in Kap. 13.5 zusammengefaßt und, im Spezialfall von MF_multiNonlinfit, hier beschrieben.
Beschränkungen des Multi-threadingDie in den OptiVec-Versionen bis einschließlich 6.1 vorhandenen Multi-Threading-Einschränkungen sind mit Version 6.2 aufgehoben.

Diese Funktionen dürfen nicht aufgerufen werden, wenn die FPU auf reduzierte Genauigkeit geschaltet wurde. Andernfalls können sie in einer unendlichen Schleife hängenbleiben, siehe V_setFPAccuracy.

FehlerbehandlungÜbersteigt die Zahl der freien Parameter (also derjenigen mit AStatus[i] = 1) die Gesamtzahl der anzupassenden Datenpunkte, so wird eine Fehlermeldung "Invalid parameter(s)" ausgegeben und das Programm abgebrochen.
RückgabewertBei Erfolg: Anpassungstest-Wert c2 (chi-Quadrat)
Wenn keine Verbesserung des Parametersatzes erzielt werden konnte: -1
QuerverweisVF_setNonlinfitOptions,   VF_multiNonlinfit,   MF_linfit,   Kap. 13,  FITDEMO*.*

MatrixLib Inhaltsverzeichnis  OptiVec Home