Skip to content

Commit 83f415c

Browse files
committed
added: reduce PredictiveController allocs with new buffer object
1 parent 8d5e13b commit 83f415c

File tree

9 files changed

+66
-11
lines changed

9 files changed

+66
-11
lines changed

docs/src/internals/predictive_control.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@ ModelPredictiveControl.linconstraint!(::PredictiveController, ::LinModel)
3434

3535
```@docs
3636
ModelPredictiveControl.optim_objective!(::PredictiveController)
37+
ModelPredictiveControl.getinput
3738
```

src/controller/execute.jl

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ julia> u = moveinput!(mpc, ry); round.(u, digits=3)
5252
function moveinput!(
5353
mpc::PredictiveController,
5454
ry::Vector = mpc.estim.model.yop,
55-
d ::Vector = mpc.estim.buffer.empty;
56-
Dhat ::Vector = repeat(d, mpc.Hp),
57-
Rhaty::Vector = repeat(ry, mpc.Hp),
55+
d ::Vector = mpc.buffer.empty;
56+
Dhat ::Vector = repeat!(mpc.buffer.D̂, d, mpc.Hp),
57+
Rhaty::Vector = repeat!(mpc.buffer.R̂y, ry, mpc.Hp),
5858
Rhatu::Vector = mpc.Uop,
5959
= Dhat,
6060
R̂y = Rhaty,
@@ -67,13 +67,9 @@ function moveinput!(
6767
initpred!(mpc, mpc.estim.model, d, D̂, R̂y, R̂u)
6868
linconstraint!(mpc, mpc.estim.model)
6969
ΔŨ = optim_objective!(mpc)
70-
Δu = ΔŨ[1:mpc.estim.model.nu] # receding horizon principle: only Δu(k) is used (1st one)
71-
u = mpc.estim.lastu0 + mpc.estim.model.uop + Δu
72-
return u
70+
return getinput(mpc, ΔŨ)
7371
end
7472

75-
76-
7773
@doc raw"""
7874
getinfo(mpc::PredictiveController) -> info
7975
@@ -506,6 +502,24 @@ function preparestate!(mpc::PredictiveController, ym, d=mpc.estim.buffer.empty)
506502
return preparestate!(mpc.estim, ym, d)
507503
end
508504

505+
@doc raw"""
506+
getinput(mpc::PredictiveController, ΔŨ) -> u
507+
508+
Get current manipulated input `u` from a [`PredictiveController`](@ref) solution `ΔŨ`.
509+
510+
The first manipulated input ``\mathbf{u}(k)`` is extracted from the input increments vector
511+
``\mathbf{ΔŨ}`` and applied on the plant (from the receding horizon principle).
512+
"""
513+
function getinput(mpc, ΔŨ)
514+
Δu = mpc.buffer.u
515+
for i in 1:mpc.estim.model.nu
516+
Δu[i] = ΔŨ[i]
517+
end
518+
u = Δu
519+
u .+= mpc.estim.lastu0 .+ mpc.estim.model.uop
520+
return u
521+
end
522+
509523
"""
510524
updatestate!(mpc::PredictiveController, u, ym, d=[]) -> x̂next
511525

src/controller/explicitmpc.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ struct ExplicitMPC{NT<:Real, SE<:StateEstimator} <: PredictiveController{NT}
3434
Uop::Vector{NT}
3535
Yop::Vector{NT}
3636
Dop::Vector{NT}
37+
buffer::PredictiveControllerBuffer{NT}
3738
function ExplicitMPC{NT, SE}(
3839
estim::SE, Hp, Hc, M_Hp, N_Hc, L_Hp
3940
) where {NT<:Real, SE<:StateEstimator}
@@ -65,6 +66,7 @@ struct ExplicitMPC{NT<:Real, SE<:StateEstimator} <: PredictiveController{NT}
6566
Uop, Yop, Dop = repeat(model.uop, Hp), repeat(model.yop, Hp), repeat(model.dop, Hp)
6667
nΔŨ = size(Ẽ, 2)
6768
ΔŨ = zeros(NT, nΔŨ)
69+
buffer = PredictiveControllerBuffer{NT}(nu, ny, nd, Hp)
6870
mpc = new{NT, SE}(
6971
estim,
7072
ΔŨ, ŷ,
@@ -78,6 +80,7 @@ struct ExplicitMPC{NT<:Real, SE<:StateEstimator} <: PredictiveController{NT}
7880
Ks, Ps,
7981
d0, D̂0, D̂E,
8082
Uop, Yop, Dop,
83+
buffer
8184
)
8285
return mpc
8386
end

src/controller/linmpc.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct LinMPC{
4343
Uop::Vector{NT}
4444
Yop::Vector{NT}
4545
Dop::Vector{NT}
46+
buffer::PredictiveControllerBuffer{NT}
4647
function LinMPC{NT, SE, JM}(
4748
estim::SE, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, optim::JM
4849
) where {NT<:Real, SE<:StateEstimator, JM<:JuMP.GenericModel}
@@ -74,6 +75,7 @@ struct LinMPC{
7475
Uop, Yop, Dop = repeat(model.uop, Hp), repeat(model.yop, Hp), repeat(model.dop, Hp)
7576
nΔŨ = size(Ẽ, 2)
7677
ΔŨ = zeros(NT, nΔŨ)
78+
buffer = PredictiveControllerBuffer{NT}(nu, ny, nd, Hp)
7779
mpc = new{NT, SE, JM}(
7880
estim, optim, con,
7981
ΔŨ, ŷ,
@@ -86,6 +88,7 @@ struct LinMPC{
8688
Ks, Ps,
8789
d0, D̂0, D̂E,
8890
Uop, Yop, Dop,
91+
buffer
8992
)
9093
init_optimization!(mpc, model, optim)
9194
return mpc

src/controller/nonlinmpc.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct NonLinMPC{
4545
Uop::Vector{NT}
4646
Yop::Vector{NT}
4747
Dop::Vector{NT}
48+
buffer::PredictiveControllerBuffer{NT}
4849
function NonLinMPC{NT, SE, JM, JEFunc}(
4950
estim::SE, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE::JEFunc, optim::JM
5051
) where {NT<:Real, SE<:StateEstimator, JM<:JuMP.GenericModel, JEFunc<:Function}
@@ -75,6 +76,7 @@ struct NonLinMPC{
7576
Uop, Yop, Dop = repeat(model.uop, Hp), repeat(model.yop, Hp), repeat(model.dop, Hp)
7677
nΔŨ = size(Ẽ, 2)
7778
ΔŨ = zeros(NT, nΔŨ)
79+
buffer = PredictiveControllerBuffer{NT}(nu, ny, nd, Hp)
7880
mpc = new{NT, SE, JM, JEFunc}(
7981
estim, optim, con,
8082
ΔŨ, ŷ,
@@ -87,6 +89,7 @@ struct NonLinMPC{
8789
Ks, Ps,
8890
d0, D̂0, D̂E,
8991
Uop, Yop, Dop,
92+
buffer
9093
)
9194
init_optimization!(mpc, model, optim)
9295
return mpc

src/general.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ end
4444
"Generate a block diagonal matrix repeating `n` times the matrix `A`."
4545
repeatdiag(A, n::Int) = kron(I(n), A)
4646

47+
"In-place version of `repeat` but for vectors only."
48+
function repeat!(Y::Vector, a::Vector, n::Int)
49+
na = length(a)
50+
for i=0:n-1
51+
Y[(1+na*i):(na*(i+1))] = a
52+
end
53+
return Y
54+
end
55+
4756
"Convert 1-element vectors and normal matrices to Hermitians."
4857
to_hermitian(A::AbstractVector) = Hermitian(reshape(A, 1, 1), :L)
4958
to_hermitian(A::AbstractMatrix) = Hermitian(A, :L)

src/predictive_control.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,28 @@ julia> u = mpc([5]); round.(u, digits=3)
1919
"""
2020
abstract type PredictiveController{NT<:Real} end
2121

22+
struct PredictiveControllerBuffer{NT<:Real}
23+
u ::Vector{NT}
24+
R̂y::Vector{NT}
25+
::Vector{NT}
26+
empty::Vector{NT}
27+
end
28+
29+
@doc raw"""
30+
PredictiveControllerBuffer{NT}(nu::Int, ny::Int, nd::Int)
31+
32+
Create a buffer for `PredictiveController` objects.
33+
34+
The buffer is used to store intermediate results during computation without allocating.
35+
"""
36+
function PredictiveControllerBuffer{NT}(nu::Int, ny::Int, nd::Int, Hp::Int) where NT <: Real
37+
u = Vector{NT}(undef, nu)
38+
R̂y = Vector{NT}(undef, ny*Hp)
39+
= Vector{NT}(undef, nd*Hp)
40+
empty = Vector{NT}(undef, 0)
41+
return PredictiveControllerBuffer{NT}(u, R̂y, D̂, empty)
42+
end
43+
2244
include("controller/construct.jl")
2345
include("controller/execute.jl")
2446
include("controller/explicitmpc.jl")

src/sim_model.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ struct SimModelBuffer{NT<:Real}
2929
end
3030

3131
@doc raw"""
32-
SimModelBuffer(nu::Int, nx::Int, ny::Int, nd::Int) -> SimModelBuffer{NT}
32+
SimModelBuffer{NT}(nu::Int, nx::Int, ny::Int, nd::Int)
3333
3434
Create a buffer for `SimModel` objects for inputs, states, outputs, and disturbances.
3535

src/state_estim.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ struct StateEstimatorBuffer{NT<:Real}
3333
end
3434

3535
@doc raw"""
36-
StateEstimatorBuffer(nx̂::Int, nym::Int) -> StateEstimatorBuffer{NT}
36+
StateEstimatorBuffer{NT}(nu::Int, nx̂::Int, nym::Int, ny::Int, nd::Int)
3737
3838
Create a buffer for `StateEstimator` objects for estimated states and measured outputs.
3939
40-
The buffer is used to store intermediate results during simulation without allocating.
40+
The buffer is used to store intermediate results during estimation without allocating.
4141
"""
4242
function StateEstimatorBuffer{NT}(
4343
nu::Int, nx̂::Int, nym::Int, ny::Int, nd::Int

0 commit comments

Comments
 (0)