64 | | |
65 | | class Kalman : public BM { |
66 | | protected: |
67 | | //! Indetifier of output rv |
68 | | RV rvy; |
69 | | //! Indetifier of exogeneous rv |
70 | | RV rvu; |
71 | | //! cache of rv.count() |
72 | | int dimx; |
73 | | //! cache of rvy.count() |
74 | | int dimy; |
75 | | //! cache of rvu.count() |
76 | | int dimu; |
77 | | //! Matrix A |
78 | | mat A; |
79 | | //! Matrix B |
80 | | mat B; |
81 | | //! Matrix C |
82 | | mat C; |
83 | | //! Matrix D |
84 | | mat D; |
85 | | //! Matrix Q in square-root form |
86 | | sq_T Q; |
87 | | //! Matrix R in square-root form |
88 | | sq_T R; |
89 | | |
90 | | //!posterior density on $x_t$ |
91 | | enorm<sq_T> est; |
92 | | //!preditive density on $y_t$ |
93 | | enorm<sq_T> fy; |
94 | | |
95 | | //! placeholder for Kalman gain |
96 | | mat _K; |
97 | | //! cache of fy.mu |
98 | | vec& _yp; |
99 | | //! cache of fy.R |
100 | | sq_T& _Ry; |
101 | | //!cache of est.mu |
102 | | vec& _mu; |
103 | | //!cache of est.R |
104 | | sq_T& _P; |
105 | | |
106 | | public: |
107 | | //! Default constructor |
108 | | Kalman ( ); |
109 | | //! Copy constructor |
110 | | Kalman ( const Kalman<sq_T> &K0 ); |
111 | | //! Set parameters with check of relevance |
112 | | void set_parameters ( const mat &A0, const mat &B0, const mat &C0, const mat &D0, const sq_T &Q0, const sq_T &R0 ); |
113 | | //! Set estimate values, used e.g. in initialization. |
114 | | void set_est ( const vec &mu0, const sq_T &P0 ) { |
115 | | sq_T pom ( dimy ); |
116 | | est.set_parameters ( mu0, P0 ); |
117 | | P0.mult_sym ( C, pom ); |
118 | | fy.set_parameters ( C*mu0, pom ); |
119 | | }; |
120 | | |
121 | | //! Here dt = [yt;ut] of appropriate dimensions |
122 | | void bayes ( const vec &dt ); |
123 | | //!access function |
124 | | const epdf& posterior() const { |
125 | | return est; |
126 | | } |
127 | | //!access function |
128 | | mat& __K() { |
129 | | return _K; |
130 | | } |
131 | | //!access function |
132 | | vec _dP() { |
133 | | return _P->getD(); |
134 | | } |
135 | | }; |
| 33 | class StateSpace |
| 34 | { |
| 35 | protected: |
| 36 | //! cache of rv.count() |
| 37 | int dimx; |
| 38 | //! cache of rvy.count() |
| 39 | int dimy; |
| 40 | //! cache of rvu.count() |
| 41 | int dimu; |
| 42 | //! Matrix A |
| 43 | mat A; |
| 44 | //! Matrix B |
| 45 | mat B; |
| 46 | //! Matrix C |
| 47 | mat C; |
| 48 | //! Matrix D |
| 49 | mat D; |
| 50 | //! Matrix Q in square-root form |
| 51 | sq_T Q; |
| 52 | //! Matrix R in square-root form |
| 53 | sq_T R; |
| 54 | public: |
| 55 | StateSpace() : dimx (0), dimy (0), dimu (0), A(), B(), C(), D(), Q(), R() {} |
| 56 | void set_parameters (const mat &A0, const mat &B0, const mat &C0, const mat &D0, const sq_T &Q0, const sq_T &R0); |
| 57 | void validate(); |
| 58 | //! not virtual in this case |
| 59 | void from_setting (const Setting &set) { |
| 60 | UI::get (A, set, "A", UI::compulsory); |
| 61 | UI::get (B, set, "B", UI::compulsory); |
| 62 | UI::get (C, set, "C", UI::compulsory); |
| 63 | UI::get (D, set, "D", UI::compulsory); |
| 64 | mat Qtm, Rtm; |
| 65 | if(!UI::get(Qtm, set, "Q", UI::optional)){ |
| 66 | vec dq; |
| 67 | UI::get(dq, set, "dQ", UI::compulsory); |
| 68 | Qtm=diag(dq); |
| 69 | } |
| 70 | if(!UI::get(Rtm, set, "R", UI::optional)){ |
| 71 | vec dr; |
| 72 | UI::get(dr, set, "dQ", UI::compulsory); |
| 73 | Rtm=diag(dr); |
| 74 | } |
| 75 | R=Rtm; // automatic conversion |
| 76 | Q=Qtm; |
| 77 | |
| 78 | validate(); |
| 79 | } |
| 80 | }; |
| 81 | |
| 82 | //! Common abstract base for Kalman filters |
| 83 | template<class sq_T> |
| 84 | class Kalman: public BM, public StateSpace<sq_T> |
| 85 | { |
| 86 | protected: |
| 87 | //! id of output |
| 88 | RV yrv; |
| 89 | //! id of input |
| 90 | RV urv; |
| 91 | //! Kalman gain |
| 92 | mat _K; |
| 93 | //!posterior |
| 94 | shared_ptr<enorm<sq_T> > est; |
| 95 | //!marginal on data f(y|y) |
| 96 | enorm<sq_T> fy; |
| 97 | public: |
| 98 | Kalman() : BM(), StateSpace<sq_T>(), yrv(),urv(), _K(), est(new enorm<sq_T>){} |
| 99 | void set_statistics (const vec &mu0, const mat &P0) {est->set_parameters (mu0, P0); }; |
| 100 | void set_statistics (const vec &mu0, const sq_T &P0) {est->set_parameters (mu0, P0); }; |
| 101 | //! posterior |
| 102 | const enorm<sq_T>& posterior() const {return *est.get();} |
| 103 | //! shared posterior |
| 104 | shared_ptr<epdf> shared_posterior() {return est;} |
| 105 | //! load basic elements of Kalman from structure |
| 106 | void from_setting (const Setting &set) { |
| 107 | StateSpace<sq_T>::from_setting(set); |
| 108 | |
| 109 | mat P0; vec mu0; |
| 110 | UI::get(mu0, set, "mu0", UI::optional); |
| 111 | UI::get(P0, set, "P0", UI::optional); |
| 112 | set_statistics(mu0,P0); |
| 113 | // Initial values |
| 114 | UI::get (yrv, set, "yrv", UI::optional); |
| 115 | UI::get (urv, set, "urv", UI::optional); |
| 116 | set_drv(concat(yrv,urv)); |
| 117 | |
| 118 | validate(); |
| 119 | } |
| 120 | void validate() { |
| 121 | StateSpace<sq_T>::validate(); |
| 122 | bdm_assert_debug(est->dimension(), "Statistics and model parameters mismatch"); |
| 123 | } |
| 124 | }; |
| 125 | /*! |
| 126 | * \brief Basic Kalman filter with full matrices |
| 127 | */ |
| 128 | |
| 129 | class KalmanFull : public Kalman<fsqmat> |
| 130 | { |
| 131 | public: |
| 132 | //! For EKFfull; |
| 133 | KalmanFull() :Kalman<fsqmat>(){}; |
| 134 | //! Here dt = [yt;ut] of appropriate dimensions |
| 135 | void bayes (const vec &dt); |
| 136 | }; |
| 137 | |
| 138 | |
142 | | */ |
143 | | class KalmanCh : public Kalman<chmat> { |
144 | | protected: |
145 | | //! pre array (triangular matrix) |
146 | | mat preA; |
147 | | //! post array (triangular matrix) |
148 | | mat postA; |
149 | | |
150 | | public: |
151 | | //! copy constructor |
152 | | BM* _copy_() const { |
153 | | KalmanCh* K = new KalmanCh; |
154 | | K->set_parameters ( A, B, C, D, Q, R ); |
155 | | K->set_statistics ( _mu, _P ); |
156 | | return K; |
157 | | } |
158 | | //! Set parameters with check of relevance |
159 | | void set_parameters ( const mat &A0, const mat &B0, const mat &C0, const mat &D0, const chmat &Q0, const chmat &R0 ); |
160 | | void set_statistics ( const vec &mu0, const chmat &P0 ) { |
161 | | est.set_parameters ( mu0, P0 ); |
162 | | }; |
163 | | |
164 | | |
165 | | /*!\brief Here dt = [yt;ut] of appropriate dimensions |
166 | | |
167 | | The following equality hold::\f[ |
168 | | \left[\begin{array}{cc} |
169 | | R^{0.5}\\ |
170 | | P_{t|t-1}^{0.5}C' & P_{t|t-1}^{0.5}CA'\\ |
171 | | & Q^{0.5}\end{array}\right]<\mathrm{orth.oper.}>=\left[\begin{array}{cc} |
172 | | R_{y}^{0.5} & KA'\\ |
173 | | & P_{t+1|t}^{0.5}\\ |
174 | | \\\end{array}\right]\f] |
175 | | |
176 | | Thus this object evaluates only predictors! Not filtering densities. |
177 | | */ |
178 | | void bayes ( const vec &dt ); |
| 145 | Complete constructor: |
| 146 | */ |
| 147 | class KalmanCh : public Kalman<chmat> |
| 148 | { |
| 149 | protected: |
| 150 | //! @{ \name Internal storage - needs initialize() |
| 151 | //! pre array (triangular matrix) |
| 152 | mat preA; |
| 153 | //! post array (triangular matrix) |
| 154 | mat postA; |
| 155 | //!@} |
| 156 | public: |
| 157 | //! copy constructor |
| 158 | BM* _copy_() const { |
| 159 | KalmanCh* K = new KalmanCh; |
| 160 | K->set_parameters (A, B, C, D, Q, R); |
| 161 | K->set_statistics (est->_mu(), est->_R()); |
| 162 | return K; |
| 163 | } |
| 164 | //! set parameters for adapt from Kalman |
| 165 | void set_parameters (const mat &A0, const mat &B0, const mat &C0, const mat &D0, const chmat &Q0, const chmat &R0); |
| 166 | //! initialize internal parametetrs |
| 167 | void initialize(); |
| 168 | |
| 169 | /*!\brief Here dt = [yt;ut] of appropriate dimensions |
| 170 | |
| 171 | The following equality hold::\f[ |
| 172 | \left[\begin{array}{cc} |
| 173 | R^{0.5}\\ |
| 174 | P_{t|t-1}^{0.5}C' & P_{t|t-1}^{0.5}CA'\\ |
| 175 | & Q^{0.5}\end{array}\right]<\mathrm{orth.oper.}>=\left[\begin{array}{cc} |
| 176 | R_{y}^{0.5} & KA'\\ |
| 177 | & P_{t+1|t}^{0.5}\\ |
| 178 | \\\end{array}\right]\f] |
| 179 | |
| 180 | Thus this object evaluates only predictors! Not filtering densities. |
| 181 | */ |
| 182 | void bayes (const vec &dt); |
| 183 | |
| 184 | void from_settings(const Setting &set){ |
| 185 | Kalman<chmat>::from_setting(set); |
| 186 | initialize(); |
| 187 | } |
186 | | class EKFfull : public KalmanFull, public BM { |
187 | | protected: |
188 | | //! Internal Model f(x,u) |
189 | | shared_ptr<diffbifn> pfxu; |
190 | | |
191 | | //! Observation Model h(x,u) |
192 | | shared_ptr<diffbifn> phxu; |
193 | | |
194 | | enorm<fsqmat> E; |
195 | | public: |
196 | | //! Default constructor |
197 | | EKFfull ( ); |
198 | | |
199 | | //! Set nonlinear functions for mean values and covariance matrices. |
200 | | void set_parameters ( const shared_ptr<diffbifn> &pfxu, const shared_ptr<diffbifn> &phxu, const mat Q0, const mat R0 ); |
201 | | |
202 | | //! Here dt = [yt;ut] of appropriate dimensions |
203 | | void bayes ( const vec &dt ); |
204 | | //! set estimates |
205 | | void set_statistics ( vec mu0, mat P0 ) { |
206 | | mu = mu0; |
207 | | P = P0; |
208 | | }; |
209 | | //!dummy! |
210 | | const epdf& posterior() const { |
211 | | return E; |
212 | | }; |
213 | | const mat _R() { |
214 | | return P; |
215 | | } |
216 | | }; |
217 | | |
218 | | /*! |
219 | | \brief Extended Kalman Filter |
| 195 | class EKFfull : public KalmanFull |
| 196 | { |
| 197 | protected: |
| 198 | //! Internal Model f(x,u) |
| 199 | shared_ptr<diffbifn> pfxu; |
| 200 | |
| 201 | //! Observation Model h(x,u) |
| 202 | shared_ptr<diffbifn> phxu; |
| 203 | |
| 204 | public: |
| 205 | //! Default constructor |
| 206 | EKFfull (); |
| 207 | |
| 208 | //! Set nonlinear functions for mean values and covariance matrices. |
| 209 | void set_parameters (const shared_ptr<diffbifn> &pfxu, const shared_ptr<diffbifn> &phxu, const mat Q0, const mat R0); |
| 210 | |
| 211 | //! Here dt = [yt;ut] of appropriate dimensions |
| 212 | void bayes (const vec &dt); |
| 213 | //! set estimates |
| 214 | void set_statistics (const vec &mu0, const mat &P0) { |
| 215 | est->set_parameters (mu0, P0); |
| 216 | }; |
| 217 | const mat _R() { |
| 218 | return est->_R().to_mat(); |
| 219 | } |
| 220 | }; |
| 221 | |
| 222 | /*! |
| 223 | \brief Extended Kalman Filter in Square root |
| 227 | |
| 228 | class EKFCh : public KalmanCh |
| 229 | { |
| 230 | protected: |
| 231 | //! Internal Model f(x,u) |
| 232 | shared_ptr<diffbifn> pfxu; |
| 233 | |
| 234 | //! Observation Model h(x,u) |
| 235 | shared_ptr<diffbifn> phxu; |
| 236 | public: |
| 237 | //! copy constructor duplicated - calls different set_parameters |
| 238 | BM* _copy_() const { |
| 239 | EKFCh* E = new EKFCh; |
| 240 | E->set_parameters (pfxu, phxu, Q, R); |
| 241 | E->set_statistics (est->_mu(), est->_R()); |
| 242 | return E; |
| 243 | } |
| 244 | //! Set nonlinear functions for mean values and covariance matrices. |
| 245 | void set_parameters (const shared_ptr<diffbifn> &pfxu, const shared_ptr<diffbifn> &phxu, const chmat Q0, const chmat R0); |
| 246 | |
| 247 | //! Here dt = [yt;ut] of appropriate dimensions |
| 248 | void bayes (const vec &dt); |
| 249 | |
| 250 | void from_setting (const Setting &set); |
| 251 | |
| 252 | // TODO dodelat void to_setting( Setting &set ) const; |
| 253 | |
| 254 | }; |
| 255 | |
| 256 | UIREGISTER (EKFCh); |
| 257 | SHAREDPTR (EKFCh); |
| 258 | |
| 259 | |
| 260 | //////// INstance |
| 261 | |
| 262 | /*! \brief (Switching) Multiple Model |
| 263 | The model runs several models in parallel and evaluates thier weights (fittness). |
| 264 | |
| 265 | The statistics of the resulting density are merged using (geometric?) combination. |
| 266 | |
| 267 | The next step is performed with the new statistics for all models. |
| 268 | */ |
| 269 | class MultiModel: public BM |
| 270 | { |
| 271 | protected: |
| 272 | //! List of models between which we switch |
| 273 | Array<EKFCh*> Models; |
| 274 | //! vector of model weights |
| 275 | vec w; |
| 276 | //! cache of model lls |
| 277 | vec _lls; |
| 278 | //! type of switching policy [1=maximum,2=...] |
| 279 | int policy; |
| 280 | //! internal statistics |
| 281 | enorm<chmat> est; |
| 282 | public: |
| 283 | void set_parameters (Array<EKFCh*> A, int pol0 = 1) { |
| 284 | Models = A;//TODO: test if evalll is set |
| 285 | w.set_length (A.length()); |
| 286 | _lls.set_length (A.length()); |
| 287 | policy = pol0; |
| 288 | |
| 289 | est.set_rv (RV ("MM", A (0)->posterior().dimension(), 0)); |
| 290 | est.set_parameters (A (0)->posterior().mean(), A (0)->posterior()._R()); |
| 291 | } |
| 292 | void bayes (const vec &dt) { |
| 293 | int n = Models.length(); |
| 294 | int i; |
| 295 | for (i = 0; i < n; i++) { |
| 296 | Models (i)->bayes (dt); |
| 297 | _lls (i) = Models (i)->_ll(); |
| 298 | } |
| 299 | double mlls = max (_lls); |
| 300 | w = exp (_lls - mlls); |
| 301 | w /= sum (w); //normalization |
| 302 | //set statistics |
| 303 | switch (policy) { |
| 304 | case 1: { |
| 305 | int mi = max_index (w); |
| 306 | const enorm<chmat> &st = Models (mi)->posterior() ; |
| 307 | est.set_parameters (st.mean(), st._R()); |
| 308 | } |
| 309 | break; |
| 310 | default: |
| 311 | bdm_error ("unknown policy"); |
| 312 | } |
| 313 | // copy result to all models |
| 314 | for (i = 0; i < n; i++) { |
| 315 | Models (i)->set_statistics (est.mean(), est._R()); |
| 316 | } |
| 317 | } |
| 318 | //! posterior density |
| 319 | const enorm<chmat>& posterior() const { |
| 320 | return est; |
| 321 | } |
| 322 | |
| 323 | void from_setting (const Setting &set); |
| 324 | |
| 325 | // TODO dodelat void to_setting( Setting &set ) const; |
| 326 | |
| 327 | }; |
| 328 | |
| 329 | UIREGISTER (MultiModel); |
| 330 | SHAREDPTR (MultiModel); |
| 331 | |
| 332 | /////////// INSTANTIATION |
| 333 | |
224 | | class EKF : public Kalman<fsqmat> { |
225 | | //! Internal Model f(x,u) |
226 | | diffbifn* pfxu; |
227 | | //! Observation Model h(x,u) |
228 | | diffbifn* phxu; |
229 | | public: |
230 | | //! Default constructor |
231 | | EKF ( RV rvx, RV rvy, RV rvu ); |
232 | | //! copy constructor |
233 | | EKF<sq_T>* _copy_() const { |
234 | | return new EKF<sq_T> ( this ); |
235 | | } |
236 | | //! Set nonlinear functions for mean values and covariance matrices. |
237 | | void set_parameters ( diffbifn* pfxu, diffbifn* phxu, const sq_T Q0, const sq_T R0 ); |
238 | | //! Here dt = [yt;ut] of appropriate dimensions |
239 | | void bayes ( const vec &dt ); |
240 | | }; |
241 | | |
242 | | /*! |
243 | | \brief Extended Kalman Filter in Square root |
244 | | |
245 | | An approximation of the exact Bayesian filter with Gaussian noices and non-linear evolutions of their mean. |
246 | | */ |
247 | | |
248 | | class EKFCh : public KalmanCh { |
249 | | protected: |
250 | | //! Internal Model f(x,u) |
251 | | shared_ptr<diffbifn> pfxu; |
252 | | |
253 | | //! Observation Model h(x,u) |
254 | | shared_ptr<diffbifn> phxu; |
255 | | public: |
256 | | //! copy constructor duplicated - calls different set_parameters |
257 | | BM* _copy_() const { |
258 | | EKFCh* E = new EKFCh; |
259 | | E->set_parameters ( pfxu, phxu, Q, R ); |
260 | | E->set_statistics ( _mu, _P ); |
261 | | return E; |
262 | | } |
263 | | //! Set nonlinear functions for mean values and covariance matrices. |
264 | | void set_parameters ( const shared_ptr<diffbifn> &pfxu, const shared_ptr<diffbifn> &phxu, const chmat Q0, const chmat R0 ); |
265 | | |
266 | | //! Here dt = [yt;ut] of appropriate dimensions |
267 | | void bayes ( const vec &dt ); |
268 | | |
269 | | void from_setting ( const Setting &set ); |
270 | | |
271 | | // TODO dodelat void to_setting( Setting &set ) const; |
272 | | |
273 | | const enorm<chmat>& posterior() {return est;} |
274 | | }; |
275 | | |
276 | | UIREGISTER ( EKFCh ); |
277 | | SHAREDPTR ( EKFCh ); |
278 | | |
279 | | |
280 | | /*! |
281 | | \brief Kalman Filter with conditional diagonal matrices R and Q. |
282 | | */ |
283 | | |
284 | | class KFcondQR : public Kalman<ldmat> { |
285 | | //protected: |
286 | | public: |
287 | | void condition ( const vec &QR ) { |
288 | | bdm_assert_debug ( QR.length() == ( dimx + dimy ), "KFcondQR: conditioning by incompatible vector" ); |
289 | | |
290 | | Q.setD ( QR ( 0, dimx - 1 ) ); |
291 | | R.setD ( QR ( dimx, -1 ) ); |
292 | | }; |
293 | | }; |
294 | | |
295 | | /*! |
296 | | \brief Kalman Filter with conditional diagonal matrices R and Q. |
297 | | */ |
298 | | |
299 | | class KFcondR : public Kalman<ldmat> { |
300 | | //protected: |
301 | | public: |
302 | | //!Default constructor |
303 | | KFcondR ( ) : Kalman<ldmat> ( ) {}; |
304 | | |
305 | | void condition ( const vec &R0 ) { |
306 | | bdm_assert_debug ( R0.length() == ( dimy ), "KFcondR: conditioning by incompatible vector" ); |
307 | | |
308 | | R.setD ( R0 ); |
309 | | }; |
310 | | |
311 | | }; |
312 | | |
313 | | //////// INstance |
314 | | |
315 | | template<class sq_T> |
316 | | Kalman<sq_T>::Kalman ( const Kalman<sq_T> &K0 ) : BM ( ), rvy ( K0.rvy ), rvu ( K0.rvu ), |
317 | | dimx ( K0.dimx ), dimy ( K0.dimy ), dimu ( K0.dimu ), |
318 | | A ( K0.A ), B ( K0.B ), C ( K0.C ), D ( K0.D ), |
319 | | Q ( K0.Q ), R ( K0.R ), |
320 | | est ( K0.est ), fy ( K0.fy ), _yp ( fy._mu() ), _Ry ( fy._R() ), _mu ( est._mu() ), _P ( est._R() ) { |
321 | | |
322 | | // copy values in pointers |
323 | | // _mu = K0._mu; |
324 | | // _P = K0._P; |
325 | | // _yp = K0._yp; |
326 | | // _Ry = K0._Ry; |
327 | | |
328 | | } |
329 | | |
330 | | template<class sq_T> |
331 | | Kalman<sq_T>::Kalman ( ) : BM (), est ( ), fy (), _yp ( fy._mu() ), _Ry ( fy._R() ), _mu ( est._mu() ), _P ( est._R() ) { |
332 | | }; |
333 | | |
334 | | template<class sq_T> |
335 | | void Kalman<sq_T>::set_parameters ( const mat &A0, const mat &B0, const mat &C0, const mat &D0, const sq_T &Q0, const sq_T &R0 ) { |
| 335 | void StateSpace<sq_T>::set_parameters (const mat &A0, const mat &B0, const mat &C0, const mat &D0, const sq_T &Q0, const sq_T &R0) |
| 336 | { |
356 | | void Kalman<sq_T>::bayes ( const vec &dt ) { |
357 | | bdm_assert_debug ( dt.length() == ( dimy + dimu ), "Kalman::bayes wrong size of dt" ); |
358 | | |
359 | | sq_T iRy ( dimy ); |
360 | | vec u = dt.get ( dimy, dimy + dimu - 1 ); |
361 | | vec y = dt.get ( 0, dimy - 1 ); |
362 | | //Time update |
363 | | _mu = A * _mu + B * u; |
364 | | //P = A*P*A.transpose() + Q; in sq_T |
365 | | _P.mult_sym ( A ); |
366 | | _P += Q; |
367 | | |
368 | | //Data update |
369 | | //_Ry = C*P*C.transpose() + R; in sq_T |
370 | | _P.mult_sym ( C, _Ry ); |
371 | | _Ry += R; |
372 | | |
373 | | mat Pfull = _P.to_mat(); |
374 | | |
375 | | _Ry.inv ( iRy ); // result is in _iRy; |
376 | | _K = Pfull * C.transpose() * ( iRy.to_mat() ); |
377 | | |
378 | | sq_T pom ( ( int ) Pfull.rows() ); |
379 | | iRy.mult_sym_t ( C*Pfull, pom ); |
380 | | ( _P ) -= pom; // P = P -PC'iRy*CP; |
381 | | ( _yp ) = C * _mu + D * u; //y prediction |
382 | | ( _mu ) += _K * ( y - _yp ); |
383 | | |
384 | | |
385 | | if ( evalll == true ) { //likelihood of observation y |
386 | | ll = fy.evallog ( y ); |
387 | | } |
388 | | |
389 | | //cout << "y: " << y-(*_yp) <<" R: " << _Ry->to_mat() << " iR: " << _iRy->to_mat() << " ll: " << ll <<endl; |
390 | | |
391 | | }; |
392 | | |
393 | | /*! \brief (Switching) Multiple Model |
394 | | The model runs several models in parallel and evaluates thier weights (fittness). |
395 | | |
396 | | The statistics of the resulting density are merged using (geometric?) combination. |
397 | | |
398 | | The next step is performed with the new statistics for all models. |
399 | | */ |
400 | | class MultiModel: public BM { |
401 | | protected: |
402 | | //! List of models between which we switch |
403 | | Array<EKFCh*> Models; |
404 | | //! vector of model weights |
405 | | vec w; |
406 | | //! cache of model lls |
407 | | vec _lls; |
408 | | //! type of switching policy [1=maximum,2=...] |
409 | | int policy; |
410 | | //! internal statistics |
411 | | enorm<chmat> est; |
412 | | public: |
413 | | void set_parameters ( Array<EKFCh*> A, int pol0 = 1 ) { |
414 | | Models = A;//TODO: test if evalll is set |
415 | | w.set_length ( A.length() ); |
416 | | _lls.set_length ( A.length() ); |
417 | | policy = pol0; |
418 | | |
419 | | est.set_rv ( RV ( "MM", A ( 0 )->posterior().dimension(), 0 ) ); |
420 | | est.set_parameters ( A ( 0 )->posterior().mean(), A ( 0 )->posterior()._R() ); |
421 | | } |
422 | | void bayes ( const vec &dt ) { |
423 | | int n = Models.length(); |
424 | | int i; |
425 | | for ( i = 0; i < n; i++ ) { |
426 | | Models ( i )->bayes ( dt ); |
427 | | _lls ( i ) = Models ( i )->_ll(); |
428 | | } |
429 | | double mlls = max ( _lls ); |
430 | | w = exp ( _lls - mlls ); |
431 | | w /= sum ( w ); //normalization |
432 | | //set statistics |
433 | | switch ( policy ) { |
434 | | case 1: { |
435 | | int mi = max_index ( w ); |
436 | | const enorm<chmat> &st = Models ( mi )->posterior() ; |
437 | | est.set_parameters ( st.mean(), st._R() ); |
438 | | } |
439 | | break; |
440 | | default: |
441 | | bdm_error ( "unknown policy" ); |
442 | | } |
443 | | // copy result to all models |
444 | | for ( i = 0; i < n; i++ ) { |
445 | | Models ( i )->set_statistics ( est.mean(), est._R() ); |
446 | | } |
447 | | } |
448 | | //! posterior density |
449 | | const enorm<chmat>& posterior() const { |
450 | | return est; |
451 | | } |
452 | | |
453 | | void from_setting ( const Setting &set ); |
454 | | |
455 | | // TODO dodelat void to_setting( Setting &set ) const; |
456 | | |
457 | | }; |
458 | | |
459 | | UIREGISTER ( MultiModel ); |
460 | | SHAREDPTR ( MultiModel ); |
461 | | |
462 | | |
463 | | |
464 | | //TODO why not const pointer?? |
465 | | |
466 | | template<class sq_T> |
467 | | EKF<sq_T>::EKF ( RV rvx0, RV rvy0, RV rvu0 ) : Kalman<sq_T> ( rvx0, rvy0, rvu0 ) {} |
468 | | |
469 | | template<class sq_T> |
470 | | void EKF<sq_T>::set_parameters ( diffbifn* pfxu0, diffbifn* phxu0, const sq_T Q0, const sq_T R0 ) { |
471 | | pfxu = pfxu0; |
472 | | phxu = phxu0; |
473 | | |
474 | | //initialize matrices A C, later, these will be only updated! |
475 | | pfxu->dfdx_cond ( _mu, zeros ( dimu ), A, true ); |
476 | | // pfxu->dfdu_cond ( *_mu,zeros ( dimu ),B,true ); |
477 | | B.clear(); |
478 | | phxu->dfdx_cond ( _mu, zeros ( dimu ), C, true ); |
479 | | // phxu->dfdu_cond ( *_mu,zeros ( dimu ),D,true ); |
480 | | D.clear(); |
481 | | |
482 | | R = R0; |
483 | | Q = Q0; |
| 351 | void StateSpace<sq_T>::validate(){ |
| 352 | bdm_assert_debug (A.cols() == dimx, "KalmanFull: A is not square"); |
| 353 | bdm_assert_debug (B.rows() == dimx, "KalmanFull: B is not compatible"); |
| 354 | bdm_assert_debug (C.cols() == dimx, "KalmanFull: C is not square"); |
| 355 | bdm_assert_debug ( (D.rows() == dimy) || (D.cols() == dimu), "KalmanFull: D is not compatible"); |
| 356 | bdm_assert_debug ( (Q.cols() == dimx) || (Q.rows() == dimx), "KalmanFull: Q is not compatible"); |
| 357 | bdm_assert_debug ( (R.cols() == dimy) || (R.rows() == dimy), "KalmanFull: R is not compatible"); |
485 | | |
486 | | template<class sq_T> |
487 | | void EKF<sq_T>::bayes ( const vec &dt ) { |
488 | | bdm_assert_debug ( dt.length() == ( dimy + dimu ), "EKF<>::bayes wrong size of dt" ); |
489 | | |
490 | | sq_T iRy ( dimy, dimy ); |
491 | | vec u = dt.get ( dimy, dimy + dimu - 1 ); |
492 | | vec y = dt.get ( 0, dimy - 1 ); |
493 | | //Time update |
494 | | _mu = pfxu->eval ( _mu, u ); |
495 | | pfxu->dfdx_cond ( _mu, u, A, false ); //update A by a derivative of fx |
496 | | |
497 | | //P = A*P*A.transpose() + Q; in sq_T |
498 | | _P.mult_sym ( A ); |
499 | | _P += Q; |
500 | | |
501 | | //Data update |
502 | | phxu->dfdx_cond ( _mu, u, C, false ); //update C by a derivative hx |
503 | | //_Ry = C*P*C.transpose() + R; in sq_T |
504 | | _P.mult_sym ( C, _Ry ); |
505 | | ( _Ry ) += R; |
506 | | |
507 | | mat Pfull = _P.to_mat(); |
508 | | |
509 | | _Ry.inv ( iRy ); // result is in _iRy; |
510 | | _K = Pfull * C.transpose() * ( iRy.to_mat() ); |
511 | | |
512 | | sq_T pom ( ( int ) Pfull.rows() ); |
513 | | iRy.mult_sym_t ( C*Pfull, pom ); |
514 | | ( _P ) -= pom; // P = P -PC'iRy*CP; |
515 | | _yp = phxu->eval ( _mu, u ); //y prediction |
516 | | ( _mu ) += _K * ( y - _yp ); |
517 | | |
518 | | if ( evalll == true ) { |
519 | | ll += fy.evallog ( y ); |
520 | | } |
521 | | }; |
522 | | |