Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ssdata & storage format of systems? #857

Closed
B-LIE opened this issue Jun 8, 2023 · 7 comments
Closed

ssdata & storage format of systems? #857

B-LIE opened this issue Jun 8, 2023 · 7 comments

Comments

@B-LIE
Copy link

B-LIE commented Jun 8, 2023

I'm puzzled by the following:

> using ControlSystems

> sys = tf([2,1],[5,6,1])

> ssdata(sys)
(nothing, nothing, nothing, nothing)

> ssdata(ss(sys))
([0.0 0.5; -0.4 -1.2], [0.0; 1.0;;], [0.4 0.4], [0.0;;])
  • This indicates that the system is stored in the format it was created in, and not in state space form?

  • Another observation... ssdata creates two extra, blank lines for the outputs, ;; for the C matrix and the D matrix. Why? (I've seen similar things in other Julia code, too, and it puzzles me :-o )

@albheim
Copy link
Member

albheim commented Jun 8, 2023

Yes, there are a few different ways the systems are stored.
TransferFunctions constsis of a matrix of either SisoTf types storing two polynomials or SisoZpk storing a gain and a vector each for pole/zero locations.
Then there is StateSpace storing four matrices, and some other versions of special state spaces as well.

The extra ;; is (I think) from normal matrix plotting since maybe version 1.8?

julia> (rand(1, 1), rand(2, 1), rand(1, 2))
([0.1785620036939919;;], [0.6089651884889287; 0.7791505974417174;;], [0.494261101514058 0.47886582862763305])

It denotes that there is a second dimension when it is not otherwise clear from the data, i.e. for a 2x1 size matrix to distinguish it from a 2-length vector.

@baggepinnen
Copy link
Member

Why was this puzzling? Transfer functions and statespace models have quite different properties when it comes to computation and it makes sense to be able to represent both. For one, transfer functions can represent non-proper systems, whereas statespace models (without mass matrix) can not. The computations involved in computing, e.g., frequency responses are also vastly different for the two different representations.

@baggepinnen
Copy link
Member

I also encourage you to actually look at the source code, it would trivially answer this kind of question, a big benefit of using open-source software ;)

@B-LIE
Copy link
Author

B-LIE commented Jun 8, 2023

Why was this puzzling?

"Puzzling" for one with background in MATLAB's ControlToolbox - where ssdata responds with A,B,C,D matrices irrespective of which constructor was used. Also, my impression is that numerically speaking, it is better with storing models in State Space form, so I thought that was done. The documentation of ssdata uses generic sys as argument.

But you are right - I shouldn't assume that ControlSystems.jl has exactly the same use as MATLAB's toolbox.

As you say, storing the system as a transfer function has some advantages in that transfer functions can handle infinite dimensional systems (such as with the delay) function. The delay is, of course, a representation of the simple advection equation $\frac{\partial x}{\partial t} = -v\frac{\partial x}{\partial z}$ with $z \in [0,L]$ leading to Laplace transform $\exp{(-\tau s)}$ with $\tau = L/v$. Many other fancy transfer functions can be found which are not fractions of polynomials, such as in various heat exchangers. It would be cool if ControlSystems could allow for such types by multiplying a transfer function with other functions (such as those given by linear PDEs), but there is perhaps not a big "market" for this :-o.

Anyways, my confusion was due to MATLAB experience.

@B-LIE
Copy link
Author

B-LIE commented Jun 8, 2023

I also encourage you to actually look at the source code

I tried to open the ControlSystems.jl source code in GitHub, but didn't really find ssdata.

However, utility function Base.functionloc found it. [I've had experience in the past where Base.functionloc gives an error message, though.]

@baggepinnen
Copy link
Member

baggepinnen commented Jun 8, 2023

I can recommend the function dump to inspect the structure of any composed object

julia> H = tf(1, [1,1]);

julia> dump(H)
TransferFunction{Continuous, ControlSystemsBase.SisoRational{Int64}}
  matrix: Array{ControlSystemsBase.SisoRational{Int64}}((1, 1))
    1: ControlSystemsBase.SisoRational{Int64}
      num: Polynomials.Polynomial{Int64, :x}
        coeffs: Array{Int64}((1,)) [1]
      den: Polynomials.Polynomial{Int64, :x}
        coeffs: Array{Int64}((2,)) [1, 1]
  timeevol: Continuous Continuous()

The macro @edit is also useful in locating the source of the code that is being called

julia> @edit ssdata(H)

As a side, we represent time-delay systems as an LFT of a statespace system with a time-delay block:

julia> tf(1, [1,1]) * delay(2.0)
DelayLtiSystem{Float64, Float64}

P: StateSpace{Continuous, Float64}
A = 
 -1.0
B = 
 0.0  1.0
C = 
 1.0
 0.0
D = 
 0.0  0.0
 1.0  0.0

Continuous-time state-space model

Delays: [2.0]

you can read more about this in the paper https://github.com/JuliaControl/CDC2021/blob/master/CDC2021.pdf

@baggepinnen
Copy link
Member

baggepinnen commented Jun 8, 2023

Also, my impression is that numerically speaking, it is better with storing models in State Space form, so I thought that was done.

For many things yes, but not for everything, we thus allow the user to choose the representation. We also store zpk models as separate arrays of zeros poles and gain, which is preferable in some situations.

We have a whole page in the documentation dedicated to these choices
https://juliacontrol.github.io/ControlSystems.jl/stable/man/numerical/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants