Created
August 10, 2017 20:50
-
-
Save pablovela5620/2d56018f8c98df40033b99a4a5a6154b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "FusionEKF.h" | |
#include "tools.h" | |
#include "Eigen/Dense" | |
#include <iostream> | |
using namespace std; | |
using Eigen::MatrixXd; | |
using Eigen::VectorXd; | |
using std::vector; | |
/* | |
* Constructor. | |
*/ | |
FusionEKF::FusionEKF() { | |
is_initialized_ = false; | |
previous_timestamp_ = 0; | |
// initializing matrices | |
R_laser_ = MatrixXd(2, 2); | |
R_radar_ = MatrixXd(3, 3); | |
H_laser_ = MatrixXd(2, 4); | |
H_radar = MatrixXd(3, 4); | |
//measurement covariance matrix - laser | |
R_laser_ << 0.0225, 0, | |
0, 0.0225; | |
//measurement covariance matrix - radar | |
R_radar_ << 0.09, 0, 0, | |
0, 0.0009, 0, | |
0, 0, 0.09; | |
/** | |
TODO: | |
* Finish initializing the FusionEKF. | |
* Set the process and measurement noises | |
*/ | |
H_laser_ << 1, 0, 0, 0, //from section 10 lesson 5 | |
0, 1, 0, 0; | |
H_radar << 1, 1, 0, 0, | |
1, 1, 0, 0, | |
1, 1, 1, 1; | |
ekf_.F_ = MatrixXd(4, 4); // 4x4 matrix (initial state transition) | |
ekf_.F_ << 1, 0, 1, 0, | |
0, 1, 0, 1, | |
0, 0, 1, 0, | |
0, 0, 0, 1; | |
ekf_.P_ = MatrixXd(4, 4);// 4x4 matrix (covariance) | |
ekf_.P_ << 1, 0, 0, 0, | |
0, 1, 0, 0, | |
0, 0, 1000, 0, | |
0, 0, 0, 1000; | |
//set the acceleration noise components | |
noise_ax = 9;//provided in quiz as 9 in seciont 13 lesson 5 (sigmax^2) | |
noise_ay = 9;//provided in quiz as 9 | |
} | |
/** | |
* Destructor. | |
*/ | |
FusionEKF::~FusionEKF() {} | |
void FusionEKF::ProcessMeasurement(const MeasurementPackage &measurement_pack) { | |
/***************************************************************************** | |
* Initialization | |
****************************************************************************/ | |
if (!is_initialized_) { | |
/** | |
TODO: | |
* Initialize the state ekf_.x_ with the first measurement. | |
* Create the covariance matrix. | |
* Remember: you'll need to convert radar from polar to cartesian coordinates. | |
*/ | |
// first measurement | |
cout << "EKF: " << endl; | |
ekf_.x_ = VectorXd(4); | |
ekf_.x_ << 1, 1, 1, 1;// this value is important for the RMSE | |
if (measurement_pack.sensor_type_ == MeasurementPackage::RADAR) { | |
/** | |
Convert radar from polar to cartesian coordinates and initialize state. | |
*/ | |
//just set ekf_.x_(0) to ro*cos(theta) | |
float rho = measurement_pack.raw_measurements_(0); | |
float theta = measurement_pack.raw_measurements_(1); | |
float rho_dot = measurement_pack.raw_measurements_(2); | |
ekf_.x_(0) = rho * cos(theta); | |
ekf_.x_(1) = rho * sin(theta); | |
ekf_.x_(2) = rho_dot * cos(theta); | |
ekf_.x_(3) = rho_dot * sin(theta); | |
} else if (measurement_pack.sensor_type_ == MeasurementPackage::LASER) { | |
/** | |
Initialize state. | |
*/ | |
//set ekf_.x_(0) to x | |
ekf_.x_(0) = measurement_pack.raw_measurements_(0); | |
//set ekf_.x_(1) to y | |
ekf_.x_(1) = measurement_pack.raw_measurements_(1); | |
} | |
previous_timestamp_ = measurement_pack.timestamp_; | |
// done initializing, no need to predict or update | |
is_initialized_ = true; | |
return; | |
} | |
/***************************************************************************** | |
* Prediction | |
****************************************************************************/ | |
/** | |
TODO: FOUND IN SECTION 8 LESSON 5 | |
* Update the state transition matrix F according to the new elapsed time. | |
- Time is measured in seconds. | |
* Update the process noise covariance matrix. | |
* Use noise_ax = 9 and noise_ay = 9 for your Q matrix. | |
*/ | |
float dt = (measurement_pack.timestamp_ - previous_timestamp_) / 1000000.0; //dt - expressed in seconds | |
previous_timestamp_ = measurement_pack.timestamp_; | |
float dt_2 = dt * dt; | |
float dt_3 = dt_2 * dt; | |
float dt_4 = dt_3 * dt; | |
//Modify the F matrix so that the time is integrated | |
ekf_.F_(0, 2) = dt; | |
ekf_.F_(1, 3) = dt; | |
//set the process covariance matrix Q Section 9 Lesson 5 | |
ekf_.Q_ = MatrixXd(4, 4); | |
ekf_.Q_ << dt_4 / 4 * noise_ax, 0, dt_3 / 2 * noise_ax, 0, | |
0, dt_4 / 4 * noise_ay, 0, dt_3 / 2 * noise_ay, | |
dt_3 / 2 * noise_ax, 0, dt_2 * noise_ax, 0, | |
0, dt_3 / 2 * noise_ay, 0, dt_2 * noise_ay; | |
ekf_.Predict(); | |
/***************************************************************************** | |
* Update | |
****************************************************************************/ | |
/** | |
TODO: | |
* Use the sensor type to perform the update step. | |
* Update the state and covariance matrices. | |
*/ | |
if (measurement_pack.sensor_type_ == MeasurementPackage::RADAR) { | |
// Radar updates | |
//set ekf_.H_ by setting to Hj which is the calculated the jacobian | |
Tools tools; | |
H_radar = tools.CalculateJacobian(ekf_.x_); | |
ekf_.H_ = H_radar; | |
//set ekf_.R_ by just using R_radar_ | |
ekf_.R_ = R_radar_; | |
ekf_.UpdateEKF(measurement_pack.raw_measurements_); | |
} else { | |
// Laser updates | |
// set ekf_.H_ by just using H_laser_; | |
ekf_.H_ = H_laser_; | |
// set ekf_.R_ by just using R_laser_; | |
ekf_.R_ = R_laser_; | |
ekf_.Update(measurement_pack.raw_measurements_); | |
} | |
// print the output | |
cout << "x_ = " << ekf_.x_ << endl; | |
cout << "P_ = " << ekf_.P_ << endl; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "kalman_filter.h" | |
using Eigen::MatrixXd; | |
using Eigen::VectorXd; | |
KalmanFilter::KalmanFilter() {} | |
KalmanFilter::~KalmanFilter() {} | |
void KalmanFilter::Init(VectorXd &x_in, MatrixXd &P_in, MatrixXd &F_in, | |
MatrixXd &H_in, MatrixXd &R_in, MatrixXd &Q_in) { | |
x_ = x_in; | |
P_ = P_in; | |
F_ = F_in; | |
H_ = H_in; | |
R_ = R_in; | |
Q_ = Q_in; | |
} | |
void KalmanFilter::Predict() { | |
/** | |
TODO: | |
* predict the state | |
*/ | |
x_ = F_ * x_; | |
MatrixXd Ft = F_.transpose(); | |
P_ = F_ * P_ * Ft + Q_; | |
} | |
void KalmanFilter::Update(const VectorXd &z) { | |
/** | |
TODO: | |
* update the state by using Kalman Filter equations | |
*/ | |
VectorXd y = z - H_ * x_; //z_pred = H_ * x_ | |
MatrixXd Ht = H_.transpose(); | |
MatrixXd S = H_ * P_ * Ht + R_; | |
MatrixXd Si = S.inverse(); | |
MatrixXd K = P_ * Ht * Si; | |
long x_size = x_.size(); | |
MatrixXd I = MatrixXd::Identity(x_size, x_size); | |
//new state | |
x_ = x_ + (K * y); | |
P_ = (I - K * H_) * P_; | |
} | |
void KalmanFilter::UpdateEKF(const VectorXd &z) { | |
/** | |
TODO: | |
* update the state by using Extended Kalman Filter equations | |
*/ | |
float px = x_(0); | |
float py = x_(1); | |
float vx = x_(2); | |
float vy = x_(3); | |
float rho = sqrt(px*px+py*py); | |
float phi = atan2(py,px); | |
float rho_dot; | |
if(fabs(rho)<0.0001){ | |
rho_dot =0; | |
} else{ | |
rho_dot = ((px*vx)+(py*vy))/rho; | |
} | |
VectorXd z_radar(3); | |
z_radar << rho, phi, rho_dot; | |
VectorXd y = z - z_radar; | |
MatrixXd Ht = H_.transpose(); | |
MatrixXd S = H_ * P_ * Ht + R_; | |
MatrixXd Si = S.inverse(); | |
MatrixXd K = P_ * Ht * Si; | |
long x_size = x_.size(); | |
MatrixXd I = MatrixXd::Identity(x_size, x_size); | |
//new state | |
x_ = x_ + (K * y); | |
P_ = (I - K * H_) * P_; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include "tools.h" | |
using Eigen::VectorXd; | |
using Eigen::MatrixXd; | |
using std::vector; | |
Tools::Tools() {} | |
Tools::~Tools() {} | |
VectorXd Tools::CalculateRMSE(const vector<VectorXd> &estimations, | |
const vector<VectorXd> &ground_truth) { | |
/** | |
TODO: | |
* Calculate the RMSE here. | |
*/ | |
VectorXd rmse(4); | |
rmse << 0, 0, 0, 0; | |
// check the validity of the following inputs: | |
// * the estimation vector size should not be zero | |
// * the estimation vector size should equal ground truth vector size | |
if (estimations.size() != ground_truth.size() | |
|| estimations.size() == 0) { | |
cout << "Invalid estimation or ground_truth data" << endl; | |
return rmse; | |
} | |
//accumulate sqared residuals | |
for (unsigned int i = 0; i < estimations.size(); ++i) { | |
VectorXd residual = estimations[i] - ground_truth[i]; | |
//coefficient-wise multiplication | |
residual = residual.array() * residual.array(); | |
rmse += residual; | |
} | |
//calculate the mean | |
rmse = rmse / estimations.size(); | |
//calculate the squared root | |
rmse = rmse.array().sqrt(); | |
//return the result | |
return rmse; | |
} | |
MatrixXd Tools::CalculateJacobian(const VectorXd &x_state) { | |
/** | |
TODO: | |
* Calculate a Jacobian here. | |
*/ | |
MatrixXd Hj(3, 4); | |
//recover state parameters | |
float px = x_state(0); | |
float py = x_state(1); | |
float vx = x_state(2); | |
float vy = x_state(3); | |
//pre-compute a set of terms to avoid repeated calculations | |
float c1 = px * px + py * py; | |
float c2 = sqrt(c1); | |
float c3 = (c1 * c2); | |
//check division by zero | |
if (fabs(c1) < 0.0001) { | |
cout << "CalculateJacobian() - Error - Division by Zero" << endl; | |
return Hj; | |
} | |
//compute the Jacobian matrix | |
Hj << (px / c2), (py / c2), 0, 0, | |
-(py / c1), (px / c1), 0, 0, | |
py * (vx * py - vy * px) / c3, px * (px * vy - py * vx) / c3, px / c2, py / c2; | |
return Hj; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment