Documentation |
This example uses systune to explore trade-offs between setpoint tracking and disturbance rejection when tuning PID controllers.
On this page… |
---|
When tuning 1-DOF PID controllers, it is often impossible to achieve good tracking and fast disturbance rejection at the same time. Assuming the control bandwidth is fixed, faster disturbance rejection requires more gain inside the bandwidth, which can only be achieved by increasing the slope at the crossover frequency. Because a larger slope means a smaller phase margin, this typically comes at the expense of more overshoot in the response to setpoint changes.
Figure 1: Trade-off in 1-DOF PID Tuning.
This example uses systune to explore this trade-off and find the right compromise for your application. See also pidtool for a more direct and interactive way to make such trade-off (Transient behavior slider).
Consider the PI loop of Figure 2 with a load disturbance at the plant input.
Figure 2: PI Control Loop.
For this example we use the plant model
The PI controller has two parameters to tune: the proportional and integral gains. The target control bandwidth is 1 rad/s.
Construct a tunable model T0 of the closed-loop transfer from r to y. Use an "analysis point" block to mark the location u where the disturbance enters.
G = zpk(-5,[-1 -2 -10],10); C = ltiblock.pid('C','pi'); LS = AnalysisPoint('u'); T0 = feedback(G*LS*C,1); T0.u = 'r'; T0.y = 'y';
The gain of the open-loop response is a key indicator of the feedback loop behavior. The open-loop gain should be high (greater than one) inside the control bandwidth to ensure good disturbance rejection, and should be low (less than one) outside the control bandwidth to be insensitive to measurement noise and unmodeled plant dynamics. Accordingly, use three requirements to express the control objectives:
"Tracking" requirement to specify a response time of about 2 seconds to step changes in r.
"MinLoopGain" requirement to keep the loop gain high before 0.5 rad/s
"MaxLoopGain" requirement to limit the control bandwidth and force a roll-off of -20 dB/decade past 4 rad/s
s = tf('s'); wc = 1; % target crossover frequency % Tracking R1 = TuningGoal.Tracking('r','y',2); % Disturbance rejection R2 = TuningGoal.MinLoopGain('u',wc/s); R2.Focus = [0 0.5]; % Bandwidth and roll-off R3 = TuningGoal.MaxLoopGain('u',4/s);
Using systune, you can now tune the PI gains to meet these requirements. Treat the bandwidth and disturbance rejection goals as hard constraints and optimize tracking subject to these constraints.
T1 = systune(T0,R1,[R2 R3]);
Final: Soft = 1.24, Hard = 0.99993, Iterations = 139
Verify that all three requirements are nearly met. The blue curves are the achieved values and the yellow patches highlight regions where the requirements are violated.
figure('Position',[100,100,560,580])
viewSpec([R1 R2 R3],T1)
Tracking vs. Rejection Trade-Off
To gain insight into this trade-off, increase the required loop gain by a factor inside the frequency band [0,0.5] rad/s. Re-tune the PI gains for the values .
% Increase loop gain by factor 2
alpha = 2;
R2.MinGain = alpha*wc/s;
T2 = systune(T0,R1,[R2 R3]);
Final: Soft = 1.32, Hard = 0.99969, Iterations = 120
% Increase loop gain by factor 5
alpha = 5;
R2.MinGain = alpha*wc/s;
T3 = systune(T0,R1,[R2 R3]);
Final: Soft = 1.52, Hard = 0.99993, Iterations = 147
Now compare the responses to a step command r and to a step disturbance d entering at the plant input u.
figure, step(T1,T2,T3,10) title('Setpoint tracking') legend('\alpha = 1','\alpha = 2','\alpha = 5')
% Compute closed-loop transfer from u to y D1 = getIOTransfer(T1,'u','y'); D2 = getIOTransfer(T2,'u','y'); D3 = getIOTransfer(T3,'u','y'); step(D1,D2,D3,10) title('Disturbance rejection') legend('\alpha = 1','\alpha = 2','\alpha = 5')
Note how disturbance rejection improves as alpha increases, but only at the expense of increased overshoot and oscillations in setpoint tracking. Plot the open-loop responses for the three designs, and note how the slope at crossover (0dB) increases with alpha.
L1 = getLoopTransfer(T1,'u'); L2 = getLoopTransfer(T2,'u'); L3 = getLoopTransfer(T3,'u'); bodemag(L1,L2,L3,{1e-2,1e2}), grid title('Open-loop response') legend('\alpha = 1','\alpha = 2','\alpha = 5')
Which design is most suitable depends on the primary purpose of the feedback loop you are tuning.
If you cannot compromise tracking to improve disturbance rejection, consider using a 2-DOF architecture instead. A 2-DOF PI controller is capable of fast disturbance rejection without significant increase of overshoot in setpoint tracking.
Figure 3: 2-DOF PI Control Loop.
Use the ltiblock.pid2 object to parameterize the 2-DOF PI controller and construct a tunable model T0 of the closed-loop system in Figure 3.
C = ltiblock.pid2('C','pi'); T0 = feedback(G*LS*C,1,2,1,+1); T0 = T0(:,1); T0.u = 'r'; T0.y = 'y';
Next tune the 2-DOF PI controller for the largest loop gain tried earlier ( ).
% Minimum loop gain inside bandwidth (for disturbance rejection) alpha = 5; R2.MinGain = alpha*wc/s; % Tune 2-DOF PI controller T4 = systune(T0,R1,[R2 R3]);
Final: Soft = 1.31, Hard = 0.99996, Iterations = 123
Compare the setpoint tracking and disturbance rejection properties of the 1-DOF and 2-DOF designs for .
clf, step(T3,'b',T4,'g--',10) title('Setpoint tracking') legend('1-DOF','2-DOF')
D4 = getIOTransfer(T4,'u','y'); step(D3,'b',D4,'g--',10) title('Disturbance rejection') legend('1-DOF','2-DOF')
The responses to a step disturbance are identical but the 2-DOF controller eliminates the overshoot in the response to a setpoint change. Compare the tuned 1-DOF and 2-DOF PI controllers and observe how the proportional and integral gains are nearly the same, the main difference coming from the setpoint weight b.
showTunable(T3) % 1-DOF PI
C = 1 Kp + Ki * --- s with Kp = 1.94, Ki = 2.13 Name: C Continuous-time PI controller in parallel form.
showTunable(T4) % 2-DOF PI
C = 1 s u = Kp (b*r-y) + Ki --- (r-y) + Kd -------- (c*r-y) s Tf*s+1 with Kp = 1.943, Ki = 2.1264, Kd = 0, Tf = 1, b = 0.32476, c = 1. Continuous-time 2-DOF PID controller.