rlocus behaviour seems inconsistent for system with cancelling pole and zero

10 views (last 30 days)
In the past, if sys included a coincident pole/zero pair, rlocus(sys) would show both. Now the plot shows neither (i.e. it seems to have made a unilateral decision to cancel the pole with the zero). However, the closed-loop poles obtained via rlocfind(sys) or feedback(sys,k) still include the coincident one.
e.g.
sys = tf([1 2 0],[1 4 6 17 0]); % coincident pole and zero at s = 0
rlocus(sys) % shows neither pole or zero at s = 0
[k,poles] = rlocfind(sys) % shows a red + at s = 0
cl = feedback(sys,15); % returns a closed-loop transfer function with both pole and zero at s = 0
This is quite confusing. Is the change deliberate? I would suggest that rlocus should leave the user to decide whether to eliminate any matching pole/zero pairs rather than taking matters into its own hands.
  1 Comment
Paul
Paul on 28 Mar 2022
One would think that rlocus and rlocfind would be consistent with each other, i.e., either show the open loop pole/zero and the closed loop pole, or show none of them.
It looks like the tolerance used to not show the open/loop pole zero is very tight. I changed the numerator to [1 2 eps] and rolcus showed the open loop pole/zero at/nearly at the origin.
AFAIK, feedback() will never do the pole zero cancellation.

Sign in to comment.

Answers (1)

Neelanshu
Neelanshu on 7 Feb 2024
Hi Will,
I understand from your query that you're looking to create a root locus plot of a system using MATLAB's "rlocus" function without automatically cancelling coincident poles and zeros.
One approach as mentioned by Paul is to utilise "eps" to obtain pole and zero nearly at origin. Alternatively you can convert the "transfer function model" to "zero pole gain" model. The rlocus doesnt perform pole-zero cancellation for "zero pole gain" model of the system as shown:
sys_zpk = zpk(1,1,1)
sys_zpk = (s-1) ----- (s-1) Continuous-time zero/pole/gain model.
rlocus(sys_zpk)
Hope this helps.
  2 Comments
Will Graham
Will Graham on 7 Feb 2024
Thanks Neelanshu. It's useful to know how to generate a root locus plot that includes the cancelling pole/zero, but my real concern is consistency between commands. If you generate a root locus plot that doesn't show the cancelling pair, and then find an extra pole appearing in the outputs from rlocfind and feedback, it's confusing.
Paul
Paul on 7 Feb 2024
Well, this is all very interesting.
Examples by @Neelanshu
sys_zpk = zpk(1,1,1);
figure,rlocus(sys_zpk);
sys_tf = tf([1 -1],[1 -1]);
figure,rlocus(sys_tf);
To be clear, the pole/zero cancellation is actually affecting the calculation, it's not just a plotting thing. We can see this by
r = rlocus(sys_zpk)
r = 1x52
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
r = rlocus(sys_tf)
r = []
But, add a pole at the origin:
sys_zpk = zpk(1,[1 0],1)
sys_zpk = (s-1) ------- s (s-1) Continuous-time zero/pole/gain model.
figure
rlocus(sys_zpk)
systf = tf([1 -1],[1 -1 0]);
figure
rlocus(systf)
r = rlocus(systf)
r = 2x53
0 -0.1000 -0.1072 -0.1149 -0.1232 -0.1320 -0.1415 -0.1517 -0.1626 -0.1742 -0.1868 -0.2002 -0.2146 -0.2300 -0.2465 -0.2643 -0.2833 -0.3036 -0.3254 -0.3488 -0.3739 -0.4008 -0.4296 -0.4605 -0.4936 -0.5290 -0.5671 -0.6078 -0.6515 -0.6983 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000 1.0000
Hmm, that pole/zero at s = 1 is kept on the plot and the calculation
Here's the original example by @Will Graham
sys = tf([1 2 0],[1 4 6 17 0]); % coincident pole and zero at s = 0
figure
rlocus(sys) % shows neither pole or zero at s = 0
r = rlocus(sys)
r =
1.0e+02 * Columns 1 through 9 -0.0364 + 0.0000i -0.0350 + 0.0000i -0.0349 + 0.0000i -0.0348 + 0.0000i -0.0346 + 0.0000i -0.0345 + 0.0000i -0.0343 + 0.0000i -0.0341 + 0.0000i -0.0339 + 0.0000i -0.0018 + 0.0215i -0.0025 + 0.0236i -0.0025 + 0.0238i -0.0026 + 0.0240i -0.0027 + 0.0242i -0.0028 + 0.0245i -0.0028 + 0.0248i -0.0029 + 0.0251i -0.0030 + 0.0254i -0.0018 - 0.0215i -0.0025 - 0.0236i -0.0025 - 0.0238i -0.0026 - 0.0240i -0.0027 - 0.0242i -0.0028 - 0.0245i -0.0028 - 0.0248i -0.0029 - 0.0251i -0.0030 - 0.0254i Columns 10 through 18 -0.0337 + 0.0000i -0.0335 + 0.0000i -0.0333 + 0.0000i -0.0330 + 0.0000i -0.0327 + 0.0000i -0.0324 + 0.0000i -0.0321 + 0.0000i -0.0317 + 0.0000i -0.0314 + 0.0000i -0.0031 + 0.0257i -0.0033 + 0.0261i -0.0034 + 0.0265i -0.0035 + 0.0270i -0.0037 + 0.0275i -0.0038 + 0.0280i -0.0040 + 0.0286i -0.0041 + 0.0293i -0.0043 + 0.0300i -0.0031 - 0.0257i -0.0033 - 0.0261i -0.0034 - 0.0265i -0.0035 - 0.0270i -0.0037 - 0.0275i -0.0038 - 0.0280i -0.0040 - 0.0286i -0.0041 - 0.0293i -0.0043 - 0.0300i Columns 19 through 27 -0.0310 + 0.0000i -0.0306 + 0.0000i -0.0302 + 0.0000i -0.0297 + 0.0000i -0.0293 + 0.0000i -0.0288 + 0.0000i -0.0284 + 0.0000i -0.0279 + 0.0000i -0.0275 + 0.0000i -0.0045 + 0.0307i -0.0047 + 0.0316i -0.0049 + 0.0324i -0.0051 + 0.0334i -0.0054 + 0.0344i -0.0056 + 0.0355i -0.0058 + 0.0367i -0.0060 + 0.0380i -0.0063 + 0.0394i -0.0045 - 0.0307i -0.0047 - 0.0316i -0.0049 - 0.0324i -0.0051 - 0.0334i -0.0054 - 0.0344i -0.0056 - 0.0355i -0.0058 - 0.0367i -0.0060 - 0.0380i -0.0063 - 0.0394i Columns 28 through 36 -0.0270 + 0.0000i -0.0266 + 0.0000i -0.0261 + 0.0000i -0.0257 + 0.0000i -0.0253 + 0.0000i -0.0249 + 0.0000i -0.0246 + 0.0000i -0.0242 + 0.0000i -0.0239 + 0.0000i -0.0065 + 0.0409i -0.0067 + 0.0424i -0.0069 + 0.0441i -0.0071 + 0.0459i -0.0073 + 0.0478i -0.0075 + 0.0498i -0.0077 + 0.0519i -0.0079 + 0.0541i -0.0080 + 0.0564i -0.0065 - 0.0409i -0.0067 - 0.0424i -0.0069 - 0.0441i -0.0071 - 0.0459i -0.0073 - 0.0478i -0.0075 - 0.0498i -0.0077 - 0.0519i -0.0079 - 0.0541i -0.0080 - 0.0564i Columns 37 through 45 -0.0236 + 0.0000i -0.0233 + 0.0000i -0.0231 + 0.0000i -0.0228 + 0.0000i -0.0226 + 0.0000i -0.0224 + 0.0000i -0.0222 + 0.0000i -0.0220 + 0.0000i -0.0218 + 0.0000i -0.0082 + 0.0589i -0.0083 + 0.0615i -0.0085 + 0.0642i -0.0086 + 0.0671i -0.0087 + 0.0701i -0.0088 + 0.0733i -0.0089 + 0.0766i -0.0090 + 0.0801i -0.0091 + 0.0837i -0.0082 - 0.0589i -0.0083 - 0.0615i -0.0085 - 0.0642i -0.0086 - 0.0671i -0.0087 - 0.0701i -0.0088 - 0.0733i -0.0089 - 0.0766i -0.0090 - 0.0801i -0.0091 - 0.0837i Columns 46 through 53 -0.0217 + 0.0000i -0.0215 + 0.0000i -0.0214 + 0.0000i -0.0213 + 0.0000i -0.0212 + 0.0000i -0.0211 + 0.0000i -0.0200 + 0.0000i -0.0200 + 0.0000i -0.0092 + 0.0875i -0.0092 + 0.0915i -0.0093 + 0.0957i -0.0094 + 0.1001i -0.0094 + 0.1048i -0.0095 + 0.1096i -0.0100 + 2.1999i Inf + 0.0000i -0.0092 - 0.0875i -0.0092 - 0.0915i -0.0093 - 0.0957i -0.0094 - 0.1001i -0.0094 - 0.1048i -0.0095 - 0.1096i -0.0100 - 2.1999i Inf + 0.0000i
Only three roots returned, but there should be four.
sys_zpk = zpk(sys)
sys_zpk = s (s+2) ----------------------------------- s (s+3.636) (s^2 + 0.3642s + 4.676) Continuous-time zero/pole/gain model.
But everything is as expected for zpk
sys_zpk = zpk([-2 0],[0, -3.636, roots([1 0.3642 4.676]).'],1);
figure
rlocus(sys_zpk)
r = rlocus(sys_zpk)
r =
1.0e+02 * Columns 1 through 9 0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0018 + 0.0215i -0.0025 + 0.0236i -0.0025 + 0.0238i -0.0026 + 0.0240i -0.0027 + 0.0242i -0.0028 + 0.0245i -0.0028 + 0.0248i -0.0029 + 0.0251i -0.0030 + 0.0254i -0.0018 - 0.0215i -0.0025 - 0.0236i -0.0025 - 0.0238i -0.0026 - 0.0240i -0.0027 - 0.0242i -0.0028 - 0.0245i -0.0028 - 0.0248i -0.0029 - 0.0251i -0.0030 - 0.0254i -0.0364 + 0.0000i -0.0350 + 0.0000i -0.0349 + 0.0000i -0.0348 + 0.0000i -0.0347 + 0.0000i -0.0345 + 0.0000i -0.0343 + 0.0000i -0.0341 + 0.0000i -0.0339 + 0.0000i Columns 10 through 18 -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0031 + 0.0257i -0.0033 + 0.0261i -0.0034 + 0.0265i -0.0035 + 0.0270i -0.0037 + 0.0275i -0.0038 + 0.0280i -0.0040 + 0.0286i -0.0041 + 0.0293i -0.0043 + 0.0300i -0.0031 - 0.0257i -0.0033 - 0.0261i -0.0034 - 0.0265i -0.0035 - 0.0270i -0.0037 - 0.0275i -0.0038 - 0.0280i -0.0040 - 0.0286i -0.0041 - 0.0293i -0.0043 - 0.0300i -0.0337 + 0.0000i -0.0335 + 0.0000i -0.0333 + 0.0000i -0.0330 + 0.0000i -0.0327 + 0.0000i -0.0324 + 0.0000i -0.0321 + 0.0000i -0.0317 + 0.0000i -0.0314 + 0.0000i Columns 19 through 27 -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0045 + 0.0307i -0.0047 + 0.0316i -0.0049 + 0.0324i -0.0051 + 0.0334i -0.0054 + 0.0344i -0.0056 + 0.0355i -0.0058 + 0.0367i -0.0060 + 0.0380i -0.0063 + 0.0394i -0.0045 - 0.0307i -0.0047 - 0.0316i -0.0049 - 0.0324i -0.0051 - 0.0334i -0.0054 - 0.0344i -0.0056 - 0.0355i -0.0058 - 0.0367i -0.0060 - 0.0380i -0.0063 - 0.0394i -0.0310 + 0.0000i -0.0306 + 0.0000i -0.0302 + 0.0000i -0.0297 + 0.0000i -0.0293 + 0.0000i -0.0288 + 0.0000i -0.0284 + 0.0000i -0.0279 + 0.0000i -0.0275 + 0.0000i Columns 28 through 36 -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0065 + 0.0409i -0.0067 + 0.0424i -0.0069 + 0.0441i -0.0071 + 0.0459i -0.0073 + 0.0478i -0.0075 + 0.0498i -0.0077 + 0.0519i -0.0079 + 0.0541i -0.0080 + 0.0564i -0.0065 - 0.0409i -0.0067 - 0.0424i -0.0069 - 0.0441i -0.0071 - 0.0459i -0.0073 - 0.0478i -0.0075 - 0.0498i -0.0077 - 0.0519i -0.0079 - 0.0541i -0.0080 - 0.0564i -0.0270 + 0.0000i -0.0266 + 0.0000i -0.0261 + 0.0000i -0.0257 + 0.0000i -0.0253 + 0.0000i -0.0249 + 0.0000i -0.0246 + 0.0000i -0.0242 + 0.0000i -0.0239 + 0.0000i Columns 37 through 45 -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0082 + 0.0589i -0.0083 + 0.0615i -0.0085 + 0.0642i -0.0086 + 0.0671i -0.0087 + 0.0701i -0.0088 + 0.0733i -0.0089 + 0.0766i -0.0090 + 0.0801i -0.0091 + 0.0837i -0.0082 - 0.0589i -0.0083 - 0.0615i -0.0085 - 0.0642i -0.0086 - 0.0671i -0.0087 - 0.0701i -0.0088 - 0.0733i -0.0089 - 0.0766i -0.0090 - 0.0801i -0.0091 - 0.0837i -0.0236 + 0.0000i -0.0233 + 0.0000i -0.0231 + 0.0000i -0.0228 + 0.0000i -0.0226 + 0.0000i -0.0224 + 0.0000i -0.0222 + 0.0000i -0.0220 + 0.0000i -0.0218 + 0.0000i Columns 46 through 53 -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0000 + 0.0000i -0.0092 + 0.0875i -0.0092 + 0.0915i -0.0093 + 0.0958i -0.0094 + 0.1002i -0.0094 + 0.1048i -0.0095 + 0.1096i -0.0100 + 2.2000i Inf + 0.0000i -0.0092 - 0.0875i -0.0092 - 0.0915i -0.0093 - 0.0958i -0.0094 - 0.1002i -0.0094 - 0.1048i -0.0095 - 0.1096i -0.0100 - 2.2000i Inf + 0.0000i -0.0217 + 0.0000i -0.0215 + 0.0000i -0.0214 + 0.0000i -0.0213 + 0.0000i -0.0212 + 0.0000i -0.0211 + 0.0000i -0.0200 + 0.0000i -0.0200 + 0.0000i
For the tf cases, I'm pretty sure this behavior can be explained as follows.
Buried in rlocus, the tf input is converted to an ss object
sys_ss = ss(sys)
sys_ss = A = x1 x2 x3 x4 x1 -4 -1.5 -2.125 0 x2 4 0 0 0 x3 0 2 0 0 x4 0 0 0.25 0 B = u1 x1 0.5 x2 0 x3 0 x4 0 C = x1 x2 x3 x4 y1 0 0.5 0.5 0 D = u1 y1 0 Continuous-time state-space model.
We can see, by inspection of the structure of the system, that x4 has no effect on th input/output behavior. Matlab calls this structurally non-minimal. Inside rlocus, it makes a call to sminreal and we lose the pole/zero at the origin
sminreal(sys_ss)
ans = A = x1 x2 x3 x1 -4 -1.5 -2.125 x2 4 0 0 x3 0 2 0 B = u1 x1 0.5 x2 0 x3 0 C = x1 x2 x3 y1 0 0.5 0.5 D = u1 y1 0 Continuous-time state-space model.
tf(ans)
ans = s + 2 ---------------------- s^3 + 4 s^2 + 6 s + 17 Continuous-time transfer function.
and we get the root locus of the reduced order system.
Now let's check a different case with tf
sys = tf([1 -1],[1 -1 0])
sys = s - 1 ------- s^2 - s Continuous-time transfer function.
In this case, the conversion to ss results in a structurally minimal system
ss(sys)
ans = A = x1 x2 x1 1 0 x2 1 0 B = u1 x1 2 x2 0 C = x1 x2 y1 0.5 -0.5 D = u1 y1 0 Continuous-time state-space model.
because C(1,2) is non-zero. So the call to sminreal does nothing
sminreal(ans)
ans = A = x1 x2 x1 1 0 x2 1 0 B = u1 x1 2 x2 0 C = x1 x2 y1 0.5 -0.5 D = u1 y1 0 Continuous-time state-space model.
and the rlocus results include the pole/zero at s = 1.
I didn't poke around in the code for the zpk case, but I suspect it's a similar issue. Going all the way back to the simplest case
sys_zpk = zpk(1,1,1);
The ss realization is structurally minimal
ss(sys_zpk)
ans = A = x1 x1 1 B = u1 x1 7.451e-09 C = x1 y1 7.451e-09 D = u1 y1 1 Continuous-time state-space model.
sminreal(ans)
ans = A = x1 x1 1 B = u1 x1 7.451e-09 C = x1 y1 7.451e-09 D = u1 y1 1 Continuous-time state-space model.
so the pole/zero at s = 1 stays.
But the ss realization of the tf form
sys_tf = ss(tf([1 -1],[1 -1]))
sys_tf = A = x1 x1 1 B = u1 x1 1 C = x1 y1 0 D = u1 y1 1 Continuous-time state-space model.
is structurally minimal because C = 0
sminreal(sys_tf)
ans = D = u1 y1 1 Static gain.
and the pole/zero at s = 1 is eliminated.
Summary: rlocus converts tf (and probably also zpk) objects to ss and then calls sminreal on the result. If the ss realization is not structurally minimal, pole/zero cancellations will ensue.
I don't know why that call to sminreal was implemented in rlocus. Maybe it improves the accuracy of the results, or maybe it was some other reason. Regardless, it seems like the inconsistent behavior from the user's perspective is undesirable and that, if the call to sminreal is needed, some other action might be warranted, like a warning if sminreal eliminated some poles/zeros, or an option to have the the cancelled poles/zeros added back in to the output returned to the user (the output arguments and/or the plot).

Sign in to comment.

Products


Release

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!