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

Revision 1154, 20.2 kB (checked in by smidl, 14 years ago)

UKF

  • 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    void to_setting ( Setting &set ) const {
78        UI::save( A, set, "A" );
79        UI::save( B, set, "B" );
80        UI::save( C, set, "C" );
81        UI::save( D, set, "D" );
82        UI::save( Q.to_mat(), set, "Q" );
83        UI::save( R.to_mat(), set, "R" );
84    }
85    //! access function
86    const mat& _A() const {
87        return A;
88    }
89    //! access function
90    const mat& _B() const {
91        return B;
92    }
93    //! access function
94    const mat& _C() const {
95        return C;
96    }
97    //! access function
98    const mat& _D() const {
99        return D;
100    }
101    //! access function
102    const sq_T& _Q() const {
103        return Q;
104    }
105    //! access function
106    const sq_T& _R() const {
107        return R;
108    }
109};
110
111//! Common abstract base for Kalman filters
112template<class sq_T>
113class Kalman: public BM, public StateSpace<sq_T> {
114protected:
115    //! id of output
116    RV yrv;
117    //! Kalman gain
118    mat  _K;
119    //!posterior
120    enorm<sq_T> est;
121    //!marginal on data f(y|y)
122    enorm<sq_T>  fy;
123public:
124    Kalman<sq_T>() : BM(), StateSpace<sq_T>(), yrv(), _K(),  est() {}
125    //! Copy constructor
126    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 ) {}
127    //!set statistics of the posterior
128    void set_statistics ( const vec &mu0, const mat &P0 ) {
129        est.set_parameters ( mu0, P0 );
130    };
131    //!set statistics of the posterior
132    void set_statistics ( const vec &mu0, const sq_T &P0 ) {
133        est.set_parameters ( mu0, P0 );
134    };
135    //! return correctly typed posterior (covariant return)
136    const enorm<sq_T>& posterior() const {
137        return est;
138    }
139   
140    /*! Create object from the following structure
141
142    \code
143    class = 'KalmanFull';
144    prior = configuration of bdm::epdf;          % prior density represented by any offspring of epdf, bdm::epdf::from_setting - it will be converted to gaussian
145    --- inherited fields ---
146    bdm::StateSpace<sq_T>::from_setting
147    bdm::BM::from_setting
148    \endcode
149    */
150    void from_setting ( const Setting &set ) {
151        StateSpace<sq_T>::from_setting ( set );
152        BM::from_setting(set);
153
154        shared_ptr<epdf> pri=UI::build<epdf>(set,"prior",UI::compulsory);
155        //bdm_assert(pri->dimension()==);
156        set_statistics ( pri->mean(), pri->covariance() );
157    }
158    void to_setting ( Setting &set ) const {
159        StateSpace<sq_T>::to_setting ( set );
160        BM::to_setting(set);
161
162        UI::save(est, set, "prior");
163    }
164    //! validate object
165    void validate() {
166        StateSpace<sq_T>::validate();
167        dimy = this->C.rows();
168        dimc = this->B.cols();
169        set_dim ( this->A.rows() );
170
171        bdm_assert ( est.dimension(), "Statistics and model parameters mismatch" );
172    }
173
174};
175/*!
176* \brief Basic Kalman filter with full matrices
177*/
178
179class KalmanFull : public Kalman<fsqmat> {
180public:
181    //! For EKFfull;
182    KalmanFull() : Kalman<fsqmat>() {};
183    //! Here dt = [yt;ut] of appropriate dimensions
184    void bayes ( const vec &yt, const vec &cond = empty_vec );
185
186    virtual KalmanFull* _copy() const {
187        KalmanFull* K = new KalmanFull;
188        K->set_parameters ( A, B, C, D, Q, R );
189        K->set_statistics ( est._mu(), est._R() );
190        return K;
191    }
192};
193UIREGISTER ( KalmanFull );
194
195
196/*! \brief Kalman filter in square root form
197
198Trivial example:
199\include kalman_simple.cpp
200
201Complete constructor:
202*/
203class KalmanCh : public Kalman<chmat> {
204protected:
205    //! @{ \name Internal storage - needs initialize()
206    //! pre array (triangular matrix)
207    mat preA;
208    //! post array (triangular matrix)
209    mat postA;
210    //!@}
211public:
212    //! copy constructor
213    virtual KalmanCh* _copy() const {
214        KalmanCh* K = new KalmanCh;
215        K->set_parameters ( A, B, C, D, Q, R );
216        K->set_statistics ( est._mu(), est._R() );
217        K->validate();
218        return K;
219    }
220    //! set parameters for adapt from Kalman
221    void set_parameters ( const mat &A0, const mat &B0, const mat &C0, const mat &D0, const chmat &Q0, const chmat &R0 );
222    //! initialize internal parametetrs
223    void initialize();
224
225    /*!\brief  Here dt = [yt;ut] of appropriate dimensions
226
227    The following equality hold::\f[
228    \left[\begin{array}{cc}
229    R^{0.5}\\
230    P_{t|t-1}^{0.5}C' & P_{t|t-1}^{0.5}CA'\\
231    & Q^{0.5}\end{array}\right]<\mathrm{orth.oper.}>=\left[\begin{array}{cc}
232    R_{y}^{0.5} & KA'\\
233    & P_{t+1|t}^{0.5}\\
234    \\\end{array}\right]\f]
235
236    Thus this object evaluates only predictors! Not filtering densities.
237    */
238    void bayes ( const vec &yt, const vec &cond = empty_vec );
239
240    /*! Create object from the following structure
241
242    \code
243    class = 'KalmanCh';
244    --- inherited fields ---
245    bdm::Kalman<chmat>::from_setting
246    \endcode
247    */
248    void from_setting ( const Setting &set ) {
249        Kalman<chmat>::from_setting ( set );
250    }
251
252    void validate() {
253        Kalman<chmat>::validate();
254        initialize();
255    }
256};
257UIREGISTER ( KalmanCh );
258
259/*!
260\brief Extended Kalman Filter in full matrices
261
262An approximation of the exact Bayesian filter with Gaussian noices and non-linear evolutions of their mean.
263*/
264class EKFfull : public KalmanFull {
265protected:
266    //! Internal Model f(x,u)
267    shared_ptr<diffbifn> pfxu;
268
269    //! Observation Model h(x,u)
270    shared_ptr<diffbifn> phxu;
271
272public:
273    //! Default constructor
274    EKFfull ();
275
276    //! Set nonlinear functions for mean values and covariance matrices.
277    void set_parameters ( const shared_ptr<diffbifn> &pfxu, const shared_ptr<diffbifn> &phxu, const mat Q0, const mat R0 );
278
279    //! Here dt = [yt;ut] of appropriate dimensions
280    void bayes ( const vec &yt, const vec &cond = empty_vec );
281    //! set estimates
282    void set_statistics ( const vec &mu0, const mat &P0 ) {
283        est.set_parameters ( mu0, P0 );
284    };
285    //! access function
286    const mat _R() {
287        return est._R().to_mat();
288    }
289
290   /*! Create object from the following structure
291
292    \code
293    class = 'EKFfull';
294 
295    OM = configuration of bdm::diffbifn;    % any offspring of diffbifn, bdm::diffbifn::from_setting
296    IM = configuration of bdm::diffbifn;    % any offspring of diffbifn, bdm::diffbifn::from_setting
297    dQ = [...];                             % vector containing diagonal of Q
298    dR = [...];                             % vector containing diagonal of R
299    --- optional fields ---
300    mu0 = [...];                            % vector of statistics mu0
301    dP0 = [...];                            % vector containing diagonal of P0
302    -- or --
303    P0 = [...];                             % full matrix P0
304    --- inherited fields ---
305    bdm::BM::from_setting
306    \endcode
307    If the optional fields are not given, they will be filled as follows:
308    \code
309    mu0 = [0,0,0,....];                     % empty statistics
310    P0 = eye( dim );             
311    \endcode
312    */
313    void from_setting ( const Setting &set ) {
314        BM::from_setting ( set );
315        shared_ptr<diffbifn> IM = UI::build<diffbifn> ( set, "IM", UI::compulsory );
316        shared_ptr<diffbifn> OM = UI::build<diffbifn> ( set, "OM", UI::compulsory );
317
318        //statistics
319        int dim = IM->dimension();
320        vec mu0;
321        if ( !UI::get ( mu0, set, "mu0" ) )
322            mu0 = zeros ( dim );
323
324        mat P0;
325        vec dP0;
326        if ( UI::get ( dP0, set, "dP0" ) )
327            P0 = diag ( dP0 );
328        else if ( !UI::get ( P0, set, "P0" ) )
329            P0 = eye ( dim );
330
331        set_statistics ( mu0, P0 );
332
333        //parameters
334        vec dQ, dR;
335        UI::get ( dQ, set, "dQ", UI::compulsory );
336        UI::get ( dR, set, "dR", UI::compulsory );
337        set_parameters ( IM, OM, diag ( dQ ), diag ( dR ) );
338
339//                      pfxu = UI::build<diffbifn>(set, "IM", UI::compulsory);
340//                      phxu = UI::build<diffbifn>(set, "OM", UI::compulsory);
341//
342//                      mat R0;
343//                      UI::get(R0, set, "R",UI::compulsory);
344//                      mat Q0;
345//                      UI::get(Q0, set, "Q",UI::compulsory);
346//
347//
348//                      mat P0; vec mu0;
349//                      UI::get(mu0, set, "mu0", UI::optional);
350//                      UI::get(P0, set,  "P0", UI::optional);
351//                      set_statistics(mu0,P0);
352//                      // Initial values
353//                      UI::get (yrv, set, "yrv", UI::optional);
354//                      UI::get (urv, set, "urv", UI::optional);
355//                      set_drv(concat(yrv,urv));
356//
357//                      // setup StateSpace
358//                      pfxu->dfdu_cond(mu0, zeros(pfxu->_dimu()), A,true);
359//                      phxu->dfdu_cond(mu0, zeros(pfxu->_dimu()), C,true);
360//
361    }
362
363    void validate() {
364        KalmanFull::validate();
365
366        // check stats and IM and OM
367    }
368};
369UIREGISTER ( EKFfull );
370
371
372/*!
373\brief Extended Kalman Filter in Square root
374
375An approximation of the exact Bayesian filter with Gaussian noices and non-linear evolutions of their mean.
376*/
377
378class EKFCh : public KalmanCh {
379protected:
380    //! Internal Model f(x,u)
381    shared_ptr<diffbifn> pfxu;
382
383    //! Observation Model h(x,u)
384    shared_ptr<diffbifn> phxu;
385public:
386    //! copy constructor duplicated - calls different set_parameters
387    EKFCh* _copy() const {
388        return new EKFCh(*this);
389    }
390    //! Set nonlinear functions for mean values and covariance matrices.
391    void set_parameters ( const shared_ptr<diffbifn> &pfxu, const shared_ptr<diffbifn> &phxu, const chmat Q0, const chmat R0 );
392
393    //! Here dt = [yt;ut] of appropriate dimensions
394    void bayes ( const vec &yt, const vec &cond = empty_vec );
395   
396    /*! Create object from the following structure
397
398    \code
399    class = 'EKFCh';
400    OM = configuration of bdm::diffbifn;    % any offspring of diffbifn, bdm::diffbifn::from_setting
401    IM = configuration of bdm::diffbifn;    % any offspring of diffbifn, bdm::diffbifn::from_setting
402    dQ = [...];                             % vector containing diagonal of Q
403    dR = [...];                             % vector containing diagonal of R
404    --- optional fields ---
405    mu0 = [...];                            % vector of statistics mu0
406    dP0 = [...];                            % vector containing diagonal of P0
407    -- or --
408    P0 = [...];                             % full matrix P0
409    --- inherited fields ---
410    bdm::BM::from_setting
411    \endcode
412    If the optional fields are not given, they will be filled as follows:
413    \code
414    mu0 = [0,0,0,....];                     % empty statistics
415    P0 = eye( dim );             
416    \endcode
417    */
418    void from_setting ( const Setting &set );
419
420    void validate() {};
421    // TODO dodelat void to_setting( Setting &set ) const;
422
423};
424
425UIREGISTER ( EKFCh );
426SHAREDPTR ( EKFCh );
427
428class UKFCh : public EKFCh{
429        public:
430                double kappa;
431               
432        void bayes ( const vec &yt, const vec &cond = empty_vec ){
433               
434                vec &_mu = est._mu();
435                chmat &_P = est._R();
436                chmat &_Ry = fy._R();
437                vec &_yp = fy._mu();
438               
439                int dim = dimension();
440                int dim2 = 1+dim+dim;
441               
442                double npk =dim+kappa;//n+kappa
443                mat Xi(dim,dim2);
444                vec w=ones(dim2)* 0.5/npk;
445                w(0) = (npk-dim)/npk; // mean is special
446               
447                //step 1.
448                int i;
449                Xi.set_col(0,_mu); 
450               
451                for ( i=0;i<dim; i++){
452                        vec tmp=sqrt(npk)*_P._Ch().get_col(i);
453                        Xi.set_col(i+1, _mu+tmp);
454                        Xi.set_col(i+1+dim, _mu-tmp);
455                }
456               
457                // step 2.
458                mat Xik(dim,dim2);
459                for (i=0; i<dim2; i++){
460                        Xik.set_col(i, pfxu->eval(Xi.get_col(i), cond));
461                }
462               
463                //step 3
464                vec xp=zeros(dim);
465                for (i=0;i<dim2;i++){
466                        xp += w(i) * Xik.get_col(i);
467                }
468       
469                //step 4
470                mat Xpred_dif(dim2,dim);
471                for (i=0;i<dim2;i++){
472                        Xpred_dif.set_row(i, sqrt(w(i)) * (Xik.get_col(i) - xp));
473                }               
474               
475                // NEW Sigma points
476                mat tmp;
477                qr(concat_vertical(Xpred_dif,Q._Ch()), tmp);
478                mat Ppred=tmp.get_rows(0,dim-1);
479                // New Xi(k+1)
480                Xik.set_col(0,xp);
481                for ( i=0;i<dim; i++){
482                        vec tmp=sqrt(npk)*Ppred.get_col(i);
483                        Xik.set_col(i+1, _mu+tmp);
484                        Xik.set_col(i+1+dim, _mu-tmp);
485                }
486                for (i=0;i<dim2;i++){
487                        Xpred_dif.set_row(i, sqrt(w(i)) * (Xik.get_col(i) - xp));
488                }               
489               
490               
491               
492                //step 5
493                mat Yi(dimy,dim2);
494                for (i=0; i<dim2; i++){
495                        Yi.set_col(i, phxu->eval(Xik.get_col(i), cond));
496                }
497                //step 6
498                _yp.clear();
499                for (i=0;i<dim2;i++){
500                        _yp += w(i) * Yi.get_col(i);
501                }
502                //step 7
503                mat Ypred_dif(dim2,dimy);
504               
505                for (i=0; i<dim2; i++){
506                        Ypred_dif.set_row(i, sqrt(w(i))*(Yi.get_col(i)-_yp));
507                }
508                if (!qr(concat_vertical(Ypred_dif,R._Ch()) ,tmp)){ bdm_warning("QR failed");}
509                _Ry._Ch() = tmp.get_rows(0,dimy-1);
510               
511                // step 8
512                mat Pxy=Xpred_dif.T()*Ypred_dif;
513                mat iRy=inv(_Ry._Ch());
514               
515                //filtering????? -- correction
516                mat K=Pxy*iRy*iRy.T();
517                mat K2=Pxy*inv(_Ry.to_mat());
518               
519                /////////////// new filtering density
520                _mu = xp + K*(yt - _yp);
521                // fill the space in Ppred;
522                mat Rpred =concat_vertical(Xpred_dif - Ypred_dif*K.T(), _Ry._Ch()*K.T());
523               
524                if(!qr(Rpred,tmp)) {bdm_warning("QR failed");}
525                _P._Ch()=tmp.get_rows(0,dim-1);
526        }
527        void from_setting(const Setting &set){
528                EKFCh::from_setting(set);
529                kappa = 1.0;
530                UI::get(kappa,set,"kappa");
531        }
532};
533UIREGISTER(UKFCh);
534
535//////// INstance
536
537/*! \brief (Switching) Multiple Model
538The model runs several models in parallel and evaluates thier weights (fittness).
539
540The statistics of the resulting density are merged using (geometric?) combination.
541
542The next step is performed with the new statistics for all models.
543*/
544class MultiModel: public BM {
545protected:
546    //! List of models between which we switch
547    Array<EKFCh*> Models;
548    //! vector of model weights
549    vec w;
550    //! cache of model lls
551    vec _lls;
552    //! type of switching policy [1=maximum,2=...]
553    int policy;
554    //! internal statistics
555    enorm<chmat> est;
556public:
557    //! set internal parameters
558    void set_parameters ( Array<EKFCh*> A, int pol0 = 1 ) {
559        Models = A;//TODO: test if evalll is set
560        w.set_length ( A.length() );
561        _lls.set_length ( A.length() );
562        policy = pol0;
563
564        est.set_rv ( RV ( "MM", A ( 0 )->posterior().dimension(), 0 ) );
565        est.set_parameters ( A ( 0 )->posterior().mean(), A ( 0 )->posterior()._R() );
566    }
567    void bayes ( const vec &yt, const vec &cond = empty_vec ) {
568        int n = Models.length();
569        int i;
570        for ( i = 0; i < n; i++ ) {
571            Models ( i )->bayes ( yt );
572            _lls ( i ) = Models ( i )->_ll();
573        }
574        double mlls = max ( _lls );
575        w = exp ( _lls - mlls );
576        w /= sum ( w ); //normalization
577        //set statistics
578        switch ( policy ) {
579        case 1: {
580            int mi = max_index ( w );
581            const enorm<chmat> &st = Models ( mi )->posterior() ;
582            est.set_parameters ( st.mean(), st._R() );
583        }
584        break;
585        default:
586            bdm_error ( "unknown policy" );
587        }
588        // copy result to all models
589        for ( i = 0; i < n; i++ ) {
590            Models ( i )->set_statistics ( est.mean(), est._R() );
591        }
592    }
593    //! return correctly typed posterior (covariant return)
594    const enorm<chmat>& posterior() const {
595        return est;
596    }
597
598    void from_setting ( const Setting &set );
599
600};
601UIREGISTER ( MultiModel );
602SHAREDPTR ( MultiModel );
603
604//! conversion of outer ARX model (mlnorm) to state space model
605/*!
606The model is constructed as:
607\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]
608For example, for:
609Using Frobenius form, see [].
610
611For easier use in the future, indices theta_in_A and theta_in_C are set. TODO - explain
612*/
613//template<class sq_T>
614class StateCanonical: public StateSpace<fsqmat> {
615protected:
616    //! remember connection from theta ->A
617    datalink_part th2A;
618    //! remember connection from theta ->C
619    datalink_part th2C;
620    //! remember connection from theta ->D
621    datalink_part th2D;
622    //!cached first row of A
623    vec A1row;
624    //!cached first row of C
625    vec C1row;
626    //!cached first row of D
627    vec D1row;
628
629public:
630    //! set up this object to match given mlnorm
631    void connect_mlnorm ( const mlnorm<fsqmat> &ml );
632
633    //! fast function to update parameters from ml - not checked for compatibility!!
634    void update_from ( const mlnorm<fsqmat> &ml );
635};
636/*!
637State-Space representation of multivariate autoregressive model.
638The original model:
639\f[ y_t =     heta [\ldots y_{t-k}, \ldots u_{t-l}, \ldots z_{t-m}]' + \Sigma^{-1/2} e_t \f]
640where \f$ k,l,m \f$ are maximum delayes of corresponding variables in the regressor.
641
642The transformed state is:
643\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]
644
645The state accumulates all delayed values starting from time \f$ t \f$ .
646
647
648*/
649class StateFromARX: public StateSpace<chmat> {
650protected:
651    //! remember connection from theta ->A
652    datalink_part th2A;
653    //! remember connection from theta ->B
654    datalink_part th2B;
655    //!function adds n diagonal elements from given starting point r,c
656    void diagonal_part ( mat &A, int r, int c, int n ) {
657        for ( int i = 0; i < n; i++ ) {
658            A ( r, c ) = 1.0;
659            r++;
660            c++;
661        }
662    };
663    //! similar to ARX.have_constant
664    bool have_constant;
665public:
666    //! set up this object to match given mlnorm
667    //! Note that state-space and common mpdf use different meaning of \f$ _t \f$ in \f$ u_t \f$.
668    //!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$
669    //! For consequences in notation of internal variable xt see arx2statespace_notes.lyx.
670    void connect_mlnorm ( const mlnorm<chmat> &ml, RV &xrv, RV &urv );
671
672    //! fast function to update parameters from ml - not checked for compatibility!!
673    void update_from ( const mlnorm<chmat> &ml );
674
675    //! access function
676    bool _have_constant() const {
677        return have_constant;
678    }
679};
680
681/////////// INSTANTIATION
682
683template<class sq_T>
684void 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 ) {
685
686    A = A0;
687    B = B0;
688    C = C0;
689    D = D0;
690    R = R0;
691    Q = Q0;
692    validate();
693}
694
695template<class sq_T>
696void StateSpace<sq_T>::validate() {
697    bdm_assert ( A.cols() == A.rows(), "KalmanFull: A is not square" );
698    bdm_assert ( B.rows() == A.rows(), "KalmanFull: B is not compatible" );
699    bdm_assert ( C.cols() == A.rows(), "KalmanFull: C is not compatible" );
700    bdm_assert ( ( D.rows() == C.rows() ) && ( D.cols() == B.cols() ), "KalmanFull: D is not compatible" );
701    bdm_assert ( ( Q.cols() == A.rows() ) && ( Q.rows() == A.rows() ), "KalmanFull: Q is not compatible" );
702    bdm_assert ( ( R.cols() == C.rows() ) && ( R.rows() == C.rows() ), "KalmanFull: R is not compatible" );
703}
704
705}
706#endif // KF_H
707
Note: See TracBrowser for help on using the browser.