This repository provides a tutorial-oriented simulation of a digital PI control loop applied to a first-order system identified via non-parametric methods.
The simulation includes actuator saturation and an anti-windup algorithm using conditional integration, allowing the user to visualize the same discrete behavior expected on a microcontroller (Arduino, Teensy, ESP32, etc.).
⚠️ Note: This tutorial is for educational purposes only, focusing on understanding discrete-time digital control, actuator limits, and anti-windup strategies.
- Model a first-order process identified experimentally (non-parametric fit)
- Discretize the plant using Zero-Order Hold (ZOH)
- Implement a discrete PI controller in positional form
- Include saturation limits to emulate real actuator constraints
- Add anti-windup via conditional integration
- Observe reference tracking and control signal behavior
A first-order model without delay was identified experimentally from step-response data:
Example parameters used in this tutorial:
Discretized with Zero-Order Hold.
Discrete-time implementation:
y(k) = num(2)*u1 - den(2)*y1;When implementing a PI in incremental form, the integral action appears only as a difference between errors and is not accumulated explicitly. The control law is:
This form does not integrate the error in an accumulating memory, but instead adjusts the control from the last value.
Because the controller does not store the integral sum, once saturation is applied:
- The incremental update is naturally “cut off”
- No further accumulation occurs beyond limits
- There is no wind-up phenomenon to correct
Therefore, in incremental PI controllers, explicit anti-windup logic is not required — saturation alone is sufficient.
In contrast, the positional PI form computes:
Where the term
does accumulate over time. If the actuator saturates, the integral would continue growing and later produce large overshoot when saturation exits — this is the classical integrator wind-up.
To prevent it, conditional integration is used:
- Integrate only when the control is not saturated, or
- When the error would help the controller exit saturation
if (u>=100 && e>0) || (u<=0 && e<0)
I = I; % Freeze integrator
else
I = I + Ts*e;
end
u = Kp*e + Kp/Ti*I;To emulate real actuator limits in microcontrollers, the control output is constrained:
This ensures that the controller output never exceeds the physical limits of the actuator (e.g., PWM 0–100%).
In MATLAB/Simulink:
if u > 100
u=100;
end
if u< 0
u=0;
endBelow are example plots generated with the script:
![]() Response Without saturation |
![]() Response saturation With antiwindup |
Response saturation Without antiwindup:
MIT License


