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();
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
stimmt, müsste dirac() mit multipliziert werden.
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.
Impulse können verwendet werden, um Summierungen oder Integrale zurückzusetzen oder entsprechende Werte in ein latch-Register zu übernehmen.
Die Impulse werden nicht nachgeholt, wenn das System zum Impulszeitpunkt nicht aktiv war.
pulse = timer({ interval: <time> // verpflichtend, sofern nicht midestens ein (*) definiert ist
, aligned: <bool>
, readTime: <bool>
, useTZ: <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.
| Eigenschaft | Wert | Beschreibung |
|---|---|---|
| interval | <time> | Zeitintervall, in dem ein Ereignis ausgelöst wird. |
| aligned | <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, uint64 in UTC-Nano-Sekunden seit 1.1.1970. |
| useTZ1 | <bool> | Verwende zur Interpretation der Uhrzeit die mit dem #timezone-Macro eingestellte lokale Zeitzone.Warnung: Zeitstempel die in die Zeitspanne der Zeitumstellung fallen, können übersehen werden! |
| 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 minute, hour, 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):
| Angabe | Bedeutung |
|---|---|
| keine Angabe | ist '*', wenn alle folgenden Elemente nicht definiert sind, sonst der kleinsmögliche Wert, i.d.R. '0' (bzw. '1' für day und month). |
| '*' | immer / zu jeder |
| '*/n' | im Interval von n |
| 'a-e' | im Bereich von a bis einschließlich e |
| 'a-e/n' | im Bereich von a bis einschließlich e im Raster n Ausführung um/am , , , mit |
| '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.
Beispiele für die crontab-Syntax:
| minute: | hour: | day: | month: | weekday: | Impulszeitpunkt ... |
|---|---|---|---|---|---|
30 | 4 | täglich um 4:30 Uhr, "nach Betriebsschluss" | |||
1 | am 01. eines Monats um 0:00 Uhr | ||||
'50-59/4' | 23 | 30 | '3-12/3' | am 30.03., 30.6., 30.09., 30.12., jeweils um 23:50, 23:54, 23:58 | |
'*/15' | alle 15 Minuten, x:00, x:15, x:30, x:45 | ||||
'3-59/15' | alle 15 Minuten, x:03, x:18, x:33, x:48 | ||||
15 | 'apr-sep' | am 15. der Monate April bis September um 0:00 Uhr | |||
10 | 'oct-mar' | am 10. der Monate Oktober bis März | |||
'6,9,14,18' | täglich um 6, 9, 14 und 18 Uhr | ||||
2 | '*' | '*' | 'sun' | wöchentlich am Sonntag um 2:00 Uhr | |
30 | 2 | 'mon' | WARNUNG: Die Einträge für day und month fehlen |
Im letzten Beispiel liegt eine Unstimmigkeit vor, da die Einträge für day und month nicht angegeben sind, also im Automatik-Mode stehen. Laut Regelwerk werden diese per Default gegen ihren ersten Wert (hier also 1) verglichen, da rechts davon eine Zuweisung steht. Dies führt aber nicht zum gewünschten Ergebnis.
trigg_1 = timer({minute:30, hour:2, weekday:sun});
Im Log-File2 wird eine Warnung für diese Unstimmigkeit ausgegeben:
|WARNING|module.math: (WW) "timer(24): Enclosed, automatic definitions found in crontab! Criteria may not function as expected! Please review the definition."
Solange ein zusammenhängender Block von Eigenschaften definiert wird, werden die Rand-Elemente korrekt automatisch ergänzt. Links mit ihrem kleinsten Wert (0 oder 1), rechts mit '*', Beispiele:
-
minute, hour, day
-
day, month
-
hour, day
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: off|<time>
, delayOff: off|<time>
, restart:<bool>
, startup: inf|<bool>
});
| Eigenschaft | Wert | Beschreibung |
|---|---|---|
| delayOn | off/<time> | Zeit in Sekunden zur Verzögerung der positiven Flanke off3 oder 0: keine Verzögerung (def.) |
| delayOff | off/<time> | Zeit in Sekunden zur Verzögerung der negativen Flanke off3 oder 0: keine Verzögerung (def.) |
| restart | <bool> | Nachfolgende Flanken in der Wartezeit starten das Zeitintervall neu |
| startup | inf/<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.
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.
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. Die Eingänge signal und reset werden als <bool> interpretiert, der Eingang duration als Dauer in Sekunden.
p1 = pulse(signal, {...});
p2 = pulse(signal, reset, {...});
p3 = pulse(signal, reset, duration, {...});
// Das Konfigurationsobjekt ist verpflichtend
px = pulse(..., { edge:<int>
, duration:<time>
, restart:<bool>
, startup: inf|<bool>
});
| Eigenschaft | Wert | Beschreibung |
|---|---|---|
| edge | <int> | Auswahl der steuernden Flanke: -1: negEdge, 0: anyEdge, +1: posEdge (default) |
| duration | <time> | Dauer des Impulses in Sekunden (def.: 10 ns) |
| restart | <bool> | Verlängerung des Impulses mit erneuter Flanke möglich |
| startup | inf/<bool> | Startbedingung für die Flankenerkennung, siehe nachfolgende Beschreibung |
Das folgende Beispiel zeigt für edge = +1 das Verhalten für die Eigenschaft restart:
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.
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: <time>
, mode: <enum>
, reset: <enum>
, control: <dbl>
, fOut: <dbl>
, width: <uint>
, taps: [<uint>]|p##
});
| Eigenschaft | Wert | Beschreibung |
|---|---|---|
| period | <time> | Konstante Periodendauer des Signalverlaufs in Sekunden, entspricht Eingang period Wertebereich: Verpflichtend für alle Betriebsarten außer prbs, sofern nicht über den Eingang period vorgegeben3 |
| 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 |
| width | <uint> | PRBS Signal-Ausgabebreite Wertebereich |
| taps | [<uint>]/p## | PRBS Rückführpositionen oder vordefiniertes Polynom p2..p24 |
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
Mode: rect
Ausgegeben wird ein <bool> 0-1-Rechtecksignal, wobei control 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 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 in Sekunden
Mode: ramp (def.)
Ausgegeben werden Rampen mit der relativen Position im Interval als Skalierungswert
Mode: ramp2
Ausgegeben werden Rampen mit den Skalierungswerten , wobei der Rücksprung auf in der Mitte der Periodendauer liegt.
Mode: sawtooth
Ausgegeben wird ein Sägezahnförmiger Verlauf, wobei control 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 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 als Rückführung für die Längen 2 .. 24 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.
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: countincr
c9 = counter(count, incr, reset); // mode: countincr
c10 = counter(count, incr, reset, preset); // mode: countincr
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 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.
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.
Für die im Bild gezeigte Anordnung ergibt sich folgendes Zählschema:
| A | B | Rechtslauf Inkrementieren | Linkslauf Dekrementieren |
|---|---|---|---|
| 0 | 0 | A: 0->1 | B: 0->1 |
| 1 | 0 | B: 0->1 | A: 1->0 |
| 1 | 1 | A: 1->0 | B: 1->0 |
| 0 | 1 | B: 1->0 | A: 0->1 |
| 0 | 0 | A: 0->1 | 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>.
Ist incr (Mode countincr) oder dir (Mode countdir) NaN oder INF, gilt der zuletzt eingegangene endliche Wert. Ein nicht endliches preset-Argument gilt als nicht angegeben, ebenso ein fehlender oder nicht endlicher Wert im persistenten Speicher (der Zähler beginnt dann mit start). Akzeptiert werden nur numerische Skalare; bei einem Vektor, einer Matrix, einem String oder einem komplexen Wert liefert counter() die Fehlermeldung Input Value is not a numerical scalar.
| Eigenschaft | Wert | Beschreibung |
|---|---|---|
| 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 Parameter r |
| lower | off/<int> | Zählwert stoppt an unterer Grenze, kein Überlauf |
| upper | off/<int> | Zählwert stoppt an oberer Grenze, kein Überlauf |
| range | <uint> | Zählwert Bereich Überlauf von den Randwerten nach oder |
| modulo | <uint> | Zählwert Bereich count %= modulo mit VorzeichenÜ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 . 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|<time>
});
| Eigenschaft | Wert | Beschreibung |
|---|---|---|
| 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 |