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.
| Element | Wert |
|---|---|
| Implementierungsklasse | plantpulse.app.edge.component.collector.plc.PLCValueFomula |
| Aufrufstelle | Schritt 3 in PLCValueReader.read() (raw → format → Formel → Cache-Aktualisierung) |
| Bibliothek | plantpulse-edge-fomula.jar (plantpulse.edge.fomula.FormulaEngine) |
| Variablenersetzung | ${VALUE} (aktueller Tag-Wert) / ${tag_id} (letzter Wert anderer Tags, LastValueMap Cache) |
Anwendbare data_type | Float / Double / Integer / Long nur anwendbar. Andere Typen (String, Boolean, …) werden unverändert durchgereicht |
| Ergebnis | Formula.evaluate(...) BigDecimal → Typ-basiertes Rendering (Ganzzahl-Typen als Ganzzahl, Float/Double als Dezimalzahl) |
Ablauf
-
Der Treiber empfängt den raw String-Wert (z. B.
"16384"). -
PLCValueFomula.fomulaValue(address, value)wird aufgerufen. -
Wenn
address.getFomula()leer ist, wird der Wert unverändert zurückgegeben. -
Wenn
data_typenicht Float / Double / Integer / Long ist, wird der Wert unverändert zurückgegeben. -
Die in der Formel referenzierten Namen werden geprüft —
VALUEist der gerade gelesene Wert, die übrigen sind der letzte Wert anderer Tags ausLastValueMap. -
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>`] -
Nur die in der Formel referenzierten Namen werden mit Werten gebunden und ausgewertet →
BigDecimal→ Typ-basierte String-Rückgabe.
Variablentypen
| Notation | Bedeutung | Quelle |
|---|---|---|
${VALUE} | raw Wert des aktuellen Tags | Wert, den der Treiber gerade gelesen hat |
${TAG_ID_X} | Letzter Wert eines anderen Tags | LastValueMap (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).
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).
| Kategorie | Token | Hinweis |
|---|---|---|
| Arithmetik | +, -, *, /, ^ | ^ ist Potenzierung |
| Vergleich | >, <, >=, <=, =, <> | = ist gleich, <> ist ungleich (wie in Excel) |
| Gruppierung | (, ) | Klammer-Priorität |
| Konstanten | PI, E | Kreiszahl, Eulersche Zahl |
| Bedingungen | IF, SWITCH, AND, OR, NOT | IF(조건, 참일때, 거짓일때) |
| Rundung | ROUND, ROUNDUP, ROUNDDOWN, CEILING, FLOOR, INT, TRUNC | ROUND(값, 자리수) |
| Numerisch | ABS, SIGN, MOD, POWER, SQRT, CBRT, EXP, FACT | Das Vorzeichen des Restes von MOD folgt dem Divisor |
| Aggregation | MIN, MAX, SUM, AVERAGE, COALESCE | Mehrere Argumente |
| Logarithmus | LOG, LOG10, LN | LOG = Dekadischer Logarithmus (Basis 10), LN = natürlicher Logarithmus |
| Trigonometrie | SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2 | Bogenmaß (Radians) wie in Excel |
| Hyperbolisch | SINH, COSH, TANH, ASINH, ACOSH, ATANH | |
| Winkelumrechnung | DEGREES, RADIANS | Bogenmaß ↔ Grad |
- Bitweise Operationen (
&,|) - Benutzerdefinierte Funktionen
- String-Operationen / Datumsoperationen Falls solche benötigt werden, verwenden Sie nachgelagerte Schritte (externe Funktion / Nachverarbeitungsknoten).
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)
| Element | Wert |
|---|---|
data_type | Float |
fomula | ${VALUE}*0.1 |
| Eingabe → Ausgabe | 16384 → 1638.4 |
Verwendung: Ganzzahl raw → Dezimalzahl mit einer Nachkommastelle. Wenn Temperatur / Druck / Durchfluss-Sensoren den Wert als Ganzzahl senden.
2. Einheitenumrechnung (mV → V)
| Element | Wert |
|---|---|
data_type | Float |
fomula | ${VALUE}/1000 |
| Eingabe → Ausgabe | 3300 → 3.3 |
3. Offset-Korrektur (Celsius → Kelvin)
| Element | Wert |
|---|---|
data_type | Float |
fomula | ${VALUE}+273.15 |
| Eingabe → Ausgabe | 25 → 298.15 |
4. Referenz auf anderes Tag (Nullpunkt-Korrektur)
| Element | Wert |
|---|---|
data_type | Float |
fomula | ${VALUE}-${TAG_ZERO} |
| Eingabe → Ausgabe | VALUE=1024, TAG_ZERO=24 → 1000 |
TAG_ZERO ist die ID eines anderen Tags. Wird für Nullpunkt-/Tara-Korrektur verwendet.
5. Polynom (Quadrat)
| Element | Wert |
|---|---|
data_type | Float |
fomula | ${VALUE}*${VALUE}*0.001 |
| Eingabe → Ausgabe | 100 → 10.0 |
6. Funktion — Quadratwurzel
| Element | Wert |
|---|---|
data_type | Float |
fomula | sqrt(${VALUE}) |
| Eingabe → Ausgabe | 144 → 12.0 |
7. Funktion — Trigonometrie (sin, Bogenmaß)
| Element | Wert |
|---|---|
data_type | Float |
fomula | sin(${VALUE}) |
| Eingabe → Ausgabe | 1.5708 (≈π/2) → 1.0 |
Wird ein Winkel in Grad eingegeben, verwenden Sie sin(${VALUE}*pi/180).
8. Mehrere Tags — Kalibrierung (gain × x + offset)
| Element | Wert |
|---|---|
data_type | Float |
fomula | ${VALUE}*${TAG_GAIN}+${TAG_OFFSET} |
| Eingabe → Ausgabe | VALUE=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
| Element | Wert |
|---|---|
data_type | Float |
fomula | ${VALUE}*1.0 |
| Eingabe → Ausgabe | 123 → 123.0 |
Wenn ein über Integer empfangener Wert nur in Float umgewandelt (gecastet) werden soll.
10. Potenzierung / Exponential
| Element | Wert |
|---|---|
data_type | Float |
fomula | ${VALUE}^2 |
| Eingabe → Ausgabe | 5 → 25.0 |
11. Logarithmus
| Element | Wert |
|---|---|
data_type | Float |
fomula | log(${VALUE}) |
| Eingabe → Ausgabe | 100 → 2.0 |
ln(...) kann ebenfalls verwendet werden (natürlicher Logarithmus).
12. Kombination — dB-Umrechnung für RMS
| Element | Wert |
|---|---|
data_type | Float |
fomula | 20*log(${VALUE}) |
| Eingabe → Ausgabe | 1000 → 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 / Symptom | Ursache | Lösung |
|---|---|---|
계산식에 해당하는 변수값이 아직 캐시에 없습니다 : 계산식=[${VALUE}-${TAG_ZERO}] | Referenziertes Tag (TAG_ZERO) wurde noch nie erfasst | Referenziertes 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 operand | Klammern nicht ausgeglichen oder fehlender Operand nach einem Operator | Wird beim Speichern abgelehnt; die Fehlermeldung im Dialog nennt die Position |
| Nachverarbeitung nicht angewendet (raw wird unverändert zurückgegeben) | data_type ist String/Boolean | Auf Float/Double/Integer/Long ändern oder falls Nachverarbeitung erforderlich, separaten Verarbeitungsschritt verwenden |
Ergebnis ist immer 0 | Der raw Wert ist tatsächlich 0 | raw 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ätsminderung | Division durch 0 oder sqrt negative Zahl usw. — Berechnungsfehler | Infinity/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
LastValueMapist 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 inLong/QWordbis zur letzten Stelle erhalten bleiben (kein Verlust wie bei der altendouble-Auswertung). - Das Ergebnis wird als
Double.toString()→ String-Cache gespeichert. Bei Anzeige / Sparkplug-Veröffentlichung wird es erneut indata_typeumgewandelt (siehe SparkplugDataTypeMapper). - 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.