Skip to content

Commit 40a14eb

Browse files
authored
Add function for stable/unstable decomposition (#947)
* Add function for stable/unstable decomposition * fix another DSP deprecation * fix * test tweak
1 parent aa37310 commit 40a14eb

File tree

6 files changed

+43
-3
lines changed

6 files changed

+43
-3
lines changed

docs/src/man/creating_systems.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,9 +497,10 @@ Filters can be designed using [DSP.jl](https://docs.juliadsp.org/stable/filters/
497497
using DSP, ControlSystemsBase, Plots
498498
499499
fs = 100
500-
df = digitalfilter(Bandpass(5, 10; fs), Butterworth(2))
500+
df = digitalfilter(Bandpass(5, 10), Butterworth(2); fs)
501501
G = tf(df, 1/fs) # Sample time must be provided in the conversion to get the correct frequency scale in the Bode plot
502502
bodeplot(G, xscale=:identity, yscale=:identity, hz=true)
503+
vline!([5 10], l=(:black, :dash), label="Band-pass limits", sp=1)
503504
```
504505

505506
See also

lib/ControlSystemsBase/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name = "ControlSystemsBase"
22
uuid = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e"
33
authors = ["Dept. Automatic Control, Lund University"]
44
repo = "https://github.com/JuliaControl/ControlSystems.jl.git"
5-
version = "1.11.3"
5+
version = "1.12.0"
66

77
[deps]
88
DSP = "717857b8-e6f2-59f4-9121-6e50c889abd2"

lib/ControlSystemsBase/src/ControlSystemsBase.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export LTISystem,
2222
# Linear Algebra
2323
balance,
2424
balance_statespace,
25+
stab_unstab,
2526
are,
2627
lqr,
2728
kalman,

lib/ControlSystemsBase/src/analysis.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
"""
22
poles(sys)
33
4-
Compute the poles of system `sys`."""
4+
Compute the poles of system `sys`.
5+
6+
Note: Poles with multiplicity `n > 1` may suffer numerical inaccuracies on the order `eps(numeric_type(sys))^(1/n)`, i.e., a double pole in a system with `Float64` coefficients may be computed with an error of about `√(eps(Float64)) ≈ 1.5e-8`.
7+
"""
58
poles(sys::AbstractStateSpace) = eigvalsnosort(sys.A)
69

710
# Seems to have a lot of rounding problems if we run the full thing with sisorational,

lib/ControlSystemsBase/src/matrix_comps.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,27 @@ function baltrunc(sys::ST; atol = sqrt(eps(numeric_type(sys))), rtol = 1e-3, n =
671671
return ST(A,B,C,D,sys.timeevol), S, T
672672
end
673673

674+
"""
675+
stab, unstab, sep = stab_unstab(sys; kwargs...)
676+
677+
Decompose `sys` into `sys = stab + unstab` where `stab` contains all stable poles and `unstab` contains unstable poles.
678+
679+
`0 ≤ sep ≤ 1` is the estimated separation between the stable and unstable spectra.
680+
681+
The docstring of `MatrixPencils.ssblkdiag`, reproduced below, provides more information on the keyword arguments:
682+
$(@doc(MatrixPencils.ssblkdiag))
683+
"""
684+
function stab_unstab(sys::AbstractStateSpace; kwargs...)
685+
stable_unstable = true
686+
disc = isdiscrete(sys)
687+
A, B, C, _, _, blkdims, sep = MatrixPencils.ssblkdiag(sys.A, sys.B, sys.C; disc, stable_unstable, withQ = false, withZ = false, kwargs...)
688+
n1 = blkdims[1];
689+
i1 = 1:n1; i2 = n1+1:sys.nx
690+
return (; stab=ss(A[i1,i1], B[i1,:], C[:,i1], sys.D, timeevol(sys)),
691+
unstab=ss(A[i2,i2], B[i2,:], C[:,i2], 0, timeevol(sys)),
692+
sep)
693+
end
694+
674695
"""
675696
syst = similarity_transform(sys, T; unitary=false)
676697
Perform a similarity transform `T : Tx̃ = x` on `sys` such that

lib/ControlSystemsBase/test/test_matrix_comps.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,20 @@ syst = similarity_transform(sys, Tr)
8888
@test sys.C*Tr syst.C
8989

9090

91+
## stab_unstab
92+
sys = ssrand(2,3,40, stable=false)
93+
stab, unstab = stab_unstab(sys)
94+
@test all(real(poles(stab)) .< 0)
95+
@test all(real(poles(unstab)) .>= 0)
96+
@test linfnorm(stab + unstab - sys)[1] < 1e-5
97+
98+
sys = ssrand(2,3,40, stable=false, Ts=1)
99+
stab, unstab = stab_unstab(sys)
100+
@test all(abs.(poles(stab)) .< 1)
101+
@test all(abs.(poles(unstab)) .>= 1)
102+
@test linfnorm(stab + unstab - sys)[1] < 1e-5
103+
104+
91105
sys = ss([1 0.1; 0 1], ones(2), [1. 0], 0)
92106
sysi = ControlSystemsBase.innovation_form(sys, I, I)
93107
@test sysi.A sysi.A

0 commit comments

Comments
 (0)