Skip to content

Commit 2470717

Browse files
committed
nint_u seems to works for SteadyKalmanFilter
1 parent 4732d8c commit 2470717

File tree

4 files changed

+90
-86
lines changed

4 files changed

+90
-86
lines changed

src/estimator/kalman.jl

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ struct SteadyKalmanFilter <: StateEstimator
77
nym::Int
88
nyu::Int
99
nxs::Int
10-
As::Matrix{Float64}
11-
Cs::Matrix{Float64}
10+
As ::Matrix{Float64}
11+
Cs_u::Matrix{Float64}
12+
Cs_y::Matrix{Float64}
13+
nint_u ::Vector{Int}
1214
nint_ym::Vector{Int}
1315
::Matrix{Float64}
1416
B̂u ::Matrix{Float64}
@@ -20,9 +22,9 @@ struct SteadyKalmanFilter <: StateEstimator
2022
::Hermitian{Float64, Matrix{Float64}}
2123
::Hermitian{Float64, Matrix{Float64}}
2224
K::Matrix{Float64}
23-
function SteadyKalmanFilter(model, i_ym, nint_ym, Q̂, R̂)
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)
25+
function SteadyKalmanFilter(model, i_ym, nint_u, nint_ym, Q̂, R̂)
26+
nym, nyu, nx̂, nxs, As, Cs_u, Cs_y, nint_u, nint_ym = init_estimstoch(model, i_ym, nint_ym; nint_u)
27+
Â, B̂u, Ĉ, B̂d, D̂d = augment_model(model, As, Cs_u, Cs_y)
2628
validate_kfcov(nym, nx̂, Q̂, R̂)
2729
K = try
2830
Q̂_kalman = Matrix(Q̂) # Matrix() required for Julia 1.6
@@ -47,7 +49,7 @@ struct SteadyKalmanFilter <: StateEstimator
4749
model,
4850
lastu0, x̂,
4951
i_ym, nx̂, nym, nyu, nxs,
50-
As, Cs, nint_ym,
52+
As, Cs_u, Cs_y, nint_u, nint_ym,
5153
Â, B̂u, B̂d, Ĉ, D̂d,
5254
Ĉm, D̂dm,
5355
Q̂, R̂,
@@ -131,13 +133,14 @@ function SteadyKalmanFilter(
131133
i_ym::IntRangeOrVector = 1:model.ny,
132134
σQ::Vector = fill(1/model.nx, model.nx),
133135
σR::Vector = fill(1, length(i_ym)),
136+
nint_u ::IntVectorOrInt = 0,
134137
nint_ym::IntVectorOrInt = default_nint(model, i_ym),
135-
σQ_int::Vector = fill(1, max(sum(nint_ym), 0))
138+
σQ_int::Vector = fill(1, max(sum(nint_u) + sum(nint_ym), 0))
136139
)
137140
# estimated covariances matrices (variance = σ²) :
138141
= Diagonal{Float64}([σQ ; σQ_int ].^2);
139142
= Diagonal{Float64}(σR.^2);
140-
return SteadyKalmanFilter(model, i_ym, nint_ym, Q̂ , R̂)
143+
return SteadyKalmanFilter(model, i_ym, nint_u, nint_ym, Q̂ , R̂)
141144
end
142145

143146
@doc raw"""
@@ -178,8 +181,10 @@ struct KalmanFilter <: StateEstimator
178181
nym::Int
179182
nyu::Int
180183
nxs::Int
181-
As::Matrix{Float64}
182-
Cs::Matrix{Float64}
184+
As ::Matrix{Float64}
185+
Cs_u::Matrix{Float64}
186+
Cs_y::Matrix{Float64}
187+
nint_u ::Vector{Int}
183188
nint_ym::Vector{Int}
184189
::Matrix{Float64}
185190
B̂u ::Matrix{Float64}
@@ -310,8 +315,10 @@ struct UnscentedKalmanFilter{M<:SimModel} <: StateEstimator
310315
nym::Int
311316
nyu::Int
312317
nxs::Int
313-
As::Matrix{Float64}
314-
Cs::Matrix{Float64}
318+
As ::Matrix{Float64}
319+
Cs_u::Matrix{Float64}
320+
Cs_y::Matrix{Float64}
321+
nint_u ::Vector{Int}
315322
nint_ym::Vector{Int}
316323
P̂0::Hermitian{Float64, Matrix{Float64}}
317324
::Hermitian{Float64, Matrix{Float64}}
@@ -530,8 +537,10 @@ struct ExtendedKalmanFilter{M<:SimModel} <: StateEstimator
530537
nym::Int
531538
nyu::Int
532539
nxs::Int
533-
As::Matrix{Float64}
534-
Cs::Matrix{Float64}
540+
As ::Matrix{Float64}
541+
Cs_u::Matrix{Float64}
542+
Cs_y::Matrix{Float64}
543+
nint_u ::Vector{Int}
535544
nint_ym::Vector{Int}
536545
P̂0::Hermitian{Float64, Matrix{Float64}}
537546
::Hermitian{Float64, Matrix{Float64}}

src/estimator/luenberger.jl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ struct Luenberger <: StateEstimator
77
nym::Int
88
nyu::Int
99
nxs::Int
10-
As::Matrix{Float64}
11-
Cs::Matrix{Float64}
10+
As ::Matrix{Float64}
11+
Cs_u::Matrix{Float64}
12+
Cs_y::Matrix{Float64}
13+
nint_u ::Vector{Int}
1214
nint_ym::Vector{Int}
1315
::Matrix{Float64}
1416
B̂u ::Matrix{Float64}

src/state_estim.jl

Lines changed: 57 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,27 @@ end
7474
7575
Init stochastic model matrices from integrator specifications for state estimation.
7676
"""
77-
function init_estimstoch(model, i_ym, nint_ym)
77+
function init_estimstoch(model, i_ym, nint_ym; nint_u=0)
7878
validate_ym(model, i_ym)
79-
nx, ny = model.nx, model.ny
79+
nu, nx, ny = model.nu, model.nx, model.ny
8080
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)
81+
As_u , Cs_u , nint_u = init_integrators(nint_u , nu , "u")
82+
As_ym, Cs_ym, nint_ym = init_integrators(nint_ym, nym, "ym")
83+
As_y, _ , Cs_y = stoch_ym2y(model, i_ym, As_ym, [], Cs_ym, [])
84+
nxs_u, nxs_y = size(As_u, 1), size(As_y, 1)
85+
# combines input and output stochastic models:
86+
As = [As_u zeros(nxs_u, nxs_y); zeros(nxs_y, nxs_u) As_y]
87+
Cs_u = [Cs_u zeros(nu, nxs_y)]
88+
Cs_y = [zeros(ny, nxs_u) Cs_y]
89+
90+
#Bs = B*Ks (nx × nxs)
91+
#Cs_u # nu x nxs_u
92+
#B # nx x nu
93+
#K_res = B*Cs_u # (nx × nu) * (nu × nxs_u) = (nx × nxs_u)
94+
95+
nxs = nxs_u + nxs_y
8396
nx̂ = nx + nxs
84-
As, _ , Cs = stoch_ym2y(model, i_ym, Asm, [], Csm, [])
85-
return nym, nyu, nxs, nx̂, As, Cs, nint_ym
97+
return nym, nyu, nx̂, nxs, As, Cs_u, Cs_y, nint_u, nint_ym
8698
end
8799

88100
"Validate the specified measured output indices `i_ym`."
@@ -108,74 +120,49 @@ function stoch_ym2y(model::SimModel, i_ym, Asm, Bsm, Csm, Dsm)
108120
end
109121

110122
@doc raw"""
111-
init_integrators(i_ym, nint_ym::Vector{Int}) -> Asm, Csm, nint_ym
123+
init_integrators(nint::Vector{Int}, nys, varname::String) -> As, Cs, nint
112124
113-
Calc stochastic model matrices from output integrators specifications for state estimation.
125+
Calc state-space matrices `As, Cs` (stochastic part) from integrator specifications `nint`.
114126
115-
For closed-loop state estimators. `nint_ym` is a vector providing how many integrator should
116-
be added for each measured output ``\mathbf{y^m}``. The argument generates the `Asm` and
117-
`Csm` matrices:
127+
This function is used to initialize the stochastic part of the augmented model for the
128+
design of state estimators. The vector `nint` provides how many integrators (in series)
129+
should be incorporated for each stochastic output ``\mathbf{y_s}``:
118130
```math
119131
\begin{aligned}
120-
\mathbf{x_s}(k+1) &= \mathbf{A_s^m x_s}(k) + \mathbf{B_s^m e}(k) \\
121-
\mathbf{y_s^m}(k) &= \mathbf{C_s^m x_s}(k)
132+
\mathbf{x_s}(k+1) &= \mathbf{A_s x_s}(k) + \mathbf{B_s e}(k) \\
133+
\mathbf{y_s}(k) &= \mathbf{C_s x_s}(k)
122134
\end{aligned}
123135
```
124-
where ``\mathbf{e}(k)`` is a conceptual and unknown zero mean white noise.
125-
``\mathbf{B_s^m}`` is not used for closed-loop state estimators thus ignored.
126-
"""
127-
function init_integrators(i_ym, nint_ym)
128-
if nint_ym == 0 # alias for no output integrator at all
129-
nint_ym = fill(0, length(i_ym))
130-
end
131-
nym = length(i_ym);
132-
if length(nint_ym) nym
133-
error("nint_ym size ($(length(nint_ym))) ≠ measured output quantity nym ($nym)")
134-
end
135-
any(nint_ym .< 0) && error("nint_ym values should be ≥ 0")
136-
nxs = sum(nint_ym)
137-
Asm, Csm = zeros(nxs, nxs), zeros(nym, nxs)
138-
if nxs 0 # construct stochastic model state-space matrices (integrators) :
139-
i_Asm, i_Csm = 1, 1
140-
for iym = 1:nym
141-
nint = nint_ym[iym]
142-
if nint 0
143-
rows_Asm = (i_Asm):(i_Asm + nint - 1)
144-
Asm[rows_Asm, rows_Asm] = Bidiagonal(ones(nint), ones(nint-1), :L)
145-
Csm[iym, i_Csm+nint-1] = 1
146-
i_Asm += nint
147-
i_Csm += nint
148-
end
149-
end
150-
end
151-
return Asm, Csm, nint_ym
152-
end
136+
where ``\mathbf{e}(k)`` is an unknown zero mean white noise. The estimations does not use
137+
``\mathbf{B_s}``, it is thus ignored. Note that this function is called twice :
153138
154-
function init_integrators_u(nu, nint_u)
155-
if nint_u == 0 # alias for no output integrator at all
156-
nint_u = fill(0, length(nu))
139+
1. for the unmodeled disturbances at measured outputs ``\mathbf{y^m}``
140+
2. for the unmodeled disturbances at manipulated inputs ``\mathbf{u}``
141+
"""
142+
function init_integrators(nint::Vector{Int}, nys, varname::String)
143+
if nint == 0 # alias for no integrator at all
144+
nint = fill(0, nys)
157145
end
158-
#nym = length(i_ym);
159-
if length(nint_u) nu
160-
error("nint_u size ($(length(nint_u))) ≠ manipulated input quantity nu ($nu)")
146+
if length(nint) nys
147+
error("nint_$(varname) size ($(length(nint))) ≠ n$(varname) ($nys)")
161148
end
162-
any(nint_u .< 0) && error("nint_u values should be ≥ 0")
163-
nxs = sum(nint_u)
164-
Asm, Csm = zeros(nxs, nxs), zeros(nym, nxs)
149+
any(nint .< 0) && error("nint_$(varname) values should be ≥ 0")
150+
nxs = sum(nint)
151+
As, Cs = zeros(nxs, nxs), zeros(nys, nxs)
165152
if nxs 0 # construct stochastic model state-space matrices (integrators) :
166-
i_Asm, i_Csm = 1, 1
167-
for iym = 1:nym
168-
nint = nint_u[iym]
169-
if nint 0
170-
rows_Asm = (i_Asm):(i_Asm + nint - 1)
171-
Asm[rows_Asm, rows_Asm] = Bidiagonal(ones(nint), ones(nint-1), :L)
172-
Csm[iym, i_Csm+nint-1] = 1
173-
i_Asm += nint
174-
i_Csm += nint
153+
i_As, i_Cs = 1, 1
154+
for i = 1:nys
155+
nint_i = nint[i]
156+
if nint_i 0
157+
rows_As = (i_As):(i_As + nint_i - 1)
158+
As[rows_As, rows_As] = Bidiagonal(ones(nint_i), ones(nint_i-1), :L)
159+
Cs[i, i_Cs+nint_i-1] = 1
160+
i_As += nint_i
161+
i_Cs += nint_i
175162
end
176163
end
177164
end
178-
return Asm, Csm, nint_u
165+
return As, Cs, nint
179166
end
180167

181168
@doc raw"""
@@ -195,13 +182,13 @@ returns the augmented matrices `Â`, `B̂u`, `Ĉ`, `B̂d` and `D̂d`:
195182
```
196183
An error is thrown if the augmented model is not observable and `verify_obsv == true`.
197184
"""
198-
function augment_model(model::LinModel, As, Cs; verify_obsv=true)
185+
function augment_model(model::LinModel, As, Cs_u, Cs_y; verify_obsv=true)
199186
nu, nx, nd = model.nu, model.nx, model.nd
200187
nxs = size(As, 1)
201-
= [model.A zeros(nx,nxs); zeros(nxs,nx) As]
202-
B̂u = [model.Bu; zeros(nxs,nu)]
203-
= [model.C Cs]
204-
B̂d = [model.Bd; zeros(nxs,nd)]
188+
= [model.A model.Bu*Cs_u; zeros(nxs,nx) As]
189+
B̂u = [model.Bu; zeros(nxs, nu)]
190+
= [model.C Cs_y]
191+
B̂d = [model.Bd; zeros(nxs, nd)]
205192
D̂d = model.Dd
206193
# observability on Ĉ instead of Ĉm, since it would always return false when nym ≠ ny:
207194
if verify_obsv && !observability(Â, Ĉ)[:isobservable]
@@ -269,8 +256,8 @@ function returns the next state of the augmented model, defined as:
269256
"""
270257
function (estim::StateEstimator, x̂, u, d)
271258
# `@views` macro avoid copies with matrix slice operator e.g. [a:b]
272-
nx = estim.model.nx
273-
@views return [f(estim.model, x̂[1:nx], u, d); estim.As*x̂[nx+1:end]]
259+
@views x̂d, x̂s = x̂[1:estim.model.nx], x̂[estim.model.nx+1:end]
260+
return [f(estim.model, x̂d, u + estim.Cs_u*x̂s, d); estim.As*x̂s]
274261
end
275262

276263
@doc raw"""
@@ -280,8 +267,8 @@ Output function ``\mathbf{ĥ}`` of the augmented model, see [`f̂`](@ref) for d
280267
"""
281268
function (estim::StateEstimator, x̂, d)
282269
# `@views` macro avoid copies with matrix slice operator e.g. [a:b]
283-
nx = estim.model.nx
284-
@views return h(estim.model, x̂[1:nx], d) + estim.Cs*x̂[nx+1:end]
270+
@views x̂d, x̂s = x̂[1:estim.model.nx], x̂[estim.model.nx+1:end]
271+
return h(estim.model, x̂d, d) + estim.Cs_y*x̂s
285272
end
286273

287274

src/yo.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
where ``\mathbf{e}(k)`` is an unknown zero mean white noise. The estimations does not use
3+
``\mathbf{B_s}``, it is thus ignored. Note that this function is called twice :
4+
5+
1. for the unmodeled disturbances at measured outputs ``\mathbf{y^m}``, and
6+
2. for the unmodeled disturbances at manipulated inputs ``\mathbf{u}``.

0 commit comments

Comments
 (0)