Skip to content

Commit aa28cef

Browse files
authored
Merge pull request #41 from JuliaControl/coprime
add balanced truncation on coprime factors
2 parents 3a75d7a + 4f4667c commit aa28cef

4 files changed

Lines changed: 69 additions & 43 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "RobustAndOptimalControl"
22
uuid = "21fd56a4-db03-40ee-82ee-a87907bee541"
33
authors = ["Fredrik Bagge Carlson", "Marcus Greiff"]
4-
version = "0.3.3"
4+
version = "0.3.4"
55

66
[deps]
77
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"

src/RobustAndOptimalControl.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ using ChainRulesCore
2424
export show_construction, vec2sys
2525
include("utils.jl")
2626

27-
export dss, hinfnorm2, h2norm, hankelnorm, nugap, νgap, baltrunc2, stab_unstab, baltrunc_unstab
27+
export dss, hinfnorm2, h2norm, hankelnorm, nugap, νgap, baltrunc2, stab_unstab, baltrunc_unstab, baltrunc_coprime
2828
include("descriptor.jl")
2929

3030
export ExtendedStateSpace, system_mapping, performance_mapping, noise_mapping, ssdata_e, partition, ss

src/descriptor.jl

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,23 +86,37 @@ function baltrunc2(sys::LTISystem; residual=false, n=missing, kwargs...)
8686
ss(sysr), hs
8787
end
8888

89-
# function coprime_baltrunc(sys; residual=false, n=missing, kwargs...)
90-
# N,M = DescriptorSystems.glcf(dss(sys), mindeg=true, mininf=true, fast=false)
91-
# nu = size(N.B, 2)
92-
# # A,E,B,C,D = DescriptorSystems.dssdata(N)
93-
# # NM = DescriptorSystems.dss(A,E,[B M.B],C,[D M.D])
94-
# # Nr1, hs = DescriptorSystems.gbalmr(N; matchdc=residual, ord=n-size(M.A, 1), kwargs...)
95-
# NM = [N M]
96-
# sysr, hs = DescriptorSystems.gbalmr(NM; matchdc=residual, ord=n, kwargs...)
97-
98-
# A,E,B,C,D = DescriptorSystems.dssdata(sysr)
99-
100-
# Nr = DescriptorSystems.dss(A,E,B[:, 1:nu],C,D[:, 1:nu])
101-
# Mr = DescriptorSystems.dss(A,E,B[:, nu+1:end],C,D[:, nu+1:end])
102-
# sysr = Mr \ Nr
103-
# ss(sysr), hs
104-
# # Nr, Mr
105-
# end
89+
"""
90+
baltrunc_coprime(sys; residual = false, n = missing, factorization::F = DescriptorSystems.glcf, kwargs...)
91+
92+
Compute a balanced truncation of the left coprime factorization of `sys`.
93+
See [`baltrunc2`](@ref) for additional keyword-argument help.
94+
95+
# Arguments:
96+
- `factorization`: The function to perform the coprime factorization. A normalized factorization may be used by passing `RobustAndOptimalControl.DescriptorSystems.gnlcf`.
97+
- `kwargs`: Are passed to `DescriptorSystems.gbalmr`
98+
"""
99+
function baltrunc_coprime(sys; residual=false, n=missing, factorization::F = DescriptorSystems.glcf, kwargs...) where F
100+
N,M = factorization(dss(sys))
101+
nu = size(N.B, 2)
102+
A,E,B,C,D = DescriptorSystems.dssdata(N)
103+
NM = DescriptorSystems.dss(A,E,[B M.B],C,[D M.D])
104+
sysr, hs = DescriptorSystems.gbalmr(NM; matchdc=residual, ord=n, kwargs...)
105+
106+
A,E,B,C,D = DescriptorSystems.dssdata(DescriptorSystems.dss2ss(sysr)[1])
107+
108+
BN = B[:, 1:nu]
109+
DN = D[:, 1:nu]
110+
BM = B[:, nu+1:end]
111+
DMi = pinv(D[:, nu+1:end])
112+
113+
Ar = A - BM * (DMi * C)
114+
Cr = (DMi * C)
115+
Br = BN - BM * (DMi * DN)
116+
Dr = (DMi * DN)
117+
118+
ss(Ar,Br,Cr,Dr,sys.timeevol), hs
119+
end
106120

107121

108122
"""

test/test_descriptor.jl

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,27 +23,39 @@ end >= 94
2323

2424

2525
##
26-
# sys = ssrand(2,3,4, stable=false)
27-
# # N,M = coprime_baltrunc(sys, n=3)
28-
# sysr, _ = coprime_baltrunc(sys, n=3)
29-
30-
# @test sysr.nx == 3
31-
32-
# bodeplot([sys, sysr])
33-
34-
## stab_unstab
35-
sys = ssrand(2,3,40, stable=false)
36-
stab, unstab = stab_unstab(sys)
37-
@test all(real(poles(stab)) .< 0)
38-
@test all(real(poles(unstab)) .>= 0)
39-
@test linfnorm(stab + unstab - sys)[1] < 1e-8
40-
41-
## baltrunc_unstab
42-
sys = ssrand(2,3,40, stable=true)
43-
sysus = ssrand(2,3,2, stable=true)
44-
sysus.A .*= -1
45-
sys = sys + sysus
46-
sysr, hs = baltrunc_unstab(sys, n=20)
47-
@test sysr.nx == 20
48-
@test linfnorm(sysr - sys)[1] < 1e-3
49-
# bodeplot([sys, sysr])
26+
@testset "unstable baltrunc" begin
27+
@info "Testing unstable baltrunc"
28+
for proper = [true, false]
29+
sys = ssrand(2,3,40; stable=true, proper)
30+
sysus = ssrand(2,3,2; stable=true, proper)
31+
sysus.A .*= -1
32+
sys = sys + sysus
33+
34+
sysr, hs = RobustAndOptimalControl.baltrunc_coprime(sys, n=20, factorization = RobustAndOptimalControl.DescriptorSystems.glcf)
35+
36+
@test sysr.nx <= 20
37+
@test linfnorm(sysr - sys)[1] < 9e-3
38+
39+
e = poles(sysr)
40+
@test count(e->real(e)>0, e) == 2 # test that the two unstable poles were preserved
41+
# bodeplot([sys, sysr])
42+
end
43+
44+
## stab_unstab
45+
sys = ssrand(2,3,40, stable=false)
46+
stab, unstab = stab_unstab(sys)
47+
@test all(real(poles(stab)) .< 0)
48+
@test all(real(poles(unstab)) .>= 0)
49+
@test linfnorm(stab + unstab - sys)[1] < 1e-8
50+
51+
## baltrunc_unstab
52+
sys = ssrand(2,3,40, stable=true)
53+
sysus = ssrand(2,3,2, stable=true)
54+
sysus.A .*= -1
55+
sys = sys + sysus
56+
sysr, hs = baltrunc_unstab(sys, n=20)
57+
@test sysr.nx <= 20
58+
@test linfnorm(sysr - sys)[1] < 1e-3
59+
# bodeplot([sys, sysr])
60+
61+
end

0 commit comments

Comments
 (0)