Skip to content

Commit 8338557

Browse files
authored
Merge pull request #58 from JuliaControl/dev_vector_doc
doc: clarify notation `update_estimate!` and imc block diagram
2 parents d1b1123 + b685d87 commit 8338557

File tree

9 files changed

+999
-131
lines changed

9 files changed

+999
-131
lines changed

docs/src/assets/imc.svg

Lines changed: 855 additions & 0 deletions
Loading

docs/src/internals/state_estim.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,12 @@ ModelPredictiveControl.init_estimate!
5555
## Update Estimate
5656

5757
!!! info
58-
All these methods assume that the operating points are already removed in `u`, `ym`
59-
and `d` arguments. Strickly speaking, the arguments should be called `u0`, `ym0` and
60-
`d0`, following [`setop!`](@ref) notation. The `0` is dropped to simplify the notation.
58+
All these methods assume that the `u0`, `y0m` and `d0` arguments are deviation vectors
59+
from their respective operating points (see [`setop!`](@ref)). The associated equations
60+
in the documentation drops the ``\mathbf{0}`` in subscript to simplify the notation.
61+
Strictly speaking, the manipulated inputs, measured outputs, measured disturbances and
62+
estimated states should be denoted with ``\mathbf{u_0, y_0^m, d_0}`` and
63+
``\mathbf{x̂_0}``, respectively.
6164

6265
```@docs
6366
ModelPredictiveControl.update_estimate!

src/controller/execute.jl

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -348,30 +348,33 @@ function predict!(Ŷ0, x̂0, x̂0next, u0, û0, mpc::PredictiveController, mod
348348
end
349349

350350
"""
351-
obj_nonlinprog!(U0 , _ , _ , mpc::PredictiveController, model::LinModel, Ŷ0, ΔŨ)
351+
obj_nonlinprog!(U0 , , _ , mpc::PredictiveController, model::LinModel, Ŷ0, ΔŨ)
352352
353353
Nonlinear programming objective function when `model` is a [`LinModel`](@ref).
354354
355355
The function is called by the nonlinear optimizer of [`NonLinMPC`](@ref) controllers. It can
356356
also be called on any [`PredictiveController`](@ref)s to evaluate the objective function `J`
357-
at specific input increments `ΔŨ` and predictions `Ŷ0` values. It mutates the `U0` argument.
357+
at specific input increments `ΔŨ` and predictions `Ŷ0` values. It mutates the `U0` and
358+
`Ȳ` arguments.
358359
"""
359360
function obj_nonlinprog!(
360-
U0, _ , _ , mpc::PredictiveController, model::LinModel, Ŷ0, ΔŨ::AbstractVector{NT}
361+
U0, , _ , mpc::PredictiveController, model::LinModel, Ŷ0, ΔŨ::AbstractVector{NT}
361362
) where NT <: Real
362363
J = obj_quadprog(ΔŨ, mpc.H̃, mpc.q̃) + mpc.p[]
363364
if !iszero(mpc.E)
364-
ny, Hp, D̂E = model.ny, mpc.Hp, mpc.D̂E
365-
U = U0
366-
mul!(U, mpc.S̃, ΔŨ)
367-
U .+= mpc.T_lastu0 .+ mpc.Uop
368-
UE = @views [U; U[(end - model.nu + 1):end]]
369-
ŶE = Vector{NT}(undef, ny + ny*Hp)
370-
ŶE[1:ny] .= mpc.
371-
ŶE[1+ny:end] .= Ŷ0 .+ mpc.Yop
372-
J += mpc.E*mpc.JE(UE, ŶE, D̂E)
365+
ny, Hp, ŷ, D̂E = model.ny, mpc.Hp, mpc.ŷ, mpc.D̂E
366+
U = U0
367+
U .+= mpc.Uop
368+
uend = @views U[(end-model.nu+1):end]
369+
=
370+
Ŷ .= Ŷ0 .+ mpc.Yop
371+
UE = [U; uend]
372+
ŶE = [ŷ; Ŷ]
373+
E_JE = mpc.E*mpc.JE(UE, ŶE, D̂E)
374+
else
375+
E_JE = 0.0
373376
end
374-
return J
377+
return J + E_JE
375378
end
376379

377380
"""
@@ -403,13 +406,14 @@ function obj_nonlinprog!(
403406
end
404407
# --- economic term ---
405408
if !iszero(mpc.E)
406-
ny, Hp, D̂E = model.ny, mpc.Hp, mpc.D̂E
409+
ny, Hp, ŷ, D̂E = model.ny, mpc.Hp, mpc., mpc.D̂E
407410
U = U0
408-
U .+= mpc.Uop
409-
UE = @views [U; U[(end - model.nu + 1):end]]
410-
ŶE = Vector{NT}(undef, ny + ny*Hp)
411-
ŶE[1:ny] .= mpc.
412-
ŶE[1+ny:end] .= Ŷ0 .+ mpc.Yop
411+
U .+= mpc.Uop
412+
uend = @views U[(end-model.nu+1):end]
413+
=
414+
Ŷ .= Ŷ0 .+ mpc.Yop
415+
UE = [U; uend]
416+
ŶE = [ŷ; Ŷ]
413417
E_JE = mpc.E*mpc.JE(UE, ŶE, D̂E)
414418
else
415419
E_JE = 0.0

src/estimator/execute.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,10 @@ 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 [`MovingHorizonEstimator`] model
249-
is kept constant over the estimation horizon ``H_e``. The matrix dimensions and sample time
250-
must stay the same. Note that the observability and controllability of the new augmented
251-
model is not verified (see Extended Help for details).
248+
use the time-varying [`KalmanFilter`](@ref) instead. The [`MovingHorizonEstimator`](@ref)
249+
model is kept constant over the estimation horizon ``H_e``. The matrix dimensions and sample
250+
time must stay the same. Note that the observability and controllability of the new
251+
augmented model is not verified (see Extended Help for more info).
252252
253253
# Examples
254254
```jldoctest

src/estimator/internal_model.jl

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ Construct an internal model estimator based on `model` ([`LinModel`](@ref) or [`
5656
unmeasured ``\mathbf{y^u}``. `model` evaluates the deterministic predictions
5757
``\mathbf{ŷ_d}``, and `stoch_ym`, the stochastic predictions of the measured outputs
5858
``\mathbf{ŷ_s^m}`` (the unmeasured ones being ``\mathbf{ŷ_s^u=0}``). The predicted outputs
59-
sum both values : ``\mathbf{ŷ = ŷ_d + ŷ_s}``.
59+
sum both values : ``\mathbf{ŷ = ŷ_d + ŷ_s}``. See the Extended Help for more details.
6060
6161
!!! warning
6262
`InternalModel` estimator does not work if `model` is integrating or unstable. The
@@ -81,7 +81,10 @@ InternalModel estimator with a sample time Ts = 0.5 s, LinModel and:
8181
supposes 1 integrator per measured outputs by default, assuming that the current stochastic
8282
estimate ``\mathbf{ŷ_s^m}(k) = \mathbf{y^m}(k) - \mathbf{ŷ_d^m}(k)`` is constant in the
8383
future. This is the dynamic matrix control (DMC) strategy, which is simple but sometimes
84-
too aggressive. Additional poles and zeros in `stoch_ym` can mitigate this.
84+
too aggressive. Additional poles and zeros in `stoch_ym` can mitigate this. The following
85+
block diagram summarizes the internal model structure.
86+
87+
![block diagram of the internal model structure](../assets/imc.svg)
8588
"""
8689
function InternalModel(
8790
model::SM;
@@ -219,9 +222,9 @@ function setmodel_estimator!(estim::InternalModel, model::LinModel, _ , _ , _)
219222
end
220223

221224
@doc raw"""
222-
update_estimate!(estim::InternalModel, u, ym, d=[])
225+
update_estimate!(estim::InternalModel, u0, y0m, d0=[])
223226
224-
Update `estim.x̂0`/`x̂d`/`x̂s` with current inputs `u`, measured outputs `ym` and dist. `d`.
227+
Update `estim.x̂0`/`x̂d`/`x̂s` with current inputs `u0`, measured outputs `y0m` and dist. `d0`.
225228
226229
The [`InternalModel`](@ref) updates the deterministic `x̂d` and stochastic `x̂s` estimates with:
227230
```math
@@ -234,19 +237,19 @@ This estimator does not augment the state vector, thus ``\mathbf{x̂ = x̂_d}``.
234237
[`init_internalmodel`](@ref) for details.
235238
"""
236239
function update_estimate!(
237-
estim::InternalModel{NT, SM}, u, ym, d=empty(estim.x̂0)
240+
estim::InternalModel{NT, SM}, u0, y0m, d0=empty(estim.x̂0)
238241
) where {NT<:Real, SM}
239242
model = estim.model
240243
x̂d, x̂s = estim.x̂d, estim.x̂s
241244
# -------------- deterministic model ---------------------
242-
ŷd, x̂dnext = Vector{NT}(undef, model.ny), Vector{NT}(undef, model.nx)
243-
h!(ŷd, model, x̂d, d)
244-
f!(x̂dnext, model, x̂d, u, d)
245+
ŷ0d, x̂dnext = Vector{NT}(undef, model.ny), Vector{NT}(undef, model.nx)
246+
h!(ŷ0d, model, x̂d, d0)
247+
f!(x̂dnext, model, x̂d, u0, d0)
245248
x̂d .= x̂dnext # this also updates estim.x̂0 (they are the same object)
246249
# --------------- stochastic model -----------------------
247250
x̂snext = Vector{NT}(undef, estim.nxs)
248251
ŷs = zeros(NT, model.ny)
249-
ŷs[estim.i_ym] = ym - ŷd[estim.i_ym] # ŷs=0 for unmeasured outputs
252+
ŷs[estim.i_ym] = y0m - ŷ0d[estim.i_ym] # ŷs=0 for unmeasured outputs
250253
mul!(x̂snext, estim.Âs, x̂s)
251254
mul!(x̂snext, estim.B̂s, ŷs, 1, 1)
252255
x̂s .= x̂snext

0 commit comments

Comments
 (0)