PID Control
English translation
Execution setup
The Python option uses python-control. If the module is missing, run %pip install control==0.10.2 in a Colab or Jupyter code cell.
Learning objectives
Selecting a gain based only on response speed can leave the system vulnerable to overshoot or model changes. Compare different performance metrics.
Baseline P, PI, and PID comparison
Starting conditions
Motor parameters: ,,,,. P=(500,0,0), PI=(500,300,0), PID=(500,300,30).
Procedure
- Build three closed-loop models using negative unity feedback.
- Plot the unit-step responses over s in the same figure, and check the poles first.
- Record overshoot, settling time, and steady-state error for stable models.
Results to retain
- A table with 3 controller rows, response plots, and a brief comparison of their roles.
import numpy as np
import matplotlib.pyplot as plt
import control as ctl
s = ctl.tf('s')
G=.01/((.01*s+.1)*(.5*s+1)+.01**2)
configs={'P':(500,0,0),'PI':(500,300,0),'PID':(500,300,30)}
for name,(kp,ki,kd) in configs.items():
C=kp+ki/s+kd*s
T=ctl.feedback(C*G,1)
print(name,ctl.poles(T))
# TODO: Record responses and performance metrics.
Record results and self-check
Controller:
Kp:
Ki:
Kd:
Stability:
Overshoot [%]:
Settling Time [s]:
Steady-State Error:
Points to check
- Are the plant, input, and time axis the same, with only the controller changing?
- For unstable or unconverged cases, did you give a reason instead of reporting metrics?
Changing one term at a time
Starting conditions
Starting from the PID baseline (500,300,30), change only Kp to 250,500,750. Keep Ki and Kd fixed.
Procedure
- Use the PID result from Activity 1, , as the baseline, and change only to 250 and 750 in turn. Keep , , the plant, and the time axis unchanged.
- Plot both unit-step responses alongside the baseline curve in the same figure. Use the same
ctl.step_infosettings to calculate overshoot, settling time, and steady-state error, and record them in the same columns as Activity 1. - Choose one of the two additional settings. Use the table values to explain which metric you aim to improve over the baseline and which changes you are willing to accept.
Results to retain
- Response plots and a performance table for both settings. One sentence explaining your choice.
import numpy as np
import matplotlib.pyplot as plt
import control as ctl
s = ctl.tf('s')
G=.01/((.01*s+.1)*(.5*s+1)+.01**2)
for kp in [250,500,750]:
T=ctl.feedback((kp+300/s+30*s)*G,1)
print(kp,ctl.dcgain(T))
# TODO: Complete the time responses and comparison of the second gain.
Record results and self-check
Changed term:
Value:
Overshoot [%]:
Settling Time [s]:
Steady-State Error:
Points to check
- Did you change only one gain at a time?
- Did you support claims of faster response with specific metrics?
Input limits and integrator windup
Starting conditions
1st-order plant , reference 2→.5 (changes at 5 s), , dt=.01 s. Use , .
Procedure
- In the supplied PI simulation, plot the actual input alongside the input before limiting.
- Compare conditional integration enabled and disabled.
- Explain why the error persists after lowering the reference, relating it to the integrator state.
Results to retain
- Three plots of output, input, and integrator state, and a comparison table.
In the comparison table, IAE is from the reference-change time to the final recording time. Calculate input saturation duration by multiplying the number of samples where the limited is 0 or 1 over the entire record by dt.
Use the same interval and calculation method for both integration approaches.
import numpy as np
import matplotlib.pyplot as plt
def simulate(antiwindup):
t=np.arange(0,12,.01);y=0.;integral=0.;rows=[]
for now in t:
ref=2. if now<5 else .5;e=ref-y;raw=2*e+integral;u=np.clip(raw,0,1)
if not antiwindup or (0<raw<1) or (raw>=1 and e<0) or (raw<=0 and e>0):integral+=e*.01
y+=(-y+u)*.01;rows.append((ref,y,raw,u,integral))
return t,np.array(rows)
for flag in [False,True]:
time,trace=simulate(flag);plt.plot(time,trace[:,1],label=str(flag))
plt.xlabel('Time [s]');plt.ylabel('Output');plt.legend()
# TODO: Add the input, integrator state, and metrics after 5 s.
Record results and self-check
Integration handling:
IAE after the reference change:
Maximum integral value:
Input saturation duration [s]:
Points to check
- Did you distinguish input values before and after limiting?
- Did you compare only integration handling without also changing the PI gains?