Skip to content

Commit 7aba16e

Browse files
committed
reduce allocation UnscentedKalmanFilter
1 parent 3228f29 commit 7aba16e

File tree

7 files changed

+57
-37
lines changed

7 files changed

+57
-37
lines changed

src/controller/construct.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ function init_quadprog(::LinModel{NT}, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp) where {NT<:
548548
end
549549
"Return empty matrices if `model` is not a [`LinModel`](@ref)."
550550
function init_quadprog(::SimModel{NT}, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp) where {NT<:Real}
551-
= Hermitian(zeros(NT, 0, 0))
551+
= Hermitian(zeros(NT, 0, 0), :L)
552552
= zeros(NT, 0)
553553
p = zeros(NT, 1) # dummy value (updated just before optimization)
554554
return H̃, q̃, p
@@ -679,7 +679,7 @@ function relaxΔU(::SimModel{NT}, C, C_Δumin, C_Δumax, ΔUmin, ΔUmax, N_Hc) w
679679
ΔŨmin, ΔŨmax = [ΔUmin; NT[0.0]], [ΔUmax; NT[Inf]]
680680
A_ϵ = [zeros(NT, 1, length(ΔUmin)) NT[1.0]]
681681
A_ΔŨmin, A_ΔŨmax = -[I C_Δumin; A_ϵ], [I -C_Δumax; A_ϵ]
682-
Ñ_Hc = Hermitian([N_Hc zeros(NT, nΔU, 1);zeros(NT, 1, nΔU) C])
682+
Ñ_Hc = Hermitian([N_Hc zeros(NT, nΔU, 1);zeros(NT, 1, nΔU) C], :L)
683683
else # ΔŨ = ΔU (only hard constraints)
684684
ΔŨmin, ΔŨmax = ΔUmin, ΔUmax
685685
I_Hc = Matrix{NT}(I, nΔU, nΔU)

src/controller/explicitmpc.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ struct ExplicitMPC{NT<:Real, SE<:StateEstimator} <: PredictiveController{NT}
4242
Ewt = 0 # economic costs not supported for ExplicitMPC
4343
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt)
4444
# Matrix() call is needed to convert `Diagonal` to normal `Matrix`
45-
M_Hp, N_Hc, L_Hp = Hermitian(Matrix(M_Hp)), Hermitian(Matrix(N_Hc)), Hermitian(Matrix(L_Hp))
45+
M_Hp = Hermitian(Matrix(M_Hp), :L)
46+
N_Hc = Hermitian(Matrix(N_Hc), :L)
47+
L_Hp = Hermitian(Matrix(L_Hp), :L)
4648
# dummy vals (updated just before optimization):
4749
R̂y, R̂u, T_lastu = zeros(NT, ny*Hp), zeros(NT, nu*Hp), zeros(NT, nu*Hp)
4850
noR̂u = iszero(L_Hp)

src/controller/linmpc.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ struct LinMPC{
5050
Ewt = 0 # economic costs not supported for LinMPC
5151
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt)
5252
# Matrix() call is needed to convert `Diagonal` to normal `Matrix`
53-
M_Hp, N_Hc, L_Hp = Hermitian(Matrix(M_Hp)), Hermitian(Matrix(N_Hc)), Hermitian(Matrix(L_Hp))
53+
M_Hp = Hermitian(Matrix(M_Hp), :L)
54+
N_Hc = Hermitian(Matrix(N_Hc), :L)
55+
L_Hp = Hermitian(Matrix(L_Hp), :L)
5456
# dummy vals (updated just before optimization):
5557
R̂y, R̂u, T_lastu = zeros(NT, ny*Hp), zeros(NT, nu*Hp), zeros(NT, nu*Hp)
5658
noR̂u = iszero(L_Hp)

src/controller/nonlinmpc.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ struct NonLinMPC{
5151
= copy(model.yop) # dummy vals (updated just before optimization)
5252
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt)
5353
# Matrix() call is needed to convert `Diagonal` to normal `Matrix`
54-
M_Hp, N_Hc, L_Hp = Hermitian(Matrix(M_Hp)), Hermitian(Matrix(N_Hc)), Hermitian(Matrix(L_Hp))
54+
M_Hp = Hermitian(Matrix(M_Hp), :L)
55+
N_Hc = Hermitian(Matrix(N_Hc), :L)
56+
L_Hp = Hermitian(Matrix(L_Hp), :L)
5557
# dummy vals (updated just before optimization):
5658
R̂y, R̂u, T_lastu = zeros(NT, ny*Hp), zeros(NT, nu*Hp), zeros(NT, nu*Hp)
5759
noR̂u = iszero(L_Hp)

src/estimator/kalman.jl

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ function update_estimate!(estim::SteadyKalmanFilter, u, ym, d=empty(estim.x̂))
192192
mul!(x̂next, B̂u, u, 1, 1)
193193
mul!(x̂next, B̂d, d, 1, 1)
194194
mul!(x̂next, K̂, v̂, 1, 1)
195-
x̂ .= x̂next
195+
estim.x̂ .= x̂next
196196
return nothing
197197
end
198198

@@ -347,6 +347,7 @@ function update_estimate!(estim::KalmanFilter, u, ym, d)
347347
return update_estimate_kf!(estim, u, ym, d, estim.Â, estim.Ĉm, estim.P̂, estim.x̂)
348348
end
349349

350+
350351
struct UnscentedKalmanFilter{NT<:Real, SM<:SimModel} <: StateEstimator{NT}
351352
model::SM
352353
lastu0::Vector{NT}
@@ -368,12 +369,13 @@ struct UnscentedKalmanFilter{NT<:Real, SM<:SimModel} <: StateEstimator{NT}
368369
B̂d::Matrix{NT}
369370
D̂d::Matrix{NT}
370371
P̂0::Hermitian{NT, Matrix{NT}}
371-
::Hermitian{NT, Matrix{NT}}
372-
::Hermitian{NT, Matrix{NT}}
372+
::Hermitian{NT, Matrix{NT}}
373+
::Hermitian{NT, Matrix{NT}}
373374
::Matrix{NT}
374375
::Hermitian{NT, Matrix{NT}}
375-
::Matrix{NT}
376+
::Matrix{NT}
376377
Ŷm::Matrix{NT}
378+
sqrtP̂::LowerTriangular{NT, Matrix{NT}}
377379
::Int
378380
γ::NT
379381
::Vector{NT}
@@ -396,14 +398,15 @@ struct UnscentedKalmanFilter{NT<:Real, SM<:SimModel} <: StateEstimator{NT}
396398
= zeros(NT, nx̂, nym)
397399
= Hermitian(zeros(NT, nym, nym), :L)
398400
X̂, Ŷm = zeros(NT, nx̂, nσ), zeros(NT, nym, nσ)
401+
sqrtP̂ = LowerTriangular(zeros(NT, nx̂, nx̂))
399402
return new{NT, SM}(
400403
model,
401404
lastu0, x̂, P̂,
402405
i_ym, nx̂, nym, nyu, nxs,
403406
As, Cs_u, Cs_y, nint_u, nint_ym,
404407
Â, B̂u, Ĉ, B̂d, D̂d,
405408
P̂0, Q̂, R̂,
406-
K̂, M̂, X̂, Ŷm,
409+
K̂, M̂, X̂, Ŷm, sqrtP̂,
407410
nσ, γ, m̂, Ŝ
408411
)
409412
end
@@ -571,21 +574,23 @@ noise, respectively.
571574
"""
572575
function update_estimate!(estim::UnscentedKalmanFilter{NT}, u, ym, d) where NT<:Real
573576
x̂, P̂, Q̂, R̂, K̂, M̂ = estim.x̂, estim.P̂, estim.Q̂, estim.R̂, estim.K̂, estim.
574-
X̂, Ŷm = estim.X̂, estim.Ŷm
575577
nym, nx̂, nσ = estim.nym, estim.nx̂, estim.
576578
γ, m̂, Ŝ = estim.γ, estim.m̂, estim.
579+
X̂, Ŷm = estim.X̂, estim.Ŷm
580+
sqrtP̂ = estim.sqrtP̂
577581
# --- initialize matrices ---
578-
X̂_next = Matrix{NT}(undef, nx̂, nσ)
582+
x̂next = Vector{NT}(undef, nx̂)
579583
= Vector{NT}(undef, estim.model.nu)
580584
ŷm = Vector{NT}(undef, nym)
581585
= Vector{NT}(undef, estim.model.ny)
582-
sqrt_P̂ = LowerTriangular{NT, Matrix{NT}}(Matrix{NT}(undef, nx̂, nx̂))
583586
# --- correction step ---
584-
sqrt_P̂ .= cholesky(P̂).L
585-
γ_sqrt_P̂ = lmul!(γ, sqrt_P̂)
587+
P̂_chol = sqrtP̂.data
588+
P̂_chol .=
589+
cholesky!(Hermitian(P̂_chol, :L)) # also modifies sqrtP̂
590+
γ_sqrtP̂ = lmul!(γ, sqrtP̂)
586591
X̂ .=
587-
X̂[:, 2:nx̂+1] .+= γ_sqrt_P̂
588-
X̂[:, nx̂+2:end] .-= γ_sqrt_P̂
592+
X̂[:, 2:nx̂+1] .+= γ_sqrtP̂
593+
X̂[:, nx̂+2:end] .-= γ_sqrtP̂
589594
for j in axes(Ŷm, 2)
590595
@views ĥ!(ŷ, estim, estim.model, X̂[:, j], d)
591596
@views Ŷm[:, j] .= ŷ[estim.i_ym]
@@ -594,27 +599,36 @@ function update_estimate!(estim::UnscentedKalmanFilter{NT}, u, ym, d) where NT<:
594599
X̄, Ȳm = X̂, Ŷm
595600
X̄ .=.-
596601
Ȳm .= Ŷm .- ŷm
597-
M̂ .= Hermitian(Ȳm ** Ȳm' .+)
602+
.data .= Ȳm ** Ȳm' .+
598603
mul!(K̂, X̄, lmul!(Ŝ, Ȳm'))
599604
rdiv!(K̂, cholesky(M̂))
600605
= ŷm
601606
v̂ .= ym .- ŷm
602-
x̂_cor =+*
603-
P̂_cor =- Hermitian(K̂ **', :L)
607+
x̂cor = x̂next
608+
x̂cor .=
609+
mul!(x̂cor, K̂, v̂, 1, 1)
610+
P̂cor = Hermitian(P̂ .-**', :L)
604611
# --- prediction step ---
605-
X̂_cor, sqrt_P̂_cor = X̂, sqrt_P̂
606-
sqrt_P̂_cor .= cholesky(P̂_cor).L
607-
γ_sqrt_P̂_cor = lmul!(γ, sqrt_P̂_cor)
608-
X̂_cor .= x̂_cor
609-
X̂_cor[:, 2:nx̂+1] .+= γ_sqrt_P̂_cor
610-
X̂_cor[:, nx̂+2:end] .-= γ_sqrt_P̂_cor
611-
for j in axes(X̂_next, 2)
612-
@views f̂!(X̂_next[:, j], û, estim, estim.model, X̂_cor[:, j], u, d)
612+
X̂cor, sqrtP̂cor = X̂, sqrtP̂
613+
P̂cor_chol = sqrtP̂cor.data
614+
P̂cor_chol .= P̂cor
615+
cholesky!(Hermitian(P̂cor_chol, :L)) # also modifies sqrtP̂cor
616+
γ_sqrtP̂cor = lmul!(γ, sqrtP̂cor)
617+
X̂cor .= x̂cor
618+
X̂cor[:, 2:nx̂+1] .+= γ_sqrtP̂cor
619+
X̂cor[:, nx̂+2:end] .-= γ_sqrtP̂cor
620+
X̂next = X̂cor
621+
for j in axes(X̂next, 2)
622+
@views x̂cor .= X̂cor[:, j]
623+
@views f̂!(X̂next[:, j], û, estim, estim.model, x̂cor, u, d)
613624
end
614-
x̂_next = mul!(x̂, X̂_next, m̂)
615-
X̄_next = X̂_next
616-
X̄_next .= X̂_next .- x̂_next
617-
P̂ .= Hermitian(X̄_next ** X̄_next' .+ Q̂)
625+
x̂next .= mul!(x̂, X̂next, m̂)
626+
X̄next = X̂next
627+
X̄next .= X̂next .- x̂next
628+
P̂next = P̂cor
629+
P̂next.data .= X̄next ** X̄next' .+
630+
estim.x̂ .= x̂next
631+
estim.P̂ .= P̂next
618632
return nothing
619633
end
620634

@@ -822,17 +836,17 @@ function update_estimate_kf!(estim::StateEstimator{NT}, u, ym, d, Â, Ĉm, P̂
822836
Q̂, R̂, M̂, K̂ = estim.Q̂, estim.R̂, estim.M̂, estim.
823837
nx̂, nu, ny = estim.nx̂, estim.model.nu, estim.model.ny
824838
x̂next, û, ŷ = Vector{NT}(undef, nx̂), Vector{NT}(undef, nu), Vector{NT}(undef, ny)
825-
P̂next = similar(P̂)
826839
mul!(M̂, P̂.data, Ĉm') # the ".data" weirdly removes a type instability in mul!
827-
rdiv!(M̂, cholesky!(Hermitian(Ĉm ** Ĉm' .+ R̂)))
840+
rdiv!(M̂, cholesky!(Hermitian(Ĉm ** Ĉm' .+, :L)))
828841
mul!(K̂, Â, M̂)
829842
ĥ!(ŷ, estim, estim.model, x̂, d)
830843
ŷm = @views ŷ[estim.i_ym]
831844
= ŷm
832845
v̂ .= ym .- ŷm
833846
f̂!(x̂next, û, estim, estim.model, x̂, u, d)
834847
mul!(x̂next, K̂, v̂, 1, 1)
848+
P̂next = Hermitian(Â * (P̂ .-* Ĉm * P̂) *' .+ Q̂, :L)
835849
estim.x̂ .= x̂next
836-
P̂ .= Hermitian(Â * (P̂ .-* Ĉm * P̂) *' .+ Q̂)
850+
estim.P̂ .= P̂next
837851
return nothing
838852
end

src/estimator/luenberger.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,6 @@ function update_estimate!(estim::Luenberger, u, ym, d=empty(estim.x̂))
118118
mul!(x̂next, B̂u, u, 1, 1)
119119
mul!(x̂next, B̂d, d, 1, 1)
120120
mul!(x̂next, K̂, v̂, 1, 1)
121-
x̂ .= x̂next
121+
estim.x̂ .= x̂next
122122
return nothing
123123
end

src/estimator/mhe/execute.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ function update_estimate!(estim::MovingHorizonEstimator{NT}, u, ym, d) where NT<
8181
# --------- update estimate -----------------------
8282
estim.Ŵ[1:nŵ*Nk] .= @views estim.Z̃[nx̃+1:nx̃+nŵ*Nk] # update Ŵ with optimum for warm-start
8383
V̂, X̂ = predict!(V̂, X̂, û, ŷ, estim, model, estim.Z̃)
84-
x̂ .= X̂[end-nx̂+1:end]
84+
estim.x̂ .= @views X̂[end-nx̂+1:end]
8585
Nk == estim.He && update_cov!(estim::MovingHorizonEstimator)
8686
return nothing
8787
end

0 commit comments

Comments
 (0)