Basic Implementation

We can implement a simple PI controller as follows:

float error = target_rtd - rRTD;
float u = Kp * error + integral;
integral += Ki * (error + error_prev)/2 * Ts; // global variable

However, real-world physical systems have limitations that must be addressed:

1. Actuator Saturation Limits

In physical systems, actuators have operational limits. For our application, the control input must remain between 0 and 1, corresponding to 0% and 100% of the MOSFET duty cycle.

if (u < 0)u = 0;
else if (u > 1) u = 1; 

2. Anti-Integral Windup

When the control input $u$ is clipped by saturation, the error accumulates in the integral term, resulting in massive overshoot. To address this, we separate the control input into two terms: P and I

  float error = target_rtd - rRTD;
  float u_P =Kp * error; // Proportional part
  integral += Ki * (error +error_prev)/2 * Ts;
  float u_I = integral; //integral part
  error_prev = error;

Then we implement anti-windup measures using saturation logic. This code handles two cases:

  1. Upper saturation: If the proportional term ($u_P$) alone exceeds 1.0, we clip it to 1.0 and reset the integral term ($u_I$) to prevent windup. If the combined control signal ($u_P + u_I$) exceeds 1.0, we limit the integral term so their sum equals exactly 1.0.
  2. Lower saturation: Similarly, if $u_P$ is less than 0.0, we clip it to 0.0 and reset $u_I$. If their combined value is negative, we adjust u_I to cancel out $u_P$, effectively making the control signal 0.0.

This approach prevents integral windup while maintaining the maximum possible control authority within the actuator's physical limits.

// Upper saturation
if ((u_P + u_I) > 1.0f) {
  u_I = 1.0f - u_P;
  integral = u_I
}

// Lower saturation
if ((u_P + u_I) < 0.0f) {
  u_I = -u_P;
  integral = u_I
}

Result

PI_resp.png

From the real result, you can see the control input saturates during the first 8 seconds, then decreases to equilibrium.

The resistance reaches the desired value within 30 seconds. Even though the model doesn't exactly match, the system remains stable and shows no oscillatory behavior, as it was designed.