K. Taubert, W. Wiedl: Matlab Differentialgleichungen

1. Integratoren für den allgemeinen Fall.

Matlab umfaßt meherere Integratoren für Anfangswertprobleme bei Systemen gewöhnlicher Differentialgleichungen 1. Ordnung:

GIF-Datei mit formaler Systembeschreibung GIF-Datei mit Anfangswerten

die im einfachsten Falle alle durch:

   [t,y] = Integrator(M-Function, t-Intervall, Anfangswerte);
aufgerufen werden. Dabei sind: Vom Anwender wird also erwartet:
  1. die Formulierung des Problems in der angegebenen Form,
  2. die Wahl eines geeigneten Integrators.

1.1 Formulierung des Problems.

Beispiel 1.1

Ein Standardbeispiel, das wir später auch für spezielle Integratoren verwenden werden, ist die 'van der Pol-Differentialgleichung'.
van der Pol-Differentialgleichung
Dieses System 2. Ordnung muß in einer M-Function als System 1. Ordnung beschrieben werden. Wir setzen:
   y1'(t) = y2(t)
und erhalten für µ=2 damit:
   y1' = y2
   y2' = 2*(1-y12) * y2 - y1;
Bedingt durch die Forderung, daß der Funktionswert als Spaltenmatrix geliefert werden muß, formulieren wir die M-Function also:
   function dy = VDP(t,y)
   dy(1,1) = y(2);
   dy(2,1) = 2*(1 - y(1)^2)*y(2) - y(1);
Der Aufruf des Integrators und die
graphische Ausgabe der Lösung erfolgen dann z.B. durch:
   [t,y] = ode23('VDP',[0 20],[2; 0]);
   plot(t,y)

Beispiel 1.2

Ein weiteres Standardbeispiel besteht aus den Eulerschen Gleichungen für eine festen Körper ohne externe Kräfte. Die M-Function lautet:
   function dy=RIGID(t,y)
   dy = [ y(2)*y(3);
         -y(1)*y(3);
         -0.51*y(1)*y(2)];
Der Funktionswert wird hier als ganzes erzeugt und nicht elementweise wie in
Beispiel 1.1. Der Aufruf und die graphische Darstellung erfogt dann in der Form:
   [t,y] = ode45('RIGID',[0;12],[0 1 1]);

 

In den neuesten Versionen von Matlab (seit Release 11) ist die möglich, die obigen Integratoren auch für Probleme zu nutzen, die in der Form:

M(t) y'(t) = F(t,y);  y(0) = y0
gegeben werden. Die Matrix M(t) wird in diesem Zusammenhang als Massenmatrix bezeichnet und muß nicht-singulär sein. Die vorgegebene Formulierung des Problems erlaubt daher nicht die Behandlung von Algebro-Differentialgleichungen, ist aber von Vorteil, wenn die Massenmatrix dünn besetzt ist, da die inverse Matrix einer dünn-besetzten Matrix ist in der Regel voll bzw. dicht besetzt ist.

Wenn ein Problem mit Massenmatrix formuliert ist, muß dies den Integratoren mitgeteilt werden. Man benutzt dazu beim Aufruf der Integratoren einen 4. Stellungsparameter, dessen Werte man mit Hilfe einer zusätzlichen odeset-Anweisung besetzt:

   opt = odeset(...Eigenschaften festlegen...);
   [t,y] = integrator('M-File',Integrationsintervall,Anfangswerte,opt); 
   plot(t,y)
Um zu signalisieren, daß das Problem mit Massenmatrix formuliert wurde, muß man der Eigenschaft Mass in der odeset-Anweisung einen geeigneten Wert zuweisen. Mögliche Werte von Mass sind:
   'none' | 'M' | 'M(t)' | 'M(t,y)' 
wobei 'none' der voreingestellte Wert ist und signalisiert, daß keine Massenmatrix benötigt wird. Die drei anderen Werte signalisieren dagegen, daß eine solche Matrix benötigt wird und von welchen Parametern die Massenmatrix abhängt.

Die Massenmatrix selbst fragt der Integrator vom M-File ab, das zu diesem Zwecke mit einem dritten Stellungsparameter formuliert werden m&uszlig;:

   function dy=name(t,y,flag)
Der 3. Stellungsparameter, hier flag genannt, hat von Aufruf zu Aufruf verschiedene Werte, abhängig davon, welche Daten der Integrator vom M-File abfragt. Falls die Ableitungen abgefragt werden, den Wert '', also einen leeren String, falls die Massenmatrix abgefragt wird, den Wert 'mass'. Das M-File muß die dementsprechenden Werte zurückgeben.

Beispiel 1.3

Wir behandeln hier noch einmal das Problem aus Beispiel 1.2, formulieren diesmal das Problem aber mit der Einheitsmatrix als Massenmatrix. Das M-File kann dann z.B. wie folgt lauten:
   function wert=DRIGID(t,y,flag)
   switch flag
     case ''
       wert = [ y(2)*y(3);
             -y(1)*y(3);
             -0.51*y(1)*y(2)];
     case 'mass'
       wert = [ 1 0; 0 1];
   end
Man beachte, daß der Funktionswert einmal der Vektor der Ableitungen, einmal die Einheitsmatrix ist.

Der Aufruf erfolgt jetzt durch:

   opt = odeset('Mass','M');
   [t,y] = ode113('DRIGID',[0;12],[0 1 1]);
   plot(t,y);
Der Eigenschaft Mass wird hier der Wert 'M' zugewiesen, da die Einheitsmatrix eine konstante Matrix ist.

Bemerkung: In früheren Matlab-Versionen wurden die Eigenschaften der Massenmatrix anders beschrieben. Die hier gegebene Darstellung ist ab Version 5.2 gültig.

1.2 Fehlerkontrolle.

Die Matlab Integratoren benutzen eine Standardtechnik zur Fehlerkontrolle. In jedem Schritt wird der lokale Fehler abgeschätzt und mit einer vom Benutzer vorgegebenen Schranke verglichen.
Lokale Fehlerkontrolle bedeutet, daß der Fehler, der im aktuellen Integrationsschritt entstanden ist, unter der Voraussetzung kontrolliert wird, daß alle benutzten Ausgangswerte exakt waren.
Wenn also der n+1. Integrationsschritt in (tn,yn) beginnt und eventuell noch die Ergebnisse (tn-1,yn-1) bis (tn-k,yn-k) früherer Integrationsschritte benutzt und selbst als Ergebnis (tn+1,yn+1) liefert, so wird der Fehler, der im Schritt von tn nach tn+1 entsteht unter der Annahme, daß alle Werte (tn,yn) bis (tn-k,yn-k) exakt waren, abgeschätzt und mit der vorgegebenen Fehlerschranke verglichen.

Was abgeschätzt wird, ist also nicht der globale Fehler, die Differenz zwischen exakter Lösung y(tn+1) und berechneter Lösung yn+1, der die Anwender eigentlich interessiert. Brauchbare Abschätzungen des globalen Fehlers sind allerdings schwierig zu implementieren. Die lokale Fehlerabschätzung der Matlab Integratoren liefert in der Regel aber Lösungen mit globalen Fehlern, die grob den angegebenen lokalen Fehlerschranken entsprechen.
Je länger das Integrationsintervall allerdings wird, desto weiter kann der globale Fehler vom lokalen Fehler abweichen.
Größere Abweichungen können sind bei instabilen Problemen zu erwarten. Eine Lösung eines Anfangswertproblems nennen wir dabei stabil, wenn eine kleine Störung des Anfangswertes sich bei den Lösungskurven auch nur durch kleine Abweichungen bemerkbar machen. Falls die kleinen Störungen im Laufe der Zeit sogar herausgedämpft werden, nennen wir die Lösung asymptotisch stabil.

Bei schwierigen (für die Fehlerkontrolle) Problemen, kann es erforderlich sein, das Problem mit höherer Genauigkeit zu rechnen um überhaupt brauchbare Ergebnisse zu erhalten. Die Genauigkeitsanforderungen hängen also nicht nur von den Wünschen der Anwendenden, sondern auch vom zu lösenden Problem ab.

Die Schranken für den lokalen Fehler werden komponentenweise in der Form:

abs(LokalerFehleri) <= max(RelTol*abs(yi),AbsTol(i))
vorgegeben, wobei der skalare Wert RelTol und der Vektor AbsTol mit Hilfe der odeset Anweisung anzugeben sind. Die Voreinstellung für die relative Fehlertoleranz RelTol ist 1e-3, entspricht also 0.1% Genauigkeit. Die absolute Fehlertoleranz AbsTol kann auch als Skalar angegeben werden, wobei dieser dann zu einem geeignet langen Vektor mit lauter gleichen Werten expandiert wird. Der voreingestellte Wert für AbsTol ist 1e-6.
Bei der absoluten Fehlertoleranz ist die Skalierung der einzelnen Lösungskomponenten von Bedeutung. Wenn eine Lösungskomponente abs(yi) kleiner als AbsTol(i) ausfällt, wird der Integrator nicht veranlasst, auch nur eine genaue Stelle für diese Komponente zu berechnen. Dies bedeutet, daß man eigentlich schon vor der Integration wissen muß, in welcher Größenordnung sich die Lösungskomponenten eines Problems bewegen. In vielen Fällen wird man eine Integration mehrfach durchführen müssen, bis man eine geeignete Besetzung von AbsTol gefunden hat.

Anzumerken ist, daß die flops-Angaben von Matlab für den Fall, daß man die Voreinstellungen und den Fall, daß man die voreingestellten Werte für 'AbsTol' und 'RelTol' benutzt differieren.

Beispiel 1.4:

Wir betrachten das Anfangswertproblem:
y'(t) = µ ( y(t) - sin(t) ) + cos(t),   y(0) = 1
für verschiedene Werte von µ. Die exakte Lösung zu diesem Problem ist:
y(t) = sin(t) + exp( µt )
Ein benachbartes Anfangswertproblem:
y'(t) = µ ( y(t) - sin(t) ) + cos(t),   y(0) = 1+d
hat die exakte Lösung:
y(t) = sin(t) + (1+d) exp( µt )
Das Problem ist offensichtlich: Die
zugehörigen Tabellen geben die aufgetretenen globalen relativen Fehler, die benötigten Gleitkommaoperationen und die (systemabhängigen) Laufzeiten bei der numerischen Integration an:

1.3 Schrittweitenkontrolle.

Die Schrittweiten der Integratoren wird über die Fehlerkontrolle und damit im wesentlichen über die Vorgaben der Werte von RelTol und AbsTol gesteuert. Darüber hinaus kann noch die maximale Schrittweite über den Wert von MaxStep vorgegeben und eine Anfangsschrittweite über den Wert von InitialStep vorgeschlagen werden.

Über den Wert von InitialStep kann von Anwenderseite eine obere Schranke für die Größe des 1. Integrationsschrittes vorgegeben werden, die Schrittweite ist immer ein skalarer Wert. Intern benutzten die Integratoren ein Verfahren, das die Weite des 1. Integrationsschrittes anhand der Ableitungen zum Startzeitpunkt abschätzt. Falls dort alle Ableitungen den Wert 0 haben, fehlt dieser Anhaltspunkt und die Integratoren können einen viel zu großen Anfangsschritt wählen, der dann zeitaufwendig korrigiert werden muß.
Die Vorgabe eines Wertes von InitialStep empfiehlt sich also:

Die Wahl eines geeigneten Wertes von InitialStep setzt natürlich voraus, daß man entsprechende Informationen über das Lösungsverhalten hat.

Die Vorgabe eines Wertes für die maximale Schrittweite erfolgt über den Wert von MaxStep und ist immer eine positive skalare Zahl. Sinnvoll ist eine Vorgabe z.B. dann, wenn man die Periode einer Lösung kennt und sicher sein will, daß die Schwingung

1.5 Integrator Ausgabe

Refine-Eigenschaft
Die Refine-Eigenschaft bestimmt, wieviele Ausgabewerte pro Integrationsschritt ausgegeben werden. Der Wert dieser Eigenschaft muß eine ganze Zahl sein. Bei ode45 ist der Default-Wert 4, bei allen anderen Integratoren 1. Mit dem Refine-Wert 1 erhält man bei n Integrationsschritten also n+1 Ausgabewerte, der zusätzliche Wert ist der Wert zum Anfangszeitpunkt. Wenn Sie für eine Graphik glattere Verläufe benötigen, müssen Sie den Refine-Wert erhöhen, das ist weit weniger aufwendig, als die Reduzierung der Fehlertoleranzen. Der 'Refine'-Wert hat keinen Einfluß auf die Schrittweitensteuerung, eventuelle (äquidistante) Zwischenpunkte werden durch Interpolation gewonnen. Der genaue Algorithmus dafür ist nicht veröffentlicht, die Matlab-Literatur gibt jedoch an, daß die zusätzlichen Ausgabewerte von vergleichbarer Genauigkeit wie die Endpunkte der Integrationsschritte sind.
Die Refine-Eigenschaft ist nur wirksam, wenn das Integrationsintervall lediglich durch Anfangs- und Endzeitpunkt beschrieben wird.

Beispiel 1.5

Wir integrieren noch einmal die van der Pol-Gleichung aus
Beispiel 1.1. Die Integration erfolgt einmal mit ode45 ein anderes mal mit ode23. Da der Refine-Wert 1 ist, kann man die verwendeten Schrittweiten als Differenz der Ausgabezeitpunkte ermitteln. Graphisch dargestellt wird die Lösung und die Schrittweiten der Integratoren, man sieht die wesentlich kleineren Schrittweiten von ode23.
   opt = odeset('Refine',1,'AbsTol',1.0e-9,'RelTol',1.0e-6);
   [t1,y1] = ode45('VDP',[0 20],[2 0],opt);
   [t2,y2] = ode23('VDP',[0 20],[2 0],opt);
   subplot(2,1,1)
   plot(t2,y2)
   title('Lösung der VDP-Gleichung mit µ=2')
   subplot(2,1,2)
   n1 = length(t1);
   h1 = t1(2:n1) - t1(1:n1-1);
   n2 = length(t2)
   h2 = t2(2:n2) -t2(1:n2-1);
   plot(t1(1:n1-1),h1,t2(1:n2-1),h2)
   xlabel('ode45/ode23-Schrittweite bei Fehlertoleranz 1.0e-9/1.0e-6')

Listen mit Ausgabezeitpunkten
Das Integrationsintervall haben wir bisher immer in der Form [Anfangswert Endwert] angegeben. Die Ausgabewerte werden dann gesteuert durch:

Alternativ dazu kann man eine Liste von Ausgabezeitpunkten angeben [t0, t1, ... , tn]. Die Zeitpunkte müssen streng monoton steigend oder fallend angeordnet sein. Sobald mehr als 2 Listenelemente angegeben werden, liefern die Integratoren die Ausgabewerte nur zu diesen Zeitpunkten. Der erste Zeitpunkt wird als Startzeitpunkt, der letzte als Endpunkt des Integrationsintervalles interpretiert. Wiederum haben diese Ausgabezeitpunkte, abgesehen vom 1. und letzten, keinen Einfluß auf die Wahl der Integrationsschritte.
Es ist mit dieser Technik nicht möglich nur die Werte am Ende des Integrationsintervalles zu erhalten, es muß immer mindestens 3 Ausgabezeitpunkte geben.
   [t,y] = ode45('VDP',pi*(0:-1:-4),[2; 0]);

Statistiken zur Arbeit der Integrators
Mit Hilfe der Stats Eigenschaft kann jeder Matlab Integrator dazu veranlaßt; werden, genauere Angaben zu seiner Arbeit auszugeben, dies sind im Einzelnen:

  1. die Anzahl der erfolgreichen Schritte,
  2. die Anzahl der Fehlversuche,
  3. wie oft dy = F(t,y) ausgewertet wurde,
  4. wie oft die Jacobi-Matrix dF/dy bzw. eine Näherung dazu aufgestellt wurde,
  5. die Anzahl der LU-Zerlegungen von dF/dy,
  6. wie oft ein lineares Gleichungssystem gelöst wurde.
Die Angaben beziehen sich immer auf das gesamte Integrationsintervall, nicht auf einzelne Integrationsschritte. Die Angaben zu 3 bis 6 werden allerdings nur von den steifen Integratoren ausgegeben, die wir hier noch nicht behandeln.
Die statistischen Ausgaben erfolgen in einen dritten Ausgabewert. Der Default-Wert zur 'Stats'-Eigenschaft ist 'off', der andere mögliche Wert ist 'on'.

Beispiel 1.6:

Wir betrachten noch einmal das Problem von Beispiel 1.3, benutzen jetzt aber den Aufruf:
   opt   = odeset('Mass','M','Stats','on');
   [t,y,S] = ode45('DYRIGID2',Intv,Ynull,opt);
Auf dem Bildschirm erhalten wir die Ausgabe:
    19 successful steps
     2 failed attempts
   127 function evaluations
Im Vektor S sind die Werte [ 19 2 127 0 0 0 ] abgelegt.

Eigene Ausgabefunktionen
Matlab bietet die Möglichkeit, nach jedem Integrationssschritt eine eigene Ausgabefunktion aufzurufen, der Name dieser Funktion, genauer, der Name des M-Files, muß als Wert der Eigenschaft OutputFcn angegeben werden.

   opt = odeset('OutputFcn','Eigenw','Refine',1);   
   [t,y] = ode45('VDP',[0 20],[2 0],opt);
Betont sei, daß mit einer eigenen Ausgabefunktion nicht die Funktionswerte des Integrators beeinflußt werden, im obigen Aufruf also nicht die Werte von t und y.

Der Rückgabewert einer Ausgabefunktion muß ein Skalar mit dem Wert 0 oder 1 sein. Er bestimmt, ob die Integration abgebrochen wird (1) oder fortgesetzt wird (0).

Der Integrator ruft die Ausgabefunktion auf:

Beispiel 1.7:

Wir integrieren die van der Pol-Gleichung aus Beispiel 1.1 und wollen die Integration abbrechen, sobald die Jacobi-Matrix des Systems komplexe Eigenwerte aufweist. Wir benutzen dazu eine M-Funktion, die je nach Aufruf, die Ableitungen dy = F(t,y) oder die Jacobi-Matrix dF/dy liefert.
   function dy = DOUTFUN(t,y,flag)
   global my;
   switch flag
     case ''
       dy = [ y(2);
              my*(1 - y(1)^2)*y(2) - y(1) ];
     case 'Jacobian'
       dy = [ 0.0                     1.0;
              -my*2*y(1)*y(2)-1       my*(1-y(1).^2) ];
   end
Die Ausgabefunktion berechnet die Eigenwerte der Jacobi-Matrix und gibt als Funktionswert 1 (abbrechen) zuück, sobald ein komplexer Eigenwert auftritt, anderenfalls wird als Funktionswert 0 (weiter integrieren) geliefert.
   function out = OUTOUT2(t,y,flag)
   if nargin == 2 | flag == 'init'
     eiw = eig(DOUTFUN(t,y,'Jacobian'))';
     if imag(eiw(1)) ~= 0
       out = 1;
     else
       out = 0;
     end
   end
Das aufrufende Skript lautet:
   global my eiw;
   my = 5.0;
   opt = odeset('Refine',1,'OutputFcn','Outout2', ...
                'AbsTol',1.0e-9,'RelTol',1.0e-6);
   [t,y] =ode45('VDP',[0 20],[2 0],opt);
   plot(t,y)
   title('Lösung der van der Pol-Gleichung für µ=5')
   xlabel('t-Intervall mit realen Eigenwerten')
Zu beachten ist, da&szLig; im Falle eines Refine-Wertes > 1, der Wert des 1. Stellungsoperanden der Ausgabefunktion ein entsprechend langer Vektor ist.

Beispiel 1.8:

In diesem Beispiel sollen die Lösungskurven der van der Pol Gleichung zusammen mit den zugehörigen Eigenwerten der Jacobi-Matrix dargestellt werden. Wir benutzen dasselbe M-File DOUTFUN wie in Beispiel 1.7, die Ausgabefunktion lautet jetzt jedoch:
   function out = OUTOUTF(t,y,flag)
   global my eiw;
   if nargin == 2 | flag == 'init'
     [n1,n2] = size(eiw);
     eiw(n1+1,:) = eig(DOUTFUN(t,y,'Jacobian'))';
     out = 0;
   else
     out = 1;
   end
Das aufrufende Skript ist:
   clear all
   global my eiw;
   my = 5.0;
   opt = odeset('Refine',1,'OutputFcn','Outoutf', ...
                'AbsTol',1.0e-9,'RelTol',1.0e-6);
   [t,y] =ode45('VDP',[0 20],[2 0],opt);
   subplot(3,1,1)
   plot(t,y)
   title('Lösung der van der Pol-Gleichung mit µ=5');
   subplot(3,1,2)
   plot(t,real(eiw))
   subplot(3,1,3)
   plot(t,imag(eiw))
   xlabel('Eigenwerte der Jacobi-Matrix')