Zum Hauptinhalt springen

Leitfaden zur Verwendung von Formula (Formel, fomula)

Wenn Sie bei der Tag-Registrierung im Feld fomula einen arithmetischen Ausdruck hinterlegen, verarbeitet der Treiber den vom PLC gelesenen Rohwert (raw value) nach und verwendet den umgerechneten Wert für Cache / Sparkplug / REST-Antworten.

PunktWert
Implementierungsklasseplantpulse.app.edge.component.collector.plc.PLCValueFomula
AufrufstelleSchritt 3 von PLCValueReader.read() (raw → format → fomula → Cache-Aktualisierung)
Bibliothekplantpulse-edge-fomula.jar (plantpulse.edge.fomula.FormulaEngine)
Variablenersetzung${VALUE} (aktueller Tag-Wert) / ${tag_id} (letzter Wert eines anderen Tags, LastValueMap-Cache)
Geltungsbereich data_typeNur Float / Double / Integer / Long. Andere Typen (String, Boolean, …) werden unverändert durchgereicht
ErgebnisBigDecimal von Formula.evaluate(...) → typabhängiges Rendering (ganzzahlige Typen als Ganzzahl, Float/Double als Dezimalzahl)

Ablauf

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

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

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

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

  5. Die in der Formel referenzierten Namen werden ermittelt — VALUE ist der soeben gelesene Wert, alle übrigen sind die letzten Werte anderer Tags aus LastValueMap.

  6. Wurde ein referenzierter Tag noch nie erfasst, tritt eine Ausnahme auf:

    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 → Rückgabe als typabhängiger String.


Variablenarten

NotationBedeutungQuelle
${VALUE}Rohwert des aktuellen TagsDer soeben vom Treiber gelesene Wert
${TAG_ID_X}Letzter Wert eines anderen TagsLastValueMap (gemeinsamer Cache aller Tags)

LastValueMap hält die letzten Roh- bzw. nachverarbeiteten Werte aller Tags. Referenziert werden können nicht nur andere Tags desselben OPC, sondern auch Tags anderer OPC (sofern der betreffende Tag mindestens einmal erfasst wurde und im Cache vorliegt).

Variable nicht vorhanden

Wird ${TAG_ZERO} referenziert, TAG_ZERO aber noch nie erfasst, kann kein Wert gebunden werden und es tritt eine Ausnahme auf. Wählen Sie für den referenzierten Tag eine kürzere timecycle oder registrieren Sie ihn unter auto_collect=true, damit er zuerst erfasst wird. (Die Syntaxprüfung beim Speichern lässt diesen Fall durch — es handelt sich um ein Problem der Erfassungsreihenfolge, nicht um einen Formelfehler.)


Ausdruckssyntax

Die Schreibweise entspricht der von Excel. Funktionsnamen und Bedeutung sind identisch mit Excel, sodass Sie in Excel verwendete Formeln nahezu unverändert übernehmen können. Groß-/Kleinschreibung spielt keine Rolle (IF = if).

KategorieTokenAnmerkung
Arithmetik+, -, *, /, ^^ ist die Potenzierung
Vergleich>, <, >=, <=, =, <>= ist gleich, <> ist ungleich (wie in Excel)
Gruppierung(, )Klammern haben Vorrang
KonstantenPI, EKreiszahl, eulersche Zahl
BedingungIF, SWITCH, AND, OR, NOTIF(조건, 참일때, 거짓일때)
RundungROUND, ROUNDUP, ROUNDDOWN, CEILING, FLOOR, INT, TRUNCROUND(값, 자리수)
NumerikABS, SIGN, MOD, POWER, SQRT, CBRT, EXP, FACTDas Vorzeichen des Rests bei 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, ATAN2Basis Radiant (wie in Excel)
HyperbelfunktionenSINH, COSH, TANH, ASINH, ACOSH, ATANH
WinkelumrechnungDEGREES, RADIANSRadiant ↔ Grad
Nicht unterstützt
  • Bitoperationen (&, |)
  • Benutzerdefinierte Funktionen
  • String- / Datumsoperationen Falls Sie dies benötigen, behandeln Sie es in einer nachgelagerten Stufe (externe Funktion / Nachverarbeitungs-Node).
Ungültige Formeln werden nicht gespeichert

Syntaktisch fehlerhafte Formeln werden bereits beim Speichern abgelehnt (UI-Speicherung / CSV-Upload / Backup-Wiederherstellung gleichermaßen). Im Tag-Konfigurationsdialog können Sie einen Beispielwert eingeben und das Ergebnis vorab prüfen.

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

Variablennotation

Sowohl ${VALUE} als auch der bloße Name VALUE sind zulässig. Gleiches gilt für andere Tags — ${TAG_ZERO} = TAG_ZERO. Bereits gespeicherte ${...}-Formeln funktionieren unverändert weiter.

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

Umfangreiche Beispielsammlung

1. Einfache Skalierung (×0,1)

PunktWert
data_typeFloat
fomula${VALUE}*0.1
Eingabe → Ausgabe163841638.4

Verwendung: Ganzzahliger Rohwert → Gleitkommazahl mit einer Nachkommastelle. Wenn Temperatur-, Druck- oder Durchflusssensoren ihre Werte als Ganzzahlen senden.

2. Einheitenumrechnung (mV → V)

PunktWert
data_typeFloat
fomula${VALUE}/1000
Eingabe → Ausgabe33003.3

3. Offset-Korrektur (Celsius → Kelvin)

PunktWert
data_typeFloat
fomula${VALUE}+273.15
Eingabe → Ausgabe25298.15

4. Referenz auf anderen Tag (Nullpunktkorrektur)

PunktWert
data_typeFloat
fomula${VALUE}-${TAG_ZERO}
Eingabe → AusgabeVALUE=1024, TAG_ZERO=241000

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

5. Polynom (Quadrat)

PunktWert
data_typeFloat
fomula${VALUE}*${VALUE}*0.001
Eingabe → Ausgabe10010.0

6. Funktion — Quadratwurzel

PunktWert
data_typeFloat
fomulasqrt(${VALUE})
Eingabe → Ausgabe14412.0

7. Funktion — Trigonometrie (sin, Radiant)

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

Bei Eingabe in Grad: sin(${VALUE}*pi/180).

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

PunktWert
data_typeFloat
fomula${VALUE}*${TAG_GAIN}+${TAG_OFFSET}
Eingabe → AusgabeVALUE=100, GAIN=0.05, OFFSET=27.0

Muster, bei dem gerätespezifische Korrekturkoeffizienten als eigene Tags (oder HTTP-bind-Tags) verwaltet werden.

9. Typumwandlung / erzwungene Gleitkommadarstellung

PunktWert
data_typeFloat
fomula${VALUE}*1.0
Eingabe → Ausgabe123123.0

Wenn ein als Integer eingehender Wert lediglich nach Float gecastet werden soll.

10. Potenz / Exponent

PunktWert
data_typeFloat
fomula${VALUE}^2
Eingabe → Ausgabe525.0

11. Logarithmus

PunktWert
data_typeFloat
fomulalog(${VALUE})
Eingabe → Ausgabe1002.0

ln(...) ist ebenfalls verwendbar (natürlicher Logarithmus).

12. Kombiniert — dB-Umrechnung des RMS

PunktWert
data_typeFloat
fomula20*log(${VALUE})
Eingabe → Ausgabe100060.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 gebündelten Registrierung von OPC + Tags fügen Sie fomula einfach innerhalb von tag_list[] ein.

Wert lesen (es wird der nachverarbeitete Wert 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}]Der referenzierte Tag (TAG_ZERO) wurde noch nie erfasstReferenzierten Tag zuerst registrieren + mit auto_collect=true einen Zyklus durchlaufen lassen
계산식이 참조하는 값이 숫자가 아닙니다Der Wert des referenzierten Tags ist keine Zahl (z. B. Referenz auf einen Tag mit data_type=String)So anpassen, dass ein Tag mit numerischem Typ referenziert wird
Closing brace not found / Missing second operandKlammern nicht paarig oder Operand nach einem Operator fehltWird beim Speichern abgelehnt; die Fehlermeldung im Dialog nennt auch die Position
Nachverarbeitung wird nicht angewendet (Rohwert wird unverändert zurückgegeben)data_type ist String/BooleanAuf Float/Double/Integer/Long ändern oder bei Bedarf eine separate Verarbeitungsstufe verwenden
Ergebnis ist immer 0Der Rohwert ist tatsächlich 0Zunächst den gelesenen Rohwert mit GET /api/v1/tag/.../value prüfen. (Der alte Parser berechnete unvollständige Ausdrücke wie ${VALUE}* stillschweigend als 0; heute werden solche Ausdrücke bereits beim Speichern abgelehnt.)
Erfassungsfehler FORMAT_FAILED + QualitätsminderungBerechnungsfehler, z. B. Division durch 0 oder negativer Wert bei sqrtInfinity/NaN werden nicht gespeichert, sondern als Fehler ausgewiesen. Bauen Sie eine Absicherung in die Formel ein — z. B.: IF(TAG_ZERO=0, 0, VALUE/TAG_ZERO)

Betriebshinweise

  • LastValueMap ist ein Singleton (in-memory). Beim Neustart des Gateway wird er initialisiert → im ersten Zyklus können Referenzen auf andere Tags fehlschlagen.
  • Die Berechnung erfolgt durchgängig mit BigDecimal, sodass auch große Ganzzahlen aus Long/QWord bis zur letzten Stelle erhalten bleiben (kein Genauigkeitsverlust wie bei der alten double-Auswertung).
  • Das Ergebnis wird als Double.toString() → String-Cache abgelegt. Für Anzeige / Sparkplug-Veröffentlichung wird es erneut nach data_type gecastet (siehe Sparkplug DataTypeMapper).
  • Referenzieren sich innerhalb desselben OPC die fomula mehrerer Tags gegenseitig, kann der erste Zyklus je nach Erfassungsreihenfolge teilweise fehlschlagen. Betrieblich ist das unkritisch (ab dem nächsten Zyklus normal); für eine saubere Lösung legen Sie die referenzierten Tags in ein separates OPC mit kürzerer timecycle.