計算式 (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_type | Float / Double / Integer / Long のみ適用。それ以外の型(String、Boolean、…)はそのまま通過 |
| 結果 | Formula.evaluate(...) の BigDecimal → 型別レンダリング(整数系は整数、Float/Double は小数) |
動作フロー
-
ドライバからraw文字列値を受け取る (例:
"16384")。 -
PLCValueFomula.fomulaValue(address, value)を呼び出す。 -
address.getFomula()が空であればそのまま返す。 -
data_typeが Float / Double / Integer / Long でない場合はそのまま返す。 -
計算式が参照する名前を確認 —
VALUEは読み取ったばかりの値、残りはLastValueMapの他のタグの最後の値。 -
参照タグがまだ一度も収集されていない場合は例外:
Variable value referenced by the formula is not yet in cache : formula=[`<fomula>`], variable=[`<name>`] -
計算式が参照する名前のみを値でバインドして評価 →
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、NOT | IF(조건, 참일때, 거짓일때) |
| 丸め | ROUND、ROUNDUP、ROUNDDOWN、CEILING、FLOOR、INT、TRUNC | ROUND(값, 자리수) |
| 数値 | ABS、SIGN、MOD、POWER、SQRT、CBRT、EXP、FACT | MOD の剰余の符号は除数に従う |
| 集計 | MIN、MAX、SUM、AVERAGE、COALESCE | 引数は複数 |
| 対数 | LOG、LOG10、LN | LOG = 常用対数(底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_type | Float |
fomula | ${VALUE}*0.1 |
| 入力 → 出力 | 16384 → 1638.4 |
用途: 整数raw → 小数1桁の実数。温度 / 圧力 / 流量センサーが整数で値を送る場合。
2. 単位変換 (mV → V)
| 項目 | 値 |
|---|---|
data_type | Float |
fomula | ${VALUE}/1000 |
| 入力 → 出力 | 3300 → 3.3 |
3. オフセット補正 (摂氏 → ケルビン)
| 項目 | 値 |
|---|---|
data_type | Float |
fomula | ${VALUE}+273.15 |
| 入力 → 出力 | 25 → 298.15 |
4. 他タグ参照 (ゼロ点補正)
| 項目 | 値 |
|---|---|
data_type | Float |
fomula | ${VALUE}-${TAG_ZERO} |
| 入力 → 出力 | VALUE=1024、TAG_ZERO=24 → 1000 |
TAG_ZERO は他タグのID。ゼロ点 / Tare補正に使用。
5. 多項式 (二乗)
| 項目 | 値 |
|---|---|
data_type | Float |
fomula | ${VALUE}*${VALUE}*0.001 |
| 入力 → 出力 | 100 → 10.0 |
6. 関数 — 平方根
| 項目 | 値 |
|---|---|
data_type | Float |
fomula | sqrt(${VALUE}) |
| 入力 → 出力 | 144 → 12.0 |
7. 関数 — 三角 (sin、ラジアン)
| 項目 | 値 |
|---|---|
data_type | Float |
fomula | sin(${VALUE}) |
| 入力 → 出力 | 1.5708 (≈π/2) → 1.0 |
角度(度)入力の場合は sin(${VALUE}*pi/180).
8. 複数タグ — キャリブレーション (gain × x + offset)
| 項目 | 値 |
|---|---|
data_type | Float |
fomula | ${VALUE}*${TAG_GAIN}+${TAG_OFFSET} |
| 入力 → 出力 | VALUE=100、GAIN=0.05、OFFSET=2 → 7.0 |
機器別の補正係数を別タグ(またはHTTP-bindタグ)で管理するパターン。
9. 型変換 / 強制実数化
| 項目 | 値 |
|---|---|
data_type | Float |
fomula | ${VALUE}*1.0 |
| 入力 → 出力 | 123 → 123.0 |
Integer で入力された値を Float にキャスティングしたい場合。
10. 累乗 / 指数
| 項目 | 値 |
|---|---|
data_type | Float |
fomula | ${VALUE}^2 |
| 入力 → 出力 | 5 → 25.0 |
11. 対数
| 項目 | 値 |
|---|---|
data_type | Float |
fomula | log(${VALUE}) |
| 入力 → 出力 | 100 → 2.0 |
ln(...) も使用可能 (自然対数)。
12. 複合 — RMSのdB変換
| 項目 | 値 |
|---|---|
data_type | Float |
fomula | 20*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/Boolean | Float/Double/Integer/Long に変更するか、後処理が必要な場合は別の加工段階を使用 |
結果が常に 0 | raw値が実際に 0 | raw読み取り値を最初に 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にキャスティングされます (SparkplugDataTypeMapper参照)。 - 同一OPC内で複数のタグのformulaが相互に参照する場合、収集順序によって最初のサイクルが部分的に失敗することがあります。運用上は大きな問題ではありませんが(次のサイクルから正常)、クリーンにするには参照先タグをより短い
timecycleの別OPCに配置してください。