| 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 | | |