MATLAB — E INE E INFÜHRUNG basierend auf den Skripten von • Prof. Dr. Martin Reißel, Fachhochschule Aachen, Standort Jülich • M.Sc. Ivan Cherlenyak und Prof. Dr. Hans-Jürgen Reinhardt, Universität Siegen • Dr. Susanne Teschl, Fachhochschule Technikum Wien • Prof. Dr. Jörn Behrens und Prof. Dr. Armin Iske, Alfred Wegener Institute für Polarund Meeresforschung sowie Universität Hamburg Kapitel 1 Was ist MATLAB Kurz gesagt: MATLAB ist ein Softwarepaket für numerische Berechnungen und für die Visualisierung von Daten im technisch-wissenschaftlichen Bereich. MATLAB wurde in den 70er Jahren an der University of New Mexico und der Stanford University entwickelt um Kurse aus Lineare Algebra und Numerische Analysis zu unterstützen. Der Name (MATrix LABoratory) erinnert noch daran. Heute ist MATLAB ein universelles Werkzeug, das in weiten Bereichen der angewandten Mathematik eingesetzt wird. Man kann MATLAB auf zwei Arten verwenden: • Bei der interaktiven Verwendung werden Anweisungen direkt über die Tastatur eingegeben und sofort ausgeführt. • Für umfangreiche Probleme ist es empfehlenswert, MATLAB als Programmiersprache einzusetzen. Wesentlichen Eigenschaften sind: • die Sprache wird interpretiert, d.h. Übersetzen etc. entfällt • grundlegender Datentyp sind doppeltgenaue Matrizen; Variablen (auch Felder) müssen nicht vereinbart werden • vom Benutzer definierte Funktionen und Unterprogramme werden einfach in Textdateien (m-Files) abgespeichert und können dann wie eingebaute Funktionen benutzt werden 2 3 • auf dieser Basis gibt es zahlreiche Erweiterungen (Toolboxes), die (nach Kauf) eine Unmenge an Funktionalitäten zur Verfügung stellen • ein einfaches Hilfe-System, in dem auch Dokumentationen eigener Funktionen leicht handhabbar sind. Darüber hinaus können auch C- und Fortran-Programme in Form von sogenannten mexFiles von MATLAB ausgeführt werden. Nach dem Hochfahren von MATLAB sollte etwa folgendes Fenster zu sehen sein Abbildung 1.1: Matlab Oberfläche. Das Fenster ist in 5 Bereiche geteilt: • in der Mitte befindet sich das Kommandofenster, in dem der Benutzer seine Befehle eingibt und auch Ausgaben des Programms angezeigt werden 4 • rechts oben werden (bei Einstellung Workspace) alle augenblicklich vorhandenen Variablen mit Typ und Speicherbedarf angezeigt • rechts unten werden (bei Einstellung Command History) alle vom Benutzer eingegebenen Kommandos angezeigt • links oben sind (bei Einstellung Current Directory) alle vom Benutzer in seinem Arbeitsverzeichnis abgelegten m-Files zu sehen • links unten werden Details zu der gewählten Datei angezeigt, z.B. Name der Funktion. Für jedes neue Projekt sollte ein eigenes Verzeichnis angelegt werden. Damit MATLAB in diesem Verzeichnis arbeitet, muss am oberen Rand des Fensters unter “Current Directory“ das jeweilige Verzeichnis eingestellt werden. Abbildung 1.2: Aktuelles Verzeichnis. 1.1 Hilfe MATLAB verfügt über umfangreiche Online-Hilfen. Mit diesen erhalten Sie detaillierte Informationen zur Funktionalität von MATLAB. Die Hilfsysteme können mit den Befehlen help, helpwin und helpdesk aufgerufen werden. • Das help- Kommando. >> help name gibt Hilfetext zur Variable oder Funktion “name“ aus. Alle MATLAB-Funktionen sind in logische Gruppen (Themen) eingeteilt, und die MATLAB-Verzeichnisstruktur basiert auf dieser Einteilung. Gibt man alleine “help“ ein, so wird diese Gruppierung angezeigt. Hiermit kann man sich nun weiter vortasten. 5 • Das lookfor- Kommando Basierend auf einem Schlüsselwort können Sie mit dem lookfor-Kommando nach Funktionen suchen. Dabei wird die erste Zeile des help-Textes jeder MATLABFunktion ausgegeben, die das angegebene Schlüsselwort beinhaltet. Sucht man zum Beispiel Informationen über Splines, dann gibt man am Prompt >> lookfor spline an. • Das Hilfefenstersystem helpwin Gibt man den Befehl >> helpwin ein, so wird ein neues Windowsfenster geöffnet (siehe Abbildung 1.3), das verwendet werden kann, um interaktive Hilfe über MATLAB Funktionen zu erhalten. Das helpwin-System ist das interaktive Analog des help-Systems. Durch Doppelklicken auf ein Thema in diesem Textfenster, erhält man eine Liste zu diesem Thema. Der helpwin-Befehl läßt sich analog dem help-Befehl mit dem gewünschten Thema bzw. der gewünschten Funktion direkt aufrufen. • Das Hilfesystem helpdesk Das MATLAB-Hilfesystem helpdesk liefert HTML-basierte Hilfe. Diese HTMLDokumente haben den Vorteil, dass sie Grafiken beinhalten können und Verweise auf andere Dokumente leicht machbar sind. 6 Abbildung 1.3: Help. Kapitel 2 Erste Schritte Der MATLAB-Prompt (die Eingabeaufforderung) wird durch die Zeichen “»“ gekennzeichnet. Das Semikolon “;“ trennt mehrere Befehle in einer Zeile, und unterdrückt die Ausgabe von Werten, wohingegen das Komma “,“ Befehle trennt, aber die Werte auch ausgibt. Zuweisungen erfolgen durch den Operator “=“. Drei Punkte am Zeilenende “...“ bedeutet, dass der Ausdruck in der nächsten Zeile weitergeht. Kommentare werden mit “%“ eingeleitet. MATLAB unterscheidet zwischen Groß- und Kleinbuchstaben, d.h. “Antwort“ und “antwort“ sind unterschiedliche Variablennamen. Folgende Regeln sind bei der Definition von Variablen zu beachten: • Ein Variablenname darf keine Sonderzeichen außer dem Unterstrich enthalten. • Das erste Zeichen muß ein Buchstabe sein. • Der Name darf nicht mehr als 19 Zeichen enthalten (der Rest wird automatisch abgeschnitten). D.h. “test_3“ wäre ein gültiger Variablenname, aber “Summe_a+b“ oder auch “5_Test“ sind keine gültigen Variablennamen. 7 8 2.1 Einfache Rechenoperationen Alle Anweisungen werden nach dem Prompt eingegeben und mit “Return“ bestätigt. MATLAB nennt das Ergebnis ans (kurz für answer): >> 12+3*1/8 ans = 12.3750 Addition (+), Subtraktion (-), Multiplikation (*) und Division (/) werden wie gewohnt bezeichnet und verwendet. Benötigt man einen Ausdruck häufiger, so ist es sinnvoll eine Variable anzulegen: >> a_1 = 12+3*1/8; b_1 = 9/5+2/3 b_1 = 2.4667 Durch das Semikolon hinter der ersten Zuweisung wird die Ausgabe unterdrückt. Trotzdem ist die Variable “a_1“ definiert. Der Wert einer Variablen kann auch abgefragt werden: >> a_1 a_1 = 12.3750 Wichtig: Bei der Multiplikation darf das Multiplikationszeichen (*) nicht weggelassen werden: 9 >> 8a_1 ??? 8a_1 | Error: Unexpected MATLAB expression. wohingegen >> 8*a_1 ans = 99 2.2 Komplexe Zahlen Komplexe Zahlen können wie reelle Zahlen eingegeben werden: >> z1 = 3+4*j, z2 = 1-3i z1 = 3.0000 + 4.0000i z2 = 1.0000 - 3.0000i Beachten Sie, dass die imaginäre Einheit als “i“ oder “j“ eingegeben werden kann (intern wird “i“ verwendet). Außerdem kann das Multiplikationszeichen zwischen “i“ und dem Imaginärteil weggelassen werden. Im Fall a = 1; b = 2; z = a + b ∗ j ist das Multiplikationszeichen zwischen b und “j“ jedoch notwendig. Addition, Subtraktion, Multiplikation, Division und Funktionswerte werden wie bei den reellen Zahlen gebildet: 10 >> z = z1/3 + z2*z1^2 z = 66.0000 +46.3333i >> sqrt(1+2i) ans = 1.2720 + 0.7862i Die konjugiert komplexe Zahl zu z erhalten wir mit >> z = 1+3i; conj(z) ans = 1.0000 - 3.0000i Auch durch Anfügen eines Apostrophs ’ wird eine Zahl komplex konjugiert. Das ist ein Spezialfall - im allgemeinen bewirkt A′ , daß die Matrix A transponiert und komplex konjugiert wird. >> z’ ans = 1.0000 - 3.0000i Absolutbetrag und Phasenwinkel berechnet man mit abs(z) und angle(z), wobei der Phasenwinkel von MATLAB im Bogenmaß ausgegeben wird. >> abs(z) ans = 11 3.1623 >> angle(z) ans = 1.2490 2.3 Vektoren Vektoren werden genau wie Skalare als spezielle Matrizen behandelt. Dabei wird strikt zwischen Zeilenvektoren (1 × n Matrizen) und Spaltenvektoren (n×1 Matrizen) unterschieden. Die Eingabe von Zeilenvektoren erfolgt durch >> z=[1 2 5 7] z = 1 2 5 7 bzw. >> z=[1,2,5,7] z = 1 2 5 7 Bei Spaltenvektoren müssen die Komponenten durch “;“ getrennt werden, d.h. >> s=[1;2;3;4] s = 1 2 3 4 12 Mit dem Befehl size ermittelt man das Format einer Variablen. Für s und z aus dem vorherigen Beispiel erhalten wir >> size(z),size(s) ans = 1 4 ans = 4 1 d.h. z ist eine 1×4 Matrix, s eine 4×1 Matrix. Man beachte, daß das Ergebnis von size selbst ein Vektor mit zwei Komponenten ist. Zeilenvektoren werden mit Hilfe des Transpositionsoperators ’ in Spalten umgewandelt und umgekehrt: >> z,s z = 1 2 5 7 s = 1 2 3 4 >> z’ ans = 1 2 5 7 >> s’ ans = 1 2 3 4 Vektoren gleichen Formats können addiert, subtrahiert und mit einer reellen Zahl multipliziert werden: 13 >> z=[1,2,5,7] z = 1 2 5 7 >> z2=[5:8] z2 = 5 6 7 8 >> z+z2 ans = 6 8 12 15 >> z*4 ans = 4 8 20 28 Das Skalarprodukt ergibt sich als Matrixmultiplikation eines Zeilenvektors mit einem Spaltenvektor: >> z,s z = 1 2 5 7 s = 1 2 3 4 >> z*s ans = 48 d.h. das Ergebnis ist eine 1×1 Matrix. Umgekehrt erhalten wir eine n×n Matrix, in unserem Beispiel also >> s*z ans = 14 1 2 5 7 2 4 10 14 3 6 15 21 4 8 20 28 Daneben gibt es die Möglichkeit, zwei Vektoren komponentenweise zu multiplizieren, indem statt * der Operator .* benutzt wird: >> z=[1,2,5,7] z = 1 2 5 7 >> z2=[5:8] z2 = 5 6 7 8 >> z.*z2 ans = 5 12 35 56 Auf ein einzelnes Element eines Vektors wird in Array-Notation zugegriffen: >> z=[1,2,5,7] z = 1 2 5 7 >> z(3) ans = 5 Man beachte die runden Klammern! Die Indizierung beginnt bei 1 (nicht bei 0). Analog kann man komplette Teilvektoren selektieren, z.B. >> z=[1,2,5,7] z = 1 2 5 7 >> z(1:3) 15 ans = 1 2 5 d.h. z(1 : 3) selektiert die Komponenten mit Index 1, 2, 3. Soll ein nicht zusammenhängender Bereich selektiert werden, so benutzt man einfach einen Indexvektor >> z([1,3,4]) ans = 1 5 7 Neben dem Auswählen von Teilvektoren können Vektoren auch erweitert werden: >> z=[1,2,5,7] z = 1 2 5 7 >> z=[z,8,9] z = 1 2 5 7 8 9 >> z2=[5:8] z2 = 5 6 7 8 >> z=[z,z2] z = Columns 1 through 7 1 2 5 7 8 9 5 Columns 8 through 10 6 7 8 Bei allen Operationen mit Vektoren muß darauf geachtet werden, dass die (Matrix-) Formate mathematisch korrekt gewählt sind, d.h. man kann keine Spalten- zu Zeilenvektoren addieren etc. Für Vektoren sind zahlreiche spezielle Funktionen implementiert, so z.B. die Norm eines Vektors: >> z=[1,2,5,7] 16 z = 1 2 5 7 >> norm(z) ans = 8.8882 2.4 Matrizen Für Matrizen gelten analoge Aussagen wie für Vektoren. Mit >> a = [1 2 3;4 5 6] a = 1 2 3 4 5 6 definiert man also eine 2×3 Matrix. Matrizen können auch aus Zeilen- bzw. Spaltenvektoren zusammengesetzt werden: >> z1=[3 2 1] z1 = 3 2 1 >> z2=[6 5 4]; >> b=[z1;z2] b = 3 2 1 6 5 4 Man beachte, dass Zeilen mit “;“ aber Spalten mit “,“ getrennt werden müssen. Zur Selektion einzelner Elemente wird wieder Array-Notation benutzt, so dass für die Matrix b aus dem letzten Beispiel folgt >> b(2,1) ans = 6 17 Analog zu Vektoren können Untermatrizen ausgewählt bzw. Matrizen erweitert werden. Addition und Subtraktion zweier Matrizen sowie Multiplikation einer Matrix mit einer reellen Zahl sind wie üblich definiert. Wie bei Vektoren können zwei Matrizen mit Hilfe der Operatoren .* bzw. ./ komponentenweise multipliziert bzw. dividiert werden: >> a,b a = 1 2 3 4 5 6 b = 3 2 1 6 5 4 >> a.*b ans = 3 4 3 24 25 24 Zum Transponieren einer Matrix benutzt man wieder den Operator ’. Existiert die Inverse A−1 , so ist die Lösung x von A∗x = b gegeben durch x = A−1 ∗b. A ist invertierbar genau dann, wenn die Determinate von A ungleich Null ist: >> A= [3 4 -2; -1 2 8; 2 0 -5], b = [4; -1; 3] A = b = 3 4 -2 -1 2 8 2 0 -5 18 4 -1 3 >> det(A) ans = 22 Wir erhalten die Inverse A−1 mit inv(A): >> x = inv(A)*b x = 2.1818 -0.5000 0.2727 MATLAB bietet noch eine andere Schreibweise für x = A−1 ∗ b: >> x = A\b x = 2.1818 -0.5000 0.2727 Das Symbol “\“ bezeichnet die sogenannte Linksdivision (left division). Der Name kommt daher, dass nun der Nenner links steht und der Bruchstrich nach links geneigt ist. Hier steht A\ sozusagen für die Inverse von A. Im Fall von Skalaren ist die Linksdivision >> 2\3 19 ans = 1.5000 gleich der Rechtsdivision 3/2 (die Multiplikation von Skalaren ist ja kommutativ). Bei Matrizen aber ist inv(A) ∗ b (Linksdivision) ungleich b ∗ inv(A) (Rechtsdivision), der letzte Ausdruck ist nämlich gar nicht definiert. Daher erhalten wir eine Fehlermeldung, wenn wir eingeben: >> b/A ??? Error using ==> / Matrix dimensions must agree. Die Verwendung von x = A\b anstelle von x = inv(A) ∗ b hat verschiedene Vorteile: • Erstens werden bei Eingabe von A\b weniger interne Rechenschritte durchgeführt (es wird das Gaußsche Eliminationsverfahren verwendet). Daher erhält man so vor allem bei größeren Problemen schneller eine Lösung. • Zweitens liefert die Eingabe von x = A\b auch dann eine Lösung, wenn das Gleichungssystem nicht eindeutig lösbar ist (und daher die Inverse A−1 nicht existiert). Im Fall eines überbestimmten Systems erhält man zum Beispiel eine Lösung, die den quadratischen Fehler von Ax − b = 0 minimiert. Es gibt einige Funktionen zum einfachen erzeugen spezieller Matrizen: >> ones(2,3) ans = 1 1 1 1 1 1 >> zeros(3,2) ans = 0 0 0 0 20 0 0 >> eye(3) ans = 1 0 0 0 1 0 0 0 1 >> rand(3,2) ans = 0.4398 0.3651 0.3400 0.3932 0.3142 0.5915 MATLAB erlaubt es, daß Funktionen mehrere Ergebniswerte liefern, die in einem Vektor zusammengefasst werden. Ein Beispiel dafür ist die (eingebaute) LU-Zerlegung einer Matrix A, d.h. P A = LU , wobei A die Eingabe und P, L, U Ausgabewerte sind. Ein entsprechender Aufruf der Funktion lu sieht wie folgt aus: >> A=3*eye(3)+ones(3) A = 4 1 1 1 4 1 1 1 4 >> [L,U,P] = lu(A) L = 1.0000 0 0 0.2500 1.0000 0 0.2500 0.2000 1.0000 U = 4.0000 1.0000 1.0000 0 3.7500 0.7500 0 0 3.6000 P = 21 1 0 0 0 1 0 0 0 1 Weitere Details sind mit help lu zu erhalten. Darüberhinaus sind die meisten Standardfunktionen (exp, sin, cos, etc.) auf Matrizen definiert, wobei sie jeweils komponentenweise angewandt werden. Bei allen Operationen mit Matrizen muss darauf geachtet werden, dass die Matrix-Formate mathematisch korrekt gewählt sind. 2.5 Lösung von Gleichungen Die Anweisung solve(f,’x’) löst die symbolische Gleichung f nach x auf. Kommt nur eine Variable vor, so wird automatisch nach ihr aufgelöst und es genügt der Befehl solve(f). • Die lineare Gleichung 3x + 4 = 17 wird gelöst mit: >> solve(’3*x + 4 = 17’) ans = 13/3 Die einfachen Anführungszeichen sind hier notwendig, damit das Gleichheitszeichen nicht als Zuweisung interpretiert wird. • Geben wir beim nächsten Beispiel, der Exponentialgleichung 5x−1 = 10, eine der Zahlen als Kommazahl ein: >> f = ’5^(x-1) = 10’; solve(f) ans = log(5, 10) + 1 22 im Gegensatz zu >> f = ’5.0^(x-1) = 10’; solve(f) ans = 2.4306765580733930506701065687640 Nun wird, da die Zahl 5 in der Form 5. eingegeben worden ist, auch das Ergebnis numerisch ausgegeben. Auch mit double kann ein numerisches Ergebnis ausgegeben werden. • Mehrere Lösungen gibt es in folgendem Beispiel, bei dem die Schnittpunkte von tan(2x) und sin(x) berechnet werden: >> solve(’tan(2*x) = sin(x)’) ans = acos(1/2 - 3^(1/2)/2) acos(3^(1/2)/2 + 1/2) 0 -acos(1/2 - 1/2*3^(1/2)) -acos(1/2*3^(1/2) + 1/2) >> double(ans) ans = 1.9455 0 + 0.8314i 0 23 -1.9455 0 - 0.8314i Es werden also sowohl die reellen als auch die komplexen Lösungen ausgegeben! Natürlich kann auf eine bestimmte Lösung zugegriffen werden: >> w = ans(2) w = 3.1416 • MATLAB kann nicht immer alle Lösungen ausgeben. So hat zum Beispiel die trigonometrische Gleichung sin(3x + 1.2) = 0 unendlich viele Lösungen: >> solve(’sin(3*x + 1.2) = 0’) ans = -.40000000000000000000000000000000 MATLAB berechnet hier aber nur eine Nullstelle! • Ein Gleichungssystem bestehend aus den symbolischen Gleichungen g1, g2, g3 wird mit solve(g1,g2,g3,’x,y,z’) nach den Variablen x, y und z aufgelöst. Kommen sonst keine Variablen vor, so genügt die Anweisung solve(g1,g2,g3): >> g1 = ’x + y + z = 0’; >> g2 = ’4*x + 5*y + z - 3 = 0’; >> g3 = ’-2*x + y - 3*z - 5 = 0’; >> [x y z]= solve(g1,g2,g3) x = -1 24 y = 3/2 z = -1/2 2.6 Ableiten Die Anweisung diff bildet die Ableitung eines symbolischen Ausdrucks : >> syms x; diff(cos(x)) ans = -sin(x) >> diff(sqrt(5*x^2 - 7*x + 4)) ans = (10*x - 7)/(2*(5*x^2 - 7*x + 4)^(1/2)) Im nächsten Beispiel kommen in der Funktion zwei Variablen, x und t, vor. Wir müssen daher angeben, nach welcher Variablen differenziert werden soll: >> syms t; diff(3*x*t,x) ans = 3*t 25 Möchte man eine höhere Ableitung berechnen, so gibt man das zusätzlich in der Klammer an: >> diff(cos(x),2) ans = -cos(x) Hier wird 2-mal differenziert. 2.7 Integration Mit der Anweisung int wird ein symbolischer Ausdruck integriert: >> syms x; int(log(x)) ans = x*(log(x) - 1) Nun wollen wir y = t ∗ x3 nach t integrieren. Da hier zwei Variable t und x vorkommen, müssen wir angeben, dass wir nach t integrieren wollen: >> syms t; int(t*x^3,t) ans = (t^2*x^3)/2 Um bestimmt zu integieren, etwa von 0 bis 1, geben wir zusätzlich die Integrationsgrenzen an: >> int(x^2,0,1) 26 ans = 1/3 2.8 Grenzwertbestimmung Grenzwerte (auch einseitige) können ebenfalls symbolisch mit der limit-Anweisung berechnet werden: >> syms x a; limit(sin(a*x)/x, x,0) ans = a Das erste Argument gibt hierbei die Funktion an, deren Grenzwert bestimmt werden soll. Das zweite und dritte Argument spezifizieren welche Variable sich welchem Wert nähern soll. Durch Hinzufügen von “right“ oder “left“ werden die entsprechenden einseitigen Grenzwerte bestimmt: >> syms t; limit(1/(t-1),t,1,’right’) ans = Inf Kapitel 3 Graphiken und Funktionen 3.1 Graphiken Mit der Funktion plot können in MATLAB Polygonzüge durch gegebene x-y Wertepaare gezeichnet werden. Um den Graphen von sin(x) auf dem Intervall [0, 2π] zu zeichnen konnen wir folgende Kommandos benutzen: >> x=[0:0.1:2*pi]; >> y=sin(x); >> plot(x,y) Mit dem ersten Befehl werden x-Werte zwischen 0 und 2π mit Abstand 0.1 erzeugt. Der zweite Befehl generiert die zugehörigen Funktionswerte. Mit plot(x,y) öffnet sich ein neues Fenster und der Polygonzug wird blau in ein Koordinatensystem eingezeichnet (siehe Abbildung 3.1). Erzeugen wir anschließend einen zweiten Satz von Funktionswerten z.B. für cos(x) und plotten den neuen Graphen, so erscheint er im selben Grafikfenster, aber die alte Grafik wird vorher gelöscht. Um beide Kurven ins selbe Grafikfenster zu zeichnen, müssen wir den Befehl “hold on“ benutzen. Nach “hold on“ erfolgen sämtliche plot Ausgaben ins selbe Koordinatensystem im momentan aktiven Grafikfenster. Das kann durch “hold off“ wieder rückgängig gemacht werden, d.h. nach “hold off“ wird bei jedem plot Befehl der Fensterinhalt zuerst gelöscht. Wenn also nacheinander erst der sinus (in blau) und dann der cosinus (in rot) ins selbe Fenster gezeichnet werden soll, dann benutzen wir: 27 28 Abbildung 3.1: sin(x). >> x=[0:0.1:2*pi]; >> y=sin(x); >> plot(x,y) >> hold on >> z=cos(x); >> plot(x,z,’r’) >> hold off und erhalten den Graphen in Abbildung 3.2. Alternativ geht auch >> x=[0:0.1:2*pi]; >> y=sin(x); >> z=cos(x); >> plot(x,y,x,z,’r’) Eine Funktion kann auch gezeichnet werden, ohne daß Datenpunkte angegeben werden müssen. Dies ist mit der Anweisung fplot möglich. Mit ihr kann man Funktionen zeichnen, ohne vorher einen Vektor x definieren zu müssen. MATLAB wählt die Stellen, an denen die Funktionswerte berechnet werden, automatisch. Gezeichnet wird die Funktion hier für −20 ≤ x ≤ 20 mit einem sichtbaren Wertebereich von −0.4 ≤ y ≤ 1.2 (siehe Abbildung 3.3). 29 Abbildung 3.2: cos(x) und sin(x) im gleichen Koordinatensystem. >> fplot(’sin(x)./x’, [-20,20,-0.4,1.2]) Abbildung 3.3: sin(x)/x. Es kann vorteilhaft sein, eine oder beide Achsen eines rechtwinkligen Koordinatensystems logarithmisch zu skalieren. So wird eine Exponentialfunktion y = aebx in einem „ordinatenlogarithmischen Papier“ (d.h. die y-Achse ist logarithmisch geteilt) als Gerade dargestellt. >> x = linspace(0,10,50); 30 >> y = 3*exp(-0.5*x); >> semilogy(x,y); grid Hier besteht der Vektor x aus 50 Werten im gleichen Abstand, wobei der erste Wert 0 und der letzte Wert 10 ist. Fehlt die Angabe für die Anzahl der Werte, so wird dafür 100 genommen. Abbildung 3.4 zeigt das Resultat. Abbildung 3.4: Semilogplot von y = aebx . Will man eine Funktion z = f (x, y) graphisch veranschaulichen, so kann man den Graph dieser Funktion, eine Fläche, über der (x, y)-Ebene zeichnen. Dazu ist anzugeben, über welchem x-Bereich und y-Bereich gezeichnet werden soll. Wir wollen die Funktion z = xy zuerst sehr grobflächig als Maschenplot (Drahtgitter) über den folgenden 15 Gitterpunkten (−2/−1), (−2/0), ..., (2/1) zeichnen, die aus den fünf x-Werten 2, −1, 0, 1, 2 sowie den drei y-Werten 1, 0 und 1 gebildet werden können. >> x = -2:1:2 >> y = -1:1:1 >> [xx, yy] = meshgrid(x,y) x = 31 -2 -1 0 1 2 -1 0 1 -2 -1 0 1 2 -2 -1 0 1 2 -2 -1 0 1 2 -1 -1 -1 -1 -1 0 0 0 0 0 1 1 1 1 1 y = xx = yy = Von besonderer Bedeutung ist hier die Anweisung meshgrid (mesh = Masche, grid = Gitter). Es erzeugt zwei Matrizen, hier xx und yy genannt. Einander entsprechende Elemente dieser beiden Matrizen bilden gerade die beiden Koordinaten unserer Gitterpunkte. Anwendung der Punktmultiplikation ergibt: >> z = xx.*yy z = 2 1 0 -1 -2 0 0 0 0 0 32 -2 -1 0 1 2 Dies sind die gewünschten Funktionswerte. Zuletzt soll jeder dieser Funktionswerte über „seinem“ Gitterpunkt als Punkt dargestellt und in x- und in y-Richtung durch Strecken mit den Nachbarpunkten verbunden werden. Wir erhalten den Maschenplot oder das Drahtmodell der Funktion. Dies erfolgt mit Hilfe der Anweisung mesh: >> mesh(x,y,z) 2 1 0 −1 −2 1 0.5 2 1 0 0 −0.5 −1 −1 −2 Abbildung 3.5: Maschenplot von f(x,y)=xy. x und y geben die x- bzw. die y-Werte der Gitterpunkte an, z die Funktionswerte über den Gitterpunkten. Statt die Punkte durch Strecken zu verbinden, können auch kleine Flächenstücke zwischen den Punkten verwendet werden. Man erhält so ein Kachelmodell der Funktion, indem man mesh durch surf (von surface) ersetzt. Im Folgenden ist die Fläche außerdem durch mehr Gitterpunkte feinmaschiger gezeichnet und die Achsen sind beschriftet. >> x = -2:0.2:2; y = -1:0.2:1; >> [xx,yy] = meshgrid(x,y,z); >> z = xx.*yy; >> surf(x,y,z); xlabel(’x’); ylabel(’y’); zlabel(’z’) 33 2 z 1 0 −1 −2 1 0.5 2 1 0 0 −0.5 y −1 −1 −2 x Abbildung 3.6: Surfaceplot von f(x,y)=xy. Der plot Befehl läßt noch zahlreiche Optionen zu. Nach dem Zeichnen von Grafiken können diese auch noch mit dem title bzw. legend Befehl beschriftet werden. Außerdem kann der Inhalt eines Grafikfensters auch in vielen gängigen Grafikformaten (ps, jpeg, etc.) abgespeichert werden. Details sind mit der help Funktion zu erfahren. 3.2 Funktionen Funktionen sind analog zu anderen prozeduralen Programmiersprachen aufgebaut, d.h. die Schnittstelle wird durch Funktionsname, Eingabe- und Ergebnisparameter festgelegt, wobei keine Typen angegeben werden müssen. Der File-Name und der Funktionsname müssen übereinstimmen. In der Regel wird jede Funktion in ein eigenes m-File in den Arbeitsbereich gelegt. Als Beispiel betrachten wir die Definition der Funktion f (x) = 0.01 ∗ (50 − x) ∗ x Um ein neues m-File zu erzeugen klickt man mit der rechten Maustaste in das linke obere Fenster (Current Directory), worauf ein Menü erscheint, in dem der Punkt “New File – Blank M-File“ angewählt werden muß. Anschließend wird ein File mit einem DefaultNamen generiert, den wir z.B. auf “f.m“ ändern. Durch Doppelklick auf das f.m Icon wird die Datei nun in einem gesonderten Editor-Fenster geöffnet. 34 Abbildung 3.7: Neues m-file. Als erstes definieren wir in der ersten Zeile die korrekte Schnittstelle für unsere Funktion, d.h. function y = f(x) da wir einen Eingabe- und einen Ausgabeparameter benutzen wollen. Die nächsten Zeilen sollte man für Funktionsdokumentation (Kommentarzeilen werden mit % eingeleitet) nutzen (nicht zwingend notwendig, aber sinnvoll). Rufen wir später help f auf, so wird diese Dokumentation angezeigt. Wir können unsere Funktion f z.B. wie folgt vereinbaren (siehe Abbildung 3.8): Die Variablen a und g, die in der Funktion vereinbart sind, werden als lokale Variablen behandelt, d.h. außerhalb der Funktion sind sie nicht sichtbar. Man beachte, daß bei der Multiplikation der Operator .* benutzt wurde, damit die Funktion (wie die Standardfunktionen sin, cos, etc.) auch komponentenweise auf Vektoren und Matrizen angewandt werden kann. Das m-File muss explizit abgespeichert werden. Anschließend kann f wie 35 Abbildung 3.8: Definition der Funktion. gewohnt benutzt werden >> f(1) ans = 0.4900 >> x=[1:4] x = 1 2 3 4 >> f(x) ans = 0.4900 0.9600 1.4100 1.8400 Als Hilfetext erhalten wir >> help f 36 y = f(x) berechnet f(x) = 0.01 * (50-x) * x 3.3 Gewöhnliche Differentialgleichungen MATLAB hat mehrere vordefinierte Funktionen zur näherungsweisen Lösung von Anfangswertproblemen für Systeme von Differentialgleichungen erster Ordnung. Eine dieser Funktionen ist ode45 mit Schnittstelle [t,x]=ode45(@f,[t0,te],x0) Die Eingabeparameter sind • f , eine Funktion f (t, x) die von t und x abhängt und die rechte Seite der Differentialgleichung enhält, • [t0, te], ein zweidimensionaler Vektor, der Anfangs und Endzeit enthält, • x0, der Anfangswert. Als Ausgabe erhalten wir einen Vektor t, der Zeitpunkte zwischen t0 und te enthält, sowie x, das die zugehörigen (genäherten) Funktionswerte der Lösung x an den Zeitpunkten von t enthält. Dabei treten folgende Besonderheiten auf: • werden Funktionen als Parameter an andere Funktionen übergeben, so geschieht dies (analog zu C) über einen Funktionszeiger, den wir durch das “@“ Zeichen vor dem Funktionsnamen erhalten , • f muß immer t und x als Parameter besitzen, auch wenn es nur von einer der beiden Variablen (oder auch von keiner) abhängt, • der Zeitvektor [t0, te] darf sowohl ein Spalten- als auch ein Zeilenvektor sein, • lösen wir ein System, so ist x(t) und damit auch x0 vektorwertig; ode45 verlangt, daß es sich hierbei um Spaltenvektoren handelt. 37 Um das Grenzpopulationsproblem x’ = a*(g-x)*x, x(0)= 10 für a = 0.01, g = 50 auf dem Zeitintervall T = [0, 20] anzunähern, ändern wir zunächst unsere oben definierte Funktion f ab zu function y = f(t,x) %y = f(t,x) % berechnet f(t,x) = 0.01 * (50-x) * x a=0.01; g=50; y=a*(g-x).*x; und benutzen dann folgende Befehle >> T=[0,20]; >> x0=10; >> [t,x]=ode45(@f,T,x0); >> plot(t,x) so erhalten wir als Ausgabe den Graphen in Abbildung 3.9. Um die Modellparameter a und g nicht fest in f kodieren zu müssen, vereinbart man sie als globale Variablen. Dazu muss f zuerst mitgeteilt werden, dass es sich um globale Variablen handelt: function y = f(t,x) %y = f(t,x) % berechnet f(t,x) = a * (g-x) * x global a g; y=a*(g-x).*x; Zusätzlich muß im Kommandofenster ebenfalls der “global“ Befehl abgesetzt werden und anschließend den Variablen ein Wert zugewiesen werden: 38 Abbildung 3.9: Lösung der ODE. >> global a g >> a=0.01;g=75; Dabei sind einige Besonderheiten zu beachten: • nach der “global“ Vereinbarung haben unbedingt Zuweisungen an die globalen Variablen zu erfolgen; eventuell vorher zugewiesene Werte sind nach global nicht sichtbar • alle Änderungen an globalen Variablen, die nach der global Vereinbarung erfolgen, sind systemweit sichtbar • die Variablen in “global“ dürfen nicht durch Komma getrennt werden. Kapitel 4 MATLAB als Programmiersprache Einfache Funktionen, die in m-files abgespeichert werden, haben wir ja bereits im letzten Kapitel gesehen. In diesem Kapitel werden nun wichtige Kontrollmechanismen zur Steuerung des Ablaufes von MATLAB-Anweisungen vorgestellt. Von diesen Mechanismen wird innerhalb von Funktionen massiv gebraucht gemacht. 4.1 If-Abfragen If-Abfragen führen zu bedingten Verzweigungen innerhalb eines Programmablaufes. Die Verzweigung erfolgt in Abhängigkeit eines bestimmten Testresultats. Diese If-Abfragen tauchen typischerweise in Situationen auf, in denen fehlerhafte Eingaben behandelt werden müssen, um größerem Unheil vorzubeugen bzw. die Korrektheit des zugrundeliegenden Algorithmus zu garantieren. Ein klassisches Beispiel für den ersten Fall ist die Operation der Division a/b einer Zahl a dividiert durch b. Man will natürlich nur durch b dividieren, falls b nicht Null ist. Anderenfalls verzichten wir auf die Division. Die entsprechende Folge von MATLAB-Anweisungen sieht für diesen Fall folgendes vor: >> if b ~= 0 c = a/b; end wobei wir angenommen haben, daß die Variablen a und b dem MATLAB-Interpreter bereits bekannt sind. Der Test in dieser If-Abfrage lautet b ˜= 0: es wird geprüft, ob b un39 40 gleich Null ist. Fällt dieser Test positiv aus (d.h. b ist nicht Null), so wird in die Zeile c = a/b; verzweigt. Jede If-Abfrage endet generell mit der Anweisung end. Mit dem obigen Beispiel haben wir bereits den Relationsoperator ˜= (ungleich) kennengelernt. Dieser liefert im obigen Fall das Resultat 1, falls b 6= 0, ansonsten das Resultat 0. Mit anderen Worten: Der Test b ˜= 0 fällt positiv aus, falls die Operation b ˜= 0 den Wert 1 liefert; der Test b ˜= 0 fällt negativ aus, falls die Operation b ˜= 0 den Wert 0 liefert. Weitere Relationsoperatoren in MATLAB sind die folgenden: < kleiner > größer <= kleiner oder gleich >= größer oder gleich == ˜= gleich ungleich Ein weiteres Beispiel, das an das obige anknüpft: Wir wollen der Variablen c den Wert der Division a/b zuweisen, falls b nicht Null ist, anderenfalls wollen wir c den Wert Null zuweisen. Mit MATLAB sieht die entsprechende Anweisungsfolge wie folgt aus. >> if b ~= 0 c = a/b; else c = 0; end Ein weiteres Beispiel: Wir wollen die Vorzeichenfunktion implementieren: Wir weisen der Variablen s den Wert −1 zu, falls die Variable x einen negativen Wert besitzt, s bekommt den Wert 1, falls der Wert von x positiv ist; anderenfalls (d.h. falls x den Wert Null besitzt), bekommt s den Wert Null zugewiesen. >> if x < 0 s = -1; 41 elseif x > 0 s = 1; else s = 0; end 4.2 For-Schleifen Wollen wir eine bestimmte Folge von Anweisungen n-mal hintereinander ausführen, so bietet sich die Verwendung einer sogenannten For-Schleife an. Nehmen wir an, wir wollen elf ganzzahlige Zufallszahlen aus dem Intervall [0, 2] erzeugen (um etwa am Totowettbewerb teilzunehmen). Eine mögliche Implementation mit einer For-Schleife sieht folgendermaßen aus. Beipiel 1: Elf Totozahlen zufällig generieren. Der Vektor x enthält nach Ablauf der For-Schleife die elf Zufallszahlen. >> x = []; >> for k=1:11 x = [x; round(2*rand)]; end >> x x = 2 2 0 2 1 0 1 42 1 2 2 0 Beipiel 2: Wir berechnen die Zahl 12! = 1 ∗ 2 ∗ . . . ∗ 12. Die Hilfsvariable “fac“ wird das Ergebnis enthalten. >> n = 12; >> fac = 1; >> for i=2:n fac = i*fac; end >> fac fac = 479001600 Nun brauchen wir die Variable “fac“ nicht mehr. >> clear fac; 4.3 While-Schleifen Wir haben im vorigen Unterabschnitt For-Schleifen kennengelernt. While-Schleifen sind so ähnlich: Während man bei einer For-Schleife bereits vor deren Ablauf weiß, wie oft man den Schleifenkörper durchlaufen möchte, koppelt man dies bei While-Schleifen an eine Bedingung: Vor jedem Durchlaufen des Schleifenkörpers findet ein Test statt. Fällt der Test positiv aus, so wird der Schleifenkörper durchlaufen. Anderenfalls wird die While-Schleife verlassen (oder erst gar nicht betreten), und die Anweisungen nach der While-Schleife werden ausgeführt. 43 Ein Negativbeispiel: Wir produzieren absichtlich eine Endlosschleife (wenn Sie noch nicht wissen, was eine Endlosschleife ist, dann werden Sie es gleich wissen) mit der folgenden Anweisungssequenz. >> n = 1; >> while n > 0 n = n + 1; end Mit der Tastenkombination CTRL + C kann man die aktuelle Berechnung abbrechen, und bekommt den vertrauten MATLAB-Prompt zurück, d.h. man kann anschließend die begonnene MATLAB-Sitzung fortführen. Ein weniger destruktives Beispiel: Wir wollen zu einer positiven Zahl x die kleinste ganze Zahl n mit der Eigenschaft n < x < n + 1 berechnen. Zur Information: Üblicherweise kürzt man diese Zahl mit [x] ab, und das Symbol [·] wird als Gaußklammer bezeichnet. >> x = 5.3; >> n=0; >> while n+1 <= x n = n+1; end >> n n = 5 Selbstverständlich ist [x] auch für negative reelle Zahlen definiert. Diese mögliche Erweiterung der obigen Implementation von [x]sieht beispielsweise so aus: >> x = - 5.3; >> n=0; 44 >> if x < 0 while n > x n = n-1; end elseif x > 0 while n+1 <= x n = n+1; end end >> n n = -6 Sie werden es zurecht als umständlich empfunden haben, die einzelnen Anweisungen, die mit If-Anweisungen sowie For- und While-Schleifen verbunden sind, Zeile für Zeile an den Interpreter zu übergeben. Wie bereits eingangs erwähnt, tauchen solche Kontrollstrukturen üblicherweise innerhalb von Funktionen auf. 4.4 Abbruch von Schleifen Für den Fall, daß man den Ablauf einer For- oder einer While-Schleife aus irgendwelchen Gründen terminieren lassen möchte, steht in MATLAB der Befehl break zur Verfügung. Diese Art von Abbruch kann sinnvoll sein in Anwendungen, die mit Suchen oder Zählen in Verbindung stehen. Hierzu jeweils ein Beispiel. Beipiel 3: Ein Suchbeispiel mit einer For-Schleife. Man möchte zu einem Zeilenvektor x, dessen Komponenten Zufallszahlen aus dem Intervall [0, 1] sind, dessen kleinsten Index i ermitteln, für den gilt x(i) < 0.5. Falls es keinen solchen Index gibt, so soll i den Wert −1 besitzen. >> n = 10; 45 >> x = rand(1,n) >> i = -1; >> for k=1:n if x(k) < 0.5 i = k; break; end end >> i x = Columns 1 through 5 0.0357 0.8491 0.9340 0.6787 0.7577 0.6555 0.1712 0.7060 Columns 6 through 10 0.7431 0.3922 i = 1 Beipiel 4: Ein Zählbeispiel mit einer While-Schleife. Man möchte solange Zufallszahlen aus [0, 1] erzeugen, bis eine der Zufallszahlen größer als 0.99 ist. Die Anzahl n der Versuche sollen mitgezählt und anschließend anzeigt werden; Falls die Anzahl der Versuche 10 übersteigt, so möchte man aufhören. >> x = rand; >> n = 1; 46 >> while x <= 0.99 if n > 10 n = - 1; break; else x = rand; n = n+1; end; end; >> n n = -1