ControlSystems -- root locus, etc.?

I was just playing around with the ControlSystems package. One question and one observation…
Q: is there a function for plotting root locus? Of course, it is easy to do this in a for loop, but if there is a function, my notebook would look nicer…
O: I tested the tzero() function. It struck me that it was really slow… at least compared to the pole() function… I never experienced waiting for the answer in MATLAB… or is my memory failing me?

rlocusplot
Did you measure time with Benchmartools? If you ran it once only, you experienced the initial compilation time.

Thanks for super fast response. I’ll check rlocusplot later in the weekend. [I assume that K can be both negative and positive…]

Didn’t benchmark tzero. I just observed that the pole command was super snappy, while tzero was slow in comparison. Will check again.

A longer compilation time for finding transmission zeros is expected since it’s a much more complicated process. It involves several qr factorization and generalized eigenvalues decompositions whereas finding system poles is essentially only a single eigenvalue calculation. tzero should however be very fast after the very first call.

rlocusplot– is the documentation clear?


I was hoping that a state space description qualified as an LTISystem (…which I don’t know what is, since the documentation is not really indexed – one of the reasons why I prefer printed documents…)

Here is what I get:

What do I do wrong? Of course, coding a “root locus” function is straightforward and gives freedom, but is somewhat messy – so I’d prefer to use the built-in function. Here is the result of my “messy” code:

That seems like a bug. Feel free to open an issue. In the meantime, you can use tf(sys) to convert your ss to a tf before calling rlocusplot.

Hi, again: I’m not very computer/GitHub savvy… Do I need a GitHub account to “open an issue”? I have several issues…

  • Yes, rlocusplot produces something if the system is given as transfer function (tf(sys_org)). It should, of course, produce the same result with a state space system. Function rlocusplot also fails if I use argument zpg(sys_org) … which is also a bug.
  • The produced plot is very incorrect… In fact, I don’t know what the result is – doesn’t look anything like my plot (which is correct…). Contrast the plot from rlocusplot with my plot above…:

    … or… zoomed in:

Well, I’m afraid I can’t really help you if you only post images, I would need to have the code (in text) to figure out what is going on.

I opened an issue.

PS. Don’t forget to quote-code-with-backticks

Yes, I understand that you need numbers. Is this ok?

julia> sys_org
ControlSystems.StateSpace{Float64,Array{Float64,2}}
A = 
  4.37956    209.205
 -0.0357143   -2.0  
B = 
 2.09205
 0.0    
C = 
 1.0  0.0
D = 
 0.0

Continuous-time state-space model

julia> rlocusplot(tf(sys_org), linspace(-1,8,50))

Is this ok? This produces a plot similar to the one I included above…

[The matrices are generated by a Julia interface to a nonlinear reactor model in OpenModelica, which is run from Julia, and linearized from Julia – using linearization algorithms in OpenModelica. That’s why they are not “nice numbers”…]

It would be far easier if the code was such that I could copy-paste it into the terminal and not have to type it all by hand.

1 Like

OK. Is this fine?

julia> using ControlSystems
julia> A = [4.38 209; -0.036 -2]; 
julia> B = [2.09; 0];
julia> C = [1 0];
julia> D = 0;
julia> sys = ss(A,B,C,D);
julia> rlocusplot(tf(sys), linspace(-1,8,50))

I can’t seem to figure out what is going wrong. Our old implementation works alright, but the new adaptive stepsize implementation seems to do the wrong thing in this case. I’ll open an issue about it, but do not have time to resolve it now :worried:

No problem. I’ll try to write my own rootlocusplot (as opposed to rlocusplot) when I have time (probably not until early October during my fall “vacation” to Hungary and Vienna) - then if you like some of it, you can pick from it.

I needed to do the root locus plot, and created my own function rootlocusplot()

Here is my function, in case it is of use:

function rootlocusplot(P::LTISystem;k=linspace(0,1,20),G=I,CGrad=:plasma_r,MSC=:black)
    #
    # Code by Bernt Lie
    # University of South-Eastern Norway
    # v.0.1, September 15, 2018
    #
    # P: LTI plant
    # k: scalar gain range
    # G: gain matrix, u = k*G*(ref-y)
    # CGrad: color gradient for roots over k
    # MSC: marker stroke color for open loop roots
    %
    A = P.A
    B = P.B*G
    C = P.C
    D = P.D*G
    #
    e0 = eigvals(A)
    tz = tzero(ss(A,B,C,D))
    #
    Eig = zeros(Complex,(length(k),2))
    if length(D)==1
        for (i,ki) in enumerate(k)
            Ac = A - ki*B*((1 + ki*D)\C);
            Eig[i,:] = eigvals(Ac)
        end
    else
        for (i,ki) in enumerate(k)
            Ac = A - ki*B*((I + ki*D)\C);
            Eig[i,:] = eigvals(Ac)
        end
    end
    #
    scatter(real(tz),imag(tz),shape=:o,ms=6,msc=MSC,mc=:white,label="Transmission zeros")
    #
    scatter!(real(Eig)[:,1],imag(Eig)[:,1],shape=:x,ms=3,mc=CGrad,mz=k,label="")
    scatter!(real(Eig)[:,2],imag(Eig)[:,2],shape=:x,ms=3,mc=CGrad,mz=k,label="")
    #
    scatter!(real(e0),imag(e0),shape=:x,ms=6,mc=MSC,label="Open loop roots")
    #
    plot!(title="Root locus plot")
    plot!(xlabel="real(root)")
    plot!(ylabel="imag(root)")
end

The function works for MIMO systems and is based on u = k\cdot G\cdot (r-y) where r is some reference, G is a chosen/known gain matrix, and k is specified in some range.
It would have been nice to put a k next to the color bar to indicate what the color bar is, but I don’t know how to do that.

I have assumed that the system does not have time delay. The function should work for the case D\neq 0, I think.