00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "UnscentedKalman.h"
00025 #include <cxcore.h>
00026 #include <stdio.h>
00027
00028 namespace alvar {
00029
00030 UnscentedKalman::UnscentedKalman(int state_n, int obs_n, int state_k, double alpha, double beta) {
00031 state_k = 0;
00032
00033 this->state_k = state_k;
00034 this->state_n = state_n;
00035 this->obs_n = obs_n;
00036 sigma_n = 2 * state_n + 1;
00037
00038 double L = state_n + state_k;
00039 lambda = alpha*alpha * L - L;
00040 lambda2 = 1 - alpha*alpha + beta;
00041
00042 state = cvCreateMat(state_n, 1, CV_64F); cvSetZero(state);
00043 stateCovariance = cvCreateMat(state_n, state_n, CV_64F); cvSetZero(stateCovariance);
00044 sqrtStateCovariance = cvCreateMat(state_n, state_n, CV_64F); cvSetZero(sqrtStateCovariance);
00045 stateD = cvCreateMat(state_n, state_n, CV_64F); cvSetZero(stateD);
00046 stateU = cvCreateMat(state_n, state_n, CV_64F); cvSetZero(stateU);
00047 stateV = cvCreateMat(state_n, state_n, CV_64F); cvSetZero(stateV);
00048 stateTmp = cvCreateMat(state_n, state_n, CV_64F); cvSetZero(stateTmp);
00049 stateDiff = cvCreateMat(state_n, 1, CV_64F); cvSetZero(stateDiff);
00050
00051 predObs = cvCreateMat(obs_n, 1, CV_64F); cvSetZero(predObs);
00052 predObsCovariance = cvCreateMat(obs_n, obs_n, CV_64F); cvSetZero(predObsCovariance);
00053 predObsDiff = cvCreateMat(obs_n, 1, CV_64F); cvSetZero(predObsDiff);
00054
00055 invPredObsCovariance = cvCreateMat(obs_n, obs_n, CV_64F); cvSetZero(invPredObsCovariance);
00056 statePredObsCrossCorrelation = cvCreateMat(state_n, obs_n, CV_64F); cvSetZero(statePredObsCrossCorrelation);
00057 kalmanGain = cvCreateMat(state_n, obs_n, CV_64F); cvSetZero(kalmanGain);
00058 kalmanTmp = cvCreateMat(state_n, obs_n, CV_64F); cvSetZero(kalmanTmp);
00059
00060 sigma_state = new CvMat*[sigma_n];
00061 sigma_predObs = new CvMat*[sigma_n];
00062
00063 for (int i = 0; i < sigma_n; i++) {
00064 sigma_state[i] = cvCreateMat(state_n, 1, CV_64F); cvSetZero(sigma_state[i]);
00065 sigma_predObs[i] = cvCreateMat(obs_n, 1, CV_64F); cvSetZero(sigma_predObs[i]);
00066 }
00067
00068 sigmasUpdated = false;
00069 }
00070
00071 UnscentedKalman::~UnscentedKalman() {
00072 cvReleaseMat(&state);
00073 cvReleaseMat(&stateCovariance);
00074 cvReleaseMat(&sqrtStateCovariance);
00075 cvReleaseMat(&stateD);
00076 cvReleaseMat(&stateU);
00077 cvReleaseMat(&stateV);
00078 cvReleaseMat(&stateTmp);
00079 cvReleaseMat(&stateDiff);
00080 cvReleaseMat(&kalmanTmp);
00081 cvReleaseMat(&kalmanGain);
00082 cvReleaseMat(&statePredObsCrossCorrelation);
00083 cvReleaseMat(&invPredObsCovariance);
00084
00085 cvReleaseMat(&predObs);
00086 cvReleaseMat(&predObsCovariance);
00087 cvReleaseMat(&predObsDiff);
00088
00089 for (int i = 0; i < sigma_n; i++) {
00090 cvReleaseMat(&sigma_state[i]);
00091 cvReleaseMat(&sigma_predObs[i]);
00092 }
00093 delete[] sigma_state;
00094 delete[] sigma_predObs;
00095 }
00096
00097 void UnscentedKalman::initialize() {
00098
00099
00100
00101
00102
00103 #ifdef MYDEBUG
00104 printf("stateCovariance:\n");
00105 for (int i = 0; i < 5; i++)
00106 printf("%+.10f %+.10f %+.10f %+.10f %+.10f\n",
00107 cvGetReal2D(stateCovariance, 0, i),
00108 cvGetReal2D(stateCovariance, 1, i),
00109 cvGetReal2D(stateCovariance, 2, i),
00110 cvGetReal2D(stateCovariance, 3, i),
00111 cvGetReal2D(stateCovariance, 4, i));
00112 #endif
00113
00114
00115
00116 cvSVD(stateCovariance, stateD, stateU, stateV);
00117 double L = state_n + state_k;
00118 double scale = L + lambda;
00119 for (int i = 0; i < state_n; i++) {
00120 double d = cvGetReal2D(stateD, i, i);
00121 cvSetReal2D(stateD, i, i, sqrt(scale*d));
00122 }
00123 cvGEMM(stateD, stateV, 1., NULL, 0, stateTmp, CV_GEMM_B_T);
00124 cvGEMM(stateU, stateTmp, 1., NULL, 0, sqrtStateCovariance);
00125 #ifdef MYDEBUG
00126 printf("sqrtStateCovariance:\n");
00127 for (int i = 0; i < 5; i++)
00128 printf("%+.10f %+.10f %+.10f %+.10f %+.10f\n",
00129 cvGetReal2D(sqrtStateCovariance, 0, i),
00130 cvGetReal2D(sqrtStateCovariance, 1, i),
00131 cvGetReal2D(sqrtStateCovariance, 2, i),
00132 cvGetReal2D(sqrtStateCovariance, 3, i),
00133 cvGetReal2D(sqrtStateCovariance, 4, i));
00134 cvGEMM(sqrtStateCovariance, sqrtStateCovariance, 1., NULL, 0, stateTmp);
00135 printf("sqrtStateCovariance^2:\n");
00136 for (int i = 0; i < 5; i++)
00137 printf("%+.10f %+.10f %+.10f %+.10f %+.10f\n",
00138 cvGetReal2D(stateTmp, 0, i),
00139 cvGetReal2D(stateTmp, 1, i),
00140 cvGetReal2D(stateTmp, 2, i),
00141 cvGetReal2D(stateTmp, 3, i),
00142 cvGetReal2D(stateTmp, 4, i));
00143 #endif
00144
00145
00146 int sigma_i = 0;
00147 cvCopy(state, sigma_state[sigma_i++]);
00148 for (int i = 0; i < state_n; i++) {
00149 CvMat col;
00150 cvGetCol(sqrtStateCovariance, &col, i);
00151 cvAdd(state, &col, sigma_state[sigma_i++]);
00152 cvSub(state, &col, sigma_state[sigma_i++]);
00153 }
00154
00155 sigmasUpdated = true;
00156 }
00157
00158 void UnscentedKalman::predict(UnscentedProcess *process_model) {
00159 if (!sigmasUpdated) initialize();
00160
00161
00162 cvSetZero(state);
00163 double L = state_n + state_k;
00164 double totalWeight = 0;
00165 for (int i = 0; i < sigma_n; i++) {
00166 double weight = i == 0
00167 ? lambda / (L + lambda)
00168 : .5 / (L + lambda);
00169 totalWeight += weight;
00170 }
00171 for (int i = 0; i < sigma_n; i++) {
00172 CvMat *sigma = sigma_state[i];
00173 process_model->f(sigma);
00174 double weight = i == 0
00175 ? lambda / (L + lambda)
00176 : .5 / (L + lambda);
00177 double scale = weight / totalWeight;
00178 cvAddWeighted(sigma, scale, state, 1., 0., state);
00179 }
00180
00181
00182 cvSetZero(stateCovariance);
00183 totalWeight = 0;
00184 for (int i = 0; i < sigma_n; i++) {
00185 double weight = i == 0
00186 ? lambda / (L + lambda) + lambda2
00187 : .5 / (L + lambda);
00188 totalWeight += weight;
00189 }
00190 for (int i = 0; i < sigma_n; i++) {
00191 double weight = i == 0
00192 ? lambda / (L + lambda) + lambda2
00193 : .5 / (L + lambda);
00194 double scale = weight / totalWeight;
00195 cvSub(sigma_state[i], state, stateDiff);
00196 cvGEMM(stateDiff, stateDiff, scale, stateCovariance, 1., stateCovariance,
00197 CV_GEMM_B_T);
00198 }
00199
00200
00201 CvMat *noise = process_model->getProcessNoise();
00202 if (noise) cvAdd(stateCovariance, noise, stateCovariance);
00203
00204 #ifdef MYDEBUG
00205 printf("predicted state: ");
00206 for (int i = 0; i < state_n; i++) printf("%f ", cvGetReal1D(state, i));
00207 printf("\n");
00208 printf("predicted stateCovariance:\n");
00209 for (int i = 0; i < state_n; i++) {
00210 for (int j = 0; j < state_n; j++) printf("%+f ", cvGetReal2D(stateCovariance, i, j));
00211 printf("\n");
00212 }
00213 #endif
00214
00215 sigmasUpdated = false;
00216 }
00217
00218 void UnscentedKalman::update(UnscentedObservation *obs) {
00219 if (!sigmasUpdated) initialize();
00220 CvMat *innovation = obs->getObservation();
00221 int obs_n = innovation->rows;
00222 if (obs_n > this->obs_n) {
00223 printf("Observation exceeds maximum size!\n");
00224 abort();
00225 }
00226
00227
00228 CvMat predObs = cvMat(obs_n, 1, CV_64F, this->predObs->data.db);
00229 cvSetZero(&predObs);
00230 for (int i = 0; i < sigma_n; i++) {
00231 CvMat sigma_h = cvMat(obs_n, 1, CV_64F, sigma_predObs[i]->data.db);
00232 double scale = i == 0
00233 ? (double)state_k / (double)(state_n + state_k)
00234 : .5 / (double)(state_n + state_k);
00235 obs->h(&sigma_h, sigma_state[i]);
00236 cvAddWeighted(&sigma_h, scale, &predObs, 1., 0., &predObs);
00237 }
00238
00239
00240 CvMat predObsCovariance = cvMat(obs_n, obs_n, CV_64F,
00241 this->predObsCovariance->data.db);
00242 CvMat statePredObsCrossCorrelation = cvMat(state_n, obs_n, CV_64F,
00243 this->statePredObsCrossCorrelation->data.db);
00244 CvMat predObsDiff = cvMat(obs_n, 1, CV_64F, this->predObsDiff->data.db);
00245 cvSetZero(&predObsCovariance);
00246 cvSetZero(&statePredObsCrossCorrelation);
00247 for (int i = 0; i < sigma_n; i++) {
00248 CvMat sigma_h = cvMat(obs_n, 1, CV_64F, sigma_predObs[i]->data.db);
00249 double scale = i == 0
00250 ? (double)state_k / (double)(state_n + state_k)
00251 : .5 / (double)(state_n + state_k);
00252 cvSub(sigma_state[i], state, stateDiff);
00253 cvSub(&sigma_h, &predObs, &predObsDiff);
00254 cvGEMM(&predObsDiff, &predObsDiff, scale, &predObsCovariance, 1., &predObsCovariance,
00255 CV_GEMM_B_T);
00256 cvGEMM(stateDiff, &predObsDiff, scale, &statePredObsCrossCorrelation, 1.,
00257 &statePredObsCrossCorrelation, CV_GEMM_B_T);
00258 }
00259
00260
00261 CvMat *noise = obs->getObservationNoise();
00262 if (noise) cvAdd(&predObsCovariance, noise, &predObsCovariance);
00263
00264 #ifdef MYDEBUG
00265 printf("real observation: ");
00266 for (int i = 0; i < obs_n; i++) printf("%+f ", cvGetReal1D(innovation ,i));
00267 printf("\n");
00268 printf("predicted observation: ");
00269 for (int i = 0; i < obs_n; i++) printf("%+f ", cvGetReal1D(&predObs,i));
00270 printf("\n");
00271 printf("predicted observation co-variance\n");
00272 for (int i = 0; i < obs_n; i++) {
00273 for (int j = 0; j < obs_n; j++) printf("%+f ", cvGetReal2D(&predObsCovariance,i,j));
00274 printf("\n");
00275 }
00276 printf("state observation cross-correlation\n");
00277 for (int i = 0; i < state_n; i++) {
00278 for (int j = 0; j < obs_n; j++) printf("%+f ", cvGetReal2D(&statePredObsCrossCorrelation,i,j));
00279 printf("\n");
00280 }
00281 #endif
00282
00283
00284
00285
00286
00287
00288
00289 CvMat invPredObsCovariance = cvMat(obs_n, obs_n, CV_64F,
00290 this->invPredObsCovariance->data.db);
00291 CvMat kalmanGain = cvMat(state_n, obs_n, CV_64F, this->kalmanGain->data.db);
00292 CvMat kalmanTmp = cvMat(state_n, obs_n, CV_64F, this->kalmanTmp->data.db);
00293
00294 cvSub(innovation, &predObs, innovation);
00295
00296
00297
00298
00299
00300 #ifdef MYDEBUG
00301 printf("innovation: ");
00302 for (int i = 0; i < obs_n; i++) printf("%f ", cvGetReal1D(innovation,i));
00303 printf("\n");
00304 double inn_norm = cvNorm(innovation);
00305 printf("innivation norm: %f\n", inn_norm);
00306 #endif
00307
00308 cvInvert(&predObsCovariance, &invPredObsCovariance, CV_SVD_SYM);
00309 cvMatMul(&statePredObsCrossCorrelation, &invPredObsCovariance, &kalmanGain);
00310 cvGEMM(&kalmanGain, innovation, 1., state, 1., state);
00311 cvMatMul(&kalmanGain, &predObsCovariance, &kalmanTmp);
00312 cvGEMM(&kalmanTmp, &kalmanGain, -1., stateCovariance, 1., stateCovariance,
00313 CV_GEMM_B_T);
00314 #ifdef MYDEBUG
00315 printf("estimated state: ");
00316 for (int i = 0; i < state_n; i++) printf("%f ", cvGetReal1D(state, i));
00317 printf("\n");
00318 #endif
00319
00320 sigmasUpdated = false;
00321 }
00322
00323 }