@@ -70,26 +70,36 @@ function remove_op!(estim::StateEstimator, u, d, ym)
7070end
7171
7272"""
73- init_estimstoch(model, i_ym, nint_ym)
73+ init_estimstoch(model, i_ym, nint_u, nint_ym) -> As, Cs_u, Cs_y, nxs, nint_u, nint_ym
7474
7575Init stochastic model matrices from integrator specifications for state estimation.
76+
77+ TBW.
78+
79+ The function [`init_integrators`](@ref) builds the state-space matrice of the unmeasured
80+ disturbance models.
7681"""
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
82+ function init_estimstoch (model, i_ym, nint_u:: IntVectorOrInt , nint_ym:: IntVectorOrInt )
83+ nu, ny, nym = model. nu, model. ny, length (i_ym)
84+ As_u , Cs_u , nint_u = init_integrators (nint_u , nu , " u" )
85+ As_ym, Cs_ym, nint_ym = init_integrators (nint_ym, nym, " ym" )
86+ As_y, _ , Cs_y = stoch_ym2y (model, i_ym, As_ym, [], Cs_ym, [])
87+ nxs_u, nxs_y = size (As_u, 1 ), size (As_y, 1 )
88+ # combines input and output stochastic models:
89+ As = [As_u zeros (nxs_u, nxs_y); zeros (nxs_y, nxs_u) As_y]
90+ Cs_u = [Cs_u zeros (nu, nxs_y)]
91+ Cs_y = [zeros (ny, nxs_u) Cs_y]
92+ nxs = nxs_u + nxs_y
93+ return As, Cs_u, Cs_y, nxs, nint_u, nint_ym
8694end
8795
8896" Validate the specified measured output indices `i_ym`."
8997function validate_ym (model:: SimModel , i_ym)
9098 if length (unique (i_ym)) ≠ length (i_ym) || maximum (i_ym) > model. ny
9199 error (" Measured output indices i_ym should contains valid and unique indices" )
92100 end
101+ nym, nyu = length (i_ym), model. ny - length (i_ym)
102+ return nym, nyu
93103end
94104
95105" Convert the measured outputs stochastic model `stoch_ym` to all outputs `stoch_y`."
@@ -108,74 +118,49 @@ function stoch_ym2y(model::SimModel, i_ym, Asm, Bsm, Csm, Dsm)
108118end
109119
110120@doc raw """
111- init_integrators(i_ym, nint_ym::Vector{Int} ) -> Asm, Csm, nint_ym
121+ init_integrators(nint, nys, varname::String ) -> As, Cs, nint
112122
113- Calc stochastic model matrices from output integrators specifications for state estimation .
123+ Calc state-space matrices `As, Cs` (stochastic part) from integrator specifications `nint` .
114124
115- For closed-loop state estimators. `nint_ym` is a vector providing how many integrator should
116- be added for each measured output `` \m athbf{y^m}``. The argument generates the `Asm` and
117- `Csm` matrices :
125+ This function is used to initialize the stochastic part of the augmented model for the
126+ design of state estimators. The vector `nint` provides how many integrators (in series)
127+ should be incorporated for each stochastic output `` \m athbf{y_s}`` :
118128```math
119129\b egin{aligned}
120- \m athbf{x_s}(k+1) &= \m athbf{A_s^m x_s}(k) + \m athbf{B_s^m e}(k) \\
121- \m athbf{y_s^m }(k) &= \m athbf{C_s^m x_s}(k)
130+ \m athbf{x_s}(k+1) &= \m athbf{A_s x_s}(k) + \m athbf{B_s e}(k) \\
131+ \m athbf{y_s}(k) &= \m athbf{C_s x_s}(k)
122132\e nd{aligned}
123133```
124- where ``\m athbf{e}(k)`` is a conceptual and unknown zero mean white noise.
125- ``\m athbf{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
134+ where ``\m athbf{e}(k)`` is an unknown zero mean white noise. The estimations does not use
135+ ``\m athbf{B_s}``, it is thus ignored. Note that this function is called twice :
153136
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))
137+ 1. for the unmodeled disturbances at measured outputs ``\m athbf{y^m}``
138+ 2. for the unmodeled disturbances at manipulated inputs ``\m athbf{u}``
139+ """
140+ function init_integrators (nint:: IntVectorOrInt , nys, varname:: String )
141+ if nint == 0 # alias for no integrator at all
142+ nint = fill (0 , nys)
157143 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 )" )
144+ if length (nint) ≠ nys
145+ error (" nint_$(varname) size ($(length (nint)) ) ≠ n$(varname) ($nys )" )
161146 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)
147+ any (nint .< 0 ) && error (" nint_ $(varname) values should be ≥ 0" )
148+ nxs = sum (nint )
149+ As, Cs = zeros (nxs, nxs), zeros (nys , nxs)
165150 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
151+ i_As, i_Cs = 1 , 1
152+ for i = 1 : nys
153+ nint_i = nint[i ]
154+ if nint_i ≠ 0
155+ rows_As = (i_As ): (i_As + nint_i - 1 )
156+ As[rows_As, rows_As ] = Bidiagonal (ones (nint_i ), ones (nint_i - 1 ), :L )
157+ Cs[i, i_Cs + nint_i - 1 ] = 1
158+ i_As += nint_i
159+ i_Cs += nint_i
175160 end
176161 end
177162 end
178- return Asm, Csm, nint_u
163+ return As, Cs, nint
179164end
180165
181166@doc raw """
@@ -195,26 +180,27 @@ returns the augmented matrices `Â`, `B̂u`, `Ĉ`, `B̂d` and `D̂d`:
195180```
196181An error is thrown if the augmented model is not observable and `verify_obsv == true`.
197182"""
198- function augment_model (model:: LinModel , As, Cs ; verify_obsv= true )
183+ function augment_model (model:: LinModel , As, Cs_u, Cs_y ; verify_obsv= true )
199184 nu, nx, nd = model. nu, model. nx, model. nd
200185 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)]
186+ Â = [model. A model . Bu * Cs_u ; zeros (nxs,nx) As]
187+ B̂u = [model. Bu; zeros (nxs, nu)]
188+ Ĉ = [model. C Cs_y ]
189+ B̂d = [model. Bd; zeros (nxs, nd)]
205190 D̂d = model. Dd
206191 # observability on Ĉ instead of Ĉm, since it would always return false when nym ≠ ny:
207192 if verify_obsv && ! observability (Â, Ĉ)[:isobservable ]
208- error (" The augmented model is unobservable. You may try to use 0 " *
209- " integrator on model integrating outputs with nint_ym parameter." )
193+ error (" The augmented model is unobservable. You may try to use 0 integrator on " *
194+ " model integrating outputs with nint_ym parameter. Adding integrators at both " *
195+ " inputs (nint_u) and outputs (nint_ym) can also violate observability." )
210196 end
211197 return Â, B̂u, Ĉ, B̂d, D̂d
212198end
213199" No need to augment the model if `model` is not a [`LinModel`](@ref)."
214- augment_model (:: SimModel , _ , _ ) = nothing
200+ augment_model (:: SimModel , _ , _ , _ ) = nothing
215201
216202@doc raw """
217- default_nint(model::LinModel, i_ym=1:model.ny)
203+ default_nint(model::LinModel, i_ym=1:model.ny, nint_u )
218204
219205Get default integrator quantity per measured outputs `nint_ym` for [`LinModel`](@ref).
220206
@@ -234,24 +220,27 @@ julia> nint_ym = default_nint(model)
234220 1
235221```
236222"""
237- function default_nint (model:: LinModel , i_ym:: IntRangeOrVector = 1 : model. ny)
223+ function default_nint (model:: LinModel , i_ym= 1 : model. ny, nint_u= 0 )
224+ validate_ym (model, i_ym)
238225 nint_ym = fill (0 , length (i_ym))
239226 for i in eachindex (i_ym)
240227 nint_ym[i] = 1
241- Asm, Csm = init_integrators (i_ym, nint_ym)
242- As , _ , Cs = stoch_ym2y (model, i_ym, Asm, [], Csm, [])
243- Â , _ , Ĉ = augment_model (model, As, Cs, verify_obsv= false )
228+ As, Cs_u, Cs_y = init_estimstoch (model, i_ym, nint_u, nint_ym)
229+ Â, _ , Ĉ = augment_model (model, As, Cs_u, Cs_y, verify_obsv= false )
244230 # observability on Ĉ instead of Ĉm, since it would always return false when nym ≠ ny
245231 observability (Â, Ĉ)[:isobservable ] || (nint_ym[i] = 0 )
246232 end
247233 return nint_ym
248234end
249235"""
250- default_nint(model::SimModel, i_ym=1:model.ny)
236+ default_nint(model::SimModel, i_ym=1:model.ny, nint_u=0 )
251237
252238One integrator on each measured output by default if `model` is not a [`LinModel`](@ref).
253239"""
254- default_nint (:: SimModel , i_ym:: IntRangeOrVector = 1 : model. ny) = fill (1 , length (i_ym))
240+ function default_nint (model:: SimModel , i_ym= 1 : model. ny, nint_u= 0 )
241+ validate_ym (model, i_ym)
242+ return fill (1 , length (i_ym))
243+ end
255244
256245@doc raw """
257246 f̂(estim::StateEstimator, x̂, u, d)
@@ -269,8 +258,8 @@ function returns the next state of the augmented model, defined as:
269258"""
270259function f̂ (estim:: StateEstimator , x̂, u, d)
271260 # `@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 ] ]
261+ @views x̂d, x̂s = x̂[ 1 : estim. model. nx], x̂[estim . model . nx + 1 : end ]
262+ return [f (estim. model, x̂d , u + estim . Cs_u * x̂s , d); estim. As* x̂s ]
274263end
275264
276265@doc raw """
@@ -280,8 +269,8 @@ Output function ``\mathbf{ĥ}`` of the augmented model, see [`f̂`](@ref) for d
280269"""
281270function ĥ (estim:: StateEstimator , x̂, d)
282271 # `@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 ]
272+ @views x̂d, x̂s = x̂[ 1 : estim. model. nx], x̂[estim . model . nx + 1 : end ]
273+ return h (estim. model, x̂d , d) + estim. Cs_y * x̂s
285274end
286275
287276
0 commit comments