Skip to content

Commit 38c6036

Browse files
author
Pieter Cawood
committed
Update docs
1 parent 1ba6636 commit 38c6036

File tree

1 file changed

+89
-52
lines changed

1 file changed

+89
-52
lines changed

README.md

Lines changed: 89 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66
<div style="display: flex; align-items: flex-start;">
77
<div style="flex: 1;">
88

9-
A **playground** for experimenting with **PID** and **machine-learning-based controllers**.
9+
A **playground** for experimenting with **PID**, **model‑predictive**, and **machinelearningbased controllers**.
1010
DeepPID provides both **traditional** and **neural adaptive controllers** in a single, consistent framework, complete with a live **Tkinter + Matplotlib GUI** for interactive benchmarking.
1111

12-
Through extensive simulation and real-time tests on **nonlinear**, **coupled**, and **time-varying plants**, it is demonstrated that the **ML-based adaptive models** (*GRU*, *MLP*, and *Transformer* variants) consistently **outperform conventional PID and Cascade-PID controllers** in both transient and steady-state performance.
12+
Through extensive simulation and real-time tests on **nonlinear**, **coupled**, and **timevarying plants**, it is shown that the **MLbased adaptive models** (*GRU*, *MLP*, *Transformer*) and the **Hybrid MPC** consistently **outperform conventional PID and CascadePID controllers** in difficult regimes while preserving safety.
1313

1414
The adaptive models achieve:
1515
-**Faster convergence** with minimal overshoot
16-
- 🎯 **Near-zero steady-state error** across diverse process conditions
17-
- 🧩 **Robustness** to parameter drift and actuator limits without manual re-tuning
16+
- 🎯 **Nearzero steadystate error** across diverse process conditions
17+
- 🧩 **Robustness** to parameter drift and actuator limits without manual retuning
1818

19-
These results confirm that **data-driven adaptation—when combined with physical constraints—generalizes PID control** beyond fixed-gain heuristics while maintaining interpretability and stability.
19+
These results confirm that **datadriven adaptation—combined with physical constraints—generalizes PID control** beyond fixedgain heuristics while maintaining interpretability and stability.
2020

2121
</div>
2222
<div style="margin-left: 20px; flex-shrink: 0;">
@@ -27,37 +27,56 @@ These results confirm that **data-driven adaptation—when combined with physica
2727

2828
---
2929

30-
### GRUController — Adaptive Neural Controller (PID-inspired)
30+
## At‑a‑glance: PID vs Deep Learning vs MPC
3131

32-
A gated recurrent unit (GRU) network that directly predicts actuator speeds based on recent state history.
33-
It embeds **PID-like control objectives**—composition matching, total flow regulation, smoothness, and bounded actuation—into its online loss function.
34-
While not using explicit PID equations, it behaves as a **hybrid adaptive controller**, combining physical constraints with data-driven prediction.
35-
This approach consistently **outperforms fixed-gain PID** under nonlinear, coupled, or drifting plant conditions, achieving **near-zero steady-state error** and **smoother transients**.
32+
| Approach | Best For | Strengths | Trade-offs | What it Needs |
33+
|---|---|---|---|---|
34+
| **PID / Cascade PID** | Well-behaved, weakly coupled plants with modest drift | Simple, interpretable, tiny footprint, fast response | Retuning under drift/nonlinearity, cross-coupling fights, limited look‑ahead | A rough time constant + sensible bounds; optional feed‑forward |
35+
| **Deep Learning (MLP / GRU / Transformer)** | Nonlinear, coupled, time‑varying plants; unknown physics; multi‑objective shaping | Learns mappings PID can’t; adapts online; smooth under constraints; minimal modeling | Needs careful safety layer; online training budget; behavior depends on loss design | Physical bounds/slew; losses for composition/total/smoothness; optional PID reference |
36+
| **Model Predictive Control (Hybrid MPC)** | Constraint‑heavy problems needing short look‑ahead; competing objectives | Plans over horizon; handles constraints explicitly; blends physics + learned residuals | Heavier compute; relies on model quality; horizon/weights tuning | Discrete plant update (α / k), bounds, small horizon, good normalization |
37+
38+
**When to pick what**
39+
- Start with **PID / Cascade PID** for near‑first‑order dynamics, mild couplings, or when you need a **tiny, explainable** controller.
40+
- Choose **MLP / GRU / Transformer** for **persistent nonlinearity/coupling** or frequent operating‑point changes—especially if constant re‑tuning is painful.
41+
- Use **Hybrid MPC** when you need **explicit constraint handling** and **short‑horizon look‑ahead** (e.g., avoiding actuator banging while meeting a tight total/spec).
42+
43+
> **Stability slider**: System inconsistencies and model mismatch can be **simulated** in the GUI via the **Stability** slider. Setting it **below 100%** injects drift/noise to benchmark robustness under uncertain conditions.
3644
3745
---
3846

39-
### MLPController — Physics-Aware Neural Controller
47+
## Featured controllers
48+
49+
### GRUController — Adaptive Neural Controller (PID‑inspired)
50+
A gated recurrent unit (GRU) network that directly predicts actuator speeds from recent history. It embeds **PID‑like control objectives**—composition matching, total flow regulation, smoothness, and bounded actuation—into its online loss. It behaves as a **hybrid adaptive controller**, combining physical constraints with data‑driven prediction. Achieves **near‑zero steady‑state error** and **smoother transients** under nonlinear, coupled, or drifting plants.
4051

41-
A feed-forward multilayer perceptron that maps system state directly to actuator commands.
42-
It incorporates a **physics-aware loss**, penalizing composition and total flow errors, actuator smoothness, and saturation proximity.
43-
This model is **lightweight yet powerful**, excelling in steady-state precision and smooth transitions, ideal for slower or more stable plants.
52+
### MLPController — Physics‑Aware Neural Controller
53+
A feed‑forward multilayer perceptron mapping the state to actuator commands. Uses a **physics‑aware loss** (composition, total, smoothness, and saturation barriers). **Lightweight yet strong** for steady‑state precision and smooth transitions—great baseline for slower or more stable plants.
54+
55+
### HybridMPCController — Predictive Optimizer with Learned Residuals
56+
A **short‑horizon optimizer** that rolls out a simple plant model while a **learned residual network** patches model mismatch. It enforces bounds/slew on the applied action and balances composition/total/smoothness with horizon costs. High **robustness + interpretability**, outperforming fixed‑gain and static MPC baselines in constraint‑heavy tasks.
4457

4558
---
4659

47-
### HybridMPCController — Gradient-Based Predictive Optimizer with Learned Residuals
60+
## Other controllers in the zoo
61+
62+
- **PIDController** — IMC‑style single‑loop PID with derivative on measurement, setpoint‑weighting, conditional integrator, anti‑windup, and **online τ (alpha) refinement**.
63+
- **CascadePIDController** — Inner IMC‑tuned PID per channel plus **outer PI loops** for total and composition (zero‑sum trim).
64+
- **TransformerCtrl** — Causal Transformer that consumes a recent feature window; trains online with the same physics‑aware objective.
65+
- **PINNCtrl** — MLP variant that adds **physics barriers** (positivity, soft limit barrier) to increase consistency.
66+
- **RLSafetyCtrl** — Actor network wrapped by the same **slew + clamp safety layer**; uses a supervised objective in the demo (swap for PPO/SAC in a full RL setup).
67+
- **PIDResidualNN** — Classic PID with a small NN that proposes **delta speeds**; residual is rate‑limited and tightly clamped.
68+
- **AdaptiveHierCtrl** — Cascade PID with a **tiny NN tuner** that adjusts inner‑loop gains in **log‑space** relative to baselines (safe, slow drift).
4869

49-
A **short-horizon optimizer** that blends classical MPC with a **learned residual dynamics model**.
50-
It predicts future trajectories using a simplified plant model and refines them using a small neural correction network.
51-
The result is a **model-predictive controller that adapts online**—providing high robustness and interpretability while outperforming both PID and static MPC approaches.
70+
> All controllers output **speeds** and are passed through the **same** slew limiter + clamps for apples‑to‑apples comparisons. Neural models train **online** with physics‑aware losses; MPC plans a short sequence but applies only the **first safe action** each tick.
5271
5372
---
5473

5574
The GUI (`examples/test.py`) lets you:
56-
- Choose different **plant problems** (tank, flow, quadcopter-like, etc.)
57-
- Set the stability / random noise in the system.
58-
- Switch between **controllers** (PID, CascadePID, MLP, GRU, Transformer, etc.)
59-
- Observe **real-time set-point tracking**, **mean absolute error (MAE)** curves, and **controller outputs**
60-
- See which approach adapts fastest to nonlinear or coupled dynamics
75+
- Choose different **plant problems** (tank, flow, quadcopterlike, etc.).
76+
- **Set Stability / noise** to simulate system inconsistency and model mismatch.
77+
- Switch between **controllers** (PID, CascadePID, MLP, GRU, Transformer, MPC, etc.).
78+
- Observe **realtime setpoint tracking**, **MAE curves**, and **controller outputs**.
79+
- See which approach adapts fastest to nonlinear or coupled dynamics.
6180

6281
<p align="center">
6382
<img src="docs/gui.gif" alt="DeepPID GUI"><br>
@@ -69,10 +88,41 @@ The GUI (`examples/test.py`) lets you:
6988
## What’s inside
7089

7190
- **PID**: IMC‑style auto‑tuned PID with anti‑windup, bumpless transfer, and online refinement.
72-
- **CascadePID**: stabilized inner PID with outer composition/total loops.
73-
- **Neural controllers**: MLP, GRU, Transformer, PINN‑flavored, hybrid MPC stub, and safety‑wrapped RL stub.
74-
- **GUI**: real‑time MAE table + history plot for apples‑to‑apples comparisons.
75-
- **Packaging**: imports work (`import deeppid`) and examples run out of the box.
91+
- **CascadePID**: Stabilized inner PID with outer composition/total loops.
92+
- **Neural controllers**: MLP, GRU, Transformer, PINN‑flavored, safety‑wrapped RL.
93+
- **Hybrid MPC**: Short‑horizon optimizer with a learned residual dynamics model.
94+
- **GUI**: Real‑time MAE table + history plot for apples‑to‑apples comparisons.
95+
- **Packaging**: Imports work (`import deeppid`) and examples run out of the box.
96+
97+
---
98+
99+
## Controller zoo (names match `controllers.py`)
100+
101+
- `PIDController` — IMC auto‑tuned + online refinement
102+
- `CascadePIDController` — inner PID + outer total/composition PI
103+
- `MLPController` — physics‑aware feed‑forward NN
104+
- `GRUController` — sequence model with safety + objectives
105+
- `HybridMPCController` — short‑horizon optimizer + residual model
106+
- `PIDResidualNN` — PID + small residual NN
107+
- `TransformerCtrl` — causal Transformer policy
108+
- `RLSafetyCtrl` — actor NN + safety (demo)
109+
- `PINNCtrl` — MLP with stronger physics penalties
110+
- `AdaptiveHierCtrl` — CascadePID with tiny NN tuner (log‑scaled gains)
111+
112+
---
113+
114+
## Problem zoo (names match `problems.py`)
115+
116+
- `SingleTankMixerProblem` — Baseline first‑order lag + noise (N=5).
117+
- `DeadtimeVaryingGainsProblem` — Dead‑time, actuator smoothing, drift (N=5).
118+
- `NonlinearBackpressureProblem` — Backpressure coupling + soft saturation (N=5).
119+
- `TwoTankCascadeProblem` — Two‑stage transport/mixing (N=5).
120+
- `FaultySensorsActuatorsProblem` — Stiction, outages, spikes (N=5).
121+
- `QuadcopterAltYawProblem` — Altitude (total) + yaw (composition), N=4 rotors.
122+
123+
> Add your own problems in `deeppid/envs/problems.py` and register them in `AVAILABLE_PROBLEMS`.
124+
125+
---
76126

77127
## Install (editable)
78128

@@ -99,7 +149,7 @@ This launches the controller shoot‑out app. Choose any plant from the dropdown
99149
```text
100150
deeppid/
101151
controllers/
102-
controllers.py # PID, CascadePID, MLP, GRU, Transformer, etc.
152+
controllers.py # PID, CascadePID, MLP, GRU, Transformer, MPC, etc.
103153
utils/
104154
utils.py # Utility functions
105155
envs/
@@ -111,27 +161,17 @@ tests/ # (optional) put your pytest tests here
111161

112162
## How the GRU controller works (and why it’s different from PID)
113163

114-
**Conventional PID** computes the next actuation using fixed (or slowly tuned) gains `Kp, Ki, Kd`
115-
around an interpretable structure with anti‑windup and filters. It’s great when the plant can be
116-
reasonably approximated by first/second‑order dynamics and the operating point doesn’t move too much.
164+
**Conventional PID** uses fixed/slowly tuned gains `Kp, Ki, Kd` around an interpretable structure with anti‑windup and filters—great when the plant is near first/second order and the operating point doesn’t move much.
117165

118166
**GRU controller (adaptive & live)** takes a different tack:
119167

120168
- **State** each tick: `[target ratio, total set‑point, recent measured flows, previous speeds]`
121-
- **Sequence model**: a GRU processes the recent context to estimate the next speeds in one shot
169+
- **Sequence model**: a GRU processes the recent context to estimate next speeds in one shot
122170
- **Hard safety layer**: speeds are **slew‑limited** and **clamped** to `[min, max]`
123-
- **Online objective** (optimized every few steps):
124-
- match **composition** (fractions) to target
125-
- match **total** output to the requested value
126-
- keep **smooth** changes (actuator wellness)
127-
- stay inside bounds with a **soft barrier**
128-
- optionally track a reference/baseline (e.g., PID suggestion)
129-
- **Why it helps**: when the plant is nonlinear, coupled, or operating conditions drift, the GRU
130-
can “learn” mappings PID would need re‑tuning for. You still keep the same safety rails as PID.
131-
132-
You can inspect all loss terms and constraints in `controllers.py` (classes `GRUController`, `MLPController`).
133-
Everything is implemented to be **stable‑by‑construction**: we never bypass slew/clamp and we bias to
134-
baseline allocations when signals are missing or become non‑finite.
171+
- **Online objective** (optimized every few steps): composition, total, smoothness, bound barrier, optional reference
172+
- **Why it helps**: with nonlinear, coupled, or drifting plants, the GRU learns mappings PID would need re‑tuning for—keeping the **same safety rails**.
173+
174+
You can inspect all loss terms and constraints in `controllers.py` (`GRUController`, `MLPController`). Everything is implemented to be **stable‑by‑construction**: we never bypass slew/clamp and we bias to baseline allocations when signals are missing or non‑finite.
135175

136176
---
137177

@@ -173,18 +213,18 @@ class MyCustomProblem:
173213
self._y = torch.zeros(self.N, dtype=torch.float64)
174214

175215
def baseline_allocation(self, ratio: torch.Tensor, F_total: torch.Tensor) -> torch.Tensor:
176-
\"\"\"Feedforward speeds (simple inverse of k within bounds).\"\"\"
216+
"""Feedforward speeds (simple inverse of k within bounds)."""
177217
s = (ratio * F_total) / (self.k_coeff + 1e-12)
178218
return torch.clamp(s, self.speed_min, self.speed_max)
179219

180220
def step(self, speeds_cmd: torch.Tensor) -> torch.Tensor:
181-
\"\"\"One simulation step. Update and return filtered measured outputs.\"\"\"
221+
"""One simulation step. Update and return filtered measured outputs."""
182222
y_raw = self.k_coeff * speeds_cmd
183223
self._y = self._y + self.alpha * (y_raw - self._y)
184224
return self._y.clone()
185225

186226
def comp_from_speeds(self, speeds: torch.Tensor) -> torch.Tensor:
187-
\"\"\"Return composition (fractions) implied by nominal model for display/metrics.\"\"\"
227+
"""Return composition (fractions) implied by nominal model for display/metrics."""
188228
flow = self.k_coeff * speeds
189229
tot = flow.sum() + 1e-12
190230
return flow / tot
@@ -207,7 +247,7 @@ Your new problem will now appear in the GUI's *Problem* dropdown.
207247

208248
Controllers live in `deeppid/controllers/controllers.py`. The GUI expects them to be discoverable via the
209249
package registry `deeppid.AVAILABLE` (set up in `deeppid/__init__.py`). The easiest path is to implement
210-
a class with a **PID-like interface** and wrap it with `CtrlAdapter` automatically:
250+
a class with a **PIDlike interface** and wrap it with `CtrlAdapter` automatically:
211251

212252
**Minimum contract (any of these works):**
213253
- Provide `step(flows_meas_filt, target_ratio, F_total, speeds_direct)` → returns speeds (Tensor of length N); or
@@ -269,10 +309,7 @@ from .controllers.controllers import MyFancyController
269309
AVAILABLE["MyFancy"] = MyFancyController
270310
```
271311

272-
It will then show up in the GUI *Driver* combo-box automatically.
273-
274-
> 🧩 Tip: If your controller already conforms to the `step(...)` signature, the GUI will call it directly.
275-
> Otherwise it will fall back to `forward(...)`. `CtrlAdapter` normalizes those differences for you.
312+
It will then show up in the GUI *Driver* combo‑box automatically.
276313

277314
---
278315

0 commit comments

Comments
 (0)