Skip to content

Commit 6df51d9

Browse files
committed
Umin and Umax have now nu*Hp elements
instead of `nu*Hc`
1 parent f362878 commit 6df51d9

File tree

6 files changed

+101
-109
lines changed

6 files changed

+101
-109
lines changed

src/controller/explicitmpc.jl

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
struct ExplicitMPC{S<:StateEstimator} <: PredictiveController
2-
estim::S
1+
struct ExplicitMPC{SE<:StateEstimator} <: PredictiveController
2+
estim::SE
33
ΔŨ::Vector{Float64}
44
::Vector{Float64}
55
Hp::Int
@@ -12,9 +12,8 @@ struct ExplicitMPC{S<:StateEstimator} <: PredictiveController
1212
R̂u::Vector{Float64}
1313
R̂y::Vector{Float64}
1414
noR̂u::Bool
15-
S̃_Hp::Matrix{Bool}
16-
T_Hp::Matrix{Bool}
17-
T_Hc::Matrix{Bool}
15+
::Matrix{Bool}
16+
T::Matrix{Bool}
1817
::Matrix{Float64}
1918
F::Vector{Float64}
2019
G::Matrix{Float64}
@@ -31,7 +30,7 @@ struct ExplicitMPC{S<:StateEstimator} <: PredictiveController
3130
::Vector{Float64}
3231
Ŷop::Vector{Float64}
3332
Dop::Vector{Float64}
34-
function ExplicitMPC{S}(estim::S, Hp, Hc, Mwt, Nwt, Lwt) where {S<:StateEstimator}
33+
function ExplicitMPC{SE}(estim::SE, Hp, Hc, Mwt, Nwt, Lwt) where {SE<:StateEstimator}
3534
model = estim.model
3635
nu, ny, nd = model.nu, model.ny, model.nd
3736
= zeros(ny)
@@ -44,10 +43,10 @@ struct ExplicitMPC{S<:StateEstimator} <: PredictiveController
4443
C = Cwt
4544
R̂y, R̂u = zeros(ny*Hp), zeros(nu*Hp) # dummy vals (updated just before optimization)
4645
noR̂u = iszero(L_Hp)
47-
S_Hp, T_Hp, S_Hc, T_Hc = init_ΔUtoU(nu, Hp, Hc)
46+
S, T = init_ΔUtoU(nu, Hp, Hc)
4847
E, F, G, J, K, Q = init_predmat(estim, model, Hp, Hc)
49-
_ , S̃_Hp, Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S_Hp, S_Hc, N_Hc, E)
50-
P̃, q̃, p = init_quadprog(model, Ẽ, S̃_Hp, M_Hp, Ñ_Hc, L_Hp)
48+
_ , , Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S, N_Hc, E)
49+
P̃, q̃, p = init_quadprog(model, Ẽ, , M_Hp, Ñ_Hc, L_Hp)
5150
P̃_chol = cholesky(P̃)
5251
Ks, Ps = init_stochpred(estim, Hp)
5352
d, D̂ = zeros(nd), zeros(nd*Hp)
@@ -59,7 +58,7 @@ struct ExplicitMPC{S<:StateEstimator} <: PredictiveController
5958
ΔŨ, ŷ,
6059
Hp, Hc,
6160
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, R̂u, R̂y, noR̂u,
62-
S̃_Hp, T_Hp, T_Hc,
61+
S̃, T,
6362
Ẽ, F, G, J, K, Q, P̃, q̃, p,
6463
P̃_chol,
6564
Ks, Ps,
@@ -148,13 +147,13 @@ ExplicitMPC controller with a sample time Ts = 4.0 s, KalmanFilter estimator and
148147
```
149148
"""
150149
function ExplicitMPC(
151-
estim::S;
150+
estim::SE;
152151
Hp::Union{Int, Nothing} = nothing,
153152
Hc::Int = DEFAULT_HC,
154153
Mwt = fill(DEFAULT_MWT, estim.model.ny),
155154
Nwt = fill(DEFAULT_NWT, estim.model.nu),
156155
Lwt = fill(DEFAULT_LWT, estim.model.nu)
157-
) where {S<:StateEstimator}
156+
) where {SE<:StateEstimator}
158157
isa(estim.model, LinModel) || error("estim.model type must be LinModel")
159158
poles = eigvals(estim.model.A)
160159
nk = sum(poles .≈ 0)
@@ -165,7 +164,7 @@ function ExplicitMPC(
165164
@warn("prediction horizon Hp ($Hp) ≤ number of delays in model "*
166165
"($nk), the closed-loop system may be zero-gain (unresponsive) or unstable")
167166
end
168-
return ExplicitMPC{S}(estim, Hp, Hc, Mwt, Nwt, Lwt)
167+
return ExplicitMPC{SE}(estim, Hp, Hc, Mwt, Nwt, Lwt)
169168
end
170169

171170
setconstraint!(::ExplicitMPC,kwargs...) = error("ExplicitMPC does not support constraints.")

src/controller/linmpc.jl

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
struct LinMPC{S<:StateEstimator} <: PredictiveController
2-
estim::S
1+
struct LinMPC{SE<:StateEstimator} <: PredictiveController
2+
estim::SE
33
optim::JuMP.Model
44
con::ControllerConstraint
55
ΔŨ::Vector{Float64}
@@ -14,9 +14,8 @@ struct LinMPC{S<:StateEstimator} <: PredictiveController
1414
R̂u::Vector{Float64}
1515
R̂y::Vector{Float64}
1616
noR̂u::Bool
17-
S̃_Hp::Matrix{Bool}
18-
T_Hp::Matrix{Bool}
19-
T_Hc::Matrix{Bool}
17+
::Matrix{Bool}
18+
T::Matrix{Bool}
2019
::Matrix{Float64}
2120
F::Vector{Float64}
2221
G::Matrix{Float64}
@@ -32,7 +31,7 @@ struct LinMPC{S<:StateEstimator} <: PredictiveController
3231
::Vector{Float64}
3332
Ŷop::Vector{Float64}
3433
Dop::Vector{Float64}
35-
function LinMPC{S}(estim::S, Hp, Hc, Mwt, Nwt, Lwt, Cwt, optim) where {S<:StateEstimator}
34+
function LinMPC{SE}(estim::SE, Hp, Hc, Mwt, Nwt, Lwt, Cwt, optim) where {SE<:StateEstimator}
3635
model = estim.model
3736
nu, ny, nd = model.nu, model.ny, model.nd
3837
= zeros(ny)
@@ -44,10 +43,10 @@ struct LinMPC{S<:StateEstimator} <: PredictiveController
4443
C = Cwt
4544
R̂y, R̂u = zeros(ny*Hp), zeros(nu*Hp) # dummy vals (updated just before optimization)
4645
noR̂u = iszero(L_Hp)
47-
S_Hp, T_Hp, S_Hc, T_Hc = init_ΔUtoU(nu, Hp, Hc)
46+
S, T = init_ΔUtoU(nu, Hp, Hc)
4847
E, F, G, J, K, Q = init_predmat(estim, model, Hp, Hc)
49-
con, S̃_Hp, Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S_Hp, S_Hc, N_Hc, E)
50-
P̃, q̃, p = init_quadprog(model, Ẽ, S̃_Hp, M_Hp, Ñ_Hc, L_Hp)
48+
con, , Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S, N_Hc, E)
49+
P̃, q̃, p = init_quadprog(model, Ẽ, , M_Hp, Ñ_Hc, L_Hp)
5150
Ks, Ps = init_stochpred(estim, Hp)
5251
d, D̂ = zeros(nd), zeros(nd*Hp)
5352
Ŷop, Dop = repeat(model.yop, Hp), repeat(model.dop, Hp)
@@ -58,7 +57,7 @@ struct LinMPC{S<:StateEstimator} <: PredictiveController
5857
ΔŨ, ŷ,
5958
Hp, Hc,
6059
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, R̂u, R̂y, noR̂u,
61-
S̃_Hp, T_Hp, T_Hc,
60+
S̃, T,
6261
Ẽ, F, G, J, K, Q, P̃, q̃, p,
6362
Ks, Ps,
6463
d, D̂,
@@ -187,15 +186,15 @@ LinMPC controller with a sample time Ts = 4.0 s, OSQP optimizer, KalmanFilter es
187186
```
188187
"""
189188
function LinMPC(
190-
estim::S;
189+
estim::SE;
191190
Hp::Union{Int, Nothing} = DEFAULT_HP,
192191
Hc::Int = DEFAULT_HC,
193192
Mwt = fill(DEFAULT_MWT, estim.model.ny),
194193
Nwt = fill(DEFAULT_NWT, estim.model.nu),
195194
Lwt = fill(DEFAULT_LWT, estim.model.nu),
196195
Cwt = DEFAULT_CWT,
197196
optim::JuMP.Model = JuMP.Model(OSQP.MathOptInterfaceOSQP.Optimizer)
198-
) where {S<:StateEstimator}
197+
) where {SE<:StateEstimator}
199198
isa(estim.model, LinModel) || error("estim.model type must be LinModel")
200199
poles = eigvals(estim.model.A)
201200
nk = sum(poles .≈ 0)
@@ -206,7 +205,7 @@ function LinMPC(
206205
@warn("prediction horizon Hp ($Hp) ≤ number of delays in model "*
207206
"($nk), the closed-loop system may be zero-gain (unresponsive) or unstable")
208207
end
209-
return LinMPC{S}(estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, optim)
208+
return LinMPC{SE}(estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, optim)
210209
end
211210

212211
"""

src/controller/nonlinmpc.jl

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const DiffCacheType = DiffCache{Vector{Float64}, Vector{Float64}}
22

3-
struct NonLinMPC{S<:StateEstimator, JEfunc<:Function} <: PredictiveController
4-
estim::S
3+
struct NonLinMPC{SE<:StateEstimator, JEfunc<:Function} <: PredictiveController
4+
estim::SE
55
optim::JuMP.Model
66
con::ControllerConstraint
77
ΔŨ::Vector{Float64}
@@ -17,9 +17,8 @@ struct NonLinMPC{S<:StateEstimator, JEfunc<:Function} <: PredictiveController
1717
R̂u::Vector{Float64}
1818
R̂y::Vector{Float64}
1919
noR̂u::Bool
20-
S̃_Hp::Matrix{Bool}
21-
T_Hp::Matrix{Bool}
22-
T_Hc::Matrix{Bool}
20+
::Matrix{Bool}
21+
T::Matrix{Bool}
2322
::Matrix{Float64}
2423
F::Vector{Float64}
2524
G::Matrix{Float64}
@@ -35,9 +34,9 @@ struct NonLinMPC{S<:StateEstimator, JEfunc<:Function} <: PredictiveController
3534
::Vector{Float64}
3635
Ŷop::Vector{Float64}
3736
Dop::Vector{Float64}
38-
function NonLinMPC{S, JEFunc}(
39-
estim::S, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE::JEFunc, optim
40-
) where {S<:StateEstimator, JEFunc<:Function}
37+
function NonLinMPC{SE, JEFunc}(
38+
estim::SE, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE::JEFunc, optim
39+
) where {SE<:StateEstimator, JEFunc<:Function}
4140
model = estim.model
4241
nu, ny, nd = model.nu, model.ny, model.nd
4342
= zeros(ny)
@@ -48,10 +47,10 @@ struct NonLinMPC{S<:StateEstimator, JEfunc<:Function} <: PredictiveController
4847
C = Cwt
4948
R̂y, R̂u = zeros(ny*Hp), zeros(nu*Hp) # dummy vals (updated just before optimization)
5049
noR̂u = iszero(L_Hp)
51-
S_Hp, T_Hp, S_Hc, T_Hc = init_ΔUtoU(nu, Hp, Hc)
50+
S, T = init_ΔUtoU(nu, Hp, Hc)
5251
E, F, G, J, K, Q = init_predmat(estim, model, Hp, Hc)
53-
con, S̃_Hp, Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S_Hp, S_Hc, N_Hc, E)
54-
P̃, q̃, p = init_quadprog(model, Ẽ, S̃_Hp, M_Hp, Ñ_Hc, L_Hp)
52+
con, , Ñ_Hc, Ẽ = init_defaultcon(model, Hp, Hc, C, S, N_Hc, E)
53+
P̃, q̃, p = init_quadprog(model, Ẽ, , M_Hp, Ñ_Hc, L_Hp)
5554
Ks, Ps = init_stochpred(estim, Hp)
5655
d, D̂ = zeros(nd), zeros(nd*Hp)
5756
Ŷop, Dop = repeat(model.yop, Hp), repeat(model.dop, Hp)
@@ -62,7 +61,7 @@ struct NonLinMPC{S<:StateEstimator, JEfunc<:Function} <: PredictiveController
6261
ΔŨ, ŷ,
6362
Hp, Hc,
6463
M_Hp, Ñ_Hc, L_Hp, Cwt, Ewt, JE, R̂u, R̂y, noR̂u,
65-
S̃_Hp, T_Hp, T_Hc,
64+
S̃, T,
6665
Ẽ, F, G, J, K, Q, P̃, q̃, p,
6766
Ks, Ps,
6867
d, D̂,
@@ -211,7 +210,7 @@ NonLinMPC controller with a sample time Ts = 10.0 s, Ipopt optimizer, UnscentedK
211210
```
212211
"""
213212
function NonLinMPC(
214-
estim::S;
213+
estim::SE;
215214
Hp::Int = DEFAULT_HP,
216215
Hc::Int = DEFAULT_HC,
217216
Mwt = fill(DEFAULT_MWT, estim.model.ny),
@@ -221,8 +220,8 @@ function NonLinMPC(
221220
Ewt = DEFAULT_EWT,
222221
JE::JEFunc = (_,_,_) -> 0.0,
223222
optim::JuMP.Model = JuMP.Model(optimizer_with_attributes(Ipopt.Optimizer,"sb"=>"yes"))
224-
) where {S<:StateEstimator, JEFunc<:Function}
225-
return NonLinMPC{S, JEFunc}(estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, optim)
223+
) where {SE<:StateEstimator, JEFunc<:Function}
224+
return NonLinMPC{SE, JEFunc}(estim, Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, optim)
226225
end
227226

228227
"""
@@ -258,7 +257,7 @@ function init_optimization!(mpc::NonLinMPC)
258257
# --- nonlinear optimization init ---
259258
model = mpc.estim.model
260259
ny, nu, Hp, Hc = model.ny, model.nu, mpc.Hp, mpc.Hc
261-
nC = (2*Hc*nu + 2*nvar + 2*Hp*ny) - length(mpc.con.b)
260+
nC = (2*Hp*nu + 2*nvar + 2*Hp*ny) - length(mpc.con.b)
262261
# inspired from https://jump.dev/JuMP.jl/stable/tutorials/nonlinear/tips_and_tricks/#User-defined-operators-with-vector-outputs
263262
Jfunc, Cfunc = let mpc=mpc, model=model, nC=nC, nvar=nvar , nŶ=Hp*ny
264263
last_ΔŨtup_float, last_ΔŨtup_dual = nothing, nothing

src/estimator/internal_model.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
struct InternalModel{M<:SimModel} <: StateEstimator
2-
model::M
1+
struct InternalModel{SM<:SimModel} <: StateEstimator
2+
model::SM
33
lastu0::Vector{Float64}
44
::Vector{Float64}
55
x̂d::Vector{Float64}
@@ -20,7 +20,7 @@ struct InternalModel{M<:SimModel} <: StateEstimator
2020
D̂d::Matrix{Float64}
2121
Âs::Matrix{Float64}
2222
B̂s::Matrix{Float64}
23-
function InternalModel{M}(model::M, i_ym, Asm, Bsm, Csm, Dsm) where {M<:SimModel}
23+
function InternalModel{SM}(model::SM, i_ym, Asm, Bsm, Csm, Dsm) where {SM<:SimModel}
2424
nu, ny = model.nu, model.ny
2525
nym, nyu = length(i_ym), ny - length(i_ym)
2626
validate_internalmodel(model)
@@ -87,10 +87,10 @@ future. This is the dynamic matrix control (DMC) strategy, which is simple but s
8787
aggressive. Additional poles and zeros in `stoch_ym` can mitigate this.
8888
"""
8989
function InternalModel(
90-
model::M;
90+
model::SM;
9191
i_ym::IntRangeOrVector = 1:model.ny,
9292
stoch_ym::Union{StateSpace, TransferFunction} = ss(1,1,1,1,model.Ts).*I(length(i_ym))
93-
) where {M<:SimModel}
93+
) where {SM<:SimModel}
9494
stoch_ym = minreal(ss(stoch_ym))
9595
if iscontinuous(stoch_ym)
9696
stoch_ym = c2d(stoch_ym, model.Ts, :tustin)
@@ -102,7 +102,7 @@ function InternalModel(
102102
stoch_ym = c2d(stoch_ym_c, model.Ts, :tustin)
103103
end
104104
end
105-
return InternalModel{M}(model, i_ym, stoch_ym.A, stoch_ym.B, stoch_ym.C, stoch_ym.D)
105+
return InternalModel{SM}(model, i_ym, stoch_ym.A, stoch_ym.B, stoch_ym.C, stoch_ym.D)
106106
end
107107

108108
"Validate if `model` is asymptotically stable for [`LinModel`](@ref)."

src/estimator/kalman.jl

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,8 @@ function update_estimate!(estim::KalmanFilter, u, ym, d)
325325
return update_estimate_kf!(estim, estim.Â, estim.Ĉm, u, ym, d)
326326
end
327327

328-
struct UnscentedKalmanFilter{M<:SimModel} <: StateEstimator
329-
model::M
328+
struct UnscentedKalmanFilter{SM<:SimModel} <: StateEstimator
329+
model::SM
330330
lastu0::Vector{Float64}
331331
::Vector{Float64}
332332
::Hermitian{Float64, Matrix{Float64}}
@@ -353,9 +353,9 @@ struct UnscentedKalmanFilter{M<:SimModel} <: StateEstimator
353353
γ::Float64
354354
::Vector{Float64}
355355
::Diagonal{Float64, Vector{Float64}}
356-
function UnscentedKalmanFilter{M}(
357-
model::M, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, α, β, κ
358-
) where {M<:SimModel}
356+
function UnscentedKalmanFilter{SM}(
357+
model::SM, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, α, β, κ
358+
) where {SM<:SimModel}
359359
nym, nyu = validate_ym(model, i_ym)
360360
As, Cs_u, Cs_y, nint_u, nint_ym = init_estimstoch(model, i_ym, nint_u, nint_ym)
361361
nxs = size(As, 1)
@@ -455,13 +455,13 @@ function UnscentedKalmanFilter(
455455
end
456456

457457
@doc raw"""
458-
UnscentedKalmanFilter{M<:SimModel}(model::M, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, α, β, κ)
458+
UnscentedKalmanFilter{SM<:SimModel}(model::SM, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, α, β, κ)
459459
460460
Construct the estimator from the augmented covariance matrices `P̂0`, `Q̂` and `R̂`.
461461
462462
This syntax allows nonzero off-diagonal elements in ``\mathbf{P̂}_{-1}(0), \mathbf{Q̂, R̂}``.
463463
"""
464-
UnscentedKalmanFilter{M}(model::M, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, α, β, κ) where {M<:SimModel}
464+
UnscentedKalmanFilter{SM}(model::SM, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂, α, β, κ) where {SM<:SimModel}
465465

466466

467467
@doc raw"""
@@ -568,8 +568,8 @@ function update_estimate!(estim::UnscentedKalmanFilter, u, ym, d)
568568
return x̂, P̂
569569
end
570570

571-
struct ExtendedKalmanFilter{M<:SimModel} <: StateEstimator
572-
model::M
571+
struct ExtendedKalmanFilter{SM<:SimModel} <: StateEstimator
572+
model::SM
573573
lastu0::Vector{Float64}
574574
::Vector{Float64}
575575
::Hermitian{Float64, Matrix{Float64}}
@@ -593,9 +593,9 @@ struct ExtendedKalmanFilter{M<:SimModel} <: StateEstimator
593593
::Hermitian{Float64, Matrix{Float64}}
594594
::Matrix{Float64}
595595
::Matrix{Float64}
596-
function ExtendedKalmanFilter{M}(
596+
function ExtendedKalmanFilter{SM}(
597597
model, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂
598-
) where {M<:SimModel}
598+
) where {SM<:SimModel}
599599
nym, nyu = validate_ym(model, i_ym)
600600
As, Cs_u, Cs_y, nint_u, nint_ym = init_estimstoch(model, i_ym, nint_u, nint_ym)
601601
nxs = size(As, 1)
@@ -659,7 +659,7 @@ functions must be compatible with this feature though. See [Automatic differenti
659659
for common mistakes when writing these functions.
660660
"""
661661
function ExtendedKalmanFilter(
662-
model::M;
662+
model::SM;
663663
i_ym::IntRangeOrVector = 1:model.ny,
664664
σP0::Vector = fill(1/model.nx, model.nx),
665665
σQ::Vector = fill(1/model.nx, model.nx),
@@ -670,22 +670,22 @@ function ExtendedKalmanFilter(
670670
nint_ym ::IntVectorOrInt = default_nint(model, i_ym, nint_u),
671671
σQint_ym ::Vector = fill(1, max(sum(nint_ym), 0)),
672672
σP0int_ym::Vector = fill(1, max(sum(nint_ym), 0))
673-
) where {M<:SimModel}
673+
) where {SM<:SimModel}
674674
# estimated covariances matrices (variance = σ²) :
675675
P̂0 = Diagonal{Float64}([σP0; σP0int_u; σP0int_ym].^2);
676676
= Diagonal{Float64}([σQ; σQint_u; σQint_ym].^2);
677677
= Diagonal{Float64}(σR.^2);
678-
return ExtendedKalmanFilter{M}(model, i_ym, nint_u, nint_ym, P̂0, Q̂ , R̂)
678+
return ExtendedKalmanFilter{SM}(model, i_ym, nint_u, nint_ym, P̂0, Q̂ , R̂)
679679
end
680680

681681
@doc raw"""
682-
ExtendedKalmanFilter{M<:SimModel}(model::M, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂)
682+
ExtendedKalmanFilter{SM<:SimModel}(model::SM, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂)
683683
684684
Construct the estimator from the augmented covariance matrices `P̂0`, `Q̂` and `R̂`.
685685
686686
This syntax allows nonzero off-diagonal elements in ``\mathbf{P̂}_{-1}(0), \mathbf{Q̂, R̂}``.
687687
"""
688-
ExtendedKalmanFilter{M}(model::M, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂) where {M<:SimModel}
688+
ExtendedKalmanFilter{SM}(model::SM, i_ym, nint_u, nint_ym, P̂0, Q̂, R̂) where {SM<:SimModel}
689689

690690
@doc raw"""
691691
update_estimate!(estim::ExtendedKalmanFilter, u, ym, d=empty(estim.x̂))

0 commit comments

Comments
 (0)