Files
EVOLV/third_party/docs/pid-control-theory.md
znetsixe 6a6c04d34b Migrate to new Gitea instance (gitea.wbd-rd.nl)
- Update all submodule URLs from gitea.centraal.wbd-rd.nl to gitea.wbd-rd.nl
- Add settler as proper submodule in .gitmodules
- Add agent skills, function anchors, decisions, and improvements
- Add Docker configuration and scripts
- Add manuals and third_party docs
- Update .gitignore with secrets and build artifacts
- Remove stale .tgz build artifact

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 21:07:04 +01:00

169 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PID Control for Process Applications
> **Used by**: `mechanical-process-engineer` agent, `node-red-runtime` agent, `generalFunctions/src/pid/`
> **Validation**: Verified against Astrom & Hagglund (ISA, 2006) and MATLAB/Simulink documentation
## Continuous PID Controller
### Standard (ISA/Ideal) Form
```
u(t) = K_p · [e(t) + (1/T_i) · ∫e(τ)dτ + T_d · de(t)/dt]
```
Where:
- u(t) = controller output
- e(t) = error = setpoint - process variable (SP - PV)
- K_p = proportional gain
- T_i = integral time (seconds)
- T_d = derivative time (seconds)
### Parallel Form
```
u(t) = K_p · e(t) + K_i · ∫e(τ)dτ + K_d · de(t)/dt
```
Where K_i = K_p/T_i and K_d = K_p · T_d
## Discrete PID Implementation
### Positional Form (absolute output)
```
u[k] = K_p · e[k] + K_i · Δt · Σe[j] + K_d · (e[k] - e[k-1]) / Δt
```
- Computes the absolute output value each cycle
- Requires tracking of the integral sum
- Subject to integral windup
- Used when the controller output directly sets an actuator position
### Velocity Form (incremental output)
```
Δu[k] = K_p · (e[k] - e[k-1]) + K_i · Δt · e[k] + K_d · (e[k] - 2·e[k-1] + e[k-2]) / Δt
u[k] = u[k-1] + Δu[k]
```
- Computes the **change** in output each cycle
- Inherently bumpless on mode transfers (auto→manual→auto)
- Less prone to windup (but still needs anti-windup for output limits)
- Preferred for incremental actuators (VFDs, variable valves)
## Anti-Windup Strategies
Integral windup occurs when the controller output saturates (hits actuator limits) but the integral term continues to accumulate, causing large overshoot when the error changes sign.
### 1. Clamping (Conditional Integration)
Stop integrating when the output is saturated **and** the error has the same sign as the integral term:
```
if (u_raw > u_max || u_raw < u_min) && sign(e) == sign(integral):
freeze integral (do not accumulate)
else:
integral += e * Δt
```
- Simple to implement
- Effective for most process control applications
- The approach used in the EVOLV generalFunctions PID implementation
### 2. Back-Calculation
When the output saturates, feed back the difference between the saturated and unsaturated output to "unwind" the integrator:
```
integral += (K_i · e + K_b · (u_saturated - u_raw)) · Δt
```
Where K_b = 1/T_t (tracking time constant, typically T_t = √(T_i · T_d) or T_t = T_d).
- More sophisticated than clamping
- Better performance for systems with large disturbances
- Recommended by Astrom & Hagglund for demanding applications
### 3. Integrator Reset
Reset the integrator to a value that would produce the saturated output:
```
if u_raw > u_max:
integral = (u_max - K_p · e) / K_i
```
- Simple but can be aggressive
- May cause discontinuities
## Derivative Filtering
The derivative term amplifies high-frequency noise. Always filter it:
### First-Order Low-Pass Filter on D-Term
```
D_filtered[k] = α · D_filtered[k-1] + (1-α) · D_raw[k]
```
Where α = T_f / (T_f + Δt) and T_f = T_d / N (N typically 5-20, default 10).
### Derivative on PV (not Error)
To avoid derivative kick on setpoint changes:
```
D = -K_d · (PV[k] - PV[k-1]) / Δt (instead of using error)
```
This is the standard approach for process control.
## Cascade PID
Two nested loops where the outer (master) loop's output is the setpoint for the inner (slave) loop.
```
[SP_outer] → [PID_outer] → [SP_inner] → [PID_inner] → [Actuator] → [Process]
↑ ↑
[PV_outer] ←──── [Process] ←── [PV_inner]
```
### Design Rules
- Inner loop must be **5-10x faster** than outer loop
- Tune inner loop first (with outer loop in manual)
- Then tune outer loop
- Anti-windup on outer loop essential (its output is bounded by inner loop's SP limits)
### EVOLV Application
- Outer: Level controller → outputs flow setpoint
- Inner: Flow controller → outputs pump speed
- pumpingStation node coordinates this cascade
## Tuning Methods
### Ziegler-Nichols (Ultimate Gain Method)
1. Set I and D to zero, increase K_p until sustained oscillation
2. Record ultimate gain K_u and ultimate period T_u
3. Apply: K_p = 0.6·K_u, T_i = T_u/2, T_d = T_u/8
### Cohen-Coon (Process Reaction Curve)
1. Apply step change, record process reaction curve
2. Identify: gain K, dead time L, time constant τ
3. Apply formulas based on K, L, τ
### Lambda Tuning (IMC-based)
1. Identify process as FOPDT: K, L, τ
2. Choose closed-loop time constant λ (typically λ = max(3·L, τ))
3. K_p = τ/(K·λ), T_i = τ
- **Preferred for process control** — gives non-oscillatory response
- Directly specifies desired closed-loop speed
- Robust to model uncertainty when λ is chosen conservatively
## Authoritative References
1. Astrom, K.J. & Hagglund, T. (2006). "Advanced PID Control." ISA — The Instrumentation, Systems, and Automation Society.
2. Astrom, K.J. & Hagglund, T. (1995). "PID Controllers: Theory, Design, and Tuning." 2nd ed., ISA.
3. Seborg, D.E. et al. (2011). "Process Dynamics and Control." 3rd ed., Wiley. (Chapter on PID control)
4. MATLAB/Simulink documentation — "Anti-Windup Control Using PID Controller Block"
5. Smith, C.A. & Corripio, A.B. (2005). "Principles and Practices of Automatic Process Control." 3rd ed., Wiley.