Zum Hauptinhalt springen

Präprozessor-Direktiven

Präprozessor-Direktiven

Über Präprozessor-Direktiven können Funktionen des Math Modul Compilers, der Verarbeitung von Variablen und der Ausführung des Codes beeinflusst werden. Die Präprozessor-Direktiven müssen am Anfang einer Zeile im Formel-Text stehen und enden mit dem ersten Zeilenende, das nicht in einer Klammer-Ebene verborgen ist. Kommentare können nach bekannten Regeln eingefügt werden.

Die Direktiven werden durch ein #-Zeichen gefolgt von einem Bezeichner gekennzeichnet. Welche Parameter der Direktive folgen und wie diese formatiert sind, hängt von der Funktion ab. Mögliche Formate sind zum Beispiel:

#directiveA <parameter>
#directiveB <name>[<parameter>](<parameter>){<code>}
#directiveC <key>, <key>=<value>, …

Formeltext einfügen "#include"

Mit dieser Direktive kann Formeltext aus einer Ressource oder einer externen Datei eingefügt werden. Die verwendete Syntax bestimmt, welche Quelle angesprochen wird.

#include "aRessource"
#include 'aRessource'
#include <aFile>

Die als String angegebene Ressource wird unter Berücksichtigung der dort angegeben decoder oder als Text in den Quelltext übernommen.

Die in <…> angegebene Datei wird in den Quelltext übernommen. Es sind absolute und relative Pfade erlaubt, wobei relative Pfade ausgehend von fest bestimmten Verzeichnissen (Suchpfade) gesucht werden. Elemente in %...% werden durch den entsprechenden Wert der Umgebungsvariablen ersetzt.

Suchpfade unter WINDOWS:

  • %USERPROFILE%/mm_lib/

  • %LOCALAPPDATA%/optimeas.osg.com/mm_lib/

  • %APPDATA%/optimeas.osg.com/mm_lib/

Suchpfade unter LINUX/YOCTO:

  • /sdi/config/mm_lib/

  • /sdi/apps/smartcore/mm_lib/

  • /var/lib/mm_lib/

  • /usr/local/lib/mm_lib/

  • /usr/lib/mm_lib/

Zeitbezug entfernen "#timeless"

Wie einleitend beschrieben, verarbeitet das Math Modul die Daten aus den verschiedenen Quellen des smartCORE immer zeitrichtig. Damit wird sichergestellt, dass z.B. ein Strom- und Spannungssignal zur Berechnung einer Leistung zueinander passend korreliert werden.

Allerdings gibt es auch Datenquellen, die nur extrem selten neue Werte liefern. Dies können z.B. Messdaten einer Wetterstation sein, die vielleicht nur alle 10 Minuten abgefragt und in die smartCORE Kanäle geschrieben werden oder Daten eines Fahrplans, der nur einmal täglich von einem Server abgefragt und aktualisiert wird.

Daten, die vom smartCORE in das Math Modul übergeben werden, laufen nach der einstellbaren Zeit inputTimeoutS in einen Time-Out und werden dann mit eben diesem Zeitversatz und dem zuletzt anstehenden Wert weiter verwendet, obwohl die Gültigkeit nicht durch jüngere Messungen oder Abfragen bestätigt ist. Das hat zur Folge, dass alle davon abhängigen Berechnungen zwar immer noch zeitrichtig aber um diese Zeitspanne verzögert ausgeführt werden.

Diese Verzögerung kann in der Darstellung der MQTT Daten in der Cloud oder auch für Steuerungsaufgaben ungünstige Auswirkungen haben.

Mit den Funktionen

können die verschiedenen Zustände einer Eingangsvariable abgefragt werden. Für den Fall, dass kein smartCORE Kanal verbunden werden konnte oder dass dieser Kanal noch keine Daten liefert, wird ein default Wert zugewiesen, der über das Macro #protperty <channel>, default=<var> eingestellt werden kann.

Um den Zeitbezug bestimmter Eingangskanäle für das Math Modul aufzulösen, kann die Direktive #timeless verwendet werden. Die Kanalnamen können in einer Liste mit einem Komma als Trennzeichen an die Direktive übergeben werden. Enthalten die Namen andere Zeichen als die für einen Bezeichner zulässigen, müssen sie in '...' oder "..." gesetzt werden. Die Verwendung der $'...' Syntax ist nicht zulässig, da hier nur ein Attribut des Kanals gesetzt wird.

#timeless <varName>, <varName2>, ...

Die so gekennzeichneten Eingangskanäle sind daraufhin immer vom Anfang bis zum Ende des jeweiligen Berechnungsintervalls evaluationTimeMs bezogen auf die jeweilige Systemzeit gültig.

Timeless Schema

In dem gezeigten Beispiel wird die Berechnung des Formelsatzes zu den Zeitpunkten t0,t_0, t1t_1 und t2t_2 ausgeführt. Bis zum Zeitpunkt t0t_0 wurde auf dem Kanal nur der Wert y0y_0 eingestellt. Bis zum Zeitpunkt t1t_1 liefert die Signalquelle die Datenpunkte y1,y_1, y2y_2 und y3y_3. Die Datenpunkte y4y_4 und y5y_5 werden erst bis zum Zeitpunkt t2t_2 produziert, obwohl ihr Zeitstempel noch vor t1t_1 liegt.

Für den Anfang des Intervalls wird immer der unmittelbar davor liegende Datensatz des Kanals verwendet, egal wie alt dieser ist. Für das Intervall ]t0,t1]]t_0,t_1] also der Datenpunkt y1,y_1, für das Intervall ]t1,t2]]t_1,t_2] der Datenpunkt y5y_5.

Fallen zufällig neue Datenwerte in das aktuelle Berechnungsintervall und sind dort auch schon rechtzeitig eingetragen, werden sie mit ihren Zeitpunkten berücksichtigt. Für das Intervall ]t0,t1]]t_0,t_1] sind dies die Datenpunkte y2y_2 und y3y_3.

Die Gültigkeit des jüngsten vorliegenden Datensatzes (hier y3y_3) wird automatisch bis zum Ende des Intervalls (hier t1t_1) verlängert, sodass dieser Kanal letztlich keine von ihm abhängigen Berechnungen aufhalten kann.

Der Preis dafür ist, dass möglicherweise kurze Signaländerungen, die in diesem verlängerten Gültigkeitsbereich liegen, nicht mehr in die Berechnungen einfließen. Im Beispiel wird der Datenpunkt y4y_4 "übersehen", da er in einem Zeitintervall liegt, das bereits durch den Automatismus ergänzt wurde. Mit der Annahme und Voraussetzung, dass diese Kanäle aber nur selten Daten liefern, sollte das kein Problem darstellen.

Setzen von Eigenschaften einer Variable "#property" 1

Mit dieser Präprozessor-Direktive können von einer Eingangs- oder Ausgangsvariable Eigenschaften und Meta-Informationen gesetzt werden.

#property <channel>, <key>=<value>, ...
ArgumentTypBeschreibung
channel<str>Der Kanalname muss als erstes Argument angegeben werden. Wenn dieser Sonderzeichen wie Leerzeichen oder Kommata enthält, muss er in Anführungszeichen gesetzt werden. Die Verwendung der $'...' Syntax ist nicht zulässig, da hier nur Eigenschaften des Kanals gesetzt werden.
key<str>Der Name der Eigenschaft, siehe nachfolgende Tabelle
value<var>Der neue Wert der Eigenschaft (Variant)

Die folgende Tabelle ist eine Aufstellung der möglichen und erlaubten Eigenschaften und deren Werte:

EigenschaftTypBeschreibung
default<var>Der default-Wert, der einer Variablen zugewiesen wird, bis die ersten Datenwerte aus dem smartCORE Kanal eintreffen. Damit wird es möglich, auf verzögernd startende Datenströme im Math Modul zu reagieren.
timeless<bool>Hiermit wird das timeless-Feature für diesen Kanal ein oder ausgeschaltet. Dies entspricht dem Macro #timeless

Definition von Funktionen "#define"

Under Construction Diese Funktion ist in Vorbereitung.

#define <newFunction>(<argsList>)[<options>]{<code>}

Debug-Informationen "#dump"

warnung

For Debugging Only Diese Präprozessor-Direktive ist ausschließlich für Diagnose und Entwicklung vorgesehen. Sie produziert sehr viele Informelle Ausgaben im Logfile des smartCORE und sollten deshalb auch nur über kurze Zeiträume eingesetzt werden.

Parameter der Direktive #dump ist eine durch Komma getrennte Key oder Key-Value-Liste und wirkt sich auf den nachfolgenden Formeltext aus:

#dump <key>, <key>=<value>, ...
KeyValueBeschreibung
treeGibt den übersetzten Objektbaum aus. Zur Interpretation siehe unten.
node<uint>Fügt einen bestimmten Objektknoten für das kontinuierliche Monitoring hinzu (2, 3).
var<str>Fügt ein regex-Ausdruck zur Auswahl von Kanalnamen hinzu, deren Zugriffe protokolliert werden sollen (2)
trace<enum>schaltet die Datenflussausgabe für
 - in Eingänge,
 - out Ausgänge oder
 - io beide Datenrichtungen
frei.
clearLöscht alle Dump-Einstellungen für den nachfolgenden Code-Abschnitt.

Beispiele:

#dump tree
#dump node=5, node=9
#dump var='Temp.*', trace=out

Ausgabe des Objekt-Baumes

Die Ausgabe des Objekt-Baums mittels #dump tree gibt Detailinformationen zu den funktionalen Beziehungen des definierten Formelsatzes. Die Auswertung ist fachkundigen Mitarbeitern der optiMEAS vorbehalten.

        +---o   [0]: sequencer, bareImpl, op: ';' listOfArgs
> out: nullptr
+---o [1]: operatorNode, followInputs, op: '=' orderR2L
| > out: { n:'duration', s:[upLnk, wrVar], *rd[0], *wr[1], h:'=', empty}
| +---o [2]: operatorNode, followInputs, op: '*' orderL2R
| | > out: { n:'', s:[upLnk], *rd[1], *wr[2], h:'*', empty}
| | +---o [3]: varPoolSource, followInputs
| | | > var: { n:'wv2', s:[rdVar], *rd[3], empty}
| | | > out: { n:'', s:[upLnk], *rd[2], *wr[3], empty}
| | +---o [4]: constValueNode, constValue
| | | > out: { n:'', s:[upLnk, const], *rd[2], *wr[4], [1]={t: INF, d: TrustedTimestamp }, [0]={t: 0, d: (cScalar, cInt) 59}}}

Trace-Ausgaben für einen Datenfluss-Verbindungselement (out: oder var:, Kanal bzw. TS_Stream) haben folgenden, kompakten Aufbau:

{ n:'duration', s:[upLnk, wrVar], *rd[0], *wr[1], h:'=', [9]={t: 48, d: (cScalar, cDbl) 54.978065}, ... [0]={t: 20, d: (cScalar, cDbl) 0.000000}}}

Darin bedeuten:

KürzelFlagsBeschreibung
n:'...'der Name des Kanals, sofern es sich um eine Variable handelt
s:[]Status-Flags des Kanals
upLnkUp-Link, Verbindung von einem Unterknoten zu dem übergeordneten Knoten
rdVarRead Variable, Eingangsvariable, wird vom smartCORE bereit gestellt und wird nur gelesen
wrVarWrite Variable, Ausgangsvariable, kann in den smartCORE zurückgeführt werden
inzInitializer, hat einen initialisierenden Knoten
constConstant value, der Wert verändert sich während der Laufzeit nicht.
discrDiscrete evaluation, Dieser Kanal wird in diskreten Abtastschritten berechnet
ev@0Evaluate at Start, der Diskrete Kanal wurde initialisiert
evDTEvaluate Delta-T, ein Abtastschritt wurde für den diskreten Kanal gerechnet
explExplicit name, Variable wurde mit der $'…' Syntax definiert und muss im smartCORE existieren
fldEField-Element, Kanal beschickt ein bestimmtes Datenfeld in einer mehrdimensionalen Struktur (Vektor, Matrix, …)
privPrivate, Eine Variable, die von einem Funktionsblock angelegt wurde und von diesem exklusiv verwendet wird
propAuf der Variablen wurden mit #property Eigenschaften gesetzt.
noTnoTime, dieser Kanal wurde als #timeless markiert und ist immer bis zum Ende des Berechnungsintervalls gültig.
nRecNoRecursion, diese Variable darf nicht in einer Rekursions-Schleife verwendet werden.
noChDieser Kanal konnte nicht mit einem smartCORE Kanal als Input verbunden werden. => Default als Konstant-Wert zugewiesen. Siehe auch isConnected()
noDDer Eingangskanal ist noch leer, keine Daten aus dem smartCORE. Siehe auch isEmpty()
tmoTimeout für Eingangsdaten, sofern der Kanal noch leer ist (noD) oder er nicht als #timeless markiert wurde. Siehe auch isTimeout()
fDefDer default-Wert wurde in den Kanal geschrieben, siehe auch #property <channel>, default=<var>
*rd[]Die Indices der Objektknoten, die lesend auf den Kanal zugreifen
*wr[]Der Index des Objektknoten, der schreibend auf den Kanal zugreift
*@0[]Der Index des Objektknotens, der die Initialisierung des diskreten Kanals ausführt.
h:'...'Hinweis auf die Funktion des schreibenden Knotens, z.B. '*' oder 'sin(…)'
[n]={}der gespeicherte Sample an jüngster Position n (entspricht der Anzahl der Einträge - 1) mit...
t:Zeitstempel in ns seit 01.01.1070, INF (unendlich) oder NAV (ungültig)
d:Datenwert mit (Struktur, Typ) Wert oder TrustedTimestamp, d.h. der davor liegende Wert behält seine Gültigkeit bis zu diesem Zeitpunkt. Der Zeitpunkt kann in jedem Berechnungsintervall monoton wachsen.
[0]={}der gespeicherte Sample an der ältesten Position (optional)

Berechnungsablauf verfolgen "#monitor"

For Debugging Only WARNUNG! Diese Präprozessor-Direktive ist ausschließlich für Diagnose und Entwicklung vorgesehen. Sie produziert sehr viele Informelle Ausgaben im Logfile des smartCORE und sollten deshalb auch nur über kurze Zeiträume eingesetzt werden.

Überwachung der internen Puffer "#warn"

For Debugging Only WARNUNG! Diese Präprozessor-Direktive ist ausschließlich für Diagnose und Entwicklung vorgesehen. Sie produziert sehr viele Informelle Ausgaben im Logfile des smartCORE und sollten deshalb auch nur über kurze Zeiträume eingesetzt werden. Dazu erzeugt diese Option zusätzliche CPU Last und darf nur temporär unter Beobachtung angewendet werden !!!

Parameter der Direktive #warn ist eine durch Komma getrennte Key oder Key-Value-Liste und wirkt sich auf den nachfolgenden Formeltext aus:

KeyValueBeschreibung
maxbuflen<uint>Überwacht auf die maximale Anzahl an Datensätzen in einer Daten-Queue. Eine Warnung wird ausgegeben, wenn der Grenzwert überschritten wird. Die Grenze wird für die folgende Meldung um 25% von maxbuflen angehoben.
timeout<dbl>Überwacht den Zeitabstand zwischen dem ersten Datensample und der Ausführungszeit. Eine Warnung wird ausgegeben, wenn diese Zeit größer ist, als der gesetzte Wert in s.
clearLöscht alle Warn-Einstellungen für den nachfolgenden Code-Abschnitt.

Beispiele:

#warn maxBufLen=10, timeout=1000
// Formeltext zur Überwachung
#warn clea

Footnotes

  1. Ab Katalog Version 10 verfügbar.

  2. Option kann mehrfach genannt werden. 2

  3. Knotennummern aus dem Objekt-Baum