Syntax C/C++ | #include <MFstd.h>
float VF_multiNonlinfit( fVector A, iVector AStatus, unsigned npars,
VF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
void (*modelfunc)(fVector YModel, fVector XModel, ui size, unsigned iexperiment, fVector A),
void (*derivatives)(fVector dYdAi,fVector X, ui size, unsigned ipar, unsigned iexperiment, fVector A, VF_NONLINFITWORKSPACE *ws),
VF_NONLINFITOPTIONS *FitOpts,
VF_NONLINFITWORKSPACE *WorkSpace );
float VF_multiNonlinfitwW( fVector A, fMatrix Covar, iVector AStatus, unsigned npars,
VF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
void (*modelfunc)(fVector YModel, fVector X, ui size, unsigned iexperiment, fVector A),
void (*derivatives)(fVector dYdAi, fVector X, ui size, unsigned ipar, unsigned iexperiment, fVector A, VF_NONLINFITWORKSPACE *ws),
VF_NONLINFITOPTIONS *FitOpts,
VF_NONLINFITWORKSPACE *WorkSpace ); |
Syntax C/C++ simplified | #include <MFstd.h>
float VF_multiNonlinfit( fVector A, iVector AStatus, unsigned npars,
VF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
void (*modelfunc)(fVector YModel, fVector XModel, ui size, unsigned iexperiment, fVector A),
void (*derivatives)(fVector dYdAi,fVector X, ui size, unsigned ipar, unsigned iexperiment, fVector A, VF_NONLINFITWORKSPACE *ws) );
float VF_multiNonlinfitwW( fVector A, fMatrix Covar, iVector AStatus, unsigned npars,
VF_EXPERIMENT *ListOfExperiments, unsigned nexperiments,
void (*modelfunc)(fVector YModel, fVector X, ui size, unsigned iexperiment, fVector A),
void (*derivatives)(fVector dYdAi, fVector X, ui size, unsigned ipar, unsigned iexperiment, fVector A, VF_NONLINFITWORKSPACE *ws) ); |
Pascal/Delphi | uses VFmnlfit;
function VF_multiNonlinfit( A: fVector; AStatus: iVector; nParameters: UInt;
ListOfExperiments: PVF_EXPERIMENT; nexperiments: UInt;
ModelFunc, Derivatives: Pointer;
FitOpts: PVF_NONLINFITOPTIONS; WorkSpace: PMF_NONLINFITWORKSPACE ): Single;
function VF_multiNonlinfitwW( A: fVector; Covar: fMatrix; AStatus: iVector; nParameters: UInt;
ListOfExperiments: PVF_EXPERIMENT; nexperiments: UInt;
ModelFunc, Derivatives: Pointer;
FitOpts: PVF_NONLINFITOPTIONS; WorkSpace: PMF_NONLINFITWORKSPACE ): Single;
Syntax der als Parameter übergebenen Funktionen ModelFunc und Derivatives:
procedure ModelFunc( YModel, X:fVector; size:UIntSize; iexperiment:UInt; A:fVector );
procedure Derivatives( dYdAi, X:fVector; size:UIntSize; ipar, iexperiment:UInt; A:fVector; ws:PVF_NONLINFITWORKSPACE );
|
Pascal/Delphi simplified | uses VFmnlfit;
function VF_multiNonlinfit( A: fVector; AStatus: iVector; nParameters: UInt;
ListOfExperiments: PVF_EXPERIMENT; nexperiments: UInt;
ModelFunc, Derivatives: Pointer ): Single;
function VF_multiNonlinfitwW( A: fVector; Covar: fMatrix; AStatus: iVector; nParameters: UInt;
ListOfExperiments: PVF_EXPERIMENT; nexperiments: UInt;
ModelFunc, Derivatives: Pointer ): Single; |
|
Beschreibung | Die in ListOfExperiments enthaltenen Eingabe-Daten werden benutzt, um die Parameter ai einer allgemeinen nicht-linearen Modell-Funktion y = f(x) zu bestimmen.
Argumente:
A | Vektor der Länge npars; gibt die berechneten Koeffizienten zurück |
Covar | Matrix der Dimensionen [npars, npars]; gibt die Kovarianzen der Koeffizenten zurück |
AStatus | Vektor der Länge npars; entscheidet darüber, welche Parameter frei oder eingefroren sind |
npars | Gesamtzahl der Parameter |
ListOfExperiments | Eingabedaten, siehe Kap. 13.4 |
nexperiments | Anzahl der Datensätze in ListOfExperiments |
modelfunc | Benutzer-definierte Modell-Funktion |
derivatives | Benutzer-definierte Funktion, die die partiellen Ableitungen der Modellfunktion nach den einzelnen Parametern berechnet. Durch Setzen dieses Arguments auf NULL / nil wird der Routine signalisiert, die partiellen Ableitungen numerisch zu bestimmen. |
FitOpts | Zeiger auf eine Struktur mit Fit-Optionen, siehe chap. 13.3 |
WorkSpace | Zeiger auf eine Struktur mit internen Variablen, siehe chap. 13.3 |
FitOpts und WorkSpace dürfen auf NULL / nil gesetzt werden. In der Variante mit vereinfachter Syntax gibt es diese beiden Argumente gar nicht erst.
Die Parameter ai werden in dem Vektor A zurückgegeben. Die Modell-Funktion (und damit der Parameter-Vektor) kann mehr Parameter enthalten als tatsächlich angepaßt werden sollen. Daher muss 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. Je besser Sie diese Startwerte "raten", umso schneller wird die Routine konvergieren. npars bezeichnet die Gesamtzahl der Parameter in A (also nicht nur die freien Parameter!).
Die Eingabe-Daten müssen in Sätzen des Typs VF_EXPERIMENT zusammengefaßt werden. Angenommen, man habe zwei X-Y-Datensätze, bestehend aus den Vektoren X1, Y1 (für VF_multiLinfitwW auch InvVar1) von je size1 Elementen, und X2, Y2 (und InvVar2) von je size2 Elementen. Hieraus hat man die Experimenten-Liste zusammenzustellen wie im folgenden Beispiel:
| Experimenten-Liste in C/C++ konstruieren |
VF_EXPERIMENT ExpList[2];
ExpList[0].X = X1; ExpList[0].Y = Y1; ExpList[0].size = size1;
ExpList[1].X = X2; ExpList[1].Y = Y2; ExpList[1].size = size2;
/* für die Variante mit Einzelpunkt-Wichtung außerdem: */
ExpList[0].InvVar = InvVar1; ExpList[0].WeightOfExperiment = wt1;
ExpList[1].InvVar = InvVar2; ExpList[1].WeightOfExperiment = wt2;
| Experimenten-Liste in Pascal/Delphi konstruieren |
var ExpList: array[0..1] of VF_EXPERIMENT;
begin
...
ExpList[0].X := X1; ExpList[0].Y := Y1;
ExpList[0].size := size1;
ExpList[1].X := X2; ExpList[1].Y := Y2;
ExpList[1].size := size2;
(* für die Variante mit Einzelpunkt-Wichtung außerdem: *)
ExpList[0].InvVar := InvVar1;
ExpList[0].WeightOfExperiment := wt1;
ExpList[1].InvVar := InvVar2;
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 einen gegebenen X-Vektor die entsprechenden Y-Werte zu berechnen.
In C/C++ muss sie wie folgt geschrieben werden:
| Modell-Funktion für C/C++ |
void _cdecl MyFunc( fVector Y, fVector X, ui size, unsigned iexperiment, fVector A )
{
for(ui i=0; i<size; i++ )
Y[i] = f( X[i] );
}
Dabei ist f( X[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 VF_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 Y-Werte mit einen für jedes Experiment verschiedenen Wert C skaliert sein. In diesem Falle muss 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 ) Y[i] *= A[5]; else Y[i] *= A[6];
Zusätzlich zu der Modell-Funktion benötigt VF_multiNonlinfit die partiellen Ableitungen von Y 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 VF_multiNonlinfit_autoDeriv numerisch berechnet werden.
| Partielle Ableitungen für C/C++ |
void _cdecl MyDerivs( fVector dYdAi, fVector X, ui size, unsigned ipar, unsigned iexperiment, fVector A, VF_NONLINFITWORKSPACE *ws )
{
ui i;
switch( ipar )
{
case 0: for(i=0; i<size; i++ )
dYdAi[i] = part_derv_of_Y_w_resp_zu_A0( X[i] );
break;
case 1: for(i=0; i<size; i++ )
dYdAi[i] = part_derv_of_Y_w_resp_zu_A1( X[i] );
break;
default: /* für alle unbekannten Ableitungen: */
VF_multiNonlinfit_autoDeriv(
dYdAi, X, size, ipar, iexperiment, A, ws );
}
}
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 VF_multiNonlinfit wird dann etwa so aussehen:
VF_multiNonlinfit( A, AStatus, npars, ExpList, 2, MyFunc, MyDerivs, &FitOpts, &WorkSpace );
oder vereinfacht
VF_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 VF_multiNonlinfit:
VF_multiNonlinfit( A, AStatus, npars, ExpList, 2, MyFunc, NULL );
| Modell-Funktion für Pascal/Delphi |
In Pascal/Delphi muss die Modell-Funktion wie folgt geschrieben werden:
procedure MyFunc( Y, X:fVector; size:UIntSize; iexperiment:UInt; A:fVector );
var i:UIntSize;
begin
for i:=0 to size-1 do
VF_Pelement( Y, i )^ := f( VF_element( X, i ) );
end;
Dabei ist f( Xi ) 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 VF_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 Y-Werte mit einen für jedes Experiment verschiedenen Wert C skaliert sein. In diesem Falle muss 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
VF_Pelement(Y,i)^ := VF_element(Y,i) * VF_element(A,5)
else VF_Pelement(Y,i)^ := VF_element(Y,i) * VF_element(A,6);
Zusätzlich zu der Modell-Funktion benötigt VF_multiNonlinfit die partiellen Ableitungen von Y 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 VF_multiNonlinfit_autoDeriv numerisch berechnet werden.
| Partielle Ableitungen für Pascal/Delphi |
procedure MyDerivs( dYdAi, X:fVector; size:UIntSize; ipar, iexperiment:UInt; A:fVector; ws:PVF_NONLINFITWORKSPACE );
var i:UIntSize;
begin
case ipar of
0: begin
for i:=0 to size-1 do
VF_Pelement( dYdAi, i )^ := part_derv_of_Y_w_resp_zu_A0(VF_element( X, i )); end;
1: begin
for i:=0 to size-1 do
VF_Pelement( dYdAi, i )^ := part_derv_of_Y_w_resp_zu_A0(VF_element( X, i )); end;
else (* für alle unbekannten Ableitungen: *)
VF_multiNonlinfit_autoDeriv(
dYdAi, X, size:UIntSize; ipar, iexperiment, A, ws );
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 VF_multiNonlinfit wird dann etwa so aussehen:
VF_multiNonlinfit( A, AStatus, npars, @ExpList, 2, @MyFunc, @MyDerivs, @FitOpts, @WorkSpace );
oder vereinfacht
VF_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 VF_multiNonlinfit:
VF_multiNonlinfit( A, AStatus, npars, @ExpList, 2, @MyFunc, nil );
In der gewichteten Variante VF_multiNonlinfitwW muss der Vektor ExpList[i].InvVar für jedes Experiment den Kehrwert der Varianzen der einzelnen X-Y -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 zusammengefasst und, im Spezialfall von VF_multiNonlinfit, hier beschrieben. |
|