Transfer Function Control
Housekeeping
close all; clear; clc; s = tf('s');
The first step in our analysis is to create a sample system based on chosen poles & zeros to explore the effect of adding lead & lag controllers.
Below we define a simple system using poles, zeros, and plot it's open-loop and closed-loop zeros along with it's step response.
gain = 4;
plant = gain;
for z = []
plant = plant*(s-z);
end
for p = [0, -4]
plant = plant/(s-p);
end
Plant = tf(plant);
Controller = 1;
System = feedback(Controller*plant,1);
Now le's begin our analysis!
t_start = 0;
t_stop = 5;
t_step = 0.01;
t = t_start:t_step:t_stop;
u = ones(size(t));
%u = t;
%u = sin(t);
OLpoles = pole(Plant);
OLzeros = zero(Plant);
CLpoles = pole(System);
CLzeros = zero(System);
yOL = lsim(Controller*Plant, u, t);
yCL = lsim(System, u, t);
f1 = figure();
f1.Position = [0 0 1300 500];
subplot(1,2,1); title('Pole Zero Map');
scatter(real(OLzeros), imag(OLzeros), 150, 'Marker', 'o', 'MarkerEdgeColor','r','LineWidth', 3); hold on;
scatter(real(OLpoles), imag(OLpoles), 150, 'Marker', 'x', 'MarkerEdgeColor','r','LineWidth', 3); hold on;
scatter(real(CLzeros), imag(CLzeros), 150, 'Marker', 'o', 'MarkerEdgeColor','k','LineWidth', 3); hold on;
scatter(real(CLpoles), imag(CLpoles), 150, 'Marker', 'x', 'MarkerEdgeColor','k','LineWidth', 3); hold off;
xline(0); yline(0); hold off;
xlim([-6, 2]);
ylim([-5, 5]);
xlabel('real');
ylabel('imag');
legend('OL zeros','OL poles','CL zeros','CL poles', 'FontSize', 12, 'Location', 'northwest')
subplot(1,2,2); title('System Response');
plot(t, u, 'LineStyle', '--'); hold on;
plot(t, yOL); hold on;
plot(t, yCL); hold off;
legend('input','open-loop response','closed-loop response', 'FontSize', 12, 'Location', 'northwest');
Suppose now that we wish the output had a faster response time than simple feedback can provide, and we are not satisfied with using purely proportional control.
Suppose again, that we have actual design requirements of say...
Damping Ratio = 0.707
Settling Time = 0.667s
Using our formulas for 2nd order systems, we can deduce:
Knowing that this gives us our desired pole locations of:
Let us plot the Root Locus of our system and confirm there is no way to achieve this with proportional control.
zeta = 0.707;
settling_time_2_perc = 0.667;
zeta_x_natfreq = 4/settling_time_2_perc;
natfreq = zeta_x_natfreq/zeta;
%make sure the pole with positive imaginary part is first!
%arrays for plotting desired poles
x = []; y = [];
desired_poles = [-1*zeta_x_natfreq + natfreq*(zeta*zeta-1)^0.5, -1*zeta_x_natfreq - natfreq*(zeta*zeta-1)^0.5]; % desired poles
for p = [-1*zeta_x_natfreq + natfreq*(zeta*zeta-1)^0.5, -1*zeta_x_natfreq - natfreq*(zeta*zeta-1)^0.5] % desired poles
x = [x real(p)];
y = [y imag(p)];
end
f2 = figure();
f2.Position = [0 0 800 500];
title('Pole Zero Map');
scatter(x, y, 150, 'Marker', 'x', 'MarkerEdgeColor','k','LineWidth', 3); hold on;
rlocus(Plant); hold on;
%xline(0); yline(0); hold off;
xlim([-22, 2]);
ylim([-7.5, 7.5]);
legend('Desired Poles')
As we can observe from the Root Locus, there is no way for us to achieve our desired poles using only proportional control due to our poles not lying on the Root Locus plot. This is a limitation of both SISO proportional control as well as MIMO proportional control schemes like LQR; they can scale the response, but without introducing any poles or zeros can't fundamentally alter the response.
What we need is a controller whose output response faster than its input. What we need is a LAG CONTROLLER!
The first step is to choose a location for our zero, and apply the angle criterion to find the required pole.
One rule of thumb is to introduce a zero with the same real part as our poles, i.e.
Recall that radians
Knowing that we have a pole with an unknown angle this can be written as:
radians or
The second step is to use the magnitude criterion to find our required gain. Recall that
lead_controller_zero = real(desired_poles(1));
% APPLYING THE ANGLE CRITERION
zero_angle = 0;
pole_angle = 0;
plantzeros = zero(Plant);
plantpoles = pole(Plant);
for i = 1:size(zero(Plant),1)
zero_angle = zero_angle + atan2(imag(desired_poles(1) - plantzeros(i)), real(desired_poles(1) - plantzeros(i)));
end
for i = 1:size(pole(Plant),1)
pole_angle = pole_angle + atan2(imag(desired_poles(1) - plantpoles(i)), real(desired_poles(1) - plantpoles(i)));
end
for i = 1:size(lead_controller_zero,1)
zero_angle = zero_angle + zero_angle + atan2(imag(desired_poles(1) - lead_controller_zero(i)), real(desired_poles(1) - lead_controller_zero(i)));
end
phi = pi + zero_angle - pole_angle;
lead_controller_pole = lead_controller_zero(1) + lead_controller_zero(1)/tan(phi);
% APPLYING THE MAGNITUDE CRITERION
zero_mag = 1;
pole_mag = 1;
% Looping over all the zeros & poles in both the plant and controller
for i = 1:size(zero(Plant),1)
diff = (desired_poles(1) - plantzeros(i));
zero_mag = zero_mag + sqrt(real(diff)*real(diff) + imag(diff)*imag(diff));
end
for i = 1:size(pole(Plant),1)
diff = (desired_poles(1) - plantpoles(i));
pole_mag = pole_mag * sqrt(real(diff)^2 + imag(diff)^2);
end
for i = lead_controller_zero
diff = (desired_poles(1) - i);
zero_mag = zero_mag * sqrt(real(diff)^2 + imag(diff)^2);
end
for i = lead_controller_pole
diff = (desired_poles(1) - i);
pole_mag = pole_mag * sqrt(real(diff)^2 + imag(diff)^2);
end
lead_controller_gain = pole_mag/(gain(1)*zero_mag);
Now that we have our controller parameters, let us construct our new feedback system!
Plant = tf(plant);
LeadController = lead_controller_gain * (s-lead_controller_zero)/(s-lead_controller_pole);
LeadSystem = feedback(LeadController*Plant,1);
With this new system, let us confirm that the root locus passes through our desired poles. The effect of the lead controller should be that the root-locus is pulled to the left, increasing response speed.
f3 = figure();
f3.Position = [0 0 800 500];
title('Pole Zero Map');
scatter(x, y, 150, 'Marker', 'x', 'MarkerEdgeColor','k','LineWidth', 3); hold on;
rlocus(LeadController*Plant); hold on;
%xline(0); yline(0); hold off;
xlim([-22, 2]);
ylim([-7.5, 7.5]);
legend('Desired Poles')
Assuming our poles are now located on our root-locus, the calculated gain should be the correct value to shift our system poles to the desired location. With our achieved pole locations, let us examine the performance of our controller compared to the open-loop system and unity-feedback.
t_start = 0;
t_stop = 5;
t_step = 0.01;
t = t_start:t_step:t_stop;
u = ones(size(t));
%u = t;
%u = sin(t);
yOL = lsim(Plant, u, t);
yCL = lsim(System, u, t);
yLEAD = lsim(LeadSystem, u, t);
f4 = figure();
f4.Position = [0 0 800 500];
plot(t, u, 'LineStyle', '--'); hold on;
plot(t, yOL); hold on;
plot(t, yCL); hold on;
plot(t, yLEAD); hold off;
ylim([0,2]);
title('Step Respone of Open & Closed Loop Systems')
xlabel('time');
ylabel('response');
legend('input','open-loop response','closed-loop response', 'lead-controlled response', 'FontSize', 12, 'Location', 'northwest');
Our system seems to work very well with a step input, but let us see how it looks with ramp and sinusoidal inputs!
t_start = 0;
t_stop = 5;
t_step = 0.01;
t = t_start:t_step:t_stop;
u1 = ones(size(t));
u2 = t;
u3 = sin(t);
y1LEAD = lsim(LeadSystem, u1, t);
y2LEAD = lsim(LeadSystem, u2, t);
y3LEAD = lsim(LeadSystem, u3, t);
f5 = figure();
f5.Position = [0 0 800 500];
plot(t, u1, 'LineStyle', '--'); hold on;
plot(t, u2, 'LineStyle', '--'); hold on;
plot(t, u3, 'LineStyle', '--'); hold on;
plot(t, y1LEAD); hold on;
plot(t, y2LEAD); hold on;
plot(t, y3LEAD); hold off;
ylim([-1, 3]);
title('Ramp / Sine Respone of Lead Controlled Systems')
xlabel('time');
ylabel('response');
legend('step input','ramp input', 'sine input', 'step response', 'ramp response', 'sine response', 'FontSize', 12, 'Location', 'northwest');
From the above plot we can see that our system performs very well at steady-state for a step input, but does lag with time-varying inputs like ramps and sinusoids. IFor the remp input there is a small steady-state error that persists, but examining the sinusoidal input we can see that we have a consistent phase-lead (imagine that!) compared to the input. What we need now is to introduce a lag controller!
Ideally our controller should be have just enough of an effect to reduce steady-state error, but should modify the location of the desired poles as little as possible.
A good rule of thumb is to introduce a pole-zero pair both close to the origin and close to each other. Let us try placing the pole at approximately 10% the magnitude of our desired poles.
Let's try: and
lag_controller_gain = 1;
lag_controller_zero = 0.1*lead_controller_zero;
lag_controller_pole = 1.1*lag_controller_zero;
LagController = lag_controller_gain * (s-lag_controller_zero)/(s-lag_controller_pole);
LeadLagController = LeadController*LagController;
LeadLagSystem = feedback(LeadLagController*Plant,1);
With our newly minted Lag and combination LeadLag Controllers, let us verify that the Root Locus has not been altered to any significant degree.
f6 = figure();
f6.Position = [0 0 1300 500];
subplot(1,2,1); title('Lead Controller Only');
rlocus(LeadController*Plant); hold on;
scatter(x, y, 150, 'Marker', 'x', 'MarkerEdgeColor','k','LineWidth', 3); hold off;
xlim([-22, 2]);
ylim([-7.5, 7.5]);
subplot(1,2,2); title('Lead+Lag Controller');
rlocus(LeadLagController*Plant); hold on;
scatter(x, y, 150, 'Marker', 'x', 'MarkerEdgeColor','k','LineWidth', 3); hold off;
xlim([-22, 2]);
ylim([-7.5, 7.5]);
Looking at our Root Locus we can see the new pole-zero pair near the origin, but the root locus of our system has not been altered in any major way so we can expect our system response (at least to a step input) to remain exactly the same.
Let us check again our new system's performance to our three inputs.
t_start = 0;
t_stop = 5;
t_step = 0.01;
t = t_start:t_step:t_stop;
u1 = ones(size(t));
u2 = t;
u3 = sin(t);
y1LEAD = lsim(LeadLagSystem, u1, t);
y2LEAD = lsim(LeadLagSystem, u2, t);
y3LEAD = lsim(LeadLagSystem, u3, t);
f5 = figure();
f5.Position = [0 0 800 500];
plot(t, u1, 'LineStyle', '--'); hold on;
plot(t, u2, 'LineStyle', '--'); hold on;
plot(t, u3, 'LineStyle', '--'); hold on;
plot(t, y1LEAD); hold on;
plot(t, y2LEAD); hold on;
plot(t, y3LEAD); hold off;
ylim([-1, 3]);
title('Ramp / Sine Respone of Lead+Lag Controlled Systems')
xlabel('time');
ylabel('response');
legend('step input','ramp input', 'sine input', 'step response', 'ramp response', 'sine response', 'FontSize', 12, 'Location', 'northwest');
Unfortunately, one of the limitations of poles as fast as we have used is that the system requires a long time to remove steady state error and may not always be useful on it's own.
However, if low steady state error in response to transient inputs is important, it is possible to increase the proportional gain of the system (we can add gain to the lag controller) by accepting a greater overshoot for a step input.
Let's give it a try!
lag_controller_gain = 5; % updated gain here
lag_controller_zero = 0.1*lead_controller_zero;
lag_controller_pole = 1.1*lag_controller_zero;
LagController = lag_controller_gain * (s-lag_controller_zero)/(s-lag_controller_pole);
LeadLagController = LeadController*LagController;
LeadLagSystem = feedback(LeadLagController*Plant,1);
Now let's make sure our Root Locus hasn't deviated too much.
f6 = figure();
f6.Position = [0 0 1300 500];
subplot(1,2,1); title('Lead Controller Only');
rlocus(LeadController*Plant); hold on;
scatter(x, y, 150, 'Marker', 'x', 'MarkerEdgeColor','k','LineWidth', 3); hold off;
xlim([-22, 2]);
ylim([-7.5, 7.5]);
subplot(1,2,2); title('Lead+Lag Controller');
rlocus(LeadLagController*Plant); hold on;
scatter(x, y, 150, 'Marker', 'x', 'MarkerEdgeColor','k','LineWidth', 3); hold off;
xlim([-22, 2]);
ylim([-7.5, 7.5]);
And finally to re-check our system response[s].
t_start = 0;
t_stop = 5;
t_step = 0.01;
t = t_start:t_step:t_stop;
u1 = ones(size(t));
u2 = t;
u3 = sin(t);
y1LEAD = lsim(LeadLagSystem, u1, t);
y2LEAD = lsim(LeadLagSystem, u2, t);
y3LEAD = lsim(LeadLagSystem, u3, t);
f5 = figure();
f5.Position = [0 0 800 500];
plot(t, u1, 'LineStyle', '--'); hold on;
plot(t, u2, 'LineStyle', '--'); hold on;
plot(t, u3, 'LineStyle', '--'); hold on;
plot(t, y1LEAD); hold on;
plot(t, y2LEAD); hold on;
plot(t, y3LEAD); hold off;
ylim([-1, 3]);
title('Ramp / Sine Respone of Lead+Lag Controlled Systems')
xlabel('time');
ylabel('response');
legend('step input','ramp input', 'sine input', 'step response', 'ramp response', 'sine response', 'FontSize', 12, 'Location', 'northwest');