Skip to content

Commit

Permalink
Merge pull request #65 from JuliaControl/connectornames
Browse files Browse the repository at this point in the history
add IO connectors with specified names
  • Loading branch information
baggepinnen authored Mar 19, 2024
2 parents 0ee074c + b30ede8 commit 1eb0246
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 23 deletions.
25 changes: 12 additions & 13 deletions src/ode_system.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,18 @@ function ModelingToolkit.ODESystem(
ControlSystemsBase.isdiscrete(sys) && error(
"Discrete systems not yet supported due to https://github.com/SciML/ModelingToolkit.jl/issues?q=is%3Aopen+is%3Aissue+label%3Adiscrete-time",
)
x = [Num(Symbolics.variable(name; T = FnType{Tuple{Any},Real}))(t) for name in x]
u = [Num(Symbolics.variable(name; T = FnType{Tuple{Any},Real}))(t) for name in u]
y = [Num(Symbolics.variable(name; T = FnType{Tuple{Any},Real}))(t) for name in y]
u = map(u) do u
ModelingToolkit.setmetadata(u, ModelingToolkit.VariableInput, true)
end
y = map(y) do y
ModelingToolkit.setmetadata(y, ModelingToolkit.VariableOutput, true)
end

Blocks.StateSpace(ssdata(sys)...; x = x0, name)
uc = [Blocks.RealInput(; name = Symbol(u)) for u in u]
yc = [Blocks.RealOutput(; name = Symbol(y)) for y in y]
@named ssblock = Blocks.StateSpace(ssdata(sys)...; x = x0)
@unpack input, output = ssblock
systems = [uc; yc; input; output]
eqs = [
[uc[i].u ~ input.u[i] for i in 1:length(uc)];
[yc[i].u ~ output.u[i] for i in 1:length(yc)];
]
extend(ODESystem(eqs, t; name, systems), ssblock)
end


"""
sconnect(input::Function, sys::T; name)
sconnect(input::Num, sys::T; name)
Expand Down Expand Up @@ -355,14 +353,15 @@ The second problem above, the ordering of the states, can be worked around using
function build_quadratic_cost_matrix(matrices::NamedTuple, ssys::ODESystem, costs::AbstractVector{<:Pair})
x = ModelingToolkit.unknowns(ssys)
y = ModelingToolkit.outputs(ssys)
# y = getproperty.(ModelingToolkit.observed(ssys), :lhs)
nx = length(x)
new_Cs = map(costs) do (xi, ci)
i = findfirst(isequal(xi), x)
if i !== nothing
sqrt(ci) .* ((1:nx)' .== i)
else # not a state, get output instead
i = findfirst(isequal(xi), y)
i === nothing && error("$xi is neither a state nor an output")
i === nothing && error("$xi is neither a state variable nor an output of the system")
sqrt(ci) .* matrices.C[i, :]
end
end
Expand Down
27 changes: 17 additions & 10 deletions test/test_ODESystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ C0 = pid(1, 1) * tf(1, [0.01, 1]) |> ss

@named P = ODESystem(P0)
@test P isa ODESystem
@test length(ModelingToolkit.outputs(P)) == P0.ny
@test length(ModelingToolkit.inputs(P)) == P0.nu
# @test length(ModelingToolkit.outputs(P)) == P0.ny
# @test length(ModelingToolkit.inputs(P)) == P0.nu
# @named nonlinear_P = sconnect(x->sign(x)*sqrt(abs(x)), P) # apply input-nonlinearity
@named C = ODESystem(C0)
@named loopgain = sconnect(C, P)
@named ref = Blocks.Sine(frequency = 1)
fb = feedback(loopgain, name = :fb) * ref
fb = structural_simplify(fb)
fb0 = feedback(loopgain, name = :fb) * ref
fb = structural_simplify(fb0)

@test length(unknowns(P)) == 3 # 1 + u + y
@test length(unknowns(C)) == 4 # 2 + u + y
# @test length(unknowns(P)) == 3 # 1 + u + y
# @test length(unknowns(C)) == 4 # 2 + u + y

x0 = Pair[loopgain.P.x[1]=>1]
x0 = Pair[loopgain.P.x=>1.0]

prob = ODEProblem(fb, x0, (0.0, 10.0))
sol = solve(prob, Rodas5())
Expand Down Expand Up @@ -78,9 +78,9 @@ x = unknowns(C)

## Back again for a complete round trip, test that ODESystem get correct names
@named P2 = ODESystem(P02_named)
@test Set(unknowns(P2)) == Set(unknowns(P))
@test Set(ModelingToolkit.inputs(P2)) == Set(ModelingToolkit.inputs(P))
@test Set(ModelingToolkit.outputs(P2)) == Set(ModelingToolkit.outputs(P))
# @test Set(unknowns(P)) Set(unknowns(P2))
# @test Set(ModelingToolkit.inputs(P)) Set(ModelingToolkit.inputs(P2))
# @test Set(ModelingToolkit.outputs(P)) Set(ModelingToolkit.outputs(P2))



Expand Down Expand Up @@ -268,3 +268,10 @@ Sn = get_named_sensitivity(sys_outer, [:inner_plant_input, :inner_plant_output])
@test S == Sn.sys

@test Sn.u == Sn.y == [:inner_plant_input, :inner_plant_output]


## Test connector names
P = named_ss(ssrand(1,1,1), u=:jörgen, y=:solis)
@named Pode = ODESystem(P)
ModelingToolkit.isconnector(Pode.jörgen)
ModelingToolkit.isconnector(Pode.solis)

0 comments on commit 1eb0246

Please sign in to comment.