RealTime Simulation und Optische Elemente


Die RealTime Simulation ist ein besonderer Fall der dynamischen Analyse (Dyna). Die Simulation
wird so vom Rechner getimed, dass die Ergebnisse in der realen Zeit zur Ausgabe kommen. Für die
Ausgabe kommen dann sogenannte optische Elemente (zBsp. Lampe, Zeiger-Instrument) zum
Einsatz, die während einer Simu-Session ihr Aussehen (entsprechend der Rechenergebnisse) ändern
können).

Schauen wir uns mal das Beispiel DocSamples\RealTime Circuits\Transistor_AMulti.circ an:

Lamp1, D1, SW1 und Me1 sind optische Elemente. Der Umschalter SW1 wird nicht von einem
Rechenergebniss (Spannung, Strom), sondern von einer CircuitVariable (TokenRefParameter SW1.state)
gesteuert, um das Ein- und Ausschalten der Blinkschaltung zu simulieren.

Für eine RealTime Simu sind unter Menue:Settings/AnalysisSettings folgende Einstellungen zu beachten:

Der Marker RealTime Simulation ist natürlich anzuhaken. 

Mit Optical FrameRate legt man fest, wie oft alle optischen Elemente pro Sekunde neu gezeichnet werden sollen.
Kommen analoge optische Elemente (wie Me1) in der Schaltung vor, sollte die FrameRate gerade so hoch
gewählt werden, dass eine flüssige natürliche Darstellung erreicht wird. Man muß nämlich beachten, dass eine
hohe FrameRate den Rechner auch entsprechend belastet. Hat man mindestens einen  2-Kern-Prozessor zur
Verfügung, stellt die FrameRate nicht mehr das große Problem dar. Mit einem Wert von 30 dürfte man dann 
immer richtig liegen.

Setzt man den Marker Open End On dann schaltet man auf eine Simulation mit offenen Ende. Die Simul-Session 
wird dabei nach Ablauf der Zeit TimeRange immer wieder neu gestartet, die Zeit wird aber nicht
mehr auf 0 gestellt, sondern erhöht sich kontinuierlich, bis der Simu-Prozess durch Drücken der Tasten Ctrl+B
oder durch Anklicken des Schliess-Symbols des Doku-Fensters händisch abgebrochen wird. Open End Simul ist
vor allem bei der Interactive Simulation sehr praktisch.

Der Parameter TimeRange sollte natürlich im Sekunden-Bereich liegen. Der Parameter Number Of Timesteps
legt dann noch die Zeit-Schrittweite (Timestep = TimeRange/Number Of Timesteps) fest, die für dynamische
Simulationen nicht zu groß gewählt werden darf . Ein kleine Zeitschrittweite bedeutet hohe Genauigkeit, aber
auch höheren Rechenaufwand. Die Anzeige Prozessor-Load in der Status-Zeile zeigt die Auslastung des Haupt-
Rechen-Threads an. Wenn Diese auf über 100 % steigt (Anzeige 100%), verlangsamt sich der Fortgang der
Zeit entsprechend.

Mit einem TimeZoom Factor von > 1 kann man eine RT-Simu zeitlich verlangsamen, mit < 1 beschleunigen.
Man kann hier also eine Art von Zeit-Mikroskop einschalten. Hat man z.Bsp. eine Schaltung, die im Mikro-
Sekunden-Bereich arbeitet, so könnte man mit einem TimeZoom-Faktor von 1M (1e6) den Simu-Ablauf in
den Sekunden-Bereich transformieren, und so eine RT-Simu ermöglichen. Es ist dann aber zu beachten,
dass Anzeige-Elemente, die ein reales dynamisches Verhalten eingebaut haben, nicht verwendet werden
dürfen.

Alle optischen Elemente sind gescriptet (externe Elemente). Ich habe sie ins Verzeichniss Data\Optical Elements
gelegt, wo sie mit Hilfe des Add Ext. Elements-Dialog, wie alle anderen ext. Elemente auch, in eine Schaltung
eingefügt werden können.
Im Verzeichniss DocSamples\RealTime Circuits findet ihr weitere einfache Beispiele für RealTime- und
Interactive Simulation.

Wer optische Elemente nicht selber kreieren möchte, kann die folgenden Kapitel ignorieren.

 

Optische Elemente erstellen mit Hilfe von optischen Modul-Bitmaps

Optische Modul-Bitmaps (OMBitmaps) werden im Prinzip genauso verwendet wie MBitmaps. Nur können
Diese, gesteuert von einer bzw. mehrerer Input-Variable, ihr Aussehen ändern. Es gibt zwei verschiedene Arten
von OMBitmaps: Diskrete OMBitmaps (DOMBitmap) und Analoge OMBitmaps (AOMBitmap).

Diskrete optische Modul-Bitmaps

Ein DOMBitmap besteht im Gegensatz zum MBitmap aus mehreren (mind. 2) Bitmaps. Jedes dieser Bitmaps
hat eine ID (Nummer) über die das Anschalten (Zeichnen) des ensprechnden Bitmaps während einer Simu-Session
gesteuert werden kann. Die ID ist also die (einzige) Input-Variable.
Die Verwendung eines DOMBitmaps ist immer dann interessant, wenn ein opt. Element nur eine kleine Anzahl
von diskreten optischen Zuständen annehmen kann (z.Bsp: Schalter, Ein/Aus-Lampe).

Ein DOMBitmap kann mit Hilfe des Dialogs Menue: Tools/Create Edit DOM Bitmap erstellt bzw. editiert werden:

Über Add Bitmap fügt man die gewünschten Bitmaps in die Liste hinzu. Die Bitmaps müssen natürlich vorher
mit einem Image-Editor erstellt worden sein. Mittels der Clear-Buttons ist auch ein Löschen aus der Liste
möglich. Für die Connection-Points gilt das Selbe wie beim MBitmap. Mit dem Button Save DOModulBitmap
wird das gerade erstellte bzw. editierte DOMBitmap unter dem Namen <DOMBitmap Name>.dombmp im
Verzeichniss Data\<DOMBitmap Folder> gespeichert. Mittels Load DOModulBitmap kann ein DOMBitmap
zum Editieren oder Anschauen in den Dialog geladen werden.
Die ID ist eine ganze Zahl und muß für die Steuerung entsprechend eindeutig gewählt werden.
Die Bitmaps selber sind direkt in DOMBitmap-Datei enthalten, müssen also nicht unbedingt mitgeliefert werden.

Optisches Element mit DOMBitmap erstellen:

Ein opt. Element kann als externes Element mit allen SelfDef-Typen, dem DSelfDef als auch mit einem Modul-Script
erstellt werden. Die Vorgehensweise unterscheidet sich nur in der Auswahl des MBitmaps und dem Hinzufügen
eines speziellen Block's um das OMBitmap zu steuern.

Schauen wir uns das am Beispiel ToggleSwitch.selfdef mal genauer an. Der Script sieht im Wesentlichen so aus:

#MBitmap = ToggleSwitch.dombmp
#AutoComment = Toggle Switch
#Token = SW

#PinDescriptions
Pin1 = PinC
Pin2 = PinA
Pin3 = PinB
#End

#Parameter
State = State (a=0 | b=1), 0
ROpen = Resist Open (Ohm), 10M
RClose= Resist Close (Ohm), 1
#End

#VarsAndConstants
GOpen = 1/ROpen
GClose = 1/RClose
#End

#Volts
ua = u2 - u1
ub = u3 - u1
#End

#LaplaceCurrents
Ga = {State > 0 ? GOpen : GClose}
Gb = {State > 0 ? GClose : GOpen}
i2 = Ga*Ua
i3 = Gb*Ub
<i1 = -i2-i3>
#End

#DefineOpticalBehavior
OMBitmap.ID = {State > 0 ? 1 : 0}
#End

Das ist ein gewöhnlicher SelfDef-Script vom Typ LaplaceCurrents, der einen Umschalter beschreibt.
Nur bei #MBitmap wird ein DOMBitmap (Endung *.dombmp) verlinkt. Außerdem muß der Block
#DefineOpticalBehavior hinzugefügt werden, um der Input-Variablen ID des DOMBitmaps immer den
aktuellen Wert zu zuweisen. OMBitmap.ID muß genau einmal auf der linke Seite in diesem Block vokommen.
Die rechte Seite besteht aus einer Formel, die alle Symbole der linken Seite der Vorgänger-Blöcke enthalten
kann (wie bei den DynCharts). Hier wird der Parameter State verwendet. Bei State = 0 wird die Strecke a-->c
durchgeschaltet und das Bitmap mit der ID = 0 gezeichnet. Bei State = 1 wird die Strecke b-->c durchgeschaltet
und das Bitmap mit der ID = 1 gezeichnet.
Da State ein Parameter ist, wird er in der Regel mit Hilfe einer Circuit-Variable verändert, der Schalter bewegt
sich dann, wie von einer Geisterhand gesteuert, während einer Simu-Session.

Das opt. Element ToggleSwitch_Controlled.selfdef ist ähnlich aufgebaut, nur das ein zusätzlicher Ctrl-Pin
den Schalter steuert. Hier wird in #DefineOpticalBehavior die Pin-Spannung Uctrl zur Berechnung des richtigen
ID verwendet.

Analoge optische Modul-Bitmaps

Ein AOMBitmap beteht aus einem sogenannten Ground-Bitmap, sowie einem Script, der während einer
Simu-Session Drawing-Funktionen ausführt. Im Script können beliebig viele Input-Variable definiert werden,
die bei Ausführung des Script's Zeichenfunktionen steuern können. Dabei wird bei jedem Zeitschritt immer
erst das Ground-Bitmap gezeichnet, bevor die programmierten Drawing-Funktionen zeichnen.
AOMBitmaps sind immer dann interessant wenn sich das Aussehen proportional zu irgendwelchen Größen
ändern soll (z.Bsp. Zeiger-Instrumente, Lampe mit beliebiger Helligkeit, Ziffern-Anzeigen).

Ein AOMBitmap kann mit Hilfe des Dialogs Menue: Tools/Create Edit AOM Bitmap erstellt bzw. editiert werden.
Hier das Beispiel Voltmeter2.aombmp nach ausgeführten Test Script:

Mit dem Button Load Bitmap wird das Ground-Bitmap (muß mittels Image-Editor vorher erstellt worden sein)
geladen. Mit Load ModulBitmap kann (wie hier geschehen) ein schon vorhandenes AOMBitmap zum
Anschauen bzw. Editieren geladen werden. Mittels Save ModulBitmap wird das aktuelle AOMBitmap unter
dem Namen <MBitmap Name>. aombmp im Verzeichniss Data\<MBitmap Folder> gespeichert. Ground-
Bitmap und Script sind direkt in der Datei enthalten, müssen also nicht extra mitgeliefert werden.
Den Script kann man sich Anschauen bzw. Editieren nach Ausführung von Edit Script:

#DefineInputs
Alfa = 20
Umess = 1
mr = 1
#End

#SetFonts
ftest = "Times New Roman", 10, C_BOLD
fscale = "Times New Roman", 6, C_REGULAR
fmr = "Times New Roman", 10, C_BOLD
fu = "Times New Roman", 7, C_BOLD
#End

#VarsAndConstants
Wg = BgrndImage.Width
Hg = BgrndImage.Height
Hc = 28
l = 8
r = Wg/2
xp0 = r
yp0 = Hg - Hc
cscale = $ARGB(255,100,100,100)
cscaletext = $ARGB(255,0,0,255)
cmr = $ARGB(255,0,0,255)
cnadel = $ARGB(255,50,50,50)
cbgu = $ARGB(255,0,0,0)
cu = $HSV(180, 1.0, 1.0)
#End

#DrawInitImage
rc = r-5
rct = r-18
$DrawArc(Wg/2-rc, Hg-Hc-rc, 2*rc, 2*rc, -180, 180, 2, cscale)
$For i=1 To 9
   Beta = i*18
   xp1 = Wg/2-rc*cos(Beta)
   yp1 = yp0-rc*sin(Beta)
   xp2 = Wg/2-rct*cos(Beta) 
   yp2 = yp0-rct*sin(Beta) 
   $DrawLine(xp1, yp1, xp1+l*cos(Beta), yp1+l*sin(Beta), 2, cscale)
   $DrawString(xp2,yp2, fscale ,cscaletext, C_CENTER, $Format("%3.1f", i/10))
$EndFor
$DrawString(xp0,yp0-20, fmr , cmr, C_CENTERH, $FormatSI(mr, 3, "V"))
$FillRectangle(xp0, yp0+14, 40, 16, cbgu, C_CENTER)
#End

#DrawStepImage
xp = r *(1- cos(Alfa))
yp = yp0 - r*sin(Alfa)
$DrawLine(xp0, yp0, xp, yp, 1.5, cnadel)
$DrawString(xp0,yp0+14, fu , cu, C_CENTER, $FormatSI(Umess,3,"V"))
#End

Beschreibung der einzelnen Blöcke:

#DefineInputs
Hier können beliebig viele Input-Variable definiert werden. Links ist das Symbol, rechts der Defaultwert. 
Bei einer Simu-Session wird den Input-Variablen von einem SelfDef-Script aus (im Block #DefineOpticalBehavior)
für jeden (im Allgemeinen) Zeitschritt ein Wert zugewiesen. Der Default-Wert wird für Test Script, als auch für
verschiedene Anzeigen (Add Ext. Elemente Dialog, ToolBar-Symbol) verwendet, hat also für die eigentliche
Simulation keine Bedeutung. Die Symbole werden in den nachfolgenden Blöcken auf den rechten Seiten verwendet,
um die Drawing-Funktionen entsprechend zu steuern.

#SetFonts
Hier müssen Fonts für die Text-Zeichen-Funktionen vordefiniert werden. Links ist das Symbol, welches in den
Drawing-Funktionen verwendet wird. Rechts stehen (mit ','-Trennung) die Schrift-Familie, dann die Schrift-Größe
und der Schrift-Typ (C_REGULAR: normal, C_BOLD: fett, C_ITALIC: schräg, C_BOLDITALIC: schräg & fett).

#VarsAndConstants
Wie bei den SelfDef-Scripts werden hier beim Starten der Simulation (InitCompute-Prozess) Variable/Konstante
vorberechnet, die dann in den nachfolgenden Blöcken (als Symbole) verwendet werden können.

#DrawInitImage
Beim Start der Simulation (InitCompute-Prozess) wird erst das Ground-Image gezeichnet, dann zeichnen die
Drawing-Funktionen in diesem Block darüber. Man kann hier auch von einer Erweiterung des Ground-Image
zur Laufzeit sprechen. Dieser Block wird für eine Simu-Session nur einmal abgearbeitet, belastet den Rechner
also kaum. Oft ist es sogar praktischer für das Ground-Bitmap nur eine weisse Fläche zu verwenden, und das
MBitmap komplett im Script zu zeichnen (siehe Lamp_simple.aombmp).

#DrawStepImage
Die Drawing-Funktionen hier zeichnen während der Simu-Session bei jedem Zeitschritt über das Ground/Init-
Bitmap. Das Ground/Init-Bitmap wird immer erst neu in die Graphik-Oberfläche geladen, so dass man sich
keine Gedanken über den Hintergrund beim Zeichnen in diesem Block machen muß. Hier sollten so wenig wie
möglich Operationen durchgeführt werden (besser in den Vorgänger-Blöcken vorbereiten), da Berechnung
und Zeichnung für jeden Zeitschritt durchgeführt werden muß.

Es gibt Color-Funktionen, String-Format-Funktionen, Drawing-Funktionen sowie Struktur-Elemente.
Erläuterung der einzelnen Funktionen:

String-Format-Funktionen:

Funktion Beschreibung Parameter
$Format(FormatString, Var1, Var2,...) Bringt eine Zeichenkette zurück, die aus dem FormatString und den Vars gebildet wird. (wie Format-Funktion in C, nur %c ist nicht erlaubt) FormatString: String in Anführungszeichen
$FormatSI(Var, NumZiff, UnitString) Bringt Var als Zeichenkette in SI-Schreibweise mit angehängten UnitString zurück (z.Bsp. 0.12345 --> 123.4mV) Var: Variable
NumZiff: Anzahl der Ziffern
UnitString: anzuhängenter String

Color-Funktionen:

Funktion Beschreibung Parameter
$ARGB(A, R, G, B) Bringt einen Color-Wert zurück A: Alfa (0..255), R: Rot (0..255)
G: Grün (0..255), B: Blau (0..255)
$RGB(R, G, B) wie $ARGB nur A = 255  
$HSV(H, S, V) Bringt einen Color-Wert nach dem HSV-Farbraum zurück H: Farbton (0..360)
S: Sättigung (0..1)
V: Dunkelstufe/Helligkeit (0..1)

Drawing-Funktionen:

Funktion Beschreibung Parameter
$DrawLine(x1,y1, x2,y2, width, color) Zeichnet eine Linie vom Punkt x1,y1 zum Punkt x2,y2  x1,y1,x2,y2: Punkt-Koordinaten in Bezug auf die linke obere Ecke des
Bitmaps in Pixeln
width: Strich-Stärke in Pixeln
color: Color-Wert für Farbe
$DrawEllipse(x,y, w,h, width, color, align) Zeichnet Ellipse, die vom Rechteck x,y, x+w, y+h eingeschlossen wird analog zu $DrawLine()
align: Bezug von x,y zum Zeichenpunkt (siehe Aligntments)
$FillEllipse(x,y, w,h, color, align) Füllt Ellipse, die vom Rechteck x,y, x+w, y+h eingeschlossen wird mit der Farbe color analog zu $DrawEllipse()
$DrawRectangle(x,y, w,h, width, color, align) Zeichnet Rechteck an die Positiom x,y mit der Breite w und der Höhe h analog zu $DrawLine()
$FillRectangle(x,y, w,h, color, align) Füllt Rechteck an der Positiom x,y, der Breite w und der Höhe h mit der Farbe color analog zu $DrawLine()
$DrawArc(x,y w,h, alfa1,alfa2, width, color) wie $DrawEllipse(), nur das vom Winkel alfa1 bis zum Winkel alfa2 gezeichnet wird analog zu $DrawLine()
alfa1/alfa2: Winkel (0..360°)
$DrawPie(x,y w,h, alfa1,alfa2, width, color) wie $DrawArc, nur das Begrenzungslinien mit gezeichnet werden (Torte)  
$DrawString(x,y, font, color, align, String) Zeichnet die Zeichenkette in String an die Position x,y mit den Parametern in font und der Farbe color font: bei #SetFonts zu definieren
String: "XXX", String-Variable, $Format-Funktion oder Summations-Kette
Alle Drawing-Funktionen rufen letztendlich GDI+ Funktionen auf und ähneln daher Diesen. Also hier mal nachschauen.
Zeichenketten (Strings) können auch in einer sogenannten String-Summations-Kette zusammengefügt werden.
Eine String-Variable muß immer mit einer Tilte (~) anfangen. Strings werden in "" eingeschlossen.
Bsp. für Summations-Kette: ~text = "Der Wert beträgt " + $FormatSI(VoltVar, 3, "V")

Alignment-Konstanten:

Symbol Beschreibung
C_LEFTTOP x/y-Punkt bezieht sich auf obere linke Ecke des Zeichen-Rechtecks
C_CENTERH x/y-Punkt bezieht sich auf obere und horizontal zentrierte Position des Zeichen-Rechtecks
C_CENTERV x/y-Punkt bezieht sich auf linke und vertikal zentrierte Position des Zeichen-Rechtecks
C_CENTER x/y-Punkt bezieht sich auf vertikal und horizontal zentrierte Position (Mitte) des Zeichen-Rechtecks

Struktur Elemente:

Funktion / Anweisung Beschreibung
$FOR <ind>=<start> TO <end> <ind> wird mit <start> initialisiert, bei jedem Schleifendurchgang um 1 erhöht
bis <end> erreicht ist. Bei jedem Durchgang wird der Block bis $ENDFOR
gerechnet. <ind> ist nur innerhalb des $FOR-Blocks definiert
$ENDFOR schließt den $FOR-Block ab
$IF <val1> > <val2> $IF-Block wird ausgeführt wenn <val1> größer <val2> ist
$IF <val1> < <val2> $IF-Block wird ausgeführt wenn <val1> kleiner <val2> ist
$ELSE schließt $IF-Block ab und beginnt Alternativ-Block
$ENDIF schließt den $IF-Block oder $ELSE-Block ab

Noch zu beachten: Die Funktionen sin, cos, tan arbeiten hier speziell mit Winkeln in ° (0...360) !

Optisches Element mit AOMBitmap erstellen:

Dies geschieht praktisch genauso wie mit einem DOMBitmap. Schauen wir uns die wesentlichen Teile des
Beispiel's Voltmeter.selfdef an:

#MBitmap = Voltmeter2.aombmp
#AutoComment = <mr>V/<Rm>Ohm
#Token = Me

#Parameter
mr = MessRange (V), 1
Rm = MessResist (Ohm), 1M
#End

#VarsAndConstants
G = 1/(Rm+0.001)
#End

#Volts
u = u1 - u2
#End

#LaplaceCurrents
i1 = G*u
<i2 = -i1>
#End

#DefineOpticalBehavior
OMBitmap.Alfa = fmax(0, fmin(180,180/mr*u))
OMBitmap.Umess = u
OMBitmap.mr = mr
#End

Wir binden hier die besprochene Datei Voltmeter2.aombmp ein. Im Block #DefineOpticalBehavior 
müssen dann analog zum DOMBitmap die Input-Variablen zugewiesen werden. Wir haben hier nicht die feste
Input-Variable ID, sondern die im AOMBitmap-Script definierten Input-Variablen zu zuweissen. Also Alfa für
den  Winkel des Zeigers, Umess für die Digital-Ausgabe und mr um den Messbereich als Info anzuzeigen.

Zurück zur Hauptseite