Naming of states, inputs and outputs in `ControlSystemsMTK`

Hi, I just tested naming states, inputs and outputs while passing a state-space model to ODESystem.

It seems the optional names are ignored, am I doing something wrong here ?

using ControlSystemsBase, ControlSystemsMTK, ModelingToolkit, LinearAlgebra
ssmodel = ss(Diagonal(rand(10)), rand(10,3), rand(2,10),0)
x_names = [Symbol("x$i") for i in 1:10]
sys = ModelingToolkit.ODESystem(ssmodel; name=:sys, x=x_names)

This returns

Model sys with 12 equations
Unknowns (15):
(x(t))[1] [defaults to 0.0]: State variables of StateSpace system sys
(x(t))[2] [defaults to 0.0]: State variables of StateSpace system sys
(x(t))[3] [defaults to 0.0]: State variables of StateSpace system sys
(x(t))[4] [defaults to 0.0]: State variables of StateSpace system sys
(x(t))[5] [defaults to 0.0]: State variables of StateSpace system sys
(x(t))[6] [defaults to 0.0]: State variables of StateSpace system sys
(x(t))[7] [defaults to 0.0]: State variables of StateSpace system sys
(x(t))[8] [defaults to 0.0]: State variables of StateSpace system sys
(x(t))[9] [defaults to 0.0]: State variables of StateSpace system sys
(x(t))[10] [defaults to 0.0]: State variables of StateSpace system sys
Parameters (0):

Iโ€™m on

[a6e380b2] ControlSystems v1.10.0
[aaaaaaaa] ControlSystemsBase v1.10.2
[687d7614] ControlSystemsMTK v2.0.1
[961ee093] ModelingToolkit v9.5.0

Yeah, I donโ€™t think itโ€™s possible to easily change the name of a variable that appears in a ModelingToolkit system, and here we use Blocks.StateSpace from MTK stdlib. Maybe one could do something with replace, I havenโ€™t looked into the possibilities here.

Ah, I think I just understood your answer, maybe I should just implement my own block then, because this seems to fall down to RealInput / RealOutput. So if I need to name my variables it looks simpler to rebuilt StateSpace with additional parameters and one named subcomponent per input/output.

Regarding the replace I wouldnโ€™t even know what to replace ^^. The MTK internals are somewhat cryptic sometimes

EDIT Something else related, would you know how to connect a Block to the input or output of a StateSpace, Iโ€™m receiving ERROR: None Sym BasicSymbolic doesn't have a name errorsโ€ฆ

You need to be more precise here, what is a Block? and are you talking about ControlSystems.StateSpace or ModelingToolkitStandardLibrary.Blocks.StateSpace? Hereโ€™s an example that performs multiple connections between systems from the ModelingToolkitStandardLibrary.Blocks submodule

Sorry, my previous message was not very clear indeed.

Iโ€™m trying to do something like

using ControlSystemsBase, ControlSystemsMTK, ModelingToolkit, LinearAlgebra, ModelingToolkitStandardLibrary
ssmodel = ss(Diagonal(rand(10)), rand(10,3), rand(2,10),0)
sys = ModelingToolkit.ODESystem(ssmodel; name=:sys)

@named sine = ModelingToolkitStandardLibrary.Blocks.Sine(; frequency=3)

eqs = Equation[
       connect(sys.input.u[3], sine.output)

But the last line fails with ERROR: None Sym BasicSymbolic doesn't have a name. Unless I missed something, in the example you linked, there are only scalar connections, right ?

I guess if this is not yet supported a quick and dirty way to solve both problems is to scalarize everything in a ScalarStateSpace.

The problem here is that sys.input is a connector, but sys.input.u is a variable. You can only form connections between connectors. If you want to say that a particular variable is equal to something else, you instead use a normal equation, i.e.,

sys.input.u[3] ~ sine.output.u

This actually gave me an idea of a much nicer interface, give me a few minuts and Iโ€™ll see if I can improve the experience here

x_names are still ignored, but names for inputs and outputs now have connectors, so you should be able to do

connect(sys.input3name, sine.output)

for some input3name specified in u_names

1 Like

Thanks for the quick work ! It works perfectly. A quick comment, Iโ€™m working with relatively large matrices that overflow the REPL upon showing the state space model. I was think of using ideas from BlockArrays.jl/src/show.jl at master ยท JuliaArrays/BlockArrays.jl ยท GitHub, do you mind if I propose a PR about that ?

How do those array display? Proposing a PR is of course welcome, we even have a brand new file :slight_smile:

From BlockArrays main page, you can see this kind of printing.

2ร—2-blocked 3ร—5 BlockMatrix{Float64}:
 -1.17797    0.359738   โ”‚   0.87676    -2.06495    1.74256
  1.54787    1.64133    โ”‚  -0.0416484  -2.00241   -0.522441
  0.430093  -0.0263753  โ”‚  -1.31275     0.278447  -0.139579

I figured it would be nice to have something similar to preserve the

dx = A x + B u
 y = C x + D u

shape of state space models

How will that help with matrices that are too large to fit in one repl screen? Wonโ€™t it actually make the problem worse?

Well, I was thinking of using this to keep the structure clean, and using the IOContext so that there is no overflow, but a cropping of the internals of the large matrices instead

I have always questioned the utility of seeing some but not all the values? I generally find magic like this a bit annoying. With the current behavior, I can resize the terminal to have the matrices display nicer if the overflow is slight. There is also no information hidden from me, which there would be if the show method decides to crop a bit in the middle. If the information being printed is too much for your liking, maybe itโ€™s better to avoid displaying very large systems in the REPL in the first place?

If the show method can be implemented such that the block-arrays style is used when it fits completely without cropping, but the current display style is used otherwise, perhaps that could be an okay compromise? I donโ€™t really want to introduce any cropping, unless perhaps the matrices are very large.