From e6646060ed10370d09f4612a697ab50b8f900a55 Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Mon, 3 Jan 2022 08:20:11 +0100 Subject: [PATCH 1/4] allow broadcast multiplication with siso tfs --- src/types/TransferFunction.jl | 16 ++++++++++++++++ test/test_transferfunction.jl | 3 +++ 2 files changed, 19 insertions(+) diff --git a/src/types/TransferFunction.jl b/src/types/TransferFunction.jl index d02acb591..bf2c5a885 100644 --- a/src/types/TransferFunction.jl +++ b/src/types/TransferFunction.jl @@ -143,6 +143,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_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]), From 836fdf81342182f46ea97b66d62d0a8c9752a1d1 Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Mon, 3 Jan 2022 08:21:24 +0100 Subject: [PATCH 2/4] add less strictly typed constructor for ss --- src/types/StateSpace.jl | 1 + test/test_statespace.jl | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/types/StateSpace.jl b/src/types/StateSpace.jl index 913ab7575..75d28349b 100644 --- a/src/types/StateSpace.jl +++ b/src/types/StateSpace.jl @@ -268,6 +268,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/test/test_statespace.jl b/test/test_statespace.jl index f759d238b..bb6159061 100644 --- a/test/test_statespace.jl +++ b/test/test_statespace.jl @@ -120,7 +120,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 From 15af23537d39bf961e74ba85713a1bb859ed9958 Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Mon, 3 Jan 2022 08:26:35 +0100 Subject: [PATCH 3/4] add hint at broadcast functionality in error message --- src/types/TransferFunction.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/types/TransferFunction.jl b/src/types/TransferFunction.jl index bf2c5a885..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) From 575db72f4d5fabfd480d2071e0277339fa645ba9 Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Mon, 3 Jan 2022 09:14:50 +0100 Subject: [PATCH 4/4] handle + Number of different type --- src/types/StateSpace.jl | 4 ++++ test/test_statespace.jl | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/types/StateSpace.jl b/src/types/StateSpace.jl index 75d28349b..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) diff --git a/test/test_statespace.jl b/test/test_statespace.jl index bb6159061..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])