Modellierung von DigitalElementen mit dem DSelfDef-Script

Ein DSelfDef-Element hat im Allgemeinen folgenden Grundaufbau:

Ein DSelfDef besteht aus voneinander getrennten Eingängen und Ausgängen. Ein Eingang (InputVolt) misst die 
Pinold-Spannung zwischen dem Plus-Pin und dem Minus-Pin. Er hat einen Eingangswiderstand und eine
optionale Kapazität. Im Regel-Fall ist ein Pin von Beiden an die interne Masse (Pin 0) geschaltet, so das es
nicht herausgezogen werden muß (kein Anschluß-Pin). Bei den Ausgängen unterscheidet man zwischen 
Spannungs-Quelle mit Ausgangswiderstand (OutputVolt) und Leitwert (OutputConductance).  Ein OutputVolt
besteht aus einem Plus-Pin und einem Minus-Pin zwischen denen die Pin-Spannung entsteht. Eine Output-
Conductance
besteht aus einem Leitwert (Widerstand), der zwischen beide Pins geschaltet wird. Wie beim
Eingang kann auch bei einem Ausgang ein Pin von Beiden an die interne Masse (Pin 0) geschaltet werden.
Die Ausgangswerte (Uout's, Gout's) werden bei jedem Zeitschritt über das innere Verhalten (Inner Behavior)
aus den Eingangswerten (Uin's) berechnet. Da bei den Eingängen die PinOld-Spannung (Spannung einen Zeitschritt
vorher) benutzt wird, sind die Ausgänge von den Eingängen statisch entkoppelt. Das bedeutet, dass eine Spannungs-
Änderung am Eingang erst einen Zeitschritt später zur Reaktion an den Ausgängen führen kann. Bei genügend
kleiner Zeit-Schrittweite kann man das aber verschmerzen. Diese Entkopplung hat aber den großen Vorteil, dass
man nicht auf Stetigkeit und Differenzierbarkeit irgendwelcher Funktionen bei der Definition des inneren Verhaltens
achten muß. Auch muß deswegen der Ausgangswert für den Zeitpunkt t = 0 initialisiert werden.
Im Allgemeinen erstellt man mittels DSelfDef-Script's digitale Elemente. Da man bei InnerBehavior auch ganz
normale analoge Funktionen verwenden kann und auch die Spannungen analog auftreten, besteht die Möglichkeit
auch analoge Elemente zu modellieren, wenn Diese statisch trennbare Ein- und Ausgänge haben und der statische
Arbeitspunkt festgelegt ist oder keine Rolle spielt. Zum Beispiel für einen Transistor geht das nicht, da die Statik
hier eine herausragende Bedeutung hat (die Kennwerte sind vom AP abhängig).
DSelfDef's können in einer Schaltung beliebig mit anderen Element-Typen gemischt werden, da sie ja praktisch
als analoge Elemente auftreten. Auch zum Lösen von Differential-Gleichungs-Systemen eignen sie sich
hervorragend.
Kleinsignal-Analyse (LSA) macht bei DSelfDef natürlich keinen Sinn. Die Schrittweiten-Steuerung sollte besser
abgeschaltet sein, wenn DSelfDef-Elemente in einer Schaltung verwendet werden.

So, nun wollen wir uns anhand von Beispielen der Sache weiter nähern.

Modellierung eines Nand-Gatters:

Wir machen erstmal wieder eine Skizze und tragen die Pin-Nummern und die Spannungsbezeichnungen ein:

Alle Pin-Spannungen sind auf die interne Masse bezogen. Das ist in der Regel immer so.

Jetzt schauen wir uns gleich mal den Script an:

#Parameter
Umax = Umax(V), 5
Uth = Uth(V), 2.5
Rin = Rin(Ohm),1k
Cin = Cin(F), 100p
Rout = Rout(Ohm), 100
U0 = U0(t=0)(V), 0
#End

#VarsAndConstants
#End

#InputVolts
uin1 = 1,0,Rin,Cin
uin2 = 2,0,Rin,Cin
#End

#OutputVolts
uout = 3,0,U0,Rout
#End

#InnerBehavior
uout = Umax*$nand(uin1, uin2, Uth)
#End

Hier der vollständige Script von Nand.dselfdef.

Bei #InputVolts tragen wir unsere Eingangsspannungs-Quellen ein.
Eine Zeile hat folgende Syntax:

<USymbol> = <+Pin>, <-Pin>, <Rin>, <Cin>

Bei <Pin> trägt man die Anschluss-Pin-Nummer ein, 0 steht für die interne Masse. <Rin> und <Cin>
können Werte, Parameter als auch Vars/Constants sein. <Cin> ist optional.

Bei #OutputVolts tragen wir unsere Ausgangsspannungs-Quellen ein.
Eine Zeile hat folgende Syntax:

<USymbol> = <+Pin>, <-Pin>, <U0>, <Rout>

Bei <Pin> trägt man die Anschluss-Pin-Nummer ein, 0 steht für die interne Masse. <U0> und <Rout>
können Werte, Parameter als auch Vars/Constants sein. <U0> ist der Initialisierungs-Wert für t = 0.

#InnerBehavior ist der zentrale Teil, in dem die Berechnungen für das Verhalten pro Zeitschritt durchgeführt
werden und den Ausgangs-Spannungen bzw. Ausgangs-Leitwerten ein Ergebnis zugewiesen werden muß.
Hier können USymbole, Parameter, Vars/Constants, ZwischenVariable und StateVars verwendet werden.
Wir benutzen hier die Spezial-Funktion $Nand womit sich die Sache stark vereinfacht.
Hier alle Spezial-Funktionen, die nur für DSelfDef zur Verfügung stehen. Es können natürlich auch alle
normalen Funktionen benutzt werden.
Man sieht, dass man sich nicht mit irgendwelchen Pin-Strömen herum schlagen muß.

Innerhalb von #DefineDynCharts können USymbols, Parameter, Vars/Constants und StateVars verwendet
werden.

Wir haben hier ein sehr einfaches Nand-Gatter konstruiert, es schaltet schlagartig von einem Zeitschritt zum
Nächsten wenn beide Eingänge den Wert Uth über/unter-schreiten. Wir könnten aber wenigstens eine
definierte Verzögerung hineinbringen. Die Zeile in #InnerBehavior sähe dann folgendermaßen aus:

uout = Umax*$Delay($nand(uin1, uin2, Uth), Tv)   ; Der Ausgangswert von $Nand wird um Tv verzögert.

Nun testen wir das Gatter im harten Einsatz und öffnen die Schaltung DocSamples/DigiNand_AMulti.circ:

Der Kondensator C1 verhindert wilde Schwingungen, die durch Einschritt-Verzögerung der Gatter hervorgerufen wird.
Realistischer wäre es, wenn man die Gatter mit einem definierten Delay ausstatten würde. Also, als Übung mal das
DigiElement Nand_withDelay.dselfdef verwenden.

In ToneCirc ist das interne Nand-Element realcurrent-mäßig (nichtlinear, mit I(U)-Funktionen) implementiert. Es braucht
natürlich wesentlich mehr Rechenaufwand, simuliert aber das Umschalt-Verhalten wesentlich realitätsgetreuer.

Modellierung RS-FlipFlop mit Nand-Gattern:

Hier wieder eine Skizze, die Spannungspfeile gegen Masse erspare ich mir aber absofort:

       

In den Script schreiben wir nun gleich hinein:

#InputVolts
US  = 1,0,Rin,Cin
UR = 2,0,Rin,Cin
#End

#OutputVolts
UQ    = 3,0,0.0,Rout
UQN = 4,0,0.0,Rout
#End

#InnerBehavior
UQ    = Umax*$Nand(US,_UQN, Uth)
UQN = Umax*$Nand(UR,_UQ, Uth)     ;(uR=0,uS=0) --> (uR=1,uS=1): Ausgänge alternieren
#End

Hier der vollständige Script von RSFlipFlop.dselfdef.

zu #InnerBehavior:
Wegen der Rückkopplung von den Ausgängen auf die Eingänge müssen Ausgangs-Spannungen auch auf
der rechten Seite in der Nand-Funktion eingesetzt werden. Hier muß man nun vor das USymbol ein Underline ('_')
setzen um zu erzwingen, dass die PinOld-Spannung verwendet wird. Alle Eingangs-Spannungen sind ja per default
PinOld-Spannungen.

Bitte die Schaltung DocSamples/Test_RSFlipFlop.circ öffnen um den RS-FF zu testen:

Wir Ihr seht habe ich für die Ausgaben mal einen GlobalScope verwendet um die Signale übersichtlich übereinander
zu setzen. Def1 ist ein einfacher Delayer, der dafür sorgt, dass die Pulse zeitverschoben an den Eingängen ankommen.

Modellierung Flanken-getriggerter MonoFlop:

     

Im Script sieht das so aus:

#InputVolts
uc = 1,0,Rin,Cin
#End

#OutputVolts
uq = 2,0,0.0,Rout
#End

#InnerBehavior
Z  = $RisingEdgeTrigger(uc, Uth, 0)
uq = Umax*$MonoFlop(Z, 0.5, Ti)
#End

Hier der vollständige Script von monoflop_edgetriggered.dselfdef.

Zu #InnerBehavior:
Die erste Zeile erzeugt einen kurzen Impuls (Z = 1) wenn UC bei ansteigender Flanke Uth überschreitet. Ansonsten
wird immer 0 zurückgegeben (Z = 0, letzter Parameter).
In der zweiten Zeile gibt $MonoFlop für eine definierte Zeit (Ti) 1 zurück wenn Z > 0.5 (also 1) wird.

Bitte die Schaltung DocSamples/Test_MonoFlop_edgetrigg.circ öffnen um den MonoFlop zu testen:

Hier gibt es nichts weiter zu sagen.

Modellierung gesteuerter Schalter:

Um den Ausgangs-Leitwert zu behandeln, hier noch der spannungs-gesteuerte Schalter:

      

Im Script steht:

#VarsAndConstants
Goff = 1/Roff
Gon = 1/Ron
#End

#InputVolts
uctrl = 3,0,Rin,Cin
#End

#OutputConductances
Gout = 1,2,Goff
#End

#StateVars
#End

#InnerBehavior
Gout = {Uctrl > Uth ? Gon : Goff}      ;if Uctrl > Uth then Gout = Gon else Gout = Goff
#End

Hier der vollständige Script von ControlledSwitch.dselfdef.

Man sieht, dass der Ausgangsleitwert Gout mit Hilfe der Relations-Funktion umgeschaltet wird wenn Uctrl
Uth erreicht. Um einen Ausgangsleitwert zu definieren benutzen wir eine Zeile in #OutputConductances.

Eine Zeile in #OutputConductances hat folgende Syntax:

<GSymbol> = <Pin1>, <Pin2>, <G0>

Bei <Pin> trägt man die Anschluss-Pin-Nummer ein, 0 steht für die interne Masse. <G0> kann ein Wert,
Parameter als auch Vars/Constants sein. <G0> ist der Initialisierungs-Wert für t = 0.

Die meisten Digi's befinden sich im Verzeichniss Data/Digital Elements.

Zurück zur Hauptseite