Files
EVOLV/wiki/concepts/pid-control-theory.md
znetsixe 48f790d123
Some checks failed
CI / lint-and-test (push) Has been cancelled
chore: clean up superproject structure
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>
2026-04-07 18:01:04 +02:00

5.2 KiB
Raw Permalink Blame History

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.