indii/ml/filter/KalmanSmoother.hpp

00001 #ifndef INDII_ML_FILTER_KALMANSMOOTHER_HPP
00002 #define INDII_ML_FILTER_KALMANSMOOTHER_HPP
00003 
00004 #include "TwoFilterSmoother.hpp"
00005 #include "KalmanSmootherModel.hpp"
00006 
00007 namespace indii {
00008   namespace ml {
00009     namespace filter {
00010 
00011 /**
00012  * Kalman two-filter smoother.
00013  *
00014  * @author Lawrence Murray <lawrence@indii.org>
00015  * @version $Rev: 552 $
00016  * @date $Date: 2008-09-04 15:25:50 +0100 (Thu, 04 Sep 2008) $
00017  *
00018  * @param T The type of time.
00019  *
00020  * The Kalman two-filter smoother performs both a forward and
00021  * backwards filtering pass, fusing the estimates from the two passes
00022  * into the smoothed estimate. The forwards filtering pass is
00023  * identical to that of KalmanFilter. The backwards filtering pass
00024  * requires the inverse of the state transition model, and works in an
00025  * analogous fashion to the forwards pass, but with time reversed.
00026  *
00027  * It is suitable for models with linear transition and measurement
00028  * functions, approximating state and noise with
00029  * indii::ml::aux::GaussianPdf distributions.
00030  *
00031  * @bug Buggy, see test results. Consider RauchTungStriebelSmoother
00032  * instead.
00033  * 
00034  * @see indii::ml::filter for general usage guidelines.
00035  * @see LinearModel for more detail on linear filters.
00036  */
00037 template <class T>
00038 class KalmanSmoother : public TwoFilterSmoother<T> {
00039 public:
00040   /**
00041    * Create new Kalman two-filter smoother.
00042    *
00043    * @param model Model to estimate.
00044    * @param tT \f$t_T\f$; starting time.
00045    * @param p_xT \f$p(\mathbf{x}_T)\f$; prior over the state at time
00046    * \f$t_T\f$.
00047    */
00048   KalmanSmoother(KalmanSmootherModel<T>* model,
00049       const T tT, const indii::ml::aux::GaussianPdf& p_xT);
00050 
00051   /**
00052    * Destructor.
00053    */
00054   virtual ~KalmanSmoother();
00055 
00056   virtual void smooth(const T tn, const indii::ml::aux::vector& ytn,
00057       const indii::ml::aux::GaussianPdf& p_xtn_ytn);
00058 
00059   virtual indii::ml::aux::GaussianPdf backwardMeasure();
00060 
00061   virtual indii::ml::aux::GaussianPdf smoothedMeasure();
00062 
00063 private:
00064   /**
00065    * Model to estimate.
00066    */
00067   KalmanSmootherModel<T>* model;
00068 
00069   /**
00070    * Size of the state space.
00071    */
00072   const unsigned int N;
00073 };
00074 
00075     }
00076   }
00077 }
00078 
00079 template <class T>
00080 indii::ml::filter::KalmanSmoother<T>::KalmanSmoother(
00081     KalmanSmootherModel<T>* model, const T tT,
00082     const indii::ml::aux::GaussianPdf& p_xT) :
00083     TwoFilterSmoother<T>(tT, p_xT), model(model), N(p_xT.getDimensions()) {
00084   //
00085 }
00086 
00087 template <class T>
00088 indii::ml::filter::KalmanSmoother<T>::~KalmanSmoother() {
00089   //
00090 }
00091 
00092 template <class T>
00093 void indii::ml::filter::KalmanSmoother<T>::smooth(const T tn,
00094     const indii::ml::aux::vector& ytn,
00095     const indii::ml::aux::GaussianPdf& p_xtn_ytn) {
00096   namespace aux = indii::ml::aux;
00097 
00098   /* pre-condition */
00099   assert (tn < this->tn);
00100 
00101   T delta = this->tn - tn;
00102   this->tn = tn;
00103 
00104   /* backward filter */
00105   aux::GaussianPdf p_xtn_ytnp1_b(model->p_xtnm1_ytn(this->p_xtn_ytn_b,
00106       delta));
00107   this->p_xtn_ytn_b = model->p_xtnm1_ytnm1(p_xtn_ytnp1_b, ytn, delta);
00108 
00109   /* fuse p_xtn_ytn and p_xtn_ytnp1_b */
00110   const aux::symmetric_matrix& P_xtn_ytn = p_xtn_ytn.getCovariance();
00111   const aux::symmetric_matrix& P_xtn_ytnp1_b = p_xtn_ytnp1_b.getCovariance();
00112   aux::matrix PI_xtn_ytn(N,N);
00113   aux::matrix PI_xtn_ytnp1_b(N,N);
00114   aux::matrix X(N,N);
00115 
00116   /* calculate inverses */
00117   noalias(X) = P_xtn_ytn;
00118   aux::inv(X, PI_xtn_ytn);
00119 
00120   noalias(X) = P_xtn_ytnp1_b;
00121   aux::inv(X, PI_xtn_ytnp1_b);
00122 
00123   /* calculate fused covariance */
00124   aux::symmetric_matrix P_xtn_ytT(N);
00125   aux::matrix Y(N,N);
00126   noalias(Y) = PI_xtn_ytn + PI_xtn_ytnp1_b;
00127   /**
00128    * @todo ^^^ Subtract sigma_t^-1, see Jordan 15.7.2 end.
00129    */
00130   aux::inv(Y, X);
00131   noalias(P_xtn_ytT) = X;
00132 
00133   /* calculate fused mean */
00134   const aux::vector& x_xtn_ytn = p_xtn_ytn.getExpectation();
00135   const aux::vector& x_xtn_ytnp1_b = p_xtn_ytnp1_b.getExpectation();
00136   aux::vector x_xtn_ytT(N);
00137 
00138   noalias(x_xtn_ytT) = prod(PI_xtn_ytn, x_xtn_ytn);
00139   noalias(x_xtn_ytT) += prod(PI_xtn_ytnp1_b, x_xtn_ytnp1_b);
00140   x_xtn_ytT = prod(P_xtn_ytT, x_xtn_ytT);
00141 
00142   /* update smoothed state */
00143   this->p_xtn_ytT.setExpectation(x_xtn_ytT);
00144   this->p_xtn_ytT.setCovariance(P_xtn_ytT);
00145 
00146   /* post-condition */
00147   assert (this->tn == tn);
00148 }
00149 
00150 template <class T>
00151 indii::ml::aux::GaussianPdf
00152     indii::ml::filter::KalmanSmoother<T>::smoothedMeasure() {
00153   return model->p_y_x(this->p_xtn_ytT);
00154 }
00155 
00156 template <class T>
00157 indii::ml::aux::GaussianPdf
00158     indii::ml::filter::KalmanSmoother<T>::backwardMeasure() {
00159   return model->p_y_x(this->p_xtn_ytn_b);
00160 }
00161 
00162 #endif

Generated on Wed Dec 17 15:11:57 2008 for dysii Dynamical Systems Library by  doxygen 1.5.3