From 695e4b9ebaba809b398c0968b0127c610cf263c1 Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Tue, 17 Jun 2025 07:10:28 +0200 Subject: [PATCH 1/5] add `find_similarity_transform` this was previously implemented in ControlSystemIdentification --- lib/ControlSystemsBase/Project.toml | 2 +- lib/ControlSystemsBase/src/matrix_comps.jl | 38 ++++++++++++++++++- .../test/test_matrix_comps.jl | 13 +++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/lib/ControlSystemsBase/Project.toml b/lib/ControlSystemsBase/Project.toml index 9cc72f056..cc90a664a 100644 --- a/lib/ControlSystemsBase/Project.toml +++ b/lib/ControlSystemsBase/Project.toml @@ -2,7 +2,7 @@ name = "ControlSystemsBase" uuid = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e" authors = ["Dept. Automatic Control, Lund University"] repo = "https://github.com/JuliaControl/ControlSystems.jl.git" -version = "1.16.1" +version = "1.17.0" [deps] ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" diff --git a/lib/ControlSystemsBase/src/matrix_comps.jl b/lib/ControlSystemsBase/src/matrix_comps.jl index bf7bb2ea8..5e14f4a7c 100644 --- a/lib/ControlSystemsBase/src/matrix_comps.jl +++ b/lib/ControlSystemsBase/src/matrix_comps.jl @@ -710,7 +710,7 @@ D̃ = D ``` If `unitary=true`, `T` is assumed unitary and the matrix adjoint is used instead of the inverse. -See also [`balance_statespace`](@ref). +See also [`balance_statespace`](@ref), [`find_similarity_transform`](@ref). """ function similarity_transform(sys::ST, T; unitary=false) where ST <: AbstractStateSpace if unitary @@ -726,6 +726,42 @@ function similarity_transform(sys::ST, T; unitary=false) where ST <: AbstractSta ST(A,B,C,D,sys.timeevol) end +""" + find_similarity_transform(sys1, sys2, method = :obsv) + +Find T such that `ControlSystemsBase.similarity_transform(sys1, T) == sys2` + +Ref: Minimal state-space realization in linear system theory: an overview, B. De Schutter + +If `method == :obsv`, the observability matrices of `sys1` and `sys2` are used to find `T`, whereas `method == :ctrb` uses the controllability matrices. + +```jldoctest +julia> T = randn(3,3); + +julia> sys1 = ssrand(1,1,3); + +julia> sys2 = ControlSystemsBase.similarity_transform(sys1, T); + +julia> T2 = find_similarity_transform(sys1, sys2); + +julia> T2 ≈ T +true +``` +""" +function find_similarity_transform(sys1, sys2, method = :obsv) + if method === :obsv + O1 = obsv(sys1) + O2 = obsv(sys2) + return O1\O2 + elseif method === :ctrb + C1 = ctrb(sys1) + C2 = ctrb(sys2) + return C1/C2 + else + error("Unknown method $method") + end +end + """ time_scale(sys::AbstractStateSpace{Continuous}, a; balanced = false) time_scale(G::TransferFunction{Continuous}, a; balanced = true) diff --git a/lib/ControlSystemsBase/test/test_matrix_comps.jl b/lib/ControlSystemsBase/test/test_matrix_comps.jl index 174b40aa4..ff3a72495 100644 --- a/lib/ControlSystemsBase/test/test_matrix_comps.jl +++ b/lib/ControlSystemsBase/test/test_matrix_comps.jl @@ -39,6 +39,19 @@ sysdb, _ = balance_statespace(sysd) @test ControlSystemsBase.balance_transform(A,B,C) ≈ ControlSystemsBase.balance_transform(sys) +@testset "similarity transform" begin + @info "Testing similarity transform" + T = randn(3,3) + sys1 = ssrand(1,1,3) + sys2 = ControlSystemsBase.similarity_transform(sys1, T) + T2 = ControlSystemIdentification.find_similarity_transform(sys1, sys2) + @test T2 ≈ T atol=1e-8 + + T3 = ControlSystemIdentification.find_similarity_transform(sys1, sys2, :ctrb) + @test T3 ≈ T atol=1e-8 + +end + W = [1 0; 0 1] @test covar(sys, W) ≈ [0.002560975609756 0.002439024390244; 0.002439024390244 0.002560975609756] D2 = [1 0; 0 1] From 130456f5bf7c4a91b02ab6a83bfdbd8397718fba Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Tue, 17 Jun 2025 07:11:34 +0200 Subject: [PATCH 2/5] export --- lib/ControlSystemsBase/src/ControlSystemsBase.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ControlSystemsBase/src/ControlSystemsBase.jl b/lib/ControlSystemsBase/src/ControlSystemsBase.jl index e871290bc..8e991ad90 100644 --- a/lib/ControlSystemsBase/src/ControlSystemsBase.jl +++ b/lib/ControlSystemsBase/src/ControlSystemsBase.jl @@ -44,6 +44,7 @@ export LTISystem, balreal, baltrunc, similarity_transform, + find_similarity_transform, time_scale, innovation_form, observer_predictor, From e4127f5343dad930d5cbf136118214ca174470be Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Tue, 17 Jun 2025 08:01:46 +0200 Subject: [PATCH 3/5] fix --- lib/ControlSystemsBase/test/test_matrix_comps.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ControlSystemsBase/test/test_matrix_comps.jl b/lib/ControlSystemsBase/test/test_matrix_comps.jl index ff3a72495..5595d21d0 100644 --- a/lib/ControlSystemsBase/test/test_matrix_comps.jl +++ b/lib/ControlSystemsBase/test/test_matrix_comps.jl @@ -44,10 +44,10 @@ sysdb, _ = balance_statespace(sysd) T = randn(3,3) sys1 = ssrand(1,1,3) sys2 = ControlSystemsBase.similarity_transform(sys1, T) - T2 = ControlSystemIdentification.find_similarity_transform(sys1, sys2) + T2 = find_similarity_transform(sys1, sys2) @test T2 ≈ T atol=1e-8 - T3 = ControlSystemIdentification.find_similarity_transform(sys1, sys2, :ctrb) + T3 = find_similarity_transform(sys1, sys2, :ctrb) @test T3 ≈ T atol=1e-8 end From d448c2debb0843005fa05e807a66cb6eab7fb40f Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Tue, 17 Jun 2025 08:49:42 +0200 Subject: [PATCH 4/5] up docstring --- lib/ControlSystemsBase/src/matrix_comps.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ControlSystemsBase/src/matrix_comps.jl b/lib/ControlSystemsBase/src/matrix_comps.jl index 5e14f4a7c..c8193a269 100644 --- a/lib/ControlSystemsBase/src/matrix_comps.jl +++ b/lib/ControlSystemsBase/src/matrix_comps.jl @@ -729,7 +729,7 @@ end """ find_similarity_transform(sys1, sys2, method = :obsv) -Find T such that `ControlSystemsBase.similarity_transform(sys1, T) == sys2` +Find T such that `similarity_transform(sys1, T) == sys2` Ref: Minimal state-space realization in linear system theory: an overview, B. De Schutter @@ -740,7 +740,7 @@ julia> T = randn(3,3); julia> sys1 = ssrand(1,1,3); -julia> sys2 = ControlSystemsBase.similarity_transform(sys1, T); +julia> sys2 = similarity_transform(sys1, T); julia> T2 = find_similarity_transform(sys1, sys2); From 75e421df2bafd055f01d7d860997477aeb53f524 Mon Sep 17 00:00:00 2001 From: Fredrik Bagge Carlson Date: Tue, 17 Jun 2025 08:50:24 +0200 Subject: [PATCH 5/5] up docstring --- lib/ControlSystemsBase/src/matrix_comps.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/ControlSystemsBase/src/matrix_comps.jl b/lib/ControlSystemsBase/src/matrix_comps.jl index c8193a269..3cc8c307c 100644 --- a/lib/ControlSystemsBase/src/matrix_comps.jl +++ b/lib/ControlSystemsBase/src/matrix_comps.jl @@ -736,6 +736,8 @@ Ref: Minimal state-space realization in linear system theory: an overview, B. De If `method == :obsv`, the observability matrices of `sys1` and `sys2` are used to find `T`, whereas `method == :ctrb` uses the controllability matrices. ```jldoctest +julia> using ControlSystemsBase + julia> T = randn(3,3); julia> sys1 = ssrand(1,1,3);