sankalpsthakur commited on
Commit
a7a0e30
·
verified ·
1 Parent(s): 37dadb7

Publish read-only edge adapters and generic PLC tag examples

Browse files
Files changed (3) hide show
  1. edge/inference_onnx.py +50 -0
  2. edge/plc_guard.py +29 -0
  3. edge/tag_map.yml +33 -0
edge/inference_onnx.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Run the public pump surrogate with ONNX Runtime on CPU."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import json
8
+ from pathlib import Path
9
+
10
+ import numpy as np
11
+ import onnxruntime as ort
12
+
13
+ FEATURE_ORDER = (
14
+ "speed_fraction",
15
+ "static_head_m",
16
+ "system_k",
17
+ "voltage_fraction",
18
+ "ambient_temp_c",
19
+ "inlet_pressure_bar",
20
+ )
21
+ TARGET_ORDER = (
22
+ "flow_m3h",
23
+ "total_head_m",
24
+ "input_power_kw",
25
+ "winding_temp_c",
26
+ "npsh_margin_m",
27
+ "efficiency_fraction",
28
+ )
29
+
30
+
31
+ def predict(model_path: Path, values: list[float]) -> dict[str, float]:
32
+ if len(values) != len(FEATURE_ORDER):
33
+ raise ValueError(f"expected {len(FEATURE_ORDER)} values")
34
+ session = ort.InferenceSession(str(model_path), providers=["CPUExecutionProvider"])
35
+ output = session.run(["outputs"], {"features": np.asarray([values], dtype=np.float32)})[0][0]
36
+ return {name: float(value) for name, value in zip(TARGET_ORDER, output, strict=True)}
37
+
38
+
39
+ def main() -> int:
40
+ parser = argparse.ArgumentParser()
41
+ parser.add_argument("--model", type=Path, default=Path("onnx/model.onnx"))
42
+ parser.add_argument("values", nargs=6, type=float, metavar="VALUE")
43
+ args = parser.parse_args()
44
+ print(json.dumps({"feature_order": FEATURE_ORDER, "prediction": predict(args.model, args.values)}, indent=2))
45
+ return 0
46
+
47
+
48
+ if __name__ == "__main__":
49
+ raise SystemExit(main())
50
+
edge/plc_guard.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Read-only advisory boundary around pump-surrogate predictions.
2
+
3
+ This module has no network, PLC, OPC UA, S7, or Modbus client. It cannot write
4
+ to a controller. Certified equipment protection and emergency shutdown logic
5
+ must remain in an independently engineered PLC/SIS layer.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+
11
+ def advisory(features: dict[str, float], prediction: dict[str, float]) -> dict[str, object]:
12
+ reasons: list[str] = []
13
+ if features["voltage_fraction"] < 0.90:
14
+ reasons.append("undervoltage_demo_threshold")
15
+ if prediction["npsh_margin_m"] < 1.0:
16
+ reasons.append("cavitation_margin_demo_threshold")
17
+ if prediction["winding_temp_c"] > 70.0:
18
+ reasons.append("thermal_demo_threshold")
19
+ if features["speed_fraction"] > 0.35 and prediction["flow_m3h"] < 0.20:
20
+ reasons.append("no_flow_demo_threshold")
21
+ if prediction["input_power_kw"] > 3.2:
22
+ reasons.append("overload_demo_threshold")
23
+ return {
24
+ "mode": "read_only_advisory",
25
+ "severity": "review" if reasons else "nominal",
26
+ "reasons": reasons,
27
+ "automatic_write_allowed": False,
28
+ "operator_or_safety_system_decision_required": bool(reasons),
29
+ }
edge/tag_map.yml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ schema_version: 1
2
+ profile: generic_pump_demo_read_only
3
+ write_enabled: false
4
+ note: >-
5
+ Illustrative symbolic mappings only. Siemens is a trademark of its owner;
6
+ this project is not affiliated with or validated by Siemens. No PLC client
7
+ or controller write path is included.
8
+ signals:
9
+ speed_fraction:
10
+ opcua_node: "ns=2;s=PumpDemo.SpeedFraction"
11
+ modbus_input_register: 30001
12
+ s7_symbolic: "DB_PUMP_DEMO.SpeedFraction"
13
+ static_head_m:
14
+ opcua_node: "ns=2;s=PumpDemo.StaticHeadM"
15
+ modbus_input_register: 30003
16
+ s7_symbolic: "DB_PUMP_DEMO.StaticHeadM"
17
+ system_k:
18
+ opcua_node: "ns=2;s=PumpDemo.SystemK"
19
+ modbus_input_register: 30005
20
+ s7_symbolic: "DB_PUMP_DEMO.SystemK"
21
+ voltage_fraction:
22
+ opcua_node: "ns=2;s=PumpDemo.VoltageFraction"
23
+ modbus_input_register: 30007
24
+ s7_symbolic: "DB_PUMP_DEMO.VoltageFraction"
25
+ ambient_temp_c:
26
+ opcua_node: "ns=2;s=PumpDemo.AmbientTempC"
27
+ modbus_input_register: 30009
28
+ s7_symbolic: "DB_PUMP_DEMO.AmbientTempC"
29
+ inlet_pressure_bar:
30
+ opcua_node: "ns=2;s=PumpDemo.InletPressureBar"
31
+ modbus_input_register: 30011
32
+ s7_symbolic: "DB_PUMP_DEMO.InletPressureBar"
33
+