.. _link-formel-editor: ============ Formeleditor ============ .. toctree:: :glob: :hidden: .. note:: Der Formeleditor dient berechneten Variablen. Mit ihm haben wir die Möglichkeit komplexe auf Bedingungen aufbauende Berechnungen vornehmen zu lassen, die sowohl auf Plc Variablen als auch auf anderen berechneten Variablen aufbauen. .. image:: ../images/24.png :width: 800 Im Formeleditor stehen uns diverse Funktionen und eine eigene Syntax Sprache zur Verfügung. Wir können andere Variablen referenzieren, Platzhalder definieren und zahlreiche mathematische Operatoren und Funktionen, sowie, Bedingungen mit If/Else Konstrukten benutzen. Variablen die wir einsetzen wollen können wir per Drag&Drop aus der Navigation in den Text kopieren. Formel Beispiele ================ .. code:: $MS.SGas.Q_ein.plc->Auto - $MS.SGas.Q_aus.plc->Auto .. code:: var p_ein = $VK_Vk.SGas.p_ein.v->Auto; var p_aus = $VK_Vk.SGas.p_aus.v->Auto; return p_aus / p_ein * 100; .. code:: var q_plc = $K_KK.SGas.Q.plc->Auto; var rel = $MS.SGas.rel.calc->Auto; var q_calibrated = q_plc * rel; return if (IsValid(rel)) { q_calibrated } else { 0 }; .. code:: var q = $K_KK.SGas.Q.calc->Auto; var v_aus = if (q < 0) {Integral(Abs(q) @ Raster = Hour)} else {0}; return v_aus; .. code:: var q = $K_KK.SGas.Q.calc->Auto; var v_ein = if (q > 0) {Integral(q @ Raster = Hour)} else {0}; return v_ein; .. code:: Avg($K_KK.SGas.p_M1.plc->Auto, $K_KK.SGas.p_M2.plc->Auto) .. code:: Sum( $TSp.SGas.Q_kavmess.calc->DirectChildren, $K_KK.SGas.Q.plc->DirectChildren @OptionalParams = True ) Syntax Elemente =============== var --- Ein Schlüsselwort, welches man vor Platzhalternamen schreibt, gefolgt von ist gleich und dem zugewiesenen Wert. Die Zeile wird mit einem Semikolon beendet. Beispiele ~~~~~~~~~ .. code:: var q = $K_KK.SGas.Q.calc->Auto; .. code:: var v_aus = if ($K_KK.SGas.Q.calc->Auto < 0) {Integral(Abs($K_KK.SGas.Q.calc->Auto) @ Raster = Hour)} else {0}; return ------ Dieses Schlüsselwort wird vor einen Rückgabe-Wert oder -Block geschrieben. Beispiele ~~~~~~~~~ .. code:: return $MS.SGas.Q_ein.plc->Auto - $MS.SGas.Q_aus.plc->Auto; Auch in Kurzform möglich in letzter Zeile .. code:: $MS.SGas.Q_ein.plc->Auto - $MS.SGas.Q_aus.plc->Auto; Oder als Block .. code:: return if (IsValid(value)) { calibrated } else { 0 }; if, else -------- Ermöglicht differenzierte Logik. Wenn A gilt, tue dies, ansonsten das. Beispiele ~~~~~~~~~ .. code:: return if (IsValid(value)) { calibrated } else { 0 }; .. code:: var q = $K_KK.SGas.Q.calc->Auto; var v_aus = if (q < 0) {Integral(Abs(q) @ Raster = Hour)} else {0}; NaN --- Ein spezieller Wert, der angibt keine Zahl zu sein (Not a Number). .. note:: Jeder Wert (einer Variablen) besteht aus 2 Zahlen, einmal dem Wert selbst, und einmal der Qualität zwischen 0 und 1, 0 = schlecht, 1 = gut. Es kann in Berechnungen und der Verwendung bestimmter Variablen passieren, dass Werte eine schlechte Qualität aufweisen. Ist dies der Fall, so wird bei bestimmten Operationen aus z.B. der Multiplikation einer Zahl mit einer schlechten Qualität auch das Ergebnis als schlecht gewertet und so erhält das Ergebnis daher den Wert NaN. ``NaN`` steht für ``Not a Number`` Operatoren ---------- Uns stehen die typischen arithmetischen Opeartoren zur Verfügung. - ``+`` Addition - ``-`` Subtraktion - ``*`` Multiplikation - ``/`` Division - ``%`` Modulo Funktionen ========== .. csv-table:: :header: "Aufruf", "Beschreibung" :widths: 50, 50 "``Abs( x1 )``", "Absolutwert" "``And( x1 ... xn )``", "Logische && Operation über alle Variablen. 0 = false, 1 = true." "``Avg( x1 ... xn @ OptionalParams = [True | False] )``", "Wie Average" "``Average( x1 ... xn @ OptionalParams = [True | False] )``", "Mittelwert über alle übergebene Argumenten." "``BitAnd( x1, x2 ... xn )``", "Bitweise & Operation über 2 Argumenten." "``BitOr( x1, x2 ... xn )``", "Bitweise | Operation über 2 Argumenten." "``Diff( x1, x2 ... xn )``", "Differenz. Ergebnis: arg0 - arg1 - arg2 - ... - argn. |br| Das selbe wie SumDiff @ NPositiv = 1" "``Div( x1, x2 )``", "Division. Ergebnis arg0 / arg1" "``Eq( x1, x2 ... xn )``", "Logische == Operation über alle Argumenten. |br| Liefert 0 wenn FALSE, 1 wenn TRUE." "``Ge( x1, x2 ... xn )``", "Logische >= Operation über alle Argumenten. |br| Liefert 0 wenn FALSE, 1 wenn TRUE." "``Gt( x1, x2 ... xn )``", "Logische > Operation über alle Argumenten. |br| Liefert 0 wenn FALSE, 1 wenn TRUE." "``If( Messages.FormulaOperation_If, 3 )``", "Logisches If - else Block. Argument 1 - Bedienung, |br| Argument 2 - Wert wenn TRUE, Argument 3 - Wert wenn FALSE. |br| Argument 1 ungleich 0 wird als TRUE interpretiert. " "``IsValid( x1 )``", "Boolesche funktion, welche überprüft ob die Qualität |br| des Wertes größer 0 und Plausibliltät gleich Ok ist." "``LastValid( x1 @ Raster = [Raster-Wert], Width = [Int-Wert] )``", "Liefert den letzten gültigen Wert unnerhalb eines |br| spezifizierten Zeitberechs. Parameter sind Raster, Width. |br| Falls nichts spezifiziert ist die Width = 1." "``NextValid( x1 @ Raster = [Raster-Wert], Width = [Int-Wert] )``", "Liefert den nächsten gültigen Wert unnerhalb eines |br| spezifizierten Zeitberechs. Parameter sind Raster, Width. |br| Falls nichts spezifiziert ist die Width = 1." "``LastValidValueInRaster( x1 @ Grid = [Hour | Das | Week | Month | Year] )``", "Liefert den letzten gültigen Wert innerhalb eines Virtuellen Raster" "``Le( x1, x2 ... xn )``", "Logische <= Operation über alle Argumenten. |br| Liefern 0 wenn FALSE, 1 wenn TRUE." "``Lt( x1, x2 ... xn )``", "Logische < Operation über alle Argumenten. |br| Liefern 0 wenn FALSE, 1 wenn TRUE." "``LocalHour( x1 )``", "Gibt die aktuelle Stunde des Wert-Zeitstempels |br| in der Localen Zeitzone zurück." "``LocalFractionalHour( x1 )``", "Gibt die aktuelle Stunde (Partiell) des Wert-Zeitstempels |br| in der Localen Zeitzone zurück." "``LocalWeekDay( x1 )``", "Gibt den aktuellen Wochentag des Wert-Zeitstempels |br| in der Localen Zeitzone zurück." "``LocalDayOfMonth( x1 )``", "Gibt den aktuellen Tag seit Monatbegin des Wert-Zeitstempels |br| in der Localen Zeitzone zurück." "``LocalDayOfYear( x1 )``", "Gibt den aktuellen Tag seit Jahresbegin des Wert-Zeitstempels |br| in der Localen Zeitzone zurück." "``VirtualZoneHour( x1 )``", "Gibt die aktuelle Stunde des Wert-Zeitstempels |br| in der Virtuelen Zeitzone zurück." "``VirtualZoneDayOfMonth( x1 )``", "Gibt den aktuellen Tag des Monats des Wert-Zeitstempels |br| in der Virtuellen Zeitzone zurück." "``VirtualZoneDayOfYear( x1 )``", "Gibt den aktuellen Tag des Jahres des Wert-Zeitstempels |br| in der Virtuellen Zeitzone zurück." "``VirtualZoneFractionalDayOfYear( x1 )``", "Gibt den aktuellen Tag des Jahres (partiell) des Wert-Zeitstempels |br| in der Virtuellen Zeitzone zurück." "``VirtualZoneYear( x1 )``", "Gibt den Jahr des Wert-Zeitstempels in der Virtuellen Zeitzone zurück." "``Map( x1, x2, x3 ... xn )``", "Wertmapping. Parameter 1 - Wert, Parameter n - Testwert, |br| Parameter n+1 - Ausgabwert, wenn Parameter n gleich Parameter 1 ist." "``Mult( x1 ... xn )``", "Produkt über alle Argumenten. arg0 * arg1 * ... * argn." "``Min( x1 ... xn )``", "Minimum aus allen Argumenten." "``Max( x1 ... xn )``", "Maximum aus allen Argumenten." "``Merge( x1 ... xn @ OptionalParams = [True | False] )``", "Zusammenführen aller Argumenten über die Variablenqualität. |br| Der Wert mit der höchster Qualität wird geliefert. |br| Bei gleicher Qualität wird der Wert des Arguments " "``Median( x1 ... xn )``", "TODO" "``MovingAverage( x1 @ Width = [Int-Wert], Offset = [Int-Wert], Centered = [True | False], Model )``", "Mittelwert gebildet über Zeit aus mehreren nachfolgenden Werten. |br| Anzahl der Werte wird über Parameter Width bestimmt." "``MovingMedian( x1 @ Width = [Int-Wert], Offset = [Int-Wert], Centered = [True | False], Model )``", "TODO" "``Not( x1 )``", "Logische 'Nicht' Operation." "``NotEq( x1, x2 ... xn )``", "Logische != Operation über alle Variablen. Liefert 0 wenn FALSE, 1 wenn TRUE." "``Negate( x1 )``", "Wert * -1. Dabei wird weder der Zeitstempel noch die Qualität des |br| Wertes verändert." "``Or( x1 ... xn )``", "Logische || Operation über alle Variablen. Liefert 0 wenn FALSE, 1 wenn TRUE." "``Power( x1, x2 )``", "Potenzfunktion: arg1^arg2." "``Random( x1, x2 )``", "Zufallswert zwischen arg1 und arg2." "``TimeInterval( x1 @ Raster = [Raster-Wert] )``", "Zeitinterval des aktuellen Zeitabschnitts in Rastereinheiten." "``LowerLimit( x1 )``", "TRUE(1) wenn der Wert die untere Grenze verletzt." "``UpperLimit( x1 )``", "TRUE(1) when der Wert die obere Grenze verletzt" "``Quality( x1 )``", "Wertqualität." "``Sign( x1 )``", "Liefert den Vorzeichen des Arguments. '1' bei positiven, '-1' bei negativen |br| und '0' bei 0-Werten." "``Sum( x1 ... xn, @ OptionalParams = [True | False] )``", "Summe über alle Argumenten." "``SumDiff( x1 ... xn )``", "Summe/Differenz über die Needs, wobei die ersten |br| nPositiv Argumenten positiv und der Rest negativ eingeht." "``Integral( x1 @ Raster = [Raster-Wert] )``", "Integral über die Zeit (z.B. Q -> V)." "``IntegralKum( x1 @ Raster = [Raster-Wert], ResetOnNaN = [True | False] )``", "Integriert kummulativ über die Zeit (z.B. Q -> V_kum)." "``Rate( x1 @ Raster = [Raster-Wert] )``", "Rate aus Volumen." "``SumKum( x1 @ Raster = [Raster-Wert], ResetOnNaN = [True | False] )``", "Summiert kummulativ über die Zeit (z.B. V -> V_kum)" "``Differential( x1 @ Raster = [Raster-Wert] )``", "Dividiert einen Wert durch die Rasterzeit. |br| Berechnet zB. Volumenstrom Q aus Volumen V." "``Delta( x1 )``", "Liefert jeweils den Unterschied zwischen zwei aufeinanderfolgenden |br| Werten des Arguments. |br| Damit kann zB. aus Zählwert eine Volumina ausgerechnet werden." "``WindowCounter( x1 @ Raster = [Raster-Wert] )``", "Liefert Anzahl der Rastereinheiten während dessen |br| das Argument 'TRUE' (ungleich 0) bleibt. |br| Damit lässt sich zB. berechnen für wie lange ein bestimmtes Zustand " "``Sin( x1 )``", "Sinus (radian)" "``Cos( x1 )``", "Cosinus (radian)" "``Tan( x1 )``", "Tangens (radian)" Verfügbare Raster-Werte ----------------------- Milli_1, Milli_2, Milli_5, Milli_10, Milli_20, Milli_25, Milli_50, Milli_100, Milli_200, Milli_250, Milli_500, Second_1, Second_2, Second_5, Second_10, Second_15, Second_30, Minute_1, Minute_2, Minute_5, Minute_10, Minute_15, Minute_30, Hour, Day, Week, Month, Year Beispiele --------- .. code:: Sum( $TSp.SGas.Q_kavmess.calc->DirectChildren, $K_KK.SGas.Q.plc->DirectChildren @OptionalParams = True ) .. code:: Integral(Abs($K_KK.SGas.Q.calc->Auto) @ Raster = Hour) .. code:: Avg($K_KK.SGas.p_M1.plc->Auto, $K_KK.SGas.p_M2.plc->Auto) .. _link-search-policy: Suchspezifikationen bei Variablen ================================= Sowohl im Formeleditor als auch bei der Anlage von Variablen Knoten Auto ---- ``->Auto`` Sucht in vordefinierter Reihenfolge und geht jeweils zum nächsten Punkt, aber nur solange noch nichts gefunden wurde. 1. Sucht bei diesem Objekt, aber stoppt sofort, wenn das richtige Objekt gefunden wurde. 2. Sucht bei den Eltern und Eltern von Eltern, aber stoppt sofort, wenn ein richtiges Objekt gefunden wurde. 3. Sucht in die Tiefe über alle Zweige und gibt alle obserste (also zuerst gefundene) passende Kinder zurück. Angenommen wir zeigen uns das Verdichtungsverhältnis von ``VK05`` an und rufen in der Formel den Wert vom Eingangsdruck mit dem Schlüssel ``Auto``, so sucht der Berechnungsalgorithmus nach einem Eingangsdruck am Objekt VK05, also am selben Objekt. .. container:: clearer .. figure:: ../images/26.png :figwidth: 200 :align: left Wenn er den Wert nicht findet, geht er den Objektbaum von ``VK05`` wie wir ihn in der Hierarchie unter Objekte finden hoch und schaut bei den hierarchisch übergeordneten Objekten nach einem Eingangsdruck. Also zuerst bei ``Alle Verdichter``, dann bei ``Kevernenspeicher`` und wenn das nicht klappt dann schaut er bei den Kindknoten von ``VK05``, also ``VK05_E-NSA-PAC`` und ``VK05_S-NSA-PAC``. Parent ------ ``->Parent`` Sucht bei allen Eltern und Eltern von Eltern aber stoppt beim ersten Fund Children -------- ``->Children`` Sucht bei den Kindern ThisOrParent ------------ ``->ThisOrParent`` Sucht bei allen Eltern und Eltern von Eltern und am aktuellen Objekt ThisOrChildren -------------- ``->ThisOrChildren`` Sucht bei Kindern, Kindes-Kindern und am aktuellen Objekt und nimmt alles was passt. This ---- ``->This`` Nimmt das aktuelle Objekt. DirectChildren -------------- ``->DirectChildren`` Sucht nur bei direkten Kindern (also nicht Kindes-Kindern) und gibt alle passenden Geschwister zurück. TopChildren ----------- ``->TopChildren`` Sucht in die Tiefe über alle Zweige und gibt alle obserste (also zuerst gefundene) passende Kinder zurück. Ausführlicher: Sucht bei allen Kindern und allen Kindes-Kindern in allen Verzweigungen in die Tiefe, jeweils stoppend bei einem Fund, wo alle passenden Objekte gesammelt werden. Die Sammlung aus allen Fund-Zweigen wird dann zurückgegeben. All --- ``->All`` Nimmt alle Knoten. Objekt Angabe ------------- Beispiel: ``->vk03`` Nimmt benanntes Objekt (also hier von vk03), wobei hier Bezug genommen wird auf den ``Object_Key``