diff --git a/src/types/Lti.jl b/src/types/Lti.jl index 654a470da..aaef22e35 100644 --- a/src/types/Lti.jl +++ b/src/types/Lti.jl @@ -72,7 +72,7 @@ function Base.getproperty(sys::LTISystem, s::Symbol) end Base.propertynames(sys::LTISystem, private::Bool=false) = - (fieldnames(typeof(sys))..., (isdiscrete(sys) ? (:Ts,) : ())...) + (fieldnames(typeof(sys))..., :nu, :ny, (isdiscrete(sys) ? (:Ts,) : ())...) diff --git a/src/types/PartionedStateSpace.jl b/src/types/PartionedStateSpace.jl index 3528d7985..39049761a 100644 --- a/src/types/PartionedStateSpace.jl +++ b/src/types/PartionedStateSpace.jl @@ -56,6 +56,10 @@ function getproperty(sys::PartionedStateSpace, d::Symbol) end end +function Base.propertynames(s::PartionedStateSpace, private::Bool=false) + (fieldnames(typeof(s))..., :B1, :B2, :C1, :C2, :D11, :D12, :D21, :D22, :nu, :ny, :nx, (isdiscrete(s) ? (:Ts,) : ())...) +end + timeevol(sys::PartionedStateSpace) = timeevol(sys.P) function +(s1::PartionedStateSpace, s2::PartionedStateSpace) diff --git a/src/types/StateSpace.jl b/src/types/StateSpace.jl index 717052e5d..bf1dd1206 100644 --- a/src/types/StateSpace.jl +++ b/src/types/StateSpace.jl @@ -378,6 +378,10 @@ function Base.getproperty(sys::AbstractStateSpace, s::Symbol) end end +function Base.propertynames(s::AbstractStateSpace, private::Bool=false) + (fieldnames(typeof(s))..., :nu, :ny, :nx, (isdiscrete(s) ? (:Ts,) : ())...) +end + ##################################################################### ## Display Functions ## ##################################################################### diff --git a/src/types/TransferFunction.jl b/src/types/TransferFunction.jl index 29175158a..a36ff0650 100644 --- a/src/types/TransferFunction.jl +++ b/src/types/TransferFunction.jl @@ -1,12 +1,10 @@ struct TransferFunction{TE, S<:SisoTf{T} where T} <: LTISystem{TE} matrix::Matrix{S} timeevol::TE - nu::Int - ny::Int function TransferFunction{TE,S}(matrix::Matrix{S}, timeevol::TE) where {S,TE} # Validate size of input and output names ny, nu = size(matrix) - return new{TE,S}(matrix, timeevol, nu, ny) + return new{TE,S}(matrix, timeevol) end end function TransferFunction(matrix::Matrix{S}, timeevol::TE) where {TE<:TimeEvolution, T<:Number, S<:SisoTf{T}} @@ -35,6 +33,22 @@ Base.size(G::TransferFunction) = size(G.matrix) Base.eltype(::Type{S}) where {S<:TransferFunction} = S Base.zero(G::TransferFunction{TE,S}) where {TE,S} = tf(zeros(numeric_type(S), size(G)), G.timeevol) # can not create a zero of a discrete system from the type alone, the sampletime is not stored. +function Base.getproperty(G::TransferFunction, s::Symbol) + s ∈ fieldnames(typeof(G)) && return getfield(G, s) + if s === :ny + return size(G, 1) + elseif s === :nu + return size(G, 2) + elseif s === :Ts + if isdiscrete(G) + return timeevol(G).Ts + else + @warn "Getting time 0.0 for non-discrete systems is deprecated. Check `isdiscrete` before trying to access time." + return 0.0 + end + throw(ArgumentError("$(typeof(G)) has no property named $s")) + end +end function Base.getindex(G::TransferFunction{TE,S}, inds...) where {TE,S<:SisoTf} if size(inds, 1) != 2 @@ -82,9 +96,9 @@ end ## EQUALITY ## function ==(G1::TransferFunction, G2::TransferFunction) - fields = [:timeevol, :ny, :nu, :matrix] + fields = (:timeevol, :ny, :nu, :matrix) for field in fields - if getfield(G1, field) != getfield(G2, field) + if getproperty(G1, field) != getproperty(G2, field) return false end end @@ -94,9 +108,9 @@ end ## Approximate ## function isapprox(G1::TransferFunction, G2::TransferFunction; kwargs...) G1, G2 = promote(G1, G2) - fieldsApprox = [:timeevol, :matrix] + fieldsApprox = (:timeevol, :matrix) for field in fieldsApprox - if !(isapprox(getfield(G1, field), getfield(G2, field); kwargs...)) + if !(isapprox(getproperty(G1, field), getproperty(G2, field); kwargs...)) return false end end diff --git a/test/test_delayed_systems.jl b/test/test_delayed_systems.jl index cc1d14f95..05e4b0877 100644 --- a/test/test_delayed_systems.jl +++ b/test/test_delayed_systems.jl @@ -156,7 +156,7 @@ w = 10 .^ (-2:0.1:2) @test freqresp(s11, w) ≈ freqresp(f2[1,1], w) rtol=1e-15 -@test propertynames(delay(1.0)) == (:P, :Tau) +@test propertynames(delay(1.0)) == (:P, :Tau, :nu, :ny) #FIXME: A lot more tests, including MIMO systems in particular diff --git a/test/test_partitioned_statespace.jl b/test/test_partitioned_statespace.jl index 57a3a9792..3f0c58160 100644 --- a/test/test_partitioned_statespace.jl +++ b/test/test_partitioned_statespace.jl @@ -42,4 +42,4 @@ sys2 = ControlSystems.PartionedStateSpace(ss(fill(1.0, 2, 2), fill(2.0, 2, 5), f # TODO: Add some tests for interconnections, implicitly tested through delay system implementations though @test (sys1 + sys1).P[1, 1] == (sys1.P[1,1] + sys1.P[1,1]) -@test propertynames(sys1) == (:P, :nu1, :ny1) +@test propertynames(sys1) == (:P, :nu1, :ny1, :B1, :B2, :C1, :C2, :D11, :D12, :D21, :D22, :nu, :ny, :nx) diff --git a/test/test_statespace.jl b/test/test_statespace.jl index f08ada0bb..c4488ae86 100644 --- a/test/test_statespace.jl +++ b/test/test_statespace.jl @@ -116,8 +116,8 @@ @test D_111.Ts == 0.005 # propertynames - @test propertynames(C_111) == (:A, :B, :C, :D, :timeevol) - @test propertynames(D_111) == (:A, :B, :C, :D, :timeevol, :Ts) + @test propertynames(C_111) == (:A, :B, :C, :D, :timeevol, :nu, :ny, :nx) + @test propertynames(D_111) == (:A, :B, :C, :D, :timeevol, :nu, :ny, :nx, :Ts) # Printing if SS <: StateSpace