Skip to content

Commit 2b9083f

Browse files
committed
doc : add docstring to construct LinModel with a specific state-space representation
1 parent 236a73c commit 2b9083f

File tree

7 files changed

+66
-54
lines changed

7 files changed

+66
-54
lines changed

docs/src/internals/predictive_control.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ The prediction methodology of this module is mainly based on Maciejowski textboo
99
[^1]: Maciejowski, J. 2000, "Predictive control : with constraints", 1st ed., Prentice Hall,
1010
ISBN 978-0201398236.
1111

12-
## Controller Initialization
12+
## Controller Construction
1313

1414
```@docs
1515
ModelPredictiveControl.init_predmat

docs/src/internals/state_estim.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
Pages = ["state_estim.md"]
55
```
66

7-
## Estimator Initialization
7+
## Estimator Construction
88

99
```@docs
1010
ModelPredictiveControl.init_estimstoch
@@ -27,13 +27,22 @@ ModelPredictiveControl.ĥ
2727
ModelPredictiveControl.remove_op!
2828
```
2929

30-
## Update Estimate
30+
## Init Estimate
3131

3232
!!! info
3333
All these methods assume that the operating points are already removed in `u`, `ym`
3434
and `d` arguments. Strickly speaking, the arguments should be called `u0`, `ym0` and
3535
`d0`, following [`setop!`](@ref) notation. The `0` is dropped to simplify the notation.
3636

37+
```@docs
38+
ModelPredictiveControl.init_estimate!
39+
```
40+
41+
## Update Estimate
42+
43+
!!! info
44+
Same as above: the arguments should be called `u0`, `ym0` and `d0`, strickly speaking.
45+
3746
```@docs
3847
ModelPredictiveControl.update_estimate!
3948
```

src/estimator/internal_model.jl

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -214,20 +214,11 @@ function update_estimate!(estim::InternalModel, u, ym, d=Float64[])
214214
return x̂d
215215
end
216216

217-
@doc raw"""
218-
initstate!(estim::InternalModel, u, ym, d=Float64[]) -> x̂d
219-
220-
Init `estim.x̂d` / `x̂s` states from current inputs `u`, meas. outputs `ym` and disturb. `d`.
221-
222-
The deterministic state `estim.x̂d` initialization method is identical to
223-
[`initstate!(::StateEstimator)`](@ref). The stochastic states `estim.x̂s` are init at 0.
224-
"""
225-
function initstate!(estim::InternalModel, u, ym, d=Float64[])
226-
model = estim.model
227-
init_estimate!(estim, model, u, ym, d)
217+
"Init the stochastic states `estim.x̂s` of [`InternalModel`](@ref) at 0. "
218+
function initstate_post!(estim::InternalModel)
228219
# TODO: best method to initialize internal model stochastic states ? not sure...
229220
estim.x̂s[:] = zeros(estim.nxs)
230-
return estim.x̂d
221+
return nothing
231222
end
232223

233224
@doc raw"""

src/estimator/kalman.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ function update_estimate!(estim::ExtendedKalmanFilter, u, ym, d=Float64[])
725725
end
726726

727727
"Initialize the covariance estimate `P̂` for the time-varying Kalman Filters"
728-
function initstate_cov!(
728+
function initstate_post!(
729729
estim::Union{KalmanFilter, UnscentedKalmanFilter, ExtendedKalmanFilter}
730730
)
731731
estim..data[:] = estim.P̂0

src/model/linmodel.jl

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,17 @@ and `:zoh` for manipulated inputs, and `:tustin`, for measured disturbances. Las
6868
the aforementioned discretization methods.
6969
7070
Note that the constructor transforms the system to its minimal realization using [`minreal`](https://juliacontrol.github.io/ControlSystems.jl/stable/lib/constructors/#ControlSystemsBase.minreal)
71-
to favor observability. As a consequence, the final state-space representation may be
72-
different from the one provided in `sys`. It is also converted into a more practical form
73-
(``\mathbf{D_u=0}`` because of the zero-order hold):
71+
to favor controllability and observability. As a consequence, the final state-space
72+
representation may be different from the one provided in `sys`. It is also converted into a
73+
more practical form (``\mathbf{D_u=0}`` because of the zero-order hold):
7474
```math
7575
\begin{aligned}
7676
\mathbf{x}(k+1) &= \mathbf{A x}(k) + \mathbf{B_u u}(k) + \mathbf{B_d d}(k) \\
7777
\mathbf{y}(k) &= \mathbf{C x}(k) + \mathbf{D_d d}(k)
7878
\end{aligned}
7979
```
80+
Use the syntax [`LinModel(A, Bu, C, Bd, Dd, Ts, nu, nx, ny, nd)`](@ref) to force a specific
81+
state-space representation.
8082
"""
8183
function LinModel(
8284
sys::StateSpace,
@@ -180,6 +182,15 @@ function LinModel(sys::DelayLtiSystem, Ts::Real; kwargs...)
180182
return LinModel(sys_dis, Ts; kwargs...)
181183
end
182184

185+
@doc raw"""
186+
LinModel(A, Bu, C, Bd, Dd, Ts, nu, nx, ny, nd)
187+
188+
Construct the model from the discrete state-space matrices `A, Bu, C, Bd, Dd` directly.
189+
190+
This syntax do not modify the state-space representation provided in argument ([`minreal`](https://juliacontrol.github.io/ControlSystems.jl/stable/lib/constructors/#ControlSystemsBase.minreal)
191+
is not called). Care must be taken to ensure that the model is controllable and observable.
192+
"""
193+
LinModel(A, Bu, C, Bd, Dd, Ts, nu, nx, ny, nd)
183194

184195
"""
185196
f(model::LinModel, x, u, d)

src/state_estim.jl

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -283,74 +283,76 @@ end
283283
284284
Init `estim.x̂` states from current inputs `u`, measured outputs `ym` and disturbances `d`.
285285
286-
The method set the error covariance to `estim.P = estim.P̂0` (if applicable) and tries to
287-
find a good steady-state to initialize `estim.x̂` estimate.
286+
The method removes the operating points with [`remove_op!`](@ref) and call
287+
[`init_estimate!`](@ref):
288288
289289
- If `estim.model` is a [`LinModel`](@ref), it finds the steady-state of the augmented model
290290
using `u` and `d` arguments, and uses the `ym` argument to enforce that ``\mathbf{ŷ^m} =
291291
\mathbf{y^m}``. For control applications, this solution produces a bumpless manual to
292-
automatic transfer. See Extended Help for details.
292+
automatic transfer. See [`init_estimate!`](@ref) for details.
293293
- Else, `estim.x̂` is left unchanged. Use [`setstate!`](@ref) to manually modify it.
294294
295+
If applicable, it also sets the error covariance to `estim.P = estim.P̂0`.
296+
295297
# Examples
296298
```jldoctest
297299
julia> estim = SteadyKalmanFilter(LinModel(tf(3, [10, 1]), 0.5), nint_ym=[2]);
298300
299-
julia> u = [1]; ym = [3 - 0.1]; x̂ = round.(initstate!(estim, u, ym), digits=3)
301+
julia> u = [1]; y = [3 - 0.1]; x̂ = round.(initstate!(estim, u, y), digits=3)
300302
3-element Vector{Float64}:
301303
5.0
302304
0.0
303305
-0.1
304306
305-
julia> x̂ ≈ updatestate!(estim, u, ym)
307+
julia> x̂ ≈ updatestate!(estim, u, y)
306308
true
307309
308-
julia> evaloutput(estim) ≈ ym
310+
julia> evaloutput(estim) ≈ y
309311
true
310312
```
311313
312-
# Extended Help
313-
Based on [`setop!`](@ref) notation, the resulting system to solve for [`LinModel`](@ref) is:
314+
"""
315+
function initstate!(estim::StateEstimator, u, ym, d=Float64[])
316+
# --- init state estimate ----
317+
u0, d0, ym0 = remove_op!(estim, u, d, ym)
318+
init_estimate!(estim, estim.model, u0, ym0, d0)
319+
# --- init covariance error estimate, if applicable ---
320+
initstate_post!(estim)
321+
return estim.
322+
end
323+
324+
@doc raw"""
325+
init_estimate!(estim::StateEstimator, model::LinModel, u, ym, d)
326+
327+
Init `estim.x̂` estimate with the steady-state solution if `model` is a [`LinModel`](@ref).
328+
329+
Using `u`, `ym` and `d` arguments, the steady-state problem combined to the equality
330+
constraint ``\mathbf{ŷ^m} = \mathbf{y^m}`` engenders the following system to solve :
314331
```math
315332
\begin{bmatrix}
316333
\mathbf{I} - \mathbf{Â} \\
317334
\mathbf{Ĉ}
318335
\end{bmatrix} \mathbf{x̂} =
319336
\begin{bmatrix}
320-
\mathbf{B̂_u u_0} + \mathbf{B̂_d d_0} \\
321-
\mathbf{y_0} - \mathbf{D̂_d d_0}
337+
\mathbf{B̂_u u} + \mathbf{B̂_d d} \\
338+
\mathbf{y} - \mathbf{D̂_d d}
322339
\end{bmatrix}
323340
```
324-
with ``\mathbf{u_0 = u - u_{op}}`` and ``\mathbf{d_0 = d - d_{op}}``. The vector
325-
``\mathbf{y_0}`` comprises the measured ``\mathbf{y_0^m = y^m - y_{op}^m}`` and unmeasured
326-
``\mathbf{y_0^u = 0}`` outputs.
341+
in which ``\mathbf{y}`` comprises the measured ``\mathbf{y^m}`` and unmeasured
342+
``\mathbf{y^u = 0}`` outputs.
327343
"""
328-
function initstate!(estim::StateEstimator, u, ym, d=Float64[])
329-
model = estim.model
330-
# --- init covariance error estimate (if applicable) ---
331-
initstate_cov!(estim)
332-
# --- init lastu0 for PredictiveControllers ---
333-
estim.lastu0[:] = u - model.uop
334-
# --- init state estimate ----
335-
init_estimate!(estim, model, u, ym, d)
336-
return estim.
337-
end
338-
339-
"By default, state estimators do not need initialization of covariance estimate."
340-
initstate_cov!(::StateEstimator) = nothing
341-
342-
"Init estimate x̂ with the steady-state solution for if `model` is a [`LinModel`](@ref)."
343344
function init_estimate!(estim::StateEstimator, model::LinModel, u, ym, d)
344345
Â, B̂u, Ĉ, B̂d, D̂d = estim.Â, estim.B̂u, estim.Ĉ, estim.B̂d, estim.D̂d
345-
y0 = zeros(model.ny)
346-
y0[estim.i_ym] = ym - model.yop[estim.i_ym]
347-
u0 = u - model.uop
348-
d0 = d - model.dop
349-
estim.x̂[:] = [(I - Â); Ĉ]\[B̂u*u0 + B̂d*d0; y0 - D̂d*d0]
346+
y = zeros(model.ny)
347+
y[estim.i_ym] = ym
348+
estim.x̂[:] = [(I - Â); Ĉ]\[B̂u*u + B̂d*d; y - D̂d*d]
350349
end
351-
"Do nothing if `model` is not a [`LinModel`](@ref)."
350+
"Left `estim.x̂` estimate unchanged if `model` is not a [`LinModel`](@ref)."
352351
init_estimate!(::StateEstimator, ::SimModel, _ , _ , _ ) = nothing
353352

353+
"By default, do nothing at the end of `initstate!` (used to init the covariance estimate)."
354+
initstate_post!(::StateEstimator) = nothing
355+
354356
@doc raw"""
355357
evaloutput(estim::StateEstimator, d=Float64[]) -> ŷ
356358

test/test_sim_model.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ Gss2 = c2d(sys_ss[:,1:2], 0.5Ts, :zoh)
5757

5858
linmodel6 = LinModel([delay(4) delay(4)]*sys,Ts,i_d=[3])
5959
@test linmodel6.nx == 3
60-
println(eigvals(linmodel6.A))
6160
@test sum(eigvals(linmodel6.A) .≈ 0) == 1
6261

6362
linmodel7 = LinModel(

0 commit comments

Comments
 (0)