root/library/bdm/estim/kalman.cpp @ 527

Revision 527, 8.0 kB (checked in by vbarta, 15 years ago)

using shared_ptr in UI (optionally so far; loading & saving Array<T *> still works but should be phased out); testsuite run leaks down from 8822 to 480 bytes

  • Property svn:eol-style set to native
Line 
1
2#include "kalman.h"
3
4namespace bdm {
5
6using std::endl;
7
8KalmanFull::KalmanFull ( mat A0, mat B0, mat C0, mat D0, mat Q0, mat R0, mat P0, vec mu0 ) {
9        dimx = A0.rows();
10        dimu = B0.cols();
11        dimy = C0.rows();
12
13        it_assert_debug ( A0.cols() == dimx, "KalmanFull: A is not square" );
14        it_assert_debug ( B0.rows() == dimx, "KalmanFull: B is not compatible" );
15        it_assert_debug ( C0.cols() == dimx, "KalmanFull: C is not square" );
16        it_assert_debug ( ( D0.rows() == dimy ) || ( D0.cols() == dimu ),       "KalmanFull: D is not compatible" );
17        it_assert_debug ( ( Q0.cols() == dimx ) || ( Q0.rows() == dimx ), "KalmanFull: Q is not compatible" );
18        it_assert_debug ( ( R0.cols() == dimy ) || ( R0.rows() == dimy ), "KalmanFull: R is not compatible" );
19
20        A = A0;
21        B = B0;
22        C = C0;
23        D = D0;
24        R = R0;
25        Q = Q0;
26        mu = mu0;
27        P = P0;
28
29        ll = 0.0;
30        evalll = true;
31}
32
33void KalmanFull::bayes ( const vec &dt ) {
34        it_assert_debug ( dt.length() == ( dimy + dimu ), "KalmanFull::bayes wrong size of dt" );
35
36        vec u = dt.get ( dimy, dimy + dimu - 1 );
37        vec y = dt.get ( 0, dimy - 1 );
38        //Time update
39        mu = A * mu + B * u;
40        P  = A * P * A.transpose() + Q;
41
42        //Data update
43        _Ry = C * P * C.transpose() + R;
44        _iRy = inv ( _Ry );
45        _K = P * C.transpose() * _iRy;
46        P -= _K * C * P; // P = P -KCP;
47        mu += _K * ( y - C * mu - D * u );
48
49        if ( evalll ) {
50                //from enorm
51                vec x = y - C * mu - D * u;
52                ll = -0.5 * ( R.cols() * 1.83787706640935 + log ( det ( _Ry ) ) + x * ( _iRy * x ) );
53        }
54};
55
56std::ostream &operator<< ( std::ostream &os, const KalmanFull &kf ) {
57        os << "mu:" << kf.mu << endl << "P:" << kf.P << endl;
58        return os;
59}
60
61
62
63/////////////////////////////// EKFS
64EKFfull::EKFfull ( ) : BM (), E() {};
65
66void EKFfull::set_parameters ( const shared_ptr<diffbifn> &pfxu0, const shared_ptr<diffbifn> &phxu0, const mat Q0, const mat R0 ) {
67        pfxu = pfxu0;
68        phxu = phxu0;
69
70        dimx = pfxu0->_dimx();
71        dimy = phxu0->dimension();
72        dimu = pfxu0->_dimu();
73        E.epdf::set_parameters ( dimx );
74
75        A.set_size ( dimx, dimx );
76        C.set_size ( dimy, dimx );
77        //initialize matrices A C, later, these will be only updated!
78        pfxu->dfdx_cond ( mu, zeros ( dimu ), A, true );
79        B.clear();
80        phxu->dfdx_cond ( mu, zeros ( dimu ), C, true );
81        D.clear();
82
83        R = R0;
84        Q = Q0;
85}
86
87void EKFfull::bayes ( const vec &dt ) {
88        it_assert_debug ( dt.length() == ( dimy + dimu ), "KalmanFull::bayes wrong size of dt" );
89
90        vec u = dt.get ( dimy, dimy + dimu - 1 );
91        vec y = dt.get ( 0, dimy - 1 );
92
93        pfxu->dfdx_cond ( mu, zeros ( dimu ), A, true );
94        phxu->dfdx_cond ( mu, zeros ( dimu ), C, true );
95
96        //Time update
97        mu = pfxu->eval ( mu, u );// A*mu + B*u;
98        P  = A * P * A.transpose() + Q;
99
100        //Data update
101        _Ry = C * P * C.transpose() + R;
102        _iRy = inv ( _Ry );
103        _K = P * C.transpose() * _iRy;
104        P -= _K * C * P; // P = P -KCP;
105        vec yp = phxu->eval ( mu, u );
106        mu += _K * ( y - yp );
107
108        E.set_mu ( mu );
109
110        if ( BM::evalll ) {
111                //from enorm
112                vec x = y - yp;
113                BM::ll = -0.5 * ( R.cols() * 1.83787706640935 + log ( det ( _Ry ) ) + x * ( _iRy * x ) );
114        }
115};
116
117
118
119void KalmanCh::set_parameters ( const mat &A0, const mat &B0, const mat &C0, const mat &D0, const chmat &Q0, const chmat &R0 ) {
120
121        ( ( Kalman<chmat>* ) this )->set_parameters ( A0, B0, C0, D0, Q0, R0 );
122        // Cholesky special!
123        preA = zeros ( dimy + dimx + dimx, dimy + dimx );
124//      preA.clear();
125        preA.set_submatrix ( 0, 0, R._Ch() );
126        preA.set_submatrix ( dimy + dimx, dimy, Q._Ch() );
127}
128
129
130void KalmanCh::bayes ( const vec &dt ) {
131
132        vec u = dt.get ( dimy, dimy + dimu - 1 );
133        vec y = dt.get ( 0, dimy - 1 );
134        vec pom ( dimy );
135
136        //TODO get rid of Q in qr()!
137//      mat Q;
138
139        //R and Q are already set in set_parameters()
140        preA.set_submatrix ( dimy, 0, ( _P._Ch() ) *C.T() );
141        //Fixme can be more efficient if .T() is not used
142        preA.set_submatrix ( dimy, dimy, ( _P._Ch() ) *A.T() );
143
144//      if ( !qr ( preA,Q,postA ) ) it_warning ( "QR in kalman unstable!" );
145        if ( !qr ( preA, postA ) ) {
146                it_warning ( "QR in kalman unstable!" );
147        }
148
149        ( _Ry._Ch() ) = postA ( 0, dimy - 1, 0, dimy - 1 );
150        _K = inv ( A ) * ( postA ( 0, dimy - 1 , dimy, dimy + dimx - 1 ) ).T();
151        ( _P._Ch() ) = postA ( dimy, dimy + dimx - 1, dimy, dimy + dimx - 1 );
152
153        _mu = A * ( _mu ) + B * u;
154        _yp = C * _mu - D * u;
155
156        backward_substitution ( _Ry._Ch(), ( y - _yp ), pom );
157        _mu += ( _K ) * pom;
158
159        /*              cout << "P:" <<_P.to_mat() <<endl;
160                        cout << "Ry:" <<_Ry.to_mat() <<endl;
161                        cout << "_K:" <<_K <<endl;*/
162
163        if ( evalll == true ) { //likelihood of observation y
164                ll = fy.evallog ( y );
165        }
166}
167
168
169
170void EKFCh::set_parameters ( const shared_ptr<diffbifn> &pfxu0, const shared_ptr<diffbifn> &phxu0, const chmat Q0, const chmat R0 ) {
171        pfxu = pfxu0;
172        phxu = phxu0;
173
174        dimx = pfxu0->dimension();
175        dimy = phxu0->dimension();
176        dimu = pfxu0->_dimu();
177        // if mu is not set, set it to zeros, just for constant terms of A and C
178        if ( _mu.length() != dimx ) _mu = zeros ( dimx );
179        A = zeros ( dimx, dimx );
180        C = zeros ( dimy, dimx );
181        preA = zeros ( dimy + dimx + dimx, dimy + dimx );
182
183        //initialize matrices A C, later, these will be only updated!
184        pfxu->dfdx_cond ( _mu, zeros ( dimu ), A, true );
185//      pfxu->dfdu_cond ( *_mu,zeros ( dimu ),B,true );
186        B.clear();
187        phxu->dfdx_cond ( _mu, zeros ( dimu ), C, true );
188//      phxu->dfdu_cond ( *_mu,zeros ( dimu ),D,true );
189        D.clear();
190
191        R = R0;
192        Q = Q0;
193
194        // Cholesky special!
195        preA.clear();
196        preA.set_submatrix ( 0, 0, R._Ch() );
197        preA.set_submatrix ( dimy + dimx, dimy, Q._Ch() );
198}
199
200
201void EKFCh::bayes ( const vec &dt ) {
202
203        vec pom ( dimy );
204        vec u = dt.get ( dimy, dimy + dimu - 1 );
205        vec y = dt.get ( 0, dimy - 1 );
206
207        pfxu->dfdx_cond ( _mu, u, A, false ); //update A by a derivative of fx
208        phxu->dfdx_cond ( _mu, u, C, false ); //update A by a derivative of fx
209
210        //R and Q are already set in set_parameters()
211        preA.set_submatrix ( dimy, 0, ( _P._Ch() ) *C.T() );
212        //Fixme can be more efficient if .T() is not used
213        preA.set_submatrix ( dimy, dimy, ( _P._Ch() ) *A.T() );
214
215//      mat Sttm = _P->to_mat();
216//      cout << preA <<endl;
217//      cout << "_mu:" << _mu <<endl;
218
219//      if ( !qr ( preA,Q,postA ) ) it_warning ( "QR in kalman unstable!" );
220        if ( !qr ( preA, postA ) ) {
221                it_warning ( "QR in kalman unstable!" );
222        }
223
224
225        ( _Ry._Ch() ) = postA ( 0, dimy - 1, 0, dimy - 1 );
226        _K = inv ( A ) * ( postA ( 0, dimy - 1 , dimy, dimy + dimx - 1 ) ).T();
227        ( _P._Ch() ) = postA ( dimy, dimy + dimx - 1, dimy, dimy + dimx - 1 );
228
229//      mat iRY = inv(_Ry->to_mat());
230//      mat Stt = Sttm - Sttm * C.T() * iRY * C * Sttm;
231//      mat _K2 = Stt*C.T()*inv(R.to_mat());
232
233        // prediction
234        _mu = pfxu->eval ( _mu , u );
235        _yp = phxu->eval ( _mu, u );
236
237        /*      vec mu2 = *_mu + ( _K2 ) * ( y-*_yp );*/
238
239        //correction //= initial value is already prediction!
240        backward_substitution ( _Ry._Ch(), ( y - _yp ), pom );
241        _mu += ( _K ) * pom ;
242
243        /*      _K = (_P->to_mat())*C.transpose() * ( _iRy->to_mat() );
244                *_mu = pfxu->eval ( *_mu ,u ) + ( _K )* ( y-*_yp );*/
245
246//              cout << "P:" <<_P.to_mat() <<endl;
247//              cout << "Ry:" <<_Ry.to_mat() <<endl;
248//      cout << "_mu:" <<_mu <<endl;
249//      cout << "dt:" <<dt <<endl;
250
251        if ( evalll == true ) { //likelihood of observation y
252                ll = fy.evallog ( y );
253        }
254}
255
256void EKFCh::from_setting ( const Setting &set ) {
257        shared_ptr<diffbifn> IM = UI::build<diffbifn> ( set, "IM", UI::compulsory );
258        shared_ptr<diffbifn> OM = UI::build<diffbifn> ( set, "OM", UI::compulsory );
259
260        //statistics
261        int dim = IM->dimension();
262        vec mu0;
263        if ( !UI::get ( mu0, set, "mu0" ) )
264                mu0 = zeros ( dim );
265
266        mat P0;
267        vec dP0;
268        if ( UI::get ( dP0, set, "dP0" ) )
269                P0 = diag ( dP0 );
270        else if ( !UI::get ( P0, set, "P0" ) )
271                P0 = eye ( dim );
272
273        set_statistics ( mu0, P0 );
274
275        //parameters
276        vec dQ, dR;
277        UI::get ( dQ, set, "dQ", UI::compulsory );
278        UI::get ( dR, set, "dR", UI::compulsory );
279        set_parameters ( IM, OM, diag ( dQ ), diag ( dR ) );
280
281        //connect
282        shared_ptr<RV> drv = UI::build<RV> ( set, "drv", UI::compulsory );
283        set_drv ( *drv );
284        shared_ptr<RV> rv = UI::build<RV> ( set, "rv", UI::compulsory );
285        set_rv ( *rv );
286
287        string options;
288        if ( UI::get ( options, set, "options" ) )
289                set_options ( options );
290}
291
292void MultiModel::from_setting ( const Setting &set ) {
293        Array<EKFCh*> A;
294        UI::get ( A, set, "models", UI::compulsory );
295
296        set_parameters ( A );
297        set_drv ( A ( 0 )->_drv() );
298        //set_rv(A(0)->_rv());
299
300        string options;
301        if ( set.lookupValue ( "options", options ) )
302                set_options ( options );
303}
304
305}
Note: See TracBrowser for help on using the browser.