PID Control
The PID controller is used in over 90 % of industrial loops. Learn what P, I and D each do, tuning with Ziegler–Nichols and practical rules, anti-windup, derivative filtering and a digital implementation.
A PID controller computes its output from three terms of the error: Proportional (the present error), Integral (the accumulated past error) and Derivative (the predicted future error from its rate of change).
It is simple enough to implement in a few lines of firmware yet powerful enough to control temperatures, pressures, flows, motor speeds, drones and chemical reactors.
An analogy
Parking a car: P is steering harder the further you are from the spot, I is correcting a persistent drift (a sloping road), and D is easing off as you approach quickly so you don't overshoot.
What each term does
Each term addresses a different weakness.
- P: output proportional to error. More K_p → faster response, less (but not zero) steady error, more overshoot.
- I: integrates error; keeps pushing until error is exactly zero. Too much → slow oscillations.
- D: reacts to the error's rate of change, adding damping. Amplifies noise, so it is always filtered.
Tuning methods
Ziegler–Nichols closed-loop: raise P-only gain until sustained oscillation (K_u, period T_u), then apply the table. It gives fast but aggressive (≈ 25–50 % overshoot) tuning. Refinements (Tyreus–Luyben, SIMC/lambda tuning, auto-tuners using relay feedback) give more robust results. Manual tuning: set P for acceptable response, add I to remove offset, add D if overshoot needs damping.
Integral windup
When the actuator saturates (valve fully open, heater at 100 %), the integral keeps growing, causing large overshoot once the error reverses. Anti-windup stops integrating when saturated (clamping) or feeds back the saturation error (back-calculation).
Practical refinements
These are standard features of industrial PID implementations.
- Derivative on measurement (not error) avoids 'derivative kick' on setpoint changes.
- Setpoint weighting (b, c factors) separates setpoint response from disturbance rejection.
- First-order filter on D (N = 5–20).
- Bumpless transfer between manual and automatic modes.
- Sample time much shorter than the dominant time constant (≥ 10× faster).
Cascade and gain scheduling
Motor drives nest PI current, speed and position loops. Non-linear processes (pH, aircraft across speeds) use gain scheduling — different PID gains at different operating points. When PID isn't enough (multivariable coupling, constraints, long delays), model predictive control takes over.
Formulas
- Parallel form:
u(t) = K_p·e + K_i∫e dt + K_d·de/dt - Transfer function:
C(s) = K_p (1 + 1/(T_i s) + T_d s) - Ziegler–Nichols (PID):
K_p = 0.6K_u, T_i = T_u/2, T_d = T_u/8 - Discrete (Ts):
I += K_i·e·T_s; D = K_d·(e − e_prev)/T_s
Worked example: Ziegler–Nichols from a critical-gain test
Given: Plant K/(s(s + 1)(s + 5)) → K_u = 30; Oscillation ω = 2.236 rad/s → T_u = 2.81 s
Find: ZN PID gains.
- K_p = 0.6 × 30 = 18
- T_i = 2.81/2 = 1.405 s → K_i = 18/1.405 = 12.8
- T_d = 2.81/8 = 0.351 s → K_d = 18 × 0.351 = 6.32
Answer: K_p = 18, K_i = 12.8, K_d = 6.3
Worked example: One step of a digital PID
Given: K_p = 2, K_i = 0.5, K_d = 0.1, T_s = 0.1 s; e = 2.0 now, e_prev = 1.5, integral so far = 3.0
Find: Controller output.
- Integral = 3.0 + 2.0 × 0.1 = 3.2 → I-term = 0.5 × 3.2 = 1.6
- P-term = 2 × 2.0 = 4.0
- D-term = 0.1 × (2.0 − 1.5)/0.1 = 0.5
- u = 4.0 + 1.6 + 0.5 = 6.1
Answer: u = 6.1
Digital PID with anti-windup and filtered derivative (C)
typedef struct {
float kp, ki, kd; // gains
float ts; // sample time (s)
float tau; // derivative filter time constant (s)
float out_min, out_max;
float integ, d_state, prev_meas;
} pid_t;
float pid_update(pid_t *c, float setpoint, float meas) {
float e = setpoint - meas;
float p = c->kp * e;
/* derivative on measurement (no setpoint kick), low-pass filtered */
float alpha = c->tau / (c->tau + c->ts);
c->d_state = alpha * c->d_state - (1.0f - alpha) * c->kd * (meas - c->prev_meas) / c->ts;
c->prev_meas = meas;
float u = p + c->integ + c->ki * e * c->ts + c->d_state;
/* conditional integration (clamping anti-windup) */
if (u > c->out_max) u = c->out_max;
else if (u < c->out_min) u = c->out_min;
else c->integ += c->ki * e * c->ts;
return u;
}Call pid_update() at a fixed rate from a timer interrupt or RTOS task. The integrator only accumulates while the output is not saturated, and the derivative acts on the filtered measurement.
Common mistakes
- Wrong: Using unfiltered derivative on a noisy sensor. — Right: Filter the D term (or use derivative on a filtered measurement), or leave it out.
- Wrong: No anti-windup when the actuator saturates. — Right: Clamp or back-calculate the integrator whenever the output is at its limits.
Applications
- Process industry: Temperature, pressure, level and flow loops in refineries and food plants — thousands per site, mostly PI.
- Drones: Nested attitude-rate and angle PID loops stabilise quadcopters hundreds of times per second.
- Motor drives: PI current and speed loops inside every VFD and servo drive.
Key takeaways
- P reacts to the present, I to the past, D to the predicted future.
- ZN tuning: K_p = 0.6K_u, T_i = T_u/2, T_d = T_u/8 — then detune for robustness.
- Always add anti-windup and filter the derivative.
- Cascade and gain scheduling extend PID to demanding applications.
Going further
- Internal model control (IMC) tuning: IMC/lambda tuning derives PID gains from a process model and a single closed-loop time constant λ, trading speed against robustness transparently — the favourite in process industries.
- Two-degree-of-freedom PID: u = K_p(b·r − y) + K_i∫(r − y) + K_d(c·ṙ − ẏ) lets setpoint response be softened (b < 1, c = 0) without weakening disturbance rejection.
- Fractional-order PID: PI^λD^µ controllers use non-integer integration/differentiation orders for extra tuning freedom, implemented via approximations — an active research area.