/// <summary> /// Square Root, Sigma Points Information filter function. This estimates the information (of target) at next timestep (k+1) with given input at time k. /// </summary> /// <param name="xPOI">[7 x 1: east north up vel heading turnRate accleration]</param> /// <param name="xx2">[9 x 1 : 3 NAV, 3ATT, 3GIM] = [E N U, roll pitch yaw, pan tilt scan]</param> /// <param name="SPOI">[7 x 7 square root covariance of POI]</param> /// <param name="Sw">[3 x 3 square root covariance of sensor noise: altitude, turnRate, and accleration]</param> /// <param name="SMeasurement">[2 x 1 covariance vector of measurement]</param> /// <param name="Sx2">[9 x 9 square root covariance of x2]</param> /// <param name="zSCR">[2 x 1 Actual measurement of screen (pixels)]</param> /// <param name="sigma_f">scaling factor for the distance of the sigmap points from the mean</param> /// <returns></returns> public void Update(Matrix xPOI, Matrix xx2, Matrix SPOI, Matrix Sw, Matrix SMeasurement, Matrix Sx2, Matrix zSCR, double sigma_f, string screenSize, string cameraType, TargetTypes type) { //////////////////////////////// INITIALIZATION ///////////////////////////////////// // SORRY - almost impossible to debug. // variable names are mostly following IEEE Transaction paper written by Dr. Mark Campbell. // also the variable names strictly follow the names I used in MATLAB code. int nPOI = xPOI.Rows; int nw = Sw.Rows; int nLaser = 1; // state matrix Matrix xHat_a0 = new Matrix(nPOI + nw, 1); for (int i = 0; i < nPOI; i++) xHat_a0[i, 0] = xPOI[i, 0]; for (int i = 0; i < nw; i++) xHat_a0[i + nPOI, 0] = 0; // covariance matrix Matrix S_a0 = new Matrix(nPOI + nw, nPOI + nw); for (int i = 0; i < nPOI; i++) S_a0[i, i] = SPOI[i, i]; for (int i = nPOI; i < nPOI + nw; i++) S_a0[i, i] = Sw[i - nPOI, i - nPOI]; // generate 2*(nPOI + nw) + 1 sigma points Matrix Xa0 = new Matrix(nPOI + nw, 2 * (nPOI + nw) + 1); Matrix halfSigmaPoints1 = new Matrix(nPOI + nw, nPOI + nw); Matrix halfSigmaPoints2 = new Matrix(nPOI + nw, nPOI + nw); Matrix ones = new Matrix(1, nPOI + nw); ones.Ones(); halfSigmaPoints1 = xHat_a0 * ones + S_a0 * sigma_f; halfSigmaPoints2 = xHat_a0 * ones - S_a0 * sigma_f; Xa0.SetSubMatrix(0, nPOI + nw - 1, 0, 0, xHat_a0); Xa0.SetSubMatrix(0, nPOI + nw - 1, 1, (1 + nPOI + nw) - 1, halfSigmaPoints1); Xa0.SetSubMatrix(0, nPOI + nw - 1, nPOI + nw + 1, 2 * (nPOI + nw), halfSigmaPoints2); // dividing into two parts Matrix XPOI_0 = Xa0.Submatrix(0, nPOI - 1, 0, Xa0.Columns - 1); Matrix Xw_0 = Xa0.Submatrix(nPOI, Xa0.Rows - 1, 0, Xa0.Columns - 1); // weight factors double Wm0 = (sigma_f * sigma_f - (nPOI + nw)) / (sigma_f * sigma_f); double Wc0 = Wm0 + 3 - sigma_f * sigma_f / (nPOI + nw); double W = 1 / (2 * sigma_f * sigma_f); //////////////////////////// SR-SPIF PREDICTION //////////////////////////////// Matrix predPOIs = predPOI(XPOI_0, Xw_0, dT, type); // predicted sigma points Matrix xhatPOIm = predPOIs.Submatrix(0, nPOI - 1, 0, 0) * Wm0; for (int i = 1; i < predPOIs.Columns; i++) { xhatPOIm += predPOIs.Submatrix(0, nPOI - 1, i, i) * W; } // re-arrange sigma points Matrix XPOI_Cm = new Matrix(nPOI, 2 * (nPOI + nw) + 1); for (int i = 0; i < XPOI_Cm.Columns; i++) { for (int j = 0; j < XPOI_Cm.Rows; j++) { XPOI_Cm[j, i] = predPOIs[j, i] - xhatPOIm[j, 0]; } } /////////////////////// CONVERSION FROM PREDICTION TO UPDATE /////////////////////// // define x_x2 Matrix x_nav = xx2.Submatrix(0, 2, 0, 0); Matrix x_att = xx2.Submatrix(3, 5, 0, 0); Matrix x_gim = xx2.Submatrix(6, 8, 0, 0); Matrix S_nav = Sx2.Submatrix(0, 2, 0, 2); Matrix S_att = Sx2.Submatrix(3, 5, 3, 5); Matrix S_gim = Sx2.Submatrix(6, 8, 6, 8); int nSCR = 2; int nx2 = xx2.Rows; int n2a = nPOI + nw + nSCR + nx2 + nLaser; Matrix xhat_x2_m = new Matrix(nx2, 1); // creating x_x2 vector for (int i = 0; i < 3; i++) { xhat_x2_m[i, 0] = x_nav[i, 0]; xhat_x2_m[i + 3, 0] = x_att[i, 0]; xhat_x2_m[i + 6, 0] = x_gim[i, 0]; } Matrix S_x2_m = new Matrix(nx2, nx2); // creating augmented covariance diagonal matrix for x2 for (int i = 0; i < 3; i++) { S_x2_m[i, i] = S_nav[i, i]; S_x2_m[i + 3, i + 3] = S_att[i, i]; S_x2_m[i + 6, i + 6] = S_gim[i, i]; } // equation 20 Matrix X_aug_c0m = new Matrix(nPOI + nSCR + nLaser + nx2, 1); X_aug_c0m.Zero(); for (int i = 0; i < nPOI; i++) X_aug_c0m[i, 0] = XPOI_Cm[i, 0]; Matrix X_aug_cm = new Matrix(nPOI + nSCR + nLaser + nx2, 2 * n2a); X_aug_cm.Zero(); X_aug_cm.SetSubMatrix(0, nPOI - 1, 0, XPOI_Cm.Columns - 2, XPOI_Cm.Submatrix(0, nPOI - 1, 1, XPOI_Cm.Columns - 1)); ones = new Matrix(1, 2 * nSCR + nLaser); ones.Ones(); X_aug_cm.SetSubMatrix(0, nPOI - 1, XPOI_Cm.Columns - 1, XPOI_Cm.Columns - 1 + (2 * nSCR + nLaser) - 1, XPOI_Cm.Submatrix(0, nPOI - 1, 0, 0) * ones); ones = new Matrix(1, 2 * nx2); ones.Ones(); X_aug_cm.SetSubMatrix(0, nPOI - 1, XPOI_Cm.Columns - 1 + 2 * (nSCR + nLaser), XPOI_Cm.Columns - 1 + 2 * (nSCR + nLaser + nx2) - 1, XPOI_Cm.Submatrix(0, nPOI - 1, 0, 0) * ones); X_aug_cm.SetSubMatrix(nPOI, nPOI + nSCR + nLaser - 1, XPOI_Cm.Columns - 1, XPOI_Cm.Columns - 1 + nSCR + nLaser - 1, SMeasurement); X_aug_cm.SetSubMatrix(nPOI, nPOI + nSCR + nLaser - 1, XPOI_Cm.Columns - 1 + nSCR + nLaser, XPOI_Cm.Columns - 1 + 2 * (nSCR + nLaser) - 1, SMeasurement * -1); X_aug_cm.SetSubMatrix(nPOI + nSCR + nLaser, nPOI + nSCR + nLaser + nx2 - 1, XPOI_Cm.Columns - 1 + 2 * (nSCR + nLaser), XPOI_Cm.Columns - 1 + 2 * (nSCR + nLaser) + nx2 - 1, Sx2); X_aug_cm.SetSubMatrix(nPOI + nSCR + nLaser, nPOI + nSCR + nLaser + nx2 - 1, XPOI_Cm.Columns - 1 + 2 * (nSCR + nLaser) + nx2, XPOI_Cm.Columns - 1 + 2 * (nSCR + nLaser + nx2) - 1, Sx2 * -1); // equation 21 Matrix X_aug_m = new Matrix(X_aug_c0m.Rows, X_aug_c0m.Columns + X_aug_cm.Columns); Matrix meanVector = new Matrix(nPOI + nSCR + nLaser + nx2, 1); meanVector.Zero(); meanVector.SetSubMatrix(0, nPOI - 1, 0, 0, xhatPOIm); meanVector.SetSubMatrix(nPOI + nSCR + nLaser, nPOI + nSCR + nLaser + nx2 - 1, 0, 0, xx2); ones = new Matrix(1, 2 * n2a); ones.Ones(); // create augmented sigma points X_aug_m.SetSubMatrix(0, X_aug_m.Rows - 1, 0, 0, X_aug_c0m + meanVector); X_aug_m.SetSubMatrix(0, X_aug_m.Rows - 1, 1, (2 * n2a) + 1 - 1, X_aug_cm + meanVector * ones); // weight configurationU double Wm0_aug = (sigma_f * sigma_f - n2a) / (sigma_f * sigma_f); double Wc0_aug = Wm0_aug + 3 - (sigma_f * sigma_f / n2a); ////////////////////////////////////// SR-SPIF UPDATE ///////////////////////////////////////////// Matrix rangeNoise = new Matrix(1, 1); rangeNoise[0, 0] = SMeasurement[2, 2]; Matrix Z_SCR = MeasurementFct(X_aug_m.Submatrix(0, nPOI - 1, 0, X_aug_m.Columns - 1), X_aug_m.Submatrix(nPOI + nSCR + nLaser, X_aug_m.Rows - 1, 0, X_aug_m.Columns - 1), X_aug_m.Submatrix(nPOI, nPOI + nSCR + nLaser - 1, 0, X_aug_m.Columns - 1), rangeNoise, cameraType, screenSize); Matrix z_mean = new Matrix(nSCR + nLaser, 1); // measurement mean for (int i = 0; i < Z_SCR.Columns; i++) { if (i == 0) z_mean += Z_SCR.Submatrix(0, Z_SCR.Rows - 1, 0, 0) * Wm0_aug; else z_mean += Z_SCR.Submatrix(0, Z_SCR.Rows - 1, i, i) * W; } ones = new Matrix(1, Z_SCR.Columns); ones.Ones(); Matrix Z_SCR_c = Z_SCR - z_mean * ones; // equation 27 //Matrix P_POIx2SCR = new Matrix(nPOI + nx2, nSCR); Matrix augPOIx2cm = new Matrix(nPOI + nx2, X_aug_cm.Columns); augPOIx2cm.SetSubMatrix(0, nPOI - 1, 0, X_aug_cm.Columns - 1, X_aug_cm.Submatrix(0, nPOI - 1, 0, X_aug_cm.Columns - 1)); augPOIx2cm.SetSubMatrix(nPOI, nPOI + nx2 - 1, 0, X_aug_cm.Columns - 1, X_aug_cm.Submatrix(nPOI + nSCR + nLaser, nPOI + nSCR + nLaser + nx2 - 1, 0, X_aug_cm.Columns - 1)); Matrix augPOIx2c0m = new Matrix(nPOI + nx2, 1); augPOIx2c0m.SetSubMatrix(0, nPOI - 1, 0, 0, X_aug_c0m.Submatrix(0, nPOI - 1, 0, 0)); augPOIx2c0m.SetSubMatrix(nPOI, nPOI + nx2 - 1, 0, 0, X_aug_c0m.Submatrix(nPOI + nSCR + nLaser, nPOI + nSCR + nLaser + nx2 - 1, 0, 0)); Matrix P_POIx2SCR = augPOIx2cm * Z_SCR_c.Submatrix(0, Z_SCR_c.Rows - 1, 1, Z_SCR_c.Columns - 1).Transpose() * W + augPOIx2c0m * Z_SCR_c.Submatrix(0, Z_SCR_c.Rows - 1, 0, 0).Transpose() * Wc0_aug; //// Equation 28 and below chol part is equation 15 QrDecomposition qrDecomposition = new QrDecomposition(XPOI_Cm.Submatrix(0, XPOI_Cm.Rows - 1, 1, XPOI_Cm.Columns - 1).Transpose()); Matrix R_X_POI_Cm = qrDecomposition.UpperTriangularFactor; CholeskyDecomposition cholUpdate; Matrix S_POI_m; if (Wc0_aug < 0) { cholUpdate = new CholeskyDecomposition(R_X_POI_Cm.Transpose() * R_X_POI_Cm * Math.Sqrt(W) * Math.Sqrt(W) - XPOI_Cm.Submatrix(0, nPOI - 1, 0, 0) * XPOI_Cm.Submatrix(0, nPOI - 1, 0, 0).Transpose() * Math.Abs(Wc0)); S_POI_m = cholUpdate.LeftTriangularFactor.Transpose(); } else if (Wc0_aug > 0) { cholUpdate = new CholeskyDecomposition(R_X_POI_Cm.Transpose() * R_X_POI_Cm * Math.Sqrt(W) * Math.Sqrt(W) + XPOI_Cm.Submatrix(0, nPOI - 1, 0, 0) * XPOI_Cm.Submatrix(0, nPOI - 1, 0, 0).Transpose() * Math.Abs(Wc0)); S_POI_m = cholUpdate.LeftTriangularFactor.Transpose(); } else throw new Exception("Weight is zero"); //Matrix S_POI_mVer2 = new Matrix(nPOI, nPOI); for (int i = 0; i < nPOI; i++) { //S_POI_mVer2[i, i] = Math.Abs(S_POI_m[i, i]); S_POI_m[i, i] = Math.Abs(S_POI_m[i, i]); } QrDecomposition qrSPOImVer2 = new QrDecomposition(S_POI_m.Transpose().Inverse); Matrix R_POIminus = qrSPOImVer2.UpperTriangularFactor; Matrix Y_POIminus = R_POIminus.Transpose() * R_POIminus; //QrDecomposition qrDecomposition_S_x2_m = new QrDecomposition(S_x2_m.Inverse.Transpose()); //Matrix R_x2m = qrDecomposition_S_x2_m.UpperTriangularFactor; //QrDecomposition qrDecomposition_S_POI_m = new QrDecomposition(S_POI_m.Inverse.Transpose()); //Matrix R_POIm = qrDecomposition_S_POI_m.UpperTriangularFactor; //Matrix P_POIm1 = R_POIm.Transpose() * R_POIm; //Matrix P_x2m1 = R_x2m.Transpose() * R_x2m; //Matrix blkDiag = new Matrix(P_POIm1.Rows + P_x2m1.Rows, P_POIm1.Columns + P_x2m1.Columns); //blkDiag.SetSubMatrix(0, P_POIm1.Rows - 1, 0, P_POIm1.Columns - 1, P_POIm1); //blkDiag.SetSubMatrix(P_POIm1.Rows, P_POIm1.Rows + P_x2m1.Rows - 1, P_POIm1.Columns, P_POIm1.Columns + P_x2m1.Columns - 1, P_x2m1); //Matrix C_SCR = P_POIx2SCR.Transpose() * blkDiag; // Equation 28 QrDecomposition qrInvSx2 = new QrDecomposition(Sx2.Inverse); Matrix R_x2minus = qrInvSx2.UpperTriangularFactor; Matrix Y_x2minus = R_x2minus.Transpose() * R_x2minus; Matrix blkDiagYseries = new Matrix(nPOI + nx2, nPOI + nx2); blkDiagYseries.SetSubMatrix(0, nPOI - 1, 0, nPOI - 1, Y_POIminus); blkDiagYseries.SetSubMatrix(nPOI, nPOI + nx2 - 1, nPOI, nPOI + nx2 - 1, Y_x2minus); Matrix C = P_POIx2SCR.Transpose() * blkDiagYseries; // SUPER IMPORTANT STEP !! QrDecomposition anotherQrDecomposition = new QrDecomposition(Z_SCR_c.Submatrix(0, Z_SCR_c.Rows - 1, 1, Z_SCR_c.Columns - 1).Transpose()); Matrix Rvtilde = anotherQrDecomposition.UpperTriangularFactor; CholeskyDecomposition anotherCholUpdate; Matrix Svtilde; if (Wc0_aug < 0) { anotherCholUpdate = new CholeskyDecomposition(Rvtilde.Transpose() * Rvtilde * Math.Sqrt(W) * Math.Sqrt(W) - Z_SCR_c.Submatrix(0, Z_SCR_c.Rows - 1, 0, 0) * Z_SCR_c.Submatrix(0, Z_SCR_c.Rows - 1, 0, 0).Transpose() * Math.Abs(Wc0_aug)); Svtilde = anotherCholUpdate.LeftTriangularFactor.Transpose(); } else if (Wc0_aug > 0) { anotherCholUpdate = new CholeskyDecomposition(Rvtilde.Transpose() * Rvtilde * Math.Sqrt(W) * Math.Sqrt(W) + Z_SCR_c.Submatrix(0, Z_SCR_c.Rows - 1, 0, 0) * Z_SCR_c.Submatrix(0, Z_SCR_c.Rows - 1, 0, 0).Transpose() * Math.Abs(Wc0_aug)); Svtilde = anotherCholUpdate.LeftTriangularFactor.Transpose(); } else throw new Exception("Weight is zero"); //Matrix SvtildeVer2 = new Matrix(Svtilde.Rows, Svtilde.Columns); SvtildeVer2.Zero(); for (int i = 0; i < Svtilde.Columns; i++) Svtilde[i, i] = Math.Abs(Svtilde[i, i]); Matrix P_SCR = Svtilde.Transpose() * Svtilde; Matrix Y_SCR = P_SCR.Inverse; CholeskyDecomposition lastCholDecompose = new CholeskyDecomposition(Y_SCR); Matrix R_SCR = lastCholDecompose.LeftTriangularFactor.Transpose(); // Equation 31-33 //QrDecomposition qrDecomposition_SSCR = new QrDecomposition(SSCR.Transpose().Inverse); //Matrix R_SCR = qrDecomposition_SSCR.UpperTriangularFactor; Matrix v_kp1 = zSCR - z_mean; Matrix i_kp1 = new Matrix(nx2 + nSCR + nLaser, 1); Matrix xhatPOIm_xhat_x2_m_aug = new Matrix(nPOI + nx2, 1); xhatPOIm_xhat_x2_m_aug.SetSubMatrix(0, nPOI - 1, 0, 0, xhatPOIm); xhatPOIm_xhat_x2_m_aug.SetSubMatrix(nPOI, nPOI + nx2 - 1, 0, 0, xhat_x2_m); i_kp1.SetSubMatrix(0, nx2 - 1, 0, 0, R_x2minus * xhat_x2_m); i_kp1.SetSubMatrix(nx2, nx2 + nSCR + nLaser - 1, 0, 0, R_SCR * (v_kp1 + C * xhatPOIm_xhat_x2_m_aug)); Matrix I_kp1 = R_SCR * C; // equation 34 // actually [blkDiag; I_kp1]; Matrix blkDiag; blkDiag = new Matrix(R_POIminus.Rows + R_x2minus.Rows + I_kp1.Rows, R_POIminus.Columns + R_x2minus.Columns); blkDiag.SetSubMatrix(0, R_POIminus.Rows - 1, 0, R_POIminus.Columns - 1, R_POIminus); blkDiag.SetSubMatrix(R_POIminus.Rows, R_POIminus.Rows + R_x2minus.Rows - 1, R_POIminus.Columns, R_POIminus.Columns + R_x2minus.Columns - 1, R_x2minus); blkDiag.SetSubMatrix(R_POIminus.Rows + R_x2minus.Rows, blkDiag.Rows - 1, 0, blkDiag.Columns - 1, I_kp1); QrDecomposition qrDecomposition_blkDiag = new QrDecomposition(blkDiag); Matrix R_blob = qrDecomposition_blkDiag.UpperTriangularFactor; Matrix T_kp1 = qrDecomposition_blkDiag.OrthogonalFactor; Matrix RPOI = R_blob.Submatrix(0, nPOI - 1, 0, nPOI - 1); Matrix RPOIx2 = R_blob.Submatrix(0, nPOI - 1, nPOI, R_blob.Columns - 1); Matrix Rx2 = R_blob.Submatrix(nPOI, R_blob.Rows - 1, nPOI, R_blob.Columns - 1); // final calculation Matrix ninvRPOI_RPOIx2_invRx2 = (RPOI.Inverse * -1) * RPOIx2 * Rx2.Inverse; Matrix R_POIm_xhatPOIm_i_kp1 = new Matrix(nPOI + i_kp1.Rows, 1); R_POIm_xhatPOIm_i_kp1.SetSubMatrix(0, nPOI - 1, 0, 0, R_POIminus * xhatPOIm); R_POIm_xhatPOIm_i_kp1.SetSubMatrix(nPOI, R_POIm_xhatPOIm_i_kp1.Rows - 1, 0, 0, i_kp1); Matrix invRPOI_ninvRPOI_RPOIx2_invRx2 = new Matrix(RPOI.Rows, RPOI.Columns + ninvRPOI_RPOIx2_invRx2.Columns); invRPOI_ninvRPOI_RPOIx2_invRx2.SetSubMatrix(0, nPOI - 1, 0, nPOI - 1, RPOI.Inverse); invRPOI_ninvRPOI_RPOIx2_invRx2.SetSubMatrix(0, nPOI - 1, nPOI, invRPOI_ninvRPOI_RPOIx2_invRx2.Columns - 1, ninvRPOI_RPOIx2_invRx2); Matrix xhatPOI = invRPOI_ninvRPOI_RPOIx2_invRx2 * T_kp1.Transpose() * R_POIm_xhatPOIm_i_kp1; Matrix invRPOI_ninvRPOI_RPOIx2_invRx2_zeros_invRx2 = new Matrix(invRPOI_ninvRPOI_RPOIx2_invRx2.Rows + nx2 + Rx2.Rows, invRPOI_ninvRPOI_RPOIx2_invRx2.Columns); invRPOI_ninvRPOI_RPOIx2_invRx2_zeros_invRx2.SetSubMatrix(0, invRPOI_ninvRPOI_RPOIx2_invRx2.Rows - 1, 0, invRPOI_ninvRPOI_RPOIx2_invRx2.Columns - 1, invRPOI_ninvRPOI_RPOIx2_invRx2); invRPOI_ninvRPOI_RPOIx2_invRx2_zeros_invRx2.SetSubMatrix(invRPOI_ninvRPOI_RPOIx2_invRx2.Rows, invRPOI_ninvRPOI_RPOIx2_invRx2.Rows + nx2 - 1, nPOI, invRPOI_ninvRPOI_RPOIx2_invRx2.Columns - 1, Rx2.Inverse); QrDecomposition qrDecomposition_invRPOIstuff = new QrDecomposition(invRPOI_ninvRPOI_RPOIx2_invRx2_zeros_invRx2); Matrix S_blob = qrDecomposition_invRPOIstuff.UpperTriangularFactor; Matrix newSPOI = S_blob.Submatrix(0, nPOI - 1, 0, nPOI - 1); targetState = xhatPOI; if (Math.Abs(newSPOI[0, 0]) < Math.Sqrt(0.05)) newSPOI[0, 0] = Math.Sqrt(0.05) * Math.Sign(newSPOI[0, 0]); if (Math.Abs(newSPOI[1, 1]) < Math.Sqrt(0.06)) newSPOI[1, 1] = Math.Sqrt(0.05) * Math.Sign(newSPOI[1, 1]); S_target = newSPOI; }
public Matrix GenerateEllipse(int numPoint, double centerX, double centerY, Matrix sMatrix, int numSigma) { Matrix ep = new Matrix(numPoint, 2); // ellipse points // generate points in a circle for (int i = 0; i < numPoint; i++) { ep[i, 0] = numSigma * Math.Cos(2 * Math.PI / numPoint * i); ep[i, 1] = numSigma * Math.Sin(2 * Math.PI / numPoint * i); } // skew the ellipse CholeskyDecomposition chol = new CholeskyDecomposition(sMatrix); ep = chol.LeftTriangularFactor.Transpose() * ep.Transpose(); ep = ep.Transpose(); // re-center the ellipse Matrix ones = new Matrix(numPoint, 2); for (int i = 0; i < numPoint; i++) { ep[i, 0] = ep[i, 0] + centerX; ep[i, 1] = ep[i, 1] + centerY; } return ep; }
void SLAMEKFMainLoop(object o) { k = 0; while (running) { lock (dataLock) { if (currentScan == null || viconPose == null || odomPose == null || viconLastPose == viconPose) continue; // no data, no update else { #region discrete-time increment k = k + 1; #endregion if (k == 1) { #region state initialization initialOdomPose = odomPose; transformedOdomPose = new RobotPose(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, odomPose.timestamp); transformedOdomPose.x = (Math.Cos(initialViconPose.yaw - initialOdomPose.yaw)) * odomPose.x - (Math.Sin(initialViconPose.yaw - initialOdomPose.yaw)) * odomPose.y; transformedOdomPose.y = (Math.Sin(initialViconPose.yaw - initialOdomPose.yaw)) * odomPose.x + (Math.Cos(initialViconPose.yaw - initialOdomPose.yaw)) * odomPose.y; transformedOdomPose.yaw = odomPose.yaw; transformedOdomPose = transformedOdomPose - initialOdomPose + initialViconPose; odomLastPose = transformedOdomPose; xhatvPose = transformedOdomPose; #endregion #region map initialization and management #region extract features -> fz List<Vector2> currentScanXY = new List<Vector2>(); fz.Clear(); ibook = fExtract(currentScan, bAngle, maxRange); if (ibook != null) { for (int i = 0; i < currentScan.Points.Count; i++) currentScanXY.Add(currentScan.Points[i].RThetaPoint.ToVector2()); for (int i = 0; i < ibook.Count; i++) fz.Add(rotateTranslate(currentScanXY[ibook[i]], xhatvPose)); } #endregion #region populate the map -> landmarkList landmarkList.Clear(); for (int i = 0; i < fz.Count; i++) landmarkList.Add(fz[i]); #endregion #region populate the map -> mhat mhat = new Matrix(2 * landmarkList.Count, 1); for (int i = 0; i < landmarkList.Count; i++) { mhat[2 * i, 0] = landmarkList[i].X; mhat[2 * i + 1, 0] = landmarkList[i].Y; } #endregion #region covariance management -> Paug Qv = new Matrix(3, 3, Math.Pow(sigw, 2)); Pv = Qv; Paug = Pv; for (int i = 0; i < fz.Count; i++) Paug = blkdiag(Paug, new Matrix(2, 2, Math.Pow(sigw, 2))); #endregion lastScan = currentScan; #endregion } else { #region odometry processing transformedOdomPose = new RobotPose(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, odomPose.timestamp); transformedOdomPose.x = (Math.Cos(initialViconPose.yaw - initialOdomPose.yaw)) * odomPose.x - (Math.Sin(initialViconPose.yaw - initialOdomPose.yaw)) * odomPose.y; transformedOdomPose.y = (Math.Sin(initialViconPose.yaw - initialOdomPose.yaw)) * odomPose.x + (Math.Cos(initialViconPose.yaw - initialOdomPose.yaw)) * odomPose.y; transformedOdomPose.yaw = odomPose.yaw; transformedOdomPose = transformedOdomPose - initialOdomPose + initialViconPose; xStep = transformedOdomPose - odomLastPose; double omega = odomLastPose.yaw + xStep.yaw; if (xStep.x == 0) uvk.x = 0; else { double vx = xStep.x / Math.Cos(omega); uvk.x = vx * Math.Cos(omega); } if (xStep.y == 0) uvk.y = 0; else { double vy = xStep.y / Math.Sin(omega); uvk.y = vy * Math.Sin(omega); } uvk.yaw = xStep.yaw; uvk.z = 0; uvk.roll = 0; uvk.pitch = 0; uvk.timestamp = odomPose.timestamp; odomLastPose = transformedOdomPose; #endregion #region time-update xhatvPose = xhatvPose + uvk; Matrix Uvk = new Matrix(3, 1); Uvk[0, 0] = uvk.x; Uvk[1, 0] = uvk.y; Uvk[2, 0] = uvk.yaw; Pv = Pv + ScalarMultiply(Math.Pow(0.5,2),Uvk * Uvk.Transpose()) + Qv; Paug.SetSubMatrix(0, 2, 0, 2, Pv); Matrix Qmv = new Matrix(0, 0, 1.0); for (int i = 0; i < landmarkList.Count; i++) Qmv = blkdiag(Qmv, ScalarMultiply(Math.Pow(sigw / 5, 2), Pv.Submatrix(0, 1, 0, 1))); Matrix Qm = new Matrix(Paug.Rows - 3, Paug.Columns - 3, Math.Pow(sigw / 5, 2)); Paug.SetSubMatrix(3, Paug.Rows - 1, 3, Paug.Columns - 1, Paug.Submatrix(3, Paug.Rows - 1, 3, Paug.Columns - 1) + Qmv + Qm); #endregion #region feature exraction numLandmarks = landmarkList.Count; List<Vector2> currentScanXY = new List<Vector2>(); fz.Clear(); ibook = fExtract(currentScan, bAngle, maxRange); if (ibook != null) { for (int i = 0; i < currentScan.Points.Count; i++) currentScanXY.Add(currentScan.Points[i].RThetaPoint.ToVector2()); for (int i = 0; i < ibook.Count; i++) fz.Add(rotateTranslate(currentScanXY[ibook[i]], xhatvPose)); } #endregion #region data association #region variables fzHat = new List<Vector2>(landmarkList); List<Vector3> jObsv = new List<Vector3>(); List<Vector2> iObsv = new List<Vector2>(); List<Vector2> obsvFeatureList = new List<Vector2>(); Matrix cLP = new Matrix(fz.Count, fzHat.Count); Matrix dapGate = new Matrix(fz.Count, fzHat.Count); Matrix fzM = new Matrix(2,1); Matrix fzHatM = new Matrix(2,1); #endregion #region initialization // "lpsolver55.dll" directory: // (note: Alt + F7 -> Build -> enable "Allow UnSafe Code") lpsolve.Init("C:\\users\\labuser\\desktop\\MAGIC\\Framework\\SLAM"); double[] xOpt; double ignoreThisEntry = 0; int nDecision = fz.Count * fzHat.Count; int nConstraints = fz.Count + fzHat.Count; int lp = lpsolve.make_lp((int)ignoreThisEntry, nDecision); //lpsolve.set_sense(lp, true); #endregion #region c-vector (objective function) double[] cObj = new double[nDecision + 1]; cObj[0] = ignoreThisEntry; int ic = 0; for (int i = 0; i < fz.Count; i++) { for (int j = 0; j < fzHat.Count; j++) { ic = ic + 1; cObj[ic] = -1000000.0 + ciGate(fz[i], Paug.Submatrix(0, 1, 0, 1), fzHat[j], Paug.Submatrix(2 * j + 3, 2 * j + 4, 2 * j + 3, 2 * j + 4), 1.0); cLP[i, j] = cObj[ic]; fzM[0,0] = fz[i].X; fzM[1,0] = fz[i].Y; fzHatM[0,0] = fzHat[j].X; fzHatM[1,0] = fzHat[j].Y; dapGate[i, j] = ((fzM - fzHatM).Transpose() * Paug.Submatrix(2 * j + 3, 2 * j + 4, 2 * j + 3, 2 * j + 4).Inverse * (fzM - fzHatM))[0, 0]; } } lpsolve.set_obj_fn(lp, cObj); //lpsolve.set_timeout(lp, 0); #endregion #region b-vector (RHS of LE) double[] bVec = new double[nConstraints]; for (int i = 0; i < bVec.Length; i++) bVec[i] = 1.0; #endregion #region A-matrix (constraints setup) double[,] A = new double[nConstraints, nDecision]; int jc = 0; for (int i = 0; i < fz.Count; i++) { int jr = 1; for (int j = 0; j < fzHat.Count; j++) { A[i, j + jc] = 1; A[fz.Count - 1 + jr, j + jc] = 1; jr = jr + 1; } jc = jc + fzHat.Count; } List<double[]> lpConstraints = new List<double[]>(); lpConstraints.Clear(); for (int i = 0; i < nConstraints; i++) { double[] Aline = new double[nDecision + 1]; Aline[0] = ignoreThisEntry; for (int j = 1; j < nDecision + 1; j++) { Aline[j] = A[i, j - 1]; } lpConstraints.Add(Aline); } for (int i = 0; i < nConstraints; i++) lpsolve.add_constraint(lp, lpConstraints[i], lpsolve.lpsolve_constr_types.LE, bVec[i]); #endregion #region optimization and results lpsolve.solve(lp); xOpt = new double[lpsolve.get_Ncolumns(lp)]; lpsolve.get_variables(lp, xOpt); lpsolve.delete_lp(lp); ic = 0; double tau = 6.63; for (int i = 0; i < fz.Count; i++) { for (int j = 0; j < fzHat.Count; j++) { if ((xOpt[ic] > 0.98) && (xOpt[ic] < 1.02) && (dapGate[i, j] < tau)) jObsv.Add(new Vector3(i, j, cLP[i, j])); ic = ic + 1; } } if (jObsv.Count > 0) { for (int j = 0; j < jObsv.Count; j++) { iObsv.Add(new Vector2(jObsv[j].X, jObsv[j].Y)); obsvFeatureList.Add(rotateTranslate(currentScanXY[ibook[(int)(jObsv[j].X)]], xhatvPose)); // dev-only } } numObsv = iObsv.Count; #endregion #endregion #region measurement-update if (numObsv > 0) { #region spf parameters double L = 3 + 2 * landmarkList.Count; double alpha = 1.0; double kappa = 0.0; double beta = 2.0; double lambda = Math.Pow(alpha, 2) * (L + kappa) - L; double gam = Math.Sqrt(L + lambda); double wm0 = lambda / (L + lambda); double wc0 = lambda / (L + lambda) + (1 - Math.Pow(alpha, 2) + beta); wm = new Matrix((int)(2 * L) + 1, 1); for (int j = 0; j < (int)(2 * L) + 1; j++) { if (j == 0) wm[j, 0] = wm0; else wm[j, 0] = 1 / (2.0 * (L + lambda)); } wc = new Matrix((int)(2 * L) + 1, 1); for (int j = 0; j < (int)(2.0 * L) + 1; j++) { if (j == 0) wc[j, 0] = wc0; else wc[j, 0] = 1 / (2.0 * (L + lambda)); } #endregion #region spf sampler CholeskyDecomposition PCholContainer = new CholeskyDecomposition(ScalarMultiply(L + lambda, Paug)); Matrix PChol = PCholContainer.LeftTriangularFactor; chi0 = new Matrix((int)L, 1); chi0[0, 0] = xhatvPose.x - uvk.x; chi0[1, 0] = xhatvPose.y - uvk.y; chi0[2, 0] = xhatvPose.yaw - uvk.yaw; for (int i = 0; i < mhat.Rows; i++) chi0[3 + i, 0] = mhat[i, 0]; chi1 = new Matrix((int)L, (int)L); for (int i = 0; i < (int)L; i++) chi1.SetSubMatrix(0, chi1.Rows - 1, i, i, chi0 + PChol.Submatrix(0, chi0.Rows - 1, i, i)); chi2 = new Matrix((int)L, (int)L); for (int i = 0; i < (int)L; i++) chi2.SetSubMatrix(0, chi2.Rows - 1, i, i, chi0 - PChol.Submatrix(0, chi0.Rows - 1, i, i)); chi = chi0; chi = chi.Concat(2, chi1); chi = chi.Concat(2, chi2); #endregion #region spf time-update Matrix chiBar = new Matrix((int)L, (int)(2 * L) + 1); Matrix uvkSPF = new Matrix((int)L, 1); uvkSPF.Zero(); uvkSPF[0, 0] = uvk.x; uvkSPF[1, 0] = uvk.y; uvkSPF[2, 0] = uvk.yaw; for (int i = 0; i < (int)(2 * L) + 1; i++) chiBar.SetSubMatrix(0, chiBar.Rows - 1, i, i, chi.Submatrix(0, chi.Rows - 1, i, i) + uvkSPF); Matrix xBar = chiBar * wm; Matrix PBar = new Matrix((int)L, (int)L); PBar.Zero(); for (int i = 0; i < (int)(2 * L) + 1; i++) PBar = PBar + ScalarMultiply(wc[i, 0], (chiBar.Submatrix(0, chiBar.Rows - 1, i, i) - xBar) * (chiBar.Submatrix(0, chiBar.Rows - 1, i, i) - xBar).Transpose()); #endregion #region sigma-point update CholeskyDecomposition PBarCholContainer = new CholeskyDecomposition(PBar); Matrix PBarChol = PBarCholContainer.LeftTriangularFactor; chi0 = xBar; chi1 = new Matrix((int)L, (int)L); for (int i = 0; i < (int)L; i++) chi1.SetSubMatrix(0, chi1.Rows - 1, i, i, xBar + ScalarMultiply(gam, PBarChol.Submatrix(0, chi0.Rows - 1, i, i))); chi2 = new Matrix((int)L, (int)L); for (int i = 0; i < (int)L; i++) chi2.SetSubMatrix(0, chi2.Rows - 1, i, i, xBar - ScalarMultiply(gam, PBarChol.Submatrix(0, chi0.Rows - 1, i, i))); chiUpdate = chi0; chiUpdate = chiUpdate.Concat(2, chi1); chiUpdate = chiUpdate.Concat(2, chi2); #endregion #region spf measurement-update setup #region predicted measurement Matrix YBar = new Matrix(2 * numObsv, (int)(2 * L) + 1); YBar.Zero(); for (int i = 0; i < (int)(2 * L) + 1; i++) { chiUpdateObsv = new Matrix((int)(2 * numObsv), 1); for (int j = 0; j < numObsv; j++) { chiUpdateObsv[2 * j, 0] = chiUpdate[(int)(2 * iObsv[j].Y + 3), i]; chiUpdateObsv[2 * j + 1, 0] = chiUpdate[(int)(2 * iObsv[j].Y + 1 + 3), i]; } YBar.SetSubMatrix(0, YBar.Rows - 1, i, i, hFunction(chiUpdate.Submatrix(0, 2, i, i), chiUpdateObsv)); } Matrix yBar = YBar * wm; #endregion #region actual measurement Matrix z = new Matrix(2 * numObsv, 1); for (int i = 0; i < numObsv; i++) { z[2 * i, 0] = currentScan.Points[ibook[(int)(iObsv[i].X)]].RThetaPoint.R; z[2 * i + 1, 0] = currentScan.Points[ibook[(int)(iObsv[i].X)]].RThetaPoint.theta; } #endregion #region innovation covariance S = new Matrix(2 * numObsv, 2 * numObsv); S.Zero(); for (int i = 0; i < (int)(2 * L) + 1; i++) S = S + ScalarMultiply(wc[i, 0], (YBar.Submatrix(0, YBar.Rows - 1, i, i) - yBar) * (YBar.Submatrix(0, YBar.Rows - 1, i, i) - yBar).Transpose()); S = S + new Matrix(2 * numObsv, 2 * numObsv, Math.Pow(sigv, 2)); #endregion #region Kalman gain matrix W = new Matrix((int)L, 2 * numObsv); W.Zero(); for (int i = 0; i < (int)(2 * L) + 1; i++) W = W + ScalarMultiply(wc[i, 0], (chiUpdate.Submatrix(0, chiUpdate.Rows - 1, i, i) - xBar) * (YBar.Submatrix(0, YBar.Rows - 1, i, i) - yBar).Transpose()); W = W * S.Inverse; #endregion #region measurement wrapper zCart = new Matrix(2 * numObsv, 1); for (int i = 0; i < numObsv; i++) { zCart[2 * i, 0] = z[2 * i, 0] * Math.Cos(z[2 * i + 1, 0]); zCart[2 * i + 1, 0] = z[2 * i, 0] * Math.Sin(z[2 * i + 1, 0]); } for (int i = 0; i < numObsv; i++) { z[2 * i, 0] = Math.Sqrt(Math.Pow(zCart[2 * i, 0], 2) + Math.Pow(zCart[2 * i + 1, 0], 2)); z[2 * i + 1, 0] = Math.Atan2(zCart[2 * i + 1, 0], zCart[2 * i, 0]); } yBarCart = new Matrix(2 * numObsv, 1); for (int i = 0; i < numObsv; i++) { yBarCart[2 * i, 0] = yBar[2 * i, 0] * Math.Cos(yBar[2 * i + 1, 0]); yBarCart[2 * i + 1, 0] = yBar[2 * i, 0] * Math.Sin(yBar[2 * i + 1, 0]); } for (int i = 0; i < numObsv; i++) { yBar[2 * i, 0] = Math.Sqrt(Math.Pow(yBarCart[2 * i, 0], 2) + Math.Pow(yBarCart[2 * i + 1, 0], 2)); yBar[2 * i + 1, 0] = Math.Atan2(yBarCart[2 * i + 1, 0], yBarCart[2 * i, 0]); } #endregion #endregion #region spf measurement-update //(((z - yBar).Transpose() * S * (z - yBar))[0, 0] < 6.63) xBar = xBar + W * (z - yBar); Paug = PBar - W * S * W.Transpose(); #region SLAM-context of measurement update #region localization xhatvPose.x = xBar[0, 0]; xhatvPose.y = xBar[1, 0]; xhatvPose.yaw = xBar[2, 0]; Pv = Paug.Submatrix(0, 2, 0, 2); #endregion #region mapping mhat = xBar.Submatrix(3, (int)L - 1, 0, 0); int landmarkListCount = landmarkList.Count; landmarkList.Clear(); for (int i = 0; i < landmarkListCount; i++) landmarkList.Add(new Vector2(mhat[2 * i, 0], mhat[2 * i + 1, 0])); #endregion #endregion #endregion } #endregion #region show features slamFeatures.Clear(); if (ibook != null) { for (int i = 0; i < ibook.Count; i++) slamFeatures.Add(fz[i]); } #endregion #region map management double minDist = 0.5; double sigMapFreeze = 0.5; int landmarkMaxCount = 20; for (int i = 0; i < iObsv.Count; i++) fz.RemoveAt((int)(iObsv[i].X - i)); for (int i = 0; i < fz.Count; i++) { int nFlag = 0; for (int j = 0; j < landmarkList.Count; j++) { if ((fz[i] - landmarkList[j]).Length > minDist) nFlag = nFlag + 1; } if ((nFlag == landmarkList.Count) && (Pv.Trace < sigMapFreeze) && (landmarkList.Count - 1 <= landmarkMaxCount)) { landmarkList.Add(fz[i]); Paug = blkdiag(Paug, new Matrix(2, 2, (Pv.Submatrix(0, 1, 0, 1)).Trace)); Matrix mHatNew = new Matrix(2,1); mHatNew[0, 0] = fz[i].X; mHatNew[1, 0] = fz[i].Y; mhat = mhat.Concat(1, mHatNew); break; // add one feature at a time } } #endregion #region show landmarks slamLandmarks.Clear(); slamLandmarksCovariance.Clear(); for (int i = 0; i < landmarkList.Count; i++) { slamLandmarks.Add(landmarkList[i]); slamLandmarksCovariance.Add(Paug.Submatrix(2 * i + 3, 2 * i + 4, 2 * i + 3, 2 * i + 4)); } #endregion #region show correspondences slamCorrespondences.Clear(); for (int i = 0; i < obsvFeatureList.Count; i++) slamCorrespondences.Add(obsvFeatureList[i]); #endregion #region broadcast the results viconLastPose = viconPose; //filteredPose = transformedOdomPose; filteredPose = xhatvPose; lastScan = currentScan; //covMatrix = Pv; // only vehicle xy-submatrix is used in the form covMatrix = Pv; // only vehicle xy-submatrix is used in the form //transformedOdomPose = viconPose; #endregion } } } Thread.Sleep(100); } }