Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 13 additions & 54 deletions src/types/StateSpace.jl
Original file line number Diff line number Diff line change
Expand Up @@ -223,59 +223,40 @@ function isapprox(sys1::ST1, sys2::ST2; kwargs...) where {ST1<:AbstractStateSpac
end

## ADDITION ##
Base.zero(sys::AbstractStateSpace) = ss(zero(sys.D), sys.timeevol)
Base.zero(sys::AbstractStateSpace) = basetype(sys)(zero(sys.D), sys.timeevol)
Base.zero(::Type{StateSpace{Continuous, F}}) where {F} = ss([zero(F)], Continuous()) # Cannot make a zero of discrete system since sample time is not stored in type.

function +(s1::StateSpace{TE,T}, s2::StateSpace{TE,T}) where {TE,T}
function +(s1::ST, s2::ST) where {ST <: AbstractStateSpace}
#Ensure systems have same dimensions
if size(s1) != size(s2)
error("Systems have different shapes.")
end
timeevol = common_timeevol(s1,s2)
T = promote_type(numeric_type(s1), numeric_type(s2))

A = [s1.A zeros(T, nstates(s1), nstates(s2));
zeros(T, nstates(s2), nstates(s1)) s2.A]
B = [s1.B ; s2.B]
C = [s1.C s2.C;]
D = [s1.D + s2.D;]

return StateSpace{TE,T}(A, B, C, D, timeevol)
return ST(A, B, C, D, timeevol)
end

function +(s1::HeteroStateSpace, s2::HeteroStateSpace)
#Ensure systems have same dimensions
if size(s1) != size(s2)
error("Systems have different shapes.")
end
timeevol = common_timeevol(s1,s2)
T = promote_type(eltype(s1.A),eltype(s2.A))
A = [s1.A zeros(T, nstates(s1), nstates(s2));
zeros(T, nstates(s2), nstates(s1)) s2.A]
B = [s1.B ; s2.B]
C = [s1.C s2.C;]
D = [s1.D + s2.D;]

return HeteroStateSpace(A, B, C, D, timeevol)
end

+(sys::ST, n::Number) where ST <: AbstractStateSpace = ST(sys.A, sys.B, sys.C, sys.D .+ n, sys.timeevol)
+(sys::ST, n::Number) where ST <: AbstractStateSpace = basetype(ST)(sys.A, sys.B, sys.C, sys.D .+ n, sys.timeevol)
+(n::Number, sys::ST) where ST <: AbstractStateSpace = +(sys, n)
+(sys::StateSpace, n::Number) = ss(sys.A, sys.B, sys.C, sys.D .+ n, sys.timeevol)
function +(sys::HeteroStateSpace, n::Number)
HeteroStateSpace(sys.A, sys.B, sys.C, sys.D .+ n, sys.timeevol)
end

## SUBTRACTION ##
-(sys1::AbstractStateSpace, sys2::AbstractStateSpace) = +(sys1, -sys2)
-(sys::AbstractStateSpace, n::Number) = +(sys, -n)
-(n::Number, sys::AbstractStateSpace) = +(-sys, n)

## NEGATION ##
-(sys::ST) where ST <: AbstractStateSpace = ST(sys.A, sys.B, -sys.C, -sys.D, sys.timeevol)
-(sys::StateSpace) = ss(sys.A, sys.B, -sys.C, -sys.D, sys.timeevol)
-(sys::ST) where ST <: AbstractStateSpace = basetype(ST)(sys.A, sys.B, -sys.C, -sys.D, sys.timeevol)

## MULTIPLICATION ##
function *(sys1::StateSpace{TE,T}, sys2::StateSpace{TE,T}) where {TE,T}
function *(sys1::ST, sys2::ST) where {ST <: AbstractStateSpace}
#Check dimension alignment
#Note: sys1*sys2 = y <- sys1 <- sys2 <- u
if xor(issiso(sys1), issiso(sys2))
Expand All @@ -288,39 +269,17 @@ function *(sys1::StateSpace{TE,T}, sys2::StateSpace{TE,T}) where {TE,T}
error("sys1*sys2: sys1 must have same number of inputs as sys2 has outputs")
end
timeevol = common_timeevol(sys1,sys2)
T = promote_type(numeric_type(sys1), numeric_type(sys2))

A = [sys1.A sys1.B*sys2.C;
zeros(T, sys2.nx, sys1.nx) sys2.A]
B = [sys1.B*sys2.D ; sys2.B]
C = [sys1.C sys1.D*sys2.C;]
D = [sys1.D*sys2.D;]
return StateSpace{TE,T}(A, B, C, D, timeevol)
end

function *(sys1::HeteroStateSpace, sys2::HeteroStateSpace)
#Check dimension alignment
#Note: sys1*sys2 = y <- sys1 <- sys2 <- u
if xor(issiso(sys1), issiso(sys2))
if issiso(sys1)
sys1 = append(fill(sys1, sys2.ny)...)
else
sys2 = append(fill(sys2, sys1.nu)...)
end
elseif sys1.nu != sys2.ny
error("sys1*sys2: sys1 must have same number of inputs as sys2 has outputs")
end
timeevol = common_timeevol(sys1,sys2)
T = promote_type(eltype(sys1.A),eltype(sys2.A))
A = [sys1.A sys1.B*sys2.C;
zeros(T, sys2.nx, sys1.nx) sys2.A]
B = [sys1.B*sys2.D ; sys2.B]
C = [sys1.C sys1.D*sys2.C;]
D = [sys1.D*sys2.D;]

return HeteroStateSpace(A, B, C, D, timeevol)
return basetype(ST)(A, B, C, D, timeevol)
end

*(sys::ST, n::Number) where ST <: AbstractStateSpace = StateSpace(sys.A, sys.B, sys.C*n, sys.D*n, sys.timeevol)
*(sys::ST, n::Number) where ST <: AbstractStateSpace = basetype(ST)(sys.A, sys.B, sys.C*n, sys.D*n, sys.timeevol)
*(n::Number, sys::AbstractStateSpace) = *(sys, n)

## DIVISION ##
Expand All @@ -334,11 +293,11 @@ function /(n::Number, sys::ST) where ST <: AbstractStateSpace
catch
error("D isn't invertible")
end
return ST(A - B*Dinv*C, B*Dinv, -n*Dinv*C, n*Dinv, sys.timeevol)
return basetype(ST)(A - B*Dinv*C, B*Dinv, -n*Dinv*C, n*Dinv, sys.timeevol)
end

Base.inv(sys::AbstractStateSpace) = 1/sys
/(sys::ST, n::Number) where ST <: AbstractStateSpace = ST(sys.A, sys.B, sys.C/n, sys.D/n, sys.timeevol)
/(sys::ST, n::Number) where ST <: AbstractStateSpace = basetype(ST)(sys.A, sys.B, sys.C/n, sys.D/n, sys.timeevol)


#####################################################################
Expand All @@ -355,7 +314,7 @@ function Base.getindex(sys::ST, inds...) where ST <: AbstractStateSpace
error("Must specify 2 indices to index statespace model")
end
rows, cols = index2range(inds...) # FIXME: ControlSystems.index2range(inds...)
return ST(copy(sys.A), sys.B[:, cols], sys.C[rows, :], sys.D[rows, cols], sys.timeevol)
return basetype(ST)(copy(sys.A), sys.B[:, cols], sys.C[rows, :], sys.D[rows, cols], sys.timeevol)
end

function Base.getproperty(sys::AbstractStateSpace, s::Symbol)
Expand Down
3 changes: 3 additions & 0 deletions src/types/conversion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ end
Base.convert(::Type{HeteroStateSpace{TE1,AT,BT,CT,DT}}, s::StateSpace{TE2,T}) where {TE1,TE2,T,AT,BT,CT,DT} =
HeteroStateSpace{TE1,AT,BT,CT,DT}(s.A,s.B,s.C,s.D,TE1(s.timeevol))

Base.convert(::Type{HeteroStateSpace{TE,AT,BT,CT,DT}}, s::HeteroStateSpace) where {TE,AT,BT,CT,DT} =
HeteroStateSpace{TE,AT,BT,CT,DT}(AT(s.A),BT(s.B),CT(s.C),DT(s.D),TE(s.timeevol))

Base.convert(::Type{HeteroStateSpace}, s::StateSpace) = HeteroStateSpace(s)

Base.convert(::Type{StateSpace}, s::HeteroStateSpace) = StateSpace(s.A, s.B, s.C, s.D, s.Ts)
Expand Down
3 changes: 3 additions & 0 deletions src/types/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ Base.promote_rule(::Type{StateSpace{TE1,T1}}, ::Type{StateSpace{TE2,T2}}) where
Base.promote_rule(::Type{StateSpace{TE1,T}}, ::Type{HeteroStateSpace{TE2,AT,BT,CT,DT}}) where {TE1,TE2,T,AT,BT,CT,DT} =
HeteroStateSpace{promote_type(TE1, TE2),promote_type(Matrix{T},AT),promote_type(Matrix{T},BT),promote_type(Matrix{T},CT),promote_type(Matrix{T},DT)}

Base.promote_rule(::Type{HeteroStateSpace{TE1,AT,BT,CT,DT}}, ::Type{HeteroStateSpace{TE2,AS,BS,CS,DS}}) where {TE1,TE2,AT,BT,CT,DT,AS,BS,CS,DS} =
HeteroStateSpace{promote_type(TE1,TE2),promote_type(AT,AS),promote_type(BT,BS),promote_type(CT,CS),promote_type(DT,DS)}

Base.promote_rule(::Type{TransferFunction{TE1,S1}}, ::Type{StateSpace{TE2,T2}}) where {TE1,TE2,T1,S1<:SisoTf{T1},T2} =
StateSpace{promote_type(TE1, TE2), promote_type(T1,T2)}

Expand Down
2 changes: 2 additions & 0 deletions src/utilities.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Are only really needed for cases when we accept general LTISystem
# we should either use them consistently, with a good definition, or remove them
basetype(sys::LTISystem) = basetype(typeof(sys))
basetype(::Type{T}) where T <: LTISystem = T.name.wrapper
numeric_type(::Type{SisoRational{T}}) where T = T
numeric_type(::Type{<:SisoZpk{T}}) where T = T
numeric_type(sys::SisoTf) = numeric_type(typeof(sys))
Expand Down
6 changes: 6 additions & 0 deletions test/test_conversion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,10 @@ Hd = zpk([], [1, 0.5], 1.0, h)
# Error, not proper
@test_throws ErrorException ss(tf([1,0],[1]))

s1 = HeteroStateSpace(zeros(Int, 1,1),zeros(Int, 1,1),zeros(Int, 1,1),zeros(Int, 1,1))
s2 = HeteroStateSpace(zeros(Float64, 1,1),zeros(Float64, 1,1),zeros(Float64, 1,1),zeros(Float64, 1,1))
s3,s4 = promote(s1,s2)
@test s3 == s4 == s2
@test typeof(s3) == typeof(s4) == typeof(s2)

end
5 changes: 5 additions & 0 deletions test/test_promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,10 @@ TG2 = typeof(G2)
@test promote(ss(1), tf([1 .*im])) == (ss([1+0*im]),ss([1 .*im]))
@test promote(tf(1), 1) == (tf(1.), tf(1.))

T1 = HeteroStateSpace{Continuous, Matrix{Int64}, Matrix{Int64}, Matrix{Int32}, Matrix{Int64}}
T2 = HeteroStateSpace{Continuous, Matrix{Float64}, Matrix{Float64}, Matrix{Float32}, Matrix{Float64}}
@test promote_type(T1, T2) == T2



end
15 changes: 9 additions & 6 deletions test/test_statespace.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# names: append "_n" if some inputs/outputs/states are named
@testset "test_statespace" begin
# SCALARS
for SS in (StateSpace, HeteroStateSpace)
for SS in (StateSpace, HeteroStateSpace), SS2 in (StateSpace, HeteroStateSpace)
a_2 = [-5 -3; 2 -9]
CS_111 = SS(-5, 2, 3, [0])
CS_111_d = SS([3], 2, 1, 1)
Expand All @@ -20,9 +20,9 @@
# CONTINUOUS
a_1 = [-5]
C_111 = SS(a_1, [2], [3], [0])
C_211 = SS(a_2, [1; 2], [1 0], [0])
C_212 = SS(a_2, [1; 2], eye_(2), [0; 0])
C_221 = SS(a_2, [1 0; 0 2], [1 0], [0 0])
C_211 = SS2(a_2, [1; 2], [1 0], [0])
C_212 = SS2(a_2, [1; 2], eye_(2), [0; 0])
C_221 = SS2(a_2, [1 0; 0 2], [1 0], [0 0])
C_222 = SS(a_2, [1 0; 0 2], eye_(2), zeros(Int,2,2))
C_222_d = SS(a_2, [1 0; 0 2], eye_(2), eye_(2))
C_022 = SS(4.0*eye_(2))
Expand All @@ -31,8 +31,8 @@
da_1 = [-0.5]
da_2 = [0.2 -0.8; -0.8 0.07]
D_111 = SS(da_1, [2], [3], [0], 0.005)
D_211 = SS(da_2, [1; 2], [1 0], [0], 0.005)
D_221 = SS(da_2, [1 0; 0 2], [1 0], [0 0], 0.005)
D_211 = SS2(da_2, [1; 2], [1 0], [0], 0.005)
D_221 = SS2(da_2, [1 0; 0 2], [1 0], [0 0], 0.005)
D_222 = SS(da_2, [1 0; 0 2], eye_(2), zeros(2,2), 0.005)
D_222_d = SS(da_2, [1 0; 0 2], eye_(2), eye_(2), 0.005)
D_022 = SS(4.0*eye_(2), 0.005)
Expand Down Expand Up @@ -87,6 +87,9 @@
@test 1/D_222_d == SS([-0.8 -0.8; -0.8 -1.93],[1 0; 0 2],[-1 0; -0 -1],
[1 -0; 0 1],0.005)

fsys = ss(1,1,1,0)/3 # Int becomes FLoat after division
@test fsys.B[]*fsys.C[] == 1/3

# Indexing
@test size(C_222) == (2, 2)
@test size(C_212) == (2, 1)
Expand Down