Always free. For everyone.
Course outline
Module 08 of 20 · Classical control

Design practical PID control

Tune PI and PID with noise, saturation, and anti-windup in mind. This module has 3 lessons and takes about 2h 25m. Each lesson has a practice exercise that runs real Python in your browser and a short quiz.

Start module 08 in the Learning Lab
LESSON 1 OF 3

Tune proportional and integral terms

35 minControl engineering
WHAT YOU WILL DO

Choose PI gains from a simple model and desired poles.

For P=1/(tau*s+1) with PI C=Kp+Ki/s, the closed-loop denominator is tau*s^2+(1+Kp)*s+Ki. Match it to tau*(s^2+2*zeta*wn*s+wn^2): Kp=2*zeta*wn*tau-1 and Ki=tau*wn^2.

This pole matching gives a starting point, not a full performance guarantee. The PI zero changes the reference response, and actuator limits may make the chosen poles unrealistic. Simulate command effort as well as output.

Tune with a defined requirement and change one factor at a time. Increase speed only while noise, saturation, robustness, and sample timing remain acceptable. Record the plant model and the exact parallel PI convention.

See it in action

example.pyPython 3
tau, zeta, wn = 2., 0.8, 1.
kp = 2*zeta*wn*tau-1
ki = tau*wn**2
print('Kp:',kp,'Ki:',ki)
print('Denominator:',[tau,1+kp,ki])
Keep this in mind

A tuning formula is a starting design that still needs validation.

LESSON 2 OF 3

Filter the derivative and prevent windup

35 minControl engineering
WHAT YOU WILL DO

Implement useful PID details instead of an ideal derivative.

Derivative on error reacts sharply to a reference step. Derivative on measurement uses -Kd*dy/dt and avoids this reference kick. Both forms need filtering because differences amplify sensor noise.

A simple low-pass derivative update is d_f=alpha*d_old+(1-alpha)*(y-y_old)/dt with alpha=tau_f/(tau_f+dt). Use u_raw=Kp*e+I-Kd*d_f. This is a backward-Euler filter, so its exact behaviour depends on dt.

For command-valued integral state I, back-calculation uses dI/dt=Ki*e+Kaw*(u_sat-u_raw). The correction pulls the integral toward the command the actuator can actually apply. Conditional integration instead freezes accumulation that pushes farther into saturation.

See it in action

example.pyPython 3
dt, tau_f = 0.01, 0.05
y, y_old, d_old = 0.12, 0.10, 0.
alpha = tau_f/(tau_f+dt)
d_filtered = alpha*d_old+(1-alpha)*(y-y_old)/dt
raw = 2*0.5 + 0.3 - 0.1*d_filtered
applied = max(-1.,min(1.,raw))
print('Derivative:',d_filtered,'Raw:',raw,'Applied:',applied)
Keep this in mind

State the PID form, derivative filter, sample time, and anti-windup method.

LESSON 3 OF 3

Practical: compare saturation recovery

75 minControl engineering
WHAT YOU WILL DO

Show how anti-windup changes recovery after an unreachable target.

Use dy/dt=-y+u with 0<=u<=1. Request y=2 for the first five seconds, then y=0.5. The first target is unreachable because the maximum equilibrium output is one.

For Kp=2 and Ki=1, compare an ordinary integral with conditional integration. Freeze I when raw>1 and e>0, or raw<0 and e<0. Allow integration when error would move the command back inside the limits.

Record integral state, time spent saturated, and response after the target returns. Anti-windup cannot make an unreachable target reachable. Its purpose is to avoid excess stored error and improve recovery.

GUIDED PRACTICAL · 75 MIN

Your experiment plan

Use the browser editor or the downloadable notebook. All plant data are simulated. Keep a notebook with parameters, predictions, results, and units.

  1. Run both controllers with the same unreachable reference sequence.
  2. Plot output, raw command, applied command, and integral state.
  3. Measure recovery after five seconds using the same tolerance band.
  4. Repeat with a smaller actuator limit and explain which requirements become impossible.

What to hand in

  • A recovery comparison and saturation plot.
  • A working conditional integration function.
  • A distinction between feasibility and recovery quality.
Reflect on your results

Which assumption matters most? Describe one result that surprised you and one experiment that would test your explanation.

The automatic exercise checks the core code behaviour. Review observations and written deliverables yourself or with a mentor.

See it in action

example.pyPython 3
import numpy as np
import matplotlib.pyplot as plt
for anti in [False, True]:
    y, integral, history = 0., 0., []
    dt = 0.01
    for k in range(1500):
        r = 2. if k*dt<5 else 0.5
        e = r-y
        raw = 2*e+integral
        u = max(0.,min(1.,raw))
        blocked = (raw>1 and e>0) or (raw<0 and e<0)
        if not anti or not blocked:
            integral += dt*e
        y += dt*(-y+u)
        history.append(y)
    plt.plot(np.arange(1500)*dt,history,label=f'Anti-windup={anti}')
plt.xlabel('Time (s)'); plt.ylabel('Output'); plt.legend(); plt.show()
Keep this in mind

Treat saturation as part of the plant-controller system.

ABOUT THE LEARNING LAB

Free, open and run by a nonprofit.

This page is part of Control Engineering, a free course of 20 modules and 60 lessons in the engineering.fit( ) Learning Lab. The Learning Lab is built and run by engineering.fit( ), a nonprofit founded by Abdullateef Opeyemi Bakare that helps African engineering students gain research experience. You do not need an account or pay a fee to learn.

Course outline · Project lab · Visit engineering-fit.org