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
38 changes: 29 additions & 9 deletions src/descriptor.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,16 @@ Compute the a balanced truncation of order `n` and the hankel singular values
For keyword arguments, see the docstring of `DescriptorSystems.gbalmr`, reproduced below
$(@doc(DescriptorSystems.gbalmr))
"""
function baltrunc2(sys::LTISystem; residual=false, n=missing, kwargs...)
sysr, hs = DescriptorSystems.gbalmr(dss(sys); matchdc=residual, ord=n, kwargs...)
ss(sysr), hs
function baltrunc2(sys::LTISystem; residual=false, n=missing, scaleY=1.0, scaleU=1.0, kwargs...)
# Apply scaling if needed
A, B, C, D = ssdata(sys)
# Divide by scaling factors to normalize to ~[-1,1]
sys_scaled = ss(A, B / scaleU, C / scaleY, scaleY \ D / scaleU, sys.timeevol)
sysr, hs = DescriptorSystems.gbalmr(dss(sys_scaled); matchdc=residual, ord=n, kwargs...)
# Multiply by scaling factors to restore original units
Ar, Br, Cr, Dr = ssdata(ss(sysr))
sys_final = ss(Ar, Br * scaleU, scaleY * Cr, scaleY * Dr * scaleU, sys.timeevol)
sys_final, hs
end

"""
Expand All @@ -105,11 +112,15 @@ Coprime-factor reduction performs a coprime factorization of the model into \$P(
- `kwargs`: Are passed to `DescriptorSystems.gbalmr`, the docstring of which is reproduced below:
$(@doc(DescriptorSystems.gbalmr))
"""
function baltrunc_coprime(sys, info=nothing; residual=false, n=missing, factorization::F = DescriptorSystems.gnlcf, kwargs...) where F
function baltrunc_coprime(sys, info=nothing; residual=false, n=missing, factorization::F = DescriptorSystems.gnlcf, scaleY=1.0, scaleU=1.0, kwargs...) where F
# Apply scaling if needed
A, B, C, D = ssdata(sys)
# Divide by scaling factors to normalize to ~[-1,1]
sys_scaled = ss(A, B / scaleU, scaleY \ C, scaleY \ D / scaleU, sys.timeevol)
if info !== nothing && hasproperty(info, :NM)
@unpack N, M, NM = info
else
N,M = factorization(dss(sys))
N,M = factorization(dss(sys_scaled))
A,E,B,C,D = DescriptorSystems.dssdata(N)
NM = DescriptorSystems.dss(A,E,[B M.B],C,[D M.D])
end
Expand All @@ -128,7 +139,9 @@ function baltrunc_coprime(sys, info=nothing; residual=false, n=missing, factoriz
Br = BN - BM * (DMi * DN)
Dr = (DMi * DN)

ss(Ar,Br,Cr,Dr,sys.timeevol), hs, (; NM, N, M, NMr)
# Multiply by scaling factors to restore original units
sys_final = ss(Ar, Br * scaleU, scaleY * Cr, scaleY * Dr * scaleU, sys.timeevol)
sys_final, hs, (; NM, N, M, NMr)
end


Expand All @@ -139,18 +152,25 @@ Balanced truncation for unstable models. An additive decomposition of sys into `

See `baltrunc2` for other keyword arguments.
"""
function baltrunc_unstab(sys::LTISystem, info=nothing; residual=false, n=missing, kwargs...)
function baltrunc_unstab(sys::LTISystem, info=nothing; residual=false, n=missing, scaleY=1.0, scaleU=1.0, kwargs...)
# Apply scaling if needed
A, B, C, D = ssdata(sys)
# Divide by scaling factors to normalize to ~[-1,1]
sys_scaled = ss(A, B / scaleU, scaleY \ C, scaleY \ D / scaleU, sys.timeevol)
if info !== nothing && hasproperty(info, :stab)
@unpack stab, unstab = info
else
stab, unstab = DescriptorSystems.gsdec(dss(sys); job="stable", kwargs...)
stab, unstab = DescriptorSystems.gsdec(dss(sys_scaled); job="stable", kwargs...)
end
nx_unstab = size(unstab.A, 1)
if n isa Integer && n < nx_unstab
error("The model contains $(nx_unstab) poles outside the stability region, the reduced-order model must be of at least this order.")
end
sysr, hs = DescriptorSystems.gbalmr(stab; matchdc=residual, ord=n-nx_unstab, kwargs...)
ss(sysr + unstab), hs, (; stab, unstab)
# Multiply by scaling factors to restore original units
Ar, Br, Cr, Dr = ssdata(ss(sysr + unstab))
sys_final = ss(Ar, Br * scaleU, scaleY * Cr, scaleY * Dr * scaleU, sys.timeevol)
sys_final, hs, (; stab, unstab)
end


Expand Down
35 changes: 34 additions & 1 deletion test/test_reduction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -300,4 +300,37 @@ Ksr, hs, infor = baltrunc_coprime(info.Ks; n)
controller_reduction_plot(info.Gs,info.Ks)
controller_reduction_plot(info.Gs,info.Ks, method=:cr)

# ncfmargin(P, W1*Ksr)
# ncfmargin(P, W1*Ksr)



# === Scaling invariance tests for model reduction ===
using RobustAndOptimalControl: baltrunc2, baltrunc_coprime, baltrunc_unstab

# Simple SISO system

sys_siso = ssrand(1,1,9,proper=true)

# Non-unit scaling factors
scaleY = 5.0
scaleU = 0.2

# baltrunc2: compare frequency response with and without scaling
sysr_noscale, _ = baltrunc2(sys_siso; n=3)
sysr_scale, _ = baltrunc2(sys_siso; n=3, scaleY=scaleY, scaleU=scaleU)
@test sysr_noscale.nx == sysr_scale.nx == 3
@test hinfnorm2(minreal(sysr_noscale - sysr_scale))[1] < 1e-5


# baltrunc_coprime: compare frequency response with and without scaling
sysr_coprime_noscale, _, _ = baltrunc_coprime(sys_siso; n=3)
sysr_coprime_scale, _, _ = baltrunc_coprime(sys_siso; n=3, scaleY=scaleY, scaleU=scaleU)
@test sysr_coprime_noscale.nx == sysr_coprime_scale.nx == 3
@test hinfnorm2(minreal(sysr_coprime_noscale - sysr_coprime_scale))[1] < 1e-5


# baltrunc_unstab: compare frequency response with and without scaling
sysr_unstab_noscale, _, _ = baltrunc_unstab(sys_siso; n=3)
sysr_unstab_scale, _, _ = baltrunc_unstab(sys_siso; n=3, scaleY=scaleY, scaleU=scaleU)
@test sysr_unstab_noscale.nx == sysr_unstab_scale.nx == 3
@test hinfnorm2(minreal(sysr_unstab_noscale - sysr_unstab_scale))[1] < 1e-5
Loading