メインコンテンツまでスキップ

計算式 (Formula)

タグ登録時に fomula フィールドに算術式を入力すると、ドライバがPLCから読み取ったraw値(raw value)を後処理し、変換された値でキャッシュ / Sparkplug / REST応答に使用します。

項目値
実装クラスplantpulse.app.edge.component.collector.plc.PLCValueFomula
呼び出し位置PLCValueReader.read() の3段階 (raw → format → formula → キャッシュ更新)
ライブラリplantpulse-edge-fomula.jar (plantpulse.edge.fomula.FormulaEngine)
変数置換${VALUE} (現在のタグ値) / ${tag_id} (他のタグの最後の値、LastValueMap キャッシュ)
適用対象 data_typeFloat / Double / Integer / Long のみ適用。それ以外の型(String、Boolean、…)はそのまま通過
結果Formula.evaluate(...) の BigDecimal → 型別レンダリング(整数系は整数、Float/Double は小数)

動作フロー​

  1. ドライバからraw文字列値を受け取る (例: "16384")。

  2. PLCValueFomula.fomulaValue(address, value) を呼び出す。

  3. address.getFomula() が空であればそのまま返す。

  4. data_type が Float / Double / Integer / Long でない場合はそのまま返す。

  5. 計算式が参照する名前を確認 — VALUE は読み取ったばかりの値、残りは LastValueMap の他のタグの最後の値。

  6. 参照タグがまだ一度も収集されていない場合は例外:

    Variable value referenced by the formula is not yet in cache : formula=[`<fomula>`], variable=[`<name>`]
  7. 計算式が参照する名前のみを値でバインドして評価 → BigDecimal → 型別の文字列を返す。


変数の種類​

表記意味出典
${VALUE}現在のタグのraw値ドライバが読み取ったばかりの値
${TAG_ID_X}他のタグの最後の値LastValueMap (全タグ共通キャッシュ)

LastValueMap はすべてのタグの最後のraw / 後処理値を保持します。同一OPC内の他のタグだけでなく、別のOPC のタグも参照可能です (ただし、そのタグが一度でも収集されてキャッシュに存在する必要があります)。

変数が存在しない

${TAG_ZERO} を参照した際、TAG_ZERO がまだ一度も収集されていない場合、値をバインドできず例外が発生します。参照タグの timecycle を短くするか、参照タグが先に収集されるように auto_collect=true として登録 してください。(保存時点の構文チェックはこのケースを通過させます — 式エラーではなく、収集順序の問題です。)


式の構文​

Excelと同じ方法で記述します。 関数名と意味がExcelと同じなので、Excelで使用していた式をほぼそのまま移せます。大文字小文字は区別しません (IF = if)。

カテゴリトークン備考
算術+、-、*、/、^^ は累乗
比較>、<、>=、<=、=、<>= は等しい、<> は異なる (Excelと同じ)
グループ(、)括弧の優先
定数PI、E円周率、自然対数の底
条件IF、SWITCH、AND、OR、NOTIF(조건, 참일때, 거짓일때)
丸めROUND、ROUNDUP、ROUNDDOWN、CEILING、FLOOR、INT、TRUNCROUND(값, 자리수)
数値ABS、SIGN、MOD、POWER、SQRT、CBRT、EXP、FACTMOD の剰余の符号は除数に従う
集計MIN、MAX、SUM、AVERAGE、COALESCE引数は複数
対数LOG、LOG10、LNLOG = 常用対数(底10)、LN = 自然対数
三角SIN、COS、TAN、ASIN、ACOS、ATAN、ATAN2ラジアン基準 (Excelと同じ)
双曲SINH、COSH、TANH、ASINH、ACOSH、ATANH
角度変換DEGREES、RADIANSラジアン ↔ 度
サポートされないもの
  • ビット演算 (&、|)
  • ユーザー定義関数
  • 文字列演算 / 日付演算 これらが必要な場合は、後続段階 (外部関数 / 後処理ノード) で扱ってください。
不正な計算式は保存されません

構文が合わない計算式は保存時点で拒否されます (UI保存 / CSVアップロード / バックアップ復元すべて)。 タグ設定モーダルでサンプル値を入力して結果を事前に確認できます。

計算中の失敗(0除算、参照値が数値でないなど)は収集エラーとして記録され、該当タグの品質が低下します。それらしい数値を代わりに保存することはしません。

変数の表記​

${VALUE} と生名前 VALUE の両方を使用します。他のタグも同様です — ${TAG_ZERO} = TAG_ZERO。既存の保存済み ${...} 計算式はそのまま動作します。

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

豊富な例のコレクション​

1. 単純スケール (×0.1)​

項目値
data_typeFloat
fomula${VALUE}*0.1
入力 → 出力16384 → 1638.4

用途: 整数raw → 小数1桁の実数。温度 / 圧力 / 流量センサーが整数で値を送る場合。

2. 単位変換 (mV → V)​

項目値
data_typeFloat
fomula${VALUE}/1000
入力 → 出力3300 → 3.3

3. オフセット補正 (摂氏 → ケルビン)​

項目値
data_typeFloat
fomula${VALUE}+273.15
入力 → 出力25 → 298.15

4. 他タグ参照 (ゼロ点補正)​

項目値
data_typeFloat
fomula${VALUE}-${TAG_ZERO}
入力 → 出力VALUE=1024、TAG_ZERO=24 → 1000

TAG_ZERO は他タグのID。ゼロ点 / Tare補正に使用。

5. 多項式 (二乗)​

項目値
data_typeFloat
fomula${VALUE}*${VALUE}*0.001
入力 → 出力100 → 10.0

6. 関数 — 平方根​

項目値
data_typeFloat
fomulasqrt(${VALUE})
入力 → 出力144 → 12.0

7. 関数 — 三角 (sin、ラジアン)​

項目値
data_typeFloat
fomulasin(${VALUE})
入力 → 出力1.5708 (≈π/2) → 1.0

角度(度)入力の場合は sin(${VALUE}*pi/180).

8. 複数タグ — キャリブレーション (gain × x + offset)​

項目値
data_typeFloat
fomula${VALUE}*${TAG_GAIN}+${TAG_OFFSET}
入力 → 出力VALUE=100、GAIN=0.05、OFFSET=2 → 7.0

機器別の補正係数を別タグ(またはHTTP-bindタグ)で管理するパターン。

9. 型変換 / 強制実数化​

項目値
data_typeFloat
fomula${VALUE}*1.0
入力 → 出力123 → 123.0

Integer で入力された値を Float にキャスティングしたい場合。

10. 累乗 / 指数​

項目値
data_typeFloat
fomula${VALUE}^2
入力 → 出力5 → 25.0

11. 対数​

項目値
data_typeFloat
fomulalog(${VALUE})
入力 → 出力100 → 2.0

ln(...) も使用可能 (自然対数)。

12. 複合 — RMSのdB変換​

項目値
data_typeFloat
fomula20*log(${VALUE})
入力 → 出力1000 → 60.0

REST登録例 (curl)​

タグ単体登録:

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 적용"
}'

OPC + タグのセット登録時は tag_list[] 内に fomula を入れればOKです。

値のread (後処理された値が返されます):

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",
# ...
# }
# }

よくあるエラーと解決策​

メッセージ / 症状原因解決策
계산식에 해당하는 변수값이 아직 캐시에 없습니다 : 계산식=[${VALUE}-${TAG_ZERO}]参照タグ (TAG_ZERO) がまだ一度も収集されていない参照タグを先に登録し、auto_collect=true で1サイクル実行しておく
계산식이 참조하는 값이 숫자가 아닙니다参照タグの値が数値でない (例: data_type=String のタグを参照)数値型タグを参照するように修正
Closing brace not found / Missing second operand括弧の対応が合わない、または演算子の後にオペランドがない保存時点で拒否されるため、モーダルのエラーメッセージが位置を教えてくれます
後処理が適用されない (rawがそのまま返る)data_type が String/BooleanFloat/Double/Integer/Long に変更するか、後処理が必要な場合は別の加工段階を使用
結果が常に 0raw値が実際に 0raw読み取り値を最初に GET /api/v1/tag/.../value で確認。(旧パーサーは ${VALUE}* のような不完全な式を黙って 0 として計算していましたが、現在はそのような式は保存段階で拒否されます。)
収集エラー FORMAT_FAILED + 品質低下0 で割る、または sqrt 負数など計算失敗Infinity/NaN を保存せず、エラーとして明示します。式にガードを入れましょう — 例: IF(TAG_ZERO=0, 0, VALUE/TAG_ZERO)

動作メモ​

  • LastValueMap はシングルトン (in-memory)。ゲートウェイ再起動時に初期化 → 最初のサイクルでは他タグ参照が失敗する可能性があります。
  • 計算は全セクション BigDecimal なので、Long/QWord の大きな整数も最後の桁まで保持されます(旧 double 評価で生じていた損失なし)。
  • 結果は Double.toString() → 文字列キャッシュ。画面 / Sparkplug発行時に再度 data_type にキャスティングされます (Sparkplug DataTypeMapper 参照)。
  • 同一OPC内で複数のタグのformulaが相互に参照する場合、収集順序によって最初のサイクルが部分的に失敗することがあります。運用上は大きな問題ではありませんが(次のサイクルから正常)、クリーンにするには参照先タグをより短い timecycle の別OPCに配置してください。