diff --git a/src/types/StateSpace.jl b/src/types/StateSpace.jl index 913ab7575..8dfadaf5a 100644 --- a/src/types/StateSpace.jl +++ b/src/types/StateSpace.jl @@ -260,6 +260,10 @@ end +(sys::ST, n::Number) where ST <: AbstractStateSpace = 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) @@ -268,6 +272,7 @@ end ## 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) ## MULTIPLICATION ## function *(sys1::StateSpace{TE,T}, sys2::StateSpace{TE,T}) where {TE,T} diff --git a/src/types/TransferFunction.jl b/src/types/TransferFunction.jl index d02acb591..7c5bfc461 100644 --- a/src/types/TransferFunction.jl +++ b/src/types/TransferFunction.jl @@ -134,7 +134,11 @@ function *(G1::TransferFunction, G2::TransferFunction) # Note: G1*G2 = y <- G1 <- G2 <- u timeevol = common_timeevol(G1,G2) if G1.nu != G2.ny - error("G1*G2: G1 must have same number of inputs as G2 has outputs") + if issiso(G1) || issiso(G2) + error("G1*G2: G1 must have same number of inputs as G2 has outputs, did you intend to broadcast the multiplication?") + else + error("G1*G2: G1 must have same number of inputs as G2 has outputs") + end end matrix = G1.matrix * G2.matrix return TransferFunction(matrix, timeevol) @@ -143,6 +147,22 @@ end *(G::TransferFunction, n::Number) = TransferFunction(n*G.matrix, G.timeevol) *(n::Number, G::TransferFunction) = *(G, n) +function Base.Broadcast.broadcasted(::typeof(*), G1::TransferFunction, G2::TransferFunction) + issiso(G1) || issiso(G2) || error("Only SISO transfer function can be broadcasted") + # Note: G1*G2 = y <- G1 <- G2 <- u + timeevol = common_timeevol(G1,G2) + matrix = G1.matrix .* G2.matrix + return TransferFunction(matrix, timeevol) +end + +function Base.Broadcast.broadcasted(::typeof(*), G1::TransferFunction, G2::AbstractArray) + issiso(G1) || error("Only SISO transfer function can be broadcasted") + # Note: G1*G2 = y <- G1 <- G2 <- u + timeevol = G1.timeevol + matrix = G1.matrix .* G2 + return TransferFunction(matrix, timeevol) +end + ## DIVISION ## function /(n::Number, G::TransferFunction) if issiso(G) diff --git a/test/test_statespace.jl b/test/test_statespace.jl index f759d238b..f08ada0bb 100644 --- a/test/test_statespace.jl +++ b/test/test_statespace.jl @@ -55,6 +55,13 @@ @test C_222 + 1 == SS([-5 -3; 2 -9],[1 0; 0 2],[1 0; 0 1],[1 1; 1 1]) @test D_111 + D_111 == SS([-0.5 0; 0 -0.5],[2; 2],[3 3],[0], 0.005) + @test C_111 + false == C_111 + @test false + C_111 == C_111 + @test 1.0*C_111 + false == C_111 + + @test C_222 + 1.5 == 1.0C_222 + 1.5 # C_222 has eltype Int + @test 1.5 + C_222 == 1.0C_222 + 1.5 + # Subtraction @test C_111 - C_211 == SS([-5 0 0; 0 -5 -3; 0 2 -9],[2; 1; 2],[3 -1 -0],[0]) @test 1 - C_222 == SS([-5 -3; 2 -9],[1 0; 0 2],[-1 -0; -0 -1],[1 1; 1 1]) @@ -120,7 +127,13 @@ @test sprint(show, D_222) == "StateSpace{Discrete{Float64}, Float64}\nA = \n 0.2 -0.8\n -0.8 0.07\nB = \n 1.0 0.0\n 0.0 2.0\nC = \n 1.0 0.0\n 0.0 1.0\nD = \n 0.0 0.0\n 0.0 0.0\n\nSample Time: 0.005 (seconds)\nDiscrete-time state-space model" end - # Errors + # Different types + K1 = ss(I(2)) # Bool + K2 = ss(1.0I(2)) # Float64 + P = ssrand(3,3,2) + @test lft(P, -K1) == lft(P, -K2) + + # Errors @test_throws ErrorException C_111 + C_222 # Dimension mismatch @test_throws ErrorException C_111 - C_222 # Dimension mismatch @test_throws ErrorException D_111 + C_111 # Sampling time mismatch diff --git a/test/test_transferfunction.jl b/test/test_transferfunction.jl index 392bd3083..d94005ac8 100644 --- a/test/test_transferfunction.jl +++ b/test/test_transferfunction.jl @@ -76,6 +76,9 @@ z = tf("z", 0.005) vecarray(1, 2, [1,-0.7,-0.05,0.075], [1.0,-0.7,-0.05,0.075]), 0.005) == tf(vecarray(1, 2, [0], [0]), vecarray(1, 2, [1], [1]), 0.005) +@test tf(1) .* C_222 == C_222 +@test tf(1) .* I(2) == tf(I(2)) + # Division @test 1/C_111 == tf([1,5], [1,2]) @test C_212/C_111 == tf(vecarray(2, 1, [1,7,13,15], [0,1,7,10]),