Zum Hauptinhalt springen

Formel

Beim Registrieren eines Tags kann im Feld fomula eine arithmetische Formel eingegeben werden. Der Treiber verarbeitet dann den vom PLC gelesenen Rohwert (raw value) nach und verwendet den umgewandelten Wert für Cache / Sparkplug / REST-Antworten.

ElementWert
Implementierungsklasseplantpulse.app.edge.component.collector.plc.PLCValueFomula
AufrufstelleSchritt 3 in PLCValueReader.read() (raw → format → Formel → Cache-Aktualisierung)
Bibliothekplantpulse-edge-fomula.jar (plantpulse.edge.fomula.FormulaEngine)
Variablenersetzung${VALUE} (aktueller Tag-Wert) / ${tag_id} (letzter Wert anderer Tags, LastValueMap Cache)
Anwendbare data_typeFloat / Double / Integer / Long nur anwendbar. Andere Typen (String, Boolean, …) werden unverändert durchgereicht
ErgebnisFormula.evaluate(...) BigDecimal → Typ-basiertes Rendering (Ganzzahl-Typen als Ganzzahl, Float/Double als Dezimalzahl)

Ablauf​

  1. Der Treiber empfängt den raw String-Wert (z. B. "16384").

  2. PLCValueFomula.fomulaValue(address, value) wird aufgerufen.

  3. Wenn address.getFomula() leer ist, wird der Wert unverändert zurückgegeben.

  4. Wenn data_type nicht Float / Double / Integer / Long ist, wird der Wert unverändert zurückgegeben.

  5. Die in der Formel referenzierten Namen werden geprüft — VALUE ist der gerade gelesene Wert, die übrigen sind der letzte Wert anderer Tags aus LastValueMap.

  6. Wenn ein referenziertes Tag noch nie erfasst wurde, wird eine Ausnahme ausgelöst:

    Variable value referenced by the formula is not yet in cache : formula=[`<fomula>`], variable=[`<name>`]
  7. Nur die in der Formel referenzierten Namen werden mit Werten gebunden und ausgewertet → BigDecimal → Typ-basierte String-Rückgabe.


Variablentypen​

NotationBedeutungQuelle
${VALUE}raw Wert des aktuellen TagsWert, den der Treiber gerade gelesen hat
${TAG_ID_X}Letzter Wert eines anderen TagsLastValueMap (gemeinsamer Cache für alle Tags)

LastValueMap speichert die letzten raw / nachverarbeiteten Werte aller Tags. Es können nicht nur Tags desselben OPC, sondern auch Tags eines anderen OPC referenziert werden (vorausgesetzt, das Tag wurde mindestens einmal erfasst und ist im Cache vorhanden).

Variable nicht vorhanden

Wenn ${TAG_ZERO} referenziert wird, aber TAG_ZERO noch nie erfasst wurde, kann kein Wert gebunden werden und es wird eine Ausnahme ausgelöst. Stellen Sie sicher, dass die timecycle des referenzierten Tags kürzer ist, oder registrieren Sie das referenzierte Tag mit einer auto_collect=true , damit es zuerst erfasst wird. (Die Syntaxprüfung beim Speichern lässt diesen Fall durch — es ist ein Erfassungsreihenfolge-Problem, kein Formelfehler.)


Ausdruckssyntax​

Die Schreibweise erfolgt wie in Excel. Da Funktionsnamen und Bedeutung mit Excel übereinstimmen, können die meisten in Excel verwendeten Ausdrücke nahezu unverändert übernommen werden. Groß-/Kleinschreibung wird nicht unterschieden (IF = if).

KategorieTokenHinweis
Arithmetik+, -, *, /, ^^ ist Potenzierung
Vergleich>, <, >=, <=, =, <>= ist gleich, <> ist ungleich (wie in Excel)
Gruppierung(, )Klammer-Priorität
KonstantenPI, EKreiszahl, Eulersche Zahl
BedingungenIF, SWITCH, AND, OR, NOTIF(조건, 참일때, 거짓일때)
RundungROUND, ROUNDUP, ROUNDDOWN, CEILING, FLOOR, INT, TRUNCROUND(값, 자리수)
NumerischABS, SIGN, MOD, POWER, SQRT, CBRT, EXP, FACTDas Vorzeichen des Restes von MOD folgt dem Divisor
AggregationMIN, MAX, SUM, AVERAGE, COALESCEMehrere Argumente
LogarithmusLOG, LOG10, LNLOG = Dekadischer Logarithmus (Basis 10), LN = natürlicher Logarithmus
TrigonometrieSIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2Bogenmaß (Radians) wie in Excel
HyperbolischSINH, COSH, TANH, ASINH, ACOSH, ATANH
WinkelumrechnungDEGREES, RADIANSBogenmaß ↔ Grad
Nicht unterstützt
  • Bitweise Operationen (&, |)
  • Benutzerdefinierte Funktionen
  • String-Operationen / Datumsoperationen Falls solche benötigt werden, verwenden Sie nachgelagerte Schritte (externe Funktion / Nachverarbeitungsknoten).
Fehlerhafte Formeln werden nicht gespeichert

Formeln mit Syntaxfehlern werden beim Speichern abgelehnt (gilt für UI-Speichern, CSV-Upload und Backup-Wiederherstellung). Im Tag-Konfigurationsdialog können Sie Beispieldaten eingeben, um das Ergebnis vorab zu prüfen.

Fehler während der Berechnung (Division durch 0, referenzierter Wert ist keine Zahl usw.) werden als Erfassungsfehler protokolliert und die Qualität des betreffenden Tags wird herabgesetzt. Es wird kein plausibler Ersatzwert gespeichert.

Variablennotation​

Sowohl ${VALUE} als auch der reine Name VALUE werden verwendet. Gleiches gilt für andere Tags — ${TAG_ZERO} = TAG_ZERO. Bereits gespeicherte ${...} Formeln funktionieren weiterhin unverändert.

${VALUE}*0.1 기존 표기
VALUE*0.1 같은 뜻
IF(VALUE>100, 100, VALUE*0.1) 엑셀식

Vielfältige Beispiele​

1. Einfache Skalierung (×0.1)​

ElementWert
data_typeFloat
fomula${VALUE}*0.1
Eingabe → Ausgabe16384 → 1638.4

Verwendung: Ganzzahl raw → Dezimalzahl mit einer Nachkommastelle. Wenn Temperatur / Druck / Durchfluss-Sensoren den Wert als Ganzzahl senden.

2. Einheitenumrechnung (mV → V)​

ElementWert
data_typeFloat
fomula${VALUE}/1000
Eingabe → Ausgabe3300 → 3.3

3. Offset-Korrektur (Celsius → Kelvin)​

ElementWert
data_typeFloat
fomula${VALUE}+273.15
Eingabe → Ausgabe25 → 298.15

4. Referenz auf anderes Tag (Nullpunkt-Korrektur)​

ElementWert
data_typeFloat
fomula${VALUE}-${TAG_ZERO}
Eingabe → AusgabeVALUE=1024, TAG_ZERO=24 → 1000

TAG_ZERO ist die ID eines anderen Tags. Wird für Nullpunkt-/Tara-Korrektur verwendet.

5. Polynom (Quadrat)​

ElementWert
data_typeFloat
fomula${VALUE}*${VALUE}*0.001
Eingabe → Ausgabe100 → 10.0

6. Funktion — Quadratwurzel​

ElementWert
data_typeFloat
fomulasqrt(${VALUE})
Eingabe → Ausgabe144 → 12.0

7. Funktion — Trigonometrie (sin, Bogenmaß)​

ElementWert
data_typeFloat
fomulasin(${VALUE})
Eingabe → Ausgabe1.5708 (≈π/2) → 1.0

Wird ein Winkel in Grad eingegeben, verwenden Sie sin(${VALUE}*pi/180).

8. Mehrere Tags — Kalibrierung (gain × x + offset)​

ElementWert
data_typeFloat
fomula${VALUE}*${TAG_GAIN}+${TAG_OFFSET}
Eingabe → AusgabeVALUE=100, GAIN=0.05, OFFSET=2 → 7.0

Muster, bei dem gerätespezifische Kalibrierfaktoren in separaten Tags (oder HTTP-bind Tags) verwaltet werden.

9. Typumwandlung / Erzwingen einer Gleitkommazahl​

ElementWert
data_typeFloat
fomula${VALUE}*1.0
Eingabe → Ausgabe123 → 123.0

Wenn ein über Integer empfangener Wert nur in Float umgewandelt (gecastet) werden soll.

10. Potenzierung / Exponential​

ElementWert
data_typeFloat
fomula${VALUE}^2
Eingabe → Ausgabe5 → 25.0

11. Logarithmus​

ElementWert
data_typeFloat
fomulalog(${VALUE})
Eingabe → Ausgabe100 → 2.0

ln(...) kann ebenfalls verwendet werden (natürlicher Logarithmus).

12. Kombination — dB-Umrechnung für RMS​

ElementWert
data_typeFloat
fomula20*log(${VALUE})
Eingabe → Ausgabe1000 → 60.0

REST-Registrierungsbeispiel (curl)​

Registrierung eines einzelnen Tags:

curl -X POST http://<edge-host>/api/v1/opc/OPC_LS_XBM_0001/tag \
-H "Content-Type: application/json" \
-d '{
"tag_id": "OPC_LS_XBM_0001_TAG_PRESS",
"tag_name": "Pressure (kPa)",
"plc_address": "D00100",
"data_type": "Float",
"format": "REAL",
"fomula": "${VALUE}*0.1",
"description": "스케일 ×0.1 적용"
}'

Bei der Registrierung eines OPC- und Tag-Bündels einfach tag_list[] innerhalb von fomula einfügen.

Wert lesen (der nachverarbeitete Wert wird zurückgegeben):

curl -s http://<edge-host>/api/v1/tag/OPC_LS_XBM_0001_TAG_PRESS/value | jq
# {
# "result": "OK",
# "data": {
# "tag_id": "OPC_LS_XBM_0001_TAG_PRESS",
# "value": "1638.4",
# ...
# }
# }

Häufige Fehler + Lösungen​

Meldung / SymptomUrsacheLösung
계산식에 해당하는 변수값이 아직 캐시에 없습니다 : 계산식=[${VALUE}-${TAG_ZERO}]Referenziertes Tag (TAG_ZERO) wurde noch nie erfasstReferenziertes Tag zuerst registrieren + mit auto_collect=true einen Zyklus durchlaufen lassen
계산식이 참조하는 값이 숫자가 아닙니다Der Wert des referenzierten Tags ist keine Zahl (z. B. Bezug auf ein data_type=String Tag)Referenz auf ein Tag mit numerischem Typ ändern
Closing brace not found / Missing second operandKlammern nicht ausgeglichen oder fehlender Operand nach einem OperatorWird beim Speichern abgelehnt; die Fehlermeldung im Dialog nennt die Position
Nachverarbeitung nicht angewendet (raw wird unverändert zurückgegeben)data_type ist String/BooleanAuf Float/Double/Integer/Long ändern oder falls Nachverarbeitung erforderlich, separaten Verarbeitungsschritt verwenden
Ergebnis ist immer 0Der raw Wert ist tatsächlich 0raw read Wert zuerst mit GET /api/v1/tag/.../value prüfen. (Der alte Parser hat unvollständige Formeln wie ${VALUE}* stillschweigend als 0 berechnet, aber solche Formeln werden jetzt beim Speichern abgelehnt.)
Erfassungsfehler FORMAT_FAILED + QualitätsminderungDivision durch 0 oder sqrt negative Zahl usw. — BerechnungsfehlerInfinity/NaN werden nicht gespeichert, sondern als Fehler ausgegeben. Fügen Sie Schutz in die Formel ein — z. B. IF(TAG_ZERO=0, 0, VALUE/TAG_ZERO)

Betriebsnotizen​

  • LastValueMap ist ein Singleton (in-memory). Beim Neustart des Gateways wird er zurückgesetzt → Im ersten Zyklus können Referenzen auf andere Tags fehlschlagen.
  • Die Berechnung erfolgt vollständig in BigDecimal, sodass auch große Ganzzahlen in Long/QWord bis zur letzten Stelle erhalten bleiben (kein Verlust wie bei der alten double-Auswertung).
  • Das Ergebnis wird als Double.toString() → String-Cache gespeichert. Bei Anzeige / Sparkplug-Veröffentlichung wird es erneut in data_type umgewandelt (siehe Sparkplug DataTypeMapper).
  • Wenn mehrere Formeln von Tags im selben OPC aufeinander verweisen, kann der erste Zyklus je nach Erfassungsreihenfolge teilweise fehlschlagen. Betrieblich ist das kein großes Problem (ab dem nächsten Zyklus normal), aber für saubere Ergebnisse platzieren Sie die referenzierten Tags in einem separaten OPC mit kürzerer timecycle.