Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes to place #500

Merged
merged 7 commits into from
May 25, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
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 @@ -173,6 +172,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
olof3 marked this conversation as resolved.
Show resolved Hide resolved
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
olof3 marked this conversation as resolved.
Show resolved Hide resolved
C = B # B is really the "C matrix"
n != size(C,2) && error("A and C must have same number of rows")
olof3 marked this conversation as resolved.
Show resolved Hide resolved
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
olof3 marked this conversation as resolved.
Show resolved Hide resolved
return place(sys.A, sys.B, p, opt)
elseif opt == :o
olof3 marked this conversation as resolved.
Show resolved Hide resolved
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