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

Revision 744, 14.1 kB (checked in by smidl, 15 years ago)

Working unitsteps and controlloop + corresponding fixes

  • Property svn:eol-style set to native
Line 
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
16
17#include "../math/functions.h"
18#include "../stat/exp_family.h"
19#include "../math/chmat.h"
20#include "../base/user_info.h"
21//#include <../applications/pmsm/simulator_zdenek/ekf_example/pmsm_mod.h>
22
23namespace bdm {
24
25/*!
26 * \brief Basic elements of linear state-space model
27
28Parameter evolution model:\f[ x_{t+1} = A x_{t} + B u_t + Q^{1/2} e_t \f]
29Observation model: \f[ y_t = C x_{t} + C u_t + R^{1/2} w_t. \f]
30Where $e_t$ and $w_t$ are mutually independent vectors of Normal(0,1)-distributed disturbances.
31 */
32template<class sq_T>
33class StateSpace {
34protected:
35        //! Matrix A
36        mat A;
37        //! Matrix B
38        mat B;
39        //! Matrix C
40        mat C;
41        //! Matrix D
42        mat D;
43        //! Matrix Q in square-root form
44        sq_T Q;
45        //! Matrix R in square-root form
46        sq_T R;
47public:
48        StateSpace() :  A(), B(), C(), D(), Q(), R() {}
49        //!copy constructor
50        StateSpace ( const StateSpace<sq_T> &S0 ) :  A ( S0.A ), B ( S0.B ), C ( S0.C ), D ( S0.D ), Q ( S0.Q ), R ( S0.R ) {}
51        //! set all matrix parameters
52        void set_parameters ( const mat &A0, const  mat &B0, const  mat &C0, const  mat &D0, const  sq_T &Q0, const sq_T &R0 );
53        //! validation
54        void validate();
55        //! not virtual in this case
56        void from_setting ( const Setting &set ) {
57                UI::get ( A, set, "A", UI::compulsory );
58                UI::get ( B, set, "B", UI::compulsory );
59                UI::get ( C, set, "C", UI::compulsory );
60                UI::get ( D, set, "D", UI::compulsory );
61                mat Qtm, Rtm; // full matrices
62                if ( !UI::get ( Qtm, set, "Q", UI::optional ) ) {
63                        vec dq;
64                        UI::get ( dq, set, "dQ", UI::compulsory );
65                        Qtm = diag ( dq );
66                }
67                if ( !UI::get ( Rtm, set, "R", UI::optional ) ) {
68                        vec dr;
69                        UI::get ( dr, set, "dQ", UI::compulsory );
70                        Rtm = diag ( dr );
71                }
72                R = Rtm; // automatic conversion to square-root form
73                Q = Qtm;
74
75                validate();
76        }
77        //! access function
78        const mat& _A() const {
79                return A;
80        }
81        //! access function
82        const mat& _B() const {
83                return B;
84        }
85        //! access function
86        const mat& _C() const {
87                return C;
88        }
89        //! access function
90        const mat& _D() const {
91                return D;
92        }
93        //! access function
94        const sq_T& _Q() const {
95                return Q;
96        }
97        //! access function
98        const sq_T& _R() const {
99                return R;
100        }
101};
102
103//! Common abstract base for Kalman filters
104template<class sq_T>
105class Kalman: public BM, public StateSpace<sq_T> {
106protected:
107        //! id of output
108        RV yrv;
109        //! Kalman gain
110        mat  _K;
111        //!posterior
112        enorm<sq_T> est;
113        //!marginal on data f(y|y)
114        enorm<sq_T>  fy;
115public:
116        Kalman<sq_T>() : BM(), StateSpace<sq_T>(), yrv(), _K(),  est() {}
117        //! Copy constructor
118        Kalman<sq_T> ( const Kalman<sq_T> &K0 ) : BM ( K0 ), StateSpace<sq_T> ( K0 ), yrv ( K0.yrv ), _K ( K0._K ),  est ( K0.est ), fy ( K0.fy ) {}
119        //!set statistics of the posterior
120        void set_statistics ( const vec &mu0, const mat &P0 ) {
121                est.set_parameters ( mu0, P0 );
122        };
123        //!set statistics of the posterior
124        void set_statistics ( const vec &mu0, const sq_T &P0 ) {
125                est.set_parameters ( mu0, P0 );
126        };
127        //! return correctly typed posterior (covariant return)
128        const enorm<sq_T>& posterior() const {
129                return est;
130        }
131        //! load basic elements of Kalman from structure
132        void from_setting ( const Setting &set ) {
133                StateSpace<sq_T>::from_setting ( set );
134
135                mat P0;
136                vec mu0;
137                UI::get ( mu0, set, "mu0", UI::optional );
138                UI::get ( P0, set,  "P0", UI::optional );
139                set_statistics ( mu0, P0 );
140                // Initial values
141                UI::get ( yrv, set, "yrv", UI::optional );
142                UI::get ( rvc, set, "urv", UI::optional );
143                set_yrv ( concat ( yrv, rvc ) );
144
145                validate();
146        }
147        //! validate object
148        void validate() {
149                StateSpace<sq_T>::validate();
150                dimy = this->C.rows();
151                dimc = this->B.cols();
152                set_dim ( this->A.rows() );
153
154                bdm_assert ( est.dimension(), "Statistics and model parameters mismatch" );
155        }
156};
157/*!
158* \brief Basic Kalman filter with full matrices
159*/
160
161class KalmanFull : public Kalman<fsqmat> {
162public:
163        //! For EKFfull;
164        KalmanFull() : Kalman<fsqmat>() {};
165        //! Here dt = [yt;ut] of appropriate dimensions
166        void bayes ( const vec &yt, const vec &cond = empty_vec );
167        BM* _copy_() const {
168                KalmanFull* K = new KalmanFull;
169                K->set_parameters ( A, B, C, D, Q, R );
170                K->set_statistics ( est._mu(), est._R() );
171                return K;
172        }
173};
174UIREGISTER ( KalmanFull );
175
176
177/*! \brief Kalman filter in square root form
178
179Trivial example:
180\include kalman_simple.cpp
181
182Complete constructor:
183*/
184class KalmanCh : public Kalman<chmat> {
185protected:
186        //! @{ \name Internal storage - needs initialize()
187        //! pre array (triangular matrix)
188        mat preA;
189        //! post array (triangular matrix)
190        mat postA;
191        //!@}
192public:
193        //! copy constructor
194        BM* _copy_() const {
195                KalmanCh* K = new KalmanCh;
196                K->set_parameters ( A, B, C, D, Q, R );
197                K->set_statistics ( est._mu(), est._R() );
198                K->validate();
199                return K;
200        }
201        //! set parameters for adapt from Kalman
202        void set_parameters ( const mat &A0, const mat &B0, const mat &C0, const mat &D0, const chmat &Q0, const chmat &R0 );
203        //! initialize internal parametetrs
204        void initialize();
205
206        /*!\brief  Here dt = [yt;ut] of appropriate dimensions
207
208        The following equality hold::\f[
209        \left[\begin{array}{cc}
210        R^{0.5}\\
211        P_{t|t-1}^{0.5}C' & P_{t|t-1}^{0.5}CA'\\
212        & Q^{0.5}\end{array}\right]<\mathrm{orth.oper.}>=\left[\begin{array}{cc}
213        R_{y}^{0.5} & KA'\\
214        & P_{t+1|t}^{0.5}\\
215        \\\end{array}\right]\f]
216
217        Thus this object evaluates only predictors! Not filtering densities.
218        */
219        void bayes ( const vec &yt, const vec &cond = empty_vec );
220
221        void from_setting ( const Setting &set ) {
222                Kalman<chmat>::from_setting ( set );
223                validate();
224        }
225        void validate() {
226                Kalman<chmat>::validate();
227                initialize();
228        }
229};
230UIREGISTER ( KalmanCh );
231
232/*!
233\brief Extended Kalman Filter in full matrices
234
235An approximation of the exact Bayesian filter with Gaussian noices and non-linear evolutions of their mean.
236*/
237class EKFfull : public KalmanFull {
238protected:
239        //! Internal Model f(x,u)
240        shared_ptr<diffbifn> pfxu;
241
242        //! Observation Model h(x,u)
243        shared_ptr<diffbifn> phxu;
244
245public:
246        //! Default constructor
247        EKFfull ();
248
249        //! Set nonlinear functions for mean values and covariance matrices.
250        void set_parameters ( const shared_ptr<diffbifn> &pfxu, const shared_ptr<diffbifn> &phxu, const mat Q0, const mat R0 );
251
252        //! Here dt = [yt;ut] of appropriate dimensions
253        void bayes ( const vec &yt, const vec &cond = empty_vec );
254        //! set estimates
255        void set_statistics ( const vec &mu0, const mat &P0 ) {
256                est.set_parameters ( mu0, P0 );
257        };
258        //! access function
259        const mat _R() {
260                return est._R().to_mat();
261        }
262        void from_setting ( const Setting &set ) {
263                BM::from_setting ( set );
264                shared_ptr<diffbifn> IM = UI::build<diffbifn> ( set, "IM", UI::compulsory );
265                shared_ptr<diffbifn> OM = UI::build<diffbifn> ( set, "OM", UI::compulsory );
266
267                //statistics
268                int dim = IM->dimension();
269                vec mu0;
270                if ( !UI::get ( mu0, set, "mu0" ) )
271                        mu0 = zeros ( dim );
272
273                mat P0;
274                vec dP0;
275                if ( UI::get ( dP0, set, "dP0" ) )
276                        P0 = diag ( dP0 );
277                else if ( !UI::get ( P0, set, "P0" ) )
278                        P0 = eye ( dim );
279
280                set_statistics ( mu0, P0 );
281
282                //parameters
283                vec dQ, dR;
284                UI::get ( dQ, set, "dQ", UI::compulsory );
285                UI::get ( dR, set, "dR", UI::compulsory );
286                set_parameters ( IM, OM, diag ( dQ ), diag ( dR ) );
287
288                string options;
289                if ( UI::get ( options, set, "options" ) )
290                        set_options ( options );
291//                      pfxu = UI::build<diffbifn>(set, "IM", UI::compulsory);
292//                      phxu = UI::build<diffbifn>(set, "OM", UI::compulsory);
293//
294//                      mat R0;
295//                      UI::get(R0, set, "R",UI::compulsory);
296//                      mat Q0;
297//                      UI::get(Q0, set, "Q",UI::compulsory);
298//
299//
300//                      mat P0; vec mu0;
301//                      UI::get(mu0, set, "mu0", UI::optional);
302//                      UI::get(P0, set,  "P0", UI::optional);
303//                      set_statistics(mu0,P0);
304//                      // Initial values
305//                      UI::get (yrv, set, "yrv", UI::optional);
306//                      UI::get (urv, set, "urv", UI::optional);
307//                      set_drv(concat(yrv,urv));
308//
309//                      // setup StateSpace
310//                      pfxu->dfdu_cond(mu0, zeros(pfxu->_dimu()), A,true);
311//                      phxu->dfdu_cond(mu0, zeros(pfxu->_dimu()), C,true);
312//
313                validate();
314        }
315        void validate() {
316                // check stats and IM and OM
317        }
318};
319UIREGISTER ( EKFfull );
320
321
322/*!
323\brief Extended Kalman Filter in Square root
324
325An approximation of the exact Bayesian filter with Gaussian noices and non-linear evolutions of their mean.
326*/
327
328class EKFCh : public KalmanCh {
329protected:
330        //! Internal Model f(x,u)
331        shared_ptr<diffbifn> pfxu;
332
333        //! Observation Model h(x,u)
334        shared_ptr<diffbifn> phxu;
335public:
336        //! copy constructor duplicated - calls different set_parameters
337        BM* _copy_() const {
338                return new EKFCh(*this);
339        }
340        //! Set nonlinear functions for mean values and covariance matrices.
341        void set_parameters ( const shared_ptr<diffbifn> &pfxu, const shared_ptr<diffbifn> &phxu, const chmat Q0, const chmat R0 );
342
343        //! Here dt = [yt;ut] of appropriate dimensions
344        void bayes ( const vec &yt, const vec &cond = empty_vec );
345
346        void from_setting ( const Setting &set );
347
348        void validate() {};
349        // TODO dodelat void to_setting( Setting &set ) const;
350
351};
352
353UIREGISTER ( EKFCh );
354SHAREDPTR ( EKFCh );
355
356
357//////// INstance
358
359/*! \brief (Switching) Multiple Model
360The model runs several models in parallel and evaluates thier weights (fittness).
361
362The statistics of the resulting density are merged using (geometric?) combination.
363
364The next step is performed with the new statistics for all models.
365*/
366class MultiModel: public BM {
367protected:
368        //! List of models between which we switch
369        Array<EKFCh*> Models;
370        //! vector of model weights
371        vec w;
372        //! cache of model lls
373        vec _lls;
374        //! type of switching policy [1=maximum,2=...]
375        int policy;
376        //! internal statistics
377        enorm<chmat> est;
378public:
379        //! set internal parameters
380        void set_parameters ( Array<EKFCh*> A, int pol0 = 1 ) {
381                Models = A;//TODO: test if evalll is set
382                w.set_length ( A.length() );
383                _lls.set_length ( A.length() );
384                policy = pol0;
385
386                est.set_rv ( RV ( "MM", A ( 0 )->posterior().dimension(), 0 ) );
387                est.set_parameters ( A ( 0 )->posterior().mean(), A ( 0 )->posterior()._R() );
388        }
389        void bayes ( const vec &yt, const vec &cond = empty_vec ) {
390                int n = Models.length();
391                int i;
392                for ( i = 0; i < n; i++ ) {
393                        Models ( i )->bayes ( yt );
394                        _lls ( i ) = Models ( i )->_ll();
395                }
396                double mlls = max ( _lls );
397                w = exp ( _lls - mlls );
398                w /= sum ( w ); //normalization
399                //set statistics
400                switch ( policy ) {
401                case 1: {
402                        int mi = max_index ( w );
403                        const enorm<chmat> &st = Models ( mi )->posterior() ;
404                        est.set_parameters ( st.mean(), st._R() );
405                }
406                break;
407                default:
408                        bdm_error ( "unknown policy" );
409                }
410                // copy result to all models
411                for ( i = 0; i < n; i++ ) {
412                        Models ( i )->set_statistics ( est.mean(), est._R() );
413                }
414        }
415        //! return correctly typed posterior (covariant return)
416        const enorm<chmat>& posterior() const {
417                return est;
418        }
419
420        void from_setting ( const Setting &set );
421
422        // TODO dodelat void to_setting( Setting &set ) const;
423
424};
425
426UIREGISTER ( MultiModel );
427SHAREDPTR ( MultiModel );
428
429//! conversion of outer ARX model (mlnorm) to state space model
430/*!
431The model is constructed as:
432\f[ x_{t+1} = Ax_t + B u_t + R^{1/2} e_t, y_t=Cx_t+Du_t + R^{1/2}w_t, \f]
433For example, for:
434Using Frobenius form, see [].
435
436For easier use in the future, indeces theta_in_A and theta_in_C are set. TODO - explain
437*/
438//template<class sq_T>
439class StateCanonical: public StateSpace<fsqmat> {
440protected:
441        //! remember connection from theta ->A
442        datalink_part th2A;
443        //! remember connection from theta ->C
444        datalink_part th2C;
445        //! remember connection from theta ->D
446        datalink_part th2D;
447        //!cached first row of A
448        vec A1row;
449        //!cached first row of C
450        vec C1row;
451        //!cached first row of D
452        vec D1row;
453
454public:
455        //! set up this object to match given mlnorm
456        void connect_mlnorm ( const mlnorm<fsqmat> &ml );
457
458        //! fast function to update parameters from ml - not checked for compatibility!!
459        void update_from ( const mlnorm<fsqmat> &ml );
460};
461/*!
462State-Space representation of multivariate autoregressive model.
463The original model:
464\f[ y_t = \theta [\ldots y_{t-k}, \ldots u_{t-l}, \ldots z_{t-m}]' + \Sigma^{-1/2} e_t \f]
465where \f$ k,l,m \f$ are maximum delayes of corresponding variables in the regressor.
466
467The transformed state is:
468\f[ x_t = [y_{t} \ldots y_{t-k-1}, u_{t} \ldots u_{t-l-1}, z_{t} \ldots z_{t-m-1}]\f]
469
470The state accumulates all delayed values starting from time \f$ t \f$ .
471
472
473*/
474class StateFromARX: public StateSpace<chmat> {
475protected:
476        //! remember connection from theta ->A
477        datalink_part th2A;
478        //! remember connection from theta ->B
479        datalink_part th2B;
480        //!function adds n diagonal elements from given starting point r,c
481        void diagonal_part ( mat &A, int r, int c, int n ) {
482                for ( int i = 0; i < n; i++ ) {
483                        A ( r, c ) = 1.0;
484                        r++;
485                        c++;
486                }
487        };
488        //! similar to ARX.have_constant
489        bool have_constant;
490public:
491        //! set up this object to match given mlnorm
492        //! Note that state-space and common mpdf use different meaning of \f$ _t \f$ in \f$ u_t \f$.
493        //!While mlnorm typically assumes that \f$ u_t \rightarrow y_t \f$ in state space it is \f$ u_{t-1} \rightarrow y_t \f$
494        //! For consequences in notation of internal variable xt see arx2statespace_notes.lyx.
495        void connect_mlnorm ( const mlnorm<chmat> &ml, RV &xrv, RV &urv );
496
497        //! fast function to update parameters from ml - not checked for compatibility!!
498        void update_from ( const mlnorm<chmat> &ml );
499
500        //! access function
501        bool _have_constant() const {
502                return have_constant;
503        }
504};
505
506/////////// INSTANTIATION
507
508template<class sq_T>
509void 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 ) {
510
511        A = A0;
512        B = B0;
513        C = C0;
514        D = D0;
515        R = R0;
516        Q = Q0;
517        validate();
518}
519
520template<class sq_T>
521void StateSpace<sq_T>::validate() {
522        bdm_assert ( A.cols() == A.rows(), "KalmanFull: A is not square" );
523        bdm_assert ( B.rows() == A.rows(), "KalmanFull: B is not compatible" );
524        bdm_assert ( C.cols() == A.rows(), "KalmanFull: C is not compatible" );
525        bdm_assert ( ( D.rows() == C.rows() ) && ( D.cols() == B.cols() ), "KalmanFull: D is not compatible" );
526        bdm_assert ( ( Q.cols() == A.rows() ) && ( Q.rows() == A.rows() ), "KalmanFull: Q is not compatible" );
527        bdm_assert ( ( R.cols() == C.rows() ) && ( R.rows() == C.rows() ), "KalmanFull: R is not compatible" );
528}
529
530}
531#endif // KF_H
532
Note: See TracBrowser for help on using the browser.