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

Revision 583, 9.0 kB (checked in by smidl, 15 years ago)

redesign of Kalman to use BM, new object StateSpace? created

  • 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
22namespace bdm
23{
24
25/*!
26 * \brief Basic elements of linear state-space model
27
28Parameter evolution model:\f[ x_t = A x_{t-1} + B u_t + Q^{1/2} e_t \f]
29Observation model: \f[ y_t = C x_{t-1} + C u_t + Q^{1/2} w_t. \f]
30Where $e_t$ and $w_t$ are independent vectors Normal(0,1)-distributed disturbances.
31 */
32template<class sq_T>
33class 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
83template<class sq_T>
84class 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
129class 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
139
140/*! \brief Kalman filter in square root form
141
142Trivial example:
143\include kalman_simple.cpp
144
145Complete constructor:
146*/
147class 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                }
188};
189
190/*!
191\brief Extended Kalman Filter in full matrices
192
193An approximation of the exact Bayesian filter with Gaussian noices and non-linear evolutions of their mean.
194*/
195class 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
224
225An approximation of the exact Bayesian filter with Gaussian noices and non-linear evolutions of their mean.
226*/
227
228class 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
256UIREGISTER (EKFCh);
257SHAREDPTR (EKFCh);
258
259
260//////// INstance
261
262/*! \brief (Switching) Multiple Model
263The model runs several models in parallel and evaluates thier weights (fittness).
264
265The statistics of the resulting density are merged using (geometric?) combination.
266
267The next step is performed with the new statistics for all models.
268*/
269class 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
329UIREGISTER (MultiModel);
330SHAREDPTR (MultiModel);
331
332/////////// INSTANTIATION
333
334template<class sq_T>
335void 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{
337        dimx = A0.rows();
338        dimu = B0.cols();
339        dimy = C0.rows();
340
341        A = A0;
342        B = B0;
343        C = C0;
344        D = D0;
345        R = R0;
346        Q = Q0;
347        validate();
348}
349
350template<class sq_T>
351void 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");
358}
359
360}
361#endif // KF_H
362
Note: See TracBrowser for help on using the browser.