Skip to content

Commit d9b1e80

Browse files
committed
removed : warm starting with unconstrained solution
1 parent 08aa5e3 commit d9b1e80

File tree

6 files changed

+45
-65
lines changed

6 files changed

+45
-65
lines changed

docs/src/internals/state_estim.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
## Estimator Initialization
44

55
```@docs
6-
ModelPredictiveControl.init_estimstoch
6+
ModelPredictiveControl.init_integrators
77
ModelPredictiveControl.augment_model
88
ModelPredictiveControl.init_ukf
99
ModelPredictiveControl.init_internalmodel

src/estimator/internal_model.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ struct InternalModel{M<:SimModel} <: StateEstimator
3232
nx̂ = model.nx
3333
nxs = size(As,1)
3434
Âs, B̂s = init_internalmodel(As, Bs, Cs, Ds)
35-
i_ym = collect(i_ym)
3635
lastu0 = zeros(nu)
3736
x̂d == zeros(model.nx) # x̂ and x̂d are same object (updating x̂d will update x̂)
3837
x̂s = zeros(nxs)

src/estimator/kalman.jl

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,12 @@ struct SteadyKalmanFilter <: StateEstimator
2121
::Hermitian{Float64, Matrix{Float64}}
2222
K::Matrix{Float64}
2323
function SteadyKalmanFilter(model, i_ym, nint_ym, Q̂, R̂)
24-
nu, nx, ny = model.nu, model.nx, model.ny
25-
nym, nyu = length(i_ym), ny - length(i_ym)
26-
Asm, Csm, nint_ym = init_estimstoch(i_ym, nint_ym)
27-
nxs = size(Asm,1)
28-
nx̂ = nx + nxs
24+
nym, nyu, nxs, nx̂, As, Cs, nint_ym = init_estimstoch(model, i_ym, nint_ym)
25+
Â, B̂u, Ĉ, B̂d, D̂d = augment_model(model, As, Cs)
2926
validate_kfcov(nym, nx̂, Q̂, R̂)
30-
As, _ , Cs = stoch_ym2y(model, i_ym, Asm, [], Csm, [])
31-
 , B̂u, Ĉ, B̂d, D̂d = augment_model(model, As, Cs)
3227
K = try
3328
Q̂_kalman = Matrix(Q̂) # Matrix() required for Julia 1.6
34-
R̂_kalman = zeros(eltype(R̂), ny, ny)
29+
R̂_kalman = zeros(eltype(R̂), model.ny, model.ny)
3530
R̂_kalman[i_ym, i_ym] =
3631
kalman(Discrete, Â, Ĉ, Q̂_kalman, R̂_kalman)[:, i_ym]
3732
catch my_error
@@ -44,8 +39,7 @@ struct SteadyKalmanFilter <: StateEstimator
4439
end
4540
end
4641
Ĉm, D̂dm = Ĉ[i_ym, :], D̂d[i_ym, :] # measured outputs ym only
47-
i_ym = collect(i_ym)
48-
lastu0 = zeros(nu)
42+
lastu0 = zeros(model.nu)
4943
= [zeros(model.nx); zeros(nxs)]
5044
= Hermitian(Q̂, :L)
5145
= Hermitian(R̂, :L)
@@ -123,7 +117,7 @@ as state feedback. The method [`default_nint`](@ref) computes the default value
123117
- Use 1 integrator if the disturbances on the output are typically "step-like"
124118
- Use 2 integrators if the disturbances on the output are typically "ramp-like"
125119
126-
The function [`init_estimstoch`](@ref) builds the stochastic model from `nint_ym`.
120+
The function [`init_integrators`](@ref) builds the stochastic model from `nint_ym`.
127121
128122
!!! tip
129123
Increasing `σQ_int` values increases the integral action "gain".
@@ -198,17 +192,11 @@ struct KalmanFilter <: StateEstimator
198192
::Hermitian{Float64, Matrix{Float64}}
199193
::Hermitian{Float64, Matrix{Float64}}
200194
function KalmanFilter(model, i_ym, nint_ym, P̂0, Q̂, R̂)
201-
nu, nx, ny = model.nu, model.nx, model.ny
202-
nym, nyu = length(i_ym), ny - length(i_ym)
203-
Asm, Csm, nint_ym = init_estimstoch(i_ym, nint_ym)
204-
nxs = size(Asm,1)
205-
nx̂ = nx + nxs
195+
nym, nyu, nxs, nx̂, As, Cs, nint_ym = init_estimstoch(model, i_ym, nint_ym)
196+
Â, B̂u, Ĉ, B̂d, D̂d = augment_model(model, As, Cs)
206197
validate_kfcov(nym, nx̂, Q̂, R̂, P̂0)
207-
As, _ , Cs = stoch_ym2y(model, i_ym, Asm, [], Csm, [])
208-
 , B̂u, Ĉ, B̂d, D̂d = augment_model(model, As, Cs)
209198
Ĉm, D̂dm = Ĉ[i_ym, :], D̂d[i_ym, :] # measured outputs ym only
210-
i_ym = collect(i_ym)
211-
lastu0 = zeros(nu)
199+
lastu0 = zeros(model.nu)
212200
= [zeros(model.nx); zeros(nxs)]
213201
P̂0 = Hermitian(P̂0, :L)
214202
= Hermitian(Q̂, :L)
@@ -335,17 +323,11 @@ struct UnscentedKalmanFilter{M<:SimModel} <: StateEstimator
335323
function UnscentedKalmanFilter{M}(
336324
model::M, i_ym, nint_ym, P̂0, Q̂, R̂, α, β, κ
337325
) where {M<:SimModel}
338-
nu, nx, ny = model.nu, model.nx, model.ny
339-
nym, nyu = length(i_ym), ny - length(i_ym)
340-
Asm, Csm, nint_ym = init_estimstoch(i_ym, nint_ym)
341-
nxs = size(Asm,1)
342-
nx̂ = nx + nxs
343-
validate_kfcov(nym, nx̂, Q̂, R̂, P̂0)
344-
As, _ , Cs = stoch_ym2y(model, i_ym, Asm, [], Csm, [])
326+
nym, nyu, nxs, nx̂, As, Cs, nint_ym = init_estimstoch(model, i_ym, nint_ym)
345327
augment_model(model, As, Cs) # verify observability for LinModel
328+
validate_kfcov(nym, nx̂, Q̂, R̂, P̂0)
346329
nσ, γ, m̂, Ŝ = init_ukf(nx̂, α, β, κ)
347-
i_ym = collect(i_ym)
348-
lastu0 = zeros(nu)
330+
lastu0 = zeros(model.nu)
349331
= [zeros(model.nx); zeros(nxs)]
350332
P̂0 = Hermitian(P̂0, :L)
351333
= Hermitian(Q̂, :L)
@@ -555,16 +537,10 @@ struct ExtendedKalmanFilter{M<:SimModel} <: StateEstimator
555537
::Hermitian{Float64, Matrix{Float64}}
556538
::Hermitian{Float64, Matrix{Float64}}
557539
function ExtendedKalmanFilter{M}(model::M, i_ym, nint_ym, P̂0, Q̂, R̂) where {M<:SimModel}
558-
nu, nx, ny = model.nu, model.nx, model.ny
559-
nym, nyu = length(i_ym), ny - length(i_ym)
560-
Asm, Csm, nint_ym = init_estimstoch(i_ym, nint_ym)
561-
nxs = size(Asm,1)
562-
nx̂ = nx + nxs
563-
validate_kfcov(nym, nx̂, Q̂, R̂, P̂0)
564-
As, _ , Cs, _ = stoch_ym2y(model, i_ym, Asm, [], Csm, [])
540+
nym, nyu, nxs, nx̂, As, Cs, nint_ym = init_estimstoch(model, i_ym, nint_ym)
565541
augment_model(model, As, Cs) # verify observability for LinModel
566-
i_ym = collect(i_ym)
567-
lastu0 = zeros(nu)
542+
validate_kfcov(nym, nx̂, Q̂, R̂, P̂0)
543+
lastu0 = zeros(model.nu)
568544
= [zeros(model.nx); zeros(nxs)]
569545
P̂0 = Hermitian(P̂0, :L)
570546
= Hermitian(Q̂, :L)

src/estimator/luenberger.jl

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,15 @@ struct Luenberger <: StateEstimator
1919
D̂dm ::Matrix{Float64}
2020
K::Matrix{Float64}
2121
function Luenberger(model, i_ym, nint_ym, p̂)
22-
nu, nx, ny = model.nu, model.nx, model.ny
23-
nym, nyu = length(i_ym), ny - length(i_ym)
24-
Asm, Csm, nint_ym = init_estimstoch(i_ym, nint_ym)
25-
nxs = size(Asm,1)
26-
nx̂ = nx + nxs
27-
As, _ , Cs = stoch_ym2y(model, i_ym, Asm, [], Csm, [])
28-
 , B̂u, Ĉ, B̂d, D̂d = augment_model(model, As, Cs)
22+
nym, nyu, nxs, nx̂, As, Cs, nint_ym = init_estimstoch(model, i_ym, nint_ym)
23+
Â, B̂u, Ĉ, B̂d, D̂d = augment_model(model, As, Cs)
2924
K = try
3025
place(Â, Ĉ, p̂, :o)[:, i_ym]
3126
catch
3227
error("Cannot compute the Luenberger gain L with specified poles p̂.")
3328
end
3429
Ĉm, D̂dm = Ĉ[i_ym, :], D̂d[i_ym, :] # measured outputs ym only
35-
i_ym = collect(i_ym)
36-
lastu0 = zeros(nu)
30+
lastu0 = zeros(model.nu)
3731
= [zeros(model.nx); zeros(nxs)]
3832
return new(
3933
model,

src/predictive_control.jl

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -336,17 +336,12 @@ Set the estimate at `mpc.estim.x̂`.
336336
setstate!(mpc::PredictiveController, x̂) = (setstate!(mpc.estim, x̂); return mpc)
337337

338338
@doc raw"""
339-
initstate!(mpc::PredictiveController, u, ym, d=Float64[]) -> x̂
339+
initstate!(mpc::PredictiveController, u, ym, d=Float64[])
340340
341-
Init `mpc.ΔŨ` for warm-starting and the states of `mpc.estim` [`StateEstimator`](@ref).
342-
343-
Before calling [`initstate!(mpc.estim, u, ym, d)`](@ref), it warm-starts ``\mathbf{ΔŨ}``:
344-
- If `model` is a [`LinModel`](@ref), the vector is filled with the analytical minimum ``J``
345-
of the unconstrained problem.
346-
- Else, the vector is filled with zeros.
341+
Init the states of `mpc.estim` [`StateEstimator`](@ref) and warm start `mpc.ΔŨ` at zero.
347342
"""
348343
function initstate!(mpc::PredictiveController, u, ym, d=Float64[])
349-
mpc.ΔŨ[:] = unconstrained_solution(mpc, mpc.estim.model)
344+
mpc.ΔŨ .= 0
350345
return initstate!(mpc.estim, u, ym, d)
351346
end
352347

src/state_estim.jl

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,23 @@ function remove_op!(estim::StateEstimator, u, d, ym)
6969
return u0, d0, ym0
7070
end
7171

72+
"""
73+
init_estimstoch(model, i_ym, nint_ym)
74+
75+
Init stochastic model matrices from integrator specifications for state estimation.
76+
"""
77+
function init_estimstoch(model, i_ym, nint_ym)
78+
validate_ym(model, i_ym)
79+
nx, ny = model.nx, model.ny
80+
nym, nyu = length(i_ym), ny - length(i_ym)
81+
Asm, Csm, nint_ym = init_integrators(i_ym, nint_ym)
82+
nxs = size(Asm,1)
83+
nx̂ = nx + nxs
84+
As, _ , Cs = stoch_ym2y(model, i_ym, Asm, [], Csm, [])
85+
return nym, nyu, nxs, nx̂, As, Cs, nint_ym
86+
end
87+
88+
"Validate the specified measured output indices `i_ym`."
7289
function validate_ym(model::SimModel, i_ym)
7390
if length(unique(i_ym)) length(i_ym) || maximum(i_ym) > model.ny
7491
error("Measured output indices i_ym should contains valid and unique indices")
@@ -91,7 +108,7 @@ function stoch_ym2y(model::SimModel, i_ym, Asm, Bsm, Csm, Dsm)
91108
end
92109

93110
@doc raw"""
94-
init_estimstoch(i_ym, nint_ym::Vector{Int}) -> Asm, Csm, nint_ym
111+
init_integrators(i_ym, nint_ym::Vector{Int}) -> Asm, Csm, nint_ym
95112
96113
Calc stochastic model matrices from output integrators specifications for state estimation.
97114
@@ -107,7 +124,7 @@ be added for each measured output ``\mathbf{y^m}``. The argument generates the `
107124
where ``\mathbf{e}(k)`` is a conceptual and unknown zero mean white noise.
108125
``\mathbf{B_s^m}`` is not used for closed-loop state estimators thus ignored.
109126
"""
110-
function init_estimstoch(i_ym, nint_ym)
127+
function init_integrators(i_ym, nint_ym)
111128
if nint_ym == 0 # alias for no output integrator at all
112129
nint_ym = fill(0, length(i_ym))
113130
end
@@ -134,7 +151,7 @@ function init_estimstoch(i_ym, nint_ym)
134151
return Asm, Csm, nint_ym
135152
end
136153

137-
function init_estimstoch_u(nu, nint_u)
154+
function init_integrators_u(nu, nint_u)
138155
if nint_u == 0 # alias for no output integrator at all
139156
nint_u = fill(0, length(nu))
140157
end
@@ -167,7 +184,7 @@ end
167184
Augment [`LinModel`](@ref) state-space matrices with the stochastic ones `As` and `Cs`.
168185
169186
If ``\mathbf{x}`` are `model.x` states, and ``\mathbf{x_s}``, the states defined at
170-
[`init_estimstoch`](@ref), we define an augmented state vector ``\mathbf{x̂} =
187+
[`init_integrators`](@ref), we define an augmented state vector ``\mathbf{x̂} =
171188
[ \begin{smallmatrix} \mathbf{x} \\ \mathbf{x_s} \end{smallmatrix} ]``. The method
172189
returns the augmented matrices `Â`, `B̂u`, `Ĉ`, `B̂d` and `D̂d`:
173190
```math
@@ -187,7 +204,7 @@ function augment_model(model::LinModel, As, Cs; verify_obsv=true)
187204
B̂d = [model.Bd; zeros(nxs,nd)]
188205
D̂d = model.Dd
189206
# observability on Ĉ instead of Ĉm, since it would always return false when nym ≠ ny:
190-
if verify_obsv && !observability(Â, Ĉ)[begin]
207+
if verify_obsv && !observability(Â, Ĉ)[:isobservable]
191208
error("The augmented model is unobservable. You may try to use 0 "*
192209
"integrator on model integrating outputs with nint_ym parameter.")
193210
end
@@ -221,12 +238,11 @@ function default_nint(model::LinModel, i_ym::IntRangeOrVector = 1:model.ny)
221238
nint_ym = fill(0, length(i_ym))
222239
for i in eachindex(i_ym)
223240
nint_ym[i] = 1
224-
Asm, Csm = init_estimstoch(i_ym, nint_ym)
241+
Asm, Csm = init_integrators(i_ym, nint_ym)
225242
As , _ , Cs = stoch_ym2y(model, i_ym, Asm, [], Csm, [])
226243
 , _ , Ĉ = augment_model(model, As, Cs, verify_obsv=false)
227244
# observability on Ĉ instead of Ĉm, since it would always return false when nym ≠ ny
228-
isobservable, = observability(Â, Ĉ)
229-
isobservable || (nint_ym[i] = 0)
245+
observability(Â, Ĉ)[:isobservable] || (nint_ym[i] = 0)
230246
end
231247
return nint_ym
232248
end

0 commit comments

Comments
 (0)