Fundamentals
Housekeeping
close all force; clear; clc; s = tf('s');
Very often one of the first steps when working with Transfer Functions, especialy those that don't factor nicely, is to plot their poles & zeros on a pole-zero plot in the S-Plane. From there we can determine things like stability, response time, damping ratio, etc. While this is all analytically easy to understand based on the effects poles & zeros have on a system response (see the other pages in the Fundamentals series), it doens't do a very good job of explaining what the S-Plane IS. What do other points on the S-Plane represent? Can you have functions (lines) in the S-Plane?
Rather than answering those questions directly, here I will begin with a comparison of the Laplace and Fourier Transforms to build a conceptual understanding of the S-Plane with a more thorough plot of a Transfer Function there. It is best to begin with the Fourier Transform as it is both easier to understand, and is conveniently itself simply a slice of the Laplace Transform!
For example, observe the Fourier Transform of the following system:
% Creating a time-vector, two frequencies, and a signal (using 2 pi to
% convert to radians).
t = 0:0.001:0.6;
freq_1 = 50;
freq_2 = 120;
y = sin(2*pi*freq_1*t)+sin(2*pi*freq_2*t);
% Definint the number of Finite Fourier Transform points, calculating
% the transform itself, and calculating the relative power of each
% frequency
fft_points = 512;
Y = fft(y,fft_points);
Pyy = Y.* conj(Y) / fft_points;
% Creating a Plot
f1 = figure(); f1.Position = [0,0,800,800];
% Plot the original signal
subplot(2,1,1);
plot(1000*t(1:50),y(1:50));
title('Original Signal y');
xlabel('time (milliseconds)');
ylabel('signal amplitude');
% Plot the first 50% of the frequencies
subplot(2,1,2)
ft = 1000*(0:256)/fft_points;
plot(ft,Pyy(1:257));
title('Frequency content of y');
xlabel('frequency (Hz)');
Observing the Fourier Transform of our signal we can see two distinct peaks at our two frequencies, or what you might call the "poles" of our signal. Note too that while the Fourier Transform prorduces two apparent singularities at each freuency, it does not give us two "points", but rather a continuous line! This should be our first clue that the pole-zero plot is not the full representation of the Laplace Transform!
As an example, let us consider the Transfer Function:
which would produce the below Pole-Zero Plot.
G_TF = 3*(s+0.5)/((s+5)*(s+2));
f2 = figure(); f2.Position = [0,0,700,600];
pzmap(G_TF)
xlim([-6,1])
ylim([-3,3])
Just from this simple plot we can show that we have two poles and a single pole, all in the LHP [Left Half Plane] of the S-Plane. From this we know that the system is both stable, and has a purely real response [to a step input] with no oscillations. But what is the effect of each pole, and what is the effect of the LHP zero on each pole? There is certainly no direct cancellation, but we cannot say there is no effect at all!
To get a better idea of what our Transfer Function really looks like, let us plug in a variety of real and imaginary values for s (representing a variety of real and complex inputs), plug them into our Transfer Function, and plot the response! For the magnitude we can simply plot the magnitude of each complex value at each R-I point, but for the phase we will limit ourselves to only the THP (Top Half Plane) as the amount of phase will be mirrored across the real axis.
f3 = figure(); f3.Position = [0,0,1300,600];
[R1, I1] = meshgrid(-10:0.05:0, -3:0.05:3);
[R2, I2] = meshgrid(-10:0.05:0, 0.05:0.05:3);
S1=R1+j*I1;
S2=R2+j*I2;
G_surface = abs(3*(S1+1)./((S1+5).*(S1+2)));
G_surface2 = angle(3*(S2+1)./((S2+5).*(S2+2)));
subplot(1,2,1)
mesh(R1, I1, G_surface)
xlabel('real axis');
ylabel('imag axis');
zlim([0,20])
view([18.44 44.31])
subplot(1,2,2)
mesh(R2, I2, G_surface2)
xlabel('real axis');
ylabel('imag axis');
%zlim([0,20])
view([18.44 44.31])
Now THIS, is a much better representation of our Transfer Function! We can see both types of singularity; the poles at and where the response goes to ∞, as well as the single zero at where the response goes to zero. What's more, we can actually see the effect of a pole and a zero being near each other with the response of the pole at being far less pronounced than the pole at ! Based purely on this observation we can show that even in the case of unwanted poles or zeros, they can (assuming they are in the LHP) have their contribution to the overall response reduced by placing the opposite singularity nearby!
Turning our attention to the phase plot, if we follow the real axis from negative to positive we can see that each pole will produce a step increase of phase by π, with the zero producing a step decrease in phase by π. As we move further from the real axis, these effects are smoothed out.
This can be further illustrated by moving our zero closer to the pole at , and seeing that now that pole is reduced rather than the one at . Note that the transfer function appears "pinched" at the location of the zero, so much like the poles the effect of a zero on the transfer function manifests near the zero location and not only at the zero point. The furthher away the base of the transfer function is (here it is already pretty close to zero) the more noticeable this effect will be. We can also observe the same effect as the first phase plot, where moving from negative to positive on the real axis we see each pole contribute a step in response, with the zero contributing a step in response. Note that in this case because the zero "cancels out" the step response of the pole at , the pole at can only repeat the same step response rather than adding to it!
f4 = figure(); f4.Position = [0,0,1300,600];
G_surface = abs(3*(S1+4.5)./((S1+5).*(S1+2)));
G_surface2 = angle(3*(S2+4.5)./((S2+5).*(S2+2)));
subplot(1,2,1)
mesh(R1, I1, G_surface)
xlabel('real axis');
ylabel('imag axis');
zlim([0,20])
view([18.44 44.31])
subplot(1,2,2)
mesh(R2, I2, G_surface2)
xlabel('real axis');
ylabel('imag axis');
%zlim([0,20])
view([18.44 44.31])
% mesh(R2, I2, G_surface2); hold on;
% xlabel('real axis');
% ylabel('imag axis');
% scatter3(-2,0,0, 'x', 'SizeData', 300, 'MarkerFaceColor','k'); hold on;
% scatter3(-5,0,0, 'x', 'SizeData', 300, 'MarkerFaceColor','k'); hold on;
% scatter3(-4.5,0,0, 'o', 'SizeData', 300, 'MarkerFaceColor','k'); hold off;
% view([18.44 44.31])
% set(gcf,'Visible','on');
Not being content with reducing a poles/zeros effects partially, we can demonstrate the effect of full pole-zero cancellations on the effect of a Transfer Function! By moving the zero to the exact same locoation as the pole at we can show that not only do both singularities at vanish, the effects of each are removed entirely! Note that in this case, the zero does not "overpower" the pole at its point of singularity, but rather by cancellation it is like they were never there!
Because in practice the precise location of poles and zeros cannot be known, this is one of the benefits of developing Transfer Functions through the State-Space approach as pole-zero cancellations will be shown explicitly. A Transfer Function might show up as the system below, when in reality it is the system above!
f5 = figure(); f5.Position = [0,0,1300,600];
G_surface = abs(3*(S1+5)./((S1+5).*(S1+2)));
G_surface2 = angle(3*(S2+5)./((S2+5).*(S2+2)));
subplot(1,2,1)
mesh(R1, I1, G_surface)
xlabel('real axis');
ylabel('imag axis');
zlim([0,20])
view([18.44 44.31])
subplot(1,2,2)
mesh(R2, I2, G_surface2)
xlabel('real axis');
ylabel('imag axis');
%zlim([0,20])
view([18.44 44.31])
For a bit of fun, let's animate the movement of a zero across both poles to demonstrate the effect the zero can have on poles based on their relative proximity!
% v = VideoWriter("pole_vs_zero", 'MPEG-4');
% v.FrameRate = 20;
% open(v);
%
% a = -4:0.1:10;
% f5 = figure(); f5.Position = [0,0,800,600];
% for k = 1:1:length(a)
% G_surface = abs(3*(S1+a(k))./((S1+5).*(S1+2)));
% scatter3(-1*a(k),0,0, 200, "red", 'filled');
% hold on
% mesh(R1, I1, G_surface);
% hold off
% xlim([-8,2]); xlabel('real axis');
% ylim([-3,3]); ylabel('imag axis');
% zlim([0,20])
% view([18.44 44.31])
% M(k) = getframe(f5);
% writeVideo(v,M(k));
% end
% close(f5);
% close(v);
%
%
%
% v = VideoWriter("pole_vs_zero2", 'MPEG-4');
% v.FrameRate = 20;
% open(v);
%
% f6 = figure(); f6.Position = [0,0,800,600];
% for k = 1:1:length(a)
% G_surface2 = angle(3*(S2+a(k))./((S2+5).*(S2+2)));
% scatter3(-1*a(k),0,0, 200, "red", 'filled');
% hold on
% mesh(R2, I2, G_surface2);
% hold off
% xlim([-8,2]); xlabel('real axis');
% ylim([-3,3]); ylabel('imag axis');
% %zlim([0,20])
% view([18.44 44.31])
% M(k) = getframe(f6);
% writeVideo(v,M(k));
% end
% close(f6);
% close(v);