Plots & Analysis
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 examine the effects of the Root Locus Plot.
Below we choose our plant's poles, zeros, and gain before building our closed-loop system based on a unity-gain controller & feedback.
gain = 1;
plant = gain;
for z = [-1+0j]
plant = plant*(s-z);
end
for p = [-2+4j, -2-4j]
plant = plant/(s-p);
end
Plant = tf(plant);
Controller = 1;
System = feedback(Controller*plant,1);
Black's Formula:
Recall that according to Black's Formula, the simplified form of a feedback control loop takes the form of:
Ouput
Input
System TF
Open-Loop TF
Feedback TF
Controller TF
Plant TF
Assuming a unity feedback plant, a simple proportional controller with gain K, and a plant given by:
This formula simplifies to:
From this we can observe that the open-loop poles and closed-loop poles are one and the same. The closed-loop poles however are influenced by both the open-loop pole locations as well as the open-loop (or closed-loop) zero positions
OLpoles = pole(Plant);
OLzeros = zero(Plant);
CLpoles = pole(System);
CLzeros = zero(System);
f = figure(); f.Position = [0 0 800 500];
scatter(real(OLzeros), imag(OLzeros), 100, 'Marker', 'o', 'MarkerEdgeColor','b'); hold on;
scatter(real(OLpoles), imag(OLpoles), 100, 'Marker', 'x', 'MarkerEdgeColor','r'); hold on;
scatter(real(CLzeros), imag(CLzeros), 100, 'Marker', 'o', 'MarkerEdgeColor','b'); hold on;
scatter(real(CLpoles), imag(CLpoles), 100, 'Marker', 'x', 'MarkerEdgeColor','r'); hold on;
area([-100 0],[+100 +100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([-100 0],[-100 -100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([0 +100],[+100 +100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
area([0 +100],[-100 -100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
xline(0,'DisplayName','x-axis'); yline(0,'DisplayName','y-axis'); hold off;
xlim([-12 4]); xlabel('real');
ylim([-5 5]); ylabel('imag');
legend('OL zeros','OL poles','CL zeros','CL poles', 'FontSize', 12, 'Location', 'northwest')
As we can see, the simple application of unity feedback is to shift our poles to the left, increasing the rate at which the response will decay, and increasing stability. We can see this directly by simulating a step response. However, this on its own may not not solve the problem of steady state error.
t_start = 0;
t_stop = 5;
t_step = 0.01;
t = t_start:t_step:t_stop;
[yOL, tOL] = step(Controller*Plant, t);
[yCL, tCL] = step(System, t);
f = figure();
f.Position = [0 0 800 500];
plot(t, yOL,'DisplayName','Open Loop'); hold on;
plot(t, yCL,'DisplayName','Closed Loop'); hold off;
xlabel('time(s)'); ylabel('response');
legend('FontSize', 12, 'Location', 'northeast')
To determine an analytic equation for our poles, we set and solve for s.
For example, based on a "one zero, two poles" system this simplifies to:
Using the quadratic formula, this simplifies to:
The natural next step then is to compare the effect of feedback for varying gains K and observe the effect on our poles. Here we choose our minimum gain, maximum gain, and step size before plotting the poles and zeros from each feedback control system.
minGain = 0.1;
maxGain = 10;
stepGain = 0.1;
gains = minGain:stepGain:maxGain;
RLzeros = CLzeros;
RLpoles = CLpoles;
for k=minGain:stepGain:maxGain
Controller = k;
System = feedback(Controller*Plant,1);
RLzeros = [RLzeros; zero(System)];
RLpoles = [RLpoles; pole(System)];
end
f = figure();
f.Position = [0 0 800 500];
scatter(real(CLzeros), imag(CLzeros), 150, 'Marker', 'o', 'MarkerEdgeColor','k'); hold on;
scatter(real(CLpoles), imag(CLpoles), 150, 'Marker', 'x', 'MarkerEdgeColor','k'); hold on;
scatter(real(RLzeros), imag(RLzeros), 50, 'Marker', 'o', 'MarkerEdgeColor','b'); hold on;
scatter(real(RLpoles), imag(RLpoles), 50, 'Marker', 'x', 'MarkerEdgeColor','b'); hold on;
area([-100 0],[+100 +100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([-100 0],[-100 -100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([0 +100],[+100 +100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
area([0 +100],[-100 -100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
xline(0,'DisplayName','x-axis'); yline(0,'DisplayName','y-axis'); hold off;
xlim([-12 4]); xlabel('real');
ylim([-5 5]); ylabel('imag');
legend('CL zeros','CL poles','RL zeros','RL poles', 'FontSize', 12, 'Location', 'northwest')
Let's see how this compares to the built-in Root Locus plot!
f = figure();
f.Position = [0 0 800 500];
rlocus(Plant); hold on;
xlim([-12 4]); xlabel('real');
ylim([-5 5]); ylabel('imag');
% ADDING THIS FOR A LITTLE FLAIR
area([-100 0],[+100 +100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([-100 0],[-100 -100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([0 +100],[+100 +100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
area([0 +100],[-100 -100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
xline(0,'DisplayName','x-axis'); yline(0,'DisplayName','y-axis'); hold off;
From our analysis, we can observe that the root-locus plot is nothing more than the combined pole-zero maps of many feedback control systems with varying proportional gain!
In fact, the primary use for the root-locus plot is in "loop-shaping" wherein we choose the zeros, poles, and gain of our controller to produce poles that occupy a specific location in the s-plane to generate a desired settling time, damping ratio, etc. Indeed if we enable the damping lines on the root locus plot, we can see lines of constant damping and constant stability.
f = figure();
f.Position = [0 0 800 500];
P = pzoptions;
P.Grid = 'off';
rlocus(Plant, P); hold on;
xlim([-12 4]); xlabel('real');
ylim([-5 5]); ylabel('imag');
% ADDING THIS FOR A LITTLE FLAIR
area([-100 0],[+100 +100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([-100 0],[-100 -100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([0 +100],[+100 +100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
area([0 +100],[-100 -100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
xline(0,'DisplayName','x-axis'); yline(0,'DisplayName','y-axis'); hold off;
There are two requirements for a point to be present on the root locus: the angle-criterion and the magnitude-criterion
Let us again return to the results of Black's Formula:
We do not need to trouble ourselves with zeros as they are the same as the open-loop zeros, but to solve for poles, we can utilize the middle step and set
To interrogate the root locus due to the the complex nature of the poles, we consider magnitude and angle separately. Generally, the angle condition is used to determine if a point on the s-plane exists on the root locus, and the magnitude condition is used to determine the value of K required to place the transfer function at that precise point. Alternatively, if a specific point is required to be on the root-locus, a point can be chosen, and a pole can be calculated to force the root locus to pass through that point!
(note: when using a controller like a lead/lag, the zero is not an unknown due to the open & closed loop zeros being identical!)
ANGLE CONDITION:
Looking at the complex plane, we can see that the angle from the positive real axis to −1 is or π radians
Thus the angle condition can be written as: radians
Because complex poles are "two sides of the same coin", we need only consider points at or above the positive real axis. Because this limits our angles to we can simplify our equation to:
radians
MAGNITUDE CONDITION:
Beginning with the magnitude of each side, we write (where k is the model gain of the plant) or noting that we can write as
which can be solved for K to yield:
Suppose now that rather than performing a Root Locus analysis based on proportional gain, let us perform one by varying a system parameter.
Suppose we wish to analyze a mass-spring-damper system with:
x = position
m = mass
b = damper constant
k = spring constant
u = input force
The transfer function then will be:
First let us try varying the mass of our spring. Based on our knowledge of 2nd order systems, changing our mass should affect both the natural frequency as well as the damping value of the system, which when combined will alter the damped frequency.
m = 0; % we'll change this in our loop
b = 5;
k = 3;
RLzeros = [];
RLpoles = [];
for m = 1:0.1:10
Plant = (1)/(m*s*s + b*s + k);
Controller = 1;
System = feedback(Controller*Plant,1);
%RLzeros = [RLzeros; zero(System)];
RLpoles = [RLpoles; pole(System)];
end
f = figure();
f.Position = [0 0 800 500];
scatter(real(RLzeros), imag(RLzeros), 50, 'Marker', 'o', 'MarkerEdgeColor','b'); hold on;
scatter(real(RLpoles), imag(RLpoles), 50, 'Marker', 'x', 'MarkerEdgeColor','b'); hold on;
%area([-100 0],[+100 +100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
%area([-100 0],[-100 -100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
%area([0 +100],[+100 +100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
%area([0 +100],[-100 -100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
xline(0,'DisplayName','x-axis'); yline(0,'DisplayName','y-axis'); hold off;
xlim([-6 2]); xlabel('real');
ylim([-2.5 2.5]); ylabel('imag');
title('Pole Locations by Changing Mass');
%legend('RL zeros','RL poles', 'FontSize', 12, 'Location', 'northwest')
Next let's try changing the damping value. Intuitively we should expect the system to become more and more damped (faster decay and oscillations) until it becomes overdamped.
m = 10;
b = 0; % we'll change this in our loop
k = 3;
RLzeros = [];
RLpoles = [];
for b = 1:0.15:15
Plant = (1)/(m*s*s + b*s + k);
Controller = 1;
System = feedback(Controller*Plant,1);
%RLzeros = [RLzeros; zero(System)];
RLpoles = [RLpoles; pole(System)];
end
f = figure();
f.Position = [0 0 800 500];
scatter(real(RLzeros), imag(RLzeros), 50, 'Marker', 'o', 'MarkerEdgeColor','b'); hold on;
scatter(real(RLpoles), imag(RLpoles), 50, 'Marker', 'x', 'MarkerEdgeColor','b'); hold on;
area([-100 0],[+100 +100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([-100 0],[-100 -100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([0 +100],[+100 +100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
area([0 +100],[-100 -100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
xline(0,'DisplayName','x-axis'); yline(0,'DisplayName','y-axis'); hold off;
xlim([-6 2]); xlabel('real');
ylim([-2.5 2.5]); ylabel('imag');
title('Pole Locations by Changing Damping');
legend('RL zeros','RL poles', 'FontSize', 12, 'Location', 'northwest')
Next let's try changing the spring value. Intuitively we should expect the system to decay faster and faster, but because the spring constant affects only the natural frequency and not the damping value, we should notice the effect primarily in the frequency of the response and not the damping.
m = 10;
b = 5;
k = 0; % we'll change this in our loop
RLzeros = [];
RLpoles = [];
for k = 0.1:0.1:10
Plant = (1)/(m*s*s + b*s + k);
Controller = 1;
System = feedback(Controller*Plant,1);
%RLzeros = [RLzeros; zero(System)];
RLpoles = [RLpoles; pole(System)];
end
f = figure();
f.Position = [0 0 800 500];
scatter(real(RLzeros), imag(RLzeros), 50, 'Marker', 'o', 'MarkerEdgeColor','b'); hold on;
scatter(real(RLpoles), imag(RLpoles), 50, 'Marker', 'x', 'MarkerEdgeColor','b'); hold on;
area([-100 0],[+100 +100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([-100 0],[-100 -100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([0 +100],[+100 +100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
area([0 +100],[-100 -100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
xline(0,'DisplayName','x-axis'); yline(0,'DisplayName','y-axis'); hold off;
xlim([-6 2]); xlabel('real');
ylim([-2.5 2.5]); ylabel('imag');
title('Pole Locations by Changing Spring');
legend('RL zeros','RL poles', 'FontSize', 12, 'Location', 'northwest')
For a final demonstration, let's try changing two values!
m = 0; % we'll change this in our loop
b = 0; % we'll change this in our loop
k = 2;
RLzeros = [];
RLpoles = [];
for m = 1:0.1:10
for b = 0:0.15:15
Plant = (1)/(m*s*s + b*s + k);
Controller = 1;
System = feedback(Controller*Plant,1);
%RLzeros = [RLzeros; zero(System)];
RLpoles = [RLpoles; pole(System)];
end
end
f = figure();
f.Position = [0 0 800 500];
scatter(real(RLzeros), imag(RLzeros), 50, 'Marker', 'o', 'MarkerEdgeColor','b'); hold on;
scatter(real(RLpoles), imag(RLpoles), 50, 'Marker', 'x', 'MarkerEdgeColor','b'); hold on;
area([-100 0],[+100 +100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([-100 0],[-100 -100], 'FaceColor','green', 'FaceAlpha', 0.1); hold on;
area([0 +100],[+100 +100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
area([0 +100],[-100 -100], 'FaceColor','red', 'FaceAlpha', 0.1); hold on;
xline(0,'DisplayName','x-axis'); yline(0,'DisplayName','y-axis'); hold off;
xlim([-6 2]); xlabel('real');
ylim([-2.5 2.5]); ylabel('imag');
title('Pole Locations by Changing Spring');
legend('RL zeros','RL poles', 'FontSize', 12, 'Location', 'northwest')