00001
00015 #include <dlrComputerVision/extendedKalmanFilter.h>
00016 #include <dlrLinearAlgebra/linearAlgebra.h>
00017 #include <dlrNumeric/utilities.h>
00018
00019 namespace dlr {
00020
00021 namespace computerVision {
00022
00023
00024 ExtendedKalmanFilter::
00025 ExtendedKalmanFilter(double startTime)
00026 : m_covariance(),
00027 m_state(),
00028 m_previousTimestamp(startTime),
00029 m_timestamp(startTime)
00030 {
00031
00032 }
00033
00034
00035
00036
00037
00038 void
00039 ExtendedKalmanFilter::
00040 addMeasurement(unsigned int measurementID,
00041 double timestamp,
00042 numeric::Array1D<double> const& measurement,
00043 numeric::Array1D<double> const& controlInput)
00044 {
00045 this->doPredictionStep(timestamp, controlInput);
00046 this->doMeasurementUpdate(measurementID, measurement);
00047 }
00048
00049
00050 void
00051 ExtendedKalmanFilter::
00052 checkMeasurementJacobians(unsigned int measurementID,
00053 numeric::Array1D<double> const& epsilonArray,
00054 numeric::Array2D<double>& residualArray0)
00055 {
00056
00057 if(epsilonArray.size() != m_state.size()) {
00058 DLR_THROW(common::ValueException,
00059 "ExtendedKalmanFilter::checkProcessJacobians()",
00060 "Argument epsilon has incorrect size.");
00061 }
00062
00063
00064 numeric::Array2D<double> measurementJacobian0;
00065 numeric::Array2D<double> measurementJacobian1;
00066 this->getMeasurementJacobians(
00067 measurementID, m_timestamp, m_previousTimestamp, m_state,
00068 measurementJacobian0, measurementJacobian1);
00069
00070
00071 numeric::Array1D<double> measurement =
00072 this->applyMeasurementModel(
00073 measurementID, m_timestamp, m_previousTimestamp, m_state);
00074 numeric::Array2D<double> measurementNoiseCovariance =
00075 this->getMeasurementNoiseCovariance(
00076 measurementID, m_timestamp, m_previousTimestamp);
00077 if(measurementJacobian0.rows() != measurement.size()
00078 || measurementJacobian0.columns() != m_state.size()
00079 || measurementJacobian1.rows() != measurement.size()
00080 || (measurementJacobian1.columns()
00081 != measurementNoiseCovariance.rows())) {
00082 DLR_THROW(common::LogicException,
00083 "ExtendedKalmanFilter::checkMeasurementJacobians()",
00084 "At least one of the returned Jacobians has incorrect size.");
00085 }
00086
00087
00088
00089 numeric::Array2D<double> approximateJacobian0(
00090 measurementJacobian0.rows(), measurementJacobian0.columns());
00091 for(unsigned int columnIndex = 0; columnIndex < m_state.size();
00092 ++columnIndex) {
00093 numeric::Array1D<double> state = m_state.copy();
00094
00095 state[columnIndex] -= epsilonArray[columnIndex];
00096 numeric::Array1D<double> resultMeasurement0 =
00097 this->applyMeasurementModel(
00098 measurementID, m_timestamp, m_previousTimestamp, state);
00099
00100 state[columnIndex] += 2.0 * epsilonArray[columnIndex];
00101 numeric::Array1D<double> resultMeasurement1 =
00102 this->applyMeasurementModel(
00103 measurementID, m_timestamp, m_previousTimestamp, state);
00104
00105 numeric::Array1D<double> approximateGradient =
00106 ((resultMeasurement1 - resultMeasurement0)
00107 / (2.0 * epsilonArray[columnIndex]));
00108 for(unsigned int rowIndex = 0; rowIndex < resultMeasurement0.size();
00109 ++rowIndex) {
00110 approximateJacobian0(rowIndex, columnIndex) =
00111 approximateGradient[rowIndex];
00112 }
00113 }
00114
00115
00116
00117
00118
00119
00120
00121 residualArray0 = approximateJacobian0 - measurementJacobian0;
00122 }
00123
00124
00125 void
00126 ExtendedKalmanFilter::
00127 checkProcessJacobians(numeric::Array1D<double> const& epsilonArray,
00128 numeric::Array1D<double> const& controlInput,
00129 numeric::Array2D<double>& residualArray0)
00130 {
00131
00132 if(epsilonArray.size() != m_state.size()) {
00133 DLR_THROW(common::ValueException,
00134 "ExtendedKalmanFilter::checkProcessJacobians()",
00135 "Argument epsilon has incorrect size.");
00136 }
00137
00138
00139 numeric::Array2D<double> processJacobian0;
00140 numeric::Array2D<double> processJacobian1;
00141 this->getProcessJacobians(
00142 m_timestamp, m_previousTimestamp, m_state,
00143 processJacobian0, processJacobian1);
00144
00145 numeric::Array2D<double> processNoiseCovariance =
00146 this->getProcessNoiseCovariance(m_timestamp, m_previousTimestamp);
00147 if(processJacobian0.rows() != m_state.size()
00148 || processJacobian0.columns() != m_state.size()
00149 || processJacobian1.rows() != m_state.size()
00150 || processJacobian1.columns() != processNoiseCovariance.rows()) {
00151 DLR_THROW(common::LogicException,
00152 "ExtendedKalmanFilter::checkProcessJacobians()",
00153 "At least one of the returned Jacobians has incorrect size.");
00154 }
00155
00156
00157
00158 numeric::Array2D<double> approximateJacobian0(
00159 processJacobian0.rows(), processJacobian0.columns());
00160 for(unsigned int columnIndex = 0; columnIndex < m_state.size();
00161 ++columnIndex) {
00162 numeric::Array1D<double> state = m_state.copy();
00163
00164 state[columnIndex] -= epsilonArray[columnIndex];
00165 numeric::Array1D<double> resultState0 =
00166 this->applyProcessModel(m_timestamp, m_previousTimestamp, state,
00167 controlInput);
00168
00169 state[columnIndex] += 2.0 * epsilonArray[columnIndex];
00170 numeric::Array1D<double> resultState1 =
00171 this->applyProcessModel(m_timestamp, m_previousTimestamp, state,
00172 controlInput);
00173
00174 numeric::Array1D<double> approximateGradient =
00175 (resultState1 - resultState0) / (2.0 * epsilonArray[columnIndex]);
00176 for(unsigned int rowIndex = 0; rowIndex < m_state.size(); ++rowIndex) {
00177 approximateJacobian0(rowIndex, columnIndex) =
00178 approximateGradient[rowIndex];
00179 }
00180 }
00181
00182
00183
00184
00185
00186
00187
00188 residualArray0 = approximateJacobian0 - processJacobian0;
00189 }
00190
00191
00192
00193
00194 void
00195 ExtendedKalmanFilter::
00196 freezeKalmanGain()
00197 {
00198 DLR_THROW(common::NotImplementedException,
00199 "ExtendedKalmanFilter::freezeKalmanGain()",
00200 "Sorry. Should be easy to implement, though.");
00201 }
00202
00203
00204
00205
00206
00207 void
00208 ExtendedKalmanFilter::
00209 getStateEstimate(double& timestamp,
00210 numeric::Array1D<double>& state,
00211 numeric::Array2D<double>& covariance)
00212 {
00213 timestamp = m_timestamp;
00214 state = m_state.copy();
00215 covariance = m_covariance.copy();
00216 }
00217
00218
00219
00220
00221
00222 void
00223 ExtendedKalmanFilter::
00224 setStateEstimate(double timestamp,
00225 numeric::Array1D<double> const& state,
00226 numeric::Array2D<double> const& covariance)
00227 {
00228 m_timestamp = timestamp;
00229 m_state = state.copy();
00230 m_covariance = covariance.copy();
00231 }
00232
00233
00234
00235
00236 void
00237 ExtendedKalmanFilter::
00238 unfreezeKalmanGain()
00239 {
00240 DLR_THROW(common::NotImplementedException,
00241 "ExtendedKalmanFilter::unfreezeKalmanGain()",
00242 "Sorry. Should be easy to implement, though.");
00243 }
00244
00245
00246 void
00247 ExtendedKalmanFilter::
00248 doPredictionStep(double currentTime,
00249 Array1D<double> const& controlInput)
00250 {
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 m_previousTimestamp = m_timestamp;
00276 m_timestamp = currentTime;
00277 m_state = this->applyProcessModel(
00278 m_timestamp, m_previousTimestamp, m_state, controlInput);
00279
00280
00281 Array2D<double> processJacobian0;
00282 Array2D<double> processJacobian1;
00283 this->getProcessJacobians(
00284 m_timestamp, m_previousTimestamp, m_state,
00285 processJacobian0, processJacobian1);
00286 m_covariance =
00287 matrixMultiply(
00288 matrixMultiply(processJacobian0, m_covariance),
00289 processJacobian0.transpose());
00290 m_covariance +=
00291 matrixMultiply(
00292 matrixMultiply(
00293 processJacobian1,
00294 this->getProcessNoiseCovariance(m_timestamp, m_previousTimestamp)),
00295 processJacobian1.transpose());
00296 }
00297
00298
00299 void
00300 ExtendedKalmanFilter::
00301 doMeasurementUpdate(unsigned int measurementID,
00302 numeric::Array1D<double> const& measurement)
00303 {
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 Array2D<double> measurementJacobian0;
00325 Array2D<double> measurementJacobian1;
00326 this->getMeasurementJacobians(
00327 measurementID, m_timestamp, m_previousTimestamp, m_state,
00328 measurementJacobian0, measurementJacobian1);
00329
00330
00331 Array2D<double> const& HMatrix = measurementJacobian0;
00332 Array2D<double> HTranspose = HMatrix.transpose();
00333 Array2D<double> const& VMatrix = measurementJacobian1;
00334 Array2D<double> VTranspose = VMatrix.transpose();
00335
00336
00337 numeric::Array2D<double> denominator =
00338 matrixMultiply(matrixMultiply(HMatrix, m_covariance), HTranspose);
00339 denominator +=
00340 (matrixMultiply(
00341 matrixMultiply(
00342 VMatrix,
00343 this->getMeasurementNoiseCovariance(
00344 measurementID, m_timestamp, m_previousTimestamp)),
00345 VTranspose));
00346
00347 numeric::Array1D<double> innovation =
00348 measurement - this->applyMeasurementModel(
00349 measurementID, m_timestamp, m_previousTimestamp, m_state);
00350
00351 numeric::Array2D<double> kalmanGain =
00352 matrixMultiply(matrixMultiply(m_covariance, HTranspose),
00353 linearAlgebra::inverse(denominator));
00354
00355 m_state += matrixMultiply(kalmanGain, innovation);
00356
00357
00358 numeric::Array2D<double> kTimesHMinusI =
00359 matrixMultiply(kalmanGain, HMatrix);
00360 if(kTimesHMinusI.rows() != kTimesHMinusI.columns()) {
00361 DLR_THROW(common::LogicException,
00362 "ExtendedKalmanFilter::doMeasurementUpdate()",
00363 "Programming error. K * H must be square.");
00364 }
00365 for(unsigned int ii = 0; ii < kTimesHMinusI.rows(); ++ii) {
00366 kTimesHMinusI(ii, ii) -= 1.0;
00367 }
00368 m_covariance = matrixMultiply(kTimesHMinusI, m_covariance);
00369 m_covariance *= -1.0;
00370 }
00371
00372 }
00373
00374 }