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

add controller function #512

Merged
merged 3 commits into from
May 28, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions src/ControlSystems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export LTISystem,
prescale,
innovation_form,
predictor,
controller,
# Stability Analysis
isstable,
pole,
Expand Down
22 changes: 20 additions & 2 deletions src/matrix_comps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,25 @@ function predictor(sys::ST, R1, R2) where ST <: AbstractStateSpace
predictor(sys, K)
end

function ControlSystems.predictor(sys, K::AbstractMatrix)
function predictor(sys, K::AbstractMatrix)
A,B,C,D = ssdata(sys)
ss(A-K*C, [B K], C, [D zeros(size(D,1), size(K, 2))], sys.timeevol)
end
end

"""
cont = controller(sys, L::AbstractMatrix, K::AbstractMatrix)

Return the controller `cont` that is given by
`ss(A - B*L - K*C + K*D*L, K, L, 0)`

Such that `feedback(sys, cont)` produces a closed-loop system with eigenvalues given by `A-KC` and `A-BL`.

# Arguments:
- `sys`: Model of system
- `L`: State-feedback gain `u = -Lx`
- `K`: Observer gain
"""
function controller(sys, L::AbstractMatrix, K::AbstractMatrix)
A,B,C,D = ssdata(sys)
ss(A - B*L - K*C + K*D*L, K, L, 0, sys.timeevol)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this correspond to the output of the controller being -Lx?

Suggested change
ss(A - B*L - K*C + K*D*L, K, L, 0, sys.timeevol)
ss(A - B*L - K*C + K*D*L, K, -L, 0, sys.timeevol)

Copy link
Member

@albheim albheim May 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh, you want the output to be Lx so that you can use negative feedback. Seems reasonable, but could maybe confuse more people than me. Maybe just state clearly that the output of the controller is Lx and not -Lx.

Or maybe that is not something that will commonly happen, since you give a tip on how to interconnect the systems it should be fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mm, yeah I guess this is alright.

But what about the case when one wants the controller to treat the measurement and reference signals differently. I would say that this convention is still acceptable, although it would feel weird to add the measurement signal to the reference signal, instead of subtracting it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you introduce reference signals as well it can get very messy. In RobustAndOptimalControl.jl I'm experimenting with using a type ExtendedStateSpace which is similar to, and should probably be merged with PartitionedStateSpace, such that one can defined the controller with references as

function extended_controller(K)
    nx,nu,ny = K.nx, K.nu, K.ny
    A,B,C,D = ssdata(K)
    ss(A, B, -B, zeros(0,nx), C, D21=D, D22=-D)
end

i.e., it has two inputs, r and y. I haven't landed on how to represent everything yet though, I have also experimented with systems with named signals, ideally this should be used as well to not rely on indices everywhere.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, not sure either what makes the most sense, so good that you are thinking about it. Yes, it seems more like a PartitionedStateSpace. We could change PartitionedStateSpace, I don't think we really need to explicitly use such a type for the delay systems.

Perhaps it won't even be needed here either with appropriate name of the signals.

Note: In this case one would have to use positive feedback?

end
23 changes: 22 additions & 1 deletion test/test_matrix_comps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,25 @@ K = kalman(sys, I(2), I(1))
@test sysp.A == sys.A-K*sys.C
@test sysp.B == [sys.B K]

end

# Test controller
sys = ssrand(2,3,4)
Q1 = I(4)
Q2 = I(3)
R1 = I(4)
R2 = I(2)
L = lqr(sys, Q1, Q2)
K = kalman(sys, R1, R2)
cont = controller(sys, L, K)
syscl = feedback(sys, cont)

pcl = pole(syscl)
A,B,C,D = ssdata(sys)
allpoles = [
eigvals(A-B*L)
eigvals(A-K*C)
]
@test sort(pcl, by=LinearAlgebra.eigsortby) ≈ sort(allpoles, by=LinearAlgebra.eigsortby)
@test cont.B == K

end