Active Disturbance Rejection Control addresses a fundamental tension in feedback design: high-performance control normally requires an accurate plant model, yet accurate models are expensive to identify and degrade with temperature, load, and wear. ADRC resolves this by treating everything beyond a known input gain — unmodeled dynamics, parameter variation, and external disturbances — as a single lumped signal called the total disturbance. An Extended State Observer (ESO) estimates this signal in real time, and the control law subtracts the estimate before issuing the command. What remains behaves like a clean chain of integrators that a simple PD law can regulate with textbook bandwidth.
The practical payoff on embedded hardware is significant: you need only one plant number (
An
where
Augmenting the
with the convention
The forward-Euler discretization used here is:
with
All observer poles are placed at
All control poles are placed at
For a second-order plant (
After disturbance estimation the control is:
Substituting into the plant equation and using
| Case | Time | Space | Notes |
|---|---|---|---|
| Best | Linear sweep over |
||
| Average | Same; gains precomputed at construction | ||
| Worst | No branching in the hot path |
Gains are computed once at construction from closed-form binomial formulas in Compute hot path is a pair of
Second-order plant (
Observer gains:
Control gains:
At sample
- Output error:
$e = y[k] - \hat{y}$ . - Inject correction into all three states:
$\hat{x}_i \mathrel{+}= T_s \beta_i e$ . - Chain integration:
$\hat{y} \mathrel{+}= T_s \hat{\dot{y}}$ ; then$\hat{\dot{y}} \mathrel{+}= T_s b_0 u_\text{applied}[k-1]$ , where$u_\text{applied}$ is the value actually delivered by the actuator. When the actuator does not saturate this equals the commanded$u[k-1]$ ; when it does, pass the clipped value via the three-argumentCompute(reference, measuredOutput, actualApplied)overload. - PD law on integrator chain:
$u_0 = k_p(r - \hat{y}) - k_d \hat{\dot{y}}$ . - Disturbance cancellation:
$u = (u_0 - \hat{f}) / b_0$ .
After a transient of roughly
Actuator saturation (anti-windup). When the downstream actuator clips the commanded value, the ESO integrates the wrong input and its disturbance estimate drifts, causing significant overshoot. Close the anti-windup loop by feeding the actually-applied signal back: u_applied = clamp(Compute(r, y, u_applied_prev), lo, hi), then pass u_applied as the third argument on the next call. The two-argument Compute(reference, measuredOutput) is a convenience overload that assumes no saturation (commanded = applied) and is equivalent to passing the last commanded value.
ESO peaking. Large initial estimation errors drive high-magnitude corrections, temporarily saturating the actuator. Mitigation: initialize the observer near the first measurement, or schedule
Observer bandwidth vs. noise. Increasing
Euler discretization stability and accuracy. The forward-Euler ESO is unconditionally unstable once
Integer overflow in gain computation. Binomial coefficients are computed with integer arithmetic at compile time. For large orders or very high bandwidths the intermediate product may exceed std::size_t before the division; keep
Nonlinear ESO (NESO). Replace the linear correction
Discrete ESO. Exact discretization of the observer (ZOH or pole-matched) improves accuracy when
Higher-order plants. The template parameter Order generalizes the same bandwidth-parameterized structure to Compute loop extends automatically.
Multi-input / multi-output (MIMO). Each output channel runs an independent ADRC; cross-coupling is absorbed into the respective disturbance estimates.
- Electric motor drives (rejects friction, load torque, and back-EMF variation with a single
$b_0$ estimate). - Attitude and position control of UAVs and satellites (absorbs aerodynamic and thruster uncertainty).
- Industrial process control where the plant model is poorly known or time-varying.
- Hard-disk drive servo (high-bandwidth disturbance rejection without a detailed head-media model).
- Luenberger Observer — the ESO is a Luenberger observer augmented with one extra disturbance state.
- Disturbance Observer (DOB) — the transfer-function sibling; DOB works in the frequency domain while ESO works in the state-space domain.
- PID — ADRC generalizes PID: a first-order ADRC with proportional-plus-integral action recovers a PI with disturbance feed-forward.
- LQR / LQI — state-feedback alternatives that require a full model; ADRC trades optimality for model-independence.
- J. Han, "From PID to Active Disturbance Rejection Control," IEEE Transactions on Industrial Electronics, vol. 56, no. 3, pp. 900–906, 2009.
- Z. Gao, "Scaling and Bandwidth-Parameterization Based Controller Tuning," Proceedings of the American Control Conference, 2003, pp. 4989–4996.
- R. Miklosovic, A. Radke, Z. Gao, "Discrete implementation and generalization of the extended state observer," ACC, 2006.