Skip to content

Commit 9b2bece

Browse files
committed
doc: cleaning UnscentedKalmanFilter internal doc
1 parent 7e3e789 commit 9b2bece

File tree

3 files changed

+37
-27
lines changed

3 files changed

+37
-27
lines changed

src/controller/construct.jl

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ The predictive controllers support both soft and hard constraints, defined by:
4444
\mathbf{u_{min} - c_{u_{min}}} ϵ ≤&&\ \mathbf{u}(k+j) &≤ \mathbf{u_{max} + c_{u_{max}}} ϵ &&\qquad j = 0, 1 ,..., H_p - 1 \\
4545
\mathbf{Δu_{min} - c_{Δu_{min}}} ϵ ≤&&\ \mathbf{Δu}(k+j) &≤ \mathbf{Δu_{max} + c_{Δu_{max}}} ϵ &&\qquad j = 0, 1 ,..., H_c - 1 \\
4646
\mathbf{y_{min} - c_{y_{min}}} ϵ ≤&&\ \mathbf{ŷ}(k+j) &≤ \mathbf{y_{max} + c_{y_{max}}} ϵ &&\qquad j = 1, 2 ,..., H_p \\
47-
\mathbf{x̂_{min} - c_{x̂_{min}}} ϵ ≤&&\ \mathbf{x̂}_{k-1}(k+j) &≤ \mathbf{x̂_{max} + c_{x̂_{max}}} ϵ &&\qquad j = H_p
47+
\mathbf{x̂_{min} - c_{x̂_{min}}} ϵ ≤&&\ \mathbf{x̂}_{i}(k+j) &≤ \mathbf{x̂_{max} + c_{x̂_{max}}} ϵ &&\qquad j = H_p
4848
\end{alignat*}
4949
```
5050
and also ``ϵ ≥ 0``. The last line is the terminal constraints applied on the states at the
@@ -94,8 +94,10 @@ LinMPC controller with a sample time Ts = 4.0 s, OSQP optimizer, SteadyKalmanFil
9494
Terminal constraints provide closed-loop stability guarantees on the nominal plant model.
9595
They can render an unfeasible problem however. In practice, a sufficiently large
9696
prediction horizon ``H_p`` without terminal constraints is typically enough for
97-
stability. Note that terminal constraints are applied on the augmented state vector
98-
``\mathbf{x̂}`` (see [`SteadyKalmanFilter`](@ref) for details on augmentation).
97+
stability. If `mpc.estim.direct==true`, the state is estimated at ``i = k`` (the current
98+
time step), otherwise at ``i = k - 1``. Note that terminal constraints are applied on the
99+
augmented state vector ``\mathbf{x̂}`` (see [`SteadyKalmanFilter`](@ref) for details on
100+
augmentation).
99101
100102
For variable constraints, the bounds can be modified after calling [`moveinput!`](@ref),
101103
that is, at runtime, but not the softness parameters ``\mathbf{c}``. It is not possible
@@ -433,16 +435,16 @@ The model predictions are evaluated from the deviation vectors (see [`setop!`](@
433435
&= \mathbf{E ΔU} + \mathbf{F}
434436
\end{aligned}
435437
```
436-
in which ``\mathbf{x̂_0}(k) = \mathbf{x̂}_{k-1}(k) - \mathbf{x̂_{op}}`` and
437-
``\mathbf{x̂}_{k-1}(k)`` is the state estimated at the last control period. The predicted
438-
outputs ``\mathbf{Ŷ_0}`` and measured disturbances ``\mathbf{D̂_0}`` respectively include
439-
``\mathbf{ŷ_0}(k+j)`` and ``\mathbf{d̂_0}(k+j)`` values with ``j=1`` to ``H_p``, and input
440-
increments ``\mathbf{ΔU}``, ``\mathbf{Δu}(k+j)`` from ``j=0`` to ``H_c-1``. The vector
441-
``\mathbf{B}`` contains the contribution for non-zero state ``\mathbf{x̂_{op}}`` and state
442-
update ``\mathbf{f̂_{op}}`` operating points (for linearization at non-equilibrium point, see
443-
[`linearize`](@ref)). The stochastic predictions ``\mathbf{Ŷ_s=0}`` if `estim` is not a
444-
[`InternalModel`](@ref), see [`init_stochpred`](@ref). The method also computes similar
445-
matrices for the predicted terminal states at ``k+H_p``:
438+
in which ``\mathbf{x̂_0}(k) = \mathbf{x̂}_{i}(k) - \mathbf{x̂_{op}}``, with ``i = k`` if
439+
`estim.direct==true`, otherwise ``i = k - 1``. The predicted outputs ``\mathbf{Ŷ_0}`` and
440+
measured disturbances ``\mathbf{D̂_0}`` respectively include ``\mathbf{ŷ_0}(k+j)`` and
441+
``\mathbf{d̂_0}(k+j)`` values with ``j=1`` to ``H_p``, and input increments ``\mathbf{ΔU}``,
442+
``\mathbf{Δu}(k+j)`` from ``j=0`` to ``H_c-1``. The vector ``\mathbf{B}`` contains the
443+
contribution for non-zero state ``\mathbf{x̂_{op}}`` and state update ``\mathbf{f̂_{op}}``
444+
operating points (for linearization at non-equilibrium point, see [`linearize`](@ref)). The
445+
stochastic predictions ``\mathbf{Ŷ_s=0}`` if `estim` is not a [`InternalModel`](@ref), see
446+
[`init_stochpred`](@ref). The method also computes similar matrices for the predicted
447+
terminal states at ``k+H_p``:
446448
```math
447449
\begin{aligned}
448450
\mathbf{x̂_0}(k+H_p) &= \mathbf{e_x̂ ΔU} + \mathbf{g_x̂ d_0}(k) + \mathbf{j_x̂ D̂_0}

src/controller/execute.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ predictstoch!(mpc::PredictiveController, ::StateEstimator) = (mpc.F .= 0; nothin
253253
254254
Set `b` vector for the linear model inequality constraints (``\mathbf{A ΔŨ ≤ b}``).
255255
256-
Also init ``\mathbf{f_x̂} = \mathbf{g_x̂ d}(k) + \mathbf{j_x̂ D̂} + \mathbf{k_x̂ x̂}_{k-1}(k) + \mathbf{v_x̂ u}(k-1) + \mathbf{b_x̂}``
256+
Also init ``\mathbf{f_x̂} = \mathbf{g_x̂ d}(k) + \mathbf{j_x̂ D̂} + \mathbf{k_x̂ x̂_0}(k) + \mathbf{v_x̂ u}(k-1) + \mathbf{b_x̂}``
257257
vector for the terminal constraints, see [`init_predmat`](@ref).
258258
"""
259259
function linconstraint!(mpc::PredictiveController, model::LinModel)

src/estimator/kalman.jl

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -698,13 +698,15 @@ function correct_estimate!(estim::UnscentedKalmanFilter, y0m, d0)
698698
X̄, Ȳm = X̂0, Ŷ0m
699699
X̄ .= X̂0 .- x̂0
700700
Ȳm .= Ŷ0m .- ŷ0m
701+
# TODO: use estim.buffer.R̂ here to reduce allocations
701702
.data .= Ȳm ** Ȳm' .+
702703
mul!(K̂, X̄, lmul!(Ŝ, Ȳm'))
703704
rdiv!(K̂, cholesky(M̂))
704705
= ŷ0m
705706
v̂ .= y0m .- ŷ0m
706707
x̂0corr, P̂corr = estim.x̂0, estim.
707708
mul!(x̂0corr, K̂, v̂, 1, 1)
709+
# TODO: use estim.buffer.P̂ and estim.buffer.Q̂ here to reduce allocations
708710
P̂corr .= Hermitian(P̂ .-**', :L)
709711
return nothing
710712
end
@@ -714,14 +716,16 @@ end
714716
715717
Update [`UnscentedKalmanFilter`](@ref) state `estim.x̂0` and covariance estimate `estim.P̂`.
716718
717-
It implements the unscented Kalman Filter in its predictor (observer) form, based on the
718-
generalized unscented transform[^3]. See [`init_ukf`](@ref) for the definition of the
719-
constants ``\mathbf{m̂, Ŝ}`` and ``γ``.
719+
It implements the unscented Kalman Filter based on the generalized unscented transform[^3].
720+
See [`init_ukf`](@ref) for the definition of the constants ``\mathbf{m̂, Ŝ}`` and ``γ``. The
721+
superscript in e.g. ``\mathbf{X̂}_{k-1}^j(k)`` refers the vector at the ``j``th column of
722+
``\mathbf{X̂}_{k-1}(k)``. The symbol ``\mathbf{0}`` is a vector with zeros. The number of
723+
sigma points is ``n_σ = 2 n_\mathbf{x̂} + 1``. The matrices ``\sqrt{\mathbf{P̂}_{k-1}(k)}``
724+
and ``\sqrt{\mathbf{P̂}_{k}(k)}`` are the the lower triangular factors of [`cholesky`](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#LinearAlgebra.cholesky)
725+
results. The correction and prediction step equations are provided below. The correction
726+
step is skipped if `estim.direct == true` since it's already done by the user.
720727
721-
Denoting ``\mathbf{x̂}_{k-1}(k)`` as the state for the current time ``k`` estimated at the
722-
last period ``k-1``, ``\mathbf{0}``, a null vector, ``n_σ = 2 n_\mathbf{x̂} + 1``, the number
723-
of sigma points, and ``\mathbf{X̂}_{k-1}^j(k)``, the vector at the ``j``th column of
724-
``\mathbf{X̂}_{k-1}(k)``, the estimator updates the states with:
728+
# Correction Step
725729
```math
726730
\begin{aligned}
727731
\mathbf{X̂}_{k-1}(k) &= \bigg[\begin{matrix} \mathbf{x̂}_{k-1}(k) & \mathbf{x̂}_{k-1}(k) & \cdots & \mathbf{x̂}_{k-1}(k) \end{matrix}\bigg] + \bigg[\begin{matrix} \mathbf{0} & γ \sqrt{\mathbf{P̂}_{k-1}(k)} & -γ \sqrt{\mathbf{P̂}_{k-1}(k)} \end{matrix}\bigg] \\
@@ -733,17 +737,19 @@ of sigma points, and ``\mathbf{X̂}_{k-1}^j(k)``, the vector at the ``j``th colu
733737
\mathbf{K̂}(k) &= \mathbf{X̄}_{k-1}(k) \mathbf{Ŝ} \mathbf{Ȳ^m}'(k) \mathbf{M̂^{-1}}(k) \\
734738
\mathbf{x̂}_k(k) &= \mathbf{x̂}_{k-1}(k) + \mathbf{K̂}(k) \big[ \mathbf{y^m}(k) - \mathbf{ŷ^m}(k) \big] \\
735739
\mathbf{P̂}_k(k) &= \mathbf{P̂}_{k-1}(k) - \mathbf{K̂}(k) \mathbf{M̂}(k) \mathbf{K̂}'(k) \\
740+
\end{aligned}
741+
```
742+
743+
# Prediction Step
744+
```math
745+
\begin{aligned}
736746
\mathbf{X̂}_k(k) &= \bigg[\begin{matrix} \mathbf{x̂}_{k}(k) & \mathbf{x̂}_{k}(k) & \cdots & \mathbf{x̂}_{k}(k) \end{matrix}\bigg] + \bigg[\begin{matrix} \mathbf{0} & \gamma \sqrt{\mathbf{P̂}_{k}(k)} & - \gamma \sqrt{\mathbf{P̂}_{k}(k)} \end{matrix}\bigg] \\
737747
\mathbf{X̂}_{k}(k+1) &= \bigg[\begin{matrix} \mathbf{f̂}\Big( \mathbf{X̂}_{k}^{1}(k), \mathbf{u}(k), \mathbf{d}(k) \Big) & \mathbf{f̂}\Big( \mathbf{X̂}_{k}^{2}(k), \mathbf{u}(k), \mathbf{d}(k) \Big) & \cdots & \mathbf{f̂}\Big( \mathbf{X̂}_{k}^{n_σ}(k), \mathbf{u}(k), \mathbf{d}(k) \Big) \end{matrix}\bigg] \\
738748
\mathbf{x̂}_{k}(k+1) &= \mathbf{X̂}_{k}(k+1)\mathbf{m̂} \\
739749
\mathbf{X̄}_k(k+1) &= \begin{bmatrix} \mathbf{X̂}_{k}^{1}(k+1) - \mathbf{x̂}_{k}(k+1) & \mathbf{X̂}_{k}^{2}(k+1) - \mathbf{x̂}_{k}(k+1) & \cdots &\, \mathbf{X̂}_{k}^{n_σ}(k+1) - \mathbf{x̂}_{k}(k+1) \end{bmatrix} \\
740750
\mathbf{P̂}_k(k+1) &= \mathbf{X̄}_k(k+1) \mathbf{Ŝ} \mathbf{X̄}_k'(k+1) + \mathbf{Q̂}
741-
\end{aligned}
751+
\end{aligned}
742752
```
743-
by using the lower triangular factor of [`cholesky`](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#LinearAlgebra.cholesky)
744-
to compute ``\sqrt{\mathbf{P̂}_{k-1}(k)}`` and ``\sqrt{\mathbf{P̂}_{k}(k)}``. The matrices
745-
``\mathbf{P̂, Q̂, R̂}`` are the covariance of the estimation error, process noise and sensor
746-
noise, respectively.
747753
748754
[^3]: Simon, D. 2006, "Chapter 14: The unscented Kalman filter" in "Optimal State Estimation:
749755
Kalman, H∞, and Nonlinear Approaches", John Wiley & Sons, p. 433–459, <https://doi.org/10.1002/0470045345.ch14>,
@@ -773,6 +779,7 @@ function update_estimate!(estim::UnscentedKalmanFilter, y0m, d0, u0)
773779
X̄next = X̂0next
774780
X̄next .= X̂0next .- x̂0next
775781
P̂next = P̂corr
782+
# TODO: use estim.buffer.P̂ and estim.buffer.Q̂ here to reduce allocations
776783
P̂next.data .= X̄next ** X̄next' .+
777784
x̂0next .+= estim.f̂op .- estim.x̂op
778785
estim.x̂0 .= x̂0next
@@ -941,7 +948,7 @@ end
941948
Update [`ExtendedKalmanFilter`](@ref) state `estim.x̂0` and covariance `estim.P̂`.
942949
943950
The equations are similar to [`update_estimate!(::KalmanFilter)`](@ref) but with the
944-
substitutions ``\mathbf{ = }(k)`` and ``\mathbf{Ĉ^m = Ĥ^m}(k)``, the Jacobians of the
951+
substitutions ``\mathbf{Ĉ^m = Ĥ^m}(k)`` and ``\mathbf{ = }(k)``, the Jacobians of the
945952
augmented process model:
946953
```math
947954
\begin{aligned}
@@ -952,6 +959,7 @@ augmented process model:
952959
The matrix ``\mathbf{Ĥ^m}`` is the rows of ``\mathbf{Ĥ}`` that are measured outputs. The
953960
function [`ForwardDiff.jacobian`](https://juliadiff.org/ForwardDiff.jl/stable/user/api/#ForwardDiff.jacobian)
954961
automatically computes them. The correction and prediction step equations are provided below.
962+
The correction step is skipped if `estim.direct == true` since it's already done by the user.
955963
956964
# Correction Step
957965
```math

0 commit comments

Comments
 (0)