From ae72457e5279a609b4250d47a11ba580bce5f693 Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Fri, 10 Jan 2025 11:43:40 +0100 Subject: [PATCH] QOL improvements for named systems --- src/named_systems2.jl | 27 +++++++++++++++++++++++++++ test/test_diskmargin.jl | 8 ++++++-- test/test_named_systems2.jl | 14 +++++++++++++- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/named_systems2.jl b/src/named_systems2.jl index 38e3b798..bd5730d4 100644 --- a/src/named_systems2.jl +++ b/src/named_systems2.jl @@ -47,6 +47,9 @@ end NamedStateSpace(A,B,C,D,x::AbstractVector,u,y,name::String="") = NamedStateSpace{Continuous, StateSpace{Continuous, eltype(A)}}(ss(A,B,C,D), x, u, y, name) NamedStateSpace(A,B,C,D,Ts::Number,x,u,y,name::String="") = NamedStateSpace{Discrete{typeof(Ts)}, StateSpace{Discrete{typeof(Ts)}, eltype(A)}}(ss(A,B,C,D,Ts), x, u, y,name) +# This method is used by the basetype(ST)(A, B, C, D, timeevol) construct +NamedStateSpace(A,B,C,D,te::ControlSystemsBase.TimeEvolution, args...; kwargs...) = named_ss(ss(A,B,C,D,te), args...; kwargs...) + function Base.promote_rule(::Type{U}, ::Type{NamedStateSpace{T, S}}) where {T, U<:AbstractStateSpace{T} , S<:AbstractStateSpace{T}} inner = promote_type(U,S) @@ -70,6 +73,10 @@ function Base.promote_rule(::Type{U}, ::Type{NamedStateSpace{T, S}}) where NamedStateSpace{T, inner} end +function Base.promote_rule(::Type{NamedStateSpace{TE, StateSpace{TE, T1}}}, ::Type{N}) where {TE, T1, N<:Number} + NamedStateSpace{TE, StateSpace{TE, promote_type(T1,N)}} +end + function Base.convert(::Type{NamedStateSpace{T, S}}, s::U) where {T, S <: AbstractStateSpace, U <: AbstractStateSpace} @@ -93,6 +100,12 @@ function Base.convert(::Type{NamedStateSpace{T, S}}, s::U) where {T, S <: Abstra named_ss(s2, x = gensym("x"), u = gensym("u"), y = gensym("y")) end +function Base.convert(::Type{NamedStateSpace{T, S}}, N::Number) where {T, S <: AbstractStateSpace} + te = T <: Discrete ? Discrete(ControlSystemsBase.UNDEF_SAMPLEPETIME) : Continuous() + NT = numeric_type(S) + named_ss(tf(NT(N), te), x = gensym("x"), u = gensym("u"), y = gensym("y")) +end + # function Base.convert(::Type{TransferFunction{TE, S}}, s::U) where {TE, S, U <: NamedStateSpace{TE}} # convert(TransferFunction{TE, S}, s.sys) # end @@ -199,6 +212,11 @@ named_ss(G::LTISystem, args...; kwargs...) = named_ss(ss(G), args...; kwargs...) ControlSystemsBase.ss(sys::NamedStateSpace) = ss(sys.sys) +function ControlSystemsBase.StaticStateSpace(sys::NamedStateSpace) + ssys = StaticStateSpace(sys.sys) + named_ss(ssys, sys.name; sys.x, sys.u, sys.y) +end + iterable(s::Symbol) = [s] iterable(v) = v @@ -330,6 +348,15 @@ end function Base.:/(s::NamedStateSpace{T, S}, n::Number) where {T <: CS.TimeEvolution, S} s*(1/n) end + +function Base.:/(n::Number, sys::NamedStateSpace) + isys = n / sys.sys + if isone(n) + return named_ss(isys, sys.name*"_inverse", x = sys.x, u = sys.y, y = sys.u) + else + return named_ss(isys, sys.name*"_scaled_inverse") + end +end ## function Base.hcat(systems::NamedStateSpace{T,S}...) where {T,S} diff --git a/test/test_diskmargin.jl b/test/test_diskmargin.jl index 4fdb2163..896c4d1e 100644 --- a/test/test_diskmargin.jl +++ b/test/test_diskmargin.jl @@ -1,4 +1,4 @@ -using ControlSystemsBase, RobustAndOptimalControl, MonteCarloMeasurements +using ControlSystemsBase, RobustAndOptimalControl, MonteCarloMeasurements, Test # using RobustAndOptimalControl: bisect_a # Example from the diskmargin paper @@ -21,7 +21,11 @@ gainphaseplot(L) @test dm.phasemargin == dm.ϕm @test :gainmargin ∈ propertynames(dm) - +dm = diskmargin(named_ss(L), 0) +@test dm.ω0 ≈ 1.94 atol=0.02 +@test dm.γmin ≈ 0.63 atol=0.02 +@test dm.γmax ≈ 1.59 atol=0.02 +@test dm.α ≈ 0.46 atol=0.02 ## Frequency-dependent margin w = exp10.(LinRange(-2, 2, 500)) diff --git a/test/test_named_systems2.jl b/test/test_named_systems2.jl index 1917d735..52cfb4a2 100644 --- a/test/test_named_systems2.jl +++ b/test/test_named_systems2.jl @@ -425,4 +425,16 @@ sys12 = connect( @test sys12.B[1:2,1] == sys1.B[:, 1] @test sys12.B[:,2] == [sys1.B[:, 2]; sys2.B[:, 1]] -@test sys12.B[3:4,3] == sys2.B[:, 2] \ No newline at end of file +@test sys12.B[3:4,3] == sys2.B[:, 2] + +## Inv +s1 = named_ss(ssrand(2,2,2)) +isys = inv(s1) +@test isys.sys == inv(s1.sys) +@test isys.x == s1.x +@test isys.u == s1.y # Names are reversed +@test isys.y == s1.u + +isys = 2/s1 +@test isys.sys == 2/s1.sys +@test isys.x != s1.x \ No newline at end of file