root/library/bdm/estim/kalman.h @ 384

Revision 384, 13.1 kB (checked in by mido, 15 years ago)

possibly broken?

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