c++ implementation - use with caution
							parent
							
								
									673336545b
								
							
						
					
					
						commit
						d9cd90589c
					
				|  | @ -7,6 +7,7 @@ add_executable(ABC_EqF | |||
|         Direction.cpp | ||||
|         Measurements.cpp | ||||
|         utilities.cpp | ||||
|         runEQF_withcsv.h | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries(ABC_EqF gtsam) | ||||
|  |  | |||
|  | @ -5,23 +5,31 @@ | |||
| #ifndef DIRECTION_H | ||||
| #define DIRECTION_H | ||||
| //#pragma once
 | ||||
| 
 | ||||
| #include <gtsam/geometry/Unit3.h> | ||||
| #include <gtsam/base/Vector.h> | ||||
| 
 | ||||
| using namespace gtsam; | ||||
| 
 | ||||
| /**
 | ||||
|  * Direction class as a S2 element | ||||
|  */ | ||||
| class Direction { | ||||
| public: | ||||
|     Unit3 d;  // Direction (unit vector on S2)
 | ||||
|      | ||||
| 
 | ||||
|     /**
 | ||||
|      * Initialize direction | ||||
|      * @param d_vec Direction vector (must be unit norm) | ||||
|      */ | ||||
|     Direction(const Vector3& d_vec); | ||||
| 
 | ||||
|     // Accessor methods for vector components
 | ||||
|     double x() const { return d.unitVector()[0]; } | ||||
|     double y() const { return d.unitVector()[1]; } | ||||
|     double z() const { return d.unitVector()[2]; } | ||||
| 
 | ||||
|     // Check if the direction contains NaN values
 | ||||
|     bool hasNaN() const { | ||||
|         Vector3 vec = d.unitVector(); | ||||
|         return std::isnan(vec[0]) || std::isnan(vec[1]) || std::isnan(vec[2]); | ||||
|     } | ||||
| }; | ||||
| #endif //DIRECTION_H
 | ||||
|  |  | |||
|  | @ -152,23 +152,43 @@ void EqF::propagation(const Input& u, double dt) { | |||
|     __Sigma = Phi_DT * __Sigma * Phi_DT.transpose() + M_DT; | ||||
| } | ||||
| 
 | ||||
| bool hasNaN(const Vector3& vec) { | ||||
|     return std::isnan(vec[0]) || std::isnan(vec[1]) || std::isnan(vec[2]); | ||||
| } | ||||
| 
 | ||||
| void EqF::update(const Measurement& y) { | ||||
|     if (y.cal_idx > __n_cal) { | ||||
|         throw std::invalid_argument("Calibration index out of range"); | ||||
|   if (y.cal_idx > __n_cal) { | ||||
|     throw std::invalid_argument("Calibration index out of range"); | ||||
|   } | ||||
| 
 | ||||
|   // Get vector representations for checking
 | ||||
|   Vector3 y_vec = y.y.d.unitVector(); | ||||
|   Vector3 d_vec = y.d.d.unitVector(); | ||||
| 
 | ||||
|   // Skip update if any NaN values are present
 | ||||
|   if (std::isnan(y_vec[0]) || std::isnan(y_vec[1]) || std::isnan(y_vec[2]) || | ||||
|       std::isnan(d_vec[0]) || std::isnan(d_vec[1]) || std::isnan(d_vec[2])) { | ||||
|     return;  // Skip this measurement
 | ||||
|     } | ||||
|   static int update_count = 0; | ||||
|   if (update_count < 5) { | ||||
|     std::cout << "Update " << update_count << ":\n"; | ||||
|     std::cout << "y_vec: " << y_vec.transpose() << "\n"; | ||||
|     std::cout << "d_vec: " << d_vec.transpose() << "\n"; | ||||
|     update_count++; | ||||
|   } | ||||
| 
 | ||||
|     Matrix Ct = __measurementMatrixC(y.d, y.cal_idx); | ||||
| 
 | ||||
|     Vector3 action_result = outputAction(__X_hat.inv(), y.y, y.cal_idx); | ||||
|     Vector3 delta_vec = wedge(y.d.d.unitVector()) * action_result; | ||||
| 
 | ||||
|     Matrix Dt = __outputMatrixDt(y.cal_idx); | ||||
|     Matrix S = Ct * __Sigma * Ct.transpose() + Dt * y.Sigma * Dt.transpose(); | ||||
|     Matrix K = __Sigma * Ct.transpose() * S.inverse(); | ||||
| 
 | ||||
|     Vector Delta = __InnovationLift * K * delta_vec; | ||||
|     __X_hat = G::exp(Delta) * __X_hat; | ||||
|     __Sigma = (Matrix::Identity(__dof, __dof) - K * Ct) * __Sigma; | ||||
|   Matrix Ct = __measurementMatrixC(y.d, y.cal_idx); | ||||
|   Vector3 action_result = outputAction(__X_hat.inv(), y.y, y.cal_idx); | ||||
|   Vector3 delta_vec = wedge(y.d.d.unitVector()) * action_result;  // Ensure this is the right operation
 | ||||
|   Matrix Dt = __outputMatrixDt(y.cal_idx); | ||||
|   Matrix S = Ct * __Sigma * Ct.transpose() + Dt * y.Sigma * Dt.transpose(); | ||||
|   Matrix K = __Sigma * Ct.transpose() * S.inverse(); | ||||
|   Vector Delta = __InnovationLift * K * delta_vec; | ||||
|   __X_hat = G::exp(Delta) * __X_hat; | ||||
|   __Sigma = (Matrix::Identity(__dof, __dof) - K * Ct) * __Sigma; | ||||
| } | ||||
| 
 | ||||
| Matrix EqF::__stateMatrixA(const Input& u) const { | ||||
|  | @ -229,20 +249,27 @@ Matrix EqF::__inputMatrixBt() const { | |||
| } | ||||
| 
 | ||||
| Matrix EqF::__measurementMatrixC(const Direction& d, int idx) const { | ||||
|     Matrix Cc = Matrix::Zero(3, 3 * __n_cal); | ||||
|   Matrix Cc = Matrix::Zero(3, 3 * __n_cal); | ||||
| 
 | ||||
|     // If the measurement is related to a sensor that has a calibration state
 | ||||
|     if (idx >= 0) { | ||||
|         Cc.block<3, 3>(0, 3 * idx) = wedge(d.d.unitVector()); | ||||
|     } | ||||
|   // If the measurement is related to a sensor that has a calibration state
 | ||||
|   if (idx >= 0) { | ||||
|     // Cc.block<3, 3>(0, 3 * idx) = wedge(d.d.unitVector()); // WRONG
 | ||||
|     // Set the correct 3x3 block in Cc
 | ||||
|     Cc.block<3, 3>(0, 3 * idx) = wedge(d.d.unitVector()); | ||||
|   } | ||||
| 
 | ||||
|     Matrix3 wedge_d = wedge(d.d.unitVector()); | ||||
|     Matrix result(3, __dof); | ||||
|     result.block<3, 3>(0, 0) = wedge_d; | ||||
|     result.block<3, 3>(0, 3) = Matrix3::Zero(); | ||||
|     result.block(0, 6, 3, 3 * __n_cal) = Cc; | ||||
|   Matrix3 wedge_d = wedge(d.d.unitVector()); | ||||
| 
 | ||||
|     return result; | ||||
|   // This Matrix concatenation was different from the Python version
 | ||||
|   // Create the equivalent of:
 | ||||
|   // Rot3.Hat(d.d.unitVector()) @ np.hstack((Rot3.Hat(d.d.unitVector()), np.zeros((3, 3)), Cc))
 | ||||
| 
 | ||||
|   Matrix temp(3, 6 + 3 * __n_cal); | ||||
|   temp.block<3, 3>(0, 0) = wedge_d; | ||||
|   temp.block<3, 3>(0, 3) = Matrix3::Zero(); | ||||
|   temp.block(0, 6, 3, 3 * __n_cal) = Cc; | ||||
| 
 | ||||
|   return wedge_d * temp; | ||||
| } | ||||
| 
 | ||||
| Matrix EqF::__outputMatrixDt(int idx) const { | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include "Direction.h" | ||||
| #include "Measurements.h" | ||||
| #include "Data.h" | ||||
| #include "runEQF_withcsv.h" | ||||
| #include "utilities.h" | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
|  | @ -158,38 +159,65 @@ void runSimulation(EqF& filter, const std::vector<Data>& data) { | |||
|     std::cout << "Average calibration error (deg): " << (avg_cal_error * 180.0/M_PI) << std::endl; | ||||
| } | ||||
| 
 | ||||
| // int main(int argc, char** argv) {
 | ||||
| //     std::cout << "ABC-EqF: Attitude-Bias-Calibration Equivariant Filter" << std::endl;
 | ||||
| //     std::cout << "========================================================" << std::endl;
 | ||||
| //
 | ||||
| //     // Initialize filter
 | ||||
| //     int n_cal = 1;      // Number of calibration states
 | ||||
| //     int n_sensors = 2;  // Number of sensors
 | ||||
| //
 | ||||
| //     // Initial covariance - larger values for higher uncertainty
 | ||||
| //     Matrix initialSigma = Matrix::Identity(6 + 3*n_cal, 6 + 3*n_cal);
 | ||||
| //     initialSigma.diagonal().head<3>() = Vector3::Constant(0.5); // Attitude uncertainty
 | ||||
| //     initialSigma.diagonal().segment<3>(3) = Vector3::Constant(0.1); // Bias uncertainty
 | ||||
| //     initialSigma.diagonal().tail<3>() = Vector3::Constant(0.5); // Calibration uncertainty
 | ||||
| //
 | ||||
| //     std::cout << "Creating filter with " << n_cal << " calibration states..." << std::endl;
 | ||||
| //
 | ||||
| //     try {
 | ||||
| //         // Create filter
 | ||||
| //         EqF filter(initialSigma, n_cal, n_sensors);
 | ||||
| //
 | ||||
| //         // Generate simulated data
 | ||||
| //         std::cout << "Generating simulated data..." << std::endl;
 | ||||
| //         std::vector<Data> data = loadSimulatedData();
 | ||||
| //
 | ||||
| //         // Run simulation
 | ||||
| //         runSimulation(filter, data);
 | ||||
| //
 | ||||
| //     } catch (const std::exception& e) {
 | ||||
| //         std::cerr << "Error: " << e.what() << std::endl;
 | ||||
| //         return 1;
 | ||||
| //     }
 | ||||
| //
 | ||||
| //     std::cout << "Done." << std::endl;
 | ||||
| //     return 0;
 | ||||
| int main(int argc, char** argv) { | ||||
|     std::cout << "ABC-EqF: Attitude-Bias-Calibration Equivariant Filter" << std::endl; | ||||
|     std::cout << "========================================================" << std::endl; | ||||
| 
 | ||||
|     // Initialize filter
 | ||||
|     int n_cal = 1;      // Number of calibration states
 | ||||
|     int n_sensors = 2;  // Number of sensors
 | ||||
| 
 | ||||
|     // Initial covariance - larger values for higher uncertainty
 | ||||
|     Matrix initialSigma = Matrix::Identity(6 + 3*n_cal, 6 + 3*n_cal); | ||||
|     initialSigma.diagonal().head<3>() = Vector3::Constant(0.5); // Attitude uncertainty
 | ||||
|     initialSigma.diagonal().segment<3>(3) = Vector3::Constant(0.1); // Bias uncertainty
 | ||||
|     initialSigma.diagonal().tail<3>() = Vector3::Constant(0.5); // Calibration uncertainty
 | ||||
| 
 | ||||
|     std::cout << "Creating filter with " << n_cal << " calibration states..." << std::endl; | ||||
| 
 | ||||
|      | ||||
|     std::string csvFilePath; | ||||
|      | ||||
|     // Check if CSV file path is provided as command line argument
 | ||||
|     if (argc > 1) { | ||||
|         csvFilePath = argv[1]; | ||||
|     } else { | ||||
|         std::cout << "Please enter the path to your CSV data file: "; | ||||
|         std::cin >> csvFilePath; | ||||
|     } | ||||
|      | ||||
|     std::cout << "Using CSV data from: " << csvFilePath << std::endl; | ||||
|      | ||||
|     try { | ||||
|         // Create filter
 | ||||
|         EqF filter(initialSigma, n_cal, n_sensors); | ||||
| 
 | ||||
|         // Generate simulated data
 | ||||
|         std::cout << "Generating simulated data..." << std::endl; | ||||
|         std::vector<Data> data = loadSimulatedData(); | ||||
| 
 | ||||
|         // Run simulation
 | ||||
|         runSimulation(filter, data); | ||||
| 
 | ||||
|         // Run with CSV data
 | ||||
|         runEqFWithCSVData(csvFilePath); | ||||
|     } catch (const std::exception& e) { | ||||
|         std::cerr << "Error: " << e.what() << std::endl; | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     std::cout << "Done." << std::endl; | ||||
|     return 0; | ||||
| 
 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue