Zum Hauptinhalt springen

Zähl- und Zeitfunktionen

Signalformung

Dirac-Impuls "dirac"

Die Funktion gibt mit der globalen diskreten Abtastzeit discreteSampleTimeMs einen 0-1-0 Impuls der Länge 1 ns aus. Der Rückgabetyp ist <bool>.

p = dirac();

Dirac-Impuls

hinweis

Da diese Funktion in der Regel für logische Funktionen verwendet wird, ist der Rückgabe Wert als <bool> direkt false oder true. Damit für einen "echten" Dirac-Impuls die Integralbedingung

δ(f)=δ(τ)f(τ)dτ=f(0)\delta(f) = \int\delta(\tau)f(\tau)d\tau = f(0)

stimmt, müsste dirac() mit 10910^{-9} multipliziert werden.

tipp

Um ein Signal mit der diskreten Abtastzeit discreteSampleTimeMs abzutasten, ist die Funktion sample(x) zu verwenden.

Timer "timer"

Die folgende Formel liefert periodisch zu den definierten Zeitpunkten einen Impuls oder den zugehörenden Zeitstempel.

pulse = timer({ interval: <dbl>   // verpflichtend, sofern nicht midestens ein (*) definiert ist
, grid: <bool>
, readTime: <bool>
, minute: <str>     // (*)
, hour: <str>     // (*)
, day: <str>     // (*)
, month: <str>     // (*)
, weekday: <str>   // (*)
});
// Das Konfigurationsobjekt ist verpflichtend, um darin
// eine eindeutige Konfiguration aus interval oder einem
// (*) - Element, um die Ereigniszeitpunkte zu definieren.
EigenschaftWertBeschreibung
interval<dbl>Zeitintervall, in dem ein Ereignis ausgelöst wird.
grid<bool>Ist diese Option gesetzt, wird Intervall unabhängig von der Startzeit der Berechnung auf 00:00:00 des Tages bezogen.
readTime<bool>Ist diese Option gesetzt, wird statt eines 1 Nano-Sekunde Impulses zur Ereigniszeit der Zeitstempel ausgegeben, uin64 in UTC-Nano-Sekunden seit 1.1.1970.
minute<str>crontab-Syntax zur Definition der Ereigniszeitpunkte
hour<str>crontab-Syntax zur Definition der Ereigniszeitpunkte
day<str>crontab-Syntax zur Definition der Ereigniszeitpunkte
month<str>crontab-Syntax zur Definition der Ereigniszeitpunkte
weekday<str>crontab-Syntax zur Definition der Ereigniszeitpunkte

Werden statt interval die Parameter hour, minute, day, month und/oder weekday verwendet, können explizite Triggerzeitpunkte (UTC) festgelegt werden.

Für jeden Eintrag in der Reihenfolge minute, hour, day, month, weekday ist folgende Angabe möglich (angelehnt an die crontab-Syntax):

AngabeBedeutung
keine Angabeist '*', wenn alle folgenden Elemente nicht definiert sind, sonst '0'
'*'immer / zu jeder
'*/n'im Interval von n
'a-e'im Bereich von a bis einschließlich e
'a,b,c'Komma-getrennte Liste von beliebigen Einzelwerten
Ausführung um/am a, b und c

Für Wochentage und Monate können statt Zahlen auch Kurznamen verwendet werden, die den ersten drei Buchstaben der englischen Bezeichnung entsprechen: z.B. “mon”, “thu”, “apr”, “jun”, “dec”, ... .

Die Zählung der Wochentage beginnt Sonntags “sun” mit 0.

Impulse können verwendet werden, um Summierungen oder Integrale zurückzusetzen oder entsprechende Werte in ein latch-Register zu übernehmen.

BeispielImpulszeitpunkt ...
{minute: 30, hour: 4}täglich um 4:30 Uhr, "nach Betriebsschluss"
{day: 1}am 01.01. eines Monats um 0:00 Uhr
{minute: '*/15'}alle 15 Minuten, x:00, x:15, x:30, x:45
{hour: 2, weekday: 'sun'}wöchentlich am Sonntag um 2:00 Uhr
{day: 15, month: 'apr-sep'}am 15. der Monate April bis September um 0:00 Uhr
{hour: '6,9,14,18'}täglich um 6, 9, 14 und 18 Uhr

Beispiel

Im Beispiel 1b wird die Funktion timer() zur Erzeugung eines Speicherimpulses zu einer festen Uhrzeit (Betriebsschluss) eingesetzt.

Verzögerung "delay"

Die folgenden Formeln dienen der Filterung und Verzögerung von Flanken eines Signals

delayed1_s = delay(signal, {...});
delayed2_s = delay(signal, reset, {...});
// Das Konfigurationsobjekt ist verpflichtend
delayedX_s = delay(..., { delayOn:<double>
, delayOff:<double>
, restart:<bool>
, startup: inf|<bool>
});
EigenschaftWertBeschreibung
delayOn<dbl>Zeit in Sekunden zur Verzögerung der positiven Flanke
delayOff<dbl>Zeit in Sekunden zur Verzögerung der negativen Flanke
restart<bool>Nachfolgende Flanken in der Wartezeit starten das Zeitintervall neu
startupinf/<bool>Startbedingung für die Flankenerkennung, siehe nachfolgende Beschreibung

Das Verhalten ist vom ausgegebenen Signalzustand abhängig. Ist dieser false, werden nur positive Flanken auf dem Eingangssignal signal und der Zeitparameter delayOn berücksichtigt. Ist der Zustand true, werden negative Flanken und der Zeitparameter delayOff berücksichtigt.

Flankenverzögerung

Die Zeitmessung beginnt jeweils mit der ersten eintreffenden Flanke und kann optional mit weiteren folgenden Flanken neu gestartet werden (restart: true). Der Ausgangszustand wechselt nur dann, wenn mit Ablauf der Zeit das Eingangssignal im entgegengesetzten Zustand anliegt. Damit werden nur kurze Signalwechsel gefiltert und Signalwechsel nur nach Stabilisierung des Signals verzögert weiter gegeben.

Mit einem true am reset Eingang wird der Ausgangszustand auf false zurück gesetzt und gehalten.

Die Funktion kann genutzt werden, um ein "prellendes" Schaltsignal zu filtern und zu stabilisieren.

Für den Systemstart muss festgelegt werden, wie mit der Vergangenheit des Eingangs signal umgegangen wird und ob damit beim Start unmittelbar eine Flanke erkannt und damit eine Wartezeit ausgelöst werden soll. Dafür dient die Eigenschaft startup:

  • inf: das erste Signal-Sample bestimmt den Wert in der Vergangenheit und damit den Ausgang vor Systemstart, eine Flanke wird damit nicht mit dem ersten Sample ausgelöst.

  • <bool>: Der Eingang und der Ausgang werden mit diesem Signalwert (true, false) in der Vergangenheit vor Systemstart angenommen. Damit kann möglicherweise eine Flanke mit dem ersten Sample des Eingangs ausgelöst werden und eine delay-Zeit gestartet werden.

Eigenschaft startup

Puls "pulse"

Die folgenden Formeln wandeln eine wählbare Eingangsflanke auf signal in einen rechteckigen, boolschen Impuls der Dauer duration um (ähnlich einem Mono-Flop 74HC121 oder 74HC122). Mit einem true am Parameter reset wird der Ausgang auf false zurück gestellt und gehalten. Alle Parameter werden als <bool> interpretiert.

p1 = pulse(signal, {...});
p2 = pulse(signal, reset, {...});
p3 = pulse(signal, reset, duration, {...});
// Das Konfigurationsobjekt ist verpflichtend
px = pulse(..., { edge:<int>
, duration:<double>
, restart:<bool>
, startup: inf|<bool>
});
EigenschaftWertBeschreibung
edge<int>Auswahl der steuernden Flanke:
-1: negEdge,
0: anyEdge,
+1: posEdge (default)
duration<dbl>Dauer des Impulses in Sekunden
restart<bool>Verlängerung des Impulses mit erneuter Flanke möglich
startupinf/<bool>Startbedingung für die Flankenerkennung, siehe nachfolgende Beschreibung

Das folgende Beispiel zeigt für edge = +1 das Verhalten für die Eigenschaft restart:

Puls Signal

Für den Systemstart muss festgelegt werden, wie mit der Vergangenheit des Eingangs signal umgegangen wird und ob damit beim Start unmittelbar eine Flanke erkannt und damit ein Impuls ausgelöst werden soll. Dafür dient die Eigenschaft startup:

  • inf: das erste Signal-Sample bestimmt den Wert in der Vergangenheit vor Systemstart, eine Flanke wird damit nicht mit dem ersten Sample ausgelöst.

  • <bool>: Der Eingang wird mit diesem Signalwert (true, false) in der Vergangenheit vor Systemstart angenommen. Damit kann möglicherweise eine Flanke mit dem ersten Sample ausgelöst werden.

Eigenschaft startup

Funktionsgenerator "periodic"

Die Funktion periodic() kann als Funktionsgenerator eingesetzt werden und erzeugt ein periodisches Signal mit der Periodendauer period, solange der Eingang enable auf true gehalten wird. Die Signalform wird durch die Eigenschaft mode festgelegt. Die Ausgaberate erfolgt mit der globalen diskreten Abtastzeit discreteSampleTimeMs oder der gesetzten Ausgaberate fOut.

p1 = periodic(enable, {...});
p2 = periodic(enable, control, {...});
p3 = periodic(enable, control, period, {...});
// Das Konfigurationsobjekt ist verpflichtend
px = periodic(..., { period: <dbl>
, mode: <enum>
, reset: <enum>
, control: <dbl>
, fOut: <dbl>
, width: <uint>
, taps: [<uint>]|p##
});
EigenschaftWertBeschreibung
period<dbl>Konstante Periodendauer des Signalverlaufs in Sekunden, entspricht Eingang period
Wertebereich: [0.0001..[[0.0001 .. \infty[
mode<enum>Betriebsart (def.: ramp)
[rect, pwm, time, ramp, ramp2, sawtooth, 2Pi…]
reset<enum>Rückstellung des Signalverlaufs mit
[stop, start, none]
control<dbl>Konstanter Steuerwert für PWM, entspricht Eingang control
fOut<dbl>Optionale Ausgaberate für Datenpunkte in Hertz
Wertbereich [0.1..[[0.1..\infty[
width<uint>PRBS Signal-Ausgabebreite
Wertebereich [0..64][0..64]
taps[<uint>]/p##PRBS Rückführpositionen oder vordefiniertes Polynom p2..p12

Die optionalen Eingänge control und period haben Priorität über den fest eingestellten Eigenschaften. Ändert sich die Periodendauer während der Signalausgabe, wird der Signalverlauf stoßfrei an der aktuellen Ausgabeposition (*) fortgesetzt.

Auch wenn die Auswahl der Periodendauer und Ausgaberate zunächst keiner Beschränkung unterliegt, sind sinnvolle Werte im Hinblick auf die Funktion des smartCOREs zu wählen.

Werte für reset:

  • stop: (default) Der Ausgabewert wird mit enable == false zurückgesetzt.

  • start: Der Ausgabewert bleibt bis zum erneutem Start stehen und wird erst dann zurückgesetzt.

  • none: Die Ausgabe wird mit enable == false nur angehalten, nicht zurückgesetzt.

Ein paar Beispiele für Ausgabe-Modi in Verbindung mit der Periodendauer period, der Ausgaberate fOut, einem Steuersignal control und verschiedenen reset Einstellungen

Periodische Signale

Mode: rect

Ausgegeben wird ein <bool> 0-1-Rechtecksignal, wobei control [0.0..1.0]\in [0.0..1.0] die relative Lage der positiven Flanke im period-Zeitraum darstellt (default: 0.5). Reset-Zustand ist 0!

Mode: pwm

Ausgegeben wird ein <bool> 1-0-Rechtecksignal, wobei control [0.0..1.0]\in [0.0..1.0] die relative Lage der negativen Flanke im period-Zeitraum darstellt (PWM, default: 0.5). Reset-Zustand ist 0!

Mode: time

Ausgegeben werden Rampen mit den Zeitwerten [0.0..period[[0.0 .. period[ in Sekunden

Mode: ramp (def.)

Ausgegeben werden Rampen mit der relativen Position im Interval als Skalierungswert [0.0..1.0[[0.0..1.0[

Mode: ramp2

Ausgegeben werden Rampen mit den Skalierungswerten [0.0..1.0[,[1.0..0.0[[0.0..1.0[, [-1.0 .. 0.0[, wobei der Rücksprung auf 1.0-1.0 in der Mitte der Periodendauer liegt.

Mode: sawtooth

Ausgegeben wird ein Sägezahnförmiger [0.0..1.0..0.0[[0.0 .. 1.0 .. 0.0[ Verlauf, wobei control =[0..1]=[0..1] die relative Lage der 1.0-Spitze im period-Zeitraum darstellt. Reset-Zustand ist 0.0!

Mode: 2pi

Ausgegeben wird die relative Poisition im Interval als Winkelwert [0.0..2π[[0.0 .. 2π[ für nachgeschaltete Winkelfunktionen.

wave = 10.0 * sin(periodic(true, { mode : 2pi
, period: 2.0 // Signal-Periode / s
, fOut: 100.0})); // Sample-Rate

Mode: prbs

Ausgabe eines Pseudo Binären Rauschsignals (pseudo random binary sequence) mit der Ausgabefrequenz fOut. Die Periodenlänge ergibt sich aus dem konfigurierten Generator, der Parameter period wird ignoriert.

Auf dem internen 64-bit Schieberegister sind NXOR-Rückführungen an den durch taps[] markierten Stellen vorgesehen. width (def: 0) ist die bit-Breite der Ausgabe-Maske für das Schieberegister, um das PRBS zur Generierung von pseudozufälligen Amplituden zu verwenden. Mit width: 0 wird nur eine <bool>-Sequenz ausgegeben.

Für taps können auch vordefinierte Polynome p2 .. p12 als Rückführung für die Längen 2 .. 12 bit abgerufen werden.

Das PRBS Signal kann für die Paramater-Identifikation dynamischer Systeme verwendet werden.

Zählen und Messen

Zähler "counter"

Die folgenden Formeln zählen positive Flanken in verschiedenen Konfigurationen.

vorsicht

Die Bedeutung der Parameter ist vom eingestellten Betriebs-Mode abhängig!

c1  = counter(up);
c2 = counter(up, down);                     // mode: updown
c3 = counter(up, down, reset);             // mode: updown
c4 = counter(up, down, reset, preset);      // mode: updown
c5 = counter(count, dir);                   // mode: countdir
c6 = counter(count, dir, reset);            // mode: countdir
c7 = counter(count, dir, reset, preset);    // mode: countdir
c8 = counter(count, incr);                  // mode: countinc
c9 = counter(count, incr, reset);           // mode: countinc
c10 = counter(count, incr, reset, preset);   // mode: countinc
c11 = counter(A, B);                   // mode: qencoder
c12 = counter(A, B, reset);            // mode: qencoder
c13 = counter(A, B, reset, preset);    // mode: qencoder
// Optionale Konfiguration für alle Varianten
cX = counter(..., { mode: <enum> // verpflichtend, falls nicht 'updown'
, start: <int>
, preset: <int>
, lower: off|<int>
, upper: off|<int>
, range: <uint>
, modulo: <uint>
, storage: <str>
});

Im Mode updown (default) wird mit positiven Flanken auf up aufwärts und auf down abwärts gezählt (ähnlich einem 74HC193) . Kommen die Flanken exakt zum gleichen Zeitpunkt, wird +11=0+1-1=0 gezählt.

Im Mode countdir werden positive Flanken am count Eingang gezählt und die Richtung wird unabhängig davon mit dem dir-Eingang vom Typ <dbl> vorgegeben (ähnlich 74HC191). Ist dir > 0.0 (oder true), wird aufwärts gezählt, sonst mit dir <= 0.0 (oder false) abwärts. Default ist 1.0 bzw. true (aufwärts). Die Verwendung des Typs <dbl> für die Richtung erlaubt die Nutzung eines analogen Geschwindigkeits-Messwerts (z.B. in "m/s"), um die Zählrichtung zu steuern. Andrerseits ist der Eingang kompatibel zu <bool> Signalen.

mode: countdir

Anwendungsbereiche sind die Positionsbestimmung für lineare oder rotatorische Bewegungen oder auch die richtungsabhängige Zählung von Objekten, die an einer Zählstation vorbeigeführt werden.

Im Mode countincr wird die Zählschrittweite über den incr-Eingang vom Typ <int> mit steigender Flanke auf count zum Register addiert. Default ist 1 (aufwärts). Die Größenordnung von incr ist der eingestellten Zählerbreite, den Zählergrenzen, etc. sinnvoll anzupassen.

Im Mode qencoder werden alle Flanken auf den phasenverschobenen Signalen A und B gezählt. Die Verwendung der zwei Eingänge ist somit verpflichtend. Dabei gibt jeweils das Signal ohne Flanke die Zählrichtung an. Anwendungsbereiche sind die hochgenaue Positionsbestimmung für lineare oder rotatorische Bewegungen in 4-fach Auflösung ("Quadrature Encoder"). Dafür sollten die Flanken exakt die gleichen Abstände zueinander haben.

mode: qencoder

Für die im Bild gezeigte Anordnung ergibt sich folgendes Zählschema:

ABRechtslauf
Inkrementieren
Linkslauf
Dekrementieren
00\downarrow A: 0->1\uparrow B: 0->1
10\downarrow B: 0->1\uparrow A: 1->0
11\downarrow A: 1->0\uparrow B: 1->0
01\downarrow B: 1->0\uparrow A: 0->1
00\downarrow A: 0->1\uparrow B: 0->1

Mit einem true am reset Eingang wird der Zähler auf preset (def: 0) gesetzt und gehalten. preset kann über die Eigenschaften oder als viertes Argument übergeben werden.

Das Zählregister ist vom Typ <int64>.

EigenschaftWertBeschreibung
mode<enum>updown: Getrennte Zähleingänge für auf / ab (def.)
countdir: Zähleingang und getrennte Richtung <dbl> (> 0.0: aufwärts)
countincr: Takteingang und getrennte Schrittweite als <int>
qencoder: Alle Flanken der Taktsignale A, B werden richtungsabhängig gezählt
start<int>Startwert mit Start des smartCOREs
preset<int>Rücksetzwert mit true auf Paraemetr r
loweroff/<int>Zählwert stoppt an unterer Grenze,
kein Überlauf
upperoff/<int>Zählwert stoppt an oberer Grenze,
kein Überlauf
range<uint>Zählwert Bereich
[0..range1][0..range-1]
Überlauf von den Randwerten nach 00 oder range1range-1
modulo<uint>Zählwert Bereich count %= modulo mit Vorzeichen
[1modulo..modulo1][1-modulo..modulo-1]
Überlauf von den Randwerten nach 0
storage<str>Name eines persistenten Speichers für den internen Zustand. Damit bekommt nach einem Neustart des Systems der Ausgang den zuletzt gespeichert Wert. Der Inhalt dieses Speichers ist an keiner anderen Stelle im smartCORE nutzbar.

Stoppuhr "stopwatch"

Die folgenden Formeln stellen eine Stoppuhr dar und messen die Länge eines Impulses pulse oder das Intervall zwischen zwei positiven Flanken auf pulse oder zwischen der ersten positiven Flanke auf beg zur nachfolgenden positiven Flanke auf end. Die Messung beginnt mit der Startbedingung immer bei t=0.0st=0.0s. Mit einer Flanke am Eingang lap kann eine Zwischenzeit ausgegeben werden (latch = true). True am Eingang reset stellt die Stoppuhr und Ausgabe auf 0.0 und hält sie in diesem Zustand. Alle Eingänge werden als <bool> interpretiert. Die Ausgabe erfolgt in Sekunden.

t1 = stopwatch(pulse);        
t2 = stopwatch(beg,end);
t3 = stopwatch(beg,lap,end);
t4 = stopwatch(beg,lap,end,reset);
// Optionale Konfiguration für alle Varianten
tx = stopwatch(..., { latch: <bool>
, period: <bool>
, hold: <bool>
, restart: <bool>
, upper: off|<dbl>
});
EigenschaftWertBeschreibung
latch<bool>true: Ausgabe der Zeit erfolgt nur mit den steuernden Flanken (def.)
false: Kontinuierliche Ausgabe der ansteigenden Messzeit
period<bool>true: Messung zwischen zwei steigenden Flanken am Eingang pulse
false: Messung der Zeit für pulse = true
hold<bool>true: die Ausgabe wird nur mit Abschluss der Messung auf den neuen Messwert gesetzt.
false: die Ausgabe wird mit neuer/laufender Messung auf 0 gesetzt.
restart<bool>true: jede steigende Flanke an beg startet die Messung neu
false: nur die erste steigende Flanke an beg startet die Messung (def.)
upperoff/<dbl>Wenn dieser Zeitwert erreicht wird, erfolgt die Ausgabe und die Messung wird abgebrochen. (def.: off)

In der ersten Form wird nur ein Impulssignal pulse verwendet. Das folgende Diagramm zeigt verschiedene Konfigurationen und Ausgabemöglichkeiten zur Messung an einem Impulsssignal:

Zeitmessung Impulssignal

Die erste Zeile zeigt ein beliebiges zu messendes Impulssignal.

Die zweite Zeile zeigt für die Pulsdauermessung mit den aufsteigenden, gestrichelten Rampen die Zeit, die seit der zugehörenden Flanke am Fußpunkt links vergangen ist. In Magenta schließlich die Ausgabe der stopwatch() Funktion für verschiedene Eigenschaften latch, hold oder upper.

Die dritte Zeile zeigt für die Periodenmessung mit den aufsteigenden, gestrichelten Rampen wieder die Zeit, die seit der zugehörenden Flanke am Fußpunkt links vergangen ist. In Orange oder Blau schließlich die Ausgabe der stopwatch() Funktion in Abhängigkeit der Eigenschaften latch oder upper.

Für den Betrieb mit beg, lap und end Eingängen ist Konfiguration der Ausgabe entsprechend. Mit der Eigenschaft restart kann eine aktive Messung mit jeder neuen Flanke an beg wieder bei 0.0 beginnen, wodurch der Abstand ab der letzten steigenden Flanke zur Flanke auf end gemessen wird. In dieser Betriebsart kann die Ausgabe von Zwischenzeiten irreführend sein. Im folgenden Diagramm ist die Eigenschaft latch = true gesetzt, um die Ausgabe von Zwischenzeiten zu ermöglichen.

Zeitmessung Begin Lap End

Die ersten drei Zeilen zeigen exemplarische Zeitverläufe der Eingangssignale beg, lap und end. Der lap-Eingang ist optional. In den gestrichelten Bereichen ist entweder eine Rückkehr des Signals nach false (grün) zu einem beliebigen Zeitpunkt möglich, da für den Eingang beg nur eine steigende Flanke relevant ist, oder das Signal darf jeden beliebigen Zustand annehmen (rot, blau), da die Uhr nicht gestartet ist.

In der unteren Zeile folgt wieder die Ausgabe der Funktion stopwatch() für verschiedene Einstellungen der Eigenschaften restart und hold. Die aufsteigenden, gestrichelten Rampen zeigen die Zeit, die seit der zugehörenden Flanke am Fußpunkt links vergangen ist.

hinweis

stopwatch() misst nur die Länge eines einzelnen Ereignisses. Um die summierte Einschaltdauer eines Aggregates (Heizung, Kompressor, etc) zu ermitteln, ist die integrate(x, {...}) Funktion zielführend.

total_on_time = integrate(onState, {storage:'myTotalizerX'});

Dabei ist onState ein <bool> Statussignal, das als 0 oder 1 den Integranden bildet. Optional könnte noch ein Reset Signal zum Zurücksetzen des integrierten Wertes verwendet werden.