Simulation mechatronischer Systeme

Simulation mechatronischer Systeme Prof. Dr.-Ing.habil. G.P. Ostermeyer, Institut für Dynamik und Schwingungen, Technische Universität Braunschweig,20...
7 downloads 4 Views 5MB Size
Simulation mechatronischer Systeme Prof. Dr.-Ing.habil. G.P. Ostermeyer, Institut für Dynamik und Schwingungen, Technische Universität Braunschweig,2009

2

Simulation mechatronischer Systeme

Simulation mechatronischer Systeme

3

Inhalt 1. Einleitung

7

Die Grundidee zur Simulation mit PLAN Installation von PLAN Das einfachste Programm mit PLAN Die Grundfunktionalität von PLAN

10 12 16 19

2. Methoden in PLAN, Teil I

26

1.3 1.4

2.1 2.2 2.3 2.4 2.5

Grafik Animationen Usertasten 2D - Plots Mausevents und Ausschnittvergrößerung

3. Spielereien 3.1 3.2

Animierte Bilder und Bildschirmschoner Ping-Pong Spiele

4. Folgen und Reihen 4.1 4.2 4.3 4.4

Nullstelleniteration Feigenbaumdiagramm Mandelbrot- und Juliamengen Taylorreihen

27 35 38 42 54

62 63 68

77 77 82 87 93

4

Simulation mechatronischer Systeme

5. Zelluläre Automaten 5.1 5.2 5.3

Sierpinski Dreiecke Verkehrssimulation (Nagel-Schreckenbergmodell) Convay's Spiel des Lebens

6. Methoden in PLAN, Teil II 6.1 6.2 6.3 6.4

Vektoren und Matrizen Interpolation und Fourierreihen Numerische Integration Plotanimationen und 3D-Plots

7. Einfache dynamische Systeme 7.1 7.2 7.3 7.4

Ein linearer Einmassenschwinger Phasenportrait einer nichtlinearen Differentialgleichung Das Doppelpendel Laufrad auf rauem Untergrund

97 99 102 109

120 120 131 148 158

168 169 176 180 190

Simulation mechatronischer Systeme

5

6

Simulation mechatronischer Systeme

Simulation mechatronischer Systeme

7

1. Einleitung Wenn man sich mit der mathematisch-physikalischen Beschreibung dynamischer Systeme beschäftigt, muss man zwangsläufig Methoden zu deren – meist numerischer – Lösung nutzen. Nur so erschließt sich dem Nutzer die oft auf den ersten Blick nicht ersichtliche Komplexität der Dynamik. Zur numerischen Analyse dynamischer Systeme gibt es eine große Zahl sehr bequemer und sicherer Softwarewerkzeuge, die mit der Erfahrung im Umgang mit diesen Programmen schnell Auskunft geben können. Diese Programme sind aber gerade aufgrund ihrer Bequemlichkeit und Sicherheit selbst wieder meist komplexe Oberflächen mit noch komplexeren Sprachen geworden. Ihre volle Leistungsfähigkeit ist wohl nur noch Usern mit langjährigen Simulationserfahrungen sichtbar. Dadurch entsteht das Paradoxon, dass man sich immer mehr vom System entfernt, je mächtiger die Untersuchungswerkzeuge werden. Ursprünglich für das Verständnis des Systems geschaffen, machen sie selbst erfahrene User zu Black-Box-Nutzern. Wenn Sie beispielsweise einen einfachen Zweimassenschwinger untersuchen, müssen Sie die vom Programm gewählte interne Lösungsstrategie akzeptieren und anhand von mehr oder weniger sinnvollen grafischen Darstellungen deren Ergebnis verifizieren oder falsifizieren. Dazu muss man aber zumindest wissen, was das Berechnungsprogramm gemacht hat und mit welchen prinzipiellen Lösungsstrategien welche Aussagequalitäten erreichbar sind. Dazu sollte die Ausbildung des Ingenieurs die Erfahrung der Qualität numerischer Verfahren an einfachen, überschaubaren dynamischen Systemen bieten. Auch zeigt sich das Verständnis dynamischer Systeme wesentlich intensiver, wenn an mathematischen und numerischen Parametern "gespielt" wird und sofort entsprechende Rückmeldungen gegeben werden. Üblicherweise werden für den angehenden Ingenieur an den Hochschulen die Themen: Mechatronik o.ä. (Bewegungsgleichungen dynamischer Systeme) Schwingungen (Stabilität, Eigenformen, Frequenzen) Numerische Verfahren linearer Systeme (Matrizen, Eigenwerte, Eigenvektoren) Numerische Integration gewöhnlicher Differentialgleichungen

8

Simulation mechatronischer Systeme

Finite-Elemente Verfahren Techniken des Softwareengineerings Programmierkurse in unterschiedlichsten Vorlesungen geboten. Erst im Beruf müssen dann all diese Informationen vernetzt und integriert werden. Hier setzt die Vorlesung "Simulation mechatronischer Systeme" an. Zur sicheren und "schnörkellosen" Simulation wurde PLAN entwickelt. PLAN gibt in einfacher Form Einblick in das Prinzip der Simulation dynamischer Systeme. PLAN ermöglicht sehr schnell und einfach die Analyse dynamischer Systeme. PLAN bietet eine ansprechende Oberfläche und die klassischen numerischen Verfahren zur Beschreibung und Untersuchung dynamischer Systeme. Das "Erfahren" einfacher Systeme mit PLAN bündelt die oben genannten unterschiedlichen Lehrinhalte, zeigt Gefahren einer unkritischen Nutzung unterschiedlicher Untersuchungsmethoden auf, führt in einfacher Form moderne Verifikationsmethoden wie etwa "real time simulation" und "hardware-in-the-loop"-Techniken auf. Die Vorlesung will so zu einem sichereren und verantwortungsvolleren Umgang mit meist berufs- oder arbeitgeberspezifischen Simulationsumgebungen führen und neue Möglichkeiten der Verifikation dynamischer Systeme aufzeigen. Diese Zielsetzung der Vorlesung ist Resultat langjähriger Erfahrungen des Autors in Berechnungsabteilungen der Automobilindustrie, wo mit unterschiedlichsten Simulationsumgebungen hochkomplexe Modelle analysiert, Ergebnisse verifiziert, ... und schließlich marktfähige Aussagen ermittelt werden mussten. Die Vorlesung selbst ist in mehreren Jahren durch Nachfragen und Nutzung vieler Studenten gewachsen und optimiert. Die Vorlesung erfreut sich stark wachsender Beliebtheit, da sie zum einen eine komplette Softwareentwicklung zur Bearbeitung dynamischer Systeme in Studien- und Diplomarbeiten bietet und zum anderen den Umgang etwa mit MATLAB mit wenig zusätzlichem Aufwand ohne Probleme möglich macht. Der Aufbau der Vorlesung spannt einen weiten Bogen über "dynamische Systeme", von Computerspielen bis hin zu hardware-in-the-loop Experimenten mit geeigneter Sensorik und Aktorik für einfache adaptive Systeme. Ein solcher Bogen wird üblicherweise nicht in den fachspezifischen Vorlesungen geboten. Dieser interdisziplinäre Überblick ist aber wesentlich, um für die Simulationsaufgaben im Beruf gerüstet zu sein. Im Einzelnen: Es werden zunächst einfache grafische Animationen analysiert und realisiert, wie sie etwa bei Film, Fernsehen und Videospielen heute üblich sind. Dies ist die klassische Form sichtbarer "dynamischer" Systeme. Dann steht die Dynamik mathematischer Iterationen im Blickfeld. Unter anderem werden Wege ins Chaos verfolgt, selbstähnliche Strukturen realisiert und unter anderem das Apfelmännchen visualisiert.

Simulation mechatronischer Systeme

9

Natürlich werden auch numerische Integrationsverfahren für lineare und nichtlineare Differentialgleichungssysteme und deren Anwendung auf verschiedenste mechatronische Systeme erklärt und dargestellt. Hierbei werden insbesondere auch die Probleme bei einseitigen Bindungen, Stoßvorgängen oder einfach nur differentialalgebraischen Gleichungen aufgezeigt. Schließlich werden auch Anwendungen mit nichtklassischen Werkzeugen vorgestellt. So werden etwa Simulationen virtueller elektrischer Schaltungen mit Hilfe von zellulären Automaten dargestellt wie auch Selbstorganisationseffekte in diskreten Verkehrsmodellen. Den Abschluss bilden das Prinzip einfacher Mess- und Regelungsaufgaben mit hardware-in-the-loop Techniken und ihre Realisierung. Insbesondere werden grundsätzliche Probleme der realtime-Simulationen aufgezeigt. Mit diesen Inhalten hat der Leser das Rüstzeug, komplexere Projekte der Steuerung und Regelung realer Maschinen wie auch die Simulation allgemeiner dynamischer Systeme anzugehen. Die Studenten in den Vorlesungen haben dazu üblicherweise alte Maschinen, Motoren und Steuergeräte bekommen, die sie mit großem Elan zu neuem Leben erweckt haben. Das Ziel der zweisemestrigen Vorlesung ist die Vermittlung der prinzipiellen Funktionalität von Simulationsprogrammen (z.B. Matlab, ...) und deren Probleme bei komplexen dynamischen Systemen und die Realisierung jeder Menge selbstgemachter, beliebig unter Windows lauffähiger Schulungs- und Anwendungsprogramme. Zur Verfügung gestellt wird die Klassenbibliothek PLAN. Mit der Bibliothek PLAN lassen sich mit einfachsten C/C++ - Kenntnissen ab der ersten Vorlesungsstunde mathematische Tools nutzen und grafische Animationen unter Windows realisieren. Diese Software ist auch unter Visual C++ (.net), Borland C++ (CodeGear) und Linux nutzbar.

10

1.1

Simulation mechatronischer Systeme

Die Grundidee zur Simulation mit PLAN

Es gibt viele Möglichkeiten, einfache, schnell handhabbare Simulationsumgebungen aufzubauen. Die Literatur führt viele Beispiele an. So werden auf der einen Seite kleine Programme oder Unterprogramme angeboten. Deren Programmiersprache soll einfach und praktisch sein und von allen verstanden werden. So sind das meist Sprachen wie Basic. Zum anderen werden Interpreterlösungen angeboten, die mit unterschiedlichsten Sprach- und Funktionsumfängen werben. Sehr bekannte Lösungen sind etwa Mathematica oder MATLAB. Während ersteres Programm für die mathematische Untersuchung unterschiedlichster Zusammenhänge eine große Vielfalt an Methoden und Analysewerkzeugen bietet, die für viele vertiefende Fragen an das zu untersuchende System unerlässlich sind, hat sich MATLAB zu einem auch in der Industrie etablierten Standard entwickelt. Mit wenigen einfachen Befehlen lassen sich etwa dynamische Systeme auf Interpreterbasis analysieren und in Plots auswerten. Auch hier ist eine wachsende Anzahl von Zusatzbibliotheken erhältlich, mit denen zum Beispiel messdatenverarbeitende Prozeduren, regelungstechnische Anwendungen und statistische Auswertungen genutzt werden können. Kritisch bei diesen Programmen sind in der Regel allerdings die Rechenzeiten. Da die Usergemeinde im Allgemeinen diese Programme immer komfortabler ausgestaltet haben will und für die vermeintlich allgemein interessierenden Aufgaben die Programmabläufe automatisiert werden, bleibt die Nähe zum Algorithmus der Lösung einer mathematischen Aufgabe auf der Strecke. Dies ist gut, wenn man umfangreiche Erfahrungen mit der Simulation hat. Aber am Anfang sollte zunächst ein möglichst einfaches Werkzeug stehen, das die prinzipielle mathematische Lösungsstrategie wie auch die prinzipielle softwaretechnische Lösung von Simulationsaufgaben hautnah zu erleben gestattet. Darum ist PLAN anders. PLAN will eine Top-Down Programmierumgebung bieten, die das tut, was man zur Simulation braucht: eine übersichtliche grafische Oberfläche, die eine einfache Steuerung der Simulation erlaubt, eine Methode Init(), die am Anfang der Simulation gegebenenfalls Daten und Strukturen aufbaut, eine Methode Run(), die die eigentliche dynamische Simulation durchführt und dann eine Methode Reset(), um gegebenenfalls die Simulation wieder auf den Anfang zurückzustellen, damit die Simulation wiederholt werden kann. Schließlich wird noch eine Methode Finish() benötigt, um gegebenenfalls die in Init() aufgebauten Daten und Strukturen wieder abzubauen. Was Sie in Run() machen, und natürlich welche Datenstrukturen Sie haben wollen, bleibt Ihnen völlig überlassen. Die Methoden Run() und Reset() werden in einer optisch ansprechenden Umgebung durch das Betätigen von grafischen Tasten auf dem Bildschirm per Maus initiiert. Wenn Sie diese Methoden nicht definieren, passiert eben nichts, wenn Sie die entsprechenden Tasten drücken. Das Programm bleibt immer lauffähig. Simulationsergebnisse sind durch eine einfach zu handhabende Grafik darstellbar, die etwa durch Knopfdruck auf den Drucker, in ein BMP-File oder Worddokument geschrieben werden kann.

Simulation mechatronischer Systeme

11

PLAN ist in der objektorientierten Sprache C++ als Klasse TPlan geschrieben worden, die unterschiedlichste mathematische Methoden, grafische Methoden und Simulationssteuerungen enthält. Der Nutzer leitet sich eine Klasse, zum Beispiel TUser ab, die alle Eigenschaften von TPlan erbt. Die prinzipielle Programmstruktur ist nachfolgend skizziert. #include "Plan.h" class TUser : public TPlan { public: void Init(); void Run(); void Reset(); void Finish(); }; int main(int argc, char* argv[]){ TUser a; a.Execute(); return 0;}

Die Funktionen der Klasse TUser, zum Beispiel Init(), sollten von Ihnen mit Leben gefüllt werden. Wie, das wird Ihnen an vielen Beispielen in den nachfolgenden Kapiteln gezeigt. Das TUser Objekt a erbt die Methode Execute(). Damit wird in der main()-Funktion die eigentliche Simulation ausgelöst. So wird zunächst Init() ausgeführt und dann eine Simulationsoberfläche aufgebaut, die Tasten zur Ausführung von Run() oder Reset() bietet. Zum Beenden der Simulation gibt es eine Taste 'Exit'. Es wird dann zunächst die Funktion Finish() aufgerufen und softwaretechnisch alles aufgeräumt. So lassen sich mit nur geringen Kenntnissen in C/C++ Plattform unabhängig unter Windows, Linux/Unix oder Solaris auch komplexe Simulationen durchführen. Lassen Sie sich überraschen, was mit wenigen Mitteln schon möglich ist.

12

Simulation mechatronischer Systeme

1.2

Installation von PLAN

PLAN ist eine Dynamic Link Library (dll). Es gehören folgende Dateien dazu: Plan.h Plan.lib Plan.dll Auf der beiliegenden CD sind für die Borland C++ - Versionen 5.0, 6.0 und Code Gear 2007 jeweils Ordner enthalten. Jeder dieser Ordner enthält einen Ordner Planprojekt. In diesem Ordner sind neben den oben angegebenen Files auch fertige Projektrümpfe enthalten: Ordner Planprojekt (Borland 5.0, Borland 6.0) Plan.h Plan.lib Plan.dll Simulation1.cpp PrSimulation1.bpr PrSimulation1.bpf Wenn Sie auf die Datei mit der Endung .bpr klicken, wird automatisch die Borland Entwicklungsumgebung 5.0 oder 6.0 aufgerufen. Das Borland C++ 5.0 Programm zeigt sich am Bildschirm, wie Abbildung 1.1 zeigt. Ähnlich sieht das Borland C++ 6.0 aus.

Simulation mechatronischer Systeme

13

Abbildung 1.1: Borland C++ 5.0 nach Anklicken der Datei: PrSimulation1.bpr In der Mitte befindet sich das Editorfenster mit der Datei Simulation1.cpp. Am oberen Rand sieht man das Borlandband, welches die wesentlichen Möglichkeiten des Borland-Compilers enthält. Wesentlich ist zunächst das Datei-Menü. Mit Datei > Speichern unter ... können Sie der Simulation1.cpp-Datei einen anderen Namen geben und mit Datei -> Projekt Speichern unter ... auch der Projektdatei PrSimulation1. Dieser letzte Name ist dann auch der Name der .exe – Datei, die das Projekt liefert. Weiteres wichtiges Element ist das kleine grüne Dreieck in der dritten Zeile des Borlandbandes. Bei Betätigen dieser Taste wird das Projekt compiliert, gelinkt und, wenn es fehlerfrei ist auch gleich ausgeführt. Diese Projektrümpfe stellen einfach nur Konsoleprojekte dar – siehe Funktion main() -, die ein Objekt a der Klasse TUser – abgeleitet von der Klasse TPlan nutzen. Solch ein Projektrumpf stellt das einfachste Projekt mit PLAN dar und ist in dieser Form schon voll lauffähig. Bei der Borland 2007 (Code Gear)- Version sind im Ordner Planprojekt auch Unterordner enthalten:

14

Simulation mechatronischer Systeme

Ordner Planprojekt (Borland 2007) __history (Unterordner) DEBUG (Unterordner, dieser enthält PLAN.DLL) Plan.h Plan.lib PlanProjekte.groupproj PlanProjekte.groupproj.local PrSimulation1.cbproj PrSimulation1.cbproj.local Simulation1.cpp

Abbildung 1.2: te.groupproj.

Borland C++ 2007 nach Anklicken der Datei: PlanProjek-

Hier sollten Sie auf PlanProjekte.groupproj klicken oder auf PrSimulation1.cbproj.

Simulation mechatronischer Systeme

15

Das Aussehen am Bildschirm ist in Abbildung 1.2 dargestellt. Gegebenenfalls müssen Sie dort noch auf den Dateinamen Simulation1.cpp im rechten, oberen Fenster anklicken, um in der Mitte das File im Editorfenster zu sehen. Auch wenn bei dieser Borland-Version weitere Fenster gezeigt werden, ist das prinzipielle Vorgehen wie bei den anderen Versionen gezeigt.

16

Simulation mechatronischer Systeme

1.3

Das einfachste Programm mit PLAN

Wie in Kapitel 1.2 dargelegt, genügt ein einfaches Konsoleprojekt, um mit Plan zu starten. Dazu nutzen Sie am besten ein fertiges Rumpfprojekt. Dies liefert eine Datei Simulation1.cpp (oder wie immer Sie diese Datei umbenennen wollen) mit dem folgenden Inhalt: //==================================================================== // Simulation dynamischer Systeme mit PLAN //==================================================================== // Projektbeschreibung: // //==================================================================== #include #pragma hdrstop #include "Plan.h" class TUser : public TPlan { }; //==================================================================== #pragma argsused int main(int argc, char* argv[]){ TUser a; a.Execute(); return 0; } //__________________________________________________________Ost08_____

Mit diesem Sourcecode definieren Sie eine neue Klasse TUser, die von der Klasse TPlan abgeleitet wird. TUser enthält nichts außer dem, was in TPlan schon definiert ist. In der main()-Funktion wird ein Objekt a vom Typ der neuen Klasse TUser erzeugt und darin die Methode Execute() aufgerufen. Alle Programme entstehen durch den Aufbau dieser Klasse TUser, oder wie immer Sie Ihre Klasse nennen wollen. Wenn Sie das vorne genannte Rumpfprojekt nicht nutzen wollen, gehen Sie wie folgt vor: 1. Legen Sie ein neues Projekt, ein Konsoleprojekt, an. Dazu erscheint ein Konsolenexperte:

Simulation mechatronischer Systeme

17

Setzen Sie die Optionen wie dargestellt und drücke Sie ok. Sie können auch den Haken bei Konsolenanwendung im dargestellten Fenster entfernen, dann wird aus der main()-Funktion eine winmain()-Funktion und das PLANFenster das Hauptfenster. Üblicherweise erhalten Sie ein Projekt mit dem Namen Projekt1 und eine Datei User1.cpp mit dem Inhalt: //------------------------------------------------------#pragma hdrstop //------------------------------------------------------#pragma argsused int main(int argc, char* argv[]) { return 0; } //-------------------------------------------------------

2. Speichern Sie Datei und Projekt in einen Ordner, der die Dateien Plan.h, Plan.lib und Plan.dll enthält. Die letztere Datei muss bei dem Compiler 2007 gegebenenfalls auch in ein Unterverzeichnis _RELEASE oder _DEBUG kopiert werden, je nachdem, mit welcher Linkeroption Sie dann arbeiten. 3. Ergänzen Sie die .ccp – Datei wie oben angegeben, d.h. Plan.h includen und eine eigene Klasse von der Klasse TPlan ableiten. TPlan selbst ist nicht instanziierbar. In der main() – Funktion schließlich muss die von TPlan geerbte Methode Execute() in einem Objekt Ihrer Klasse aufgerufen werden. 4. Fügen Sie mit Projekt -> dem Projekt hinzufügen.. Ihrem Projekt die Datei Plan.lib hinzu. 5. Wenn Sie Ihre Programme auf Rechner portieren wollen, die kein Borland C++ enthalten, gibt es Probleme. Entweder suchen Sie noch einzelne BorlandLibraries heraus (siehe die jeweiligen Anleitungen) oder Sie gehen wie folgt vor: Wählen Sie Projekt->Optionen... und dann gehen Sie auf a) Karte Linker: Haken bei dynamische RTL verwenden entfernen b) Karte Packages: Haken bei Mit Laufzeit-Packages compilieren entfernen

18

Simulation mechatronischer Systeme

Das oben dargestellte Programm ist schon voll lauffähig. Wenn Sie es übersetzen und ausführen – das grüne Dreieck drücken! – erscheint am Bildschirm das in Abbildung 1.3 gezeigte PLAN-Simulationsfenster.

Abbildung 1.3.: Das PLAN – Simulationsfenster Es zeigt im wesentlichen eine weiße Zeichenfläche, rechts ein Band mit Tasten, die der Programmablaufsteuerung dienen und ganz unten ein zweigeteiltes Informationsband. Links werden Informationen zu den Objekten gegeben, über die die Maus gleitet. Wenn Sie die Maus etwa über die Tasten ziehen, bekommen Sie Informationen zu genau der jeweiligen Taste. Bei der Taste Exit etwa steht im Informationsband: unmittelbares Beenden des Programms. Und genau das tut diese Taste auch, wenn Sie diese mit der Maus betätigen.

Simulation mechatronischer Systeme

1.4

19

Die Grundfunktionalität von PLAN

Erstellen Sie ein neues Projekt, wie in Kap. 1.3 beschrieben. Starten Sie den C++ Builder. Der C++ Builder compiliert durch Drücken des grünen Pfeils die Dateien und führt das Programm aus. Diese Compilierung kann beim ersten Mal etwas länger dauern. Dabei werden verschiedene zusätzliche Dateien angelegt, welche die nächsten Compilierungen aber wesentlich schneller machen. Es erscheint das in Abbildung 1.3 dargestellte, den ganzen Bildschirm einnehmende Layout. Neben einer großen weißen Fläche, der Zeichenfläche, ist rechts ein Tastenfeld zu erkennen, sowie am unteren Rand eine zweigeteilte Informations- und Statusanzeige. Bewegt man die Maus über den Bildschirm, werden in der Informationsanzeige Erklärungen zu dem jeweiligen Objekt, auf dem der Mauszeiger steht, angezeigt. Zunächst sei das Tastenfeld genauer betrachtet. Unter dem PLAN-Logo ist zunächst der Titel des Programms: ====== PLAN ====== zu lesen. Hier wird später der Name Ihres Programms stehen. Im Tastenfeld gibt es zwei Tastengruppen. Unter "Ausführen" sind die Tasten Run, Reset und Info angeordnet. Wenn Sie die Taste Run drücken, verändert sich der Tastenname zu Weiter. Wenn Sie die Taste Reset drücken, erscheint auf dieser Taste wieder Run. Die Info-Taste liefert ein weiteres Windows-Fenster, in dem nur steht, das es keine benutzerdefinierten Informationen gibt. Unter dem Namen "Auswerten" sind die vier Tasten Clear, BMP-File, Zoom und Print zu sehen. Mit Clear wird das Zeichenfenster gelöscht. Man sieht natürlich nichts, da das Fenster ja leer ist. Die Taste BMP-File erstellt ein Bitmapfile von der Zeichenfläche und speichert diese unter dem Filenamen PLAN_0000.bmp (siehe Informationszeile!) ab. Wenn Sie noch einmal auf diese Taste drücken, speichert sie wieder das Zeichenfenster in ein BMP-File, diesmal heißt es aber PLAN_0001.bmp. Wenn Sie sich speziell diese Files später ansehen, z.B. durch Einbinden dieser Files in Word oder Einbinden in irgend ein Grafikprogramm (z.B. Paint), seien Sie nicht enttäuscht. Sie zeigen nur exakt das, was auf der Zeichenfläche dargestellt ist, nämlich nichts! Wenn Sie die Taste Zoom drücken, erscheint am Bildschirm ein anderes Layout. Die Zeichenfläche nimmt nun den Bildschirm vollständig ein. Nur am unteren Rand ist noch die Statusleiste bzw. die Informationszeile zu sehen.

20

Simulation mechatronischer Systeme

Abbildung 1.4: Das PLAN – Simulationsfenster, gezoomt.

Abbildung 1.5: Durch Eingeben von ? erzeugtes PLAN – Hilfefenster.

Simulation mechatronischer Systeme

21

Wenn Sie, egal, ob Sie im gezoomten Zustand sind oder nicht, die Taste ? auf der Tastatur drücken, erscheint wieder ein neues Fenster mit Erklärungen zu Tastenkürzeln, die in diesem Zustand von PLAN verstanden werden. Wichtigste Taste ist die Taste n (normal) oder ESC die wieder das nichtgezoomte Ausgangsbild darstellen. Die letzte Taste in diesem Feld ist die Taste Print. Sie macht genau das, was darauf steht: Sie sendet den Bildschirminhalt direkt zum Standarddrucker Ihres Systems! Die Tasten Run, Reset und Info sollen natürlich in Ihrem Programm mehr bewirken, als das, was sie hier tun! Tatsächlich rufen sie virtuelle Methoden von PLAN auf, die noch leer sind, und von Ihnen durch eigene Funktionen mit Leben erfüllt werden müssen. Die wesentlichen virtuellen Methoden von PLAN sind: void void void void void

Init(void); InitDraw(void); Run(void); Reset(void); Finish(void);

Die Funktion Init() wird genau einmal zu Beginn des Programms aufgerufen. Intern wird diese Funktion unmittelbar nach dem Erstellen der Windowsspezifischen Details der PLAN – Klassen aufgerufen. Diese Funktion eignet sich, um Ihre persönlichen Datenstrukturen usw. im Programm zu initialisieren oder Speicherplatz zu allokieren. Die Funktion Finish() ist das Gegenstück zur Methode Init() und wird ebenfalls genau einmal aufgerufen, und zwar unmittelbar vor der Beendigung des Programms. Hier können Sie z.B. Ihre Datenstrukturen wieder freigeben. Die Methode Run() wird von PLAN aufgerufen, wenn Sie die Taste Run drücken. Die Aufschrift der Run-Taste ändert sich beim ersten Drücken dieser Taste auf Weiter. Erneutes Drücken dieser Taste führt wieder Ihre Run()-Funktion aus, die Aufschrift der Taste ist weiterhin Weiter. In der Informationszeile am unteren Rand wird Ihnen mitgeteilt, wie oft Run() ausgeführt wurde. Sie können PLAN dazu veranlassen, die Run() – Funktion mit nur wenigen Millisekunden Abstand immer wieder aufrufen zu lassen. Dann erscheint auf der Run – Taste der Titel Halt. Wenn Sie dann diese Taste drücken, wird der automatische Selbstaufruf der Run()- Funktion unterbrochen und auf der Run – Taste steht wieder Weiter. Diese Option ist wichtig, wenn Sie etwa Animationen darstellen wollen. Dann wird in der Run() – Funktion die aktuelle Position zum Beispiel eines Männchens berechnet und dann die Programmausführung kurz an Windows gegeben, das sich um eventuelle Tasten- und Mausereignisse kümmert und eben auch die Grafik aktualisiert. Dann reicht Windows den Staffelstab an Run() zurück. Run() berechnet die wieder neue Position und so

22

Simulation mechatronischer Systeme

weiter. Dazu später mehr. Erst wenn Sie die Taste Reset drücken, wird die Tastenaufschrift Weiter oder Halt in Run zurückgeändert. Gleichzeitig wird dann in Ihrem Programm die Methode Reset() aufgerufen! Die Funktion InitDraw() wird zu Programmbeginn sowie immer dann aufgerufen, wenn Sie den Bildschirm mit der Taste Clear löschen. Implizit geschieht das auch, wenn Sie zwischen Normal- und Zoommodus hin- und herschalten. InitDraw() wird benötigt, wenn die Grafikfläche zu Beginn etwas anderes als den leeren Bildschirm zeigen soll. Wenn Sie beispielsweise ein Männchen im Wald simulieren wollen, so könnte InitDraw() den Wald zeichnen und die Simulation würde das Männchen dazu zeichnen. Wenn Sie dann die Taste Clear drücken, würde nur das Männchen vom Bildschirm verschwinden, weil der Wald ohne Männchen neu gezeichnet würde. Ganz analog können Sie die Linien einer Tabelle in InitDraw() zeichnen, deren Spalten von der durchzuführenden Simulation, etwa der Methode Run(), gefüllt werden. Immer wenn Sie Clear drücken, wird dann die Tabelle geleert sein. Neben der Exit – Taste sind zwei LED's zu sehen. Die erste zeigt den Zustand des Run()-Modus, grün ist sie, wenn Run() noch nicht ausgeführt wurde, gelb wird sie, wenn die Run() – Funktion einzeln ausgeführt wird, rot schließlich, wenn Run() kontinuierlich aufgerufen wird. Die zweite LED – Leuchte zeigt den Zustand der numerischen Integration, darauf wird später eingegangen. Die Exit – Taste schließlich, wie oben schon gesagt, schließt das Programm. Zu Beginn soll zunächst die Funktion Init() genutzt werden. Diese am Anfang einmal aufgerufene Funktion eignet sich neben der Initialisierung Ihrer eigenen Simulationsdaten besonders, um dem Programm auch optisch einen Programmnamen sowie einen erklärenden Text zu geben, der beim Drücken der Taste Info angezeigt wird. Um die virtuelle Methode Init() zu installieren, müssen im Prinzip zwei Schritte ausgeführt werden. Zunächst muss in der Klassendefinition diese Funktion deklariert werden. Selbstverständlich muß das eine öffentliche Methode sein (Schlüsselwort public:). class TUser : public TPlan { public: void Init(); };

Jetzt muss diese Funktion noch mit Leben erfüllt werden. Dies kann in der Klasse geschehen oder aber außerhalb. Man beachte, dass die Funktionsdefinition exakt mit der vorgegebenen Signatur void Init(void); übereinstimmt. Nur dann wird diese Funktion vom Programmablauf als Initiierungsfunktion genutzt. Tatsächlich ist diese Funktion als virtuelle Funktion in TPlan schon

Simulation mechatronischer Systeme

23

definiert. Mit der Definition in Ihrer Klasse sorgen Sie dafür, dass über den Mechanismus des "late bindings" die internen Funktionen von TPlan die zuletzt definierte Funktion Init(), also Ihre Funktion, nutzen. Selbstverständlich könnten Sie auch eine Funktion Init() mit anderer Signatur definieren: int Init(void); void Init(int i); .... das sind dann aber Funktionen, die nicht in der Klasse TPlan definiert sind und für deren Verwendung Sie selbst Verantwortung tragen müssen. In der Funktion Init() wird nun den Größen ProgrammName und ProgrammInfo je ein Charakterstring zugewiesen. Diese Größen lassen sich praktisch wie Variable behandeln, sind aber sogenannte Properties, die intern mehr oder weniger komplexe Funktionen aufrufen, wenn diese Größen gelesen oder beschrieben werden. In der Klasse TPlan und seinen Unterklassen gibt es eine ganze Reihe solcher Properties, die partiell nur gelesen oder nur beschrieben werden können.

void TUser::Init(void){ ProgrammName = "Testprogramm"; ProgrammInfo = "Dies ist ein erster Versuch\r" "eines Testprogrammes mit der\r" "Simulationsumgebung PLAN";}

Kompilieren Sie das Programm und führen Sie es aus. Es erscheint das schon bekannte Layout auf dem Bildschirm, aber mit kleinen Änderungen, siehe Abbildung 1.7. Unmittelbar unter dem Logofeld rechts oben erscheint nun Ihr Programmname "Testprogramm". Wenn Sie die Infotaste drücken, erscheint ein neues Fenster, das eben den an die Größe ProgrammInfo gegebenen Text zeigt. Mit der OK-Taste in diesem Infofenster kehren Sie wieder zum normalen Layout zurück.

Abbildung 1.6: Das Infofenster des Programms 1 in Kapitel 1.4.

24

Simulation mechatronischer Systeme

So können Sie gegebenenfalls dem User Ihres Programms erste Informationen mitgeben.

Abbildung 1.7: Das PLAN – Simulationsfenster, Programm 1 Kapitel 1.4. Das vollständige Programmlayout ist nachfolgend gegeben. Man beachte, dass nur in der benutzerdefinierten Klasse TUser Ergänzungen vorgenommen wurden. //==================================================================== // Simulation dynamischer Systeme mit PLAN //==================================================================== // Programm 1 Kapitel 1.4 //==================================================================== #include #pragma hdrstop #include "Plan.h" class TUser : public TPlan { public: void Init(); };

Simulation mechatronischer Systeme

25

void TUser::Init(){ ProgrammName = "Testprogramm"; ProgrammInfo = "Dies ist ein erster Versuch\r" "eines Testprogrammes mit der\r" "Simulationsumgebung PLAN";} //==================================================================== #pragma argsused int main(int argc, char* argv[]){ TUser a; a.Execute(); return 0; } //__________________________________________________________Ost08_____

26

Simulation mechatronischer Systeme

2. Methoden in PLAN, Teil I Nachfolgend werden erste Methoden und Datenstrukturen zur Erstellung von Simulationsprogrammen mit PLAN angeführt. Konkrete Simulationsaufgaben findet man in den nachfolgenden Kapiteln 3 ff. Im ersten Abschnitt stellen wir einzelne Grafik- und Schreibmethoden in PLAN vor. In den weiteren Schritten dieses Kapitels werden einfache grafische Animationen und deren Steuerung erklärt. Außerdem werden erste Plotdarstellungen, Mausevents und Ausschnittvergrößerungen eingeführt. Dieses Kapitel will mit sehr wenigen Methoden das prinzipielle Vorgehen für die Simulation aufzeigen. Alle Methoden und Befehle, auch die hier nicht angeführten, kann man im PLAN-Werkzeugkasten ausführlich dokumentiert nachlesen. Alle nachfolgenden Beispiele finden Sie auch auf der begleitenden CD. Im folgenden wird generell davon ausgegangen, dass Sie ein Konsoleprojekt mit einer main()-Funktion erstellen, in das Sie die PLAN-Bibliothek einbinden oder, wie vorne geschildert, ein fertiges Rumpfprojekt nutzen. Gegebenenfalls angegebene Zeiten für Compilierung etc. beziehen sich auf die Zeiten bei einem Pentium IV Prozessor mit 2 GHz unter Windows XP.

Simulation mechatronischer Systeme

27

2.1 Grafik in PLAN Eine der wesentlichen Eigenschaften von PLAN ist natürlich die Möglichkeit, auf der Zeichenfläche zu zeichnen. Um erste elementare Befehle kennen zu lernen, soll die Funktion Run() mit Leben erfüllt werden. Immer, wenn die Taste Run gedrückt wird, soll eine einfache Grafik erstellt werden. In PLAN sind standardmäßig einige Farben (Typ TColor) vordefiniert: Schwarz Grau Rot Gelb Gruen Blau Violett

Weiss Hellgrau Hellrot Hellgelb Hellgruen Hellblau Hellviolett

Klar Selbstverständlich kann jede andere Farbe, die Ihr Windowssystem hergibt, ebenfalls verwendet werden. Der Wertebereich der RGB-Farben ist 0-255 für alle drei Farbanteile. So wird etwa die RGB-Farbe 124,124,124 (= grau) mit folgender Anweisung gesetzt. Farbe = RGBSkala(real r100, real g100, real b100); Hierin ist r100 der Rotanteil in Prozent, entsprechend ist g100 der Gelbanteil und b100 der Blauanteil jeweils auch in Prozent. Die oben genannte graue Farbe gibt es also mit Farbe = RGBSkala(50,50,50); // 50% von 255 = 124 Um in Windows ein Objekt zu zeichnen, muss man einen Pen und ein Brush definieren. Objekte wie etwa ein Rechteck werden mit Pen gezeichnet und mit Brush ausgefüllt. Mit den Befehlen SetPen(Farbe1); SetBrush(Farbe2); erhält Pen die Farbe 1 und Brush die Farbe 2. Diese Farben bleiben global in PLAN erhalten, bis ein erneuter Aufruf dieser Funktionen die jeweilige Farbe ändert.

28

Simulation mechatronischer Systeme

Erwähnenswert ist die Farbe Klar. Dies ist keine Windowsfarbe, sondern eine tatsächlich fiese grüne Farbe – dies ist zumindest die Empfindung des Autors -, die softwaretechnisch so abgefangen wird, dass sie nicht gezeichnet wird. Ein Rechteck wird mit der Funktion void Rectangle(int x, int y, int w, int h) gezeichnet. Hierin sind (x,y) die (Pixel-)Koordinaten des linken oberen Punktes, w die Weite und h die Höhe des zu zeichnenden Rechteckes ebenfalls in Pixeln. SetPen(Hellrot); SetBrush(Gelb); Rectangle(50,50,100,200); zeichnet also ein gelbes Rechteck mit hellroter Umrahmung vom Punkt (50,50) mit der Weite 100 und der Höhe 200. Setzt man die Farbe des Pinsels auf Klar: SetBrush(Klar); Rectangle(80,80,100,100); wird nur ein Rechteck mit hellroter Umrahmung gezeichnet. Das Innere des Rechteckes wird nicht gezeichnet, bleibt also klar! Der Stift hat nicht nur eine Farbe, sondern auch eine Strichstärke. Diese wird in Pixel angegeben und wird einfach als zweites Argument der Funktion SetPen() angegeben. SetPen(Blau,9); Ab dieser Anweisung hat der Strich die Farbe Blau und eine Strichstärke von 9 Pixeln. Weitere elementare Grafikfunktionen in PLAN sind: void Circle(int x, int y, int r); void Circle(int x, int y, int rx, int ry); Die Funktion Circle() zeichnet Kreise und Ellipsen um den Punkt (x,y) mit dem Radius r bzw. mit den Radien rx in x-Richtung (horizontal) und ry in y-Richtung (vertikal). Damit sind die Befehle in der nachfolgend angegebenen Funktion Run() klar. Das resultierende Bild am Bildschirm zeigt Abbildung 2.1. Weitere Grafikbefehle wie Polygone, Kreisbögen, elliptische Bögen usw. sehe man im Anhang, bzw. in der Kurzübersicht der Befehle von PLAN nach!

Simulation mechatronischer Systeme

29

Abbildung 2.1: Das Programm 2 nach Drücken der Run - Taste. Hier der Sourcecode des Programms 2:

//==================================================================== // Simulation dynamischer Systeme mit PLAN //==================================================================== // Programm 2 (Kapitel 2.1) // //==================================================================== #include #pragma hdrstop #include "Plan.h" class TUser : public TPlan { public: void Init(void); void Run(void); };

30

Simulation mechatronischer Systeme

void TUser::Init(void){ ProgrammName = "Testprogramm"; ProgrammInfo = "Dies ist ein erster Versuch\r" "eines Testprogrammes mit der\r" "Simulationsumgebung PLAN";} void TUser::Run(void){ SetPen(Hellrot,1); SetBrush(Hellgelb); Rectangle(50,50,800,700); SetPen(Blau); SetBrush(Klar); Rectangle(80,80,800,700); SetPen(Blau,3); Circle(330,330,300); SetPen(Grau,3); SetBrush(Hellgruen); Circle(330,330,300,100); } //==================================================================== #pragma argsused int main(int argc, char* argv[]){ TUser a; a.Execute(); return 0; } //__________________________________________________________Ost08_____

Bei dem oben angeführten Beispiel sind die Grafikobjekte einfach in absoluten Pixelgrößen angegeben. Dies kann insbesondere dann zu Schwierigkeiten führen, wenn Sie etwa den Bildschirm auf unterschiedlichen Rechnern mit Ihrem Programm passgenau füllen wollen. Tatsächlich ändert sich die Größe des Zeichenfensters, das heißt, die Anzahl der Pixel auch, wenn man nur vom Normalmodus zum Zoommodus übergeht. Hierfür gibt es die Funktionen: int GetMaxW(); int GetMaxH(); Diese liefern die jeweils maximale Anzahl der Pixel der Zeichenfläche in x- bzw. yRichtung. Alle Objekte, die größer sind als die verfügbare Zeichenfläche werden automatisch abgeschnitten. Man kann auf der Zeichenfläche auch Ausschnitte, sog. Clipregionen, definieren, in denen man zeichnen will. Außerhalb dieser Ausschnitte werden die Zeichenvorgänge abgeschnitten. Die zugehörigen Funktionen sind: void View(); void View(int x, int y, int w, int h); void Clear(TColor Farbe);

Simulation mechatronischer Systeme

31

Mit View() wird die gesamte Zeichenfläche für Zeichenaktionen freigegeben. Mit View(10,10,100,100) werden beliebige grafische Anweisungen nur noch im Rechteckausschnitt von (10,10) bis (110,110) sichtbar. Mit einem erneuten Aufruf von View() mit oder ohne Argumente kann dieser Ausschnitt wieder umdefiniert werden. Mit dem Befehl Clear() wird der freigegebene Ausschnitt des Zeichenfensters gelöscht. Defaultmäßig wird hierbei der aktive Ausschnitt mit Weiß gelöscht, Sie können aber auch jede andere Farbe dazu nutzen. Die Statementfolge: View(); Clear(Grau); View(10,20,400,500); Clear();

// // // //

ganzer Bildschirm aktiv löscht mit Grau Ausschnitt aktiv aktuellen Ausschnitt löschen

x

(0,0) (10,20)

y (410,520)

(GetMaxW(),GetMaxH())

Abbildung. 2.2: Bildschirm mit View() und Clear() Anweisungen löscht den gesamten Bildschirm mit der Farbe Grau. Das Feld mit den Koordinaten (10,20) für die linke obere Ecke und (410,520) für die rechte untere wird mit der Farbe Weiß gelöscht. Auf der grauen Zeichenfläche erscheint ein weißes Rechteck, siehe Abbildung 2.2. Die Größe des gerade aktiven Ausschnittes auf der Zeichenfläche lässt sich mit den Funktionen int int int int erfragen.

GetX(); GetY(); GetW(); GetH();

// // // //

hier hier hier hier

= = = =

10 20 400 500

32

Simulation mechatronischer Systeme

Wenn man im Programm 2 (Kap.2.1) die Run()-Funktion mit einem View()-befehl ergänzt, kann man zum Beispiel die dort dargestellten Kreise passend beschneiden, sodass sie in das erste Rechteck passen.

void TUser::Run(void){ SetPen(Hellrot,1); SetBrush(Hellgelb); Rectangle(50,50,800,700); SetPen(Blau); SetBrush(Klar); View(50,50,800,700); Rectangle(80,80,800,700); SetPen(Blau,3); Circle(330,330,300); SetPen(Grau,3); SetBrush(Hellgruen); Circle(330,330,300,100); }

// Ergaenzung !!!

Das resultierende Bild zeigt Abbildung 2.3.

Abbildung 2.3: Das modifizierte Programm 2 nach Drücken der Run - Taste.

Simulation mechatronischer Systeme

33

Man kann den aktuellen Ausschnitt auch skalieren. Dadurch ist jeder Punkt im aktiven Ausschnitt durch ein reelles Zahlenpaar gegeben. Mit den Funktionen

void Scale(real xleft,real xright,real ybottom, real ytop); void Scale(real xleft,real xright,real ybottom); lässt sich ein reelles Koordinatensystem auf den Ausschnitt legen, dessen Pixel dann mit real (=double) Größen angesprochen werden können. Alle Grafikbefehle akzeptieren auch float- oder double-Argumente statt der Integer-Argumente, die sie dann in Pixelwerte umrechnen. Diese Umrechnung bezieht sich immer auf den Letzten Scale() – Befehl im Programm. Der zweite Scale()-Befehl berechnet intern den Wert für ytop auf der Hochachse so, dass eine Proportionalskalierung erzwungen wird, unabhängig von dem Größenverhältnis von Breite und Höhe des Ausschnittes. Damit wird ein Kreis auch wirklich ein Kreis. Eine nichtproportionale Skalierung macht aus jedem Kreis eine Ellipse. Man beachte, dass der Punkt (xleft,ybottom) immer links unten im Ausschnitt liegt. (x,y) Pixelkoordinatensystem: x,y,w,h

(xright,ytop)

Grafikfläche oder Ausschnitt reelles Koordinatensystem: xleft, xright, ybottom, ytop (xleft,ybottom)

(x+w,y+h)

Abbildung 2.4: Koordinatensysteme auf der Bildfläche. Umrechnungen dieser Koordinatensysteme sind gegeben mit den Funktionen IntToX(), IntToY() sowie XToInt(), YToInt(), die die Absolutwerte liefern. Relativwerte, also Längen von Strecken, werden durch die Funktionen IntToDX(), IntToDY(), DXToInt(), DYToInt() geliefert. So gilt etwa: xright = IntToX(x+w); w = DXToInt(xright - xleft);

34

Simulation mechatronischer Systeme

Textausgaben lassen sich mit den Befehlen SetText(Farbe); SetText(Farbe,Size); Text(int x, int y, char *s); TextRect(int x, int y, int w, int h, char *s, int center=0); bewerkstelligen. Mit Size wird die Schriftgröße in Pixeln gewählt, mit dem Argument 0 wird die Standardschriftgröße Ihres Windowsystems gesetzt, das ist die Größe der Schrift auf den PLAN – Tasten und die Defaulteinstellung in PLAN. Mit Farbe lässt sich die Textfarbe angeben. Der Hintergrund der Schrift wird durch die Farbe des Pinsels, siehe SetBrush(), bestimmt! Wollen Sie also auf beliebigem Untergrund nur die Schriftzeichen ausgeben, ohne das der Hintergrund überdeckt wird, müssen Sie den Pinsel auf Klar setzen! Text() gibt den im Argument angegebenen String ab der Position (x,y) aus (linke obere Ecke des Strings). TextRect() gibt den String im angegebenen Rechteck aus und schneidet gegebenenfalls überstehende Zeichen ab. Ist der String kleiner als das Rechteck (x,y,w,h), kann mit dem Parameter center der Text linksbündig (=0), mittig (=1) oder rechtsbündig (=2) im Rechteck ausgegeben werden. Die aktuelle Texthöhe oder Weite eines Strings in Pixeln kann mit den Funktionen int TextH(char *s); int TextW(char *s); erfragt werden.

Simulation mechatronischer Systeme

35

2.2 Animationen Eine der bekanntesten und auch spektakulärsten Eigenschaften von Simulationen sind die grafischen Animationen. Hier soll ein sehr einfaches Beispiel angegangen werden. Ein Rechteck soll sich über den Bildschirm bewegen. Dazu werden in der Userklasse TUser zwei Integer-Koordinaten xKoord, yKoord im private Abschnitt der Klasse definiert, die in der Init()-Funktion einen Startwert erhalten. Die Run()-Funktion soll nun zunächst das Rechteck löschen, d.h. weiß übermalen, die Koordinaten neu setzen und dann das Rechteck mit den neuen Koordinaten zeichnen. Die Reset()-Funktion dient hier dazu, die Koordinaten wieder auf ihre Startwerte zu setzen. Es ist bequem, die Reset() - Funktion auch in der Init() - Funktion aufzurufen, da so nur an einer Stelle im Programm die Anfangswerte definiert werden müssen. Der Sourcecode könnte also etwa so aussehen:

//==================================================================== // Simulation dynamischer Systeme mit PLAN //==================================================================== // Programm 3 (Kapitel 2.2) // //==================================================================== #include #pragma hdrstop #include "Plan.h" class TUser : public TPlan { int xKoord, yKoord; public: void Init(void); void Run(void); void Reset(void); }; void TUser::Init(void) { ProgrammName = "Animation"; ProgrammInfo = "Programm zur Demonstration\r" "einer einfachen Animation"; Reset();} void TUser::Run(void){ SetPen(Weiss); SetBrush(Weiss); Rectangle(xKoord,yKoord,100,100); xKoord +=5; yKoord +=5; SetPen(Schwarz); SetBrush(Hellrot); Rectangle(xKoord,yKoord,100,100);}

36

Simulation mechatronischer Systeme

void TUser::Reset(void) { Clear(); xKoord = 10; yKoord = 10;} //==================================================================== #pragma argsused int main(int argc, char* argv[]){ TUser a; a.Execute(); return 0; } //__________________________________________________________Ost08_____

Starten Sie jetzt das Programm. Wenn Sie auf die Taste Run drücken, wird ein schwarzgerändertes rotes Quadrat gezeichnet. Wenn Sie wieder auf diese Taste drücken - sie hat jetzt den passenden Namen Weiter – dann scheint sich das Quadrat zu bewegen. Wenn Sie genügend Geduld haben und oft genug diese Taste drücken, werden Sie das Quadrat an der rechten unteren Ecke der Zeichenfläche verschwinden sehen. Um das Rechteck wieder zu sehen, müssen Sie die Reset-Taste drücken. Die WeiterTaste heißt jetzt wieder Run, und Sie können das natürlich nicht besonders interessante Spiel von vorne beginnen. Störend hierbei ist natürlich unter anderem die Tatsache, dass Sie immer einen Knopf drücken müssen, um das Rechteck zu bewegen. Dies ließe sich natürlich dadurch beheben, dass Sie eine for(..), while(..) oder sonstige Schleife in der Run()-Funktion einbauen. Aber beachten Sie, dass Sie dann keine Animation haben. Windows gibt alle Kapazitäten an Ihre Run()Funktion, welche die Schleife ausführt. Mausbewegungen oder gar grafische Ausgaben kann Windows nicht erfassen beziehungsweise durchführen, solange Ihre Run()-Funktion arbeitet. PLAN führt Ihre Run-Funktion solange aus, bis diese fertig ist. Wenn Sie kein Abbruchkriterium in den Schleifen haben, müssen Sie Windows sogar persönlich um Hilfe bitten, um Ihr Programm zu beenden. Da das immer mal passieren kann, sei hier dieser rabiate Programmabbruch skizziert: Drücken Sie die Tasten Strg + Alt + Entf. Windows meldet sich mit einem Fenster, in dem unter anderem Ihr Programm steht in der Form "task ... reagiert nicht". Hier können Sie Windows dann veranlassen, diesen task zu beenden. Ein eleganterer Weg zu einer kontinuierlichen Animation ist der Weg, PLAN dazu zu veranlassen, die Funktion Run() immer wieder aufzurufen, bis Sie eingreifen. Dann kann Windows nach jedem Run()-Aufruf nachsehen, was an Grafik gemacht werden muss und ob Sie vielleicht die Maus bewegt oder eine Funktionstaste am Bildschirm betätigt haben. Dies kann einfach mit einem zusätzlichen Statement in der Run()-Funktion veranlasst werden:

Simulation mechatronischer Systeme

37

void TUser::Run(void){ SetPen(Weiss); SetBrush(Weiss); Rectangle(xKoord,yKoord,100,100); xKoord +=5; yKoord +=5; SetPen(Schwarz); SetBrush(Hellrot); Rectangle(xKoord,yKoord,100,100); CallRun = true;}

Ist die Größe CallRun auf true gesetzt, veranlasst PLAN nach Aktualisierung der Grafik und anderen kleinen Geschäften, nach ca. 20 Millisekunden den Wiederaufruf der Funktion Run(). Diese Zeit können Sie mit der Größe CallRunTime einstellen. darauf wird später eingegangen. Wenn Sie jetzt das Programm starten und die Run-Taste drücken, sehen Sie das sich nach rechts unten bewegende Quadrat. Die Run-Taste wechselt wieder ihren Namen und heißt jetzt Halt. Sie können nun jederzeit während der "Animation" die Halt-Taste drücken. PLAN stoppt dann die kontinuierlichen Aufrufe Ihrer Run()-Funktion, tauft die Run- bzw. Halt-Taste wieder um auf Weiter und wartet. Drücken Sie Weiter, dann ruft PLAN ihre Run()-Funktion weiter auf und zeigt wieder die Halt-Taste. Drücken Sie die Reset-Taste, wird die Run-, Halt-, Weiter-Taste wieder zur Run-Taste, und Sie können von vorn mit der "Animation" anfangen. Übrigens wird am unteren Rand auf der rechten Seite der PLAN Oberfläche die Anzahl der Run() – Aufrufe explizit angegeben. Achten Sie mal darauf. Erst wenn Sie die Reset – Taste drücken, wird diese Größe, sie heisst CallRunCount, wieder auf Null gesetzt. Sie können übrigens auch explizit auf diese Größe zugreifen und zum Beispiel die Anzahl von Run() – Aufrufen anzahlmäßig begrenzen, in dem Sie etwa den Wiederaufruf von Run() damit konditionieren: CallRun = (CallRunCountSize(); Plot0->Size(10,10,600,600);

// Plot nimmt ganzes Bild ein

mit der zweiten Anweisung wird das Plot Plot0 als 600x600 Pixel großes Feld vereinbart. Defaultmäßig gehen die Achsenskalen von 0.0 bis 1.0 und alle Achsentexte, Titel und Untertitel sind leer. Nun sollten natürlich noch Grundinformationen an das Plot gegeben werden wie etwa der Titel oder die Achsenbeschriftung. Dazu dienen die folgenden Methoden im Plot: Plot0->Titel = "Funktionsdarstellungen"; Plot0->Untertitel = "y = sin(x)"; Plot0->Achse(int Nr, real min, real max); Plot0->Achse(int Nr, char *s); Die beiden letzteren Funktionen erwarten in Nr eine Zahl von 0 bis 2, dabei ist 0 die x-Achse. Diese verläuft horizontal von links nach rechts. Die y-Achse mit der Nr. 1 verläuft immer von unten nach oben und die z-Achse mit der Nr 2 ist im Fall einer 3D-Darstellung die in den Raum zeigende Achse. Mit min und max gibt man die gewünschten Minimal- und Maximalwerte auf der jeweiligen Achse an. PLAN berechnet automatisch eine Achseinteilung, die zu mehr als zwei bzw. zu weniger als zehn Achsenabschnitten führen würde. Der String s in der letzten Funktion wird als Achsenbeschriftung der Achsen 0, 1 oder 2 gesetzt. Mit den Befehlen Plot0->Visible = true; Plot0->Visible = false;

Simulation mechatronischer Systeme

43

kann das Plot sichtbar oder unsichtbar gemacht werden. Unabhängig von dieser Variablen bleibt das Plot physikalisch erhalten, und kann Punkte, Kurven oder Flächen generieren, auch wenn es nicht sichtbar ist. Dies ist manchmal wichtig, wenn man sich abwechselnd auf eine grafische Animation und auf ein Plot konzentrieren will, ohne das jeweils andere abbrechen zu müssen. Üblicherweise wird man die Designangaben wie Achsenbeschriftung, Größe usw. in der Init-Funktion des Programms angeben. Man kann aber zu jedem Zeitpunkt alle Daten des Plots beliebig ändern. Ist dabei das Plot sichtbar, werden diese Änderungen unmittelbar am Bildschirm angezeigt. Mit den Angaben zur Größe des Plots, zum Titel, zur Achsbeschriftung und der Vermaßung der Achsen erscheint defaultmäßig ein zweidimensionales Plot. Für eine erste Plotversion benötigt man also nur die Funktion Init() in Ihrer Anwenderklasse.

//==================================================================== // Simulation dynamischer Systeme mit PLAN //==================================================================== // Programm 6 (Kapitel 2.4) // //==================================================================== #include #pragma hdrstop #include "Plan.h" class TUser : public TPlan { public: void Init(void); }; void TUser::Init(void){ Plot0->Size(100,100,600,600); Plot0->Titel = "Funktionsdarstellungen"; Plot0->Achse(0,0.0,6.3); Plot0->Achse(0,"x-Achse"); Plot0->Achse(1,-10.0,10.0); Plot0->Achse(1,"y-Achse");} //==================================================================== #pragma argsused int main(int argc, char* argv[]){ TUser a; a.Execute(); return 0; } //__________________________________________________________Ost08_____

Das resultierende Layout des Plotbildes in PLAN ist in Abbildung 2.6 dargestellt. Es gibt eine Reihe von Eigenschaften des Plots, die man beliebig setzen kann.

44

Simulation mechatronischer Systeme

Plot0->AchsenZahlen = true;

// oder = false;

Mit AchsenZahlen kann man die Angabe von Achsenzahlen unterdrücken. Analoges gilt für die Achsenbeschriftung: Plot0->AchsenText = true;

// oder = false;

und auch für den Titel und Untertitel des Plots: Plot0->PlotTitel = true;

// oder = false;

Je nach Wert dieser Größen wird das Plot entsprechend vergrößert oder verkleinert, sodass das von Ihnen angegebene Grafikfeld gerade ausgefüllt wird.

Abbildung 2.6: Programm 6 mit Plot0. Bitte beachten Sie, dass das Plot nicht die Zeichenfläche von PLAN behindert, sondern über dieser Zeichenfläche liegt. Man kann also parallel zum Plot die Zeichenfläche beliebig nutzen. Wird das Plot ausgeblendet (siehe unten), ist die Grafik auf der PLAN - Zeichenfläche vollständig!

Simulation mechatronischer Systeme

45

Wenn Sie auf das Plot klicken, erscheint am oberen linken Rand des Plots ein kleines Fenster mit nur 4 Hotkeys:

Abbildung 2.7: Hotkeys nach Mausklick auf Plot. Wenn Sie auf die Diskette klicken erscheint ein Bildsavemenue, wo Sie Name und Pfad (nur) des Plotbildes eingeben können. Generiert werden Bitmaps. Bei Klick auf den Drucker wird das Bitmapbild des Plots an den aktiven Drucker geschickt.

Abbildung 2.8: Plotbitmap, wenn auf den Hotkey mit der Diskette geklickt wird.

46

Simulation mechatronischer Systeme

Ein Klick auf den Hammer schließlich führt auf ein weiteres Menü, wo Sie praktisch alle Daten und Eigenschaften des Plots jederzeit definieren oder verändern können. Probieren Sie es einfach aus!

Abbildung 2.9: Plotmenü, erscheint bei Druck auf den Hammer Hotkey. Mit der Größe Links bzw. Rechts Plot0->Links = true; Plot0->Rechts = true;

// oder: Plot0->Rechts = false; // oder :Plot0->Links = false;

wird im 2D-Plot die Seite angegeben, auf der die Beschriftung und Vermaßung der yAchse angegeben wird. Die Plotachsendarstellung lässt sich über den Parameter AchsenTyp einstellen. Plot0->AchsenTyp = i;

// i = -2, -1, 0, 1, 2

Für i = 0 werden keine Achsen im Inneren des Plotfeldes gezeichnet. Bei i = 1 wird nur die Nullachse, bei i = 2 alle Achsen gezeichnet. Ist i negativ, werden die Achsen gestrichelt gezeichnet. Defaultwert ist i = 2; Auch lassen sich allen Flächen, Strichen und Texten eigene Farben zuordnen. Mit den zusätzlichen Angaben

Simulation mechatronischer Systeme

Plot0->PlotFarbe = Plot0->FeldFarbe = Plot0->AchsenFarbe Plot0->AchsenTyp =

Hellgrau; Grau; = Weiss; 2;

in der Init()-Funktion erhält man ein Plotbild wie in Abbildung 2.10.

Abbildung 2.10: Plot mit verändertem Layout.

Für Eilige gibt es 5 fertige Layouts, die mit Plot0->Layout(int i);

47

48

Simulation mechatronischer Systeme

angesprochen werden können oder aber im Plotmenü durch Klicken auf die Hotkeys des Feldes Layout am unteren Ende erstellt werden.

Abbildung 2.11: Plots mit vordefiniertem Layout 0, 1, 2, 3, 4. Auch lassen sich mit Klick auf 3D Plot im Feld Stil des Plotmenüs (Abbildung 2.9) die inaktiven Elemente für die Gestaltung von 3D – Plots aktivieren. Bitte sehen Sie im Handbuch für weitere Optionen des Plotlayouts nach. Der Inhalt des Plots sind natürlich Kurven, Punkte oder ganze Flächen. In einem Plot können bis zu 10 unterschiedliche Kurven parallel animiert dargestellt werden. Sie werden über die Variablen Kurve0, Kurve1 bis Kurve9 angesprochen. Auf die Animation von Kurven wird später eingegangen. Mit jeder dieser Variablen können natürlich beliebig viele normale Kurven in einem Plot dargestellt werden. Den Kurven können Farben und Strichstärken zugeordnet werden, die jederzeit auch geändert werden können. Plot0->Kurve0->SetPen(Schwarz,3); Plot0->Kurve1->SetPen(Gelb); Hier hat Kurve0 die Attribute: Farbe Schwarz und Strichstärke 3, Kurve1 ist gelb und hat die Strichstärke 1. Die einfachsten Grafikbefehle in Kurve0 (und allen anderen Größen Kurve1,..) sind bool MoveTo(real x, real y); bool LineTo(real x, real y); Diese Befehle geben den boolschen Wert true zurück, wenn der Punkt im aktuellen Plotfeld liegt, entsprechend wird der Wert false geliefert, wenn der Punkt außerhalb der von Ihnen angegebenen Achsenwerte liegt. Damit lässt sich das Programm 6 einfach erweitern, um etwa die Funktion y = 9*sin(x) darzustellen.

Simulation mechatronischer Systeme

49

//==================================================================== // Simulation dynamischer Systeme mit PLAN //==================================================================== // Programm 6 (Kapitel 2.5) // //==================================================================== #include #pragma hdrstop #include "Plan.h" class TUser : public TPlan { public: void Init(); void Run(); }; void TUser::Init(){ Plot0->Size(100,100,600,600); Plot0->Titel = "Funktionsdarstellungen"; Plot0->Achse(0,0.0,6.3); Plot0->Achse(0,"x-Achse"); Plot0->Achse(1,-10.0,10.0); Plot0->Achse(1,"y-Achse"); Plot0->Kurve0->SetPen(Rot,3);} void TUser::Run() { real x,a = 9.0; Plot0->Kurve0->MoveTo(x,a*sin(x)); for(x=0.2;xKurve0->LineTo(x,a*sin(x));} //==================================================================== #pragma argsused int main(int argc, char* argv[]){ TUser a; a.Execute(); return 0; } //__________________________________________________________Ost08_____

Das resultierende Plot zeigt Abbildung 2.12.

50

Simulation mechatronischer Systeme

Abbildung 2.12: Plot des Programms 6.

Wenn man Messpunkte miteinander verbindet, will man sicher auch die eigentlichen Messpunkte kennzeichnen. Hierzu kann optional in den oben schon dargestellten Befehlen MoveTo() und LineTo() je ein zusätzlicher boolescher Parameter zur Zeichnung von Markern angegeben werden bool MoveTo(real x, real y, bool ma = false); bool LineTo(real x, real y, bool ma = false); Dieser zusätzliche Parameter ma ist defaultmäßig auf false gesetzt und unterdrückt so die Darstellung der Punkte. Die Punktmarkierung selbst wird über die Größen PointTyp ( ein Wert zwischen 0 und 19) und PointColor charakterisiert. Für

Simulation mechatronischer Systeme

51

PointTyp = 0 wird kein extra Marker gezeichnet. Beide Größen lassen sich wie bei der PEN - Einstellung mit einem Befehl einstellen: void SetMarker(Farbe, Typ); Nachfolgend sind die Init()– und die Run()-Funktion in Programm 6 leicht modifiziert. Run() zeichnet 19 Cosinusfunktionen mit Markern unterschiedlichen Typs. Der Anfangswert der Cosinusfunktion ( = 1, .., 19) kennzeichnet so den Markertyp, der für die entsprechende Kurve genutzt wurde;

void TUser::Init(){ Plot0->Size(100,100,600,600); Plot0->Titel = "Funktionsdarstellungen"; Plot0->Untertitel = "y = a*cos(x)"; Plot0->Layout(1); Plot0->AchsenTyp = 0; Plot0->Achse(0,0.0,1.5); Plot0->Achse(0,"x-Achse"); Plot0->Achse(1,0.0,20.0); Plot0->Achse(1,"Markertypen i, y = i*cos(x)"); Plot0->Kurve0->SetPen(Hellgrau);} void TUser::Run() { real x,a; int i; for(i=0;iKurve0->SetMarker(Schwarz,i); Plot0->Kurve0->MoveTo(0.0,a*cos(0.0),true); for(x=0.1;xKurve0->LineTo(x,a*cos(x),true);}}

Das entsprechende Plotbild ist in Abbildung 2.13 zu sehen. Wenn man nur Punkte oder Punktmarker zeichnen will, so kann man auch den Befehl bool Point(real x, real y); nutzen. Dieser markiert auf dem Plotfeld je nach Einstellung von PointTyp einen entsprechenden Marker. Für PointTyp = 0 wird ein einzelnes Pixel in der Kurvenfarbe gezeichnet. Wenn man etwa die numerische Integration wiederholen will, wird man die ResetTaste drücken. Die Plotdarstellung soll dann im Allgemeinen auch zurückgestellt wer-

52

Simulation mechatronischer Systeme

den, insbesondere der Plotinhalt gelöscht werden. Dies lässt sich einfach mit dem Befehl Reset() im Plot bewerkstelligen.

Abbildung 2.13: Plot des Programms 6. Das Programm 6 sollte also um eine Reset()-Funktion erweitert werden, die dann auch das Plot zurücksetzt. Hier nun Programm 6 vollständig:

//==================================================================== // Simulation dynamischer Systeme mit PLAN //====================================================================

Simulation mechatronischer Systeme

53

// Programm 6 (Kapitel 2.5) // //==================================================================== #include #pragma hdrstop #include "Plan.h" class TUser : public TPlan { public: void Init(); void Run(); void Reset(); }; void TUser::Init(){ Plot0->Size(100,100,600,600); Plot0->Titel = "Funktionsdarstellungen"; Plot0->Untertitel = "y = a*cos(x)"; Plot0->Layout(1); Plot0->AchsenTyp = 0; Plot0->Achse(0,0.0,1.5); Plot0->Achse(0,"x-Achse"); Plot0->Achse(1,0.0,20.0); Plot0->Achse(1,"Markertypen i, y = i*cos(x)"); Plot0->Kurve0->SetPen(Hellgrau);} void TUser::Run() { real x,a; int i; for(i=0;iKurve0->SetMarker(Schwarz,i); Plot0->Kurve0->MoveTo(0.0,a*cos(0.0),true); for(x=0.1;xKurve0->LineTo(x,a*cos(x),true);}} void TUser::Reset(){ Plot0->Reset();} //==================================================================== #pragma argsused int main(int argc, char* argv[]){ TUser a; a.Execute(); return 0; } //__________________________________________________________Ost08_____

54

Simulation mechatronischer Systeme

2.5

Mausevents und Ausschnitte

Recht häufig sind Beeinflussungen der Simulation am Bildschirm notwendig, hier können etwa Mausklicks auf der Zeichenfläche, oder das Ziehen von Punkten mit der Maus bei gedrückter linker Maustaste hilfreich sein. Dies wird ebenfalls in einfacher Form in PLAN unterstützt. Insbesondere wird eine fest programmierte Form zum userbedienten Zoomen vorgestellt. Das Programm PLAN enthält auch Methoden, um Mausevents auf der Zeichenfläche zu detektieren: void void void void

BildMouseDown(int x, int y); BildMouseMove(int x, int y, int leftdown); BildMouseUp(int x, int y); BildMouseClick(void);

Diese werden immer dann aufgerufen, wenn der User entsprechende Mausaktionen auf der Zeichenfläche von PLAN durchführt. Über das Funktionsargument erhält man die momentane Position des Mauszeigers sowie die Information, ob die linke Maustaste gedrückt ist (leftdown = 1) oder nicht. Eine sehr einfache Anwendung könnte etwa die Zeichnung eines kleinen Kreises sein als Kennzeichnung der Mauszeigerposition auf der Zeichenfläche von PLAN, wenn die Maustaste gedrückt wird. Zusätzlich kann man die Pixelkoordinaten des Mausklickortes schreiben lassen.

//==================================================================== // Simulation dynamischer Systeme mit PLAN //==================================================================== // Programm Mausklick (Kapitel 2.5) // //==================================================================== #include #pragma hdrstop #include "Plan.h" class TUser : public TPlan { public: void BildMouseDown(int x, int y); }; void TUser::BildMouseDown(int x, int y){ Circle(x,y,10); char s[100]; sprintf(s," Mauszeiger: (%d,%d)",x,y); Text(20,20,s);} //====================================================================

Simulation mechatronischer Systeme

55

#pragma argsused int main(int argc, char* argv[]){ TUser a; a.Execute(); return 0; } //__________________________________________________________Ost08_____

Am Bildschirm wird das folgende Bild ausgegeben:

Abbildung 2.14: Programm Mausklick. Etwas sinnvoller ist die Möglichkeit, mit der Maus Handzeichnungen auf dem Bildschirm durchzuführen. Um in einen Zeichenmodus zu schalten, wenn die linke Maustaste gedrückt wird, zu zeichnen, wenn die Maus mit gedrückter Taste bewegt wird und in den Normalmodus zu schalten, wenn die Maustaste losgelassen wird können die oben genannten Funktionen genutzt werden. Im nachfolgend dargestellten Programm sind die Integer-Variablen xalt, yalt definiert worden. Ihnen wird bei jeder Mausbewegung der aktuelle Wert des Mauszeigers zugewiesen. Wenn dann mit gedrückter Maustaste eine Mausbewegung detektiert wird, wird eine Linie von (xalt,yalt) nach (x,y) gezeichnet. Damit sichert man sich vor Überraschungen, denn der interne Mauszeiger kann durch Nebenaktionen wie etwa die Textausgabe verstellt werden. Man kann also nicht unbedingt darauf hoffen, das man zu irgend einem Zeitpunkt in PLAN MoveTo(x,y)

56

Simulation mechatronischer Systeme

angibt und diese Position unverändert über längere Zeit gehalten wird. Tatsächlich wird von vielen internen Grafikaktualisierungen diese Funktion genutzt.

//==================================================================== // Simulation dynamischer Systeme mit PLAN //==================================================================== // Programm Mausklick 2 (Kapitel 2.5) // //==================================================================== #include #pragma hdrstop #include "Plan.h" class TUser : public TPlan { int xalt, yalt; public: void BildMouseDown(int x, int y); void BildMouseMove(int x, int y, int leftdown); void BildMouseUp(int x, int y); }; void TUser::BildMouseDown(int x, int y){ MoveTo(x,y); xalt = x; yalt = y;} void TUser::BildMouseMove(int x, int y, int leftdown){ if(leftdown) { MoveTo(xalt,yalt); LineTo(x,y); xalt = x; yalt = y;} char s[100]; sprintf(s," Mausposition in Pixeln (%d,%d) ",x,y); Text(20,20,s); } void TUser::BildMouseUp(int x, int y){ MoveTo(xalt,yalt); LineTo(x,y);} //==================================================================== #pragma argsused int main(int argc, char* argv[]){ TUser a; a.Execute(); return 0; } //__________________________________________________________Ost08_____

Mit diesem Programm kann man schon freihändige Zeichnungen erstellen. Ein resultierendes Ergebnis ist in Abbildung 2.15 dargestellt.

Simulation mechatronischer Systeme

57

Abbildung 2.15: Programm Mausklick 2 Eine immer wieder benötigte Anwendung dieser Mausfunktionen ist etwa die Auswahl eines Bildausschnittes durch den User. Damit kann der User sich in die Animationswelt hineinzoomen. Dies ist insbesondere wertvoll bei komplexen Animationen. Man denke etwa an eine Verkehrssimulation einer Stadt und die Möglichkeit, das Verkehrsgeschehen in nur einer Straße zu beobachten. Hierzu gibt es in PLAN eine vordefinierte Methode: Ausschnitt = true; void AusschnittDefiniert(int x, int y, int w, int h);

Wird die Größe Ausschnitt auf true gesetzt, kann der User auf der Zeichenfläche einen Ausschnitt definieren. Dazu braucht er nur mit der Maus, linke Maustaste gedrückt haltend, ein Rechteck zu markieren. Dieses wird dem User im Bild gestrichelt angezeigt (XOR – Modus, Ihre Zeichnungen werden nicht zerstört!). Sobald der User das Rechteck über die Grenzen der Zeichenfläche hinwegsetzen will, oder wenn er ein Rechteck markiert hat, schaltet sich die Option Ausschnitt wieder auf false. Wenn der User einen gültigen Ausschnitt definiert hat, ruft PLAN die Funktion AusschnittDefiniert() auf, in der Sie die aktuellen Rechteckparameter für Ihre Zwecke nutzen können.

58

Simulation mechatronischer Systeme

PLAN nutzt, wenn Sie die Größe Ausschnitt auf true setzen, temporär selbst die BildMouse...()-Funktionen, gibt sie aber dann sofort wieder frei. Eine sehr einfache Realisierung ist die nachfolgend beschriebene Bildausschnittsvergrößerung. Nehmen wir an, Sie haben eine Funktion Draw(), die ein beliebig komplexes Bild auf dem Bildschirm darstellt. Alle Zeichenfunktionen von Draw() sollen sich auf eine Skalierung der Bildfläche stützen. Mit Hilfe der Ausschnittfunktion kann man die Bildfläche so umskalieren, dass nur entsprechende Ausschnitte gezeichnet werden. Sie sollten aber dafür sorgen, dass das Bild auch wieder in den Ausgangsmaßstab gesetzt werden kann! Dazu werden hier zwei Tasten eingeführt, die zum einen die AusschnittVergrößerung, und zum anderen die Normalansicht bieten. Die Ausgangsgrößen zur Skalierung des Bildschirms sind die Variablen X0Min, X0Max und Y0Min. Die eigentliche Skalierung findet mit den Variablen XMin, XMax und YMin statt. Zu Anfang und wenn die Taste "Normalsicht" gedrückt wird, werden diese Werte auf die Ausgangswerte X0Min usw. gesetzt. Der nachfolgende Sourcecode definiert in einer Funktion Draw() eine Grafik aus vielen Dreiecken. Dabei nutzt Draw() den Scale() – Befehl mit den globalen Variablen XMin, XMax, YMin, die in der AusschnittDefiniert() – Funktion gesetzt werden, wenn denn die Taste 1 gedrückt und damit diese Funktion von PLAN aufgerufen wird. In dieser Funktion wird auch ein Polygonzug mit den Befehlen void SetPoint(int x, int y); // n – mal void Poly(); void ClearPoints(); gezeichnet, der einen internen Stack für die von Ihnen angegebenen Punkte erzeugt. Dieser Stack kann bei Bedarf sehr viele Punkte aufnehmen und eignet sich für das Zeichnen von offenen und geschlossenen Polygonzügen, dies geschieht mit der Funktion Poly(). Man sehe im Programmierhandbuch nach. Mit der Taste 0 werden die Größen XMin usw. wieder auf ihren Ausgangswert gesetzt und die Zeichnung in Originalgröße wiedergegeben.

//==================================================================== // Simulation dynamischer Systeme mit PLAN //==================================================================== // Programm Ausschnitt (Kapitel 2.5) // //==================================================================== #include #pragma hdrstop #include "Plan.h"

Simulation mechatronischer Systeme

class TUser : public TPlan { real X0Min, X0Max, Y0Min; real XMin, XMax, YMin; public: void Init(void); void Draw(void); void AusschnittDefiniert(int x, int y, int w, int h); void RunTaste0(void); void RunTaste1(void); }; void TUser::Init(void){ X0Min = XMin = -1.5; Y0Min = YMin = -1.5; X0Max = XMax = 1.5; TastenfeldName = "Ausschnittveränderung"; InsertTaste(0,"Normalsicht",""); InsertTaste(1,"Ausschnitt",""); Draw();} void TUser::Draw(void){ View(); Clear(); Scale(XMin,XMax,YMin); //=== Definiere zwei Punkte und den Punkt (0.0,0.0); real P1X, P1Y, P2X, P2Y; P1X = 1.0; P1Y = 0.0; P2X = 0.7; P2Y = 0.1; real s,c; for(int i = 0;i2 ist die eindeutige Konvergenz zwar nicht mehr gegeben, aber es wird sich ein außerordentlich komplexes Iterationsverhalten ergeben, das von der eindeutigen Lösung zunächst zwei, dann vier, acht und so weiter lösungsähnliche Werte liefert. Hier soll diese Fixpunktiteration als Plot dargestellt werden. Die wesentlichen Daten der Funktion f(x) sind sicher im Intervall [0.0,2.0] zu erwarten. Außerhalb dieses Intervalls ist die Funktion f(x) sicher negativ. Das Maximum von f(x,k) ist für Werte k mit k>1 und kSize(); Plot0->Titel = "Fixpunktiteration"; Plot0->Untertitel = "x = f(x) mit x + k*x*(1 - x)"; Plot0->Achse(0,0.0,2.0); Plot0->Achse(0,"x - Koordinate"); Plot0->Achse(1,0.0,1.5); Plot0->Achse(1,"Funktion f(x)"); }

Um die Iteration sinnvoll darstellen zu können, wird zunächst die Funktion y = f(x) im Plot dargestellt sowie die Hilfsgerade y = x. Dann geht man vom gewählten Startwert x0 aus und berechnet f(x). Dieser Wert wird dann das neue x1. Sukzessive nähert man sich so dem Fixpunkt. Dieser Weg soll als dritte Kurve im Plot dargestellt werden. Es bietet sich also an, drei Kurventypen im Plot zu definieren. Entsprechend wird die Init() – Funktion erweitert um Plot0->Kurve0->SetPen(Schwarz,3); Plot0->Kurve1->SetPen(Hellgrau,3); Plot0->Kurve2->SetPen(Hellrot);

// Grafik y = f(x) // Hilfsgerade y = x // Iterationsschritte

Um die Funktionswerte der Funktion f(x) bereit zu halten, bietet es sich an, diese als eigene Funktion real f(real x);

Simulation mechatronischer Systeme

79

in der Klasse TUser zu definieren. Die Funktion selbst kann dann so aussehen

real TUser::f(real x){ return x + k*x*(1.0 - x);}

Die Größe k wird in der Klasse TUser definiert, um sie dann in allen Funktionen der Klasse verfügbar zu haben und dort diese Größe zu variieren. Das Zeichnen der Funktion y = f(x) und der Hilfsgeraden y = x kann man in einer Funktion Draw() ablegen. Diese sorgt erst mal mit dem Aufruf von Plot0->Reset(); für ein Aufräumen im Plot und Löschen des Plotinhaltes. Die eigentliche Iteration wird in der Run() – Funktion durchgeführt. Dort sollen die Iterationen dargestellt werden. Eine erste Version von Run() könnte sein: void TUser::Run(){ Draw(); int i; real x = 0.1; Plot0->Kurve2->MoveTo(x,0.0); for(i = 0; iKurve2->LineTo(x,f(x)); x = f(x); Plot0->Kurve2->LineTo(x,x);}}

Nun macht es eigentlich keine Schwierigkeiten mehr, bei jedem Aufruf von Run() den Parameter k von k = 1.0 bis etwa k = 3.0 laufen zu lassen. Man kann in der Run() - Funktion k um 0.01 inkrementieren und CallRun solange auf true setzen, wie k kleiner als 3 ist. Man beachte, dass bei so vielen Iterationen pro Run() – Aufruf die numerischen Werte der Iteration aus dem Bereich der darstellbaren Zahlen laufen können. Es macht Sinn, für x < 0 die Iteration abzubrechen. In der Reset() – Funktion wird der Anfangswert von k festgeschrieben. Die Reset() – Funktion selbst wird dann auch in der Init() – Funktion aufgerufen, um k zu Beginn auch einen Wert zuzuweisen. Der Source Code ist jetzt also:

//==================================================================== // Simulation dynamischer Systeme mit PLAN //====================================================================

80

Simulation mechatronischer Systeme

// Fixpunktiteration // //==================================================================== #include #pragma hdrstop #include "Plan.h" class TUser : public TPlan { real k; public: void Init(); real f(real x); void Draw(); void Run(); void Reset(); }; void TUser::Init(){ Plot0->Size(); Plot0->Titel = "Fixpunktiteration"; Plot0->Untertitel = "x = f(x) mit x Plot0->Achse(0,0.0,2.0); Plot0->Achse(0,"x - Koordinate"); Plot0->Achse(1,0.0,1.5); Plot0->Achse(1,"Funktion f(x)"); Plot0->Kurve0->SetPen(Schwarz,3); Plot0->Kurve1->SetPen(Hellgrau,3); Plot0->Kurve2->SetPen(Hellrot); Reset(); } real TUser::f(real x){ return x + k*x*(1.0 - x);} void TUser::Draw(){ real x; Plot0->Reset(); Plot0->Kurve0->MoveTo(0.0,f(0.0)); for(x=0.02; xKurve0->LineTo(x,f(x)); Plot0->Kurve1->MoveTo(-0.1,-0.1); Plot0->Kurve1->LineTo(2.1,2.1); } void TUser::Run(){ Draw(); int i; real x = 0.1; Plot0->Kurve2->MoveTo(x,0.0); for(i=0;iKurve2->LineTo(x,f(x)); x = f(x); if(xKurve2->LineTo(x,x);} k+=0.005; CallRun = (k