Skip to content

Commit cfd34c4

Browse files
authored
Merge pull request #60 from JuliaControl/alloc_updatestate
remove one allocation in `updatestate!`
2 parents ce11ef1 + ac92912 commit cfd34c4

File tree

6 files changed

+40
-42
lines changed

6 files changed

+40
-42
lines changed

src/controller/execute.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ set_objective_linear_coef!(::PredictiveController, _ ) = nothing
491491
Call [`updatestate!`](@ref) on `mpc.estim` [`StateEstimator`](@ref).
492492
"""
493493
function updatestate!(mpc::PredictiveController, u, ym, d=empty(mpc.estim.x̂0))
494-
return updatestate!(mpc.estim,u,ym,d)
494+
return updatestate!(mpc.estim, u, ym, d)
495495
end
496496
updatestate!(::PredictiveController, _ ) = throw(ArgumentError("missing measured outputs ym"))
497497

src/estimator/execute.jl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,11 @@ julia> x̂ = updatestate!(kf, [1], [0]) # x̂[2] is the integrator state (nint_y
209209
"""
210210
function updatestate!(estim::StateEstimator, u, ym, d=empty(estim.x̂0))
211211
validate_args(estim, u, ym, d)
212-
u0, ym0, d0 = remove_op!(estim, u, ym, d)
213-
update_estimate!(estim, u0, ym0, d0)
214-
estim.x̂0 .+= estim.f̂op .- estim.x̂op
215-
return estim.x̂0 + estim.x̂op
212+
u0, ym0, d0 = remove_op!(estim, u, ym, d)
213+
x̂0next = update_estimate!(estim, u0, ym0, d0)
214+
x̂next = x̂0next
215+
x̂next .+= estim.x̂op
216+
return x̂next
216217
end
217218
updatestate!(::StateEstimator, _ ) = throw(ArgumentError("missing measured outputs ym"))
218219

src/estimator/internal_model.jl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ function setmodel_estimator!(estim::InternalModel, model::LinModel, _ , _ , _)
222222
end
223223

224224
@doc raw"""
225-
update_estimate!(estim::InternalModel, u0, y0m, d0=[])
225+
update_estimate!(estim::InternalModel, u0, y0m, d0) -> x̂0next
226226
227227
Update `estim.x̂0`/`x̂d`/`x̂s` with current inputs `u0`, measured outputs `y0m` and dist. `d0`.
228228
@@ -236,9 +236,7 @@ The [`InternalModel`](@ref) updates the deterministic `x̂d` and stochastic `x̂
236236
This estimator does not augment the state vector, thus ``\mathbf{x̂ = x̂_d}``. See
237237
[`init_internalmodel`](@ref) for details.
238238
"""
239-
function update_estimate!(
240-
estim::InternalModel{NT, SM}, u0, y0m, d0=empty(estim.x̂0)
241-
) where {NT<:Real, SM}
239+
function update_estimate!(estim::InternalModel{NT, SM}, u0, y0m, d0) where {NT<:Real, SM}
242240
model = estim.model
243241
x̂d, x̂s = estim.x̂d, estim.x̂s
244242
# -------------- deterministic model ---------------------
@@ -253,7 +251,10 @@ function update_estimate!(
253251
mul!(x̂snext, estim.Âs, x̂s)
254252
mul!(x̂snext, estim.B̂s, ŷs, 1, 1)
255253
x̂s .= x̂snext
256-
return nothing
254+
x̂0next = x̂dnext
255+
x̂0next .+= estim.f̂op .- estim.x̂op
256+
estim.x̂0 .= x̂0next
257+
return x̂0next
257258
end
258259

259260
@doc raw"""

src/estimator/kalman.jl

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ end
171171

172172

173173
@doc raw"""
174-
update_estimate!(estim::SteadyKalmanFilter, u0, y0m, d0=[])
174+
update_estimate!(estim::SteadyKalmanFilter, u0, y0m, d0) -> x̂0next
175175
176176
Update `estim.x̂0` estimate with current inputs `u0`, measured outputs `y0m` and dist. `d0`.
177177
@@ -181,7 +181,7 @@ The [`SteadyKalmanFilter`](@ref) updates it with the precomputed Kalman gain ``\
181181
+ \mathbf{K̂}[\mathbf{y^m}(k) - \mathbf{Ĉ^m x̂}_{k-1}(k) - \mathbf{D̂_d^m d}(k)]
182182
```
183183
"""
184-
function update_estimate!(estim::SteadyKalmanFilter, u0, y0m, d0=empty(estim.x̂0))
184+
function update_estimate!(estim::SteadyKalmanFilter, u0, y0m, d0)
185185
Â, B̂u, B̂d = estim.Â, estim.B̂u, estim.B̂d
186186
x̂0, K̂ = estim.x̂0, estim.
187187
ŷ0m, x̂0next = similar(y0m), similar(x̂0)
@@ -195,8 +195,9 @@ function update_estimate!(estim::SteadyKalmanFilter, u0, y0m, d0=empty(estim.x̂
195195
mul!(x̂0next, B̂u, u0, 1, 1)
196196
mul!(x̂0next, B̂d, d0, 1, 1)
197197
mul!(x̂0next, K̂, v̂, 1, 1)
198+
x̂0next .+= estim.f̂op .- estim.x̂op
198199
estim.x̂0 .= x̂0next
199-
return nothing
200+
return x̂0next
200201
end
201202

202203
struct KalmanFilter{NT<:Real, SM<:LinModel} <: StateEstimator{NT}
@@ -320,7 +321,7 @@ function KalmanFilter(model::SM, i_ym, nint_u, nint_ym, P̂_0, Q̂, R̂) where {
320321
end
321322

322323
@doc raw"""
323-
update_estimate!(estim::KalmanFilter, u0, y0m, d0=[])
324+
update_estimate!(estim::KalmanFilter, u0, y0m, d0) -> x̂0next
324325
325326
Update [`KalmanFilter`](@ref) state `estim.x̂0` and estimation error covariance `estim.P̂`.
326327
@@ -344,7 +345,7 @@ control period ``k-1``. See [^2] for details.
344345
[^2]: Boyd S., "Lecture 8 : The Kalman Filter" (Winter 2008-09) [course slides], *EE363:
345346
Linear Dynamical Systems*, <https://web.stanford.edu/class/ee363/lectures/kf.pdf>.
346347
"""
347-
function update_estimate!(estim::KalmanFilter, u0, y0m, d0=empty(estim.x̂0))
348+
function update_estimate!(estim::KalmanFilter, u0, y0m, d0)
348349
Ĉm = @views estim.Ĉ[estim.i_ym, :]
349350
return update_estimate_kf!(estim, u0, y0m, d0, estim.Â, Ĉm)
350351
end
@@ -537,7 +538,7 @@ function init_ukf(::SimModel{NT}, nx̂, α, β, κ) where {NT<:Real}
537538
end
538539

539540
@doc raw"""
540-
update_estimate!(estim::UnscentedKalmanFilter, u0, y0m, d0=[])
541+
update_estimate!(estim::UnscentedKalmanFilter, u0, y0m, d0) -> x̂0next
541542
542543
Update [`UnscentedKalmanFilter`](@ref) state `estim.x̂0` and covariance estimate `estim.P̂`.
543544
@@ -576,9 +577,7 @@ noise, respectively.
576577
Kalman, H∞, and Nonlinear Approaches", John Wiley & Sons, p. 433–459, <https://doi.org/10.1002/0470045345.ch14>,
577578
ISBN9780470045343.
578579
"""
579-
function update_estimate!(
580-
estim::UnscentedKalmanFilter{NT}, u0, y0m, d0=empty(estim.x̂0)
581-
) where NT<:Real
580+
function update_estimate!(estim::UnscentedKalmanFilter{NT}, u0, y0m, d0) where NT<:Real
582581
x̂0, P̂, Q̂, R̂, K̂, M̂ = estim.x̂0, estim.P̂, estim.Q̂, estim.R̂, estim.K̂, estim.
583582
nym, nx̂ = estim.nym, estim.nx̂
584583
γ, m̂, Ŝ = estim.γ, estim.m̂, estim.
@@ -633,9 +632,10 @@ function update_estimate!(
633632
X̄next .= X̂0next .- x̂0next
634633
P̂next = P̂cor
635634
P̂next.data .= X̄next ** X̄next' .+
635+
x̂0next .+= estim.f̂op .- estim.x̂op
636636
estim.x̂0 .= x̂0next
637637
estim.P̂ .= P̂next
638-
return nothing
638+
return x̂0next
639639
end
640640

641641
struct ExtendedKalmanFilter{NT<:Real, SM<:SimModel} <: StateEstimator{NT}
@@ -763,7 +763,7 @@ end
763763

764764

765765
@doc raw"""
766-
update_estimate!(estim::ExtendedKalmanFilter, u0, y0m, d0=[])
766+
update_estimate!(estim::ExtendedKalmanFilter, u0, y0m, d0) -> x̂0next
767767
768768
Update [`ExtendedKalmanFilter`](@ref) state `estim.x̂0` and covariance `estim.P̂`.
769769
@@ -792,9 +792,7 @@ automatically computes the Jacobians:
792792
```
793793
The matrix ``\mathbf{Ĥ^m}`` is the rows of ``\mathbf{Ĥ}`` that are measured outputs.
794794
"""
795-
function update_estimate!(
796-
estim::ExtendedKalmanFilter{NT}, u0, y0m, d0=empty(estim.x̂0)
797-
) where NT<:Real
795+
function update_estimate!(estim::ExtendedKalmanFilter{NT}, u0, y0m, d0) where NT<:Real
798796
model = estim.model
799797
nx̂, nu, ny = estim.nx̂, model.nu, model.ny
800798
x̂0 = estim.x̂0
@@ -838,7 +836,7 @@ function validate_kfcov(nym, nx̂, Q̂, R̂, P̂_0=nothing)
838836
end
839837

840838
"""
841-
update_estimate_kf!(estim::StateEstimator, u0, y0m, d0, Â, Ĉm)
839+
update_estimate_kf!(estim::StateEstimator, u0, y0m, d0, Â, Ĉm) -> x̂0next
842840
843841
Update time-varying/extended Kalman Filter estimates with augmented `Â` and `Ĉm` matrices.
844842
@@ -848,9 +846,7 @@ substitutes the augmented model matrices with its Jacobians (`Â = F̂` and `C
848846
The implementation uses in-place operations and explicit factorization to reduce
849847
allocations. See e.g. [`KalmanFilter`](@ref) docstring for the equations.
850848
"""
851-
function update_estimate_kf!(
852-
estim::StateEstimator{NT}, u0, y0m, d0, Â, Ĉm
853-
) where NT<:Real
849+
function update_estimate_kf!(estim::StateEstimator{NT}, u0, y0m, d0, Â, Ĉm) where NT<:Real
854850
Q̂, R̂, M̂, K̂ = estim.Q̂, estim.R̂, estim.M̂, estim.
855851
x̂0, P̂ = estim.x̂0, estim.
856852
nx̂, nu, ny = estim.nx̂, estim.model.nu, estim.model.ny
@@ -865,7 +861,8 @@ function update_estimate_kf!(
865861
f̂!(x̂0next, û0, estim, estim.model, x̂0, u0, d0)
866862
mul!(x̂0next, K̂, v̂, 1, 1)
867863
P̂next = Hermitian(Â * (P̂ .-* Ĉm * P̂) *' .+ Q̂, :L)
864+
x̂0next .+= estim.f̂op .- estim.x̂op
868865
estim.x̂0 .= x̂0next
869866
estim.P̂ .= P̂next
870-
return nothing
867+
return x̂0next
871868
end

src/estimator/luenberger.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,11 @@ end
9999

100100

101101
"""
102-
update_estimate!(estim::Luenberger, u0, y0m, d0=[])
102+
update_estimate!(estim::Luenberger, u0, y0m, d0) -> x̂0next
103103
104104
Same than [`update_estimate!(::SteadyKalmanFilter)`](@ref) but using [`Luenberger`](@ref).
105105
"""
106-
function update_estimate!(estim::Luenberger, u0, y0m, d0=empty(estim.x̂0))
106+
function update_estimate!(estim::Luenberger, u0, y0m, d0)
107107
Â, B̂u, B̂d = estim.Â, estim.B̂u, estim.B̂d
108108
x̂0, K̂ = estim.x̂0, estim.
109109
Ĉm, D̂dm = @views estim.Ĉ[estim.i_ym, :], estim.D̂d[estim.i_ym, :]
@@ -117,8 +117,9 @@ function update_estimate!(estim::Luenberger, u0, y0m, d0=empty(estim.x̂0))
117117
mul!(x̂0next, B̂u, u0, 1, 1)
118118
mul!(x̂0next, B̂d, d0, 1, 1)
119119
mul!(x̂0next, K̂, v̂, 1, 1)
120+
x̂0next .+= estim.f̂op .- estim.x̂op
120121
estim.x̂0 .= x̂0next
121-
return nothing
122+
return x̂0next
122123
end
123124

124125
"Throw an error if `setmodel!` is called on `Luenberger` observer."

src/estimator/mhe/execute.jl

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function init_estimate_cov!(estim::MovingHorizonEstimator, _ , _ , _ )
1717
end
1818

1919
@doc raw"""
20-
update_estimate!(estim::MovingHorizonEstimator, u0, y0m, d0=[])
20+
update_estimate!(estim::MovingHorizonEstimator, u0, y0m, d0) -> x̂0next
2121
2222
Update [`MovingHorizonEstimator`](@ref) state `estim.x̂0`.
2323
@@ -28,9 +28,7 @@ augmented model from ``j = N_k-1`` to ``0`` inclusively. Afterward, if ``k ≥ H
2828
arrival covariance for the next time step ``\mathbf{P̂}_{k-N_k+1}(k-N_k+2)`` is estimated
2929
using `estim.covestim` object.
3030
"""
31-
function update_estimate!(
32-
estim::MovingHorizonEstimator{NT}, u0, y0m, d0=empty(estim.x̂0)
33-
) where NT<:Real
31+
function update_estimate!(estim::MovingHorizonEstimator{NT}, u0, y0m, d0) where NT<:Real
3432
model, optim, x̂0 = estim.model, estim.optim, estim.x̂0
3533
add_data_windows!(estim::MovingHorizonEstimator, u0, d0, y0m)
3634
initpred!(estim, model)
@@ -39,9 +37,9 @@ function update_estimate!(
3937
nx̃ = !isinf(estim.C) + nx̂
4038
Z̃var::Vector{JuMP.VariableRef} = optim[:Z̃var]
4139
= Vector{NT}(undef, nym*Nk)
42-
X̂0 = Vector{NT}(undef, nx̂*Nk)
43-
û0 = Vector{NT}(undef, nu)
44-
ŷ0 = Vector{NT}(undef, ny)
40+
X̂0 = Vector{NT}(undef, nx̂*Nk)
41+
û0 = Vector{NT}(undef, nu)
42+
ŷ0 = Vector{NT}(undef, ny)
4543
= Vector{NT}(undef, nx̂)
4644
ϵ_0 = isinf(estim.C) ? empty(estim.Z̃) : estim.Z̃[begin]
4745
Z̃_0 = [ϵ_0; estim.x̂0arr_old; estim.Ŵ]
@@ -82,10 +80,10 @@ function update_estimate!(
8280
# --------- update estimate -----------------------
8381
estim.Ŵ[1:nŵ*Nk] .= @views estim.Z̃[nx̃+1:nx̃+nŵ*Nk] # update Ŵ with optimum for warm-start
8482
V̂, X̂0 = predict!(V̂, X̂0, û0, ŷ0, estim, model, estim.Z̃)
85-
# remove constant (f̂op - x̂op), since it is added in updatestate! method:
86-
estim.x̂0 .= @views X̂0[end-nx̂+1:end] .- (estim.f̂op .- estim.x̂op)
8783
Nk == estim.He && update_cov!(estim::MovingHorizonEstimator)
88-
return nothing
84+
x̂0next = X̂0[end-nx̂+1:end]
85+
estim.x̂0 .= x̂0next
86+
return x̂0next
8987
end
9088

9189

0 commit comments

Comments
 (0)