Some checks failed
CI / lint-and-test (push) Has been cancelled
Move content to correct locations: - AGENTS.md → .agents/AGENTS.md (with orchestrator reference update) - third_party/docs/ (8 reference docs) → wiki/concepts/ - manuals/ (12 Node-RED docs) → wiki/manuals/ Delete 23 unreferenced one-off scripts from scripts/ (keeping 5 active). Delete stale Dockerfile.e2e, docker-compose.e2e.yml, test/e2e/. Remove empty third_party/ directory. Root is now: README, CLAUDE.md, LICENSE, package.json, Makefile, Dockerfile, docker-compose.yml, docker/, scripts/ (5), nodes/, wiki/, plus dotfiles (.agents, .claude, .gitea). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
169 lines
5.2 KiB
Markdown
169 lines
5.2 KiB
Markdown
# 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.
|