PID Tuning & Digital Implementation
Making PID work on real plants. Learn PID forms (ideal, parallel, series), tuning methods (Ziegler–Nichols open and closed loop, Cohen–Coon, IMC/lambda, SIMC), derivative filtering and derivative-on-measurement, setpoint weighting, integral windup and anti-windup, bumpless transfer, discretisation and sample time — with a full discrete PID simulator in Python comparing Z-N and SIMC tuning.
Over 90% of industrial control loops are PID. Yet surveys regularly find that many loops in real plants run in manual or are badly tuned, oscillating and wasting energy. Good tuning and a robust implementation are practical, valuable skills.
A textbook PID equation is not enough: real controllers need derivative filtering, anti-windup, bumpless manual/auto transfer, output limits and a sensible sample time. This lesson builds all of these.
An analogy
Tuning a PID is like adjusting a shower: P is how far you turn the knob for a given temperature error, I keeps nudging until it's exactly right, D reacts to how fast the temperature is changing — and the dead time is the delay before the water reaches you, which is what makes people over-correct.
What P, I and D do
P reacts to the present error (faster but leaves offset on its own). I accumulates past error and removes offset (but adds phase lag and can cause oscillation). D reacts to the rate of change, anticipating the future (adds damping, but amplifies noise). Most process loops use PI; D helps slow, lag-dominant processes like temperature.
Tuning methods
Choose by what you know about the process:
- Ziegler–Nichols ultimate-cycle — find K_u and P_u by pushing to oscillation (risky on real plants)
- Ziegler–Nichols / Cohen–Coon reaction curve — from a FOPDT step test; aggressive
- Lambda (IMC) — choose a closed-loop time constant λ; robust, popular in pulp & paper and chemicals
- SIMC (Skogestad) — simple rules, good for both setpoint and disturbance response
- Relay auto-tuning — automatic, safe limit cycle to estimate K_u, P_u (used in many controllers)
- Loop tuning software — identify model from routine data, optimise robustness (M_s)
Implementation details
Derivative-on-measurement avoids 'derivative kick' on setpoint steps; setpoint weighting (b, c factors) softens proportional kick. A first-order filter on D (N = 8–20) limits noise amplification. Anti-windup (conditional integration or back-calculation) stops the integral growing while the valve is saturated. Bumpless transfer initialises the integral so switching manual → auto doesn't jump the output. Controller action (direct/reverse) must match the valve and process gain signs.
Digital control considerations
Controllers run in discrete time. Choose sample time T_s ≈ τ/10 or less (and ≤ θ/4); too slow adds effective delay T_s/2 and aliasing, too fast amplifies noise in D and wastes CPU. Discretisation via backward Euler or Tustin; the velocity (incremental) form naturally handles saturation and bumpless transfer. Use anti-alias filters on PVs, and watch for quantisation of small integral increments in fixed-point PLCs.
Formulas
- Ideal (ISA) PID:
u = K_c [e + (1/T_i)∫e dt + T_d de/dt] - Parallel form:
u = K_p e + K_i ∫e dt + K_d de/dt, K_i = K_c/T_i, K_d = K_c T_d - Z-N reaction curve (PID):
K_c = 1.2τ/(Kθ), T_i = 2θ, T_d = 0.5θ - Z-N ultimate cycle (PID):
K_c = 0.6K_u, T_i = P_u/2, T_d = P_u/8 - SIMC (Skogestad) PI:
K_c = τ/(K(τ_c + θ)), T_i = min(τ, 4(τ_c + θ)), τ_c = θ (default) - Lambda / IMC PI:
K_c = τ/(K(λ + θ)), T_i = τ - Filtered derivative:
D(s) = K_c T_d s / (1 + (T_d/N)s), N ≈ 8–20 - Discrete PID (velocity form):
Δu_k = K_c[(e_k − e_{k−1}) + (T_s/T_i)e_k + (T_d/T_s)(e_k − 2e_{k−1} + e_{k−2})]
Worked example: Z-N ultimate cycle
Given: Loop oscillates steadily at K_c = 4 with period 12 s
Find: PID settings.
- K_c = 0.6 × 4
- T_i = 12/2, T_d = 12/8
Answer: K_c = 2.4, T_i = 6 s, T_d = 1.5 s
Worked example: Lambda tuning
Given: K = 2, τ = 10 s, θ = 2 s, λ = 10 s
Find: PI settings.
- K_c = 10/(2 × 12)
- T_i = τ
Answer: K_c = 0.42, T_i = 10 s (slow, very robust)
Worked example: Sample time
Given: Flow loop τ = 2 s, θ = 0.5 s
Find: Maximum sample time.
- τ/10 = 0.2 s; θ/4 = 0.125 s
Answer: ≈ 0.1 s
Discrete PID with anti-windup — Ziegler–Nichols vs SIMC
# Discrete PID with derivative-on-measurement, filtered D and anti-windup,
# controlling a first-order-plus-dead-time process G = K e^(-Ls)/(tau s + 1)
K, tau, L, dt = 2.0, 10.0, 2.0, 0.1
delay = [0.0] * int(L / dt)
def simulate(Kp, Ti, Td, steps=600, umax=100.0):
y = 0.0; integ = 0.0; d_f = 0.0; y_prev = 0.0
sp = 1.0; peak = 0.0; t_settle = None; hist = []
for n in range(steps):
e = sp - y
d_raw = -(y - y_prev) / dt # derivative on measurement
d_f += (dt / (Td / 10 + dt)) * (d_raw - d_f) if Td > 0 else 0.0
u = Kp * (e + integ / Ti + Td * d_f)
u_sat = max(-umax, min(umax, u))
if u == u_sat: # conditional integration (anti-windup)
integ += e * dt
y_prev = y
delay.append(u_sat); u_d = delay.pop(0)
y += dt * (K * u_d - y) / tau # plant
peak = max(peak, y); hist.append(y)
for n in range(len(hist) - 1, -1, -1):
if abs(hist[n] - sp) > 0.02:
t_settle = (n + 1) * dt; break
return peak, t_settle, hist[-1]
# Ziegler-Nichols open-loop (reaction curve) and SIMC tuning
zn = (1.2 * tau / (K * L), 2 * L, 0.5 * L)
tc = L # SIMC closed-loop time constant
simc = (tau / (K * (tc + L)), min(tau, 4 * (tc + L)), 0.0)
for name, (Kp, Ti, Td) in (("Z-N PID", zn), ("SIMC PI", simc)):
delay[:] = [0.0] * int(L / dt)
peak, ts, yend = simulate(Kp, Ti, Td)
print(f"{name}: Kp={Kp:.2f} Ti={Ti:.1f} Td={Td:.1f} -> overshoot {max(0,(peak-1))*100:.0f}%, settle(2%) {ts:.1f} s, y(60 s)={yend:.3f}")
# Z-N PID: Kp=3.00 Ti=4.0 Td=1.0 -> overshoot 70%, settle(2%) 22.7 s, y(60 s)=1.000
# SIMC PI: Kp=1.25 Ti=10.0 Td=0.0 -> overshoot 5%, settle(2%) 12.3 s, y(60 s)=1.000Ziegler–Nichols (1942) targets quarter-amplitude decay — aggressive, 70% overshoot here. Modern model-based rules (SIMC, lambda/IMC) give smooth, robust responses and settle faster. The implementation details (derivative on PV, filtered D with N = 10, conditional-integration anti-windup) are what industrial controllers do.
PID function block in Structured Text (illustrative)
FUNCTION_BLOCK FB_PID
VAR_INPUT
sp, pv : REAL;
kc, ti, td : REAL; (* ti, td in seconds *)
ts : REAL := 0.1; (* sample time, s *)
out_min : REAL := 0.0;
out_max : REAL := 100.0;
manual : BOOL;
man_out : REAL;
END_VAR
VAR_OUTPUT
out : REAL;
END_VAR
VAR
integ, pv_prev, d_filt : REAL;
END_VAR
IF manual THEN
out := man_out;
integ := out / kc - (sp - pv); (* bumpless transfer back to auto *)
ELSE
d_filt := d_filt + ts / (td / 10.0 + ts) * (-(pv - pv_prev) / ts - d_filt);
out := kc * ((sp - pv) + integ + td * d_filt);
IF out > out_max THEN out := out_max;
ELSIF out < out_min THEN out := out_min;
ELSE integ := integ + (sp - pv) * ts / ti; (* integrate only when not saturated *)
END_IF;
END_IF;
pv_prev := pv;
END_FUNCTION_BLOCKIllustrative IEC 61131-3 code (not compiled here) showing the essentials. In practice use the vendor's tested PID block (PID_Compact, PIDE, PID in Codesys) and set its options rather than writing your own — but knowing what's inside helps you configure and troubleshoot it.
Common mistakes
- Wrong: Using Z-N settings as final tuning. — Right: Use them as a start; prefer lambda/SIMC for robustness.
- Wrong: Derivative on noisy flow loops. — Right: Flow loops: PI with fast integral, no D.
- Wrong: No anti-windup on loops that saturate. — Right: Always enable anti-windup and output limits.
- Wrong: Wrong controller action. — Right: Check direct/reverse with the valve fail position.
Applications
- Process plants: Thousands of flow, pressure, level and temperature PID loops.
- HVAC: Supply-air and chilled-water temperature loops.
- Drives: Cascaded speed/current PI in motor drives.
- Drones: Attitude PID at hundreds of Hz.
Key takeaways
- PI for most loops; D for lag-dominant ones.
- Z-N is aggressive; SIMC/lambda are robust.
- D on PV + filter, anti-windup, bumpless transfer.
- Sample at ≤ τ/10 and ≤ θ/4.
Going further
- Gain scheduling: Tuning changed with operating point for nonlinear processes.
- Robustness metrics: Maximum sensitivity M_s and gain/phase margins for tuning.
- Loop performance monitoring: Harris index, oscillation detection, valve stiction diagnosis.