🚧 Rewrite continous simulation.
This commit is contained in:
@@ -185,6 +185,56 @@ Configuration options: `--no-web`, `--web-port <n>` or env
|
||||
benches (all mutating endpoints answer 403). Plain HTTP — keep the
|
||||
port inside the bench network.
|
||||
|
||||
## Plant environments (continuous simulation)
|
||||
|
||||
A **plant environment** simulates the physical world around the
|
||||
distributed I/O: per deterministic tick it reads what the PLC
|
||||
commanded (DO/AO), runs your plant physics, and writes what the field
|
||||
now shows (DI/AI) — the sensors the PLC reads back. Environments run
|
||||
**until manually stopped** (Ctrl+C / `docker stop`), optionally ending
|
||||
sooner via an `is_done()` criterion.
|
||||
|
||||
Attach one to a live Modbus server (wall-clock-paced 10 ms ticks):
|
||||
|
||||
```bash
|
||||
wago-sim serve --node config/pump_node.yaml --port 5020 \
|
||||
--env envs.pump_station_env:PumpStationEnv
|
||||
```
|
||||
|
||||
or run headless (unpaced, for plant-model development):
|
||||
|
||||
```bash
|
||||
wago-sim sim --node config/pump_node.yaml \
|
||||
--env envs.pump_station_env:PumpStationEnv
|
||||
```
|
||||
|
||||
**Authoring one** is a small subclass — override `model()`:
|
||||
|
||||
```python
|
||||
# myenvs/tank.py
|
||||
from wago_sim.scenario.plantenv import PlantEnv
|
||||
|
||||
class TankEnv(PlantEnv):
|
||||
def model(self, state, dt_s):
|
||||
pump_on = bool(state.by_code("DO0.0")) # PLC command
|
||||
level = float(state.by_code("AI0.0")) # current field
|
||||
return {"AI0.0": level + (-5.0 if pump_on else 1.0) * dt_s}
|
||||
|
||||
Env = TankEnv # `--env myenvs.tank` picks this up
|
||||
```
|
||||
|
||||
API surface (spec FR-8.2.14–17): `observe()` returns every
|
||||
DI/DO/AI/AO channel (I/O codes, names, values) plus aliases and
|
||||
degradation parameters; `apply()` writes DI/AI (the field);
|
||||
`force()` writes DO/AO master-side (headless runs, fault setup);
|
||||
`is_done()` optional end; `reset()` deterministic replay. Reference
|
||||
forms: `pkg.mod:ClassName`, `pkg.mod:factory`, or `pkg.mod` with
|
||||
`Env`/`make_env`. The shipped example is
|
||||
`envs/pump_station_env.py` (tank + pump physics with a low-level
|
||||
switch). Scenario-continuous mode (§8 YAML: datasets, degradation,
|
||||
invariants) remains available for scripted soak runs on the same
|
||||
engine ticks.
|
||||
|
||||
## Documentation
|
||||
|
||||
- `docs/spec/software-spec.md` — the software specification
|
||||
@@ -404,17 +454,18 @@ reporting, snapshots, and the gym-style `PlantEnv`. 30 new tests
|
||||
Datasets are **optional**: signal logic runs in parallel with CSV
|
||||
streaming, or entirely without it.
|
||||
|
||||
- [x] Plant environment `scenario/plantenv.py` (FR-8.2.14–16, requested
|
||||
2026-10-04): gym-style `PlantEnv` — deterministic engine-owned
|
||||
tick clock (never wall-clock); per tick:
|
||||
`observe()` returns the WAGO input image in engineering units
|
||||
(channel values, names, per-type I/O codes, ranges, sim-time);
|
||||
the decision source decides; `apply()` writes the decided
|
||||
outputs through the datastore's internal paths (mirrors/
|
||||
statistics/watchdog stay consistent). Existing `plugins:`
|
||||
become thin adapters; external (non-Python) decision sources
|
||||
step the env over a socket; one decision source per output
|
||||
alias per tick (ownership conflicts are errors).
|
||||
- [x] Plant environment `scenario/plantenv.py` (FR-8.2.14–17, reworked
|
||||
2026-10-04 to environment-first): standalone `PlantEnv` —
|
||||
`observe()` returns ALL modules (DI/DO/AI/AO channels, per-type
|
||||
codes, names, parameters); `apply()` writes the FIELD side
|
||||
(DI/AI) by default; `force()` writes DO/AO master-side (mirrors/
|
||||
statistics/watchdog stay consistent); `model()`/`is_done()`
|
||||
override hooks (subclass authoring, FR-8.2.17); `reset()`
|
||||
deterministic. Runners: `serve --env ...` wall-clock-paced
|
||||
alongside Modbus, runs until stopped; `sim --env ...` headless
|
||||
unpaced until is_done()/Ctrl+C. Example: `envs/pump_station_env.py`.
|
||||
Verified live: PLC coil write → env physics → level registers
|
||||
drain/refill over Modbus.
|
||||
- [x] `scenario/datasets.py` — streaming CSV playback for designated
|
||||
inputs (OPTIONAL driver): header-driven time column,
|
||||
`interpolation: linear|hold`, `repeat` with seamless seams,
|
||||
|
||||
Reference in New Issue
Block a user