[an error occurred while processing this directive]   Suche  
 

SIMULINK: Subsysteme

Subsysteme sind das Äquivalent zu den Unterprogrammen der üblichen Programmiersprachen. Große Modelle kann man durch Verwendung von Subsystemen vereinfachen und überschaubarer machen.

Subsysteme lassen sich auch in anderen Modellen, in denen dieselbe Funktionalität erforderlich ist, einsetzen und ermöglichen so die Wiederverwendbarkeit einer einmal gemachten Arbeit. Zu diesem Zwecke können Anwender eigene Block Bibliotheken entwickeln.

In unserem ersten Beispiel wollen wir eine Block Bibliothek mit zunächst zwei Subsystemen entwerfen, die wir in verschiedenen Modellen zur Überwachung der Integrationsverfahren benutzen wollen.

Beispiel 1:

Wir wollen das Anfangswertproblem:
   y' + 2*y = u(t) = sin(t); y(0) = 0
mit verschiedenen, von Simulink angebotenen Lösungsverfahren über dem Intervall von 0 bi 20 lösen und dabei die von den Verfahren gewählten Schrittweiten sowie die Anzahl der Schritte anzeigen lassen.

Die Gleichung liefert die Laplace-Transformierten:

   s*Y + 2*Y = U
-> (s+2)*Y = U
-> Y = (1/(s+2))*U
Wir können folglich zur Integration das folgende Modell verwenden:

Modell zur Integration

Schrittweiten:

Die Uhr (clock) liefert uns die simulierte Zeit zu den Ereigniszeitpunkten des Systems. Wenn wir dafür sorgen, dass diese genau durch die Integrationsschritte gegeben werden, können wir aus tk+1-tk die Länge der einzelnen Integrationsschritte bestimmen.

Die Frage ist jetzt, wie erhalten wir die Differenzen der einzelnen Ereigniszeitpunkte?

Wer jetzt an diskrete Blöcke wie z.B. den Unit delay Block denkt, liegt leider im allgemeinen falsch. Das Problem ist, dass wir bei diesem Block die blockeigene Taktvorgabe nicht ausschalten können. Zumindest akzeptieren die mir zugänglichen Simulink-Versionen bei diesem Block nicht den Sample time Wert -1. Damit ist dieser Block im allgemeinen für unser Problem ungeeignet.

Was wir brauchen, ist ein Block, der uns zum Eingang uk+1 den Ausgang uk liefert, unabhängig davon, wie lange der Zeitabstand tk+1-tk ist. Dies macht der Memory Block den man in Simulink 3 in der Continous Library findet, nicht aber der Unit delay Block. Wir erhalten damit:

Modell zur Integration mit Ausgabe der Schrittweiten

Damit wir die verschiedenen Integrationsverfahren bezüglich der Schrittweiten auch richtig beurteilen, sollten wir die Simulationsparameter geeignet setzen.

Modell zur Integration mit Ausgabe der Schrittweiten

Abgesehen vom Solver, der von Lauf zu Lauf verschieden gewählt werden soll, setzen wir die Parameter wie hier abgebildet. Wichtig ist vor allem, dass wir 'Max step size' hinreichend groß wählen, denn anderenfalls werden wir im Ausgabefenster nur diesen Wert angezeigt bekommen.

Die nachfolgenden Bilder zeigen:

    • die Lösung des Problems (links)
    • die Schrittweiten des Dormand-Prince Verfahrens (rechts)
    • die Schrittweiten des TR-BDF2 Verfahrens (links)
    • die Schrittweiten des ODE15s Verfahrens (rechts)

Erzeugen von Subsystemen:

Die Blöcke zur Bestimmung der Schrittweite wollen wir nun in ein Subsystem umwandeln, wobei wir den Scope-Block nicht mit in das Subsystem nehmen. Dazu markieren wir die betreffenden Blöcke mit der Maus:

Modell mit markierten Blöcken

und wandeln Sie dann mit der Funktion: Edit -> Create Subsystem in ein Subsystem. Das Modell erscheint jetzt in der Form:

Modell mit markierten Blöcken

Durch Anklicken des Subsystem Blockes im Modell Fenster öffnen wir ein Subsystem Fenster mit dem Modell des Subsystems.

Subsystem

Sie sehen im Subsystem einen neuen Block 'Out1', der automatisch generiert wurde, weil unser Subsystem einen Verknüpfungspunkt mit dem aufrufenden System hat.

Mit dem Modell selbst können wir arbeiten wie gewohnt.

Wir wollen nun den Subsystemblock umbenennen. Es gibt eine ganze Reihe von Möglichkeiten dazu, auch zur graphischen Umgestaltung des Icons. Wir beschränken uns im Moment aber auf folgendes Verfahren:

  1. Subsystem-Block anklicken
  2. Edit -> Mask Subsystem auswählen
  3. im daraufhin erscheinenden Mask Editor Fenster geben wir im Eingabefenster Drawing commands ein:
    disp('delta t')
  4. nach anklicken von Apply können wir die Auswirkung auf den Icon des Subsystems schon erkennen
  5. durch anklicken von OK wird das Fenster des Mask Editors geschlossen und dieser selbst beendet.

Unser Modell mit dem Subsystem sieht jetzt wie folgt aus:

Modell mit maskiertem Subsystem

Schrittzähler:

Als weitere Aufgabe wollten wir ein Subsystem konstruieren, das uns die Anzahl der Integrationsschritte unseres Systems angibt. Im Grunde ist das ganz einfach. Zu jedem Ereigniszeitpunkt des Systems muss ein Zustandswert um 1 hochgezählt werden. Wiederum müssen wir hier einen Block wählen, der die Ereigniszeitpunkte des Systems übernimmt und keine eigenen Ereigniszeitpunkte hervorruft, da die Blöcke aus der 'Discrete Library' alle mit eigener Taktzeit arbeiten, sind diese ungeeignet und wir modellieren den Zähler deshalb wieder mit einem Memory Block. Als Startwert (Initial condition) dieses Blockes müssen wir -1 wählen, weil wir die Anzahl der Schritte und nicht die um 1 höhere Anzahl der Ereigniszeitpunkte zählen wollen. Wir kommen damit zum folgenden Modell:

Zähler für Ereigniszeitpunkte

Nach Umwandlung des Zähler Teilsystems in ein Simulink-Subsystem und entsprechender Maskierung:

Zähler für Ereigniszeitpunkte

Es empfiehlt sich, die konstruierten Subsysteme unter möglichst einfachen, nachprüfbaren Bedingungen zu testen. Ein Testsystem kann z.B. sein:

Model zum Testen der Subsysteme

wobei wir die Simulationszeit nur bis 1 laufen lassen. Die ausgegebenen Daten sind im Matlab Arbeitsfenster verfügbar.

Wir können nun auch die Anzahl der durchgeführten Integrationsschritte mit den verschiedenen Integrationsverfahren ermitteln. Für die oben betrachteten Verfahren haben wir:

Dormand-PrinceTR-BDFODE15s
1451240262

Bibliotheken:

Für die meisten Zwecke würde es genügen, unsere Blöcke einfach in einem eigenen Modell aufzubewahren, aus dem wir sie bei Bedarf in andere Modelle kopieren.
Das Bibliothekskonzept von Simulink bietet jedoch mehr Funktionalität auf Kosten eines größeren Aufwandes. Hauptvorteil einer Bibliothek ist der, dass die Kopie eines Blockes in einem Modell immer Verbindung zu ihrem Original in der Bibliothek (Bibliotheksblock) hat. Eine Korrektur am Bibliotheksblock wird damit automatisch von allen Kopien in den Modellen übernommen.

Zum Anlegen einer neuen Bibliothek gehen wir wie folgt vor:

  • im Simulink Fenster zum Modellieren wählen wir File -> New -> Library, worauf ein mit 'Library: untiteled' betiteltes Fenster aufgeht,
  • wir kopieren unsere Blöcke in dieses Fenster

    Fenster mit neuer Simulink Bibliothek

  • mit File -> Save im Bibliotheks-Fenster sichern wir die Bibliothek, wobei wir festlegen in welchem Verzeichnis sie unter welchem Namen zu erreichen ist. Wir legen sie hier in e:/simulink unter dem Namen IntegLib ab.

Beispiel 2:

Als Anwendung unserer Bibliothek wollen wir auf das Problem eingehen, was passiert, wenn dem Modell aus Beispiel 1 noch eine Block mit eigener Taktung hinzugefügt wird. Wir verwenden dazu eine isolierte digitale Uhr und öffnen dazu:
  • die Standard Simulink Bibliotheken,
  • unsere Bibliothek e:/simulink/IntegLib auf dem normalen 'open'-Weg,
  • ein Simulink Modellier Fenster
und konstruieren das folgende Modell:

Model zum Testen der Subsysteme mit digitaler Uhr

Für die Simulation des Modelles ist erforderlich, dass Matlab die Simulink Bibliothek mit den Bibliotheksblöcken findet. Wir fügen deshalb das Verzeichnis e:/simulink mit dem Matlab Kommando addpath e:/simulink für den Verlauf unserer weiteren Simulink Sitzung in den Matlab Suchpfad ein.

Zur Simulation verwenden wir dieselben Parameter wie in Beispiel 1, die 'sample time' der digitalen Uhr setzen wir auf 0.2. Mit dem Dormand-Prince Verfahren erhalten wir dann das folgende Bild für die Schrittweiten, wobei hier 202 Integrationsschritte anstelle der 145 in Beispiel 1 durchgeführt wurden.

Model zum Testen der Subsysteme mit digitaler Uhr

Der Unterschied ist hier recht einfach zu verstehen, der diskrete Block zwingt dem System seine Ereigniszeitpunkte auf. Das Dormand-Prince Verfahren muss diese Ereigniszeitpunkte 0.0, 0.2, 0.4, ... berücksichtigen, was zu einer ganz anderen Integration führt als ohne den diskreten Block. Die maximale Schrittweite wird trivialerweise auf 0.2 heruntergesetzt, die 'sample time' der digitalen Uhr.

Am einfachsten sehen wir das an unserem Test-System:

Model zum Testen der Subsysteme mit digitaler Uhr

das im Matlab Arbeitsfenster die folgenden Daten liefert:
simout =

         0         0         0         0
    1.0000    0.0300    0.0300    0.0004
    2.0000    0.0601    0.0300    0.0017
    3.0000    0.0994    0.0393    0.0046
    4.0000    0.1478    0.0484    0.0099
    5.0000    0.2000    0.0522    0.0175
    6.0000    0.2654    0.0654    0.0295
    7.0000    0.3395    0.0741    0.0461
    8.0000    0.4000    0.0605    0.0614
    9.0000    0.4919    0.0919    0.0874
   10.0000    0.6000    0.1081    0.1210
   11.0000    0.7144    0.1144    0.1589
   12.0000    0.8000    0.0856    0.1880
   13.0000    0.9558    0.1558    0.2409
   14.0000    1.0000    0.0442    0.2556
   .......    ......    ......    ......
woran wir sehen, dass die Schrittweite anfangs wächst und sich dann auf einen Zwischenschritt zwischen den durch die digitale Uhr vorgegebenen Ereigniszeitpunkten einpendelt.

Beispiele wie dieses sollen nicht dazu anregen, möglichts komplizierte Modelle zu konstruieren, sondern darauf aufmerksam machen, dass durch einfache Änderungen am Modell völlig neue Situationen entstehen, die nicht miteinander vergleichbar sind.

Im folgenden Beispiel verwenden wir Subsysteme um eine große Anzahl gleichartiger Blöcke mit wenig Aufwand zu konstruieren. Das Grundprinzip sind dabei Hierarchien von Subsystemen.

Beispiel 3:

Unsere beiden bisherigen Subsysteme kamen ohne Eingabesignale und ohne eigene Parameter aus. In diesem Beispiel wollen wir einen Block mit beidem generieren.

  • wir &oeffnen dazu ein Simulink-Modell Fenster und erzeugen dort mittels File ->> New -> Library ein Bibliotheks-Fenster.
  • in dieses Fenster kopieren wir einen Summen- und einen Transfer-Block.

    Teilmodell zur Konstruktion eines Subsystems

  • als Parameter für den Transferblock geben wir ein:
       Numerator:     [G]
       Denominator:   [C 2*G]
    Der Icon des Transferblockes ändert sich daraufhin in:

    Teilmodell zur Konstruktion eines Subsystems

  • wir markieren das gesamte Teilsystem und verwandeln es mittels File -> Create Subsystem in ein Subsystem

    Subsystem zu obigem Teilsystem

  • wir markieren den Subsystem-Block und öffnen mittels File -> Mask Subsystem den Masken-Editor. Je nach Vorgeschichte kann anstelle von Mask Subsystem auch Edit Mask angeboten werden. Beides führt zum selben Fenster, das wir aus Beispiel 1 schon kennen. Das erste Fenster füllen wir wie gezeigt aus, was nach 'Apply' zur Wirkung hat, dass der Icon des Subsystems die Aufschrift '(RC)1R' trägt.

    Startfenster des Masken-Editors

  • wir öffnen jetzt auch das 'Initialization' Fenster des Masken-Editors und geben unter Prompt und Variable jeweils G als Wert ein, danach klicken wir auf Add und geben jetzt unter Prompt und Variable jeweils C ein. Diese Aktion schließen wir mit Apply ab. Das Fenster sieht dann etwa wie folgt aus:

    Initialization-Fenster des Masken-Editors

    Mit OK verlassen wir den Masken-Editor.
  • wenn man einen nicht maskierten Subsystem-Block mit Doppelklick anspricht, erscheint ein Fenster mit dem Subsystem. Bei einem maskierten Subsystem-Block erscheint dagegen, wie bei jedem anderen Block, das Parameter-Fenster.

    Parameter-Fenster zum maskierten Subsystem-Block

    Wie man sieht können wir mit diesem Fenster die Parameter C und G des Blockes besetzen.
  • um das Subsystem eines maskierten Subsystem-Blockes zu sehen, müssen wir Look under Mask benutzen, es liefert in unserem Falle:

    Parameter-Fenster zum maskierten Subsystem-Block

  • schließlich wollen wir unser Subsystem in ein Modell einbauen und testen. Wir öffnen dazu ein Modell-Fenster und konstruieren:

    Modell mit maskiertem Subsystem-Block

    Was wir sehen können ist, dass unterschiedliche Parameter unterschiedliche Ergebnisse liefern und folglich die Parameterübergabe mit dem Parameter-Fenster funktioniert.
    Wir setzen voraus, dass die Bibliothek mit dem (RC)1R-Block, aus der wir diesen kopieren, in unserem Arbeitsverzeichnis liegt.
  • Wir sichern die Bibliothek unter dem Namen RCLib in einem Verzeichnis.

Beispiel 4:

Elektrische Leiterbahnen werden häufig durch eine Serie kleiner Widerstände und Kapazitäten beschrieben.

Modellierung eines Leiters durch Widerstände und Kapazitäten

Ein Glied einer solchen Reihe, bestehend aus einem Widerstand und einer Kapazität nennen wir ein RC-Glied.

Modellierung eines Leiters durch Widerstände und Kapazitäten

Wir haben bei einem solchen Glied:
  • einen Leitwert G, das ist der Kehrwert des Widerstandes R,
  • eine Kapazität C
  • einen Knoten zwischen Widerstand und Kapazität
  • einen Eingangsspannung u(t)
  • eine Knotenspannung phi(t)
Wir nehmen im folgenden an, dass alle Leitwerte G und alle Kapazitäten C gleich sind.
Der Strom durch einen Widerstand zwischen Knoten k-1 und k ist:
      iRk = G*(phik-1(t)-phik(t))
der durch eine Kapazität zwischen Knoten k und Erde:
      iCk = C*phik'(t)
wobei wir die Vorzeichen auch anders hätten wählen können. Da die Summe der Ströme durch einen Knoten 0 sein muss, haben wir für einen Knoten, der nicht am Ende einer Reihe von RC-Gliedern liegt:
      G*(phik-1(t)-phik(t)) = G*(phik(t)-phik+1(t)) + C*phik'(t)
oder:
(1)   C*phik'(t) + 2*G*phik(t) = G*(phik-1(t)+phik+1(t))
und für den letzten Knoten in der Reihe:
      G*(phin-1(t)-phin(t)) = C*phin'(t)
oder:
(2)   C*phik'(t) + G*phik(t) = G*phik-1(t)
Wir wollen mit einer Reihe von RC-Gliedern einen Prozess simulieren, bei dem zur Zeit t < 0 alle Knoten k die Spannung phik=0 haben. Zum Zeitpunkt 0 werde dann an Knoten 0 die Spannung u(t)=1 angelegt. Die Fragestellungen sind:
  • wie verhalten sich die Spannungen phik im Laufe der Zeit?
  • welche Schrittweiten verwenden die unterschiedlichen Integratoren zur Lösung dieses Problems? (Die Simulationsparameter geben wir erst später an.)

Gleichung (1) und (2) lassen sich durch Transfer Blöcke simulieren, wobei:

  • das Eingangssignal, das ist hier die Eingangsspannung, uk(t) = phik+1(t) + phik-1(t) ist.
  • im Transferblock, ausser beim letzten RC-Glied in der Reihe, der Zähler G und der Nenner C+2*G ist, bei letzten Glied haben wir im Zähler G und im Nenner C+G
  • das Ausgangssignal, das ist hier die Ausgangsspannung, yk(t) = phik(t) ist.
Im folgenden Modell haben wir das RC-Glied am Ende der Reihe durch einen Standard-Transfer-Block modelliert, die RC-Glieder davor dagegen durch Kopien des in Beispiel 3 konstruierten (RC)1R-Blockes.

Die RCLib-Bibliothek benötigen wir natürlich zum Kopieren der (RC)1R-Blöcke, aber auch beim Simulationslauf. Sie muss deshalb entweder in unserem Arbeitsverzeichnis liegen oder aber über den Matlab Suchpfad erreichbar sein, ist das nicht der Fall, so müssen wir sie mit Hilfe des Befehls addpath Verzeichnisname wenigstens temporär in den Pfad eingliedern. Benötigte aber nicht auffindbare Bibliotheken werden bei der Simulation häufig durch Bad Link in den Block-Icons angezeigt.

Modell mit 3 RC-Gliedern

Das vom Scope-Block angezeigte Ergebnis der Simulation entspricht dem erwarteten Verlauf der Lösungskurven.

Ergebniskurven

Längere Ketten mit RC-Gliedern kann man natürlich durch Aneinanderreihung mehrerer Transfer- bzw. (RC)1R-Blöcke aufbauen. Problematisch dabei ist aber:
  • der Bildschirm bietet nur beschränkten Platz,
  • die Modelle werden schnell unübersichtlich und fehlerhaft
  • es ist sehr mühsam und auch fehleranfällig, die Parameter aller Blöcke in der Reihe von Lauf zu Lauf zu ändern.

Einfacher ist es da, hierarchisch gegliederte Subsysteme mit 2, 4, 8, ... RC-Gliedern aufzubauen. Hierarchisch gegliederte Subsysteme sind im Simulink möglich.

Wir öffnen ein neues Modell-Fenster und kopieren die beiden (RC)1R-Blöcke einschließlich des Mux-Blockes in dieses Fenster. Der vordere (RC)1R-Block hat keine Rückkopplung zu seinem Vorgänger, da es diesen nicht gibt. Wenn wir den neuen Block aber hinter einem anderen Block verwenden wollen, brauchen wir diese Rückkopplung und folglich einen entsprechenden Ausgang im Subsystem. Außerdem sind nach dem Kopieren meist einige kosmetische Korrekturen am Modell notwendig. Nachdem dies alles getan ist, sieht unser Subsystem wie folgt aus:

Subsystem mit 2 RC-Gliedern

Der weitere Weg ist bekannt:
  • wir setzen bei den Parametern der (RC)1R-Blöcke die unbestimmten Werte G und C ein,
  • wir markieren das gesamte Teilsystem,
  • wir wandeln das Teilsystem mittels Create Subsystem in ein Subsystem, das durch einen einzigen Block dargestellt wird:

    Subsystem mit 2 RC-Gliedern als Block

  • da dieser Block noch nicht maskiert ist, liefert ein Doppelklick auf den Subsystem-Block das darunterliegende Subsystem:

    Subsystem mit 2 RC-Gliedern als als Subsystem

  • wir markieren den Subsystem-Block und öffnen mit Mask Subsystem den Masken-Editor. Dort legen wir wie bekannt, die Beschriftung des Icons fest und definieren die Parameter G und C als Block-Parameter. Wir nennen den Block (RC)2R
  • wir kopieren den maskierten Block in unsere RCLib-Bibliothek, Eventuell kann es erforderlich sein, dazu die Bibliothek mit Edit -> Unlock Library im Bibliotheksfenster entsperren.
Analog fügen wir noch die Blöcke (RC)4R und (RC)8R in die RCLib-Bibliothek ein, dort haben wir dann:

Bibliotheks Blöcke

Als Anwendung konstruieren wir ein Modell mit 25 RC-Gliedern, wobei wir 3 (RC)8R Blöcke aus der RCLib-Bibliothek verwenden. Das Modell soll darüberhinaus mit Blöcken zur Anzeige der Schrittweiten und zur Anzeige der Anzahl der Integrationsschritte ausgestattet werden, die wir in der IntegLib untergebracht haben. Falls die Bibliotheken weder im aktuellen Arbeitsverzeichnis noch in einem der Verzeichnisse aus dem Matlab-Path stehen, müssen ihre Verzeichnisse mit dem addpath-Kommando temporär in den Matlab-Path gestelltt werden.

Bibliotheks Blöcke

Wir simulieren das System:
  1. von 0 bis 60
  2. von 0 bis 200
mit den Verfahren:
  • Dormand-Prince
  • ODE15s
und setzen:
  • Relative Tolerance: 1.0e-6
  • Absolute Tolerance: 1.0e-9
Ansonsten werden die Default-Werte der Parameter benutzt. Wir erhalten:

  Dormand-Prince ODE15s
 0 bis 60 0 bis 2000 bis 600 bis 200
Schrittzahl113 280 206 240
mittl.Schrittw.0.8 0.8 1.2 4

Wie man sieht, zeigen die beiden Integrationsverfahren ein deutlich verschiedenes Schrittweitenverhalten. Bei kürzeren Integrationintervallen ist das Dormand-Prince Verfahren bezüglich des Aufwandes im Vorteil, bei längeren das ODE15s-Verfahren.

Wir werden sehen, dass dies eine typische Situation für ein 'steifes Problem' mit einer Transientenphase ist.