00001 #ifndef INDII_ML_ESTIMATOR_UNSCENTEDKALMANFILTER_HPP
00002 #define INDII_ML_ESTIMATOR_UNSCENTEDKALMANFILTER_HPP
00003
00004 #include "../aux/vector.hpp"
00005 #include "../aux/matrix.hpp"
00006 #include "../aux/GaussianPdf.hpp"
00007
00008 #include "Filter.hpp"
00009 #include "UnscentedTransformation.hpp"
00010
00011 namespace indii {
00012 namespace ml {
00013 namespace filter {
00014
00015 template <class T> class UnscentedKalmanFilterModel;
00016 template <class T> class UnscentedKalmanFilterTransitionAdaptor;
00017 template <class T> class UnscentedKalmanFilterMeasurementAdaptor;
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 template<class T = unsigned int>
00036 class UnscentedKalmanFilter : public Filter<T> {
00037
00038 friend class UnscentedKalmanFilterTransitionAdaptor<T>;
00039 friend class UnscentedKalmanFilterMeasurementAdaptor<T>;
00040
00041 public:
00042
00043
00044
00045
00046
00047
00048
00049 UnscentedKalmanFilter(UnscentedKalmanFilterModel<T>* model,
00050 const indii::ml::aux::GaussianPdf& p_x0);
00051
00052
00053
00054
00055 virtual ~UnscentedKalmanFilter();
00056
00057
00058
00059
00060
00061 UnscentedTransformation<T>* getTransitionTransformation();
00062
00063
00064
00065
00066
00067 UnscentedTransformation<T>* getMeasurementTransformation();
00068
00069 virtual void filter(const T tnp1, const indii::ml::aux::vector& ytnp1);
00070
00071 virtual indii::ml::aux::GaussianPdf measure();
00072
00073 protected:
00074
00075
00076
00077 const unsigned int N;
00078
00079
00080
00081
00082 const unsigned int W;
00083
00084
00085
00086
00087 const unsigned int V;
00088
00089
00090
00091
00092
00093 indii::ml::aux::GaussianPdf p_Xtn_ytn;
00094
00095
00096
00097
00098 UnscentedKalmanFilterModel<T>* model;
00099
00100
00101
00102
00103 UnscentedTransformationModel<T>* transitionModel;
00104
00105
00106
00107
00108 UnscentedTransformationModel<T>* measurementModel;
00109
00110
00111
00112
00113 UnscentedTransformation<T>* transitionTransform;
00114
00115
00116
00117
00118 UnscentedTransformation<T>* measurementTransform;
00119
00120 };
00121
00122 }
00123 }
00124 }
00125
00126 #include "UnscentedKalmanFilterTransitionAdaptor.hpp"
00127 #include "UnscentedKalmanFilterMeasurementAdaptor.hpp"
00128 #include "UnscentedKalmanFilterModel.hpp"
00129
00130 #include "boost/numeric/bindings/traits/ublas_matrix.hpp"
00131 #include "boost/numeric/bindings/traits/ublas_vector.hpp"
00132 #include "boost/numeric/bindings/traits/ublas_symmetric.hpp"
00133 #include "boost/numeric/bindings/lapack/lapack.hpp"
00134
00135 template <class T>
00136 indii::ml::filter::UnscentedKalmanFilter<T>::UnscentedKalmanFilter(
00137 indii::ml::filter::UnscentedKalmanFilterModel<T>* model,
00138 const indii::ml::aux::GaussianPdf& p_x0) :
00139 Filter<T>(p_x0),
00140 N(model->getStateSize()),
00141 W(model->getSystemNoise().getDimensions()),
00142 V(model->getMeasurementNoise().getDimensions()),
00143 p_Xtn_ytn(N+W+V),
00144 model(model) {
00145 namespace aux = indii::ml::aux;
00146 namespace ublas = boost::numeric::ublas;
00147
00148
00149 assert (p_x0.getDimensions() == model->getStateSize());
00150
00151
00152 transitionModel = new UnscentedKalmanFilterTransitionAdaptor<T>(model);
00153 transitionTransform = new UnscentedTransformation<T>(*transitionModel);
00154 measurementModel = new UnscentedKalmanFilterMeasurementAdaptor<T>(model);
00155 measurementTransform = new UnscentedTransformation<T>(*measurementModel);
00156
00157
00158 ublas::range xRange(0,N);
00159 ublas::range wRange(N,N+W);
00160 ublas::range vRange(N+W,N+W+V);
00161
00162
00163 aux::vector mu(N+W+V);
00164 aux::symmetric_matrix sigma(N+W+V);
00165 aux::GaussianPdf& w = model->getSystemNoise();
00166 aux::GaussianPdf& v = model->getMeasurementNoise();
00167
00168 noalias(project(mu, xRange)) = p_x0.getExpectation();
00169 noalias(project(mu, wRange)) = w.getExpectation();
00170 noalias(project(mu, vRange)) = v.getExpectation();
00171
00172 noalias(project(sigma, xRange, xRange)) = p_x0.getCovariance();
00173 noalias(project(sigma, wRange, xRange)) = aux::zero_matrix(W, N);
00174 noalias(project(sigma, wRange, wRange)) = w.getCovariance();
00175 noalias(project(sigma, vRange, xRange)) = aux::zero_matrix(V, N);
00176 noalias(project(sigma, vRange, wRange)) = aux::zero_matrix(V, W);
00177 noalias(project(sigma, vRange, vRange)) = v.getCovariance();
00178
00179 p_Xtn_ytn.setExpectation(mu);
00180 p_Xtn_ytn.setCovariance(sigma);
00181 }
00182
00183 template <class T>
00184 indii::ml::filter::UnscentedKalmanFilter<T>::~UnscentedKalmanFilter() {
00185 delete transitionTransform;
00186 delete measurementTransform;
00187 delete transitionModel;
00188 delete measurementModel;
00189 }
00190
00191 template <class T>
00192 void indii::ml::filter::UnscentedKalmanFilter<T>::filter(const T tnp1,
00193 const indii::ml::aux::vector& ytnp1) {
00194 namespace aux = indii::ml::aux;
00195 namespace ublas = boost::numeric::ublas;
00196 namespace lapack = boost::numeric::bindings::lapack;
00197
00198
00199 assert (tnp1 > this->tn);
00200 assert (ytnp1.size() % V == 0);
00201
00202 const T delta = tnp1 - this->tn;
00203 this->tn = tnp1;
00204
00205
00206 ublas::range xRange(0,N);
00207 ublas::range wRange(N,N+W);
00208 ublas::range vRange(N+W,N+W+V);
00209
00210
00211
00212 aux::GaussianPdf p_xtnp1_ytn(transitionTransform->transform(p_Xtn_ytn,
00213 delta));
00214
00215
00216 aux::vector mu(p_Xtn_ytn.getExpectation());
00217 aux::symmetric_matrix sigma(p_Xtn_ytn.getCovariance());
00218
00219 noalias(project(mu, xRange)) = p_xtnp1_ytn.getExpectation();
00220 noalias(project(sigma, xRange, xRange)) = p_xtnp1_ytn.getCovariance();
00221
00222 aux::GaussianPdf p_Xtnp1_ytn(mu, sigma);
00223
00224
00225
00226 aux::matrix P_xy(N+W+V,V);
00227 aux::GaussianPdf p_ytnp1_Xtnp1(measurementTransform->transform(p_Xtnp1_ytn,
00228 delta, &P_xy));
00229
00230
00231 const aux::vector &y_ytnp1_Xtnp1 = p_ytnp1_Xtnp1.getExpectation();
00232 const aux::symmetric_matrix &P_ytnp1_Xtnp1 = p_ytnp1_Xtnp1.getCovariance();
00233 const aux::vector &x_Xtnp1_ytn = p_Xtnp1_ytn.getExpectation();
00234 const aux::symmetric_matrix &P_Xtnp1_ytn = p_Xtnp1_ytn.getCovariance();
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 aux::matrix X(P_ytnp1_Xtnp1);
00251 aux::matrix KT(trans(project(P_xy,xRange,ublas::range(0,V))));
00252 int err;
00253 err = lapack::gesv(X,KT);
00254 assert (err == 0);
00255 aux::matrix K(trans(KT));
00256
00257 noalias(project(mu,xRange)) = project(x_Xtnp1_ytn,xRange) +
00258 prod(K, ytnp1 - y_ytnp1_Xtnp1);
00259
00260 X.resize(P_ytnp1_Xtnp1.size1(), KT.size2(), false);
00261 noalias(X) = prod(P_ytnp1_Xtnp1, KT);
00262 noalias(project(sigma,xRange,xRange)) = project(P_Xtnp1_ytn,xRange,xRange)
00263 - prod(K, X);
00264
00265 p_Xtn_ytn.setExpectation(mu);
00266 p_Xtn_ytn.setCovariance(sigma);
00267 this->p_xtn_ytn.setExpectation(project(mu, xRange));
00268 this->p_xtn_ytn.setCovariance(project(sigma, xRange, xRange));
00269
00270
00271 assert (this->tn == tnp1);
00272 }
00273
00274 template <class T>
00275 indii::ml::aux::GaussianPdf
00276 indii::ml::filter::UnscentedKalmanFilter<T>::measure() {
00277 return measurementTransform->transform(p_Xtn_ytn);
00278 }
00279
00280 template <class T>
00281 indii::ml::filter::UnscentedTransformation<T>*
00282 indii::ml::filter::UnscentedKalmanFilter<T>::getTransitionTransformation() {
00283 return transitionTransform;
00284 }
00285
00286 template <class T>
00287 indii::ml::filter::UnscentedTransformation<T>*
00288 indii::ml::filter::UnscentedKalmanFilter<T>::getMeasurementTransformation() {
00289 return measurementTransform;
00290 }
00291
00292 #endif