3D Grafiken und eigene Funktionen

Einfache 3D-Grafiken

Im letzten Block hast du gelernt, wie du ebene Darstellungen erstellst. Natürlich besteht auch die Möglichkeit 3D-Darstellungen zu erstellen. Wie in 2 Dimensionen basieren auch hier die Darstellungen auf einzelnen Punkten. Die wichtigsten Befehle werden wir im folgenden nun Anschauen.

plot3

plot3 funktioniert wie plot, akzeptiert aber 3 Koordinaten.

x = -10:10; y = 0:20; plot3(x,y,x+y)

Du siehst, wieder wird für jedes i jeweils ein Punkt am Ort (xi,yi,xi+yi) gezeichnet.

Aufgabe 1

t=0:pi/36:12*pi; plot(cos(t),sin(t))

Der Befehl oben zeichnet einen Kreis.

  1. Verwandle den Kreis in eine Helix, in dem du eine passende z-Komponente hinzufügst
  2. Passe den Code so an, dass aus der Helix ein Wirbel wird, der nach unten immer enger wird.

Zeichne alle Plots gleichzeitig aber in verschiedene Grafik-Fenster.

Hinweis: Mit der Maus kannst du die Grafik drehen um sie besser anschauen zu können.

Lösung Anzeigen

plot3(cos(t),sin(t),t) figure plot3(cos(t).*t.^2,sin(t),t) figure plot3(cos(t).*t.^2,sin(t).*t.^2,t) % Das sind bloss Beispiele, es gibt natürlich diverse Möglichkeiten.

Flächen darstellen

Vielleicht hättest du erwartet, dass das erste Beispiel mehr Punkte in der ganzen Ebene zeichnet. Dafür müssten dein x und dein y aber für jeden Punkt der Grundfläche ein Koordinatenpaar enthalten.

X = [ 0 1 2 0 1 2 0 1 2 ]; Y = [ 0 0 0 1 1 1 2 2 2 ]; plot3(X,Y,X+Y, '+')

Du bekommst 9 Punkte die in einer Ebene liegen. Solche Vektoren (oder Matrizen) einzugeben kann jedoch sehr mühsam werden. Der Befehl [X Y] = meshgrid(xy) löst dieses Problem für dich. Sind x und z zwei Vektoren, so gibt dir meshgrid zwei Matrizen mit allen Kombinationen zurück.

x = [ 0 1 2 ]; y = x; [ X Y ] = meshgrid(x,y) X Y plot3(X,Y,X+Y, '+')

Noch sind wir aber nicht am Ziel. Denn eigentlich möchten wir eine richtige Fläche und nicht bloss Punkte. Dies ist mit plot nicht möglich. Du kannst aber die Befehle mesh oder surf verwenden.

mesh(X,Y,X+Y) figure surf(X,Y,X+Y) colorbar

Worin unterscheiden sich die beiden Befehle? Was macht colorbar?

Sind X und Y Matrizen wie du sie von Meshgrid bekommst und haben sie eine Schrittlänge von 1, so kannst du sowohl bei bei mesh wie auch bei surf die ersten beiden Argumente weglassen.

[X Y] = meshgrid(-10:10, -10:10) mesh(X+Y) colorbar

Aufgabe 2

Erstelle von den folgenden Funktionen je eine Grafik

Verwende für die 3D-Darstellung sowohl mesh als auch surf. Zeichne zudem für jede Funktion einen Subplot mit Höhenlinien.

Hinweis: Für die Höhenlinien brauchst du den den Befehl contour.

Lösung Anzeigen

x=-10:10; y=-10:10; [X,Y]=meshgrid(x,y); f1=X.^2+Y.^2; f2=X.^2-Y.^2; f3=sin(X/3).*cos(Y/3); rows=1; cols=3; figure subplot(rows, cols, 1) mesh(f1) subplot(rows, cols, 2) surf(f1) colorbar subplot(rows, cols, 3) contour(f1) figure subplot(rows, cols, 1) mesh(f2) subplot(rows, cols, 2) surf(f2) colorbar subplot(rows, cols, 3) contour(f2) figure subplot(rows, cols, 1) mesh(f3) subplot(rows, cols, 2) surf(f3) colorbar subplot(rows, cols, 3) contour(f3)

Funktionen

In der Lösung der letzten Aufgabe fällt auf, dass du drei beinahe identische Blöcke hast. Damit hast du wieder das Problem, dass eine kleine Anpassung Änderungen an diversen Stellen nach sich zieht. Natürlich lässt sich auch das vermeiden. Die einfachste Möglichkeit ist wohl eine eigene Funktion mit den nötigen Befehlen zu definieren.

Um eine Funktion zu definieren, musst du eine neue Datei erstellen. Die Datei muss den gleichen Namen haben wie deine Funktion. Als Beispiel erstellen wir eine Funktion, die zwei Zahlen nimmt und diese durch einander dividiert.

% Datei: myDiv.m function c = myDiv(a, b) c = a/b

Hinweis: Die Datei mit der Funktion muss sich natürlich an einem Ort befinden, an dem sie auch gefunden wird. Am Besten wohl im aktiven Verzeichnis (pwd). Ausserdem solltest du aufpassen, dass du keine bestehende Funktion überschreibst. Namen wie sin oder plot sind deshalb wohl keine gute Idee.

Nun wollen wir aber die Beispiel-Funktion etwas genauer anschauen. Eine Funktion beginnt mit einer Zeile wie function c = myDiv(a, b). Das Schlüsselwort function leitet eine Funktionsdefinition ein. c gibt an welche Variable am Ende zurückgegeben werden soll. Du könntest hier auch einen Vektor ([a b c]) angeben oder ganz auf eine Rückgabe verzichten (ohne c =). myDiv ist dann der Funktionsname und muss wie gesagt mit dem Dateinamen identisch sein. (a, b) sind schliesslich die Argumente, welche die Funktion erwartet. Danach (a/b) folgen die Anweisungen die ausgeführt werden sollen. In Octave kannst du das Ende einer Funktion wird mit endfunction markieren. Das erhöht die Lesbarkeit, reduziert aber die Kompatibilität mit Matlab.

Um die Funktion nun aufzurufen tippst du einfach

myDiv(1, 2)

Aufgabe 3

Passe Aufgabe 2 so an, dass der ganze Zeichenblock in eine Funktion verpackt ist und du diese einfach je für f1, f2 und f3 einmal aufrufst. Deine Funktion hat also keinen Rückgabewert.

Lösung Anzeigen

% Datei: myPlot.m function myPlot(f) rows=1; cols=3; figure subplot(rows, cols, 1) mesh(f) subplot(rows, cols, 2) surf(f) colorbar subplot(rows, cols, 3) contour(f)

x=-10:10; y=-10:10; [X,Y]=meshgrid(x,y); f1=X.^2+Y.^2; f2=X.^2-Y.^2; f3=sin(X/3).*cos(Y/3); myPlot(f1) myPlot(f2) myPlot(f3)

Bedingte Befehlsabfolgen

Unsere Beispiel-Funktion myDiv hat ein Problem, wenn du sie mit b = 0 verwendest. Auch sonst wird es wohl oft vorkommen, dass du unterschiedliche Befehle ausführen möchtest, abhängig vom Wert einer Variable oder einer anderen Bedingung. Dafür gibt es if-else.

a = 1 if (a > 0) disp('positiv') elseif (a == 0) disp('null') else disp('negativ') end

Pass a und die Bedingungen an, bis du verstehst was wo passiert. Beachte besonders, dass du mit == auf Gleichheit testest. Mit = klappt das nicht.

Aufgabe 4

Passe nun myDiv so an, dass du Division durch Null abfangen kannst. Gibt in dem Fall 0 zurück und zeige eine Fehlermeldung an.

Lösung Anzeigen

% Datei: myDiv.m function c = myDiv(a, b) if (b == 0) c = 0; disp('Fehler: Division durch Null') else c = a/b; end

Aufgabe 5

Welche der folgenden Bedingungen sind true

Schreibe jeweils einen if-Block um die Bedingung zu testen.

Lösung Anzeigen

if (-1 < 0) disp('-1 < 0: true') end if (0 <= 0) disp('0 <= 0: true') end if (0 >= 0) disp('0 >= 0: true') end if (0 > 0) disp('0 < 0: true') end if (1 ~= 0) disp('1 ~= 0: true') end if (-1) disp('-1: true') end if (0) disp('0: true') end if (1) disp('1: true') end if (2) disp('2: true') end if ("hallo") disp('"hallo": true') end if (a = 1) disp('a=1: true') end if (1 == "1") disp('1=="1": true') end if ("foo" == "bar") disp('"foo"=="bar": true') end

Ein- und Ausgabe

In den Beispielen oben hast du gesehen, wie du mit disp Text ausgeben kannst. Mit disp kannst du aber auch mehr als ein Text ausgeben. Wenn du disp einen Vektor mit Strings (Zeichenketten) übergibst, werden diese aneinandergereiht

disp(['hallo', ' ', 'welt'])

Für komplexere Ausgaben gibt es zudem noch printf und seine Varianten. Wir werden auf diese Befehle hier aber nicht weiter eingehen. Du findest mehr Infos zu ihnen in der Hilfe.

Mit der Eingabe von Werten sollten wir uns aber schon etwas beschäftigen. Ein ganz einfaches Beispiel könnte so aussehen

% dies muss in ein eigenes m-File a = input('a = ') b = input('b = ') disp('a+b =') myDiv(a,b)

Wenn du dieses m-File nun ausführst, wirst du nach a und b gefragt und bekommst dann a/b ausgegeben.

Aufgabe 6

Programmiere in einem M-File folgende Quiz-Frage:

Wann war der erste Mensch auf dem Mond?

Eine mögliche Programmstruktur ist:

  1. Frage nach dem Jahr 19[00...99].
  2. Frage nach dem Monat [1..12].
  3. Frage nach dem Tag [1..31].
  4. Kontrolliere, ob die Antworten richtig oder falsch sind.
  5. Gib das Ergebnis aus.

(Lösung der Quiz-Frage: 20. Juli 1969)

Hinweis: du kannst mehrere Dinge gleichzeitig testen, indem du die einzelnen Tests mit && verknüpfst.
if (a == 1) && (b == 2)

Lösung Anzeigen

t=20; m=7; j=69; disp('Wann war der erste Mensch auf dem Mond?') disp(' ') jahr=input('Geben Sie das Jahr [00..99] an. '); disp(' ') monat=input('Geben Sie den Monat [1..12] an. '); disp(' ') tag=input('Geben Sie den Tag [1..31] an. '); if (jahr == j) && (monat == m) && (tag == t) disp('Sie haben richtig geraten.') elseif (jahr == j) && (monat == m) && (tag ~= t) disp(['Das Jahr und der Monat sind',... 'zwar korrekt, aber nicht der Tag!']) elseif (jahr == j) && (monat ~= m) && (tag == t) disp(['Das Jahr und der Tag sind zwar',... 'korrekt, aber nicht der Monat!']) elseif (jahr ~= j) && (monat == m) && (tag == t) disp(['Der Monat und der Tag sind zwar',... 'korrekt, aber nicht das Jahr!']) elseif (jahr == j) && (monat ~= m) && (tag ~= t) disp('Nur das Jahr ist korrekt.') elseif (jahr ~= j) && (monat == m) && (tag ~= t) disp('Nur der Monat ist korrekt.') elseif (jahr ~= j) && (monat ~= m) && (tag == t) disp('Nur der Tag ist korrekt.') elseif (jahr ~= j) && (monat ~= m) && (tag ~= t) disp(['Hatten Sie in Geschichte einen',... 'Fensterplatz?']) end disp('Es war am 20. Juli 1969.')

Hinweis: Du siehst, dass ich Zeilen einrücke, wenn diese Teil einer Funktion oder eines (if-)Blockes sind. Das ist freiwillig, erhöht aber die Lesbarkeit und macht es damit deutlich einfacher Probleme zu finden. Du solltest dir das deshalb ebenfalls angewöhnen.