Skip to content

Commit dc8681a

Browse files
authored
Merge pull request #55 from JuliaControl/adapt_mhe
Added: `setmodel!` for `MovingHorizonEstimator`
2 parents d3e0a2f + 76b0a12 commit dc8681a

File tree

10 files changed

+406
-239
lines changed

10 files changed

+406
-239
lines changed

docs/src/public/sim_model.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The [`SimModel`](@ref) types represents discrete state-space models that can be
88
construct [`StateEstimator`](@ref)s and [`PredictiveController`](@ref)s, or as plant
99
simulators by calling [`evaloutput`](@ref) and [`updatestate!`](@ref) methods on
1010
[`SimModel`](@ref) instances (to test estimator/controller designs). For time simulations,
11-
the states `x` are stored inside [`SimModel`](@ref) instances. Use [`setstate!`](@ref)
11+
the states ``\mathbf{x}`` are stored inside [`SimModel`](@ref) instances. Use [`setstate!`](@ref)
1212
method to manually modify them.
1313

1414
## SimModel

src/controller/construct.jl

+7-7
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ The ``\mathbf{F}`` and ``\mathbf{f_x̂}`` vectors are recalculated at each contr
414414
# Extended Help
415415
!!! details "Extended Help"
416416
Using the augmented matrices ``\mathbf{Â, B̂_u, Ĉ, B̂_d, D̂_d}`` in `estim` (see
417-
[`augment_model`](@ref)) and the function ``\mathbf{W}(j) = ∑_{i=0}^j \mathbf{Â}^i``,
417+
[`augment_model`](@ref)), and the function ``\mathbf{W}(j) = ∑_{i=0}^j \mathbf{Â}^i``,
418418
the prediction matrices are computed by :
419419
```math
420420
\begin{aligned}
@@ -447,8 +447,7 @@ The ``\mathbf{F}`` and ``\mathbf{f_x̂}`` vectors are recalculated at each contr
447447
\mathbf{Ĉ W}(0) \\
448448
\mathbf{Ĉ W}(1) \\
449449
\vdots \\
450-
\mathbf{Ĉ W}(H_p-1) \end{bmatrix}
451-
\mathbf{\big(x̂_{op} + f̂_{op}\big)}
450+
\mathbf{Ĉ W}(H_p-1) \end{bmatrix} \mathbf{\big(x̂_{op} + f̂_{op}\big)}
452451
\end{aligned}
453452
```
454453
For the terminal constraints, the matrices are computed with:
@@ -468,7 +467,7 @@ The ``\mathbf{F}`` and ``\mathbf{f_x̂}`` vectors are recalculated at each contr
468467
\end{bmatrix} \\
469468
\mathbf{k_x̂} &= \mathbf{Â}^{H_p} \\
470469
\mathbf{v_x̂} &= \mathbf{W}(H_p-1)\mathbf{B̂_u} \\
471-
\mathbf{b_x̂} &= \mathbf{W}(H_p-1) \mathbf{\big(x̂_{op} + f̂_{op}\big)}
470+
\mathbf{b_x̂} &= \mathbf{W}(H_p-1) \mathbf{\big(f̂_{op} - x̂_{op}\big)}
472471
\end{aligned}
473472
```
474473
"""
@@ -525,15 +524,16 @@ function init_predmat(estim::StateEstimator{NT}, model::LinModel, Hp, Hc) where
525524
jx̂[: , iCol] = j < Hp ? getpower(Âpow, Hp-j-1)*B̂d : zeros(NT, nx̂, nd)
526525
end
527526
end
528-
# --- state and state update f̂op operating points ---
527+
# --- state x̂op and state update f̂op operating points ---
529528
coef_bx̂ = getpower(Âpow_csum, Hp-1)
530529
coef_B = Matrix{NT}(undef, ny*Hp, nx̂)
531530
for j=1:Hp
532531
iRow = (1:ny) .+ ny*(j-1)
533532
coef_B[iRow,:] =*getpower(Âpow_csum, j-1)
534533
end
535-
bx̂ = coef_bx̂ * (estim.f̂op - estim.x̂op)
536-
B = coef_B * (estim.f̂op - estim.x̂op)
534+
f̂op_n_x̂op = estim.f̂op - estim.x̂op
535+
bx̂ = coef_bx̂ * f̂op_n_x̂op
536+
B = coef_B * f̂op_n_x̂op
537537
return E, G, J, K, V, B, ex̂, gx̂, jx̂, kx̂, vx̂, bx̂
538538
end
539539

src/controller/execute.jl

+6-6
Original file line numberDiff line numberDiff line change
@@ -564,12 +564,12 @@ function setmodel_controller!(mpc::PredictiveController, model::LinModel, x̂op_
564564
mpc.Yop[(1+ny*i):(ny+ny*i)] .= model.yop
565565
mpc.Dop[(1+nd*i):(nd+nd*i)] .= model.dop
566566
end
567-
con.U0min .-= mpc.Uop # convert U0 to U with the new operating point
568-
con.U0max .-= mpc.Uop # convert U0 to U with the new operating point
569-
con.Y0min .-= mpc.Yop # convert Y0 to Y with the new operating point
570-
con.Y0max .-= mpc.Yop # convert Y0 to Y with the new operating point
571-
con.x̂0min .-= estim.x̂op # convert x̂0 to with the new operating point
572-
con.x̂0max .-= estim.x̂op # convert x̂0 to with the new operating point
567+
con.U0min .-= mpc.Uop # convert U to U0 with the new operating point
568+
con.U0max .-= mpc.Uop # convert U to U0 with the new operating point
569+
con.Y0min .-= mpc.Yop # convert Y to Y0 with the new operating point
570+
con.Y0max .-= mpc.Yop # convert Y to Y0 with the new operating point
571+
con.x̂0min .-= estim.x̂op # convert to x̂0 with the new operating point
572+
con.x̂0max .-= estim.x̂op # convert to x̂0 with the new operating point
573573
con.A_Ymin .= A_Ymin
574574
con.A_Ymax .= A_Ymax
575575
con.A_x̂min .= A_x̂min

src/estimator/execute.jl

+7-3
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ Set model and operating points of `estim` [`StateEstimator`](@ref) to `model` va
245245
246246
Allows model adaptation of estimators based on [`LinModel`](@ref) at runtime ([`NonLinModel`](@ref)
247247
is not supported). Not supported by [`Luenberger`](@ref) and [`SteadyKalmanFilter`](@ref),
248-
use the time-varying [`KalmanFilter`](@ref) instead. The matrix dimensions and sample time
248+
use the time-varying [`KalmanFilter`](@ref) instead. The [`MovingHorizonEstimator`] model
249+
is kept constant over the estimation horizon ``H_e``. The matrix dimensions and sample time
249250
must stay the same. Note that the observability and controllability of the new augmented
250251
model is not verified (see Extended Help for details).
251252
@@ -272,6 +273,9 @@ julia> setmodel!(kf, LinModel(ss(0.42, 0.5, 1, 0, 4.0))); kf.model.A
272273
"""
273274
function setmodel!(estim::StateEstimator, model::LinModel)
274275
validate_model(estim.model, model)
276+
uop_old = copy(estim.model.uop)
277+
yop_old = copy(estim.model.yop)
278+
dop_old = copy(estim.model.dop)
275279
# --- update model matrices and its operating points ---
276280
estim.model.A .= model.A
277281
estim.model.Bu .= model.Bu
@@ -285,7 +289,7 @@ function setmodel!(estim::StateEstimator, model::LinModel)
285289
estim.model.dop .= model.dop
286290
estim.model.xop .= model.xop
287291
estim.model.fop .= model.fop
288-
setmodel_estimator!(estim, model)
292+
setmodel_estimator!(estim, model, uop_old, yop_old, dop_old)
289293
return estim
290294
end
291295

@@ -300,7 +304,7 @@ end
300304
validate_model(::SimModel, ::SimModel) = error("Only LinModel is supported for setmodel!")
301305

302306
"Update the augmented model matrices of `estim` by default."
303-
function setmodel_estimator!(estim::StateEstimator, model::LinModel)
307+
function setmodel_estimator!(estim::StateEstimator, model::LinModel, _ , _ , _)
304308
As, Cs_u, Cs_y = estim.As, estim.Cs_u, estim.Cs_y
305309
Â, B̂u, Ĉ, B̂d, D̂d, x̂op, f̂op = augment_model(model, As, Cs_u, Cs_y, verify_obsv=false)
306310
# --- update augmented state-space matrices ---

src/estimator/internal_model.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ function init_internalmodel(As, Bs, Cs, Ds)
203203
end
204204

205205
"Update similar values for [`InternalModel`](@ref) estimator."
206-
function setmodel_estimator!(estim::InternalModel, model::LinModel)
206+
function setmodel_estimator!(estim::InternalModel, model::LinModel, _ , _ , _)
207207
Â, B̂u, Ĉ, B̂d, D̂d, x̂op, f̂op = matrices_internalmodel(model)
208208
# --- update augmented state-space matrices ---
209209
estim. .=
@@ -215,7 +215,7 @@ function setmodel_estimator!(estim::InternalModel, model::LinModel)
215215
estim.x̂0 .+= estim.x̂op # convert x̂0 to x̂ with the old operating point
216216
estim.x̂op .= x̂op
217217
estim.f̂op .= f̂op
218-
estim.x̂0 .-= estim.x̂op # convert x̂0 to with the new operating point
218+
estim.x̂0 .-= estim.x̂op # convert to x̂0 with the new operating point
219219
end
220220

221221
@doc raw"""

src/estimator/kalman.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ function SteadyKalmanFilter(model::SM, i_ym, nint_u, nint_ym, Q̂, R̂) where {N
165165
end
166166

167167
"Throw an error if `setmodel!` is called on a SteadyKalmanFilter"
168-
function setmodel_estimator!(estim::SteadyKalmanFilter, model::LinModel)
168+
function setmodel_estimator!(::SteadyKalmanFilter, ::LinModel, _ , _ , _)
169169
error("SteadyKalmanFilter does not support setmodel! (use KalmanFilter instead)")
170170
end
171171

src/estimator/luenberger.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,4 @@ function update_estimate!(estim::Luenberger, u, ym, d=empty(estim.x̂0))
122122
end
123123

124124
"Throw an error if `setmodel!` is called on `Luenberger` observer."
125-
setmodel_estimator!(estim::Luenberger, ::LinModel) = error("Luenberger does not support setmodel!")
125+
setmodel_estimator!(::Luenberger,::LinModel,_,_,_) = error("Luenberger does not support setmodel!")

0 commit comments

Comments
 (0)