15 using namespace gtsam;
16 constexpr
size_t N = 1;
28 std::vector<Measurement>
y;
56 int maxRows = -1,
int downsample = 1);
60 int printInterval = 10);
75 int maxRows,
int downsample) {
76 std::vector<Data> data_list;
79 if (!
file.is_open()) {
80 throw std::runtime_error(
"Failed to open file: " +
filename);
83 std::cout <<
"Loading data from " <<
filename <<
"..." << std::flush;
89 double prevTime = 0.0;
92 std::getline(
file, line);
96 while (lineNumber < startRow && std::getline(
file, line)) {
101 while (std::getline(
file, line) && (maxRows == -1 || rowCount < maxRows)) {
105 if ((lineNumber - startRow - 1) % downsample != 0) {
109 std::istringstream
ss(line);
111 std::vector<double>
values;
114 while (std::getline(
ss, token,
',')) {
116 values.push_back(std::stod(token));
117 }
catch (
const std::exception&
e) {
131 double dt = (rowCount == 0) ? 0.0 :
t - prevTime;
142 std::array<Rot3, N>
S = {
Rot3(calQuat)};
152 Matrix inputCov = Matrix::Zero(6, 6);
170 if (
abs(
y0.norm() - 1.0) > 1
e-5)
y0.normalize();
171 if (
abs(d0.norm() - 1.0) > 1
e-5) d0.normalize();
174 Matrix3 covY0 = Matrix3::Zero();
187 if (
abs(
y1.norm() - 1.0) > 1
e-5)
y1.normalize();
188 if (
abs(d1.norm() - 1.0) > 1
e-5) d1.normalize();
191 Matrix3 covY1 = Matrix3::Zero();
205 if (rowCount % 1000 == 0) {
206 std::cout <<
"." << std::flush;
210 std::cout <<
" Done!" << std::endl;
211 std::cout <<
"Loaded " << data_list.size() <<
" data points";
213 if (errorCount > 0) {
214 std::cout <<
" (" << errorCount <<
" errors encountered)";
217 std::cout << std::endl;
225 if (data_list.empty()) {
226 std::cerr <<
"No data to process" << std::endl;
230 std::cout <<
"Processing " << data_list.size() <<
" data points with EqF..."
234 std::vector<double> att_errors;
235 std::vector<double> bias_errors;
236 std::vector<double> cal_errors;
239 auto start = std::chrono::high_resolution_clock::now();
241 int totalMeasurements = 0;
242 int validMeasurements = 0;
245 const double RAD_TO_DEG = 180.0 /
M_PI;
248 int progressStep = data_list.size() / 10;
249 if (progressStep < 1) progressStep = 1;
251 std::cout <<
"Progress: ";
253 for (
size_t i = 0;
i < data_list.size();
i++) {
260 for (
const auto&
y :
data.y) {
275 }
catch (
const std::exception&
e) {
276 std::cerr <<
"Error updating at t=" <<
data.t <<
": " <<
e.what()
287 Vector3 cal_error = Vector3::Zero();
288 if (!
data.xi.S.empty() && !estimate.
S.empty()) {
293 att_errors.push_back(att_error.norm());
294 bias_errors.push_back(bias_error.norm());
295 cal_errors.push_back(cal_error.norm());
298 if (
i % progressStep == 0) {
299 std::cout <<
"." << std::flush;
303 std::cout <<
" Done!" << std::endl;
305 auto end = std::chrono::high_resolution_clock::now();
306 std::chrono::duration<double>
elapsed =
end - start;
309 double avg_att_error = 0.0;
310 double avg_bias_error = 0.0;
311 double avg_cal_error = 0.0;
313 if (!att_errors.empty()) {
314 avg_att_error = std::accumulate(att_errors.begin(), att_errors.end(), 0.0) /
317 std::accumulate(bias_errors.begin(), bias_errors.end(), 0.0) /
319 avg_cal_error = std::accumulate(cal_errors.begin(), cal_errors.end(), 0.0) /
324 const Data& final_data = data_list.back();
328 Vector3 final_bias_error = final_estimate.
b - final_data.
xi.
b;
329 Vector3 final_cal_error = Vector3::Zero();
330 if (!final_data.
xi.
S.empty() && !final_estimate.
S.empty()) {
336 std::cout <<
"\n=== Filter Performance Summary ===" << std::endl;
337 std::cout <<
"Processing time: " <<
elapsed.count() <<
" seconds"
339 std::cout <<
"Processed measurements: " << totalMeasurements
340 <<
" (valid: " << validMeasurements <<
")" << std::endl;
343 std::cout <<
"\n-- Average Errors --" << std::endl;
344 std::cout <<
"Attitude: " << (avg_att_error * RAD_TO_DEG) <<
"°" << std::endl;
345 std::cout <<
"Bias: " << avg_bias_error << std::endl;
346 std::cout <<
"Calibration: " << (avg_cal_error * RAD_TO_DEG) <<
"°"
350 std::cout <<
"\n-- Final Errors --" << std::endl;
351 std::cout <<
"Attitude: " << (final_att_error.norm() * RAD_TO_DEG) <<
"°"
353 std::cout <<
"Bias: " << final_bias_error.norm() << std::endl;
354 std::cout <<
"Calibration: " << (final_cal_error.norm() * RAD_TO_DEG) <<
"°"
358 std::cout <<
"\n-- Final State vs Ground Truth --" << std::endl;
359 std::cout <<
"Attitude (RPY) - Estimate: "
360 << (final_estimate.
R.
rpy() * RAD_TO_DEG).transpose()
361 <<
"° | Truth: " << (final_data.
xi.
R.
rpy() * RAD_TO_DEG).transpose()
363 std::cout <<
"Bias - Estimate: " << final_estimate.
b.transpose()
364 <<
" | Truth: " << final_data.
xi.
b.transpose() << std::endl;
366 if (!final_estimate.
S.empty() && !final_data.
xi.
S.empty()) {
367 std::cout <<
"Calibration (RPY) - Estimate: "
368 << (final_estimate.
S[0].rpy() * RAD_TO_DEG).transpose()
370 << (final_data.
xi.
S[0].rpy() * RAD_TO_DEG).transpose() <<
"°"
375 int main(
int argc,
char* argv[]) {
376 std::cout <<
"ABC-EqF: Attitude-Bias-Calibration Equivariant Filter Demo"
378 std::cout <<
"=============================================================="
383 std::string csvFilePath;
388 csvFilePath = argv[1];
393 }
catch (
const std::exception&
e) {
394 std::cerr <<
"Error: Could not find EqFdata.csv" << std::endl;
395 std::cerr <<
"Usage: " << argv[0]
396 <<
" [csv_file_path] [max_rows] [downsample]" << std::endl;
403 maxRows = std::stoi(argv[2]);
407 downsample = std::stoi(argv[3]);
411 std::vector<Data>
data =
415 std::cerr <<
"No data available to process. Exiting." << std::endl;
423 Matrix initialSigma = Matrix::Identity(6 + 3 *
N, 6 + 3 *
N);
424 initialSigma.diagonal().head<3>() =
425 Vector3::Constant(0.1);
426 initialSigma.diagonal().segment<3>(3) =
427 Vector3::Constant(0.01);
428 initialSigma.diagonal().tail<3>() =
429 Vector3::Constant(0.1);
432 EqFilter filter(initialSigma, n_sensors);
437 }
catch (
const std::exception&
e) {
438 std::cerr <<
"Error: " <<
e.what() << std::endl;
442 std::cout <<
"\nEqF demonstration completed successfully." << std::endl;