Graphs and roles¶
Operators are wired into a graph by signal names. Compiling the graph checks it, orders it for the step, and derives the plant's control structure: its loops and the role of every signal.
Signals and the single-writer rule¶
A signal is a named array of values with a unit. Every signal has exactly one writer, checked when the graph is built. Two consequences shape how plants are described:
- A controller always writes its output. Its mode, manual output and remote setpoint are inputs, so switching to manual never changes who writes the output.
- A regulated variable is written only by the plant. Nobody sets it directly: to change it, change its setpoint. An event that targets it is refused with a fix that names the setpoint.
No algebraic loops¶
Within a step, an operator's output may depend on other outputs of the same step, through its direct feedthrough. These same-step dependencies must form no cycle: every feedback path must pass through at least one operator without direct feedthrough, typically a dynamic operator whose output is its state. A cycle is rejected at compile time, with its path:
[E_ALGEBRAIC_LOOP] b -> a -> b: These operators depend on each other within the same step (an algebraic loop).
Fix: Insert an operator without direct feedthrough on the cycle (a lag, an integrator or a delay).
A control loop through a dynamic plant or a lagged instrument has such an operator, so it compiles.
Controllers read measurements¶
A feedback operator must read the final output of an instrument, never a true value or an intermediate instrument stage. Measurement error therefore propagates into the real process: a biased transmitter makes the controller hold the wrong true value, as in a real plant.
Loops¶
Every feedback operator defines a control loop, named after its controller. The compiler follows the measurement back through the instrument to the regulated variable, and records the loop's setpoint, remote setpoint, mode, manual output, output and output limits. A signal that only reshapes the controller output, such as a valve's friction and travel limits, carries the loop's manipulated role too.
Roles¶
A role describes what a signal does. Roles come from the graph's structure, not from names, and most are relations to a loop:
| Role | Meaning |
|---|---|
regulated@L |
The true variable that loop L controls. |
measured@L |
The instrument reading that loop L's controller reads. |
reference@L |
Loop L's setpoint (or remote setpoint). |
mode@L, manual@L |
Loop L's mode and manual output. |
manipulated@L |
Loop L's controller output, and the valve positions it drives. |
exogenous |
A source: a disturbance, a feed property, a schedule. |
parameter |
A parameter that events change during the run. |
measured |
An instrument reading that no controller reads. |
observation stage |
An intermediate stage of an instrument. |
free state |
Any other signal of the plant. |
A signal may hold several roles, for example the regulated variable of one loop and the disturbance of another.
The causal graph¶
run.meta["causal_graph"] lists every signal and every edge between them. Each edge names the operator that links the two signals and says whether the effect is within the same step (direct feedthrough) or through a state. Parameters that events change are nodes too, so a fault's path from its parameter to every signal it affects can be read from the graph.