Zum Hauptinhalt springen

Präprozessor-Direktiven

Präprozessor-Direktiven

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.

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.

Definition von Funktionen "#define"

Under Construction Diese Funktion ist in Vorbereitung.

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 (*,**).
var<str>Fügt ein regex-Ausdruck zur Auswahl von Kanalnamen hinzu, deren Zugriffe protokolliert werden sollen (*)
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.

(*) Option kann mehrfach genannt werden.

(**) Knotennummern aus dem Objekt-Baum

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
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.
*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