Skip to content

Commit

Permalink
Fixes to place (#500)
Browse files Browse the repository at this point in the history
* Add tests for place.

* Removed luenberger and exented place instead.

Co-authored-by: Fredrik Bagge Carlson <[email protected]>
  • Loading branch information
olof3 and baggepinnen authored May 25, 2021
1 parent 490ba4d commit 86c7d63
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 29 deletions.
3 changes: 2 additions & 1 deletion src/ControlSystems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export LTISystem,
ctrb,
obsv,
place,
luenberger,
# Model Simplification
reduce_sys,
sminreal,
Expand Down Expand Up @@ -174,6 +173,8 @@ include("plotting.jl")
@deprecate den denvec
@deprecate norminf hinfnorm
@deprecate diagonalize(s::AbstractStateSpace, digits) diagonalize(s::AbstractStateSpace)
@deprecate luenberger(sys, p) place(sys, p, :o)
@deprecate luenberger(A, C, p) place(A, C, p, :o)
# There are some deprecations in pid_control.jl for laglink/leadlink/leadlinkat

function covar(D::Union{AbstractMatrix,UniformScaling}, R)
Expand Down
63 changes: 35 additions & 28 deletions src/synthesis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -119,45 +119,52 @@ Calculate the optimal Kalman gain for discrete time systems
dkalman(A, C, R1,R2) = Matrix(dlqr(A',C',R1,R2)')

"""
place(A, B, p)
place(sys::StateSpace, p)
place(A, B, p, opt=:c)
place(sys::StateSpace, p, opt=:c)
Calculate gain matrix `K` such that
the poles of `(A-BK)` in are in `p`.
Calculate the gain matrix `K` such that `A - BK` has eigenvalues `p`.
place(A, C, p, opt=:o)
place(sys::StateSpace, p, opt=:o)
Calculate the observer gain matrix `L` such that `A - LC` has eigenvalues `p`.
Uses Ackermann's formula.
For observer pole placement, see `luenberger`.
Currently handles only SISO systems.
"""
function place(A, B, p)
function place(A, B, p, opt=:c)
n = length(p)
n != size(A,1) && error("Must define as many poles as states")
n != size(B,1) && error("A and B must have same number of rows")
if size(B,2) == 1
acker(A,B,p)
n != size(A,1) && error("Must specify as many poles as states")
if opt === :c
n != size(B,1) && error("A and B must have same number of rows")
if size(B,2) == 1
acker(A, B, p)
else
error("place only implemented for SISO systems")
end
elseif opt === :o
C = B # B is really the "C matrix"
n != size(C,2) && error("A and C must have same number of columns")
if size(C,1) == 1
acker(A', C', p)'
else
error("place only implemented for SISO systems")
end
else
error("place only implemented for SISO systems")
error("fourth argument must be :c or :o")
end
end

function place(sys::StateSpace, p)
return place(sys.A, sys.B, p)
function place(sys::StateSpace, p, opt=:c)
if opt === :c
return place(sys.A, sys.B, p, opt)
elseif opt === :o
return place(sys.A, sys.C, p, opt)
else
error("third argument must be :c or :o")
end
end

"""
luenberger(A, C, p)
luenberger(sys::StateSpace, p)

Calculate gain matrix `L` such that the poles of `(A - LC)` are in `p`.
Uses sytem's dual form (Controllability-Observability duality) applied to Ackermann's formula.
That is, `(A - BK)` is indentic to `(A' - C'L') == (A - LC)`.
"""
function luenberger(A, C, p)
place(A', C', p)'
end

function luenberger(sys::StateSpace, p)
return luenberger(sys.A, sys.C, p)
end

#Implements Ackermann's formula for placing poles of (A-BK) in p
function acker(A,B,P)
Expand Down
32 changes: 32 additions & 0 deletions test/test_synthesis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,38 @@ z5,p5,k5 = zpkdata(ffb5)
end



@testset "place" begin
sys = ss(-4, 2, 3, 0)
A, B, C, _ = ssdata(sys)

@test place(A, B, [-10]) == [3][:,:]
@test place(A, B, [-10], :c) == [3][:,:]
@test place(A, C, [-10], :o) == [2][:,:]

A = [0 1; 0 0]
B = [0; 1]
C = [1 0]
sys = ss(A, B, C, 0)

@test place(A, B, [-1.0, -1]) [1 2]
@test place(sys, [-1.0, -1]) [1 2]
@test place(A, B, [-1.0, -1], :c) [1 2]
@test place(sys, [-1.0, -1], :c) [1 2]
@test place(A, C, [-2.0, -2], :o) [4; 4]
@test place(sys, [-2.0, -2], :o) [4; 4]

@test place(A, B, [-2 + im, -2 - im]) [5 4]
@test place(A, C, [-4 + 2im, -4 - 2im], :o) [8; 20]

A = ones(3,3) - diagm([3, 4, 5])
B = [1; 0; 2]
C = [1 1 0]
@test place(A, B, [-2 + 2im, -2 - 2im, -4]) [-2.6 5.2 0.8]
@test place(A, C, [-2 + 3im, -2 - 3im, -4], :o) [11; -12; 1]
end


@testset "acker" begin
Random.seed!(0)
A = randn(3,3)
Expand Down

0 comments on commit 86c7d63

Please sign in to comment.