From 6aed1685ed3b8641f3c693f31734b21d07ee5719 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Thu, 24 Sep 2020 15:44:29 -0400 Subject: [PATCH 001/261] adding robust cost function - version 1 --- gtsam/sfm/BinaryMeasurement.h | 7 +++- gtsam/sfm/ShonanAveraging.cpp | 47 ++++++++++++++++++------- gtsam/sfm/ShonanAveraging.h | 13 +++++++ gtsam/sfm/tests/testShonanAveraging.cpp | 24 +++++++++++++ 4 files changed, 78 insertions(+), 13 deletions(-) diff --git a/gtsam/sfm/BinaryMeasurement.h b/gtsam/sfm/BinaryMeasurement.h index c525c1b9e..9540564e0 100644 --- a/gtsam/sfm/BinaryMeasurement.h +++ b/gtsam/sfm/BinaryMeasurement.h @@ -71,6 +71,11 @@ public: this->noiseModel_->print(" noise model: "); } + void makeNoiseModelRobust(){ + this->noiseModel_ = noiseModel::Robust::Create( + noiseModel::mEstimator::Huber::Create(1.345), this->noiseModel_); + } + bool equals(const BinaryMeasurement &expected, double tol = 1e-9) const { const BinaryMeasurement *e = dynamic_cast *>(&expected); @@ -80,4 +85,4 @@ public: } /// @} }; -} // namespace gtsam \ No newline at end of file +} // namespace gtsam diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index df2d72c28..e99328302 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -53,7 +53,8 @@ ShonanAveragingParameters::ShonanAveragingParameters( optimalityThreshold(optimalityThreshold), alpha(alpha), beta(beta), - gamma(gamma) { + gamma(gamma), + useHuber(false){ // By default, we will do conjugate gradient lm.linearSolverType = LevenbergMarquardtParams::Iterative; @@ -819,9 +820,15 @@ template class ShonanAveraging<2>; ShonanAveraging2::ShonanAveraging2(const Measurements &measurements, const Parameters ¶meters) - : ShonanAveraging<2>(measurements, parameters) {} + : ShonanAveraging<2>(measurements, parameters) { + if (parameters.useHuber == true) + std::cout << "Parameter useHuber is disregarded when you pass measurements to ShonanAveraging2." + "Pass g2o file as input to enable this functionality" << std::endl; +} + ShonanAveraging2::ShonanAveraging2(string g2oFile, const Parameters ¶meters) - : ShonanAveraging<2>(parseMeasurements(g2oFile), parameters) {} + : ShonanAveraging<2>(parseMeasurements(g2oFile, + parameters.useHuber? nullptr : nullptr), parameters) {} /* ************************************************************************* */ // Explicit instantiation for d=3 @@ -829,17 +836,22 @@ template class ShonanAveraging<3>; ShonanAveraging3::ShonanAveraging3(const Measurements &measurements, const Parameters ¶meters) - : ShonanAveraging<3>(measurements, parameters) {} + : ShonanAveraging<3>(measurements, parameters) { + if (parameters.useHuber == true) + std::cout << "Parameter useHuber is disregarded when you pass measurements to ShonanAveraging2." + "Pass g2o file as input to enable this functionality" << std::endl; +} ShonanAveraging3::ShonanAveraging3(string g2oFile, const Parameters ¶meters) - : ShonanAveraging<3>(parseMeasurements(g2oFile), parameters) {} + : ShonanAveraging<3>(parseMeasurements(g2oFile, + parameters.useHuber? nullptr : nullptr), parameters) {} // TODO(frank): Deprecate after we land pybind wrapper // Extract Rot3 measurement from Pose3 betweenfactors // Modeled after similar function in dataset.cpp static BinaryMeasurement convert( - const BetweenFactor::shared_ptr &f) { + const BetweenFactor::shared_ptr &f, bool useHuber = false) { auto gaussian = boost::dynamic_pointer_cast(f->noiseModel()); if (!gaussian) @@ -847,22 +859,33 @@ static BinaryMeasurement convert( "parseMeasurements can only convert Pose3 measurements " "with Gaussian noise models."); const Matrix6 M = gaussian->covariance(); - return BinaryMeasurement( - f->key1(), f->key2(), f->measured().rotation(), - noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3), true)); + if(!useHuber){ + return BinaryMeasurement( + f->key1(), f->key2(), f->measured().rotation(), + noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3), true)); + }else{ // wrap noise mode in Huber loss + std::cout << "setting robust huber loss " << std::endl; + return BinaryMeasurement( + f->key1(), f->key2(), f->measured().rotation(), + noiseModel::Robust::Create( + noiseModel::mEstimator::Huber::Create(1.345), + noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3), true))); + } } static ShonanAveraging3::Measurements extractRot3Measurements( - const BetweenFactorPose3s &factors) { + const BetweenFactorPose3s &factors, bool useHuber = false) { ShonanAveraging3::Measurements result; result.reserve(factors.size()); - for (auto f : factors) result.push_back(convert(f)); + for (auto f : factors) result.push_back(convert(f,useHuber)); return result; } ShonanAveraging3::ShonanAveraging3(const BetweenFactorPose3s &factors, const Parameters ¶meters) - : ShonanAveraging<3>(extractRot3Measurements(factors), parameters) {} + : ShonanAveraging<3>(parameters.useHuber? + extractRot3Measurements(factors) : + extractRot3Measurements(factors), parameters) {} /* ************************************************************************* */ } // namespace gtsam diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index edd9f33a2..9718805b8 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -53,6 +53,7 @@ struct GTSAM_EXPORT ShonanAveragingParameters { double alpha; // weight of anchor-based prior (default 0) double beta; // weight of Karcher-based prior (default 1) double gamma; // weight of gauge-fixing factors (default 0) + bool useHuber; // if enabled, the Huber loss is used in the optimization (default is false) ShonanAveragingParameters(const LevenbergMarquardtParams &lm = LevenbergMarquardtParams::CeresDefaults(), @@ -77,6 +78,18 @@ struct GTSAM_EXPORT ShonanAveragingParameters { void setGaugesWeight(double value) { gamma = value; } double getGaugesWeight() { return gamma; } + + void setUseHuber(bool value) { useHuber = value; } + bool getUseHuber() { return useHuber; } + + void print() const { + std::cout << " ShonanAveragingParameters: " << std::endl; + std::cout << " alpha: " << alpha << std::endl; + std::cout << " beta: " << beta << std::endl; + std::cout << " gamma: " << gamma << std::endl; + std::cout << " useHuber: " << useHuber << std::endl; + std::cout << " --------------------------" << std::endl; + } }; using ShonanAveragingParameters2 = ShonanAveragingParameters<2>; diff --git a/gtsam/sfm/tests/testShonanAveraging.cpp b/gtsam/sfm/tests/testShonanAveraging.cpp index 1200c8ebb..e23f9e20b 100644 --- a/gtsam/sfm/tests/testShonanAveraging.cpp +++ b/gtsam/sfm/tests/testShonanAveraging.cpp @@ -321,6 +321,30 @@ TEST(ShonanAveraging2, noisyToyGraph) { EXPECT_DOUBLES_EQUAL(0, result.second, 1e-10); // certificate! } +/* ************************************************************************* */ +TEST(ShonanAveraging2, noisyToyGraphWithHuber) { + // Load 2D toy example + auto lmParams = LevenbergMarquardtParams::CeresDefaults(); + string g2oFile = findExampleDataFile("noisyToyGraph.txt"); + ShonanAveraging2::Parameters parameters(lmParams); + auto measurements = parseMeasurements(g2oFile); + std::cout << "----- changing huber before " << std::endl; + parameters.setUseHuber(true); + parameters.print(); + std::cout << "----- changing huber after " << std::endl; + ShonanAveraging2 shonan(measurements, parameters); + EXPECT_LONGS_EQUAL(4, shonan.nrUnknowns()); + + // Check graph building + NonlinearFactorGraph graph = shonan.buildGraphAt(2); + graph.print(); + EXPECT_LONGS_EQUAL(6, graph.size()); + auto initial = shonan.initializeRandomly(kRandomNumberGenerator); + auto result = shonan.run(initial, 2); + EXPECT_DOUBLES_EQUAL(0.0008211, shonan.cost(result.first), 1e-6); + EXPECT_DOUBLES_EQUAL(0, result.second, 1e-10); // certificate! +} + /* ************************************************************************* */ // Test alpha/beta/gamma prior weighting. TEST(ShonanAveraging3, PriorWeights) { From 001a55ad3a53fcd97c07dae4fee66225b29012d1 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Thu, 24 Sep 2020 16:35:41 -0400 Subject: [PATCH 002/261] robust noise in place - test fails due to non-isotropic covariance? --- gtsam/sfm/ShonanAveraging.cpp | 47 +++++++++---------------- gtsam/sfm/ShonanAveraging.h | 9 +++++ gtsam/sfm/tests/testShonanAveraging.cpp | 2 -- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index e99328302..1e6fcf6da 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -820,15 +820,13 @@ template class ShonanAveraging<2>; ShonanAveraging2::ShonanAveraging2(const Measurements &measurements, const Parameters ¶meters) - : ShonanAveraging<2>(measurements, parameters) { - if (parameters.useHuber == true) - std::cout << "Parameter useHuber is disregarded when you pass measurements to ShonanAveraging2." - "Pass g2o file as input to enable this functionality" << std::endl; -} + : ShonanAveraging<2>(parameters.useHuber? + makeNoiseModelRobust(measurements) : measurements, parameters) {} ShonanAveraging2::ShonanAveraging2(string g2oFile, const Parameters ¶meters) - : ShonanAveraging<2>(parseMeasurements(g2oFile, - parameters.useHuber? nullptr : nullptr), parameters) {} + : ShonanAveraging<2>(parameters.useHuber? + makeNoiseModelRobust( parseMeasurements(g2oFile) ) : + parseMeasurements(g2oFile), parameters) {} /* ************************************************************************* */ // Explicit instantiation for d=3 @@ -836,22 +834,20 @@ template class ShonanAveraging<3>; ShonanAveraging3::ShonanAveraging3(const Measurements &measurements, const Parameters ¶meters) - : ShonanAveraging<3>(measurements, parameters) { - if (parameters.useHuber == true) - std::cout << "Parameter useHuber is disregarded when you pass measurements to ShonanAveraging2." - "Pass g2o file as input to enable this functionality" << std::endl; -} + : ShonanAveraging<3>(parameters.useHuber? + makeNoiseModelRobust(measurements) : measurements, parameters) {} ShonanAveraging3::ShonanAveraging3(string g2oFile, const Parameters ¶meters) - : ShonanAveraging<3>(parseMeasurements(g2oFile, - parameters.useHuber? nullptr : nullptr), parameters) {} + : ShonanAveraging<3>(parameters.useHuber? + makeNoiseModelRobust( parseMeasurements(g2oFile) ) : + parseMeasurements(g2oFile), parameters) {} // TODO(frank): Deprecate after we land pybind wrapper // Extract Rot3 measurement from Pose3 betweenfactors // Modeled after similar function in dataset.cpp static BinaryMeasurement convert( - const BetweenFactor::shared_ptr &f, bool useHuber = false) { + const BetweenFactor::shared_ptr &f) { auto gaussian = boost::dynamic_pointer_cast(f->noiseModel()); if (!gaussian) @@ -859,32 +855,23 @@ static BinaryMeasurement convert( "parseMeasurements can only convert Pose3 measurements " "with Gaussian noise models."); const Matrix6 M = gaussian->covariance(); - if(!useHuber){ - return BinaryMeasurement( - f->key1(), f->key2(), f->measured().rotation(), - noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3), true)); - }else{ // wrap noise mode in Huber loss - std::cout << "setting robust huber loss " << std::endl; - return BinaryMeasurement( - f->key1(), f->key2(), f->measured().rotation(), - noiseModel::Robust::Create( - noiseModel::mEstimator::Huber::Create(1.345), - noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3), true))); - } + return BinaryMeasurement( + f->key1(), f->key2(), f->measured().rotation(), + noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3), true)); } static ShonanAveraging3::Measurements extractRot3Measurements( - const BetweenFactorPose3s &factors, bool useHuber = false) { + const BetweenFactorPose3s &factors) { ShonanAveraging3::Measurements result; result.reserve(factors.size()); - for (auto f : factors) result.push_back(convert(f,useHuber)); + for (auto f : factors) result.push_back(convert(f)); return result; } ShonanAveraging3::ShonanAveraging3(const BetweenFactorPose3s &factors, const Parameters ¶meters) : ShonanAveraging<3>(parameters.useHuber? - extractRot3Measurements(factors) : + makeNoiseModelRobust( extractRot3Measurements(factors) ): extractRot3Measurements(factors), parameters) {} /* ************************************************************************* */ diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index 9718805b8..6efcb045b 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -164,6 +164,15 @@ class GTSAM_EXPORT ShonanAveraging { return measurements_[k]; } + /// wrap factors with robust Huber loss + static Measurements makeNoiseModelRobust(Measurements measurements){ + Measurements robustMeasurements = measurements; + for (auto &measurement : robustMeasurements) { + measurement.makeNoiseModelRobust(); + } + return robustMeasurements; + } + /// k^th measurement, as a Rot. const Rot &measured(size_t k) const { return measurements_[k].measured(); } diff --git a/gtsam/sfm/tests/testShonanAveraging.cpp b/gtsam/sfm/tests/testShonanAveraging.cpp index e23f9e20b..ae24094de 100644 --- a/gtsam/sfm/tests/testShonanAveraging.cpp +++ b/gtsam/sfm/tests/testShonanAveraging.cpp @@ -328,10 +328,8 @@ TEST(ShonanAveraging2, noisyToyGraphWithHuber) { string g2oFile = findExampleDataFile("noisyToyGraph.txt"); ShonanAveraging2::Parameters parameters(lmParams); auto measurements = parseMeasurements(g2oFile); - std::cout << "----- changing huber before " << std::endl; parameters.setUseHuber(true); parameters.print(); - std::cout << "----- changing huber after " << std::endl; ShonanAveraging2 shonan(measurements, parameters); EXPECT_LONGS_EQUAL(4, shonan.nrUnknowns()); From 73600c8faaa830d3ca5db3dbbd42ab2048028323 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Thu, 24 Sep 2020 17:06:20 -0400 Subject: [PATCH 003/261] solving issue with robust model --- gtsam/sfm/ShonanAveraging.cpp | 26 +++++++++++++++++-------- gtsam/sfm/tests/testShonanAveraging.cpp | 2 +- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 1e6fcf6da..8fcfbeb26 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -337,14 +337,24 @@ double ShonanAveraging::cost(const Values &values) const { // Get kappa from noise model template static double Kappa(const BinaryMeasurement &measurement) { - const auto &isotropic = boost::dynamic_pointer_cast( - measurement.noiseModel()); - if (!isotropic) { - throw std::invalid_argument( - "Shonan averaging noise models must be isotropic."); - } - const double sigma = isotropic->sigma(); - return 1.0 / (sigma * sigma); + const auto &isotropic = boost::dynamic_pointer_cast( + measurement.noiseModel()); + double sigma; + if (isotropic) { + sigma = isotropic->sigma(); + } else{ + const auto &robust = boost::dynamic_pointer_cast( + measurement.noiseModel()); + if (robust) { + std::cout << "Verification of optimality does not work with robust cost function" << std::endl; + sigma = 1; // setting arbitrary value + }else{ + throw std::invalid_argument( + "Shonan averaging noise models must be isotropic (but robust losses are allowed)."); + + } + } + return 1.0 / (sigma * sigma); } /* ************************************************************************* */ diff --git a/gtsam/sfm/tests/testShonanAveraging.cpp b/gtsam/sfm/tests/testShonanAveraging.cpp index ae24094de..e2fa9c22a 100644 --- a/gtsam/sfm/tests/testShonanAveraging.cpp +++ b/gtsam/sfm/tests/testShonanAveraging.cpp @@ -338,7 +338,7 @@ TEST(ShonanAveraging2, noisyToyGraphWithHuber) { graph.print(); EXPECT_LONGS_EQUAL(6, graph.size()); auto initial = shonan.initializeRandomly(kRandomNumberGenerator); - auto result = shonan.run(initial, 2); + auto result = shonan.run(initial, 2, 3); EXPECT_DOUBLES_EQUAL(0.0008211, shonan.cost(result.first), 1e-6); EXPECT_DOUBLES_EQUAL(0, result.second, 1e-10); // certificate! } From 564e623f44ff1f85fb45227a5f2765f09fef4673 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Thu, 24 Sep 2020 18:24:23 -0400 Subject: [PATCH 004/261] attempting robustification in Frobenius factor --- gtsam/sfm/ShonanAveraging.cpp | 34 +++++++++++++++++++++---- gtsam/sfm/tests/testShonanAveraging.cpp | 18 ++++++++----- gtsam/slam/FrobeniusFactor.cpp | 19 +++++++++++--- 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 8fcfbeb26..0ac893b7c 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -139,13 +139,21 @@ ShonanAveraging::ShonanAveraging(const Measurements &measurements, /* ************************************************************************* */ template NonlinearFactorGraph ShonanAveraging::buildGraphAt(size_t p) const { - NonlinearFactorGraph graph; + std::cout << "zz0" << std::endl; + NonlinearFactorGraph graph; auto G = boost::make_shared(SO<-1>::VectorizedGenerators(p)); + + std::cout << "zz1" << std::endl; for (const auto &measurement : measurements_) { const auto &keys = measurement.keys(); const auto &Rij = measurement.measured(); const auto &model = measurement.noiseModel(); + measurement.print("measurement"); + std::cout << "zzzz1" << std::endl; + model->print(); + std::cout << "zzzz2" << std::endl; graph.emplace_shared>(keys[0], keys[1], Rij, p, model, G); + std::cout << "zzzz3" << std::endl; } // Possibly add Karcher prior @@ -153,13 +161,13 @@ NonlinearFactorGraph ShonanAveraging::buildGraphAt(size_t p) const { const size_t dim = SOn::Dimension(p); graph.emplace_shared>(graph.keys(), dim); } - + std::cout << "zz2" << std::endl; // Possibly add gauge factors - they are probably useless as gradient is zero if (parameters_.gamma > 0 && p > d + 1) { for (auto key : graph.keys()) graph.emplace_shared(key, p, d, parameters_.gamma); } - + std::cout << "z3" << std::endl; return graph; } @@ -177,6 +185,7 @@ ShonanAveraging::createOptimizerAt(size_t p, const Values &initial) const { // Build graph NonlinearFactorGraph graph = buildGraphAt(p); + std::cout << "yy1" << std::endl; // Anchor prior is added here as depends on initial value (and cost is zero) if (parameters_.alpha > 0) { size_t i; @@ -187,7 +196,7 @@ ShonanAveraging::createOptimizerAt(size_t p, const Values &initial) const { graph.emplace_shared>(i, SOn::Lift(p, value.matrix()), model); } - + std::cout << "yy2" << std::endl; // Optimize return boost::make_shared(graph, initial, parameters_.lm); @@ -197,7 +206,9 @@ ShonanAveraging::createOptimizerAt(size_t p, const Values &initial) const { template Values ShonanAveraging::tryOptimizingAt(size_t p, const Values &initial) const { - auto lm = createOptimizerAt(p, initial); + std::cout << "xx1" << std::endl; + auto lm = createOptimizerAt(p, initial); + std::cout << "xx2" << std::endl; return lm->optimize(); } @@ -803,17 +814,29 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, Values initialSOp = LiftTo(pMin, initialEstimate); // lift to pMin! for (size_t p = pMin; p <= pMax; p++) { // Optimize until convergence at this level + std::cout << "4a" << std::endl; Qstar = tryOptimizingAt(p, initialSOp); + std::cout << "4aa" << std::endl; + if(parameters_.useHuber){ // in this case, there is no optimality verification + std::cout << "4aaa" << std::endl; + if(pMin!=pMax) + std::cout << "When using robust norm, Shonan only tests a single rank" << std::endl; + const Values SO3Values = roundSolution(Qstar); + return std::make_pair(SO3Values, 0); + } + std::cout << "4b" << std::endl; // Check certificate of global optimzality Vector minEigenVector; double minEigenValue = computeMinEigenValue(Qstar, &minEigenVector); + std::cout << "4bb" << std::endl; if (minEigenValue > parameters_.optimalityThreshold) { // If at global optimum, round and return solution const Values SO3Values = roundSolution(Qstar); return std::make_pair(SO3Values, minEigenValue); } + std::cout << "4c" << std::endl; // Not at global optimimum yet, so check whether we will go to next level if (p != pMax) { // Calculate initial estimate for next level by following minEigenVector @@ -821,6 +844,7 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, initializeWithDescent(p + 1, Qstar, minEigenVector, minEigenValue); } } + std::cout << "4d" << std::endl; throw std::runtime_error("Shonan::run did not converge for given pMax"); } diff --git a/gtsam/sfm/tests/testShonanAveraging.cpp b/gtsam/sfm/tests/testShonanAveraging.cpp index e2fa9c22a..fd4d5e34f 100644 --- a/gtsam/sfm/tests/testShonanAveraging.cpp +++ b/gtsam/sfm/tests/testShonanAveraging.cpp @@ -330,17 +330,23 @@ TEST(ShonanAveraging2, noisyToyGraphWithHuber) { auto measurements = parseMeasurements(g2oFile); parameters.setUseHuber(true); parameters.print(); + std::cout << "1" << std::endl; ShonanAveraging2 shonan(measurements, parameters); EXPECT_LONGS_EQUAL(4, shonan.nrUnknowns()); // Check graph building - NonlinearFactorGraph graph = shonan.buildGraphAt(2); - graph.print(); - EXPECT_LONGS_EQUAL(6, graph.size()); + std::cout << "2" << std::endl; +// NonlinearFactorGraph graph = shonan.buildGraphAt(2); +// graph.print(); +// EXPECT_LONGS_EQUAL(6, graph.size()); + std::cout << "3" << std::endl; + auto initial = shonan.initializeRandomly(kRandomNumberGenerator); - auto result = shonan.run(initial, 2, 3); - EXPECT_DOUBLES_EQUAL(0.0008211, shonan.cost(result.first), 1e-6); - EXPECT_DOUBLES_EQUAL(0, result.second, 1e-10); // certificate! + std::cout << "4" << std::endl; + auto result = shonan.run(initial, 2,3); + std::cout << "5" << std::endl; +// EXPECT_DOUBLES_EQUAL(0.0008211, shonan.cost(result.first), 1e-6); +// EXPECT_DOUBLES_EQUAL(0, result.second, 1e-10); // certificate! } /* ************************************************************************* */ diff --git a/gtsam/slam/FrobeniusFactor.cpp b/gtsam/slam/FrobeniusFactor.cpp index 5697a0cd6..7af4958e8 100644 --- a/gtsam/slam/FrobeniusFactor.cpp +++ b/gtsam/slam/FrobeniusFactor.cpp @@ -26,8 +26,15 @@ namespace gtsam { boost::shared_ptr ConvertNoiseModel(const SharedNoiseModel &model, size_t d, bool defaultToUnit) { double sigma = 1.0; + std::cout << "111111" << std::endl; if (model != nullptr) { - auto sigmas = model->sigmas(); + const auto &robust = boost::dynamic_pointer_cast(model); + Vector sigmas; + if(robust) + sigmas[0] = 1; + else + sigmas = model->sigmas(); + size_t n = sigmas.size(); if (n == 1) { sigma = sigmas(0); // Rot2 @@ -46,8 +53,14 @@ ConvertNoiseModel(const SharedNoiseModel &model, size_t d, bool defaultToUnit) { throw std::runtime_error("Can only convert Pose2/Pose3 noise models"); } } -exit: - return noiseModel::Isotropic::Sigma(d, sigma); + exit: + auto isoModel = noiseModel::Isotropic::Sigma(d, sigma); + const auto &robust = boost::dynamic_pointer_cast(model); + if(robust) + return noiseModel::Robust::Create( + noiseModel::mEstimator::Huber::Create(1.345), isoModel); + else + return isoModel; } //****************************************************************************** From 8be6d33714136a120c8d9b4faf33557b35e0eb0d Mon Sep 17 00:00:00 2001 From: lcarlone Date: Thu, 24 Sep 2020 19:10:14 -0400 Subject: [PATCH 005/261] added nice unit test --- gtsam/sfm/ShonanAveraging.cpp | 21 --------------------- gtsam/sfm/tests/testShonanAveraging.cpp | 22 ++++++++++++---------- gtsam/slam/FrobeniusFactor.cpp | 12 ++++++------ gtsam/slam/FrobeniusFactor.h | 2 +- 4 files changed, 19 insertions(+), 38 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 0ac893b7c..14f5665b6 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -139,35 +139,25 @@ ShonanAveraging::ShonanAveraging(const Measurements &measurements, /* ************************************************************************* */ template NonlinearFactorGraph ShonanAveraging::buildGraphAt(size_t p) const { - std::cout << "zz0" << std::endl; NonlinearFactorGraph graph; auto G = boost::make_shared(SO<-1>::VectorizedGenerators(p)); - std::cout << "zz1" << std::endl; for (const auto &measurement : measurements_) { const auto &keys = measurement.keys(); const auto &Rij = measurement.measured(); const auto &model = measurement.noiseModel(); - measurement.print("measurement"); - std::cout << "zzzz1" << std::endl; - model->print(); - std::cout << "zzzz2" << std::endl; graph.emplace_shared>(keys[0], keys[1], Rij, p, model, G); - std::cout << "zzzz3" << std::endl; } - // Possibly add Karcher prior if (parameters_.beta > 0) { const size_t dim = SOn::Dimension(p); graph.emplace_shared>(graph.keys(), dim); } - std::cout << "zz2" << std::endl; // Possibly add gauge factors - they are probably useless as gradient is zero if (parameters_.gamma > 0 && p > d + 1) { for (auto key : graph.keys()) graph.emplace_shared(key, p, d, parameters_.gamma); } - std::cout << "z3" << std::endl; return graph; } @@ -185,7 +175,6 @@ ShonanAveraging::createOptimizerAt(size_t p, const Values &initial) const { // Build graph NonlinearFactorGraph graph = buildGraphAt(p); - std::cout << "yy1" << std::endl; // Anchor prior is added here as depends on initial value (and cost is zero) if (parameters_.alpha > 0) { size_t i; @@ -196,7 +185,6 @@ ShonanAveraging::createOptimizerAt(size_t p, const Values &initial) const { graph.emplace_shared>(i, SOn::Lift(p, value.matrix()), model); } - std::cout << "yy2" << std::endl; // Optimize return boost::make_shared(graph, initial, parameters_.lm); @@ -206,9 +194,7 @@ ShonanAveraging::createOptimizerAt(size_t p, const Values &initial) const { template Values ShonanAveraging::tryOptimizingAt(size_t p, const Values &initial) const { - std::cout << "xx1" << std::endl; auto lm = createOptimizerAt(p, initial); - std::cout << "xx2" << std::endl; return lm->optimize(); } @@ -814,29 +800,23 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, Values initialSOp = LiftTo(pMin, initialEstimate); // lift to pMin! for (size_t p = pMin; p <= pMax; p++) { // Optimize until convergence at this level - std::cout << "4a" << std::endl; Qstar = tryOptimizingAt(p, initialSOp); - std::cout << "4aa" << std::endl; if(parameters_.useHuber){ // in this case, there is no optimality verification - std::cout << "4aaa" << std::endl; if(pMin!=pMax) std::cout << "When using robust norm, Shonan only tests a single rank" << std::endl; const Values SO3Values = roundSolution(Qstar); return std::make_pair(SO3Values, 0); } - std::cout << "4b" << std::endl; // Check certificate of global optimzality Vector minEigenVector; double minEigenValue = computeMinEigenValue(Qstar, &minEigenVector); - std::cout << "4bb" << std::endl; if (minEigenValue > parameters_.optimalityThreshold) { // If at global optimum, round and return solution const Values SO3Values = roundSolution(Qstar); return std::make_pair(SO3Values, minEigenValue); } - std::cout << "4c" << std::endl; // Not at global optimimum yet, so check whether we will go to next level if (p != pMax) { // Calculate initial estimate for next level by following minEigenVector @@ -844,7 +824,6 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, initializeWithDescent(p + 1, Qstar, minEigenVector, minEigenValue); } } - std::cout << "4d" << std::endl; throw std::runtime_error("Shonan::run did not converge for given pMax"); } diff --git a/gtsam/sfm/tests/testShonanAveraging.cpp b/gtsam/sfm/tests/testShonanAveraging.cpp index fd4d5e34f..269b2c855 100644 --- a/gtsam/sfm/tests/testShonanAveraging.cpp +++ b/gtsam/sfm/tests/testShonanAveraging.cpp @@ -330,23 +330,25 @@ TEST(ShonanAveraging2, noisyToyGraphWithHuber) { auto measurements = parseMeasurements(g2oFile); parameters.setUseHuber(true); parameters.print(); - std::cout << "1" << std::endl; ShonanAveraging2 shonan(measurements, parameters); EXPECT_LONGS_EQUAL(4, shonan.nrUnknowns()); // Check graph building - std::cout << "2" << std::endl; -// NonlinearFactorGraph graph = shonan.buildGraphAt(2); -// graph.print(); -// EXPECT_LONGS_EQUAL(6, graph.size()); - std::cout << "3" << std::endl; + NonlinearFactorGraph graph = shonan.buildGraphAt(2); + EXPECT_LONGS_EQUAL(6, graph.size()); + // test that each factor is actually robust + for (size_t i=0; i<=4; i++) { // note: last is the Gauge factor and is not robust + const auto &robust = boost::dynamic_pointer_cast( + boost::dynamic_pointer_cast(graph[i])->noiseModel()); + EXPECT(robust); // we expect the factors to be use a robust noise model (in particular, Huber) + } + + // test result auto initial = shonan.initializeRandomly(kRandomNumberGenerator); - std::cout << "4" << std::endl; auto result = shonan.run(initial, 2,3); - std::cout << "5" << std::endl; -// EXPECT_DOUBLES_EQUAL(0.0008211, shonan.cost(result.first), 1e-6); -// EXPECT_DOUBLES_EQUAL(0, result.second, 1e-10); // certificate! + EXPECT_DOUBLES_EQUAL(0.0008211, shonan.cost(result.first), 1e-6); + EXPECT_DOUBLES_EQUAL(0, result.second, 1e-10); // certificate! } /* ************************************************************************* */ diff --git a/gtsam/slam/FrobeniusFactor.cpp b/gtsam/slam/FrobeniusFactor.cpp index 7af4958e8..2d7417283 100644 --- a/gtsam/slam/FrobeniusFactor.cpp +++ b/gtsam/slam/FrobeniusFactor.cpp @@ -23,18 +23,18 @@ using namespace std; namespace gtsam { //****************************************************************************** -boost::shared_ptr +SharedNoiseModel ConvertNoiseModel(const SharedNoiseModel &model, size_t d, bool defaultToUnit) { double sigma = 1.0; - std::cout << "111111" << std::endl; if (model != nullptr) { const auto &robust = boost::dynamic_pointer_cast(model); Vector sigmas; - if(robust) - sigmas[0] = 1; - else - sigmas = model->sigmas(); + if(robust){ + sigma = 1; // Rot2 + goto exit; + } //else: + sigmas = model->sigmas(); size_t n = sigmas.size(); if (n == 1) { sigma = sigmas(0); // Rot2 diff --git a/gtsam/slam/FrobeniusFactor.h b/gtsam/slam/FrobeniusFactor.h index 1fc37c785..9915a617d 100644 --- a/gtsam/slam/FrobeniusFactor.h +++ b/gtsam/slam/FrobeniusFactor.h @@ -34,7 +34,7 @@ namespace gtsam { * isotropic. If it is, we extend to 'n' dimensions, otherwise we throw an * error. If defaultToUnit == false throws an exception on unexepcted input. */ -GTSAM_EXPORT boost::shared_ptr +GTSAM_EXPORT SharedNoiseModel ConvertNoiseModel(const SharedNoiseModel &model, size_t n, bool defaultToUnit = true); From 8cf3bc5059ad9485c35a30e2b7dc0c8d93a04dc4 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Thu, 24 Sep 2020 19:11:19 -0400 Subject: [PATCH 006/261] improved test --- gtsam/sfm/tests/testShonanAveraging.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/sfm/tests/testShonanAveraging.cpp b/gtsam/sfm/tests/testShonanAveraging.cpp index 269b2c855..9242b94a3 100644 --- a/gtsam/sfm/tests/testShonanAveraging.cpp +++ b/gtsam/sfm/tests/testShonanAveraging.cpp @@ -346,7 +346,7 @@ TEST(ShonanAveraging2, noisyToyGraphWithHuber) { // test result auto initial = shonan.initializeRandomly(kRandomNumberGenerator); - auto result = shonan.run(initial, 2,3); + auto result = shonan.run(initial, 2,2); EXPECT_DOUBLES_EQUAL(0.0008211, shonan.cost(result.first), 1e-6); EXPECT_DOUBLES_EQUAL(0, result.second, 1e-10); // certificate! } From 3734039bf5c51291ac7efc2f4f85d9da98f59b6b Mon Sep 17 00:00:00 2001 From: lcarlone Date: Sat, 26 Sep 2020 16:24:34 -0400 Subject: [PATCH 007/261] added check and unit test --- gtsam/sfm/BinaryMeasurement.h | 5 ++++- gtsam/sfm/tests/testBinaryMeasurement.cpp | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/gtsam/sfm/BinaryMeasurement.h b/gtsam/sfm/BinaryMeasurement.h index 9540564e0..ef3fff70d 100644 --- a/gtsam/sfm/BinaryMeasurement.h +++ b/gtsam/sfm/BinaryMeasurement.h @@ -71,8 +71,11 @@ public: this->noiseModel_->print(" noise model: "); } + // TODO: make this more general? void makeNoiseModelRobust(){ - this->noiseModel_ = noiseModel::Robust::Create( + const auto &robust = boost::dynamic_pointer_cast(this->noiseModel_); + if(!robust) // make robust + this->noiseModel_ = noiseModel::Robust::Create( noiseModel::mEstimator::Huber::Create(1.345), this->noiseModel_); } diff --git a/gtsam/sfm/tests/testBinaryMeasurement.cpp b/gtsam/sfm/tests/testBinaryMeasurement.cpp index 3dd81c2c1..a6a75b4ff 100644 --- a/gtsam/sfm/tests/testBinaryMeasurement.cpp +++ b/gtsam/sfm/tests/testBinaryMeasurement.cpp @@ -36,6 +36,7 @@ static SharedNoiseModel rot3_model(noiseModel::Isotropic::Sigma(3, 0.05)); const Unit3 unit3Measured(Vector3(1, 1, 1)); const Rot3 rot3Measured; +/* ************************************************************************* */ TEST(BinaryMeasurement, Unit3) { BinaryMeasurement unit3Measurement(kKey1, kKey2, unit3Measured, unit3_model); @@ -48,6 +49,7 @@ TEST(BinaryMeasurement, Unit3) { EXPECT(unit3Measurement.equals(unit3MeasurementCopy)); } +/* ************************************************************************* */ TEST(BinaryMeasurement, Rot3) { // testing the accessors BinaryMeasurement rot3Measurement(kKey1, kKey2, rot3Measured, @@ -62,6 +64,26 @@ TEST(BinaryMeasurement, Rot3) { EXPECT(rot3Measurement.equals(rot3MeasurementCopy)); } +/* ************************************************************************* */ +TEST(BinaryMeasurement, Rot3MakeRobust) { + BinaryMeasurement rot3Measurement(kKey1, kKey2, rot3Measured, + rot3_model); + rot3Measurement.makeNoiseModelRobust(); + + EXPECT_LONGS_EQUAL(rot3Measurement.key1(), kKey1); + EXPECT_LONGS_EQUAL(rot3Measurement.key2(), kKey2); + EXPECT(rot3Measurement.measured().equals(rot3Measured)); + const auto &robust = boost::dynamic_pointer_cast( + rot3Measurement.noiseModel()); + EXPECT(robust); + + // test that if we call it again nothing changes: + rot3Measurement.makeNoiseModelRobust(); + const auto &robust2 = boost::dynamic_pointer_cast( + rot3Measurement.noiseModel()); + EXPECT(robust2); +} + /* ************************************************************************* */ int main() { TestResult tr; From 6567422ec54df3597ec0087eac27732fd3b191f9 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Sat, 26 Sep 2020 19:06:55 -0400 Subject: [PATCH 008/261] added control over minimum rank in ShonanAveraging example, and resolved hard-coded sigma in FrobeniusFactor --- examples/ShonanAveragingCLI.cpp | 24 ++++++++++++++++++------ gtsam/slam/FrobeniusFactor.cpp | 8 ++++---- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/examples/ShonanAveragingCLI.cpp b/examples/ShonanAveragingCLI.cpp index 09221fda2..3ecb809ae 100644 --- a/examples/ShonanAveragingCLI.cpp +++ b/examples/ShonanAveragingCLI.cpp @@ -25,6 +25,8 @@ * Read 3D dataset sphere25000.txt and output to shonan.g2o (default) * ./ShonanAveragingCLI -i spere2500.txt * + * If you prefer using a robust Huber loss, you can add the option "-h true", for instance" + * ./ShonanAveragingCLI -i spere2500.txt -u true */ #include @@ -43,7 +45,8 @@ int main(int argc, char* argv[]) { string datasetName; string inputFile; string outputFile; - int d, seed; + int d, seed, pMin; + bool useHuberLoss; po::options_description desc( "Shonan Rotation Averaging CLI reads a *pose* graph, extracts the " "rotation constraints, and runs the Shonan algorithm."); @@ -58,6 +61,10 @@ int main(int argc, char* argv[]) { "Write solution to the specified file")( "dimension,d", po::value(&d)->default_value(3), "Optimize over 2D or 3D rotations")( + "useHuberLoss,h", po::value(&useHuberLoss)->default_value(false), + "set True to use Huber loss")( + "pMin,p", po::value(&pMin)->default_value(3), + "set to use desired rank pMin")( "seed,s", po::value(&seed)->default_value(42), "Random seed for initial estimate"); po::variables_map vm; @@ -85,11 +92,14 @@ int main(int argc, char* argv[]) { NonlinearFactorGraph::shared_ptr inputGraph; Values::shared_ptr posesInFile; Values poses; + auto lmParams = LevenbergMarquardtParams::CeresDefaults(); if (d == 2) { cout << "Running Shonan averaging for SO(2) on " << inputFile << endl; - ShonanAveraging2 shonan(inputFile); + ShonanAveraging2::Parameters parameters(lmParams); + parameters.setUseHuber(useHuberLoss); + ShonanAveraging2 shonan(inputFile,parameters); auto initial = shonan.initializeRandomly(rng); - auto result = shonan.run(initial); + auto result = shonan.run(initial,pMin); // Parse file again to set up translation problem, adding a prior boost::tie(inputGraph, posesInFile) = load2D(inputFile); @@ -101,9 +111,11 @@ int main(int argc, char* argv[]) { poses = initialize::computePoses(result.first, &poseGraph); } else if (d == 3) { cout << "Running Shonan averaging for SO(3) on " << inputFile << endl; - ShonanAveraging3 shonan(inputFile); + ShonanAveraging3::Parameters parameters(lmParams); + parameters.setUseHuber(useHuberLoss); + ShonanAveraging3 shonan(inputFile,parameters); auto initial = shonan.initializeRandomly(rng); - auto result = shonan.run(initial); + auto result = shonan.run(initial,pMin); // Parse file again to set up translation problem, adding a prior boost::tie(inputGraph, posesInFile) = load3D(inputFile); @@ -118,7 +130,7 @@ int main(int argc, char* argv[]) { return 1; } cout << "Writing result to " << outputFile << endl; - writeG2o(NonlinearFactorGraph(), poses, outputFile); + writeG2o(*inputGraph, poses, outputFile); return 0; } diff --git a/gtsam/slam/FrobeniusFactor.cpp b/gtsam/slam/FrobeniusFactor.cpp index 2d7417283..5806fcfdb 100644 --- a/gtsam/slam/FrobeniusFactor.cpp +++ b/gtsam/slam/FrobeniusFactor.cpp @@ -30,11 +30,11 @@ ConvertNoiseModel(const SharedNoiseModel &model, size_t d, bool defaultToUnit) { const auto &robust = boost::dynamic_pointer_cast(model); Vector sigmas; if(robust){ - sigma = 1; // Rot2 - goto exit; - } //else: + sigmas = robust->noise()->sigmas(); + } else{ + sigmas = model->sigmas(); + } - sigmas = model->sigmas(); size_t n = sigmas.size(); if (n == 1) { sigma = sigmas(0); // Rot2 From 455f81dfc5cee89feb39cb0f2fee73913d790201 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Wed, 30 Sep 2020 16:07:45 -0400 Subject: [PATCH 009/261] reverted changes to cproject and language settings --- .cproject | 21 ++++++++++++++++++ .settings/language.settings.xml | 39 --------------------------------- 2 files changed, 21 insertions(+), 39 deletions(-) delete mode 100644 .settings/language.settings.xml diff --git a/.cproject b/.cproject index 799952207..6c6a67825 100644 --- a/.cproject +++ b/.cproject @@ -344,4 +344,25 @@ + + + + + make + testShonanAveraging.run + testShonanAveraging + true + false + true + + + make + testBinaryMeasurement.run + testBinaryMeasurement + true + false + true + + + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml deleted file mode 100644 index c6559f58f..000000000 --- a/.settings/language.settings.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 15060011669882f9a9065ce352369d669c4e3c9f Mon Sep 17 00:00:00 2001 From: lcarlone Date: Wed, 30 Sep 2020 16:10:27 -0400 Subject: [PATCH 010/261] fixed typo --- examples/ShonanAveragingCLI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ShonanAveragingCLI.cpp b/examples/ShonanAveragingCLI.cpp index 3ecb809ae..322622228 100644 --- a/examples/ShonanAveragingCLI.cpp +++ b/examples/ShonanAveragingCLI.cpp @@ -25,7 +25,7 @@ * Read 3D dataset sphere25000.txt and output to shonan.g2o (default) * ./ShonanAveragingCLI -i spere2500.txt * - * If you prefer using a robust Huber loss, you can add the option "-h true", for instance" + * If you prefer using a robust Huber loss, you can add the option "-h true", for instance * ./ShonanAveragingCLI -i spere2500.txt -u true */ From fa26cf85abb481540c61ace4ad435a2ca2d0cc02 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Wed, 30 Sep 2020 16:13:51 -0400 Subject: [PATCH 011/261] reverted changes to cproject --- .cproject | 450 ++++++++++-------------------------------------------- 1 file changed, 82 insertions(+), 368 deletions(-) diff --git a/.cproject b/.cproject index 6c6a67825..9589ace56 100644 --- a/.cproject +++ b/.cproject @@ -1,368 +1,82 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - make - testShonanAveraging.run - testShonanAveraging - true - false - true - - - make - testBinaryMeasurement.run - testBinaryMeasurement - true - false - true - - - - + + + gtsam + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + ?name? + + + + org.eclipse.cdt.make.core.append_environment + true + + + org.eclipse.cdt.make.core.autoBuildTarget + all + + + org.eclipse.cdt.make.core.buildArguments + -j4 + + + org.eclipse.cdt.make.core.buildCommand + make + + + org.eclipse.cdt.make.core.buildLocation + ${ProjDirPath}/build + + + org.eclipse.cdt.make.core.cleanBuildTarget + clean + + + org.eclipse.cdt.make.core.contents + org.eclipse.cdt.make.core.activeConfigSettings + + + org.eclipse.cdt.make.core.enableAutoBuild + false + + + org.eclipse.cdt.make.core.enableCleanBuild + true + + + org.eclipse.cdt.make.core.enableFullBuild + true + + + org.eclipse.cdt.make.core.fullBuildTarget + all + + + org.eclipse.cdt.make.core.stopOnError + true + + + org.eclipse.cdt.make.core.useDefaultBuildCmd + true + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + From 4fcfde07bda04b0c05f1a92802233c88ac53ac12 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Fri, 2 Oct 2020 17:06:41 -0400 Subject: [PATCH 012/261] check if mex compiler exists for Matlab wrapper, formatting --- CMakeLists.txt | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eedc42c9e..644058604 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,7 @@ option(GTSAM_WITH_EIGEN_MKL "Eigen will use Intel MKL if available" option(GTSAM_WITH_EIGEN_MKL_OPENMP "Eigen, when using Intel MKL, will also use OpenMP for multithreading if available" OFF) option(GTSAM_THROW_CHEIRALITY_EXCEPTION "Throw exception when a triangulated point is behind a camera" ON) option(GTSAM_BUILD_PYTHON "Enable/Disable building & installation of Python module with pybind11" OFF) +option(GTSAM_INSTALL_MATLAB_TOOLBOX "Enable/Disable installation of matlab toolbox" OFF) option(GTSAM_ALLOW_DEPRECATED_SINCE_V41 "Allow use of methods/functions deprecated in GTSAM 4.1" ON) option(GTSAM_SUPPORT_NESTED_DISSECTION "Support Metis-based nested dissection" ON) option(GTSAM_TANGENT_PREINTEGRATION "Use new ImuFactor with integration on tangent space" ON) @@ -103,19 +104,25 @@ if(NOT MSVC AND NOT XCODE_VERSION) endif() endif() -# Options relating to MATLAB wrapper -# TODO: Check for matlab mex binary before handling building of binaries -option(GTSAM_INSTALL_MATLAB_TOOLBOX "Enable/Disable installation of matlab toolbox" OFF) -set(GTSAM_PYTHON_VERSION "Default" CACHE STRING "The version of Python to build the wrappers against.") # Check / set dependent variables for MATLAB wrapper -if(GTSAM_INSTALL_MATLAB_TOOLBOX AND GTSAM_BUILD_TYPE_POSTFIXES) - set(CURRENT_POSTFIX ${CMAKE_${CMAKE_BUILD_TYPE_UPPER}_POSTFIX}) +if(GTSAM_INSTALL_MATLAB_TOOLBOX) + find_package(Matlab COMPONENTS MEX_COMPILER REQUIRED) + if(NOT Matlab_MEX_COMPILER) + message(FATAL_ERROR "Cannot find MEX compiler binary. Please check your Matlab installation and ensure MEX in installed as well.") + endif() + + if(GTSAM_BUILD_TYPE_POSTFIXES) + set(CURRENT_POSTFIX ${CMAKE_${CMAKE_BUILD_TYPE_UPPER}_POSTFIX}) + endif() + + if(NOT BUILD_SHARED_LIBS) + message(FATAL_ERROR "GTSAM_INSTALL_MATLAB_TOOLBOX and BUILD_SHARED_LIBS=OFF. The MATLAB wrapper cannot be compiled with a static GTSAM library because mex modules are themselves shared libraries. If you want a self-contained mex module, enable GTSAM_MEX_BUILD_STATIC_MODULE instead of BUILD_SHARED_LIBS=OFF.") + endif() endif() -if(GTSAM_INSTALL_MATLAB_TOOLBOX AND NOT BUILD_SHARED_LIBS) - message(FATAL_ERROR "GTSAM_INSTALL_MATLAB_TOOLBOX and BUILD_SHARED_LIBS=OFF. The MATLAB wrapper cannot be compiled with a static GTSAM library because mex modules are themselves shared libraries. If you want a self-contained mex module, enable GTSAM_MEX_BUILD_STATIC_MODULE instead of BUILD_SHARED_LIBS=OFF.") -endif() + +set(GTSAM_PYTHON_VERSION "Default" CACHE STRING "The version of Python to build the wrappers against.") if(GTSAM_BUILD_PYTHON) # Get info about the Python3 interpreter From 2afbaaaf441c6825f4a0c50a79db70c727e7d5d2 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Sun, 13 Sep 2020 17:28:15 -0400 Subject: [PATCH 013/261] Add acc power method in Alg6 --- gtsam/sfm/PowerMethod.h | 166 ++++++++++++++++++++++++++++ gtsam/sfm/ShonanAveraging.cpp | 70 +++++++----- gtsam/sfm/tests/testPowerMethod.cpp | 38 +++++++ 3 files changed, 248 insertions(+), 26 deletions(-) create mode 100644 gtsam/sfm/PowerMethod.h create mode 100644 gtsam/sfm/tests/testPowerMethod.cpp diff --git a/gtsam/sfm/PowerMethod.h b/gtsam/sfm/PowerMethod.h new file mode 100644 index 000000000..f6620f162 --- /dev/null +++ b/gtsam/sfm/PowerMethod.h @@ -0,0 +1,166 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010-2019, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file PowerMethod.h + * @date Sept 2020 + * @author Jing Wu + * @brief accelerated power method for fast eigenvalue and eigenvector computation + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace gtsam { + /* ************************************************************************* */ +/// MINIMUM EIGENVALUE COMPUTATIONS + +/** This is a lightweight struct used in conjunction with Spectra to compute + * the minimum eigenvalue and eigenvector of a sparse matrix A; it has a single + * nontrivial function, perform_op(x,y), that computes and returns the product + * y = (A + sigma*I) x */ +struct MatrixProdFunctor { + // Const reference to an externally-held matrix whose minimum-eigenvalue we + // want to compute + const Sparse &A_; + + // Spectral shift + double sigma_; + + const int m_n_; + const int m_nev_; + const int m_ncv_; + Vector ritz_val_; + Matrix ritz_vectors_; + + // Constructor + explicit MatrixProdFunctor(const Sparse &A, int nev, int ncv, + double sigma = 0) + : A_(A), + m_n_(A.rows()), + m_nev_(nev), + m_ncv_(ncv > m_n_ ? m_n_ : ncv), + sigma_(sigma) {} + + int rows() const { return A_.rows(); } + int cols() const { return A_.cols(); } + + // Matrix-vector multiplication operation + void perform_op(const double *x, double *y) const { + // Wrap the raw arrays as Eigen Vector types + Eigen::Map X(x, rows()); + Eigen::Map Y(y, rows()); + + // Do the multiplication using wrapped Eigen vectors + Y = A_ * X + sigma_ * X; + } + + long next_long_rand(long seed) { + const unsigned int m_a = 16807; + const unsigned long m_max = 2147483647L; + long m_rand = m_n_ ? (m_n_ & m_max) : 1; + unsigned long lo, hi; + + lo = m_a * (long)(seed & 0xFFFF); + hi = m_a * (long)((unsigned long)seed >> 16); + lo += (hi & 0x7FFF) << 16; + if (lo > m_max) { + lo &= m_max; + ++lo; + } + lo += hi >> 15; + if (lo > m_max) { + lo &= m_max; + ++lo; + } + return (long)lo; + } + + Vector random_vec(const int len) { + Vector res(len); + const unsigned long m_max = 2147483647L; + for (int i = 0; i < len; i++) { + long m_rand = next_long_rand(m_rand); + res[i] = double(m_rand) / double(m_max) - double(0.5); + } + return res; + } + + void init(Vector data) { + ritz_val_.resize(m_ncv_); + ritz_val_.setZero(); + ritz_vectors_.resize(m_ncv_, m_nev_); + ritz_vectors_.setZero(); + Eigen::Map v0(init_resid.data(), m_n_); + } + + void init() { + Vector init_resid = random_vec(m_n_); + init(init_resid); + } + + bool converged(double tol, const Vector x) { + double theta = x.transpose() * A_ * x; + Vector diff = A_ * x - theta * x; + double error = diff.lpNorm<1>(); + return error < tol; + } + + int num_converged(double tol) { + int converge = 0; + for (int i=0; i= m_nev_) break; + + nev_adj = nev_adjusted(nconv); + restart(nev_adj); + } + // Sorting results + sort_ritzpair(sort_rule); + + m_niter += i + 1; + m_info = (nconv >= m_nev_) ? SUCCESSFUL : NOT_CONVERGING; + + return std::min(m_nev_, nconv); + } + + Vector eigenvalues() { + return ritz_val_; + } + + Matrix eigenvectors() { + return ritz_vectors_; + } + +}; + +} // namespace gtsam diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index df2d72c28..c2e2a528c 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -470,38 +471,55 @@ Sparse ShonanAveraging::computeA(const Values &values) const { return Lambda - Q_; } -/* ************************************************************************* */ -/// MINIMUM EIGENVALUE COMPUTATIONS +// Alg.6 from paper Distributed Certifiably Correct Pose-Graph Optimization +static bool PowerMinimumEigenValue( + const Sparse &A, const Matrix &S, double *minEigenValue, + Vector *minEigenVector = 0, size_t *numIterations = 0, + size_t maxIterations = 1000, + double minEigenvalueNonnegativityTolerance = 10e-4, + Eigen::Index numLanczosVectors = 20) { -/** This is a lightweight struct used in conjunction with Spectra to compute - * the minimum eigenvalue and eigenvector of a sparse matrix A; it has a single - * nontrivial function, perform_op(x,y), that computes and returns the product - * y = (A + sigma*I) x */ -struct MatrixProdFunctor { - // Const reference to an externally-held matrix whose minimum-eigenvalue we - // want to compute - const Sparse &A_; + // a. Compute dominant eigenpair of S using power method + MatrixProdFunctor lmOperator(A, 1, std::min(numLanczosVectors, A.rows())); + lmOperator.init(); - // Spectral shift - double sigma_; + const int lmConverged = lmEigenValueSolver.compute( + maxIterations, 1e-4); - // Constructor - explicit MatrixProdFunctor(const Sparse &A, double sigma = 0) - : A_(A), sigma_(sigma) {} + // Check convergence and bail out if necessary + if (lmConverged != 1) return false; - int rows() const { return A_.rows(); } - int cols() const { return A_.cols(); } + const double lmEigenValue = lmEigenValueSolver.eigenvalues()(0); - // Matrix-vector multiplication operation - void perform_op(const double *x, double *y) const { - // Wrap the raw arrays as Eigen Vector types - Eigen::Map X(x, rows()); - Eigen::Map Y(y, rows()); - - // Do the multiplication using wrapped Eigen vectors - Y = A_ * X + sigma_ * X; + if (lmEigenValue < 0) { + // The largest-magnitude eigenvalue is negative, and therefore also the + // minimum eigenvalue, so just return this solution + *minEigenValue = lmEigenValue; + if (minEigenVector) { + *minEigenVector = lmEigenValueSolver.eigenvectors().col(0); + minEigenVector->normalize(); // Ensure that this is a unit vector + } + return true; } -}; + + Matrix C = lmEigenValue * Matrix::Identity(A.rows(), A.cols()) - A; + MatrixProdFunctor minShiftedOperator( + C, 1, std::min(numLanczosVectors, A.rows())); + minShiftedOperator.init(); + + const int minConverged = minShiftedOperator.compute( + maxIterations, minEigenvalueNonnegativityTolerance / lmEigenValue); + + if (minConverged != 1) return false; + + *minEigenValue = lmEigenValue - minShiftedOperator.eigenvalues()(0); + if (minEigenVector) { + *minEigenVector = minShiftedOperator.eigenvectors().col(0); + minEigenVector->normalize(); // Ensure that this is a unit vector + } + if (numIterations) *numIterations = minShiftedOperator.num_iterations(); + return true; +} /// Function to compute the minimum eigenvalue of A using Lanczos in Spectra. /// This does 2 things: diff --git a/gtsam/sfm/tests/testPowerMethod.cpp b/gtsam/sfm/tests/testPowerMethod.cpp new file mode 100644 index 000000000..f67fad458 --- /dev/null +++ b/gtsam/sfm/tests/testPowerMethod.cpp @@ -0,0 +1,38 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010-2019, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * testPowerMethod.cpp + * + * @file testPowerMethod.cpp + * @date Sept 2020 + * @author Jing Wu + * @brief Check eigenvalue and eigenvector computed by power method + */ + +#include +#include + +using namespace std; +using namespace gtsam; + +/* ************************************************************************* */ +TEST(PowerMethod, initialize) { + gtsam::Sparse A; + MatrixProdFunctor(A, 1, A.rows()); +} + +/* ************************************************************************* */ +int main() { + TestResult tr; + return TestRegistry::runAllTests(tr); +} +/* ************************************************************************* */ From e02633c74582c0bfa3674af78691c506e780ab43 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Mon, 14 Sep 2020 01:58:44 -0400 Subject: [PATCH 014/261] Completed and tested power method with unittest --- gtsam/sfm/PowerMethod.h | 157 +++++++++++++++++++++------- gtsam/sfm/tests/testPowerMethod.cpp | 35 ++++++- 2 files changed, 149 insertions(+), 43 deletions(-) diff --git a/gtsam/sfm/PowerMethod.h b/gtsam/sfm/PowerMethod.h index f6620f162..3b83fb8a4 100644 --- a/gtsam/sfm/PowerMethod.h +++ b/gtsam/sfm/PowerMethod.h @@ -24,14 +24,17 @@ #include #include -#include #include #include #include #include #include +#include namespace gtsam { + +using Sparse = Eigen::SparseMatrix; + /* ************************************************************************* */ /// MINIMUM EIGENVALUE COMPUTATIONS @@ -39,46 +42,63 @@ namespace gtsam { * the minimum eigenvalue and eigenvector of a sparse matrix A; it has a single * nontrivial function, perform_op(x,y), that computes and returns the product * y = (A + sigma*I) x */ -struct MatrixProdFunctor { +struct PowerFunctor { // Const reference to an externally-held matrix whose minimum-eigenvalue we // want to compute const Sparse &A_; - // Spectral shift - double sigma_; + const int m_n_; // dimension of Matrix A + const int m_nev_; // number of eigenvalues required - const int m_n_; - const int m_nev_; - const int m_ncv_; - Vector ritz_val_; - Matrix ritz_vectors_; + // a Polyak momentum term + double beta_; + // const int m_ncv_; // dimention of orthonormal basis subspace + size_t m_niter_; // number of iterations + +private: + Vector ritz_val_; // all ritz eigenvalues + Matrix ritz_vectors_; // all ritz eigenvectors + Vector ritz_conv_; // store whether the ritz eigenpair converged + Vector sorted_ritz_val_; // sorted converged eigenvalue + Matrix sorted_ritz_vectors_; // sorted converged eigenvectors + +public: // Constructor - explicit MatrixProdFunctor(const Sparse &A, int nev, int ncv, - double sigma = 0) + explicit PowerFunctor(const Sparse &A, int nev, int ncv, + double beta = 0) : A_(A), m_n_(A.rows()), m_nev_(nev), - m_ncv_(ncv > m_n_ ? m_n_ : ncv), - sigma_(sigma) {} + // m_ncv_(ncv > m_n_ ? m_n_ : ncv), + beta_(beta), + m_niter_(0) + {} int rows() const { return A_.rows(); } int cols() const { return A_.cols(); } // Matrix-vector multiplication operation - void perform_op(const double *x, double *y) const { - // Wrap the raw arrays as Eigen Vector types - Eigen::Map X(x, rows()); - Eigen::Map Y(y, rows()); + Vector perform_op(const Vector& x1, const Vector& x0) const { // Do the multiplication using wrapped Eigen vectors - Y = A_ * X + sigma_ * X; + Vector x2 = A_ * x1 - beta_ * x0; + x2.normalize(); + return x2; + } + + Vector perform_op(int i) const { + + // Do the multiplication using wrapped Eigen vectors + Vector x1 = ritz_vectors_.col(i-1); + Vector x2 = ritz_vectors_.col(i-2); + return perform_op(x1, x2); } long next_long_rand(long seed) { const unsigned int m_a = 16807; const unsigned long m_max = 2147483647L; - long m_rand = m_n_ ? (m_n_ & m_max) : 1; + // long m_rand = m_n_ ? (m_n_ & m_max) : 1; unsigned long lo, hi; lo = m_a * (long)(seed & 0xFFFF); @@ -103,62 +123,119 @@ struct MatrixProdFunctor { long m_rand = next_long_rand(m_rand); res[i] = double(m_rand) / double(m_max) - double(0.5); } + res.normalize(); return res; } - void init(Vector data) { - ritz_val_.resize(m_ncv_); + void init(const Vector x0, const Vector x00) { + // initialzie ritz eigen values + ritz_val_.resize(m_n_); ritz_val_.setZero(); - ritz_vectors_.resize(m_ncv_, m_nev_); + + // initialzie the ritz converged vector + ritz_conv_.resize(m_n_); + ritz_conv_.setZero(); + + // initialzie ritz eigen vectors + ritz_vectors_.resize(m_n_, m_n_); ritz_vectors_.setZero(); - Eigen::Map v0(init_resid.data(), m_n_); + ritz_vectors_.col(0) = perform_op(x0, x00); + ritz_vectors_.col(1) = perform_op(ritz_vectors_.col(0), x0); + + // setting beta + Vector init_resid = ritz_vectors_.col(0); + const double up = init_resid.transpose() * A_ * init_resid; + const double down = init_resid.transpose().dot(init_resid); + const double mu = up/down; + beta_ = mu*mu/4; + } void init() { - Vector init_resid = random_vec(m_n_); - init(init_resid); + Vector x0 = random_vec(m_n_); + Vector x00 = random_vec(m_n_); + init(x0, x00); } - bool converged(double tol, const Vector x) { + bool converged(double tol, int i) { + Vector x = ritz_vectors_.col(i); double theta = x.transpose() * A_ * x; + + // store the ritz eigen value + ritz_val_(i) = theta; + + // update beta + beta_ = std::max(beta_, theta * theta / 4); + Vector diff = A_ * x - theta * x; double error = diff.lpNorm<1>(); + if (error < tol) ritz_conv_(i) = 1; return error < tol; } int num_converged(double tol) { - int converge = 0; + int num_converge = 0; for (int i=0; i0 && i> pairs; + for(int i=0; i& left, const std::pair& right) { + return left.first < right.first; + }); + + // initialzie sorted ritz eigenvalues and eigenvectors + size_t num_converged = pairs.size(); + sorted_ritz_val_.resize(num_converged); + sorted_ritz_val_.setZero(); + sorted_ritz_vectors_.resize(m_n_, num_converged); + sorted_ritz_vectors_.setZero(); + + // fill sorted ritz eigenvalues and eigenvectors with sorted index + for(size_t j=0; j= m_nev_) break; - - nev_adj = nev_adjusted(nconv); - restart(nev_adj); } - // Sorting results - sort_ritzpair(sort_rule); - m_niter += i + 1; - m_info = (nconv >= m_nev_) ? SUCCESSFUL : NOT_CONVERGING; + // sort the result + sort_eigenpair(); return std::min(m_nev_, nconv); } Vector eigenvalues() { - return ritz_val_; + return sorted_ritz_val_; } Matrix eigenvectors() { - return ritz_vectors_; + return sorted_ritz_vectors_; } }; diff --git a/gtsam/sfm/tests/testPowerMethod.cpp b/gtsam/sfm/tests/testPowerMethod.cpp index f67fad458..2e9c17345 100644 --- a/gtsam/sfm/tests/testPowerMethod.cpp +++ b/gtsam/sfm/tests/testPowerMethod.cpp @@ -18,16 +18,45 @@ * @brief Check eigenvalue and eigenvector computed by power method */ +#include +#include + #include -#include + +#include +#include +#include +#include using namespace std; using namespace gtsam; +ShonanAveraging3 fromExampleName( + const std::string &name, + ShonanAveraging3::Parameters parameters = ShonanAveraging3::Parameters()) { + string g2oFile = findExampleDataFile(name); + return ShonanAveraging3(g2oFile, parameters); +} + +static const ShonanAveraging3 kShonan = fromExampleName("toyExample.g2o"); + /* ************************************************************************* */ TEST(PowerMethod, initialize) { - gtsam::Sparse A; - MatrixProdFunctor(A, 1, A.rows()); + gtsam::Sparse A(6, 6); + A.coeffRef(0, 0) = 6; + PowerFunctor pf(A, 1, A.rows()); + pf.init(); + pf.compute(20, 1e-4); + EXPECT_LONGS_EQUAL(6, pf.eigenvectors().cols()); + EXPECT_LONGS_EQUAL(6, pf.eigenvectors().rows()); + + const Vector6 x1 = (Vector(6) << 1.0, 0.0, 0.0, 0.0, 0.0, 0.0).finished(); + Vector6 actual = pf.eigenvectors().col(0); + actual(0) = abs(actual(0)); + EXPECT(assert_equal(x1, actual)); + + const double ev1 = 6.0; + EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalues()(0), 1e-5); } /* ************************************************************************* */ From fc112a4dc7a3fb62bf2ba951e2b3ea650f55bc70 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Mon, 14 Sep 2020 01:59:31 -0400 Subject: [PATCH 015/261] Added PowerMinimumEigenValue method and unittest. --- gtsam/sfm/ShonanAveraging.cpp | 62 +++++++++++++++++++++---- gtsam/sfm/ShonanAveraging.h | 8 ++++ gtsam/sfm/tests/testShonanAveraging.cpp | 5 ++ 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index c2e2a528c..786c91890 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -480,31 +480,30 @@ static bool PowerMinimumEigenValue( Eigen::Index numLanczosVectors = 20) { // a. Compute dominant eigenpair of S using power method - MatrixProdFunctor lmOperator(A, 1, std::min(numLanczosVectors, A.rows())); + PowerFunctor lmOperator(A, 1, std::min(numLanczosVectors, A.rows())); lmOperator.init(); - const int lmConverged = lmEigenValueSolver.compute( - maxIterations, 1e-4); + const int lmConverged = lmOperator.compute( + maxIterations, 1e-5); // Check convergence and bail out if necessary if (lmConverged != 1) return false; - const double lmEigenValue = lmEigenValueSolver.eigenvalues()(0); + const double lmEigenValue = lmOperator.eigenvalues()(0); if (lmEigenValue < 0) { // The largest-magnitude eigenvalue is negative, and therefore also the // minimum eigenvalue, so just return this solution *minEigenValue = lmEigenValue; if (minEigenVector) { - *minEigenVector = lmEigenValueSolver.eigenvectors().col(0); + *minEigenVector = lmOperator.eigenvectors().col(0); minEigenVector->normalize(); // Ensure that this is a unit vector } return true; } - Matrix C = lmEigenValue * Matrix::Identity(A.rows(), A.cols()) - A; - MatrixProdFunctor minShiftedOperator( - C, 1, std::min(numLanczosVectors, A.rows())); + Sparse C = lmEigenValue * Matrix::Identity(A.rows(), A.cols()) - A; + PowerFunctor minShiftedOperator(C, 1, std::min(numLanczosVectors, C.rows())); minShiftedOperator.init(); const int minConverged = minShiftedOperator.compute( @@ -521,6 +520,36 @@ static bool PowerMinimumEigenValue( return true; } +/** This is a lightweight struct used in conjunction with Spectra to compute + * the minimum eigenvalue and eigenvector of a sparse matrix A; it has a single + * nontrivial function, perform_op(x,y), that computes and returns the product + * y = (A + sigma*I) x */ +struct MatrixProdFunctor { + // Const reference to an externally-held matrix whose minimum-eigenvalue we + // want to compute + const Sparse &A_; + + // Spectral shift + double sigma_; + + // Constructor + explicit MatrixProdFunctor(const Sparse &A, double sigma = 0) + : A_(A), sigma_(sigma) {} + + int rows() const { return A_.rows(); } + int cols() const { return A_.cols(); } + + // Matrix-vector multiplication operation + void perform_op(const double *x, double *y) const { + // Wrap the raw arrays as Eigen Vector types + Eigen::Map X(x, rows()); + Eigen::Map Y(y, rows()); + + // Do the multiplication using wrapped Eigen vectors + Y = A_ * X + sigma_ * X; + } +}; + /// Function to compute the minimum eigenvalue of A using Lanczos in Spectra. /// This does 2 things: /// @@ -659,6 +688,23 @@ double ShonanAveraging::computeMinEigenValue(const Values &values, return minEigenValue; } +/* ************************************************************************* */ +template +double ShonanAveraging::computeMinEigenValueAP(const Values &values, + Vector *minEigenVector) const { + assert(values.size() == nrUnknowns()); + const Matrix S = StiefelElementMatrix(values); + auto A = computeA(S); + + double minEigenValue; + bool success = PowerMinimumEigenValue(A, S, &minEigenValue, minEigenVector); + if (!success) { + throw std::runtime_error( + "PowerMinimumEigenValue failed to compute minimum eigenvalue."); + } + return minEigenValue; +} + /* ************************************************************************* */ template std::pair ShonanAveraging::computeMinEigenVector( diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index edd9f33a2..9d117a266 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -202,6 +203,13 @@ class GTSAM_EXPORT ShonanAveraging { double computeMinEigenValue(const Values &values, Vector *minEigenVector = nullptr) const; + /** + * Compute minimum eigenvalue with accelerated power method. + * @param values: should be of type SOn + */ + double computeMinEigenValueAP(const Values &values, + Vector *minEigenVector = nullptr) const; + /// Project pxdN Stiefel manifold matrix S to Rot3^N Values roundSolutionS(const Matrix &S) const; diff --git a/gtsam/sfm/tests/testShonanAveraging.cpp b/gtsam/sfm/tests/testShonanAveraging.cpp index 1200c8ebb..4434043e8 100644 --- a/gtsam/sfm/tests/testShonanAveraging.cpp +++ b/gtsam/sfm/tests/testShonanAveraging.cpp @@ -166,9 +166,14 @@ TEST(ShonanAveraging3, CheckWithEigen) { for (int i = 1; i < lambdas.size(); i++) minEigenValue = min(lambdas(i), minEigenValue); + // Compute Eigenvalue with Accelerated Power method + double lambdaAP = kShonan.computeMinEigenValueAP(Qstar3); + // Actual check EXPECT_DOUBLES_EQUAL(0, lambda, 1e-11); EXPECT_DOUBLES_EQUAL(0, minEigenValue, 1e-11); + EXPECT_DOUBLES_EQUAL(0, lambdaAP, 1e-11); + // Construct test descent direction (as minEigenVector is not predictable // across platforms, being one from a basically flat 3d- subspace) From d6e2546cf546d9863a5c2d1c1ffa48036f2459ff Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Sat, 19 Sep 2020 23:28:43 -0400 Subject: [PATCH 016/261] feat: Add Best Heavy Ball alg to set beta --- gtsam/sfm/PowerMethod.h | 202 ++++++++++++++++++++++------ gtsam/sfm/ShonanAveraging.cpp | 4 +- gtsam/sfm/tests/testPowerMethod.cpp | 34 +++-- 3 files changed, 190 insertions(+), 50 deletions(-) diff --git a/gtsam/sfm/PowerMethod.h b/gtsam/sfm/PowerMethod.h index 3b83fb8a4..b8471e8e2 100644 --- a/gtsam/sfm/PowerMethod.h +++ b/gtsam/sfm/PowerMethod.h @@ -30,26 +30,47 @@ #include #include #include +#include +#include +#include namespace gtsam { using Sparse = Eigen::SparseMatrix; - /* ************************************************************************* */ +/* ************************************************************************* */ /// MINIMUM EIGENVALUE COMPUTATIONS -/** This is a lightweight struct used in conjunction with Spectra to compute - * the minimum eigenvalue and eigenvector of a sparse matrix A; it has a single - * nontrivial function, perform_op(x,y), that computes and returns the product - * y = (A + sigma*I) x */ struct PowerFunctor { + /** + * \brief Computer i-th Eigenpair with power method + * + * References : + * 1) Rosen, D. and Carlone, L., 2017, September. Computational + * enhancements for certifiably correct SLAM. In Proceedings of the + * International Conference on Intelligent Robots and Systems. + * 2) Yulun Tian and Kasra Khosoussi and David M. Rosen and Jonathan P. How, + * 2020, Aug, Distributed Certifiably Correct Pose-Graph Optimization, Arxiv + * 3) C. de Sa, B. He, I. Mitliagkas, C. Ré, and P. Xu, “Accelerated + * stochastic power iteration,” in Proc. Mach. Learn. Res., no. 84, 2018, pp. 58–67 + * + * It performs the following iteration: \f$ x_{k+1} = A * x_k + \beta * + * x_{k-1} \f$ where A is the certificate matrix, x is the ritz vector + * + */ + // Const reference to an externally-held matrix whose minimum-eigenvalue we // want to compute const Sparse &A_; + const Matrix &S_; + const int m_n_; // dimension of Matrix A const int m_nev_; // number of eigenvalues required + // flag for running power method or accelerated power method. If false, the former, vice versa. + bool accelerated_; + // a Polyak momentum term double beta_; @@ -64,41 +85,55 @@ private: Matrix sorted_ritz_vectors_; // sorted converged eigenvectors public: - // Constructor - explicit PowerFunctor(const Sparse &A, int nev, int ncv, - double beta = 0) - : A_(A), - m_n_(A.rows()), - m_nev_(nev), - // m_ncv_(ncv > m_n_ ? m_n_ : ncv), - beta_(beta), - m_niter_(0) - {} + // Constructor + explicit PowerFunctor(const Sparse& A, const Matrix& S, int nev, int ncv, + bool accelerated = false, double beta = 0) + : A_(A), + S_(S), + m_n_(A.rows()), + m_nev_(nev), + // m_ncv_(ncv > m_n_ ? m_n_ : ncv), + accelerated_(accelerated), + beta_(beta), + m_niter_(0) { + // Do nothing + } - int rows() const { return A_.rows(); } - int cols() const { return A_.cols(); } + int rows() const { return A_.rows(); } + int cols() const { return A_.cols(); } - // Matrix-vector multiplication operation - Vector perform_op(const Vector& x1, const Vector& x0) const { + // Matrix-vector multiplication operation + Vector perform_op(const Vector& x1, const Vector& x0) const { + // Do the multiplication + Vector x2 = A_ * x1 - beta_ * x0; + x2.normalize(); + return x2; + } - // Do the multiplication using wrapped Eigen vectors - Vector x2 = A_ * x1 - beta_ * x0; + Vector perform_op(const Vector& x1, const Vector& x0, const double beta) const { + Vector x2 = A_ * x1 - beta * x0; + x2.normalize(); + return x2; + } + + Vector perform_op(const Vector& x1) const { + Vector x2 = A_ * x1; x2.normalize(); return x2; } Vector perform_op(int i) const { - - // Do the multiplication using wrapped Eigen vectors - Vector x1 = ritz_vectors_.col(i-1); - Vector x2 = ritz_vectors_.col(i-2); - return perform_op(x1, x2); + if (accelerated_) { + Vector x1 = ritz_vectors_.col(i-1); + Vector x2 = ritz_vectors_.col(i-2); + return perform_op(x1, x2); + } else + return perform_op(ritz_vectors_.col(i-1)); } long next_long_rand(long seed) { const unsigned int m_a = 16807; const unsigned long m_max = 2147483647L; - // long m_rand = m_n_ ? (m_n_ & m_max) : 1; unsigned long lo, hi; lo = m_a * (long)(seed & 0xFFFF); @@ -127,6 +162,68 @@ public: return res; } + /// Tuning the momentum beta using the Best Heavy Ball algorithm in Ref(3) + void setBeta() { + if (m_n_ < 10) return; + double maxBeta = beta_; + size_t maxIndex; + std::vector betas = {2/3*maxBeta, 0.99*maxBeta, maxBeta, 1.01*maxBeta, 1.5*maxBeta}; + + Matrix tmp_ritz_vectors; + tmp_ritz_vectors.resize(m_n_, 10); + tmp_ritz_vectors.setZero(); + for (size_t i = 0; i < 10; i++) { + for (size_t k = 0; k < betas.size(); ++k) { + for (size_t j = 1; j < 10; j++) { + // double rayleighQuotient; + if (j <2 ) { + Vector x0 = random_vec(m_n_); + Vector x00 = random_vec(m_n_); + tmp_ritz_vectors.col(0) = perform_op(x0, x00, betas[k]); + tmp_ritz_vectors.col(1) = + perform_op(tmp_ritz_vectors.col(0), x0, betas[k]); + } + else { + tmp_ritz_vectors.col(j) = + perform_op(tmp_ritz_vectors.col(j - 1), + tmp_ritz_vectors.col(j - 2), betas[k]); + } + const Vector x = tmp_ritz_vectors.col(j); + const double up = x.transpose() * A_ * x; + const double down = x.transpose().dot(x); + const double mu = up / down; + if (mu * mu / 4 > maxBeta) { + maxIndex = k; + maxBeta = mu * mu / 4; + break; + } + } + } + } + + beta_ = betas[maxIndex]; + } + + void perturb(int i) { + // generate a 0.03*||x_0||_2 as stated in David's paper + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + std::mt19937 generator (seed); + std::uniform_real_distribution uniform01(0.0, 1.0); + + int n = m_n_; + Vector disturb; + disturb.resize(n); + disturb.setZero(); + for (int i =0; i(); @@ -179,7 +291,9 @@ public: if (converged(tol, i)) { num_converge += 1; } - if (i>0 && i0 && i= m_nev_) break; + else reset(); } // sort the result diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 786c91890..f287437d4 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -480,7 +480,7 @@ static bool PowerMinimumEigenValue( Eigen::Index numLanczosVectors = 20) { // a. Compute dominant eigenpair of S using power method - PowerFunctor lmOperator(A, 1, std::min(numLanczosVectors, A.rows())); + PowerFunctor lmOperator(A, S, 1, A.rows()); lmOperator.init(); const int lmConverged = lmOperator.compute( @@ -503,7 +503,7 @@ static bool PowerMinimumEigenValue( } Sparse C = lmEigenValue * Matrix::Identity(A.rows(), A.cols()) - A; - PowerFunctor minShiftedOperator(C, 1, std::min(numLanczosVectors, C.rows())); + PowerFunctor minShiftedOperator(C, S, 1, C.rows(), true); minShiftedOperator.init(); const int minConverged = minShiftedOperator.compute( diff --git a/gtsam/sfm/tests/testPowerMethod.cpp b/gtsam/sfm/tests/testPowerMethod.cpp index 2e9c17345..4547c91b9 100644 --- a/gtsam/sfm/tests/testPowerMethod.cpp +++ b/gtsam/sfm/tests/testPowerMethod.cpp @@ -41,21 +41,37 @@ ShonanAveraging3 fromExampleName( static const ShonanAveraging3 kShonan = fromExampleName("toyExample.g2o"); /* ************************************************************************* */ -TEST(PowerMethod, initialize) { +TEST(PowerMethod, powerIteration) { + // test power accelerated iteration gtsam::Sparse A(6, 6); A.coeffRef(0, 0) = 6; - PowerFunctor pf(A, 1, A.rows()); - pf.init(); - pf.compute(20, 1e-4); - EXPECT_LONGS_EQUAL(6, pf.eigenvectors().cols()); - EXPECT_LONGS_EQUAL(6, pf.eigenvectors().rows()); + Matrix S = Matrix66::Zero(); + PowerFunctor apf(A, S, 1, A.rows(), true); + apf.init(); + apf.compute(20, 1e-4); + EXPECT_LONGS_EQUAL(6, apf.eigenvectors().cols()); + EXPECT_LONGS_EQUAL(6, apf.eigenvectors().rows()); const Vector6 x1 = (Vector(6) << 1.0, 0.0, 0.0, 0.0, 0.0, 0.0).finished(); - Vector6 actual = pf.eigenvectors().col(0); - actual(0) = abs(actual(0)); - EXPECT(assert_equal(x1, actual)); + Vector6 actual0 = apf.eigenvectors().col(0); + actual0(0) = abs(actual0(0)); + EXPECT(assert_equal(x1, actual0)); const double ev1 = 6.0; + EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalues()(0), 1e-5); + + // test power iteration, beta is set to 0 + PowerFunctor pf(A, S, 1, A.rows()); + pf.init(); + pf.compute(20, 1e-4); + // for power method, only 5 ritz vectors converge with 20 iteration + EXPECT_LONGS_EQUAL(5, pf.eigenvectors().cols()); + EXPECT_LONGS_EQUAL(6, pf.eigenvectors().rows()); + + Vector6 actual1 = apf.eigenvectors().col(0); + actual1(0) = abs(actual1(0)); + EXPECT(assert_equal(x1, actual1)); + EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalues()(0), 1e-5); } From 758c4b061d695fabe931e0df8aa5c6c1a6ec082e Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Wed, 30 Sep 2020 11:55:18 -0400 Subject: [PATCH 017/261] Refactor power and accelerated method --- gtsam/sfm/PowerMethod.h | 420 ++++++++++------------------ gtsam/sfm/ShonanAveraging.cpp | 16 +- gtsam/sfm/tests/testPowerMethod.cpp | 71 +++-- 3 files changed, 206 insertions(+), 301 deletions(-) diff --git a/gtsam/sfm/PowerMethod.h b/gtsam/sfm/PowerMethod.h index b8471e8e2..5fa355aaa 100644 --- a/gtsam/sfm/PowerMethod.h +++ b/gtsam/sfm/PowerMethod.h @@ -13,7 +13,8 @@ * @file PowerMethod.h * @date Sept 2020 * @author Jing Wu - * @brief accelerated power method for fast eigenvalue and eigenvector computation + * @brief accelerated power method for fast eigenvalue and eigenvector + * computation */ #pragma once @@ -24,15 +25,15 @@ #include #include +#include +#include +#include #include +#include #include #include #include #include -#include -#include -#include -#include namespace gtsam { @@ -41,9 +42,11 @@ using Sparse = Eigen::SparseMatrix; /* ************************************************************************* */ /// MINIMUM EIGENVALUE COMPUTATIONS -struct PowerFunctor { +// Template argument Operator just needs multiplication operator +template +class PowerMethod { /** - * \brief Computer i-th Eigenpair with power method + * \brief Compute maximum Eigenpair with power method * * References : * 1) Rosen, D. and Carlone, L., 2017, September. Computational @@ -52,144 +55,180 @@ struct PowerFunctor { * 2) Yulun Tian and Kasra Khosoussi and David M. Rosen and Jonathan P. How, * 2020, Aug, Distributed Certifiably Correct Pose-Graph Optimization, Arxiv * 3) C. de Sa, B. He, I. Mitliagkas, C. Ré, and P. Xu, “Accelerated - * stochastic power iteration,” in Proc. Mach. Learn. Res., no. 84, 2018, pp. 58–67 + * stochastic power iteration,” in Proc. Mach. Learn. Res., no. 84, 2018, pp. + * 58–67 * * It performs the following iteration: \f$ x_{k+1} = A * x_k + \beta * - * x_{k-1} \f$ where A is the certificate matrix, x is the ritz vector + * x_{k-1} \f$ where A is the certificate matrix, x is the Ritz vector * */ - + public: // Const reference to an externally-held matrix whose minimum-eigenvalue we // want to compute - const Sparse &A_; + const Operator &A_; - const Matrix &S_; + const int dim_; // dimension of Matrix A - const int m_n_; // dimension of Matrix A - const int m_nev_; // number of eigenvalues required + size_t nrIterations_; // number of iterations - // flag for running power method or accelerated power method. If false, the former, vice versa. - bool accelerated_; + private: + double ritzValues_; // all Ritz eigenvalues + Vector ritzVectors_; // all Ritz eigenvectors - // a Polyak momentum term - double beta_; + public: + // Constructor + explicit PowerMethod(const Operator &A, const Vector &initial) + : A_(A), dim_(A.rows()), nrIterations_(0) { + Vector x0; + x0 = initial.isZero(0) ? Vector::Random(dim_) : initial; + x0.normalize(); - // const int m_ncv_; // dimention of orthonormal basis subspace - size_t m_niter_; // number of iterations + // initialize Ritz eigen values + ritzValues_ = 0.0; -private: - Vector ritz_val_; // all ritz eigenvalues - Matrix ritz_vectors_; // all ritz eigenvectors - Vector ritz_conv_; // store whether the ritz eigenpair converged - Vector sorted_ritz_val_; // sorted converged eigenvalue - Matrix sorted_ritz_vectors_; // sorted converged eigenvectors + // initialize Ritz eigen vectors + ritzVectors_.resize(dim_, 1); + ritzVectors_.setZero(); -public: - // Constructor - explicit PowerFunctor(const Sparse& A, const Matrix& S, int nev, int ncv, - bool accelerated = false, double beta = 0) - : A_(A), - S_(S), - m_n_(A.rows()), - m_nev_(nev), - // m_ncv_(ncv > m_n_ ? m_n_ : ncv), - accelerated_(accelerated), - beta_(beta), - m_niter_(0) { - // Do nothing - } - - int rows() const { return A_.rows(); } - int cols() const { return A_.cols(); } - - // Matrix-vector multiplication operation - Vector perform_op(const Vector& x1, const Vector& x0) const { - // Do the multiplication - Vector x2 = A_ * x1 - beta_ * x0; - x2.normalize(); - return x2; + ritzVectors_.col(0) = update(x0); + perturb(); } - Vector perform_op(const Vector& x1, const Vector& x0, const double beta) const { - Vector x2 = A_ * x1 - beta * x0; - x2.normalize(); - return x2; + Vector update(const Vector &x) const { + Vector y = A_ * x; + y.normalize(); + return y; } - Vector perform_op(const Vector& x1) const { - Vector x2 = A_ * x1; - x2.normalize(); - return x2; - } + Vector update() const { return update(ritzVectors_); } - Vector perform_op(int i) const { - if (accelerated_) { - Vector x1 = ritz_vectors_.col(i-1); - Vector x2 = ritz_vectors_.col(i-2); - return perform_op(x1, x2); - } else - return perform_op(ritz_vectors_.col(i-1)); - } + void updateRitz(const Vector &ritz) { ritzVectors_ = ritz; } - long next_long_rand(long seed) { - const unsigned int m_a = 16807; - const unsigned long m_max = 2147483647L; - unsigned long lo, hi; + Vector getRitz() { return ritzVectors_; } - lo = m_a * (long)(seed & 0xFFFF); - hi = m_a * (long)((unsigned long)seed >> 16); - lo += (hi & 0x7FFF) << 16; - if (lo > m_max) { - lo &= m_max; - ++lo; + void perturb() { + // generate a 0.03*||x_0||_2 as stated in David's paper + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + std::mt19937 generator(seed); + std::uniform_real_distribution uniform01(0.0, 1.0); + + int n = dim_; + Vector disturb; + disturb.resize(n); + disturb.setZero(); + for (int i = 0; i < n; ++i) { + disturb(i) = uniform01(generator); } - lo += hi >> 15; - if (lo > m_max) { - lo &= m_max; - ++lo; - } - return (long)lo; + disturb.normalize(); + + Vector x0 = ritzVectors_; + double magnitude = x0.norm(); + ritzVectors_ = x0 + 0.03 * magnitude * disturb; } - Vector random_vec(const int len) { - Vector res(len); - const unsigned long m_max = 2147483647L; - for (int i = 0; i < len; i++) { - long m_rand = next_long_rand(m_rand); - res[i] = double(m_rand) / double(m_max) - double(0.5); + // Perform power iteration on a single Ritz value + // Updates ritzValues_ + bool iterateOne(double tol) { + const Vector x = ritzVectors_; + double theta = x.transpose() * A_ * x; + + // store the Ritz eigen value + ritzValues_ = theta; + + const Vector diff = A_ * x - theta * x; + double error = diff.norm(); + return error < tol; + } + + size_t nrIterations() { return nrIterations_; } + + int compute(int maxit, double tol) { + // Starting + int nrConverged = 0; + + for (int i = 0; i < maxit; i++) { + nrIterations_ += 1; + ritzVectors_ = update(); + nrConverged = iterateOne(tol); + if (nrConverged) break; } - res.normalize(); - return res; + + return std::min(1, nrConverged); + } + + double eigenvalues() { return ritzValues_; } + + Vector eigenvectors() { return ritzVectors_; } +}; + +template +class AcceleratedPowerMethod : public PowerMethod { + double beta_ = 0; // a Polyak momentum term + + Vector previousVector_; // store previous vector + + public: + // Constructor + explicit AcceleratedPowerMethod(const Operator &A, const Vector &initial) + : PowerMethod(A, initial) { + Vector x0 = initial; + // initialize ritz vector + x0 = x0.isZero(0) ? Vector::Random(PowerMethod::dim_) : x0; + Vector x00 = Vector::Random(PowerMethod::dim_); + x0.normalize(); + x00.normalize(); + + // initialize Ritz eigen vector and previous vector + previousVector_ = update(x0, x00, beta_); + this->updateRitz(update(previousVector_, x0, beta_)); + this->perturb(); + + // set beta + Vector init_resid = this->getRitz(); + const double up = init_resid.transpose() * this->A_ * init_resid; + const double down = init_resid.transpose().dot(init_resid); + const double mu = up / down; + beta_ = mu * mu / 4; + setBeta(); + } + + Vector update(const Vector &x1, const Vector &x0, const double beta) const { + Vector y = this->A_ * x1 - beta * x0; + y.normalize(); + return y; + } + + Vector update() const { + Vector y = update(this->ritzVectors_, previousVector_, beta_); + previousVector_ = this->ritzVectors_; + return y; } /// Tuning the momentum beta using the Best Heavy Ball algorithm in Ref(3) void setBeta() { - if (m_n_ < 10) return; + if (PowerMethod::dim_ < 10) return; double maxBeta = beta_; size_t maxIndex; - std::vector betas = {2/3*maxBeta, 0.99*maxBeta, maxBeta, 1.01*maxBeta, 1.5*maxBeta}; + std::vector betas = {2 / 3 * maxBeta, 0.99 * maxBeta, maxBeta, + 1.01 * maxBeta, 1.5 * maxBeta}; - Matrix tmp_ritz_vectors; - tmp_ritz_vectors.resize(m_n_, 10); - tmp_ritz_vectors.setZero(); + Matrix tmpRitzVectors; + tmpRitzVectors.resize(PowerMethod::dim_, 10); + tmpRitzVectors.setZero(); for (size_t i = 0; i < 10; i++) { for (size_t k = 0; k < betas.size(); ++k) { for (size_t j = 1; j < 10; j++) { - // double rayleighQuotient; - if (j <2 ) { - Vector x0 = random_vec(m_n_); - Vector x00 = random_vec(m_n_); - tmp_ritz_vectors.col(0) = perform_op(x0, x00, betas[k]); - tmp_ritz_vectors.col(1) = - perform_op(tmp_ritz_vectors.col(0), x0, betas[k]); + if (j < 2) { + Vector x0 = Vector::Random(PowerMethod::dim_); + Vector x00 = Vector::Random(PowerMethod::dim_); + tmpRitzVectors.col(0) = update(x0, x00, betas[k]); + tmpRitzVectors.col(1) = update(tmpRitzVectors.col(0), x0, betas[k]); + } else { + tmpRitzVectors.col(j) = update(tmpRitzVectors.col(j - 1), + tmpRitzVectors.col(j - 2), betas[k]); } - else { - tmp_ritz_vectors.col(j) = - perform_op(tmp_ritz_vectors.col(j - 1), - tmp_ritz_vectors.col(j - 2), betas[k]); - } - const Vector x = tmp_ritz_vectors.col(j); - const double up = x.transpose() * A_ * x; + const Vector x = tmpRitzVectors.col(j); + const double up = x.transpose() * this->A_ * x; const double down = x.transpose().dot(x); const double mu = up / down; if (mu * mu / 4 > maxBeta) { @@ -203,165 +242,6 @@ public: beta_ = betas[maxIndex]; } - - void perturb(int i) { - // generate a 0.03*||x_0||_2 as stated in David's paper - unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); - std::mt19937 generator (seed); - std::uniform_real_distribution uniform01(0.0, 1.0); - - int n = m_n_; - Vector disturb; - disturb.resize(n); - disturb.setZero(); - for (int i =0; i(); - if (error < tol) ritz_conv_(i) = 1; - return error < tol; - } - - int num_converged(double tol) { - int num_converge = 0; - for (int i=0; i0 && i> pairs; - for(int i=0; i& left, const std::pair& right) { - return left.first < right.first; - }); - - // initialzie sorted ritz eigenvalues and eigenvectors - size_t num_converged = pairs.size(); - sorted_ritz_val_.resize(num_converged); - sorted_ritz_val_.setZero(); - sorted_ritz_vectors_.resize(m_n_, num_converged); - sorted_ritz_vectors_.setZero(); - - // fill sorted ritz eigenvalues and eigenvectors with sorted index - for(size_t j=0; j= m_nev_) break; - else reset(); - } - - // sort the result - sort_eigenpair(); - - return std::min(m_nev_, nconv); - } - - Vector eigenvalues() { - return sorted_ritz_val_; - } - - Matrix eigenvectors() { - return sorted_ritz_vectors_; - } - }; -} // namespace gtsam +} // namespace gtsam diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index f287437d4..9ebee4f9f 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -480,8 +480,7 @@ static bool PowerMinimumEigenValue( Eigen::Index numLanczosVectors = 20) { // a. Compute dominant eigenpair of S using power method - PowerFunctor lmOperator(A, S, 1, A.rows()); - lmOperator.init(); + PowerMethod lmOperator(A, S.row(0)); const int lmConverged = lmOperator.compute( maxIterations, 1e-5); @@ -489,34 +488,33 @@ static bool PowerMinimumEigenValue( // Check convergence and bail out if necessary if (lmConverged != 1) return false; - const double lmEigenValue = lmOperator.eigenvalues()(0); + const double lmEigenValue = lmOperator.eigenvalues(); if (lmEigenValue < 0) { // The largest-magnitude eigenvalue is negative, and therefore also the // minimum eigenvalue, so just return this solution *minEigenValue = lmEigenValue; if (minEigenVector) { - *minEigenVector = lmOperator.eigenvectors().col(0); + *minEigenVector = lmOperator.eigenvectors(); minEigenVector->normalize(); // Ensure that this is a unit vector } return true; } Sparse C = lmEigenValue * Matrix::Identity(A.rows(), A.cols()) - A; - PowerFunctor minShiftedOperator(C, S, 1, C.rows(), true); - minShiftedOperator.init(); + AcceleratedPowerMethod minShiftedOperator(C, S.row(0)); const int minConverged = minShiftedOperator.compute( maxIterations, minEigenvalueNonnegativityTolerance / lmEigenValue); if (minConverged != 1) return false; - *minEigenValue = lmEigenValue - minShiftedOperator.eigenvalues()(0); + *minEigenValue = lmEigenValue - minShiftedOperator.eigenvalues(); if (minEigenVector) { - *minEigenVector = minShiftedOperator.eigenvectors().col(0); + *minEigenVector = minShiftedOperator.eigenvectors(); minEigenVector->normalize(); // Ensure that this is a unit vector } - if (numIterations) *numIterations = minShiftedOperator.num_iterations(); + if (numIterations) *numIterations = minShiftedOperator.nrIterations(); return true; } diff --git a/gtsam/sfm/tests/testPowerMethod.cpp b/gtsam/sfm/tests/testPowerMethod.cpp index 4547c91b9..d02906980 100644 --- a/gtsam/sfm/tests/testPowerMethod.cpp +++ b/gtsam/sfm/tests/testPowerMethod.cpp @@ -18,38 +18,34 @@ * @brief Check eigenvalue and eigenvector computed by power method */ +#include +#include +#include +#include #include -#include #include #include #include +#include + #include #include using namespace std; using namespace gtsam; - -ShonanAveraging3 fromExampleName( - const std::string &name, - ShonanAveraging3::Parameters parameters = ShonanAveraging3::Parameters()) { - string g2oFile = findExampleDataFile(name); - return ShonanAveraging3(g2oFile, parameters); -} - -static const ShonanAveraging3 kShonan = fromExampleName("toyExample.g2o"); +using symbol_shorthand::X; /* ************************************************************************* */ TEST(PowerMethod, powerIteration) { - // test power accelerated iteration - gtsam::Sparse A(6, 6); + // test power iteration, beta is set to 0 + Sparse A(6, 6); A.coeffRef(0, 0) = 6; Matrix S = Matrix66::Zero(); - PowerFunctor apf(A, S, 1, A.rows(), true); - apf.init(); + PowerMethod apf(A, S.row(0)); apf.compute(20, 1e-4); - EXPECT_LONGS_EQUAL(6, apf.eigenvectors().cols()); + EXPECT_LONGS_EQUAL(1, apf.eigenvectors().cols()); EXPECT_LONGS_EQUAL(6, apf.eigenvectors().rows()); const Vector6 x1 = (Vector(6) << 1.0, 0.0, 0.0, 0.0, 0.0, 0.0).finished(); @@ -58,21 +54,52 @@ TEST(PowerMethod, powerIteration) { EXPECT(assert_equal(x1, actual0)); const double ev1 = 6.0; - EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalues()(0), 1e-5); + EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalues(), 1e-5); - // test power iteration, beta is set to 0 - PowerFunctor pf(A, S, 1, A.rows()); - pf.init(); + // test power accelerated iteration + AcceleratedPowerMethod pf(A, S.row(0)); pf.compute(20, 1e-4); - // for power method, only 5 ritz vectors converge with 20 iteration - EXPECT_LONGS_EQUAL(5, pf.eigenvectors().cols()); + // for power method, only 5 ritz vectors converge with 20 iterations + EXPECT_LONGS_EQUAL(1, pf.eigenvectors().cols()); EXPECT_LONGS_EQUAL(6, pf.eigenvectors().rows()); Vector6 actual1 = apf.eigenvectors().col(0); actual1(0) = abs(actual1(0)); EXPECT(assert_equal(x1, actual1)); - EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalues()(0), 1e-5); + EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalues(), 1e-5); +} + +/* ************************************************************************* */ +TEST(PowerMethod, useFactorGraph) { + // Let's make a scalar synchronization graph with 4 nodes + GaussianFactorGraph fg; + auto model = noiseModel::Unit::Create(1); + for (size_t j = 0; j < 3; j++) { + fg.add(X(j), -I_1x1, X(j + 1), I_1x1, Vector1::Zero(), model); + } + fg.add(X(3), -I_1x1, X(0), I_1x1, Vector1::Zero(), model); // extra row + + // Get eigenvalues and eigenvectors with Eigen + auto L = fg.hessian(); + cout << L.first << endl; + Eigen::EigenSolver solver(L.first); + cout << solver.eigenvalues() << endl; + cout << solver.eigenvectors() << endl; + + // Check that we get zero eigenvalue and "constant" eigenvector + EXPECT_DOUBLES_EQUAL(0.0, solver.eigenvalues()[0].real(), 1e-9); + auto v0 = solver.eigenvectors().col(0); + for (size_t j = 0; j < 3; j++) + EXPECT_DOUBLES_EQUAL(-0.5, v0[j].real(), 1e-9); + + // test power iteration, beta is set to 0 + Matrix S = Matrix44::Zero(); + // PowerMethod pf(L.first, S.row(0)); + AcceleratedPowerMethod pf(L.first, S.row(0)); + pf.compute(20, 1e-4); + cout << pf.eigenvalues() << endl; + cout << pf.eigenvectors() << endl; } /* ************************************************************************* */ From b7f29a051a4b8f77c6bdd1e65490c579db0c1272 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Tue, 13 Oct 2020 02:34:24 -0400 Subject: [PATCH 018/261] Reformat code. --- gtsam/linear/AcceleratedPowerMethod.h | 135 ++++++++++ gtsam/linear/PowerMethod.h | 140 ++++++++++ .../tests/testAcceleratedPowerMethod.cpp | 107 ++++++++ .../{sfm => linear}/tests/testPowerMethod.cpp | 55 ++-- gtsam/sfm/PowerMethod.h | 247 ------------------ gtsam/sfm/ShonanAveraging.cpp | 19 +- gtsam/sfm/ShonanAveraging.h | 3 +- 7 files changed, 422 insertions(+), 284 deletions(-) create mode 100644 gtsam/linear/AcceleratedPowerMethod.h create mode 100644 gtsam/linear/PowerMethod.h create mode 100644 gtsam/linear/tests/testAcceleratedPowerMethod.cpp rename gtsam/{sfm => linear}/tests/testPowerMethod.cpp (70%) delete mode 100644 gtsam/sfm/PowerMethod.h diff --git a/gtsam/linear/AcceleratedPowerMethod.h b/gtsam/linear/AcceleratedPowerMethod.h new file mode 100644 index 000000000..2cbcaf67e --- /dev/null +++ b/gtsam/linear/AcceleratedPowerMethod.h @@ -0,0 +1,135 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010-2019, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file AcceleratedPowerMethod.h + * @date Sept 2020 + * @author Jing Wu + * @brief accelerated power method for fast eigenvalue and eigenvector + * computation + */ + +#pragma once + +// #include +// #include +#include + +namespace gtsam { + +using Sparse = Eigen::SparseMatrix; + +/* ************************************************************************* */ +/// MINIMUM EIGENVALUE COMPUTATIONS + +// Template argument Operator just needs multiplication operator +template +class AcceleratedPowerMethod : public PowerMethod { + /** + * \brief Compute maximum Eigenpair with power method + * + * References : + * 1) Rosen, D. and Carlone, L., 2017, September. Computational + * enhancements for certifiably correct SLAM. In Proceedings of the + * International Conference on Intelligent Robots and Systems. + * 2) Yulun Tian and Kasra Khosoussi and David M. Rosen and Jonathan P. How, + * 2020, Aug, Distributed Certifiably Correct Pose-Graph Optimization, Arxiv + * 3) C. de Sa, B. He, I. Mitliagkas, C. Ré, and P. Xu, “Accelerated + * stochastic power iteration,” in Proc. Mach. Learn. Res., no. 84, 2018, pp. + * 58–67 + * + * It performs the following iteration: \f$ x_{k+1} = A * x_k + \beta * + * x_{k-1} \f$ where A is the certificate matrix, x is the Ritz vector + * + */ + + double beta_ = 0; // a Polyak momentum term + + Vector previousVector_; // store previous vector + + public: + // Constructor from aim matrix A (given as Matrix or Sparse), optional intial + // vector as ritzVector + explicit AcceleratedPowerMethod( + const Operator &A, const boost::optional initial = boost::none) + : PowerMethod(A, initial) { + Vector x0; + // initialize ritz vector + x0 = initial ? Vector::Random(this->dim_) : initial.get(); + Vector x00 = Vector::Random(this->dim_); + x0.normalize(); + x00.normalize(); + + // initialize Ritz eigen vector and previous vector + previousVector_ = update(x0, x00, beta_); + this->updateRitz(update(previousVector_, x0, beta_)); + this->ritzVector_ = update(previousVector_, x0, beta_); + // this->updateRitz(update(previousVector_, x0, beta_)); + this->perturb(); + + // set beta + Vector init_resid = this->ritzVector_; + const double up = init_resid.transpose() * this->A_ * init_resid; + const double down = init_resid.transpose().dot(init_resid); + const double mu = up / down; + beta_ = mu * mu / 4; + setBeta(); + } + + // Update the ritzVector with beta and previous two ritzVector + Vector update(const Vector &x1, const Vector &x0, const double beta) const { + Vector y = this->A_ * x1 - beta * x0; + y.normalize(); + return y; + } + + // Update the ritzVector with beta and previous two ritzVector + Vector update() const { + Vector y = update(this->ritzVector_, previousVector_, beta_); + previousVector_ = this->ritzVector_; + return y; + } + + // Tuning the momentum beta using the Best Heavy Ball algorithm in Ref(3) + void setBeta() { + double maxBeta = beta_; + size_t maxIndex; + std::vector betas = {2 / 3 * maxBeta, 0.99 * maxBeta, maxBeta, + 1.01 * maxBeta, 1.5 * maxBeta}; + + Matrix R = Matrix::Zero(this->dim_, 10); + for (size_t i = 0; i < 10; i++) { + for (size_t k = 0; k < betas.size(); ++k) { + for (size_t j = 1; j < 10; j++) { + if (j < 2) { + Vector x0 = this->ritzVector_; + Vector x00 = previousVector_; + R.col(0) = update(x0, x00, betas[k]); + R.col(1) = update(R.col(0), x0, betas[k]); + } else { + R.col(j) = update(R.col(j - 1), R.col(j - 2), betas[k]); + } + } + const Vector x = R.col(9); + const double up = x.transpose() * this->A_ * x; + const double down = x.transpose().dot(x); + const double mu = up / down; + if (mu * mu / 4 > maxBeta) { + maxIndex = k; + maxBeta = mu * mu / 4; + } + } + } + beta_ = betas[maxIndex]; + } +}; + +} // namespace gtsam diff --git a/gtsam/linear/PowerMethod.h b/gtsam/linear/PowerMethod.h new file mode 100644 index 000000000..fe9aabb46 --- /dev/null +++ b/gtsam/linear/PowerMethod.h @@ -0,0 +1,140 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010-2019, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file PowerMethod.h + * @date Sept 2020 + * @author Jing Wu + * @brief Power method for fast eigenvalue and eigenvector + * computation + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace gtsam { + +using Sparse = Eigen::SparseMatrix; + +/* ************************************************************************* */ +/// MINIMUM EIGENVALUE COMPUTATIONS + +// Template argument Operator just needs multiplication operator +template +class PowerMethod { + protected: + // Const reference to an externally-held matrix whose minimum-eigenvalue we + // want to compute + const Operator &A_; + + const int dim_; // dimension of Matrix A + + size_t nrIterations_; // number of iterations + + double ritzValue_; // all Ritz eigenvalues + Vector ritzVector_; // all Ritz eigenvectors + + public: + // Constructor + explicit PowerMethod(const Operator &A, + const boost::optional initial = boost::none) + : A_(A), dim_(A.rows()), nrIterations_(0) { + Vector x0; + x0 = initial ? Vector::Random(dim_) : initial.get(); + x0.normalize(); + + // initialize Ritz eigen values + ritzValue_ = 0.0; + + // initialize Ritz eigen vectors + ritzVector_ = Vector::Zero(dim_); + + ritzVector_.col(0) = update(x0); + perturb(); + } + + // Update the vector by dot product with A_ + Vector update(const Vector &x) const { + Vector y = A_ * x; + y.normalize(); + return y; + } + + Vector update() const { return update(ritzVector_); } + + // Update the ritzVector_ + void updateRitz(const Vector &ritz) { ritzVector_ = ritz; } + + // Perturb the initial ritzvector + void perturb() { + // generate a 0.03*||x_0||_2 as stated in David's paper + std::mt19937 rng(42); + std::uniform_real_distribution uniform01(0.0, 1.0); + + int n = dim_; + Vector disturb(n); + for (int i = 0; i < n; ++i) { + disturb(i) = uniform01(rng); + } + disturb.normalize(); + + Vector x0 = ritzVector_; + double magnitude = x0.norm(); + ritzVector_ = x0 + 0.03 * magnitude * disturb; + } + + // Perform power iteration on a single Ritz value + // Updates ritzValue_ + bool iterateOne(double tol) { + const Vector x = ritzVector_; + double theta = x.transpose() * A_ * x; + + // store the Ritz eigen value + ritzValue_ = theta; + + const Vector diff = A_ * x - theta * x; + double error = diff.norm(); + return error < tol; + } + + // Return the number of iterations + size_t nrIterations() const { return nrIterations_; } + + // Start the iteration until the ritz error converge + int compute(int maxIterations, double tol) { + // Starting + int nrConverged = 0; + + for (int i = 0; i < maxIterations; i++) { + nrIterations_ += 1; + ritzVector_ = update(); + nrConverged = iterateOne(tol); + if (nrConverged) break; + } + + return std::min(1, nrConverged); + } + + // Return the eigenvalue + double eigenvalues() const { return ritzValue_; } + + // Return the eigenvector + const Vector eigenvectors() const { return ritzVector_; } +}; + +} // namespace gtsam diff --git a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp new file mode 100644 index 000000000..2a117d53b --- /dev/null +++ b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp @@ -0,0 +1,107 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010-2019, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * testPowerMethod.cpp + * + * @file testAcceleratedPowerMethod.cpp + * @date Sept 2020 + * @author Jing Wu + * @brief Check eigenvalue and eigenvector computed by accelerated power method + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +using namespace std; +using namespace gtsam; +using symbol_shorthand::X; + +/* ************************************************************************* */ +TEST(AcceleratedPowerMethod, acceleratedPowerIteration) { + // test power iteration, beta is set to 0 + Sparse A(6, 6); + A.coeffRef(0, 0) = 6; + A.coeffRef(0, 0) = 5; + A.coeffRef(0, 0) = 4; + A.coeffRef(0, 0) = 3; + A.coeffRef(0, 0) = 2; + A.coeffRef(0, 0) = 1; + Vector initial = Vector6::Zero(); + const Vector6 x1 = (Vector(6) << 1.0, 0.0, 0.0, 0.0, 0.0, 0.0).finished(); + const double ev1 = 1.0; + + // test accelerated power iteration + AcceleratedPowerMethod apf(A, initial); + apf.compute(20, 1e-4); + EXPECT_LONGS_EQUAL(1, apf.eigenvectors().cols()); + EXPECT_LONGS_EQUAL(6, apf.eigenvectors().rows()); + + Vector6 actual1 = apf.eigenvectors(); + // actual1(0) = abs (actual1(0)); + EXPECT(assert_equal(x1, actual1)); + + EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalues(), 1e-5); +} + +/* ************************************************************************* */ +TEST(AcceleratedPowerMethod, useFactorGraph) { + // Let's make a scalar synchronization graph with 4 nodes + GaussianFactorGraph fg; + auto model = noiseModel::Unit::Create(1); + for (size_t j = 0; j < 3; j++) { + fg.add(X(j), -I_1x1, X(j + 1), I_1x1, Vector1::Zero(), model); + } + fg.add(X(3), -I_1x1, X(0), I_1x1, Vector1::Zero(), model); // extra row + + // Get eigenvalues and eigenvectors with Eigen + auto L = fg.hessian(); + Eigen::EigenSolver solver(L.first); + + // Check that we get zero eigenvalue and "constant" eigenvector + EXPECT_DOUBLES_EQUAL(0.0, solver.eigenvalues()[0].real(), 1e-9); + auto v0 = solver.eigenvectors().col(0); + for (size_t j = 0; j < 3; j++) + EXPECT_DOUBLES_EQUAL(-0.5, v0[j].real(), 1e-9); + + size_t maxIdx = 0; + for (auto i =0; i= solver.eigenvalues()(maxIdx).real()) maxIdx = i; + } + // Store the max eigenvalue and its according eigenvector + const auto ev1 = solver.eigenvalues()(maxIdx).real(); + auto ev2 = solver.eigenvectors().col(maxIdx).real(); + + Vector initial = Vector4::Zero(); + AcceleratedPowerMethod apf(L.first, initial); + apf.compute(20, 1e-4); + EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalues(), 1e-8); + EXPECT(assert_equal(ev2, apf.eigenvectors(), 3e-5)); +} + +/* ************************************************************************* */ +int main() { + TestResult tr; + return TestRegistry::runAllTests(tr); +} +/* ************************************************************************* */ diff --git a/gtsam/sfm/tests/testPowerMethod.cpp b/gtsam/linear/tests/testPowerMethod.cpp similarity index 70% rename from gtsam/sfm/tests/testPowerMethod.cpp rename to gtsam/linear/tests/testPowerMethod.cpp index d02906980..621286c85 100644 --- a/gtsam/sfm/tests/testPowerMethod.cpp +++ b/gtsam/linear/tests/testPowerMethod.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include @@ -42,31 +42,22 @@ TEST(PowerMethod, powerIteration) { // test power iteration, beta is set to 0 Sparse A(6, 6); A.coeffRef(0, 0) = 6; - Matrix S = Matrix66::Zero(); - PowerMethod apf(A, S.row(0)); - apf.compute(20, 1e-4); - EXPECT_LONGS_EQUAL(1, apf.eigenvectors().cols()); - EXPECT_LONGS_EQUAL(6, apf.eigenvectors().rows()); - - const Vector6 x1 = (Vector(6) << 1.0, 0.0, 0.0, 0.0, 0.0, 0.0).finished(); - Vector6 actual0 = apf.eigenvectors().col(0); - actual0(0) = abs(actual0(0)); - EXPECT(assert_equal(x1, actual0)); - - const double ev1 = 6.0; - EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalues(), 1e-5); - - // test power accelerated iteration - AcceleratedPowerMethod pf(A, S.row(0)); + A.coeffRef(0, 0) = 5; + A.coeffRef(0, 0) = 4; + A.coeffRef(0, 0) = 3; + A.coeffRef(0, 0) = 2; + A.coeffRef(0, 0) = 1; + Vector initial = Vector6::Zero(); + PowerMethod pf(A, initial); pf.compute(20, 1e-4); - // for power method, only 5 ritz vectors converge with 20 iterations EXPECT_LONGS_EQUAL(1, pf.eigenvectors().cols()); EXPECT_LONGS_EQUAL(6, pf.eigenvectors().rows()); - Vector6 actual1 = apf.eigenvectors().col(0); - actual1(0) = abs(actual1(0)); - EXPECT(assert_equal(x1, actual1)); + const Vector6 x1 = (Vector(6) << 1.0, 0.0, 0.0, 0.0, 0.0, 0.0).finished(); + Vector6 actual0 = pf.eigenvectors(); + EXPECT(assert_equal(x1, actual0)); + const double ev1 = 1.0; EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalues(), 1e-5); } @@ -82,10 +73,7 @@ TEST(PowerMethod, useFactorGraph) { // Get eigenvalues and eigenvectors with Eigen auto L = fg.hessian(); - cout << L.first << endl; Eigen::EigenSolver solver(L.first); - cout << solver.eigenvalues() << endl; - cout << solver.eigenvectors() << endl; // Check that we get zero eigenvalue and "constant" eigenvector EXPECT_DOUBLES_EQUAL(0.0, solver.eigenvalues()[0].real(), 1e-9); @@ -93,13 +81,20 @@ TEST(PowerMethod, useFactorGraph) { for (size_t j = 0; j < 3; j++) EXPECT_DOUBLES_EQUAL(-0.5, v0[j].real(), 1e-9); - // test power iteration, beta is set to 0 - Matrix S = Matrix44::Zero(); - // PowerMethod pf(L.first, S.row(0)); - AcceleratedPowerMethod pf(L.first, S.row(0)); + size_t maxIdx = 0; + for (auto i =0; i= solver.eigenvalues()(maxIdx).real()) maxIdx = i; + } + // Store the max eigenvalue and its according eigenvector + const auto ev1 = solver.eigenvalues()(maxIdx).real(); + auto ev2 = solver.eigenvectors().col(maxIdx).real(); + + Vector initial = Vector4::Zero(); + PowerMethod pf(L.first, initial); pf.compute(20, 1e-4); - cout << pf.eigenvalues() << endl; - cout << pf.eigenvectors() << endl; + EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalues(), 1e-8); + // auto actual2 = pf.eigenvectors(); + // EXPECT(assert_equal(ev2, actual2, 3e-5)); } /* ************************************************************************* */ diff --git a/gtsam/sfm/PowerMethod.h b/gtsam/sfm/PowerMethod.h deleted file mode 100644 index 5fa355aaa..000000000 --- a/gtsam/sfm/PowerMethod.h +++ /dev/null @@ -1,247 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010-2019, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file PowerMethod.h - * @date Sept 2020 - * @author Jing Wu - * @brief accelerated power method for fast eigenvalue and eigenvector - * computation - */ - -#pragma once - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace gtsam { - -using Sparse = Eigen::SparseMatrix; - -/* ************************************************************************* */ -/// MINIMUM EIGENVALUE COMPUTATIONS - -// Template argument Operator just needs multiplication operator -template -class PowerMethod { - /** - * \brief Compute maximum Eigenpair with power method - * - * References : - * 1) Rosen, D. and Carlone, L., 2017, September. Computational - * enhancements for certifiably correct SLAM. In Proceedings of the - * International Conference on Intelligent Robots and Systems. - * 2) Yulun Tian and Kasra Khosoussi and David M. Rosen and Jonathan P. How, - * 2020, Aug, Distributed Certifiably Correct Pose-Graph Optimization, Arxiv - * 3) C. de Sa, B. He, I. Mitliagkas, C. Ré, and P. Xu, “Accelerated - * stochastic power iteration,” in Proc. Mach. Learn. Res., no. 84, 2018, pp. - * 58–67 - * - * It performs the following iteration: \f$ x_{k+1} = A * x_k + \beta * - * x_{k-1} \f$ where A is the certificate matrix, x is the Ritz vector - * - */ - public: - // Const reference to an externally-held matrix whose minimum-eigenvalue we - // want to compute - const Operator &A_; - - const int dim_; // dimension of Matrix A - - size_t nrIterations_; // number of iterations - - private: - double ritzValues_; // all Ritz eigenvalues - Vector ritzVectors_; // all Ritz eigenvectors - - public: - // Constructor - explicit PowerMethod(const Operator &A, const Vector &initial) - : A_(A), dim_(A.rows()), nrIterations_(0) { - Vector x0; - x0 = initial.isZero(0) ? Vector::Random(dim_) : initial; - x0.normalize(); - - // initialize Ritz eigen values - ritzValues_ = 0.0; - - // initialize Ritz eigen vectors - ritzVectors_.resize(dim_, 1); - ritzVectors_.setZero(); - - ritzVectors_.col(0) = update(x0); - perturb(); - } - - Vector update(const Vector &x) const { - Vector y = A_ * x; - y.normalize(); - return y; - } - - Vector update() const { return update(ritzVectors_); } - - void updateRitz(const Vector &ritz) { ritzVectors_ = ritz; } - - Vector getRitz() { return ritzVectors_; } - - void perturb() { - // generate a 0.03*||x_0||_2 as stated in David's paper - unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); - std::mt19937 generator(seed); - std::uniform_real_distribution uniform01(0.0, 1.0); - - int n = dim_; - Vector disturb; - disturb.resize(n); - disturb.setZero(); - for (int i = 0; i < n; ++i) { - disturb(i) = uniform01(generator); - } - disturb.normalize(); - - Vector x0 = ritzVectors_; - double magnitude = x0.norm(); - ritzVectors_ = x0 + 0.03 * magnitude * disturb; - } - - // Perform power iteration on a single Ritz value - // Updates ritzValues_ - bool iterateOne(double tol) { - const Vector x = ritzVectors_; - double theta = x.transpose() * A_ * x; - - // store the Ritz eigen value - ritzValues_ = theta; - - const Vector diff = A_ * x - theta * x; - double error = diff.norm(); - return error < tol; - } - - size_t nrIterations() { return nrIterations_; } - - int compute(int maxit, double tol) { - // Starting - int nrConverged = 0; - - for (int i = 0; i < maxit; i++) { - nrIterations_ += 1; - ritzVectors_ = update(); - nrConverged = iterateOne(tol); - if (nrConverged) break; - } - - return std::min(1, nrConverged); - } - - double eigenvalues() { return ritzValues_; } - - Vector eigenvectors() { return ritzVectors_; } -}; - -template -class AcceleratedPowerMethod : public PowerMethod { - double beta_ = 0; // a Polyak momentum term - - Vector previousVector_; // store previous vector - - public: - // Constructor - explicit AcceleratedPowerMethod(const Operator &A, const Vector &initial) - : PowerMethod(A, initial) { - Vector x0 = initial; - // initialize ritz vector - x0 = x0.isZero(0) ? Vector::Random(PowerMethod::dim_) : x0; - Vector x00 = Vector::Random(PowerMethod::dim_); - x0.normalize(); - x00.normalize(); - - // initialize Ritz eigen vector and previous vector - previousVector_ = update(x0, x00, beta_); - this->updateRitz(update(previousVector_, x0, beta_)); - this->perturb(); - - // set beta - Vector init_resid = this->getRitz(); - const double up = init_resid.transpose() * this->A_ * init_resid; - const double down = init_resid.transpose().dot(init_resid); - const double mu = up / down; - beta_ = mu * mu / 4; - setBeta(); - } - - Vector update(const Vector &x1, const Vector &x0, const double beta) const { - Vector y = this->A_ * x1 - beta * x0; - y.normalize(); - return y; - } - - Vector update() const { - Vector y = update(this->ritzVectors_, previousVector_, beta_); - previousVector_ = this->ritzVectors_; - return y; - } - - /// Tuning the momentum beta using the Best Heavy Ball algorithm in Ref(3) - void setBeta() { - if (PowerMethod::dim_ < 10) return; - double maxBeta = beta_; - size_t maxIndex; - std::vector betas = {2 / 3 * maxBeta, 0.99 * maxBeta, maxBeta, - 1.01 * maxBeta, 1.5 * maxBeta}; - - Matrix tmpRitzVectors; - tmpRitzVectors.resize(PowerMethod::dim_, 10); - tmpRitzVectors.setZero(); - for (size_t i = 0; i < 10; i++) { - for (size_t k = 0; k < betas.size(); ++k) { - for (size_t j = 1; j < 10; j++) { - if (j < 2) { - Vector x0 = Vector::Random(PowerMethod::dim_); - Vector x00 = Vector::Random(PowerMethod::dim_); - tmpRitzVectors.col(0) = update(x0, x00, betas[k]); - tmpRitzVectors.col(1) = update(tmpRitzVectors.col(0), x0, betas[k]); - } else { - tmpRitzVectors.col(j) = update(tmpRitzVectors.col(j - 1), - tmpRitzVectors.col(j - 2), betas[k]); - } - const Vector x = tmpRitzVectors.col(j); - const double up = x.transpose() * this->A_ * x; - const double down = x.transpose().dot(x); - const double mu = up / down; - if (mu * mu / 4 > maxBeta) { - maxIndex = k; - maxBeta = mu * mu / 4; - break; - } - } - } - } - - beta_ = betas[maxIndex]; - } -}; - -} // namespace gtsam diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 9ebee4f9f..5f509c91e 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -471,16 +471,23 @@ Sparse ShonanAveraging::computeA(const Values &values) const { return Lambda - Q_; } -// Alg.6 from paper Distributed Certifiably Correct Pose-Graph Optimization +/* ************************************************************************* */ +/// MINIMUM EIGENVALUE COMPUTATIONS +// Alg.6 from paper Distributed Certifiably Correct Pose-Graph Optimization, +// it takes in the certificate matrix A as input, the maxIterations and the +// minEigenvalueNonnegativityTolerance is set to 1000 and 10e-4 ad default, +// there are two parts +// in this algorithm: +// (1) static bool PowerMinimumEigenValue( const Sparse &A, const Matrix &S, double *minEigenValue, Vector *minEigenVector = 0, size_t *numIterations = 0, size_t maxIterations = 1000, - double minEigenvalueNonnegativityTolerance = 10e-4, - Eigen::Index numLanczosVectors = 20) { + double minEigenvalueNonnegativityTolerance = 10e-4) { // a. Compute dominant eigenpair of S using power method - PowerMethod lmOperator(A, S.row(0)); + const boost::optional initial(S.row(0)); + PowerMethod lmOperator(A, initial); const int lmConverged = lmOperator.compute( maxIterations, 1e-5); @@ -501,8 +508,8 @@ static bool PowerMinimumEigenValue( return true; } - Sparse C = lmEigenValue * Matrix::Identity(A.rows(), A.cols()) - A; - AcceleratedPowerMethod minShiftedOperator(C, S.row(0)); + const Sparse C = lmEigenValue * Matrix::Identity(A.rows(), A.cols()) - A; + AcceleratedPowerMethod minShiftedOperator(C, initial); const int minConverged = minShiftedOperator.compute( maxIterations, minEigenvalueNonnegativityTolerance / lmEigenValue); diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index 9d117a266..49659386f 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -26,7 +26,8 @@ #include #include #include -#include +#include +#include #include #include From fbebd3ed6954fed7766c31a172e8761cc0c56ef7 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Tue, 13 Oct 2020 12:00:25 -0400 Subject: [PATCH 019/261] Small fix --- gtsam/linear/AcceleratedPowerMethod.h | 2 -- gtsam/linear/PowerMethod.h | 13 ++++++------- gtsam/linear/tests/testAcceleratedPowerMethod.cpp | 3 +++ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/gtsam/linear/AcceleratedPowerMethod.h b/gtsam/linear/AcceleratedPowerMethod.h index 2cbcaf67e..0e47c6a53 100644 --- a/gtsam/linear/AcceleratedPowerMethod.h +++ b/gtsam/linear/AcceleratedPowerMethod.h @@ -70,9 +70,7 @@ class AcceleratedPowerMethod : public PowerMethod { // initialize Ritz eigen vector and previous vector previousVector_ = update(x0, x00, beta_); - this->updateRitz(update(previousVector_, x0, beta_)); this->ritzVector_ = update(previousVector_, x0, beta_); - // this->updateRitz(update(previousVector_, x0, beta_)); this->perturb(); // set beta diff --git a/gtsam/linear/PowerMethod.h b/gtsam/linear/PowerMethod.h index fe9aabb46..4807e0e6a 100644 --- a/gtsam/linear/PowerMethod.h +++ b/gtsam/linear/PowerMethod.h @@ -75,11 +75,9 @@ class PowerMethod { return y; } + // Update the vector by dot product with A_ Vector update() const { return update(ritzVector_); } - // Update the ritzVector_ - void updateRitz(const Vector &ritz) { ritzVector_ = ritz; } - // Perturb the initial ritzvector void perturb() { // generate a 0.03*||x_0||_2 as stated in David's paper @@ -87,10 +85,11 @@ class PowerMethod { std::uniform_real_distribution uniform01(0.0, 1.0); int n = dim_; - Vector disturb(n); - for (int i = 0; i < n; ++i) { - disturb(i) = uniform01(rng); - } + // Vector disturb(n); + // for (int i = 0; i < n; ++i) { + // disturb(i) = uniform01(rng); + // } + Vector disturb = Vector::Random(n); disturb.normalize(); Vector x0 = ritzVector_; diff --git a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp index 2a117d53b..a84a31a0f 100644 --- a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp +++ b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp @@ -76,7 +76,10 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { // Get eigenvalues and eigenvectors with Eigen auto L = fg.hessian(); + cout << L.first << endl; Eigen::EigenSolver solver(L.first); + cout << solver.eigenvalues() << endl; + cout << solver.eigenvectors() << endl; // Check that we get zero eigenvalue and "constant" eigenvector EXPECT_DOUBLES_EQUAL(0.0, solver.eigenvalues()[0].real(), 1e-9); From 5f50e740b746573e6b85e1c300e6f50c9c593828 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Thu, 22 Oct 2020 14:19:05 -0400 Subject: [PATCH 020/261] Revise according to Frank and David's comments --- gtsam/linear/AcceleratedPowerMethod.h | 53 +++++++++++--------- gtsam/linear/PowerMethod.h | 72 +++++++++------------------ gtsam/sfm/ShonanAveraging.cpp | 61 +++++++++++++++-------- 3 files changed, 94 insertions(+), 92 deletions(-) diff --git a/gtsam/linear/AcceleratedPowerMethod.h b/gtsam/linear/AcceleratedPowerMethod.h index 0e47c6a53..0ad87626b 100644 --- a/gtsam/linear/AcceleratedPowerMethod.h +++ b/gtsam/linear/AcceleratedPowerMethod.h @@ -34,7 +34,7 @@ using Sparse = Eigen::SparseMatrix; template class AcceleratedPowerMethod : public PowerMethod { /** - * \brief Compute maximum Eigenpair with power method + * \brief Compute maximum Eigenpair with accelerated power method * * References : * 1) Rosen, D. and Carlone, L., 2017, September. Computational @@ -46,8 +46,9 @@ class AcceleratedPowerMethod : public PowerMethod { * stochastic power iteration,” in Proc. Mach. Learn. Res., no. 84, 2018, pp. * 58–67 * - * It performs the following iteration: \f$ x_{k+1} = A * x_k + \beta * - * x_{k-1} \f$ where A is the certificate matrix, x is the Ritz vector + * It performs the following iteration: \f$ x_{k+1} = A * x_k - \beta * + * x_{k-1} \f$ where A is the aim matrix we want to get eigenpair of, x is the + * Ritz vector * */ @@ -59,46 +60,52 @@ class AcceleratedPowerMethod : public PowerMethod { // Constructor from aim matrix A (given as Matrix or Sparse), optional intial // vector as ritzVector explicit AcceleratedPowerMethod( - const Operator &A, const boost::optional initial = boost::none) + const Operator &A, const boost::optional initial = boost::none, + const double initialBeta = 0.0) : PowerMethod(A, initial) { Vector x0; // initialize ritz vector - x0 = initial ? Vector::Random(this->dim_) : initial.get(); + x0 = initial ? initial.get() : Vector::Random(this->dim_); Vector x00 = Vector::Random(this->dim_); x0.normalize(); x00.normalize(); // initialize Ritz eigen vector and previous vector - previousVector_ = update(x0, x00, beta_); - this->ritzVector_ = update(previousVector_, x0, beta_); - this->perturb(); + previousVector_ = powerIteration(x0, x00, beta_); + this->ritzVector_ = powerIteration(previousVector_, x0, beta_); - // set beta - Vector init_resid = this->ritzVector_; - const double up = init_resid.transpose() * this->A_ * init_resid; - const double down = init_resid.transpose().dot(init_resid); - const double mu = up / down; - beta_ = mu * mu / 4; - setBeta(); + // initialize beta_ + if (!initialBeta) { + estimateBeta(); + } else { + beta_ = initialBeta; + } + } // Update the ritzVector with beta and previous two ritzVector - Vector update(const Vector &x1, const Vector &x0, const double beta) const { + Vector powerIteration(const Vector &x1, const Vector &x0, + const double beta) const { Vector y = this->A_ * x1 - beta * x0; y.normalize(); return y; } // Update the ritzVector with beta and previous two ritzVector - Vector update() const { - Vector y = update(this->ritzVector_, previousVector_, beta_); + Vector powerIteration() const { + Vector y = powerIteration(this->ritzVector_, previousVector_, beta_); previousVector_ = this->ritzVector_; return y; } // Tuning the momentum beta using the Best Heavy Ball algorithm in Ref(3) - void setBeta() { - double maxBeta = beta_; + void estimateBeta() { + // set beta + Vector init_resid = this->ritzVector_; + const double up = init_resid.transpose() * this->A_ * init_resid; + const double down = init_resid.transpose().dot(init_resid); + const double mu = up / down; + double maxBeta = mu * mu / 4; size_t maxIndex; std::vector betas = {2 / 3 * maxBeta, 0.99 * maxBeta, maxBeta, 1.01 * maxBeta, 1.5 * maxBeta}; @@ -110,10 +117,10 @@ class AcceleratedPowerMethod : public PowerMethod { if (j < 2) { Vector x0 = this->ritzVector_; Vector x00 = previousVector_; - R.col(0) = update(x0, x00, betas[k]); - R.col(1) = update(R.col(0), x0, betas[k]); + R.col(0) = powerIteration(x0, x00, betas[k]); + R.col(1) = powerIteration(R.col(0), x0, betas[k]); } else { - R.col(j) = update(R.col(j - 1), R.col(j - 2), betas[k]); + R.col(j) = powerIteration(R.col(j - 1), R.col(j - 2), betas[k]); } } const Vector x = R.col(9); diff --git a/gtsam/linear/PowerMethod.h b/gtsam/linear/PowerMethod.h index 4807e0e6a..ee7a04429 100644 --- a/gtsam/linear/PowerMethod.h +++ b/gtsam/linear/PowerMethod.h @@ -46,8 +46,8 @@ class PowerMethod { size_t nrIterations_; // number of iterations - double ritzValue_; // all Ritz eigenvalues - Vector ritzVector_; // all Ritz eigenvectors + double ritzValue_; // Ritz eigenvalue + Vector ritzVector_; // Ritz eigenvector public: // Constructor @@ -55,85 +55,61 @@ class PowerMethod { const boost::optional initial = boost::none) : A_(A), dim_(A.rows()), nrIterations_(0) { Vector x0; - x0 = initial ? Vector::Random(dim_) : initial.get(); + x0 = initial ? initial.get() : Vector::Random(dim_); x0.normalize(); - // initialize Ritz eigen values + // initialize Ritz eigen value ritzValue_ = 0.0; // initialize Ritz eigen vectors ritzVector_ = Vector::Zero(dim_); - - ritzVector_.col(0) = update(x0); - perturb(); + ritzVector_ = powerIteration(x0); } // Update the vector by dot product with A_ - Vector update(const Vector &x) const { + Vector powerIteration(const Vector &x) const { Vector y = A_ * x; y.normalize(); return y; } // Update the vector by dot product with A_ - Vector update() const { return update(ritzVector_); } + Vector powerIteration() const { return powerIteration(ritzVector_); } - // Perturb the initial ritzvector - void perturb() { - // generate a 0.03*||x_0||_2 as stated in David's paper - std::mt19937 rng(42); - std::uniform_real_distribution uniform01(0.0, 1.0); - - int n = dim_; - // Vector disturb(n); - // for (int i = 0; i < n; ++i) { - // disturb(i) = uniform01(rng); - // } - Vector disturb = Vector::Random(n); - disturb.normalize(); - - Vector x0 = ritzVector_; - double magnitude = x0.norm(); - ritzVector_ = x0 + 0.03 * magnitude * disturb; - } - - // Perform power iteration on a single Ritz value - // Updates ritzValue_ - bool iterateOne(double tol) { + // After Perform power iteration on a single Ritz value, if the error is less + // than the tol then return true else false + bool converged(double tol) { const Vector x = ritzVector_; - double theta = x.transpose() * A_ * x; - // store the Ritz eigen value - ritzValue_ = theta; - - const Vector diff = A_ * x - theta * x; - double error = diff.norm(); + ritzValue_ = x.dot(A_ * x); + double error = (A_ * x - ritzValue_ * x).norm(); return error < tol; } // Return the number of iterations size_t nrIterations() const { return nrIterations_; } - // Start the iteration until the ritz error converge - int compute(int maxIterations, double tol) { + // Start the power/accelerated iteration, after updated the ritz vector, + // calculate the ritz error, repeat this operation until the ritz error converge + int compute(size_t maxIterations, double tol) { // Starting - int nrConverged = 0; + bool isConverged = false; - for (int i = 0; i < maxIterations; i++) { - nrIterations_ += 1; - ritzVector_ = update(); - nrConverged = iterateOne(tol); - if (nrConverged) break; + for (size_t i = 0; i < maxIterations; i++) { + ++nrIterations_ ; + ritzVector_ = powerIteration(); + isConverged = converged(tol); + if (isConverged) return isConverged; } - return std::min(1, nrConverged); + return isConverged; } // Return the eigenvalue - double eigenvalues() const { return ritzValue_; } + double eigenvalue() const { return ritzValue_; } // Return the eigenvector - const Vector eigenvectors() const { return ritzVector_; } + Vector eigenvector() const { return ritzVector_; } }; } // namespace gtsam diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 5f509c91e..60233fc6e 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -471,14 +471,40 @@ Sparse ShonanAveraging::computeA(const Values &values) const { return Lambda - Q_; } +/* ************************************************************************* */ +template +Sparse ShonanAveraging::computeA(const Matrix &S) const { + auto Lambda = computeLambda(S); + return Lambda - Q_; +} + +/* ************************************************************************* */ +// Perturb the initial initialVector by adding a spherically-uniformly +// distributed random vector with 0.03*||initialVector||_2 magnitude to +// initialVector +Vector perturb(const Vector &initialVector) { + // generate a 0.03*||x_0||_2 as stated in David's paper + int n = initialVector.rows(); + Vector disturb = Vector::Random(n); + disturb.normalize(); + + double magnitude = initialVector.norm(); + Vector perturbedVector = initialVector + 0.03 * magnitude * disturb; + perturbedVector.normalize(); + return perturbedVector; +} + /* ************************************************************************* */ /// MINIMUM EIGENVALUE COMPUTATIONS -// Alg.6 from paper Distributed Certifiably Correct Pose-Graph Optimization, -// it takes in the certificate matrix A as input, the maxIterations and the -// minEigenvalueNonnegativityTolerance is set to 1000 and 10e-4 ad default, +// Alg.6 from paper Distributed Certifiably Correct Pose-Graph Optimization, +// it takes in the certificate matrix A as input, the maxIterations and the +// minEigenvalueNonnegativityTolerance is set to 1000 and 10e-4 ad default, // there are two parts // in this algorithm: -// (1) +// (1) compute the maximum eigenpair (\lamda_dom, \vect{v}_dom) of A by power +// method. if \lamda_dom is less than zero, then return the eigenpair. (2) +// compute the maximum eigenpair (\theta, \vect{v}) of C = \lamda_dom * I - A by +// accelerated power method. Then return (\lamda_dom - \theta, \vect{v}). static bool PowerMinimumEigenValue( const Sparse &A, const Matrix &S, double *minEigenValue, Vector *minEigenVector = 0, size_t *numIterations = 0, @@ -486,39 +512,39 @@ static bool PowerMinimumEigenValue( double minEigenvalueNonnegativityTolerance = 10e-4) { // a. Compute dominant eigenpair of S using power method - const boost::optional initial(S.row(0)); - PowerMethod lmOperator(A, initial); + PowerMethod lmOperator(A); - const int lmConverged = lmOperator.compute( + const bool lmConverged = lmOperator.compute( maxIterations, 1e-5); // Check convergence and bail out if necessary - if (lmConverged != 1) return false; + if (!lmConverged) return false; - const double lmEigenValue = lmOperator.eigenvalues(); + const double lmEigenValue = lmOperator.eigenvalue(); if (lmEigenValue < 0) { // The largest-magnitude eigenvalue is negative, and therefore also the // minimum eigenvalue, so just return this solution *minEigenValue = lmEigenValue; if (minEigenVector) { - *minEigenVector = lmOperator.eigenvectors(); + *minEigenVector = lmOperator.eigenvector(); minEigenVector->normalize(); // Ensure that this is a unit vector } return true; } const Sparse C = lmEigenValue * Matrix::Identity(A.rows(), A.cols()) - A; + const boost::optional initial = perturb(S.row(0)); AcceleratedPowerMethod minShiftedOperator(C, initial); - const int minConverged = minShiftedOperator.compute( + const bool minConverged = minShiftedOperator.compute( maxIterations, minEigenvalueNonnegativityTolerance / lmEigenValue); - if (minConverged != 1) return false; + if (!minConverged) return false; - *minEigenValue = lmEigenValue - minShiftedOperator.eigenvalues(); + *minEigenValue = lmEigenValue - minShiftedOperator.eigenvalue(); if (minEigenVector) { - *minEigenVector = minShiftedOperator.eigenvectors(); + *minEigenVector = minShiftedOperator.eigenvector(); minEigenVector->normalize(); // Ensure that this is a unit vector } if (numIterations) *numIterations = minShiftedOperator.nrIterations(); @@ -669,13 +695,6 @@ static bool SparseMinimumEigenValue( return true; } -/* ************************************************************************* */ -template -Sparse ShonanAveraging::computeA(const Matrix &S) const { - auto Lambda = computeLambda(S); - return Lambda - Q_; -} - /* ************************************************************************* */ template double ShonanAveraging::computeMinEigenValue(const Values &values, From f86ad955827efd5397b4f392a596d1e975f2d2a4 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Thu, 22 Oct 2020 14:19:23 -0400 Subject: [PATCH 021/261] Correct unittest input error --- .../tests/testAcceleratedPowerMethod.cpp | 37 ++++++++----------- gtsam/linear/tests/testPowerMethod.cpp | 35 +++++++++--------- 2 files changed, 33 insertions(+), 39 deletions(-) diff --git a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp index a84a31a0f..474492475 100644 --- a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp +++ b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp @@ -42,26 +42,24 @@ TEST(AcceleratedPowerMethod, acceleratedPowerIteration) { // test power iteration, beta is set to 0 Sparse A(6, 6); A.coeffRef(0, 0) = 6; - A.coeffRef(0, 0) = 5; - A.coeffRef(0, 0) = 4; - A.coeffRef(0, 0) = 3; - A.coeffRef(0, 0) = 2; - A.coeffRef(0, 0) = 1; - Vector initial = Vector6::Zero(); + A.coeffRef(1, 1) = 5; + A.coeffRef(2, 2) = 4; + A.coeffRef(3, 3) = 3; + A.coeffRef(4, 4) = 2; + A.coeffRef(5, 5) = 1; + Vector initial = Vector6::Random(); const Vector6 x1 = (Vector(6) << 1.0, 0.0, 0.0, 0.0, 0.0, 0.0).finished(); - const double ev1 = 1.0; + const double ev1 = 6.0; // test accelerated power iteration AcceleratedPowerMethod apf(A, initial); - apf.compute(20, 1e-4); - EXPECT_LONGS_EQUAL(1, apf.eigenvectors().cols()); - EXPECT_LONGS_EQUAL(6, apf.eigenvectors().rows()); + apf.compute(50, 1e-4); + EXPECT_LONGS_EQUAL(6, apf.eigenvector().rows()); - Vector6 actual1 = apf.eigenvectors(); - // actual1(0) = abs (actual1(0)); - EXPECT(assert_equal(x1, actual1)); + Vector6 actual1 = apf.eigenvector(); + EXPECT(assert_equal(x1, actual1, 1e-4)); - EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalues(), 1e-5); + EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalue(), 1e-5); } /* ************************************************************************* */ @@ -76,10 +74,7 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { // Get eigenvalues and eigenvectors with Eigen auto L = fg.hessian(); - cout << L.first << endl; Eigen::EigenSolver solver(L.first); - cout << solver.eigenvalues() << endl; - cout << solver.eigenvectors() << endl; // Check that we get zero eigenvalue and "constant" eigenvector EXPECT_DOUBLES_EQUAL(0.0, solver.eigenvalues()[0].real(), 1e-9); @@ -95,11 +90,11 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { const auto ev1 = solver.eigenvalues()(maxIdx).real(); auto ev2 = solver.eigenvectors().col(maxIdx).real(); - Vector initial = Vector4::Zero(); + Vector initial = Vector4::Random(); AcceleratedPowerMethod apf(L.first, initial); - apf.compute(20, 1e-4); - EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalues(), 1e-8); - EXPECT(assert_equal(ev2, apf.eigenvectors(), 3e-5)); + apf.compute(50, 1e-4); + EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalue(), 1e-8); + EXPECT(assert_equal(-ev2, apf.eigenvector(), 3e-5)); } /* ************************************************************************* */ diff --git a/gtsam/linear/tests/testPowerMethod.cpp b/gtsam/linear/tests/testPowerMethod.cpp index 621286c85..58d1ca0cc 100644 --- a/gtsam/linear/tests/testPowerMethod.cpp +++ b/gtsam/linear/tests/testPowerMethod.cpp @@ -42,23 +42,22 @@ TEST(PowerMethod, powerIteration) { // test power iteration, beta is set to 0 Sparse A(6, 6); A.coeffRef(0, 0) = 6; - A.coeffRef(0, 0) = 5; - A.coeffRef(0, 0) = 4; - A.coeffRef(0, 0) = 3; - A.coeffRef(0, 0) = 2; - A.coeffRef(0, 0) = 1; - Vector initial = Vector6::Zero(); + A.coeffRef(1, 1) = 5; + A.coeffRef(2, 2) = 4; + A.coeffRef(3, 3) = 3; + A.coeffRef(4, 4) = 2; + A.coeffRef(5, 5) = 1; + Vector initial = Vector6::Random(); PowerMethod pf(A, initial); - pf.compute(20, 1e-4); - EXPECT_LONGS_EQUAL(1, pf.eigenvectors().cols()); - EXPECT_LONGS_EQUAL(6, pf.eigenvectors().rows()); + pf.compute(50, 1e-4); + EXPECT_LONGS_EQUAL(6, pf.eigenvector().rows()); const Vector6 x1 = (Vector(6) << 1.0, 0.0, 0.0, 0.0, 0.0, 0.0).finished(); - Vector6 actual0 = pf.eigenvectors(); - EXPECT(assert_equal(x1, actual0)); + Vector6 actual0 = pf.eigenvector(); + EXPECT(assert_equal(x1, actual0, 1e-4)); - const double ev1 = 1.0; - EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalues(), 1e-5); + const double ev1 = 6.0; + EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalue(), 1e-5); } /* ************************************************************************* */ @@ -89,12 +88,12 @@ TEST(PowerMethod, useFactorGraph) { const auto ev1 = solver.eigenvalues()(maxIdx).real(); auto ev2 = solver.eigenvectors().col(maxIdx).real(); - Vector initial = Vector4::Zero(); + Vector initial = Vector4::Random(); PowerMethod pf(L.first, initial); - pf.compute(20, 1e-4); - EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalues(), 1e-8); - // auto actual2 = pf.eigenvectors(); - // EXPECT(assert_equal(ev2, actual2, 3e-5)); + pf.compute(50, 1e-4); + EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalue(), 1e-8); + auto actual2 = pf.eigenvector(); + EXPECT(assert_equal(-ev2, actual2, 3e-5)); } /* ************************************************************************* */ From 32bf81efeacd6057f9aa06ee401bc8176e8a0d3f Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Thu, 22 Oct 2020 15:51:36 -0400 Subject: [PATCH 022/261] Added more detailed documentation --- gtsam/linear/AcceleratedPowerMethod.h | 3 +-- gtsam/linear/PowerMethod.h | 10 ++++---- .../tests/testAcceleratedPowerMethod.cpp | 24 ++++++++++--------- gtsam/linear/tests/testPowerMethod.cpp | 16 ++++++------- gtsam/sfm/ShonanAveraging.cpp | 3 +++ 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/gtsam/linear/AcceleratedPowerMethod.h b/gtsam/linear/AcceleratedPowerMethod.h index 0ad87626b..2e54775d9 100644 --- a/gtsam/linear/AcceleratedPowerMethod.h +++ b/gtsam/linear/AcceleratedPowerMethod.h @@ -80,8 +80,7 @@ class AcceleratedPowerMethod : public PowerMethod { } else { beta_ = initialBeta; } - - } + } // Update the ritzVector with beta and previous two ritzVector Vector powerIteration(const Vector &x1, const Vector &x0, diff --git a/gtsam/linear/PowerMethod.h b/gtsam/linear/PowerMethod.h index ee7a04429..acb583296 100644 --- a/gtsam/linear/PowerMethod.h +++ b/gtsam/linear/PowerMethod.h @@ -89,14 +89,16 @@ class PowerMethod { // Return the number of iterations size_t nrIterations() const { return nrIterations_; } - // Start the power/accelerated iteration, after updated the ritz vector, - // calculate the ritz error, repeat this operation until the ritz error converge - int compute(size_t maxIterations, double tol) { + // Start the power/accelerated iteration, after performing the + // power/accelerated power iteration, calculate the ritz error, repeat this + // operation until the ritz error converge. If converged return true, else + // false. + bool compute(size_t maxIterations, double tol) { // Starting bool isConverged = false; for (size_t i = 0; i < maxIterations; i++) { - ++nrIterations_ ; + ++nrIterations_; ritzVector_ = powerIteration(); isConverged = converged(tol); if (isConverged) return isConverged; diff --git a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp index 474492475..b72556e0a 100644 --- a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp +++ b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp @@ -18,18 +18,16 @@ * @brief Check eigenvalue and eigenvector computed by accelerated power method */ +#include #include #include #include -#include #include - -#include +#include #include #include #include - #include #include @@ -70,7 +68,7 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { for (size_t j = 0; j < 3; j++) { fg.add(X(j), -I_1x1, X(j + 1), I_1x1, Vector1::Zero(), model); } - fg.add(X(3), -I_1x1, X(0), I_1x1, Vector1::Zero(), model); // extra row + fg.add(X(3), -I_1x1, X(0), I_1x1, Vector1::Zero(), model); // extra row // Get eigenvalues and eigenvectors with Eigen auto L = fg.hessian(); @@ -79,22 +77,26 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { // Check that we get zero eigenvalue and "constant" eigenvector EXPECT_DOUBLES_EQUAL(0.0, solver.eigenvalues()[0].real(), 1e-9); auto v0 = solver.eigenvectors().col(0); - for (size_t j = 0; j < 3; j++) - EXPECT_DOUBLES_EQUAL(-0.5, v0[j].real(), 1e-9); + for (size_t j = 0; j < 3; j++) EXPECT_DOUBLES_EQUAL(-0.5, v0[j].real(), 1e-9); size_t maxIdx = 0; - for (auto i =0; i= solver.eigenvalues()(maxIdx).real()) maxIdx = i; + for (auto i = 0; i < solver.eigenvalues().rows(); ++i) { + if (solver.eigenvalues()(i).real() >= solver.eigenvalues()(maxIdx).real()) + maxIdx = i; } // Store the max eigenvalue and its according eigenvector const auto ev1 = solver.eigenvalues()(maxIdx).real(); auto ev2 = solver.eigenvectors().col(maxIdx).real(); - Vector initial = Vector4::Random(); + Vector disturb = Vector4::Random(); + disturb.normalize(); + Vector initial = L.first.row(0); + double magnitude = initial.norm(); + initial += 0.03 * magnitude * disturb; AcceleratedPowerMethod apf(L.first, initial); apf.compute(50, 1e-4); EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalue(), 1e-8); - EXPECT(assert_equal(-ev2, apf.eigenvector(), 3e-5)); + EXPECT(assert_equal(ev2, apf.eigenvector(), 3e-5)); } /* ************************************************************************* */ diff --git a/gtsam/linear/tests/testPowerMethod.cpp b/gtsam/linear/tests/testPowerMethod.cpp index 58d1ca0cc..7f6d1efa7 100644 --- a/gtsam/linear/tests/testPowerMethod.cpp +++ b/gtsam/linear/tests/testPowerMethod.cpp @@ -18,18 +18,16 @@ * @brief Check eigenvalue and eigenvector computed by power method */ +#include #include #include #include #include #include -#include - #include #include #include - #include #include @@ -68,7 +66,7 @@ TEST(PowerMethod, useFactorGraph) { for (size_t j = 0; j < 3; j++) { fg.add(X(j), -I_1x1, X(j + 1), I_1x1, Vector1::Zero(), model); } - fg.add(X(3), -I_1x1, X(0), I_1x1, Vector1::Zero(), model); // extra row + fg.add(X(3), -I_1x1, X(0), I_1x1, Vector1::Zero(), model); // extra row // Get eigenvalues and eigenvectors with Eigen auto L = fg.hessian(); @@ -77,12 +75,12 @@ TEST(PowerMethod, useFactorGraph) { // Check that we get zero eigenvalue and "constant" eigenvector EXPECT_DOUBLES_EQUAL(0.0, solver.eigenvalues()[0].real(), 1e-9); auto v0 = solver.eigenvectors().col(0); - for (size_t j = 0; j < 3; j++) - EXPECT_DOUBLES_EQUAL(-0.5, v0[j].real(), 1e-9); + for (size_t j = 0; j < 3; j++) EXPECT_DOUBLES_EQUAL(-0.5, v0[j].real(), 1e-9); size_t maxIdx = 0; - for (auto i =0; i= solver.eigenvalues()(maxIdx).real()) maxIdx = i; + for (auto i = 0; i < solver.eigenvalues().rows(); ++i) { + if (solver.eigenvalues()(i).real() >= solver.eigenvalues()(maxIdx).real()) + maxIdx = i; } // Store the max eigenvalue and its according eigenvector const auto ev1 = solver.eigenvalues()(maxIdx).real(); @@ -92,7 +90,7 @@ TEST(PowerMethod, useFactorGraph) { PowerMethod pf(L.first, initial); pf.compute(50, 1e-4); EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalue(), 1e-8); - auto actual2 = pf.eigenvector(); + auto actual2 = pf.eigenvector(); EXPECT(assert_equal(-ev2, actual2, 3e-5)); } diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 60233fc6e..50b38f75b 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -482,6 +482,9 @@ Sparse ShonanAveraging::computeA(const Matrix &S) const { // Perturb the initial initialVector by adding a spherically-uniformly // distributed random vector with 0.03*||initialVector||_2 magnitude to // initialVector +// ref : Part III. C, Rosen, D. and Carlone, L., 2017, September. Computational +// enhancements for certifiably correct SLAM. In Proceedings of the +// International Conference on Intelligent Robots and Systems. Vector perturb(const Vector &initialVector) { // generate a 0.03*||x_0||_2 as stated in David's paper int n = initialVector.rows(); From 56300ca23c292f2e1142600fd3de8c0b7dbedc8d Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Thu, 22 Oct 2020 18:05:09 -0400 Subject: [PATCH 023/261] Fixed not solve errors and detailed documentation --- gtsam/linear/AcceleratedPowerMethod.h | 33 +++++++++---------- gtsam/linear/PowerMethod.h | 6 ++-- .../tests/testAcceleratedPowerMethod.cpp | 2 +- gtsam/sfm/ShonanAveraging.cpp | 28 ++++++++-------- 4 files changed, 33 insertions(+), 36 deletions(-) diff --git a/gtsam/linear/AcceleratedPowerMethod.h b/gtsam/linear/AcceleratedPowerMethod.h index 2e54775d9..a5148e1d4 100644 --- a/gtsam/linear/AcceleratedPowerMethod.h +++ b/gtsam/linear/AcceleratedPowerMethod.h @@ -63,16 +63,10 @@ class AcceleratedPowerMethod : public PowerMethod { const Operator &A, const boost::optional initial = boost::none, const double initialBeta = 0.0) : PowerMethod(A, initial) { - Vector x0; - // initialize ritz vector - x0 = initial ? initial.get() : Vector::Random(this->dim_); - Vector x00 = Vector::Random(this->dim_); - x0.normalize(); - x00.normalize(); - // initialize Ritz eigen vector and previous vector - previousVector_ = powerIteration(x0, x00, beta_); - this->ritzVector_ = powerIteration(previousVector_, x0, beta_); + this->ritzVector_ = initial ? initial.get() : Vector::Random(this->dim_); + this->ritzVector_.normalize(); + previousVector_ = Vector::Zero(this->dim_); // initialize beta_ if (!initialBeta) { @@ -80,9 +74,10 @@ class AcceleratedPowerMethod : public PowerMethod { } else { beta_ = initialBeta; } - } + } - // Update the ritzVector with beta and previous two ritzVector + // Update the ritzVector with beta and previous two ritzVector, and return + // x_{k+1} = A * x_k - \beta * x_{k-1} / || A * x_k - \beta * x_{k-1} || Vector powerIteration(const Vector &x1, const Vector &x0, const double beta) const { Vector y = this->A_ * x1 - beta * x0; @@ -90,7 +85,8 @@ class AcceleratedPowerMethod : public PowerMethod { return y; } - // Update the ritzVector with beta and previous two ritzVector + // Update the ritzVector with beta and previous two ritzVector, and return + // x_{k+1} = A * x_k - \beta * x_{k-1} / || A * x_k - \beta * x_{k-1} || Vector powerIteration() const { Vector y = powerIteration(this->ritzVector_, previousVector_, beta_); previousVector_ = this->ritzVector_; @@ -101,8 +97,8 @@ class AcceleratedPowerMethod : public PowerMethod { void estimateBeta() { // set beta Vector init_resid = this->ritzVector_; - const double up = init_resid.transpose() * this->A_ * init_resid; - const double down = init_resid.transpose().dot(init_resid); + const double up = init_resid.dot( this->A_ * init_resid ); + const double down = init_resid.dot(init_resid); const double mu = up / down; double maxBeta = mu * mu / 4; size_t maxIndex; @@ -111,11 +107,12 @@ class AcceleratedPowerMethod : public PowerMethod { Matrix R = Matrix::Zero(this->dim_, 10); for (size_t i = 0; i < 10; i++) { + Vector x0 = Vector::Random(this->dim_); + x0.normalize(); + Vector x00 = Vector::Zero(this->dim_); for (size_t k = 0; k < betas.size(); ++k) { for (size_t j = 1; j < 10; j++) { if (j < 2) { - Vector x0 = this->ritzVector_; - Vector x00 = previousVector_; R.col(0) = powerIteration(x0, x00, betas[k]); R.col(1) = powerIteration(R.col(0), x0, betas[k]); } else { @@ -123,8 +120,8 @@ class AcceleratedPowerMethod : public PowerMethod { } } const Vector x = R.col(9); - const double up = x.transpose() * this->A_ * x; - const double down = x.transpose().dot(x); + const double up = x.dot(this->A_ * x); + const double down = x.dot(x); const double mu = up / down; if (mu * mu / 4 > maxBeta) { maxIndex = k; diff --git a/gtsam/linear/PowerMethod.h b/gtsam/linear/PowerMethod.h index acb583296..8a577aa92 100644 --- a/gtsam/linear/PowerMethod.h +++ b/gtsam/linear/PowerMethod.h @@ -61,19 +61,19 @@ class PowerMethod { // initialize Ritz eigen value ritzValue_ = 0.0; - // initialize Ritz eigen vectors + // initialize Ritz eigen vector ritzVector_ = Vector::Zero(dim_); ritzVector_ = powerIteration(x0); } - // Update the vector by dot product with A_ + // Update the vector by dot product with A_, and return A * x / || A * x || Vector powerIteration(const Vector &x) const { Vector y = A_ * x; y.normalize(); return y; } - // Update the vector by dot product with A_ + // Update the vector by dot product with A_, and return A * x / || A * x || Vector powerIteration() const { return powerIteration(ritzVector_); } // After Perform power iteration on a single Ritz value, if the error is less diff --git a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp index b72556e0a..6179d6ca6 100644 --- a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp +++ b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp @@ -96,7 +96,7 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { AcceleratedPowerMethod apf(L.first, initial); apf.compute(50, 1e-4); EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalue(), 1e-8); - EXPECT(assert_equal(ev2, apf.eigenvector(), 3e-5)); + EXPECT(assert_equal(ev2, apf.eigenvector(), 4e-5)); } /* ************************************************************************* */ diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 50b38f75b..8d2bf4653 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -515,42 +515,42 @@ static bool PowerMinimumEigenValue( double minEigenvalueNonnegativityTolerance = 10e-4) { // a. Compute dominant eigenpair of S using power method - PowerMethod lmOperator(A); + PowerMethod pmOperator(A); - const bool lmConverged = lmOperator.compute( + const bool pmConverged = pmOperator.compute( maxIterations, 1e-5); // Check convergence and bail out if necessary - if (!lmConverged) return false; + if (!pmConverged) return false; - const double lmEigenValue = lmOperator.eigenvalue(); + const double pmEigenValue = pmOperator.eigenvalue(); - if (lmEigenValue < 0) { + if (pmEigenValue < 0) { // The largest-magnitude eigenvalue is negative, and therefore also the // minimum eigenvalue, so just return this solution - *minEigenValue = lmEigenValue; + *minEigenValue = pmEigenValue; if (minEigenVector) { - *minEigenVector = lmOperator.eigenvector(); + *minEigenVector = pmOperator.eigenvector(); minEigenVector->normalize(); // Ensure that this is a unit vector } return true; } - const Sparse C = lmEigenValue * Matrix::Identity(A.rows(), A.cols()) - A; + const Sparse C = pmEigenValue * Matrix::Identity(A.rows(), A.cols()) - A; const boost::optional initial = perturb(S.row(0)); - AcceleratedPowerMethod minShiftedOperator(C, initial); + AcceleratedPowerMethod apmShiftedOperator(C, initial); - const bool minConverged = minShiftedOperator.compute( - maxIterations, minEigenvalueNonnegativityTolerance / lmEigenValue); + const bool minConverged = apmShiftedOperator.compute( + maxIterations, minEigenvalueNonnegativityTolerance / pmEigenValue); if (!minConverged) return false; - *minEigenValue = lmEigenValue - minShiftedOperator.eigenvalue(); + *minEigenValue = pmEigenValue - apmShiftedOperator.eigenvalue(); if (minEigenVector) { - *minEigenVector = minShiftedOperator.eigenvector(); + *minEigenVector = apmShiftedOperator.eigenvector(); minEigenVector->normalize(); // Ensure that this is a unit vector } - if (numIterations) *numIterations = minShiftedOperator.nrIterations(); + if (numIterations) *numIterations = apmShiftedOperator.nrIterations(); return true; } From cf813c5a64b213ffd46a7ae7a6add1a2f342b80c Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Mon, 26 Oct 2020 15:40:49 -0400 Subject: [PATCH 024/261] Revised as David's second review --- gtsam/linear/AcceleratedPowerMethod.h | 78 +++++++++++++++++++-------- gtsam/linear/PowerMethod.h | 23 ++++---- gtsam/sfm/ShonanAveraging.cpp | 10 ++-- 3 files changed, 75 insertions(+), 36 deletions(-) diff --git a/gtsam/linear/AcceleratedPowerMethod.h b/gtsam/linear/AcceleratedPowerMethod.h index a5148e1d4..eea007353 100644 --- a/gtsam/linear/AcceleratedPowerMethod.h +++ b/gtsam/linear/AcceleratedPowerMethod.h @@ -61,7 +61,7 @@ class AcceleratedPowerMethod : public PowerMethod { // vector as ritzVector explicit AcceleratedPowerMethod( const Operator &A, const boost::optional initial = boost::none, - const double initialBeta = 0.0) + double initialBeta = 0.0) : PowerMethod(A, initial) { // initialize Ritz eigen vector and previous vector this->ritzVector_ = initial ? initial.get() : Vector::Random(this->dim_); @@ -76,61 +76,97 @@ class AcceleratedPowerMethod : public PowerMethod { } } - // Update the ritzVector with beta and previous two ritzVector, and return - // x_{k+1} = A * x_k - \beta * x_{k-1} / || A * x_k - \beta * x_{k-1} || - Vector powerIteration(const Vector &x1, const Vector &x0, + // Run accelerated power iteration on the ritzVector with beta and previous + // two ritzVector, and return x_{k+1} = A * x_k - \beta * x_{k-1} / || A * x_k + // - \beta * x_{k-1} || + Vector acceleratedPowerIteration (const Vector &x1, const Vector &x0, const double beta) const { Vector y = this->A_ * x1 - beta * x0; y.normalize(); return y; } - // Update the ritzVector with beta and previous two ritzVector, and return - // x_{k+1} = A * x_k - \beta * x_{k-1} / || A * x_k - \beta * x_{k-1} || - Vector powerIteration() const { - Vector y = powerIteration(this->ritzVector_, previousVector_, beta_); - previousVector_ = this->ritzVector_; + // Run accelerated power iteration on the ritzVector with beta and previous + // two ritzVector, and return x_{k+1} = A * x_k - \beta * x_{k-1} / || A * x_k + // - \beta * x_{k-1} || + Vector acceleratedPowerIteration () const { + Vector y = acceleratedPowerIteration(this->ritzVector_, previousVector_, beta_); return y; } // Tuning the momentum beta using the Best Heavy Ball algorithm in Ref(3) void estimateBeta() { // set beta - Vector init_resid = this->ritzVector_; - const double up = init_resid.dot( this->A_ * init_resid ); - const double down = init_resid.dot(init_resid); + Vector initVector = this->ritzVector_; + const double up = initVector.dot( this->A_ * initVector ); + const double down = initVector.dot(initVector); const double mu = up / down; double maxBeta = mu * mu / 4; size_t maxIndex; - std::vector betas = {2 / 3 * maxBeta, 0.99 * maxBeta, maxBeta, - 1.01 * maxBeta, 1.5 * maxBeta}; + std::vector betas; Matrix R = Matrix::Zero(this->dim_, 10); - for (size_t i = 0; i < 10; i++) { - Vector x0 = Vector::Random(this->dim_); - x0.normalize(); - Vector x00 = Vector::Zero(this->dim_); + size_t T = 10; + // run T times of iteration to find the beta that has the largest Rayleigh quotient + for (size_t t = 0; t < T; t++) { + // after each t iteration, reset the betas with the current maxBeta + betas = {2 / 3 * maxBeta, 0.99 * maxBeta, maxBeta, 1.01 * maxBeta, + 1.5 * maxBeta}; + // iterate through every beta value for (size_t k = 0; k < betas.size(); ++k) { + // initialize x0 and x00 in each iteration of each beta + Vector x0 = initVector; + Vector x00 = Vector::Zero(this->dim_); + // run 10 steps of accelerated power iteration with this beta for (size_t j = 1; j < 10; j++) { if (j < 2) { - R.col(0) = powerIteration(x0, x00, betas[k]); - R.col(1) = powerIteration(R.col(0), x0, betas[k]); + R.col(0) = acceleratedPowerIteration(x0, x00, betas[k]); + R.col(1) = acceleratedPowerIteration(R.col(0), x0, betas[k]); } else { - R.col(j) = powerIteration(R.col(j - 1), R.col(j - 2), betas[k]); + R.col(j) = acceleratedPowerIteration(R.col(j - 1), R.col(j - 2), betas[k]); } } + // compute the Rayleigh quotient for the randomly sampled vector after + // 10 steps of power accelerated iteration const Vector x = R.col(9); const double up = x.dot(this->A_ * x); const double down = x.dot(x); const double mu = up / down; + // store the momentum with largest Rayleigh quotient and its according index of beta_ if (mu * mu / 4 > maxBeta) { + // save the max beta index maxIndex = k; maxBeta = mu * mu / 4; } } } + // set beta_ to momentum with largest Rayleigh quotient beta_ = betas[maxIndex]; } + + // Start the accelerated iteration, after performing the + // accelerated iteration, calculate the ritz error, repeat this + // operation until the ritz error converge. If converged return true, else + // false. + bool compute(size_t maxIterations, double tol) { + // Starting + bool isConverged = false; + + for (size_t i = 0; i < maxIterations; i++) { + ++(this->nrIterations_); + Vector tmp = this->ritzVector_; + // update the ritzVector after accelerated power iteration + this->ritzVector_ = acceleratedPowerIteration(); + // update the previousVector with ritzVector + previousVector_ = tmp; + // update the ritzValue + this->ritzValue_ = this->ritzVector_.dot(this->A_ * this->ritzVector_); + isConverged = this->converged(tol); + if (isConverged) return isConverged; + } + + return isConverged; + } }; } // namespace gtsam diff --git a/gtsam/linear/PowerMethod.h b/gtsam/linear/PowerMethod.h index 8a577aa92..ae1d97cc7 100644 --- a/gtsam/linear/PowerMethod.h +++ b/gtsam/linear/PowerMethod.h @@ -66,23 +66,24 @@ class PowerMethod { ritzVector_ = powerIteration(x0); } - // Update the vector by dot product with A_, and return A * x / || A * x || + // Run power iteration on the vector, and return A * x / || A * x || Vector powerIteration(const Vector &x) const { Vector y = A_ * x; y.normalize(); return y; } - // Update the vector by dot product with A_, and return A * x / || A * x || + // Run power iteration on the vector, and return A * x / || A * x || Vector powerIteration() const { return powerIteration(ritzVector_); } - // After Perform power iteration on a single Ritz value, if the error is less - // than the tol then return true else false - bool converged(double tol) { + // After Perform power iteration on a single Ritz value, check if the Ritz + // residual for the current Ritz pair is less than the required convergence + // tol, return true if yes, else false + bool converged(double tol) const { const Vector x = ritzVector_; // store the Ritz eigen value - ritzValue_ = x.dot(A_ * x); - double error = (A_ * x - ritzValue_ * x).norm(); + const double ritzValue = x.dot(A_ * x); + const double error = (A_ * x - ritzValue * x).norm(); return error < tol; } @@ -90,18 +91,20 @@ class PowerMethod { size_t nrIterations() const { return nrIterations_; } // Start the power/accelerated iteration, after performing the - // power/accelerated power iteration, calculate the ritz error, repeat this + // power/accelerated iteration, calculate the ritz error, repeat this // operation until the ritz error converge. If converged return true, else // false. bool compute(size_t maxIterations, double tol) { // Starting bool isConverged = false; - for (size_t i = 0; i < maxIterations; i++) { + for (size_t i = 0; i < maxIterations && !isConverged; i++) { ++nrIterations_; + // update the ritzVector after power iteration ritzVector_ = powerIteration(); + // update the ritzValue + ritzValue_ = ritzVector_.dot(A_ * ritzVector_); isConverged = converged(tol); - if (isConverged) return isConverged; } return isConverged; diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 8d2bf4653..fab57c828 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -509,7 +509,7 @@ Vector perturb(const Vector &initialVector) { // compute the maximum eigenpair (\theta, \vect{v}) of C = \lamda_dom * I - A by // accelerated power method. Then return (\lamda_dom - \theta, \vect{v}). static bool PowerMinimumEigenValue( - const Sparse &A, const Matrix &S, double *minEigenValue, + const Sparse &A, const Matrix &S, double &minEigenValue, Vector *minEigenVector = 0, size_t *numIterations = 0, size_t maxIterations = 1000, double minEigenvalueNonnegativityTolerance = 10e-4) { @@ -528,7 +528,7 @@ static bool PowerMinimumEigenValue( if (pmEigenValue < 0) { // The largest-magnitude eigenvalue is negative, and therefore also the // minimum eigenvalue, so just return this solution - *minEigenValue = pmEigenValue; + minEigenValue = pmEigenValue; if (minEigenVector) { *minEigenVector = pmOperator.eigenvector(); minEigenVector->normalize(); // Ensure that this is a unit vector @@ -545,7 +545,7 @@ static bool PowerMinimumEigenValue( if (!minConverged) return false; - *minEigenValue = pmEigenValue - apmShiftedOperator.eigenvalue(); + minEigenValue = pmEigenValue - apmShiftedOperator.eigenvalue(); if (minEigenVector) { *minEigenVector = apmShiftedOperator.eigenvector(); minEigenVector->normalize(); // Ensure that this is a unit vector @@ -723,8 +723,8 @@ double ShonanAveraging::computeMinEigenValueAP(const Values &values, const Matrix S = StiefelElementMatrix(values); auto A = computeA(S); - double minEigenValue; - bool success = PowerMinimumEigenValue(A, S, &minEigenValue, minEigenVector); + double minEigenValue = 0; + bool success = PowerMinimumEigenValue(A, S, minEigenValue, minEigenVector); if (!success) { throw std::runtime_error( "PowerMinimumEigenValue failed to compute minimum eigenvalue."); From 4ee4014d7a345fc410461c1d2855ef296b8820ba Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Mon, 26 Oct 2020 15:41:01 -0400 Subject: [PATCH 025/261] Refined unittest --- .../tests/testAcceleratedPowerMethod.cpp | 23 +++++++++++++------ gtsam/linear/tests/testPowerMethod.cpp | 15 +++++++----- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp index 6179d6ca6..228ce157c 100644 --- a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp +++ b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp @@ -45,17 +45,19 @@ TEST(AcceleratedPowerMethod, acceleratedPowerIteration) { A.coeffRef(3, 3) = 3; A.coeffRef(4, 4) = 2; A.coeffRef(5, 5) = 1; - Vector initial = Vector6::Random(); - const Vector6 x1 = (Vector(6) << 1.0, 0.0, 0.0, 0.0, 0.0, 0.0).finished(); + Vector initial = (Vector(6) << 0.24434602, 0.22829942, 0.70094486, 0.15463092, 0.55871359, + 0.2465342).finished(); const double ev1 = 6.0; // test accelerated power iteration AcceleratedPowerMethod apf(A, initial); - apf.compute(50, 1e-4); + apf.compute(100, 1e-5); EXPECT_LONGS_EQUAL(6, apf.eigenvector().rows()); Vector6 actual1 = apf.eigenvector(); - EXPECT(assert_equal(x1, actual1, 1e-4)); + const double ritzValue = actual1.dot(A * actual1); + const double ritzResidual = (A * actual1 - ritzValue * actual1).norm(); + EXPECT_DOUBLES_EQUAL(0, ritzResidual, 1e-5); EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalue(), 1e-5); } @@ -79,6 +81,7 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { auto v0 = solver.eigenvectors().col(0); for (size_t j = 0; j < 3; j++) EXPECT_DOUBLES_EQUAL(-0.5, v0[j].real(), 1e-9); + // find the index of the max eigenvalue size_t maxIdx = 0; for (auto i = 0; i < solver.eigenvalues().rows(); ++i) { if (solver.eigenvalues()(i).real() >= solver.eigenvalues()(maxIdx).real()) @@ -86,7 +89,6 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { } // Store the max eigenvalue and its according eigenvector const auto ev1 = solver.eigenvalues()(maxIdx).real(); - auto ev2 = solver.eigenvectors().col(maxIdx).real(); Vector disturb = Vector4::Random(); disturb.normalize(); @@ -94,9 +96,16 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { double magnitude = initial.norm(); initial += 0.03 * magnitude * disturb; AcceleratedPowerMethod apf(L.first, initial); - apf.compute(50, 1e-4); + apf.compute(100, 1e-5); + // Check if the eigenvalue is the maximum eigen value EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalue(), 1e-8); - EXPECT(assert_equal(ev2, apf.eigenvector(), 4e-5)); + + // Check if the according ritz residual converged to the threshold + Vector actual1 = apf.eigenvector(); + const double ritzValue = actual1.dot(L.first * actual1); + const double ritzResidual = (L.first * actual1 - ritzValue * actual1).norm(); + EXPECT_DOUBLES_EQUAL(0, ritzResidual, 1e-5); + // Check } /* ************************************************************************* */ diff --git a/gtsam/linear/tests/testPowerMethod.cpp b/gtsam/linear/tests/testPowerMethod.cpp index 7f6d1efa7..4c96c5bca 100644 --- a/gtsam/linear/tests/testPowerMethod.cpp +++ b/gtsam/linear/tests/testPowerMethod.cpp @@ -45,14 +45,16 @@ TEST(PowerMethod, powerIteration) { A.coeffRef(3, 3) = 3; A.coeffRef(4, 4) = 2; A.coeffRef(5, 5) = 1; - Vector initial = Vector6::Random(); + Vector initial = (Vector(6) << 0.24434602, 0.22829942, 0.70094486, 0.15463092, 0.55871359, + 0.2465342).finished(); PowerMethod pf(A, initial); - pf.compute(50, 1e-4); + pf.compute(100, 1e-5); EXPECT_LONGS_EQUAL(6, pf.eigenvector().rows()); - const Vector6 x1 = (Vector(6) << 1.0, 0.0, 0.0, 0.0, 0.0, 0.0).finished(); - Vector6 actual0 = pf.eigenvector(); - EXPECT(assert_equal(x1, actual0, 1e-4)); + Vector6 actual1 = pf.eigenvector(); + const double ritzValue = actual1.dot(A * actual1); + const double ritzResidual = (A * actual1 - ritzValue * actual1).norm(); + EXPECT_DOUBLES_EQUAL(0, ritzResidual, 1e-5); const double ev1 = 6.0; EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalue(), 1e-5); @@ -77,6 +79,7 @@ TEST(PowerMethod, useFactorGraph) { auto v0 = solver.eigenvectors().col(0); for (size_t j = 0; j < 3; j++) EXPECT_DOUBLES_EQUAL(-0.5, v0[j].real(), 1e-9); + // find the index of the max eigenvalue size_t maxIdx = 0; for (auto i = 0; i < solver.eigenvalues().rows(); ++i) { if (solver.eigenvalues()(i).real() >= solver.eigenvalues()(maxIdx).real()) @@ -91,7 +94,7 @@ TEST(PowerMethod, useFactorGraph) { pf.compute(50, 1e-4); EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalue(), 1e-8); auto actual2 = pf.eigenvector(); - EXPECT(assert_equal(-ev2, actual2, 3e-5)); + EXPECT(assert_equal(ev2, actual2, 3e-5)); } /* ************************************************************************* */ From f604a9784de84a3c9699be737f295e77976b9a5b Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Sun, 1 Nov 2020 20:45:59 -0500 Subject: [PATCH 026/261] Delete forcing compare eigenvector in unittest --- gtsam/linear/tests/testAcceleratedPowerMethod.cpp | 6 ------ gtsam/linear/tests/testPowerMethod.cpp | 5 ----- 2 files changed, 11 deletions(-) diff --git a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp index 228ce157c..dd593e7d3 100644 --- a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp +++ b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp @@ -76,11 +76,6 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { auto L = fg.hessian(); Eigen::EigenSolver solver(L.first); - // Check that we get zero eigenvalue and "constant" eigenvector - EXPECT_DOUBLES_EQUAL(0.0, solver.eigenvalues()[0].real(), 1e-9); - auto v0 = solver.eigenvectors().col(0); - for (size_t j = 0; j < 3; j++) EXPECT_DOUBLES_EQUAL(-0.5, v0[j].real(), 1e-9); - // find the index of the max eigenvalue size_t maxIdx = 0; for (auto i = 0; i < solver.eigenvalues().rows(); ++i) { @@ -105,7 +100,6 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { const double ritzValue = actual1.dot(L.first * actual1); const double ritzResidual = (L.first * actual1 - ritzValue * actual1).norm(); EXPECT_DOUBLES_EQUAL(0, ritzResidual, 1e-5); - // Check } /* ************************************************************************* */ diff --git a/gtsam/linear/tests/testPowerMethod.cpp b/gtsam/linear/tests/testPowerMethod.cpp index 4c96c5bca..ccac4556c 100644 --- a/gtsam/linear/tests/testPowerMethod.cpp +++ b/gtsam/linear/tests/testPowerMethod.cpp @@ -74,11 +74,6 @@ TEST(PowerMethod, useFactorGraph) { auto L = fg.hessian(); Eigen::EigenSolver solver(L.first); - // Check that we get zero eigenvalue and "constant" eigenvector - EXPECT_DOUBLES_EQUAL(0.0, solver.eigenvalues()[0].real(), 1e-9); - auto v0 = solver.eigenvectors().col(0); - for (size_t j = 0; j < 3; j++) EXPECT_DOUBLES_EQUAL(-0.5, v0[j].real(), 1e-9); - // find the index of the max eigenvalue size_t maxIdx = 0; for (auto i = 0; i < solver.eigenvalues().rows(); ++i) { From 70cecb3a61d14f1b1f960f888b1a93f42a43eed6 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Sun, 1 Nov 2020 20:46:42 -0500 Subject: [PATCH 027/261] Revised documentation --- gtsam/linear/AcceleratedPowerMethod.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/gtsam/linear/AcceleratedPowerMethod.h b/gtsam/linear/AcceleratedPowerMethod.h index eea007353..0c544f05c 100644 --- a/gtsam/linear/AcceleratedPowerMethod.h +++ b/gtsam/linear/AcceleratedPowerMethod.h @@ -77,8 +77,8 @@ class AcceleratedPowerMethod : public PowerMethod { } // Run accelerated power iteration on the ritzVector with beta and previous - // two ritzVector, and return x_{k+1} = A * x_k - \beta * x_{k-1} / || A * x_k - // - \beta * x_{k-1} || + // two ritzVector, and return y = (A * x0 - \beta * x00) / || A * x0 + // - \beta * x00 || Vector acceleratedPowerIteration (const Vector &x1, const Vector &x0, const double beta) const { Vector y = this->A_ * x1 - beta * x0; @@ -87,8 +87,8 @@ class AcceleratedPowerMethod : public PowerMethod { } // Run accelerated power iteration on the ritzVector with beta and previous - // two ritzVector, and return x_{k+1} = A * x_k - \beta * x_{k-1} / || A * x_k - // - \beta * x_{k-1} || + // two ritzVector, and return y = (A * x0 - \beta * x00) / || A * x0 + // - \beta * x00 || Vector acceleratedPowerIteration () const { Vector y = acceleratedPowerIteration(this->ritzVector_, previousVector_, beta_); return y; @@ -96,7 +96,7 @@ class AcceleratedPowerMethod : public PowerMethod { // Tuning the momentum beta using the Best Heavy Ball algorithm in Ref(3) void estimateBeta() { - // set beta + // set initial estimation of maxBeta Vector initVector = this->ritzVector_; const double up = initVector.dot( this->A_ * initVector ); const double down = initVector.dot(initVector); @@ -152,7 +152,7 @@ class AcceleratedPowerMethod : public PowerMethod { // Starting bool isConverged = false; - for (size_t i = 0; i < maxIterations; i++) { + for (size_t i = 0; i < maxIterations && !isConverged; i++) { ++(this->nrIterations_); Vector tmp = this->ritzVector_; // update the ritzVector after accelerated power iteration @@ -162,7 +162,6 @@ class AcceleratedPowerMethod : public PowerMethod { // update the ritzValue this->ritzValue_ = this->ritzVector_.dot(this->A_ * this->ritzVector_); isConverged = this->converged(tol); - if (isConverged) return isConverged; } return isConverged; From abfc98e13d738c4ac4e97147e52a2cacecd7347c Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Mon, 2 Nov 2020 15:39:39 -0500 Subject: [PATCH 028/261] Fixed forcing comparing eigenvector. --- gtsam/linear/tests/testPowerMethod.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gtsam/linear/tests/testPowerMethod.cpp b/gtsam/linear/tests/testPowerMethod.cpp index ccac4556c..2e0f2152b 100644 --- a/gtsam/linear/tests/testPowerMethod.cpp +++ b/gtsam/linear/tests/testPowerMethod.cpp @@ -82,14 +82,15 @@ TEST(PowerMethod, useFactorGraph) { } // Store the max eigenvalue and its according eigenvector const auto ev1 = solver.eigenvalues()(maxIdx).real(); - auto ev2 = solver.eigenvectors().col(maxIdx).real(); Vector initial = Vector4::Random(); PowerMethod pf(L.first, initial); - pf.compute(50, 1e-4); + pf.compute(100, 1e-5); EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalue(), 1e-8); auto actual2 = pf.eigenvector(); - EXPECT(assert_equal(ev2, actual2, 3e-5)); + const double ritzValue = actual2.dot(L.first * actual2); + const double ritzResidual = (L.first * actual2 - ritzValue * actual2).norm(); + EXPECT_DOUBLES_EQUAL(0, ritzResidual, 1e-5); } /* ************************************************************************* */ From 51b6fd0b43852bf14148b39c14d2563f2d87c3d4 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 3 Nov 2020 12:11:17 -0500 Subject: [PATCH 029/261] Added flag for absolute error --- gtsam/base/Matrix.h | 2 +- gtsam/base/Vector.cpp | 6 ++++-- gtsam/base/Vector.h | 3 ++- gtsam/geometry/tests/testRot3.cpp | 6 +++--- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/gtsam/base/Matrix.h b/gtsam/base/Matrix.h index 071c33fca..9adf4e1c1 100644 --- a/gtsam/base/Matrix.h +++ b/gtsam/base/Matrix.h @@ -90,7 +90,7 @@ bool equal_with_abs_tol(const Eigen::DenseBase& A, const Eigen::DenseBas for(size_t i=0; i::max())) { + else if (abs(a - b) <= + tol * min(larger, std::numeric_limits::max()) && + !absolute) { return true; } diff --git a/gtsam/base/Vector.h b/gtsam/base/Vector.h index 319ad6ee6..b0fc74f26 100644 --- a/gtsam/base/Vector.h +++ b/gtsam/base/Vector.h @@ -87,7 +87,8 @@ static_assert( * * Return true if two numbers are close wrt tol. */ -GTSAM_EXPORT bool fpEqual(double a, double b, double tol); +GTSAM_EXPORT bool fpEqual(double a, double b, double tol, + bool absolute = false); /** * print without optional string, must specify cout yourself diff --git a/gtsam/geometry/tests/testRot3.cpp b/gtsam/geometry/tests/testRot3.cpp index 7b792f8bd..889f68580 100644 --- a/gtsam/geometry/tests/testRot3.cpp +++ b/gtsam/geometry/tests/testRot3.cpp @@ -807,15 +807,15 @@ TEST(Rot3, RQ_derivative) { test_xyz.push_back(VecAndErr{{0, 0, 0}, error}); test_xyz.push_back(VecAndErr{{0, 0.5, -0.5}, error}); test_xyz.push_back(VecAndErr{{0.3, 0, 0.2}, error}); - test_xyz.push_back(VecAndErr{{-0.6, 1.3, 0}, error}); + test_xyz.push_back(VecAndErr{{-0.6, 1.3, 0}, 1e-8}); test_xyz.push_back(VecAndErr{{1.0, 0.7, 0.8}, error}); test_xyz.push_back(VecAndErr{{3.0, 0.7, -0.6}, error}); test_xyz.push_back(VecAndErr{{M_PI / 2, 0, 0}, error}); test_xyz.push_back(VecAndErr{{0, 0, M_PI / 2}, error}); // Test close to singularity - test_xyz.push_back(VecAndErr{{0, M_PI / 2 - 1e-1, 0}, 1e-8}); - test_xyz.push_back(VecAndErr{{0, 3 * M_PI / 2 + 1e-1, 0}, 1e-8}); + test_xyz.push_back(VecAndErr{{0, M_PI / 2 - 1e-1, 0}, 1e-7}); + test_xyz.push_back(VecAndErr{{0, 3 * M_PI / 2 + 1e-1, 0}, 1e-7}); test_xyz.push_back(VecAndErr{{0, M_PI / 2 - 1.1e-2, 0}, 1e-4}); test_xyz.push_back(VecAndErr{{0, 3 * M_PI / 2 + 1.1e-2, 0}, 1e-4}); From c68a64745e1ad99cb047286434cfda1e1b7aedc7 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 3 Nov 2020 14:27:05 -0500 Subject: [PATCH 030/261] add test --- gtsam/base/tests/testMatrix.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/gtsam/base/tests/testMatrix.cpp b/gtsam/base/tests/testMatrix.cpp index 468e842f2..15087093a 100644 --- a/gtsam/base/tests/testMatrix.cpp +++ b/gtsam/base/tests/testMatrix.cpp @@ -1163,6 +1163,19 @@ TEST(Matrix , IsVectorSpace) { BOOST_CONCEPT_ASSERT((IsVectorSpace)); } +TEST(Matrix, AbsoluteError) { + double a = 2000, b = 1997, tol=1e-1; + bool isEqual; + + // Test absolute error + isEqual = fpEqual(a, b, tol, true); + EXPECT(isEqual == false); + + // Test relative error + isEqual = fpEqual(a, b, tol, false); + EXPECT(isEqual == true); +} + /* ************************************************************************* */ int main() { TestResult tr; From 326957b0d35ece7ae44cf5d06be42798c9f577dd Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 3 Nov 2020 19:31:39 -0500 Subject: [PATCH 031/261] cleaner assertion --- gtsam/base/tests/testMatrix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtsam/base/tests/testMatrix.cpp b/gtsam/base/tests/testMatrix.cpp index 15087093a..d22ffc0db 100644 --- a/gtsam/base/tests/testMatrix.cpp +++ b/gtsam/base/tests/testMatrix.cpp @@ -1169,11 +1169,11 @@ TEST(Matrix, AbsoluteError) { // Test absolute error isEqual = fpEqual(a, b, tol, true); - EXPECT(isEqual == false); + EXPECT(!isEqual); // Test relative error isEqual = fpEqual(a, b, tol, false); - EXPECT(isEqual == true); + EXPECT(isEqual); } /* ************************************************************************* */ From c5576c534f3a29f0077c58858321829da859dd6c Mon Sep 17 00:00:00 2001 From: Jose Luis Blanco-Claraco Date: Sun, 8 Nov 2020 11:57:47 +0100 Subject: [PATCH 032/261] Add iteration hook in non-linear optimizers --- .../NonlinearConjugateGradientOptimizer.h | 4 ++ gtsam/nonlinear/NonlinearOptimizer.cpp | 6 ++- gtsam/nonlinear/NonlinearOptimizer.h | 2 +- gtsam/nonlinear/NonlinearOptimizerParams.h | 30 ++++++----- tests/testNonlinearOptimizer.cpp | 52 +++++++++++++++++++ 5 files changed, 80 insertions(+), 14 deletions(-) diff --git a/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.h b/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.h index abf6b257a..a85f27425 100644 --- a/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.h +++ b/gtsam/nonlinear/NonlinearConjugateGradientOptimizer.h @@ -200,6 +200,10 @@ boost::tuple nonlinearConjugateGradient(const S &system, currentValues = system.advance(prevValues, alpha, direction); currentError = system.error(currentValues); + // User hook: + if (params.iterationHook) + params.iterationHook(iteration, prevError, currentError); + // Maybe show output if (params.verbosity >= NonlinearOptimizerParams::ERROR) std::cout << "iteration: " << iteration << ", currentError: " << currentError << std::endl; diff --git a/gtsam/nonlinear/NonlinearOptimizer.cpp b/gtsam/nonlinear/NonlinearOptimizer.cpp index fd9961742..0d7e9e17f 100644 --- a/gtsam/nonlinear/NonlinearOptimizer.cpp +++ b/gtsam/nonlinear/NonlinearOptimizer.cpp @@ -97,7 +97,11 @@ void NonlinearOptimizer::defaultOptimize() { // Update newError for either printouts or conditional-end checks: newError = error(); - + + // User hook: + if (params.iterationHook) + params.iterationHook(iterations(), currentError, newError); + // Maybe show output if (params.verbosity >= NonlinearOptimizerParams::VALUES) values().print("newValues"); diff --git a/gtsam/nonlinear/NonlinearOptimizer.h b/gtsam/nonlinear/NonlinearOptimizer.h index 9935f44ce..6fe369dd3 100644 --- a/gtsam/nonlinear/NonlinearOptimizer.h +++ b/gtsam/nonlinear/NonlinearOptimizer.h @@ -81,7 +81,7 @@ protected: public: /** A shared pointer to this class */ - typedef boost::shared_ptr shared_ptr; + using shared_ptr = boost::shared_ptr; /// @name Standard interface /// @{ diff --git a/gtsam/nonlinear/NonlinearOptimizerParams.h b/gtsam/nonlinear/NonlinearOptimizerParams.h index 65fdd1c92..53805f5f0 100644 --- a/gtsam/nonlinear/NonlinearOptimizerParams.h +++ b/gtsam/nonlinear/NonlinearOptimizerParams.h @@ -33,22 +33,19 @@ namespace gtsam { */ class GTSAM_EXPORT NonlinearOptimizerParams { public: + NonlinearOptimizerParams() = default; + /** See NonlinearOptimizerParams::verbosity */ enum Verbosity { SILENT, TERMINATION, ERROR, VALUES, DELTA, LINEAR }; - size_t maxIterations; ///< The maximum iterations to stop iterating (default 100) - double relativeErrorTol; ///< The maximum relative error decrease to stop iterating (default 1e-5) - double absoluteErrorTol; ///< The maximum absolute error decrease to stop iterating (default 1e-5) - double errorTol; ///< The maximum total error to stop iterating (default 0.0) - Verbosity verbosity; ///< The printing verbosity during optimization (default SILENT) - Ordering::OrderingType orderingType; ///< The method of ordering use during variable elimination (default COLAMD) - - NonlinearOptimizerParams() : - maxIterations(100), relativeErrorTol(1e-5), absoluteErrorTol(1e-5), errorTol( - 0.0), verbosity(SILENT), orderingType(Ordering::COLAMD), - linearSolverType(MULTIFRONTAL_CHOLESKY) {} + size_t maxIterations = 100; ///< The maximum iterations to stop iterating (default 100) + double relativeErrorTol = 1e-5; ///< The maximum relative error decrease to stop iterating (default 1e-5) + double absoluteErrorTol = 1e-5; ///< The maximum absolute error decrease to stop iterating (default 1e-5) + double errorTol = 0.0; ///< The maximum total error to stop iterating (default 0.0) + Verbosity verbosity = SILENT; ///< The printing verbosity during optimization (default SILENT) + Ordering::OrderingType orderingType = Ordering::COLAMD; ///< The method of ordering use during variable elimination (default COLAMD) virtual ~NonlinearOptimizerParams() { } @@ -71,6 +68,15 @@ public: static Verbosity verbosityTranslator(const std::string &s) ; static std::string verbosityTranslator(Verbosity value) ; + /** Type for an optional user-provided hook to be called after each + * internal optimizer iteration */ + using IterationHook = std::function< + void(size_t /*iteration*/, double/*errorBefore*/, double/*errorAfter*/)>; + + /** Optional user-provided iteration hook to be called after each + * optimization iteration (Default: empty) */ + IterationHook iterationHook; + /** See NonlinearOptimizerParams::linearSolverType */ enum LinearSolverType { MULTIFRONTAL_CHOLESKY, @@ -81,7 +87,7 @@ public: CHOLMOD, /* Experimental Flag */ }; - LinearSolverType linearSolverType; ///< The type of linear solver to use in the nonlinear optimizer + LinearSolverType linearSolverType = MULTIFRONTAL_CHOLESKY; ///< The type of linear solver to use in the nonlinear optimizer boost::optional ordering; ///< The optional variable elimination ordering, or empty to use COLAMD (default: empty) IterativeOptimizationParameters::shared_ptr iterativeParams; ///< The container for iterativeOptimization parameters. used in CG Solvers. diff --git a/tests/testNonlinearOptimizer.cpp b/tests/testNonlinearOptimizer.cpp index dc19801a2..6415174d5 100644 --- a/tests/testNonlinearOptimizer.cpp +++ b/tests/testNonlinearOptimizer.cpp @@ -566,6 +566,58 @@ TEST( NonlinearOptimizer, logfile ) // EXPECT(actual.str()==expected.str()); } +/* ************************************************************************* */ +TEST( NonlinearOptimizer, iterationHook_LM ) +{ + NonlinearFactorGraph fg(example::createReallyNonlinearFactorGraph()); + + Point2 x0(3,3); + Values c0; + c0.insert(X(1), x0); + + // Levenberg-Marquardt + LevenbergMarquardtParams lmParams; + size_t lastIterCalled = 0; + lmParams.iterationHook = [&](size_t iteration, double oldError, double newError) + { + // Tests: + lastIterCalled = iteration; + EXPECT(newError " << newError <<"\n"; + }; + LevenbergMarquardtOptimizer(fg, c0, lmParams).optimize(); + + EXPECT(lastIterCalled>5); +} +/* ************************************************************************* */ +TEST( NonlinearOptimizer, iterationHook_CG ) +{ + NonlinearFactorGraph fg(example::createReallyNonlinearFactorGraph()); + + Point2 x0(3,3); + Values c0; + c0.insert(X(1), x0); + + // Levenberg-Marquardt + NonlinearConjugateGradientOptimizer::Parameters cgParams; + size_t lastIterCalled = 0; + cgParams.iterationHook = [&](size_t iteration, double oldError, double newError) + { + // Tests: + lastIterCalled = iteration; + EXPECT(newError " << newError <<"\n"; + }; + NonlinearConjugateGradientOptimizer(fg, c0, cgParams).optimize(); + + EXPECT(lastIterCalled>5); +} + + /* ************************************************************************* */ //// Minimal traits example struct MyType : public Vector3 { From c99cb14b49a2fcd7ec774c7ceeab30e87511cacb Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 9 Nov 2020 10:38:43 -0500 Subject: [PATCH 033/261] Roustify BinaryMeasurements in a functional way, plus formatting --- gtsam/sfm/BinaryMeasurement.h | 48 +++++++++---- gtsam/sfm/ShonanAveraging.cpp | 88 +++++++++++++---------- gtsam/sfm/ShonanAveraging.h | 28 ++++---- gtsam/sfm/tests/testBinaryMeasurement.cpp | 9 ++- 4 files changed, 103 insertions(+), 70 deletions(-) diff --git a/gtsam/sfm/BinaryMeasurement.h b/gtsam/sfm/BinaryMeasurement.h index ef3fff70d..f27383175 100644 --- a/gtsam/sfm/BinaryMeasurement.h +++ b/gtsam/sfm/BinaryMeasurement.h @@ -45,11 +45,43 @@ private: T measured_; ///< The measurement SharedNoiseModel noiseModel_; ///< Noise model -public: + public: BinaryMeasurement(Key key1, Key key2, const T &measured, - const SharedNoiseModel &model = nullptr) - : Factor(std::vector({key1, key2})), measured_(measured), - noiseModel_(model) {} + const SharedNoiseModel &model = nullptr, + bool useHuber = false) + : Factor(std::vector({key1, key2})), + measured_(measured), + noiseModel_(model) { + if (useHuber) { + const auto &robust = + boost::dynamic_pointer_cast(this->noiseModel_); + if (!robust) { + // make robust + this->noiseModel_ = noiseModel::Robust::Create( + noiseModel::mEstimator::Huber::Create(1.345), this->noiseModel_); + } + } + } + + /** + * Copy constructor to allow for making existing BinaryMeasurements as robust + * in a functional way. + * + * @param measurement BinaryMeasurement object. + * @param useHuber Boolean flag indicating whether to use Huber noise model. + */ + BinaryMeasurement(const BinaryMeasurement& measurement, bool useHuber = false) { + *this = measurement; + if (useHuber) { + const auto &robust = + boost::dynamic_pointer_cast(this->noiseModel_); + if (!robust) { + // make robust + this->noiseModel_ = noiseModel::Robust::Create( + noiseModel::mEstimator::Huber::Create(1.345), this->noiseModel_); + } + } + } /// @name Standard Interface /// @{ @@ -71,14 +103,6 @@ public: this->noiseModel_->print(" noise model: "); } - // TODO: make this more general? - void makeNoiseModelRobust(){ - const auto &robust = boost::dynamic_pointer_cast(this->noiseModel_); - if(!robust) // make robust - this->noiseModel_ = noiseModel::Robust::Create( - noiseModel::mEstimator::Huber::Create(1.345), this->noiseModel_); - } - bool equals(const BinaryMeasurement &expected, double tol = 1e-9) const { const BinaryMeasurement *e = dynamic_cast *>(&expected); diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 14f5665b6..53a2222e4 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -54,7 +54,7 @@ ShonanAveragingParameters::ShonanAveragingParameters( alpha(alpha), beta(beta), gamma(gamma), - useHuber(false){ + useHuber(false) { // By default, we will do conjugate gradient lm.linearSolverType = LevenbergMarquardtParams::Iterative; @@ -139,7 +139,7 @@ ShonanAveraging::ShonanAveraging(const Measurements &measurements, /* ************************************************************************* */ template NonlinearFactorGraph ShonanAveraging::buildGraphAt(size_t p) const { - NonlinearFactorGraph graph; + NonlinearFactorGraph graph; auto G = boost::make_shared(SO<-1>::VectorizedGenerators(p)); for (const auto &measurement : measurements_) { @@ -194,7 +194,7 @@ ShonanAveraging::createOptimizerAt(size_t p, const Values &initial) const { template Values ShonanAveraging::tryOptimizingAt(size_t p, const Values &initial) const { - auto lm = createOptimizerAt(p, initial); + auto lm = createOptimizerAt(p, initial); return lm->optimize(); } @@ -334,24 +334,26 @@ double ShonanAveraging::cost(const Values &values) const { // Get kappa from noise model template static double Kappa(const BinaryMeasurement &measurement) { - const auto &isotropic = boost::dynamic_pointer_cast( - measurement.noiseModel()); - double sigma; - if (isotropic) { - sigma = isotropic->sigma(); - } else{ - const auto &robust = boost::dynamic_pointer_cast( - measurement.noiseModel()); - if (robust) { - std::cout << "Verification of optimality does not work with robust cost function" << std::endl; - sigma = 1; // setting arbitrary value - }else{ - throw std::invalid_argument( - "Shonan averaging noise models must be isotropic (but robust losses are allowed)."); - - } - } - return 1.0 / (sigma * sigma); + const auto &isotropic = boost::dynamic_pointer_cast( + measurement.noiseModel()); + double sigma; + if (isotropic) { + sigma = isotropic->sigma(); + } else { + const auto &robust = boost::dynamic_pointer_cast( + measurement.noiseModel()); + if (robust) { + std::cout << "Verification of optimality does not work with robust cost " + "function" + << std::endl; + sigma = 1; // setting arbitrary value + } else { + throw std::invalid_argument( + "Shonan averaging noise models must be isotropic (but robust losses " + "are allowed)."); + } + } + return 1.0 / (sigma * sigma); } /* ************************************************************************* */ @@ -802,10 +804,10 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, // Optimize until convergence at this level Qstar = tryOptimizingAt(p, initialSOp); if(parameters_.useHuber){ // in this case, there is no optimality verification - if(pMin!=pMax) - std::cout << "When using robust norm, Shonan only tests a single rank" << std::endl; - const Values SO3Values = roundSolution(Qstar); - return std::make_pair(SO3Values, 0); + if(pMin!=pMax) + std::cout << "When using robust norm, Shonan only tests a single rank" << std::endl; + const Values SO3Values = roundSolution(Qstar); + return std::make_pair(SO3Values, 0); } // Check certificate of global optimzality @@ -833,13 +835,17 @@ template class ShonanAveraging<2>; ShonanAveraging2::ShonanAveraging2(const Measurements &measurements, const Parameters ¶meters) - : ShonanAveraging<2>(parameters.useHuber? - makeNoiseModelRobust(measurements) : measurements, parameters) {} + : ShonanAveraging<2>(parameters.useHuber + ? makeNoiseModelRobust(measurements) + : measurements, + parameters) {} ShonanAveraging2::ShonanAveraging2(string g2oFile, const Parameters ¶meters) - : ShonanAveraging<2>(parameters.useHuber? - makeNoiseModelRobust( parseMeasurements(g2oFile) ) : - parseMeasurements(g2oFile), parameters) {} + : ShonanAveraging<2>( + parameters.useHuber + ? makeNoiseModelRobust(parseMeasurements(g2oFile)) + : parseMeasurements(g2oFile), + parameters) {} /* ************************************************************************* */ // Explicit instantiation for d=3 @@ -848,12 +854,14 @@ template class ShonanAveraging<3>; ShonanAveraging3::ShonanAveraging3(const Measurements &measurements, const Parameters ¶meters) : ShonanAveraging<3>(parameters.useHuber? - makeNoiseModelRobust(measurements) : measurements, parameters) {} + makeNoiseModelRobust(measurements) : measurements, parameters) {} ShonanAveraging3::ShonanAveraging3(string g2oFile, const Parameters ¶meters) - : ShonanAveraging<3>(parameters.useHuber? - makeNoiseModelRobust( parseMeasurements(g2oFile) ) : - parseMeasurements(g2oFile), parameters) {} + : ShonanAveraging<3>( + parameters.useHuber + ? makeNoiseModelRobust(parseMeasurements(g2oFile)) + : parseMeasurements(g2oFile), + parameters) {} // TODO(frank): Deprecate after we land pybind wrapper @@ -869,8 +877,8 @@ static BinaryMeasurement convert( "with Gaussian noise models."); const Matrix6 M = gaussian->covariance(); return BinaryMeasurement( - f->key1(), f->key2(), f->measured().rotation(), - noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3), true)); + f->key1(), f->key2(), f->measured().rotation(), + noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3), true)); } static ShonanAveraging3::Measurements extractRot3Measurements( @@ -883,9 +891,11 @@ static ShonanAveraging3::Measurements extractRot3Measurements( ShonanAveraging3::ShonanAveraging3(const BetweenFactorPose3s &factors, const Parameters ¶meters) - : ShonanAveraging<3>(parameters.useHuber? - makeNoiseModelRobust( extractRot3Measurements(factors) ): - extractRot3Measurements(factors), parameters) {} + : ShonanAveraging<3>( + parameters.useHuber + ? makeNoiseModelRobust(extractRot3Measurements(factors)) + : extractRot3Measurements(factors), + parameters) {} /* ************************************************************************* */ } // namespace gtsam diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index 6efcb045b..7dd87391a 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -53,7 +53,8 @@ struct GTSAM_EXPORT ShonanAveragingParameters { double alpha; // weight of anchor-based prior (default 0) double beta; // weight of Karcher-based prior (default 1) double gamma; // weight of gauge-fixing factors (default 0) - bool useHuber; // if enabled, the Huber loss is used in the optimization (default is false) + bool useHuber; // if enabled, the Huber loss is used in the optimization + // (default is false) ShonanAveragingParameters(const LevenbergMarquardtParams &lm = LevenbergMarquardtParams::CeresDefaults(), @@ -83,12 +84,12 @@ struct GTSAM_EXPORT ShonanAveragingParameters { bool getUseHuber() { return useHuber; } void print() const { - std::cout << " ShonanAveragingParameters: " << std::endl; - std::cout << " alpha: " << alpha << std::endl; - std::cout << " beta: " << beta << std::endl; - std::cout << " gamma: " << gamma << std::endl; - std::cout << " useHuber: " << useHuber << std::endl; - std::cout << " --------------------------" << std::endl; + std::cout << " ShonanAveragingParameters: " << std::endl; + std::cout << " alpha: " << alpha << std::endl; + std::cout << " beta: " << beta << std::endl; + std::cout << " gamma: " << gamma << std::endl; + std::cout << " useHuber: " << useHuber << std::endl; + std::cout << " --------------------------" << std::endl; } }; @@ -120,7 +121,6 @@ class GTSAM_EXPORT ShonanAveraging { using Rot = typename Parameters::Rot; // We store SO(d) BetweenFactors to get noise model - // TODO(frank): use BinaryMeasurement? using Measurements = std::vector>; private: @@ -165,12 +165,12 @@ class GTSAM_EXPORT ShonanAveraging { } /// wrap factors with robust Huber loss - static Measurements makeNoiseModelRobust(Measurements measurements){ - Measurements robustMeasurements = measurements; - for (auto &measurement : robustMeasurements) { - measurement.makeNoiseModelRobust(); - } - return robustMeasurements; + Measurements makeNoiseModelRobust(const Measurements& measurements) const { + Measurements robustMeasurements = measurements; + for (auto &measurement : robustMeasurements) { + measurement = BinaryMeasurement(measurement, true); + } + return robustMeasurements; } /// k^th measurement, as a Rot. diff --git a/gtsam/sfm/tests/testBinaryMeasurement.cpp b/gtsam/sfm/tests/testBinaryMeasurement.cpp index a6a75b4ff..a079f7e04 100644 --- a/gtsam/sfm/tests/testBinaryMeasurement.cpp +++ b/gtsam/sfm/tests/testBinaryMeasurement.cpp @@ -67,20 +67,19 @@ TEST(BinaryMeasurement, Rot3) { /* ************************************************************************* */ TEST(BinaryMeasurement, Rot3MakeRobust) { BinaryMeasurement rot3Measurement(kKey1, kKey2, rot3Measured, - rot3_model); - rot3Measurement.makeNoiseModelRobust(); + rot3_model, true); EXPECT_LONGS_EQUAL(rot3Measurement.key1(), kKey1); EXPECT_LONGS_EQUAL(rot3Measurement.key2(), kKey2); EXPECT(rot3Measurement.measured().equals(rot3Measured)); const auto &robust = boost::dynamic_pointer_cast( - rot3Measurement.noiseModel()); + rot3Measurement.noiseModel()); EXPECT(robust); // test that if we call it again nothing changes: - rot3Measurement.makeNoiseModelRobust(); + rot3Measurement = BinaryMeasurement(rot3Measurement, true); const auto &robust2 = boost::dynamic_pointer_cast( - rot3Measurement.noiseModel()); + rot3Measurement.noiseModel()); EXPECT(robust2); } From 5762ba5ac8a5c1ca1769a745db37f6ef97b9817b Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 9 Nov 2020 10:39:04 -0500 Subject: [PATCH 034/261] Remove goto, update docs, formatting --- gtsam/slam/FrobeniusFactor.cpp | 37 ++++++++++++++++++---------------- gtsam/slam/FrobeniusFactor.h | 17 ++++++++++------ 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/gtsam/slam/FrobeniusFactor.cpp b/gtsam/slam/FrobeniusFactor.cpp index 5806fcfdb..8c70a1ebb 100644 --- a/gtsam/slam/FrobeniusFactor.cpp +++ b/gtsam/slam/FrobeniusFactor.cpp @@ -26,41 +26,44 @@ namespace gtsam { SharedNoiseModel ConvertNoiseModel(const SharedNoiseModel &model, size_t d, bool defaultToUnit) { double sigma = 1.0; + bool exit = false; + if (model != nullptr) { - const auto &robust = boost::dynamic_pointer_cast(model); - Vector sigmas; - if(robust){ - sigmas = robust->noise()->sigmas(); - } else{ - sigmas = model->sigmas(); - } + const auto &robust = boost::dynamic_pointer_cast(model); + Vector sigmas; + if (robust) { + sigmas = robust->noise()->sigmas(); + } else { + sigmas = model->sigmas(); + } size_t n = sigmas.size(); if (n == 1) { sigma = sigmas(0); // Rot2 - goto exit; + exit = true; } - if (n == 3 || n == 6) { + else if (n == 3 || n == 6) { sigma = sigmas(2); // Pose2, Rot3, or Pose3 if (sigmas(0) != sigma || sigmas(1) != sigma) { if (!defaultToUnit) { throw std::runtime_error("Can only convert isotropic rotation noise"); } } - goto exit; + exit = true; } - if (!defaultToUnit) { + if (!defaultToUnit && !exit) { throw std::runtime_error("Can only convert Pose2/Pose3 noise models"); } } - exit: + auto isoModel = noiseModel::Isotropic::Sigma(d, sigma); const auto &robust = boost::dynamic_pointer_cast(model); - if(robust) - return noiseModel::Robust::Create( - noiseModel::mEstimator::Huber::Create(1.345), isoModel); - else - return isoModel; + if (robust) { + return noiseModel::Robust::Create( + noiseModel::mEstimator::Huber::Create(1.345), isoModel); + } else { + return isoModel; + } } //****************************************************************************** diff --git a/gtsam/slam/FrobeniusFactor.h b/gtsam/slam/FrobeniusFactor.h index 9915a617d..f17a9e421 100644 --- a/gtsam/slam/FrobeniusFactor.h +++ b/gtsam/slam/FrobeniusFactor.h @@ -26,13 +26,18 @@ namespace gtsam { /** - * When creating (any) FrobeniusFactor we can convert a Rot/Pose - * BetweenFactor noise model into a n-dimensional isotropic noise - * model used to weight the Frobenius norm. If the noise model passed is - * null we return a n-dimensional isotropic noise model with sigma=1.0. If - * not, we we check if the d-dimensional noise model on rotations is + * When creating (any) FrobeniusFactor we can convert a Rot/Pose BetweenFactor + * noise model into a n-dimensional isotropic noise + * model used to weight the Frobenius norm. + * If the noise model passed is null we return a n-dimensional isotropic noise + * model with sigma=1.0. + * If not, we we check if the d-dimensional noise model on rotations is * isotropic. If it is, we extend to 'n' dimensions, otherwise we throw an - * error. If defaultToUnit == false throws an exception on unexepcted input. + * error. + * If the noise model is a robust error model, we use the sigmas of the + * underlying noise model. + * + * If defaultToUnit == false throws an exception on unexepcted input. */ GTSAM_EXPORT SharedNoiseModel ConvertNoiseModel(const SharedNoiseModel &model, size_t n, From dd45797813f3de813309a22e1d34b080cce63034 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 9 Nov 2020 10:39:25 -0500 Subject: [PATCH 035/261] delete old, unused file --- .cproject | 82 ------------------------------------------------------- 1 file changed, 82 deletions(-) delete mode 100644 .cproject diff --git a/.cproject b/.cproject deleted file mode 100644 index 9589ace56..000000000 --- a/.cproject +++ /dev/null @@ -1,82 +0,0 @@ - - - gtsam - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, - - - ?name? - - - - org.eclipse.cdt.make.core.append_environment - true - - - org.eclipse.cdt.make.core.autoBuildTarget - all - - - org.eclipse.cdt.make.core.buildArguments - -j4 - - - org.eclipse.cdt.make.core.buildCommand - make - - - org.eclipse.cdt.make.core.buildLocation - ${ProjDirPath}/build - - - org.eclipse.cdt.make.core.cleanBuildTarget - clean - - - org.eclipse.cdt.make.core.contents - org.eclipse.cdt.make.core.activeConfigSettings - - - org.eclipse.cdt.make.core.enableAutoBuild - false - - - org.eclipse.cdt.make.core.enableCleanBuild - true - - - org.eclipse.cdt.make.core.enableFullBuild - true - - - org.eclipse.cdt.make.core.fullBuildTarget - all - - - org.eclipse.cdt.make.core.stopOnError - true - - - org.eclipse.cdt.make.core.useDefaultBuildCmd - true - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - From f2bfdbd317b02dfc75143c6c34c91b7f16a72f6f Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sun, 15 Nov 2020 18:40:02 -0500 Subject: [PATCH 036/261] upload build directory after workflow completes --- .github/workflows/build-linux.yml | 7 ++++++- .github/workflows/build-macos.yml | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index d80a7f4ba..07397c999 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -82,4 +82,9 @@ jobs: - name: Build and Test (Linux) if: runner.os == 'Linux' run: | - bash .github/scripts/unix.sh -t \ No newline at end of file + bash .github/scripts/unix.sh -t + - name: Upload build directory + uses: actions/upload-artifact@v2 + with: + name: gtsam-${{ matrix.name }} + path: $GITHUB_WORKSPACE/build/ diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 69873980a..524cef18a 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -51,3 +51,8 @@ jobs: if: runner.os == 'macOS' run: | bash .github/scripts/unix.sh -t + - name: Upload build directory + uses: actions/upload-artifact@v2 + with: + name: gtsam-${{ matrix.name }} + path: $GITHUB_WORKSPACE/build/ From 6d9f95d32eff60b4635bc665e94fab081f4c66db Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Sun, 15 Nov 2020 22:49:36 -0500 Subject: [PATCH 037/261] Fixed doxygen --- gtsam/linear/AcceleratedPowerMethod.h | 89 ++++++++++++++------------- gtsam/linear/PowerMethod.h | 70 +++++++++++++++------ 2 files changed, 96 insertions(+), 63 deletions(-) diff --git a/gtsam/linear/AcceleratedPowerMethod.h b/gtsam/linear/AcceleratedPowerMethod.h index 0c544f05c..0699f237e 100644 --- a/gtsam/linear/AcceleratedPowerMethod.h +++ b/gtsam/linear/AcceleratedPowerMethod.h @@ -19,46 +19,44 @@ #pragma once -// #include -// #include #include namespace gtsam { using Sparse = Eigen::SparseMatrix; -/* ************************************************************************* */ -/// MINIMUM EIGENVALUE COMPUTATIONS - -// Template argument Operator just needs multiplication operator +/** + * \brief Compute maximum Eigenpair with accelerated power method + * + * References : + * 1) Rosen, D. and Carlone, L., 2017, September. Computational + * enhancements for certifiably correct SLAM. In Proceedings of the + * International Conference on Intelligent Robots and Systems. + * 2) Yulun Tian and Kasra Khosoussi and David M. Rosen and Jonathan P. How, + * 2020, Aug, Distributed Certifiably Correct Pose-Graph Optimization, Arxiv + * 3) C. de Sa, B. He, I. Mitliagkas, C. Ré, and P. Xu, “Accelerated + * stochastic power iteration,” in Proc. Mach. Learn. Res., no. 84, 2018, pp. + * 58–67 + * + * It performs the following iteration: \f$ x_{k+1} = A * x_k - \beta * + * x_{k-1} \f$ where A is the aim matrix we want to get eigenpair of, x is the + * Ritz vector + * + * Template argument Operator just needs multiplication operator + * + */ template class AcceleratedPowerMethod : public PowerMethod { - /** - * \brief Compute maximum Eigenpair with accelerated power method - * - * References : - * 1) Rosen, D. and Carlone, L., 2017, September. Computational - * enhancements for certifiably correct SLAM. In Proceedings of the - * International Conference on Intelligent Robots and Systems. - * 2) Yulun Tian and Kasra Khosoussi and David M. Rosen and Jonathan P. How, - * 2020, Aug, Distributed Certifiably Correct Pose-Graph Optimization, Arxiv - * 3) C. de Sa, B. He, I. Mitliagkas, C. Ré, and P. Xu, “Accelerated - * stochastic power iteration,” in Proc. Mach. Learn. Res., no. 84, 2018, pp. - * 58–67 - * - * It performs the following iteration: \f$ x_{k+1} = A * x_k - \beta * - * x_{k-1} \f$ where A is the aim matrix we want to get eigenpair of, x is the - * Ritz vector - * - */ double beta_ = 0; // a Polyak momentum term Vector previousVector_; // store previous vector public: - // Constructor from aim matrix A (given as Matrix or Sparse), optional intial - // vector as ritzVector + /** + * Constructor from aim matrix A (given as Matrix or Sparse), optional intial + * vector as ritzVector + */ explicit AcceleratedPowerMethod( const Operator &A, const boost::optional initial = boost::none, double initialBeta = 0.0) @@ -70,15 +68,16 @@ class AcceleratedPowerMethod : public PowerMethod { // initialize beta_ if (!initialBeta) { - estimateBeta(); - } else { + beta_ = estimateBeta(); + } else beta_ = initialBeta; - } } - // Run accelerated power iteration on the ritzVector with beta and previous - // two ritzVector, and return y = (A * x0 - \beta * x00) / || A * x0 - // - \beta * x00 || + /** + * Run accelerated power iteration to get ritzVector with beta and previous + * two ritzVector x0 and x00, and return y = (A * x0 - \beta * x00) / || A * x0 + * - \beta * x00 || + */ Vector acceleratedPowerIteration (const Vector &x1, const Vector &x0, const double beta) const { Vector y = this->A_ * x1 - beta * x0; @@ -86,16 +85,18 @@ class AcceleratedPowerMethod : public PowerMethod { return y; } - // Run accelerated power iteration on the ritzVector with beta and previous - // two ritzVector, and return y = (A * x0 - \beta * x00) / || A * x0 - // - \beta * x00 || + /** + * Run accelerated power iteration to get ritzVector with beta and previous + * two ritzVector x0 and x00, and return y = (A * x0 - \beta * x00) / || A * x0 + * - \beta * x00 || + */ Vector acceleratedPowerIteration () const { Vector y = acceleratedPowerIteration(this->ritzVector_, previousVector_, beta_); return y; } - // Tuning the momentum beta using the Best Heavy Ball algorithm in Ref(3) - void estimateBeta() { + /// Tuning the momentum beta using the Best Heavy Ball algorithm in Ref(3) + double estimateBeta() const { // set initial estimation of maxBeta Vector initVector = this->ritzVector_; const double up = initVector.dot( this->A_ * initVector ); @@ -106,7 +107,7 @@ class AcceleratedPowerMethod : public PowerMethod { std::vector betas; Matrix R = Matrix::Zero(this->dim_, 10); - size_t T = 10; + const size_t T = 10; // run T times of iteration to find the beta that has the largest Rayleigh quotient for (size_t t = 0; t < T; t++) { // after each t iteration, reset the betas with the current maxBeta @@ -141,13 +142,15 @@ class AcceleratedPowerMethod : public PowerMethod { } } // set beta_ to momentum with largest Rayleigh quotient - beta_ = betas[maxIndex]; + return betas[maxIndex]; } - // Start the accelerated iteration, after performing the - // accelerated iteration, calculate the ritz error, repeat this - // operation until the ritz error converge. If converged return true, else - // false. + /** + * Start the accelerated iteration, after performing the + * accelerated iteration, calculate the ritz error, repeat this + * operation until the ritz error converge. If converged return true, else + * false. + */ bool compute(size_t maxIterations, double tol) { // Starting bool isConverged = false; diff --git a/gtsam/linear/PowerMethod.h b/gtsam/linear/PowerMethod.h index ae1d97cc7..a209c5779 100644 --- a/gtsam/linear/PowerMethod.h +++ b/gtsam/linear/PowerMethod.h @@ -31,15 +31,33 @@ namespace gtsam { using Sparse = Eigen::SparseMatrix; -/* ************************************************************************* */ -/// MINIMUM EIGENVALUE COMPUTATIONS - -// Template argument Operator just needs multiplication operator +/** + * \brief Compute maximum Eigenpair with power method + * + * References : + * 1) Rosen, D. and Carlone, L., 2017, September. Computational + * enhancements for certifiably correct SLAM. In Proceedings of the + * International Conference on Intelligent Robots and Systems. + * 2) Yulun Tian and Kasra Khosoussi and David M. Rosen and Jonathan P. How, + * 2020, Aug, Distributed Certifiably Correct Pose-Graph Optimization, Arxiv + * 3) C. de Sa, B. He, I. Mitliagkas, C. Ré, and P. Xu, “Accelerated + * stochastic power iteration,” in Proc. Mach. Learn. Res., no. 84, 2018, pp. + * 58–67 + * + * It performs the following iteration: \f$ x_{k+1} = A * x_k \f$ + * where A is the aim matrix we want to get eigenpair of, x is the + * Ritz vector + * + * Template argument Operator just needs multiplication operator + * + */ template class PowerMethod { protected: - // Const reference to an externally-held matrix whose minimum-eigenvalue we - // want to compute + /** + * Const reference to an externally-held matrix whose minimum-eigenvalue we + * want to compute + */ const Operator &A_; const int dim_; // dimension of Matrix A @@ -50,7 +68,10 @@ class PowerMethod { Vector ritzVector_; // Ritz eigenvector public: - // Constructor + /// @name Standard Constructors + /// @{ + + /// Construct from the aim matrix and intial ritz vector explicit PowerMethod(const Operator &A, const boost::optional initial = boost::none) : A_(A), dim_(A.rows()), nrIterations_(0) { @@ -62,23 +83,30 @@ class PowerMethod { ritzValue_ = 0.0; // initialize Ritz eigen vector - ritzVector_ = Vector::Zero(dim_); ritzVector_ = powerIteration(x0); } - // Run power iteration on the vector, and return A * x / || A * x || + /** + * Run power iteration to get ritzVector with previous ritzVector x, and + * return A * x / || A * x || + */ Vector powerIteration(const Vector &x) const { Vector y = A_ * x; y.normalize(); return y; } - // Run power iteration on the vector, and return A * x / || A * x || + /** + * Run power iteration to get ritzVector with previous ritzVector x, and + * return A * x / || A * x || + */ Vector powerIteration() const { return powerIteration(ritzVector_); } - // After Perform power iteration on a single Ritz value, check if the Ritz - // residual for the current Ritz pair is less than the required convergence - // tol, return true if yes, else false + /** + * After Perform power iteration on a single Ritz value, check if the Ritz + * residual for the current Ritz pair is less than the required convergence + * tol, return true if yes, else false + */ bool converged(double tol) const { const Vector x = ritzVector_; // store the Ritz eigen value @@ -87,13 +115,15 @@ class PowerMethod { return error < tol; } - // Return the number of iterations + /// Return the number of iterations size_t nrIterations() const { return nrIterations_; } - // Start the power/accelerated iteration, after performing the - // power/accelerated iteration, calculate the ritz error, repeat this - // operation until the ritz error converge. If converged return true, else - // false. + /** + * Start the power/accelerated iteration, after performing the + * power/accelerated iteration, calculate the ritz error, repeat this + * operation until the ritz error converge. If converged return true, else + * false. + */ bool compute(size_t maxIterations, double tol) { // Starting bool isConverged = false; @@ -110,10 +140,10 @@ class PowerMethod { return isConverged; } - // Return the eigenvalue + /// Return the eigenvalue double eigenvalue() const { return ritzValue_; } - // Return the eigenvector + /// Return the eigenvector Vector eigenvector() const { return ritzVector_; } }; From 91d275c9c74c955bb1ff86ea9b213e0344b796de Mon Sep 17 00:00:00 2001 From: Jose Luis Blanco Claraco Date: Mon, 16 Nov 2020 07:25:30 +0100 Subject: [PATCH 038/261] Add docs, fix ctor placement --- gtsam/nonlinear/NonlinearOptimizerParams.h | 40 ++++++++++++++++------ 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/gtsam/nonlinear/NonlinearOptimizerParams.h b/gtsam/nonlinear/NonlinearOptimizerParams.h index 53805f5f0..92c800e0c 100644 --- a/gtsam/nonlinear/NonlinearOptimizerParams.h +++ b/gtsam/nonlinear/NonlinearOptimizerParams.h @@ -33,8 +33,6 @@ namespace gtsam { */ class GTSAM_EXPORT NonlinearOptimizerParams { public: - NonlinearOptimizerParams() = default; - /** See NonlinearOptimizerParams::verbosity */ enum Verbosity { SILENT, TERMINATION, ERROR, VALUES, DELTA, LINEAR @@ -47,10 +45,6 @@ public: Verbosity verbosity = SILENT; ///< The printing verbosity during optimization (default SILENT) Ordering::OrderingType orderingType = Ordering::COLAMD; ///< The method of ordering use during variable elimination (default COLAMD) - virtual ~NonlinearOptimizerParams() { - } - virtual void print(const std::string& str = "") const; - size_t getMaxIterations() const { return maxIterations; } double getRelativeErrorTol() const { return relativeErrorTol; } double getAbsoluteErrorTol() const { return absoluteErrorTol; } @@ -68,13 +62,33 @@ public: static Verbosity verbosityTranslator(const std::string &s) ; static std::string verbosityTranslator(Verbosity value) ; - /** Type for an optional user-provided hook to be called after each - * internal optimizer iteration */ + /** Type for an optional user-provided hook to be called after each + * internal optimizer iteration. See iterationHook below. */ using IterationHook = std::function< void(size_t /*iteration*/, double/*errorBefore*/, double/*errorAfter*/)>; - /** Optional user-provided iteration hook to be called after each - * optimization iteration (Default: empty) */ + /** Optional user-provided iteration hook to be called after each + * optimization iteration (Default: none). + * Note that `IterationHook` is defined as a std::function<> with this + * signature: + * \code + * void(size_t iteration, double errorBefore, double errorAfter) + * \endcode + * which allows binding by means of a reference to a regular function: + * \code + * void foo(size_t iteration, double errorBefore, double errorAfter); + * // ... + * lmOpts.iterationHook = &foo; + * \endcode + * or to a C++11 lambda: + * \code + * lmOpts.iterationHook = [&](size_t iter, double oldError, double newError) + * { + * // ... + * }; + * \endcode + * or to the result of a properly-formed `std::bind` call. + */ IterationHook iterationHook; /** See NonlinearOptimizerParams::linearSolverType */ @@ -91,6 +105,12 @@ public: boost::optional ordering; ///< The optional variable elimination ordering, or empty to use COLAMD (default: empty) IterativeOptimizationParameters::shared_ptr iterativeParams; ///< The container for iterativeOptimization parameters. used in CG Solvers. + NonlinearOptimizerParams() = default; + virtual ~NonlinearOptimizerParams() { + } + + virtual void print(const std::string& str = "") const; + inline bool isMultifrontal() const { return (linearSolverType == MULTIFRONTAL_CHOLESKY) || (linearSolverType == MULTIFRONTAL_QR); From 9a4bd10e222918cfd984d793a04fad24741b7c21 Mon Sep 17 00:00:00 2001 From: Jose Luis Blanco Claraco Date: Mon, 16 Nov 2020 07:32:03 +0100 Subject: [PATCH 039/261] further extended docs --- gtsam/nonlinear/NonlinearOptimizerParams.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gtsam/nonlinear/NonlinearOptimizerParams.h b/gtsam/nonlinear/NonlinearOptimizerParams.h index 92c800e0c..a7bc10a1f 100644 --- a/gtsam/nonlinear/NonlinearOptimizerParams.h +++ b/gtsam/nonlinear/NonlinearOptimizerParams.h @@ -80,7 +80,9 @@ public: * // ... * lmOpts.iterationHook = &foo; * \endcode - * or to a C++11 lambda: + * or to a C++11 lambda (preferred if you need to capture additional + * context variables, such that the optimizer object itself, the factor graph, + * etc.): * \code * lmOpts.iterationHook = [&](size_t iter, double oldError, double newError) * { From ac089ce6a37d6c6becded9ac4bee19f8cf1fe15c Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 16 Nov 2020 12:22:09 -0500 Subject: [PATCH 040/261] use KeyVector to allow proper wrapping with TBB --- gtsam/sfm/MFAS.cpp | 6 +++--- gtsam/sfm/MFAS.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gtsam/sfm/MFAS.cpp b/gtsam/sfm/MFAS.cpp index 4cd983ecd..913752d8a 100644 --- a/gtsam/sfm/MFAS.cpp +++ b/gtsam/sfm/MFAS.cpp @@ -121,8 +121,8 @@ MFAS::MFAS(const TranslationEdges& relativeTranslations, } } -vector MFAS::computeOrdering() const { - vector ordering; // Nodes in MFAS order (result). +KeyVector MFAS::computeOrdering() const { + KeyVector ordering; // Nodes in MFAS order (result). // A graph is an unordered map from keys to nodes. Each node contains a list // of its adjacent nodes. Create the graph from the edgeWeights. @@ -140,7 +140,7 @@ vector MFAS::computeOrdering() const { map MFAS::computeOutlierWeights() const { // Find the ordering. - vector ordering = computeOrdering(); + KeyVector ordering = computeOrdering(); // Create a map from the node key to its position in the ordering. This makes // it easier to lookup positions of different nodes. diff --git a/gtsam/sfm/MFAS.h b/gtsam/sfm/MFAS.h index 3b01122a9..decfbed0f 100644 --- a/gtsam/sfm/MFAS.h +++ b/gtsam/sfm/MFAS.h @@ -84,7 +84,7 @@ class MFAS { * @brief Computes the 1D MFAS ordering of nodes in the graph * @return orderedNodes: vector of nodes in the obtained order */ - std::vector computeOrdering() const; + KeyVector computeOrdering() const; /** * @brief Computes the outlier weights of the graph. We define the outlier From 283582cd5d88e3a10ae8c9a619fb25b379029927 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 16 Nov 2020 12:31:44 -0500 Subject: [PATCH 041/261] update MFAS tests --- gtsam/sfm/tests/testMFAS.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gtsam/sfm/tests/testMFAS.cpp b/gtsam/sfm/tests/testMFAS.cpp index 362027d5d..a1f6dfa5f 100644 --- a/gtsam/sfm/tests/testMFAS.cpp +++ b/gtsam/sfm/tests/testMFAS.cpp @@ -25,7 +25,7 @@ using namespace gtsam; vector edges = {make_pair(3, 2), make_pair(0, 1), make_pair(3, 1), make_pair(1, 2), make_pair(0, 2), make_pair(3, 0)}; // nodes in the graph -vector nodes = {Key(0), Key(1), Key(2), Key(3)}; +KeyVector nodes = {Key(0), Key(1), Key(2), Key(3)}; // weights from projecting in direction-1 (bad direction, outlier accepted) vector weights1 = {2, 1.5, 0.5, 0.25, 1, 0.75}; // weights from projecting in direction-2 (good direction, outlier rejected) @@ -47,10 +47,10 @@ map getEdgeWeights(const vector &edges, TEST(MFAS, OrderingWeights2) { MFAS mfas_obj(getEdgeWeights(edges, weights2)); - vector ordered_nodes = mfas_obj.computeOrdering(); + KeyVector ordered_nodes = mfas_obj.computeOrdering(); // ground truth (expected) ordering in this example - vector gt_ordered_nodes = {0, 1, 3, 2}; + KeyVector gt_ordered_nodes = {0, 1, 3, 2}; // check if the expected ordering is obtained for (size_t i = 0; i < ordered_nodes.size(); i++) { @@ -77,10 +77,10 @@ TEST(MFAS, OrderingWeights2) { TEST(MFAS, OrderingWeights1) { MFAS mfas_obj(getEdgeWeights(edges, weights1)); - vector ordered_nodes = mfas_obj.computeOrdering(); + KeyVector ordered_nodes = mfas_obj.computeOrdering(); // "ground truth" expected ordering in this example - vector gt_ordered_nodes = {3, 0, 1, 2}; + KeyVector gt_ordered_nodes = {3, 0, 1, 2}; // check if the expected ordering is obtained for (size_t i = 0; i < ordered_nodes.size(); i++) { From 5c94b5ccc70d374a49f024dcb24bcec94382c817 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 16 Nov 2020 13:11:10 -0500 Subject: [PATCH 042/261] fix indentation and add upload for Windows --- .github/workflows/build-linux.yml | 6 +++--- .github/workflows/build-macos.yml | 6 +++--- .github/workflows/build-windows.yml | 7 ++++++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 07397c999..514f7c6d5 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -85,6 +85,6 @@ jobs: bash .github/scripts/unix.sh -t - name: Upload build directory uses: actions/upload-artifact@v2 - with: - name: gtsam-${{ matrix.name }} - path: $GITHUB_WORKSPACE/build/ + with: + name: gtsam-${{ matrix.name }} + path: $GITHUB_WORKSPACE/build/ diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 524cef18a..298fc316b 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -53,6 +53,6 @@ jobs: bash .github/scripts/unix.sh -t - name: Upload build directory uses: actions/upload-artifact@v2 - with: - name: gtsam-${{ matrix.name }} - path: $GITHUB_WORKSPACE/build/ + with: + name: gtsam-${{ matrix.name }} + path: $GITHUB_WORKSPACE/build/ diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 0a55de880..446e708a6 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -75,4 +75,9 @@ jobs: cmake --build build --config ${{ matrix.build_type }} --target wrap cmake --build build --config ${{ matrix.build_type }} --target check.base cmake --build build --config ${{ matrix.build_type }} --target check.base_unstable - cmake --build build --config ${{ matrix.build_type }} --target check.linear \ No newline at end of file + cmake --build build --config ${{ matrix.build_type }} --target check.linear + - name: Upload build directory + uses: actions/upload-artifact@v2 + with: + name: gtsam-${{ matrix.name }} + path: $GITHUB_WORKSPACE/build/ From aa2d9225dcc52848342d68435b28dc5995698700 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 16 Nov 2020 14:42:17 -0500 Subject: [PATCH 043/261] correct form for workspace env variable --- .github/workflows/build-linux.yml | 2 +- .github/workflows/build-macos.yml | 2 +- .github/workflows/build-windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 514f7c6d5..1778286d9 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -87,4 +87,4 @@ jobs: uses: actions/upload-artifact@v2 with: name: gtsam-${{ matrix.name }} - path: $GITHUB_WORKSPACE/build/ + path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 298fc316b..2a3af6b9e 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -55,4 +55,4 @@ jobs: uses: actions/upload-artifact@v2 with: name: gtsam-${{ matrix.name }} - path: $GITHUB_WORKSPACE/build/ + path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 446e708a6..1de0d0493 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -80,4 +80,4 @@ jobs: uses: actions/upload-artifact@v2 with: name: gtsam-${{ matrix.name }} - path: $GITHUB_WORKSPACE/build/ + path: ${{ github.workspace }}/build/ From d5a09aad12ef04392cacb8b8bfe1589a66e42fca Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 16 Nov 2020 17:47:42 -0500 Subject: [PATCH 044/261] differentiate between Release and Debug builds --- .github/workflows/build-linux.yml | 2 +- .github/workflows/build-macos.yml | 2 +- .github/workflows/build-windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 1778286d9..cd4933cd9 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -86,5 +86,5 @@ jobs: - name: Upload build directory uses: actions/upload-artifact@v2 with: - name: gtsam-${{ matrix.name }} + name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 2a3af6b9e..5e6f8ca04 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -54,5 +54,5 @@ jobs: - name: Upload build directory uses: actions/upload-artifact@v2 with: - name: gtsam-${{ matrix.name }} + name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 1de0d0493..63c276020 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -79,5 +79,5 @@ jobs: - name: Upload build directory uses: actions/upload-artifact@v2 with: - name: gtsam-${{ matrix.name }} + name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ From 1fd0e57fb0a2a9cd24accd3d8dc04d91328dccf6 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 18 Nov 2020 14:48:05 -0500 Subject: [PATCH 045/261] Better fkag naming, and more docs --- gtsam/base/Matrix.h | 2 +- gtsam/base/Vector.cpp | 14 +++++++------- gtsam/base/Vector.h | 5 ++++- gtsam/base/tests/testMatrix.cpp | 10 +++++----- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/gtsam/base/Matrix.h b/gtsam/base/Matrix.h index 9adf4e1c1..a3a14c6c3 100644 --- a/gtsam/base/Matrix.h +++ b/gtsam/base/Matrix.h @@ -90,7 +90,7 @@ bool equal_with_abs_tol(const Eigen::DenseBase& A, const Eigen::DenseBas for(size_t i=0; i abs(a)) ? abs(b) : abs(a); // handle NaNs - if(std::isnan(a) || isnan(b)) { + if(isnan(a) || isnan(b)) { return isnan(a) && isnan(b); } // handle inf @@ -60,15 +60,15 @@ bool fpEqual(double a, double b, double tol, bool absolute) { else if(a == 0 || b == 0 || (abs(a) + abs(b)) < DOUBLE_MIN_NORMAL) { return abs(a-b) <= tol * DOUBLE_MIN_NORMAL; } - // Check if the numbers are really close - // Needed when comparing numbers near zero or tol is in vicinity - else if(abs(a-b) <= tol) { + // Check if the numbers are really close. + // Needed when comparing numbers near zero or tol is in vicinity. + else if (abs(a - b) <= tol) { return true; } - // Use relative error + // Check for relative error else if (abs(a - b) <= tol * min(larger, std::numeric_limits::max()) && - !absolute) { + check_relative) { return true; } diff --git a/gtsam/base/Vector.h b/gtsam/base/Vector.h index b0fc74f26..49b7e6d9d 100644 --- a/gtsam/base/Vector.h +++ b/gtsam/base/Vector.h @@ -85,10 +85,13 @@ static_assert( * respectively for the comparison to be true. * If one is NaN/Inf and the other is not, returns false. * + * The `check_relative` flag toggles checking for relative error as well. By + * default, the flag is true. + * * Return true if two numbers are close wrt tol. */ GTSAM_EXPORT bool fpEqual(double a, double b, double tol, - bool absolute = false); + bool check_relative = true); /** * print without optional string, must specify cout yourself diff --git a/gtsam/base/tests/testMatrix.cpp b/gtsam/base/tests/testMatrix.cpp index d22ffc0db..a7c218705 100644 --- a/gtsam/base/tests/testMatrix.cpp +++ b/gtsam/base/tests/testMatrix.cpp @@ -1164,15 +1164,15 @@ TEST(Matrix , IsVectorSpace) { } TEST(Matrix, AbsoluteError) { - double a = 2000, b = 1997, tol=1e-1; + double a = 2000, b = 1997, tol = 1e-1; bool isEqual; - // Test absolute error - isEqual = fpEqual(a, b, tol, true); + // Test only absolute error + isEqual = fpEqual(a, b, tol, false); EXPECT(!isEqual); - // Test relative error - isEqual = fpEqual(a, b, tol, false); + // Test relative error as well + isEqual = fpEqual(a, b, tol); EXPECT(isEqual); } From 30afc95936ffb360d99012b08fb623e7d6f8ebc2 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 18 Nov 2020 16:05:13 -0500 Subject: [PATCH 046/261] placed MEX check to new cmake file --- cmake/HandleGeneralOptions.cmake | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/cmake/HandleGeneralOptions.cmake b/cmake/HandleGeneralOptions.cmake index 85a529e49..fb1e4e8d2 100644 --- a/cmake/HandleGeneralOptions.cmake +++ b/cmake/HandleGeneralOptions.cmake @@ -46,10 +46,17 @@ option(GTSAM_INSTALL_MATLAB_TOOLBOX "Enable/Disable installation of matlab set(GTSAM_PYTHON_VERSION "Default" CACHE STRING "The version of Python to build the wrappers against.") # Check / set dependent variables for MATLAB wrapper -if(GTSAM_INSTALL_MATLAB_TOOLBOX AND GTSAM_BUILD_TYPE_POSTFIXES) - set(CURRENT_POSTFIX ${CMAKE_${CMAKE_BUILD_TYPE_UPPER}_POSTFIX}) -endif() +if(GTSAM_INSTALL_MATLAB_TOOLBOX) + find_package(Matlab COMPONENTS MEX_COMPILER REQUIRED) + if(NOT Matlab_MEX_COMPILER) + message(FATAL_ERROR "Cannot find MEX compiler binary. Please check your Matlab installation and ensure MEX in installed as well.") + endif() -if(GTSAM_INSTALL_MATLAB_TOOLBOX AND NOT BUILD_SHARED_LIBS) - message(FATAL_ERROR "GTSAM_INSTALL_MATLAB_TOOLBOX and BUILD_SHARED_LIBS=OFF. The MATLAB wrapper cannot be compiled with a static GTSAM library because mex modules are themselves shared libraries. If you want a self-contained mex module, enable GTSAM_MEX_BUILD_STATIC_MODULE instead of BUILD_SHARED_LIBS=OFF.") + if(GTSAM_BUILD_TYPE_POSTFIXES) + set(CURRENT_POSTFIX ${CMAKE_${CMAKE_BUILD_TYPE_UPPER}_POSTFIX}) + endif() + + if(NOT BUILD_SHARED_LIBS) + message(FATAL_ERROR "GTSAM_INSTALL_MATLAB_TOOLBOX and BUILD_SHARED_LIBS=OFF. The MATLAB wrapper cannot be compiled with a static GTSAM library because mex modules are themselves shared libraries. If you want a self-contained mex module, enable GTSAM_MEX_BUILD_STATIC_MODULE instead of BUILD_SHARED_LIBS=OFF.") + endif() endif() From 812240b056abfafe74cb3120c244068c495442c4 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 18 Nov 2020 16:08:06 -0500 Subject: [PATCH 047/261] restructuring --- cmake/HandleGeneralOptions.cmake | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmake/HandleGeneralOptions.cmake b/cmake/HandleGeneralOptions.cmake index fb1e4e8d2..469d4bba6 100644 --- a/cmake/HandleGeneralOptions.cmake +++ b/cmake/HandleGeneralOptions.cmake @@ -24,6 +24,7 @@ option(GTSAM_WITH_EIGEN_MKL "Eigen will use Intel MKL if available" option(GTSAM_WITH_EIGEN_MKL_OPENMP "Eigen, when using Intel MKL, will also use OpenMP for multithreading if available" OFF) option(GTSAM_THROW_CHEIRALITY_EXCEPTION "Throw exception when a triangulated point is behind a camera" ON) option(GTSAM_BUILD_PYTHON "Enable/Disable building & installation of Python module with pybind11" OFF) +option(GTSAM_INSTALL_MATLAB_TOOLBOX "Enable/Disable installation of matlab toolbox" OFF) option(GTSAM_ALLOW_DEPRECATED_SINCE_V41 "Allow use of methods/functions deprecated in GTSAM 4.1" ON) option(GTSAM_SUPPORT_NESTED_DISSECTION "Support Metis-based nested dissection" ON) option(GTSAM_TANGENT_PREINTEGRATION "Use new ImuFactor with integration on tangent space" ON) @@ -40,9 +41,7 @@ elseif(GTSAM_ROT3_EXPMAP) set(GTSAM_POSE3_EXPMAP 1 CACHE BOOL "" FORCE) endif() -# Options relating to MATLAB wrapper -# TODO: Check for matlab mex binary before handling building of binaries -option(GTSAM_INSTALL_MATLAB_TOOLBOX "Enable/Disable installation of matlab toolbox" OFF) +# Set the default Python version. This is later updated in HandlePython.cmake. set(GTSAM_PYTHON_VERSION "Default" CACHE STRING "The version of Python to build the wrappers against.") # Check / set dependent variables for MATLAB wrapper From 628ae264968866dd1281a3c3710c90e6e667c8ea Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 18 Nov 2020 16:29:53 -0500 Subject: [PATCH 048/261] encapsulated and updated all the CMake related to Matlab --- cmake/GtsamMatlabWrap.cmake | 77 +++++++++++++++++++------------- cmake/HandleGeneralOptions.cmake | 16 ------- 2 files changed, 45 insertions(+), 48 deletions(-) diff --git a/cmake/GtsamMatlabWrap.cmake b/cmake/GtsamMatlabWrap.cmake index 4c44d2cb3..b17618f49 100644 --- a/cmake/GtsamMatlabWrap.cmake +++ b/cmake/GtsamMatlabWrap.cmake @@ -1,51 +1,64 @@ +# Check / set dependent variables for MATLAB wrapper +if(GTSAM_INSTALL_MATLAB_TOOLBOX) + find_package(Matlab COMPONENTS MEX_COMPILER REQUIRED) + if(NOT Matlab_MEX_COMPILER) + message(FATAL_ERROR "Cannot find MEX compiler binary. Please check your Matlab installation and ensure MEX in installed as well.") + endif() + + if(GTSAM_BUILD_TYPE_POSTFIXES) + set(CURRENT_POSTFIX ${CMAKE_${CMAKE_BUILD_TYPE_UPPER}_POSTFIX}) + endif() + + if(NOT BUILD_SHARED_LIBS) + message(FATAL_ERROR "GTSAM_INSTALL_MATLAB_TOOLBOX and BUILD_SHARED_LIBS=OFF. The MATLAB wrapper cannot be compiled with a static GTSAM library because mex modules are themselves shared libraries. If you want a self-contained mex module, enable GTSAM_MEX_BUILD_STATIC_MODULE instead of BUILD_SHARED_LIBS=OFF.") + endif() +endif() + # Set up cache options option(GTSAM_MEX_BUILD_STATIC_MODULE "Build MATLAB wrapper statically (increases build time)" OFF) set(GTSAM_BUILD_MEX_BINARY_FLAGS "" CACHE STRING "Extra flags for running Matlab MEX compilation") set(GTSAM_TOOLBOX_INSTALL_PATH "" CACHE PATH "Matlab toolbox destination, blank defaults to CMAKE_INSTALL_PREFIX/gtsam_toolbox") if(NOT GTSAM_TOOLBOX_INSTALL_PATH) - set(GTSAM_TOOLBOX_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}/gtsam_toolbox") + set(GTSAM_TOOLBOX_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}/gtsam_toolbox") endif() # GTSAM_MEX_BUILD_STATIC_MODULE is not for Windows - on Windows any static # are already compiled into the library by the linker if(GTSAM_MEX_BUILD_STATIC_MODULE AND WIN32) - message(FATAL_ERROR "GTSAM_MEX_BUILD_STATIC_MODULE should not be set on Windows - the linker already automatically compiles in any dependent static libraries. To create a standalone toolbox pacakge, simply ensure that CMake finds the static versions of all dependent libraries (Boost, etc).") + message(FATAL_ERROR "GTSAM_MEX_BUILD_STATIC_MODULE should not be set on Windows - the linker already automatically compiles in any dependent static libraries. To create a standalone toolbox pacakge, simply ensure that CMake finds the static versions of all dependent libraries (Boost, etc).") endif() -# Try to automatically configure mex path -if(APPLE) - file(GLOB matlab_bin_directories "/Applications/MATLAB*/bin") - set(mex_program_name "mex") -elseif(WIN32) - file(GLOB matlab_bin_directories "C:/Program Files*/MATLAB/*/bin") - set(mex_program_name "mex.bat") -else() - file(GLOB matlab_bin_directories "/usr/local/MATLAB/*/bin") - set(mex_program_name "mex") -endif() +set(MEX_COMMAND ${Matlab_MEX_COMPILER} CACHE PATH "Path to MATLAB MEX compiler") +set(MATLAB_ROOT ${Matlab_ROOT_DIR} CACHE PATH "Path to MATLAB installation root (e.g. /usr/local/MATLAB/R2012a)") +# Try to automatically configure mex path from provided custom `bin` path. if(GTSAM_CUSTOM_MATLAB_PATH) - set(matlab_bin_directories ${GTSAM_CUSTOM_MATLAB_PATH}) -endif() + set(matlab_bin_directory ${GTSAM_CUSTOM_MATLAB_PATH}) -# Run find_program explicitly putting $PATH after our predefined program -# directories using 'ENV PATH' and 'NO_SYSTEM_ENVIRONMENT_PATH' - this prevents -# finding the LaTeX mex program (totally unrelated to MATLAB Mex) when LaTeX is -# on the system path. -list(REVERSE matlab_bin_directories) # Reverse list so the highest version (sorted alphabetically) is preferred -find_program(MEX_COMMAND ${mex_program_name} - PATHS ${matlab_bin_directories} ENV PATH - NO_DEFAULT_PATH) -mark_as_advanced(FORCE MEX_COMMAND) -# Now that we have mex, trace back to find the Matlab installation root -get_filename_component(MEX_COMMAND "${MEX_COMMAND}" REALPATH) -get_filename_component(mex_path "${MEX_COMMAND}" PATH) -if(mex_path MATCHES ".*/win64$") - get_filename_component(MATLAB_ROOT "${mex_path}/../.." ABSOLUTE) -else() - get_filename_component(MATLAB_ROOT "${mex_path}/.." ABSOLUTE) + if(WIN32) + set(mex_program_name "mex.bat") + else() + set(mex_program_name "mex") + endif() + + # Run find_program explicitly putting $PATH after our predefined program + # directories using 'ENV PATH' and 'NO_SYSTEM_ENVIRONMENT_PATH' - this prevents + # finding the LaTeX mex program (totally unrelated to MATLAB Mex) when LaTeX is + # on the system path. + find_program(MEX_COMMAND ${mex_program_name} + PATHS ${matlab_bin_directory} ENV PATH + NO_DEFAULT_PATH) + + mark_as_advanced(FORCE MEX_COMMAND) + # Now that we have mex, trace back to find the Matlab installation root + get_filename_component(MEX_COMMAND "${MEX_COMMAND}" REALPATH) + get_filename_component(mex_path "${MEX_COMMAND}" PATH) + if(mex_path MATCHES ".*/win64$") + get_filename_component(MATLAB_ROOT "${mex_path}/../.." ABSOLUTE) + else() + get_filename_component(MATLAB_ROOT "${mex_path}/.." ABSOLUTE) + endif() endif() -set(MATLAB_ROOT "${MATLAB_ROOT}" CACHE PATH "Path to MATLAB installation root (e.g. /usr/local/MATLAB/R2012a)") # User-friendly wrapping function. Builds a mex module from the provided diff --git a/cmake/HandleGeneralOptions.cmake b/cmake/HandleGeneralOptions.cmake index 469d4bba6..ee86066a2 100644 --- a/cmake/HandleGeneralOptions.cmake +++ b/cmake/HandleGeneralOptions.cmake @@ -43,19 +43,3 @@ endif() # Set the default Python version. This is later updated in HandlePython.cmake. set(GTSAM_PYTHON_VERSION "Default" CACHE STRING "The version of Python to build the wrappers against.") - -# Check / set dependent variables for MATLAB wrapper -if(GTSAM_INSTALL_MATLAB_TOOLBOX) - find_package(Matlab COMPONENTS MEX_COMPILER REQUIRED) - if(NOT Matlab_MEX_COMPILER) - message(FATAL_ERROR "Cannot find MEX compiler binary. Please check your Matlab installation and ensure MEX in installed as well.") - endif() - - if(GTSAM_BUILD_TYPE_POSTFIXES) - set(CURRENT_POSTFIX ${CMAKE_${CMAKE_BUILD_TYPE_UPPER}_POSTFIX}) - endif() - - if(NOT BUILD_SHARED_LIBS) - message(FATAL_ERROR "GTSAM_INSTALL_MATLAB_TOOLBOX and BUILD_SHARED_LIBS=OFF. The MATLAB wrapper cannot be compiled with a static GTSAM library because mex modules are themselves shared libraries. If you want a self-contained mex module, enable GTSAM_MEX_BUILD_STATIC_MODULE instead of BUILD_SHARED_LIBS=OFF.") - endif() -endif() From 0737a4594a1c2a5eb814b6da060ffcab8749d1f6 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 19 Nov 2020 07:44:42 -0500 Subject: [PATCH 049/261] better flag name and docs --- gtsam/base/Vector.cpp | 4 ++-- gtsam/base/Vector.h | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/gtsam/base/Vector.cpp b/gtsam/base/Vector.cpp index d2f3ae868..658ab9a0d 100644 --- a/gtsam/base/Vector.cpp +++ b/gtsam/base/Vector.cpp @@ -39,7 +39,7 @@ namespace gtsam { * 1. https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ * 2. https://floating-point-gui.de/errors/comparison/ * ************************************************************************* */ -bool fpEqual(double a, double b, double tol, bool check_relative) { +bool fpEqual(double a, double b, double tol, bool check_relative_also) { using std::abs; using std::isnan; using std::isinf; @@ -68,7 +68,7 @@ bool fpEqual(double a, double b, double tol, bool check_relative) { // Check for relative error else if (abs(a - b) <= tol * min(larger, std::numeric_limits::max()) && - check_relative) { + check_relative_also) { return true; } diff --git a/gtsam/base/Vector.h b/gtsam/base/Vector.h index 49b7e6d9d..ed90a7126 100644 --- a/gtsam/base/Vector.h +++ b/gtsam/base/Vector.h @@ -85,13 +85,15 @@ static_assert( * respectively for the comparison to be true. * If one is NaN/Inf and the other is not, returns false. * - * The `check_relative` flag toggles checking for relative error as well. By - * default, the flag is true. + * @param check_relative_also is a flag which toggles additional checking for + * relative error. This means that if either the absolute error or the relative + * error is within the tolerance, the result will be true. + * By default, the flag is true. * * Return true if two numbers are close wrt tol. */ GTSAM_EXPORT bool fpEqual(double a, double b, double tol, - bool check_relative = true); + bool check_relative_also = true); /** * print without optional string, must specify cout yourself From 9e2007562a8448065224a30c72240ea4aea1b643 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 19 Nov 2020 08:04:30 -0500 Subject: [PATCH 050/261] only upload release builds --- .github/workflows/build-linux.yml | 1 + .github/workflows/build-macos.yml | 1 + .github/workflows/build-windows.yml | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index cd4933cd9..940e34b82 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -85,6 +85,7 @@ jobs: bash .github/scripts/unix.sh -t - name: Upload build directory uses: actions/upload-artifact@v2 + if: ${{ matrix.build_type }} == "Release" with: name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 5e6f8ca04..cccfd7b5b 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -53,6 +53,7 @@ jobs: bash .github/scripts/unix.sh -t - name: Upload build directory uses: actions/upload-artifact@v2 + if: ${{ matrix.build_type }} == "Release" with: name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 63c276020..a14d7de5e 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -78,6 +78,7 @@ jobs: cmake --build build --config ${{ matrix.build_type }} --target check.linear - name: Upload build directory uses: actions/upload-artifact@v2 + if: ${{ matrix.build_type }} == "Release" with: name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ From 802580eec79d5c39995af170e40a7c0ba1eb54e6 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 19 Nov 2020 12:40:38 -0500 Subject: [PATCH 051/261] enforce constant term in quadratic to be 0 --- gtsam_unstable/linear/QPSParser.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/gtsam_unstable/linear/QPSParser.cpp b/gtsam_unstable/linear/QPSParser.cpp index 3039185f2..df21c0132 100644 --- a/gtsam_unstable/linear/QPSParser.cpp +++ b/gtsam_unstable/linear/QPSParser.cpp @@ -81,7 +81,7 @@ class QPSVisitor { varname_to_key; // Variable QPS string name to key std::unordered_map> H; // H from hessian - double f; // Constant term of quadratic cost + double f = 0; // Constant term of quadratic cost std::string obj_name; // the objective function has a name in the QPS std::string name_; // the quadratic program has a name in the QPS std::unordered_map @@ -175,10 +175,11 @@ class QPSVisitor { string var_ = fromChars<1>(vars); string row_ = fromChars<3>(vars); double coefficient = at_c<5>(vars); - if (row_ == obj_name) + if (row_ == obj_name) { f = -coefficient; - else + } else { b[row_] = coefficient; + } if (debug) { cout << "Added RHS for Var: " << var_ << " Row: " << row_ @@ -194,15 +195,17 @@ class QPSVisitor { string row2_ = fromChars<7>(vars); double coefficient1 = at_c<5>(vars); double coefficient2 = at_c<9>(vars); - if (row1_ == obj_name) + if (row1_ == obj_name) { f = -coefficient1; - else + } else { b[row1_] = coefficient1; + } - if (row2_ == obj_name) + if (row2_ == obj_name) { f = -coefficient2; - else + } else { b[row2_] = coefficient2; + } if (debug) { cout << "Added RHS for Var: " << var_ << " Row: " << row1_ From 32070b013fbdf3ff245ae82803ac41d4e18b8dbd Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 19 Nov 2020 13:42:52 -0500 Subject: [PATCH 052/261] Make Values::at return as const --- gtsam/nonlinear/Values-inl.h | 15 +++++++-------- gtsam/nonlinear/Values.h | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/gtsam/nonlinear/Values-inl.h b/gtsam/nonlinear/Values-inl.h index d0f8a4790..6829e859b 100644 --- a/gtsam/nonlinear/Values-inl.h +++ b/gtsam/nonlinear/Values-inl.h @@ -338,19 +338,18 @@ namespace gtsam { } // internal /* ************************************************************************* */ - template - ValueType Values::at(Key j) const { + template + const ValueType Values::at(Key j) const { // Find the item KeyValueMap::const_iterator item = values_.find(j); // Throw exception if it does not exist - if(item == values_.end()) - throw ValuesKeyDoesNotExist("at", j); + if (item == values_.end()) throw ValuesKeyDoesNotExist("at", j); - // Check the type and throw exception if incorrect - // h() split in two lines to avoid internal compiler error (MSVC2017) - auto h = internal::handle(); - return h(j,item->second); + // Check the type and throw exception if incorrect + // h() split in two lines to avoid internal compiler error (MSVC2017) + auto h = internal::handle(); + return h(j, item->second); } /* ************************************************************************* */ diff --git a/gtsam/nonlinear/Values.h b/gtsam/nonlinear/Values.h index b49188b68..120c8839c 100644 --- a/gtsam/nonlinear/Values.h +++ b/gtsam/nonlinear/Values.h @@ -187,8 +187,8 @@ namespace gtsam { * Dynamic matrices/vectors can be retrieved as fixed-size, but not vice-versa. * @return The stored value */ - template - ValueType at(Key j) const; + template + const ValueType at(Key j) const; /// version for double double atDouble(size_t key) const { return at(key);} From 99e3a111e1d7d0d16cc05e8b12fed6390bbbdf28 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 19 Nov 2020 14:58:50 -0500 Subject: [PATCH 053/261] correct conditional syntax --- .github/workflows/build-linux.yml | 2 +- .github/workflows/build-macos.yml | 2 +- .github/workflows/build-windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 940e34b82..4039711f2 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -85,7 +85,7 @@ jobs: bash .github/scripts/unix.sh -t - name: Upload build directory uses: actions/upload-artifact@v2 - if: ${{ matrix.build_type }} == "Release" + if: ${{ matrix.build_type == "Release" }} with: name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index cccfd7b5b..1d36e048f 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -53,7 +53,7 @@ jobs: bash .github/scripts/unix.sh -t - name: Upload build directory uses: actions/upload-artifact@v2 - if: ${{ matrix.build_type }} == "Release" + if: ${{ matrix.build_type == "Release" }} with: name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index a14d7de5e..8e469d49f 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -78,7 +78,7 @@ jobs: cmake --build build --config ${{ matrix.build_type }} --target check.linear - name: Upload build directory uses: actions/upload-artifact@v2 - if: ${{ matrix.build_type }} == "Release" + if: ${{ matrix.build_type == "Release" }} with: name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ From 5749565e526f932941db53bec1f0a742ec35e005 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 19 Nov 2020 15:28:48 -0500 Subject: [PATCH 054/261] FIx indentation for Values-inl.h --- gtsam/nonlinear/Values-inl.h | 161 ++++++++++++++++++----------------- 1 file changed, 81 insertions(+), 80 deletions(-) diff --git a/gtsam/nonlinear/Values-inl.h b/gtsam/nonlinear/Values-inl.h index 6829e859b..ba4ed54d3 100644 --- a/gtsam/nonlinear/Values-inl.h +++ b/gtsam/nonlinear/Values-inl.h @@ -259,97 +259,98 @@ namespace gtsam { } /* ************************************************************************* */ - template<> - inline bool Values::filterHelper(const boost::function filter, - const ConstKeyValuePair& key_value) { - // Filter and check the type - return filter(key_value.key); - } + template<> + inline bool Values::filterHelper(const boost::function filter, + const ConstKeyValuePair& key_value) { + // Filter and check the type + return filter(key_value.key); + } - /* ************************************************************************* */ + /* ************************************************************************* */ - namespace internal { + namespace internal { - // Check the type and throw exception if incorrect - // Generic version, partially specialized below for various Eigen Matrix types - template - struct handle { - ValueType operator()(Key j, const Value* const pointer) { - try { - // value returns a const ValueType&, and the return makes a copy !!!!! - return dynamic_cast&>(*pointer).value(); - } catch (std::bad_cast&) { - throw ValuesIncorrectType(j, typeid(*pointer), typeid(ValueType)); - } - } - }; + // Check the type and throw exception if incorrect + // Generic version, partially specialized below for various Eigen Matrix types + template + struct handle { + ValueType operator()(Key j, const Value* const pointer) { + try { + // value returns a const ValueType&, and the return makes a copy !!!!! + return dynamic_cast&>(*pointer).value(); + } catch (std::bad_cast&) { + throw ValuesIncorrectType(j, typeid(*pointer), typeid(ValueType)); + } + } + }; - template - struct handle_matrix; + template + struct handle_matrix; - // Handle dynamic matrices - template - struct handle_matrix, true> { - Eigen::Matrix operator()(Key j, const Value* const pointer) { - try { - // value returns a const Matrix&, and the return makes a copy !!!!! - return dynamic_cast>&>(*pointer).value(); - } catch (std::bad_cast&) { - // If a fixed matrix was stored, we end up here as well. - throw ValuesIncorrectType(j, typeid(*pointer), typeid(Eigen::Matrix)); - } - } - }; + // Handle dynamic matrices + template + struct handle_matrix, true> { + Eigen::Matrix operator()(Key j, const Value* const pointer) { + try { + // value returns a const Matrix&, and the return makes a copy !!!!! + return dynamic_cast>&>(*pointer).value(); + } catch (std::bad_cast&) { + // If a fixed matrix was stored, we end up here as well. + throw ValuesIncorrectType(j, typeid(*pointer), typeid(Eigen::Matrix)); + } + } + }; - // Handle fixed matrices - template - struct handle_matrix, false> { - Eigen::Matrix operator()(Key j, const Value* const pointer) { - try { - // value returns a const MatrixMN&, and the return makes a copy !!!!! - return dynamic_cast>&>(*pointer).value(); - } catch (std::bad_cast&) { - Matrix A; - try { - // Check if a dynamic matrix was stored - A = handle_matrix()(j, pointer); // will throw if not.... - } catch (const ValuesIncorrectType&) { - // Or a dynamic vector - A = handle_matrix()(j, pointer); // will throw if not.... - } - // Yes: check size, and throw if not a match - if (A.rows() != M || A.cols() != N) - throw NoMatchFoundForFixed(M, N, A.rows(), A.cols()); - else - return A; // copy but not malloc - } - } - }; + // Handle fixed matrices + template + struct handle_matrix, false> { + Eigen::Matrix operator()(Key j, const Value* const pointer) { + try { + // value returns a const MatrixMN&, and the return makes a copy !!!!! + return dynamic_cast>&>(*pointer).value(); + } catch (std::bad_cast&) { + Matrix A; + try { + // Check if a dynamic matrix was stored + A = handle_matrix()(j, pointer); // will throw if not.... + } catch (const ValuesIncorrectType&) { + // Or a dynamic vector + A = handle_matrix()(j, pointer); // will throw if not.... + } + // Yes: check size, and throw if not a match + if (A.rows() != M || A.cols() != N) + throw NoMatchFoundForFixed(M, N, A.rows(), A.cols()); + else + return A; // copy but not malloc + } + } + }; - // Handle matrices - template - struct handle> { - Eigen::Matrix operator()(Key j, const Value* const pointer) { - return handle_matrix, - (M == Eigen::Dynamic || N == Eigen::Dynamic)>()(j, pointer); - } - }; + // Handle matrices + template + struct handle> { + Eigen::Matrix operator()(Key j, const Value* const pointer) { + return handle_matrix, + (M == Eigen::Dynamic || N == Eigen::Dynamic)>()(j, pointer); + } + }; - } // internal + } // internal - /* ************************************************************************* */ - template - const ValueType Values::at(Key j) const { - // Find the item - KeyValueMap::const_iterator item = values_.find(j); + /* ************************************************************************* + */ + template + const ValueType Values::at(Key j) const { + // Find the item + KeyValueMap::const_iterator item = values_.find(j); - // Throw exception if it does not exist - if (item == values_.end()) throw ValuesKeyDoesNotExist("at", j); + // Throw exception if it does not exist + if (item == values_.end()) throw ValuesKeyDoesNotExist("at", j); - // Check the type and throw exception if incorrect - // h() split in two lines to avoid internal compiler error (MSVC2017) - auto h = internal::handle(); - return h(j, item->second); + // Check the type and throw exception if incorrect + // h() split in two lines to avoid internal compiler error (MSVC2017) + auto h = internal::handle(); + return h(j, item->second); } /* ************************************************************************* */ From c206ed9c2fcfff0802951ae7cabea5c8ba7ecd5e Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 19 Nov 2020 15:35:09 -0500 Subject: [PATCH 055/261] syntax update --- .github/workflows/build-linux.yml | 2 +- .github/workflows/build-macos.yml | 2 +- .github/workflows/build-windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 4039711f2..32c3bd8aa 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -85,7 +85,7 @@ jobs: bash .github/scripts/unix.sh -t - name: Upload build directory uses: actions/upload-artifact@v2 - if: ${{ matrix.build_type == "Release" }} + if: matrix.build_type == 'Release' with: name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index 1d36e048f..cf1a474e3 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -53,7 +53,7 @@ jobs: bash .github/scripts/unix.sh -t - name: Upload build directory uses: actions/upload-artifact@v2 - if: ${{ matrix.build_type == "Release" }} + if: matrix.build_type == 'Release' with: name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 8e469d49f..7eb908c94 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -78,7 +78,7 @@ jobs: cmake --build build --config ${{ matrix.build_type }} --target check.linear - name: Upload build directory uses: actions/upload-artifact@v2 - if: ${{ matrix.build_type == "Release" }} + if: matrix.build_type == 'Release' with: name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} path: ${{ github.workspace }}/build/ From 122edc1da42471cda8e14a833680f7e568520495 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Tue, 24 Nov 2020 11:57:07 -0500 Subject: [PATCH 056/261] Added test for subgraph preconditioner in shonan --- gtsam/sfm/tests/testShonanAveraging.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gtsam/sfm/tests/testShonanAveraging.cpp b/gtsam/sfm/tests/testShonanAveraging.cpp index 1200c8ebb..cf35a42cf 100644 --- a/gtsam/sfm/tests/testShonanAveraging.cpp +++ b/gtsam/sfm/tests/testShonanAveraging.cpp @@ -91,6 +91,24 @@ TEST(ShonanAveraging3, checkOptimality) { EXPECT(!kShonan.checkOptimality(random)); } +/* ************************************************************************* */ +TEST(ShonanAveraging3, checkSubgraph) { + // Create parameter with solver set to SUBGRAPH + auto params = ShonanAveragingParameters3( + gtsam::LevenbergMarquardtParams::CeresDefaults(), "SUBGRAPH"); + ShonanAveraging3::Measurements measurements; + + auto subgraphShonan = fromExampleName("toyExample.g2o", params); + + // Create initial random estimation + Values initial; + initial = subgraphShonan.initializeRandomly(kRandomNumberGenerator); + + // Run Shonan with SUBGRAPH solver + auto result = subgraphShonan.run(initial, 3, 3); + EXPECT_DOUBLES_EQUAL(1e-11, subgraphShonan.cost(result.first), 1e-4); +} + /* ************************************************************************* */ TEST(ShonanAveraging3, tryOptimizingAt3) { const Values randomRotations = kShonan.initializeRandomly(kRandomNumberGenerator); From b5a091998266e619ad6d99c56bbcc2e3ae26bbb6 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Tue, 24 Nov 2020 11:57:24 -0500 Subject: [PATCH 057/261] Refined error message in subgraphbuilder --- gtsam/linear/SubgraphBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/linear/SubgraphBuilder.cpp b/gtsam/linear/SubgraphBuilder.cpp index c6b3ca15f..738c101db 100644 --- a/gtsam/linear/SubgraphBuilder.cpp +++ b/gtsam/linear/SubgraphBuilder.cpp @@ -383,7 +383,7 @@ Subgraph SubgraphBuilder::operator()(const GaussianFactorGraph &gfg) const { const vector tree = buildTree(gfg, forward_ordering, weights); if (tree.size() != n - 1) { throw std::runtime_error( - "SubgraphBuilder::operator() failure: tree.size() != n-1"); + "SubgraphBuilder::operator() failure: tree.size() != n-1, might caused by disconnected graph"); } // Downweight the tree edges to zero. From 7e29944f95c6afb4f9043b8c912add0f558b8852 Mon Sep 17 00:00:00 2001 From: Frank dellaert Date: Wed, 25 Nov 2020 11:02:01 -0500 Subject: [PATCH 058/261] Initial design --- tests/testGncOptimizer.cpp | 115 +++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 tests/testGncOptimizer.cpp diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp new file mode 100644 index 000000000..d9ba209c5 --- /dev/null +++ b/tests/testGncOptimizer.cpp @@ -0,0 +1,115 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file testGncOptimizer.cpp + * @brief Unit tests for GncOptimizer class + * @author Jignnan Shi + * @author Luca Carlone + * @author Frank Dellaert + */ + +#include +#include +#include + +/* ************************************************************************* */ +template +class GncParams { + using BaseOptimizer = BaseOptimizerParameters::OptimizerType; + GncParams(const BaseOptimizerParameters& baseOptimizerParams) + : baseOptimizerParams(baseOptimizerParams) {} + + BaseOptimizerParameters baseOptimizerParams; + + /// any other specific GNC parameters: +}; + +/* ************************************************************************* */ +template +class GncOptimizer { + public: + // types etc + + private: + FG INITIAL GncParameters params_; + + public: + GncOptimizer(FG, INITIAL, const GncParameters& params) : params(params) { + // Check that all noise models are Gaussian + } + + Values optimize() const { + NonlinearFactorGraph currentGraph = graph_; + for (i : {1, 2, 3}) { + BaseOptimizer::Optimizer baseOptimizer(currentGraph, initial); + VALUES currentSolution = baseOptimizer.optimize(); + if (converged) { + return currentSolution; + } + graph_i = this->makeGraph(currentSolution); + } + } + + NonlinearFactorGraph makeGraph(const Values& currentSolution) const { + // calculate some weights + this->calculateWeights(); + // copy the graph with new weights + + } +}; + +/* ************************************************************************* */ +TEST(GncOptimizer, calculateWeights) { +} + +/* ************************************************************************* */ +TEST(GncOptimizer, copyGraph) { +} + +/* ************************************************************************* */ +TEST(GncOptimizer, makeGraph) { + // has to have Gaussian noise models ! + auto fg = example::createReallyNonlinearFactorGraph(); + + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + auto gnc = GncOptimizer(fg, initial, gncParams); + + NonlinearFactorGraph actual = gnc.makeGraph(initial); +} + +/* ************************************************************************* */ +TEST(GncOptimizer, optimize) { + // has to have Gaussian noise models ! + auto fg = example::createReallyNonlinearFactorGraph(); + + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + auto gnc = GncOptimizer(fg, initial, gncParams); + Values actual = gnc.optimize(); + DOUBLES_EQUAL(0, fg.error(actual2), tol); +} + +/* ************************************************************************* */ +int main() { + TestResult tr; + return TestRegistry::runAllTests(tr); +} +/* ************************************************************************* */ From b5d06b58786b066987d6e51c8aeffb3036a29c78 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Wed, 25 Nov 2020 20:11:04 -0500 Subject: [PATCH 059/261] starting to create test and code for gncParams --- tests/testGncOptimizer.cpp | 105 ++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 48 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index d9ba209c5..878808505 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -12,7 +12,7 @@ /** * @file testGncOptimizer.cpp * @brief Unit tests for GncOptimizer class - * @author Jignnan Shi + * @author Jingnan Shi * @author Luca Carlone * @author Frank Dellaert */ @@ -21,12 +21,21 @@ #include #include +#include + +using namespace std; +using namespace gtsam; + +using symbol_shorthand::X; +using symbol_shorthand::L; + /* ************************************************************************* */ template class GncParams { - using BaseOptimizer = BaseOptimizerParameters::OptimizerType; - GncParams(const BaseOptimizerParameters& baseOptimizerParams) - : baseOptimizerParams(baseOptimizerParams) {} +public: + + // using BaseOptimizer = BaseOptimizerParameters::OptimizerType; + GncParams(const BaseOptimizerParameters& baseOptimizerParams): baseOptimizerParams(baseOptimizerParams) {} BaseOptimizerParameters baseOptimizerParams; @@ -34,64 +43,64 @@ class GncParams { }; /* ************************************************************************* */ -template -class GncOptimizer { - public: - // types etc +//template +//class GncOptimizer { +// public: +// // types etc +// +// private: +// FG INITIAL GncParameters params_; +// +// public: +// GncOptimizer(FG, INITIAL, const GncParameters& params) : params(params) { +// // Check that all noise models are Gaussian +// } +// +// Values optimize() const { +// NonlinearFactorGraph currentGraph = graph_; +// for (i : {1, 2, 3}) { +// BaseOptimizer::Optimizer baseOptimizer(currentGraph, initial); +// VALUES currentSolution = baseOptimizer.optimize(); +// if (converged) { +// return currentSolution; +// } +// graph_i = this->makeGraph(currentSolution); +// } +// } +// +// NonlinearFactorGraph makeGraph(const Values& currentSolution) const { +// // calculate some weights +// this->calculateWeights(); +// // copy the graph with new weights +// +// } +//}; - private: - FG INITIAL GncParameters params_; - - public: - GncOptimizer(FG, INITIAL, const GncParameters& params) : params(params) { - // Check that all noise models are Gaussian - } - - Values optimize() const { - NonlinearFactorGraph currentGraph = graph_; - for (i : {1, 2, 3}) { - BaseOptimizer::Optimizer baseOptimizer(currentGraph, initial); - VALUES currentSolution = baseOptimizer.optimize(); - if (converged) { - return currentSolution; - } - graph_i = this->makeGraph(currentSolution); - } - } - - NonlinearFactorGraph makeGraph(const Values& currentSolution) const { - // calculate some weights - this->calculateWeights(); - // copy the graph with new weights - - } -}; - -/* ************************************************************************* */ -TEST(GncOptimizer, calculateWeights) { -} - -/* ************************************************************************* */ -TEST(GncOptimizer, copyGraph) { -} +///* ************************************************************************* */ +//TEST(GncOptimizer, calculateWeights) { +//} +// +///* ************************************************************************* */ +//TEST(GncOptimizer, copyGraph) { +//} /* ************************************************************************* */ TEST(GncOptimizer, makeGraph) { // has to have Gaussian noise models ! - auto fg = example::createReallyNonlinearFactorGraph(); + auto fg = example::createReallyNonlinearFactorGraph(); // just a unary factor on a 2D point Point2 p0(3, 3); Values initial; initial.insert(X(1), p0); LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); - auto gnc = GncOptimizer(fg, initial, gncParams); + GncParams gncParams(lmParams); +// auto gnc = GncOptimizer(fg, initial, gncParams); - NonlinearFactorGraph actual = gnc.makeGraph(initial); +// NonlinearFactorGraph actual = gnc.makeGraph(initial); } -/* ************************************************************************* */ +/* ************************************************************************* * TEST(GncOptimizer, optimize) { // has to have Gaussian noise models ! auto fg = example::createReallyNonlinearFactorGraph(); From 02e94730a634a56d411ccbaf75bbbcf267bdb9cf Mon Sep 17 00:00:00 2001 From: Sushmita Date: Fri, 27 Nov 2020 00:14:52 -0500 Subject: [PATCH 060/261] vector of cameras and triangulation function wrapped --- gtsam/geometry/triangulation.h | 5 ++ gtsam/gtsam.i | 34 +++++++++- python/CMakeLists.txt | 2 + python/gtsam/preamble.h | 2 + python/gtsam/specializations.h | 2 + python/gtsam/tests/test_Triangulation.py | 83 ++++++++++++++++++++---- 6 files changed, 116 insertions(+), 12 deletions(-) diff --git a/gtsam/geometry/triangulation.h b/gtsam/geometry/triangulation.h index 6f6c645b8..01daab361 100644 --- a/gtsam/geometry/triangulation.h +++ b/gtsam/geometry/triangulation.h @@ -24,6 +24,8 @@ #include #include #include +#include +#include namespace gtsam { @@ -494,5 +496,8 @@ TriangulationResult triangulateSafe(const CameraSet& cameras, } } +typedef CameraSet> CameraSetCal3Bundler; +typedef CameraSet> CameraSetCal3_S2; + } // \namespace gtsam diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 880b1d4c7..47a09648a 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -1108,6 +1108,32 @@ typedef gtsam::PinholeCamera PinholeCameraCal3_S2; //typedef gtsam::PinholeCamera PinholeCameraCal3Unified; typedef gtsam::PinholeCamera PinholeCameraCal3Bundler; +class CameraSetCal3Bundler { + CameraSetCal3Bundler(); + + // common STL methods + size_t size() const; + bool empty() const; + void clear(); + + // structure specific methods + gtsam::PinholeCameraCal3Bundler at(size_t i) const; + void push_back(gtsam::PinholeCameraCal3Bundler& cam) const; +}; + +class CameraSetCal3_S2 { + CameraSetCal3_S2(); + + // common STL methods + size_t size() const; + bool empty() const; + void clear(); + + // structure specific methods + gtsam::PinholeCameraCal3_S2 at(size_t i) const; + void push_back(gtsam::PinholeCameraCal3_S2& cam) const; +}; + #include class StereoCamera { // Standard Constructors and Named Constructors @@ -1149,7 +1175,13 @@ gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, gtsam::Cal3Bundler* sharedCal, const gtsam::Point2Vector& measurements, double rank_tol, bool optimize); - +gtsam::Point3 triangulatePoint3(const gtsam::CameraSetCal3_S2& cameras, + const gtsam::Point2Vector& measurements, double rank_tol, + bool optimize); +gtsam::Point3 triangulatePoint3(const gtsam::CameraSetCal3Bundler& cameras, + const gtsam::Point2Vector& measurements, double rank_tol, + bool optimize); + //************************************************************************* // Symbolic //************************************************************************* diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 00b537340..a318a483b 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -38,6 +38,8 @@ set(ignore gtsam::Pose3Vector gtsam::KeyVector gtsam::BinaryMeasurementsUnit3 + gtsam::CameraSetCal3Bundler + gtsam::CameraSetCal3_S2 gtsam::KeyPairDoubleMap) pybind_wrap(gtsam_py # target diff --git a/python/gtsam/preamble.h b/python/gtsam/preamble.h index 6166f615e..b56766c72 100644 --- a/python/gtsam/preamble.h +++ b/python/gtsam/preamble.h @@ -10,3 +10,5 @@ PYBIND11_MAKE_OPAQUE(std::vector); PYBIND11_MAKE_OPAQUE(std::vector > >); PYBIND11_MAKE_OPAQUE(std::vector > >); PYBIND11_MAKE_OPAQUE(std::vector); +PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); +PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); diff --git a/python/gtsam/specializations.h b/python/gtsam/specializations.h index cacad874c..431697aac 100644 --- a/python/gtsam/specializations.h +++ b/python/gtsam/specializations.h @@ -13,3 +13,5 @@ py::bind_vector > >(m_, "Bina py::bind_map(m_, "IndexPairSetMap"); py::bind_vector(m_, "IndexPairVector"); py::bind_map(m_, "KeyPairDoubleMap"); +py::bind_vector > >(m_, "CameraSetCal3_S2"); +py::bind_vector > >(m_, "CameraSetCal3Bundler"); diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index b43ad9b57..c358152ae 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -15,21 +15,24 @@ import numpy as np import gtsam as g from gtsam.utils.test_case import GtsamTestCase from gtsam import Cal3_S2, Cal3Bundler, Rot3, Pose3, \ - PinholeCameraCal3_S2, Point3, Point2Vector, Pose3Vector, triangulatePoint3 + PinholeCameraCal3_S2, Point3, Point2Vector, Pose3Vector, triangulatePoint3, CameraSetCal3_S2, CameraSetCal3Bundler, PinholeCameraCal3Bundler class TestVisualISAMExample(GtsamTestCase): - def test_TriangulationExample(self): - # Some common constants - sharedCal = Cal3_S2(1500, 1200, 0, 640, 480) - + def setUp(self): + # Set up two camera poses # Looking along X-axis, 1 meter above ground plane (x-y) upright = Rot3.Ypr(-np.pi / 2, 0., -np.pi / 2) - pose1 = Pose3(upright, Point3(0, 0, 1)) - camera1 = PinholeCameraCal3_S2(pose1, sharedCal) + self.pose1 = Pose3(upright, Point3(0, 0, 1)) # create second camera 1 meter to the right of first camera - pose2 = pose1.compose(Pose3(Rot3(), Point3(1, 0, 0))) - camera2 = PinholeCameraCal3_S2(pose2, sharedCal) + self.pose2 = self.pose1.compose(Pose3(Rot3(), Point3(1, 0, 0))) + + + def test_TriangulationExample(self): + # Some common constants + sharedCal = Cal3_S2(1500, 1200, 0, 640, 480) + camera1 = PinholeCameraCal3_S2(self.pose1, sharedCal) + camera2 = PinholeCameraCal3_S2(self.pose2, sharedCal) # landmark ~5 meters infront of camera landmark = Point3(5, 0.5, 1.2) @@ -42,8 +45,8 @@ class TestVisualISAMExample(GtsamTestCase): poses = Pose3Vector() measurements = Point2Vector() - poses.append(pose1) - poses.append(pose2) + poses.append(self.pose1) + poses.append(self.pose2) measurements.append(z1) measurements.append(z2) @@ -76,5 +79,63 @@ class TestVisualISAMExample(GtsamTestCase): # triangulated_landmark = triangulatePoint3(poses,bundlerCal, measurements, rank_tol, optimize) # self.gtsamAssertEquals(landmark, triangulated_landmark,1e-9) + def test_distinct_Ks(self): + K1 = Cal3_S2(1500, 1200, 0, 640, 480) + camera1 = PinholeCameraCal3_S2(self.pose1, K1) + + K2 = Cal3_S2(1600, 1300, 0, 650, 440) + camera2 = PinholeCameraCal3_S2(self.pose2, K2) + + # landmark ~5 meters infront of camera + landmark = Point3(5, 0.5, 1.2) + + # 1. Project two landmarks into two cameras and triangulate + z1 = camera1.project(landmark) + z2 = camera2.project(landmark) + # two cameras + measurements = Point2Vector() + cameras = CameraSetCal3_S2() + + measurements.append(z1) + measurements.append(z2) + cameras.append(camera1) + cameras.append(camera2) + + optimize = True + rank_tol = 1e-9 + + triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol, optimize) + self.gtsamAssertEquals(landmark, triangulated_landmark, 1e-2) + + def test_distinct_Ks_Bundler(self): + K1 = Cal3Bundler(1500, 0, 0, 640, 480) + camera1 = PinholeCameraCal3Bundler(self.pose1, K1) + + K2 = Cal3Bundler(1500, 0, 0, 640, 480) + camera2 = PinholeCameraCal3Bundler(self.pose2, K2) + + # landmark ~5 meters infront of camera + landmark = Point3(5, 0.5, 1.2) + + # 1. Project two landmarks into two cameras and triangulate + z1 = camera1.project(landmark) + z2 = camera2.project(landmark) + # two cameras + measurements = Point2Vector() + cameras = CameraSetCal3Bundler() + + measurements.append(z1) + measurements.append(z2) + cameras.append(camera1) + cameras.append(camera2) + + optimize = True + rank_tol = 1e-9 + + triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol, optimize) + self.gtsamAssertEquals(landmark, triangulated_landmark, 1e-2) + + + if __name__ == "__main__": unittest.main() From ff40590fc3dbf9963730fe4bdceda06d12914d71 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 12:59:27 -0500 Subject: [PATCH 061/261] added equals in NonlinearOptimizerParams --- gtsam/nonlinear/NonlinearOptimizerParams.h | 11 +++++++++++ tests/testNonlinearOptimizer.cpp | 13 +++++++++++++ 2 files changed, 24 insertions(+) diff --git a/gtsam/nonlinear/NonlinearOptimizerParams.h b/gtsam/nonlinear/NonlinearOptimizerParams.h index a7bc10a1f..218230421 100644 --- a/gtsam/nonlinear/NonlinearOptimizerParams.h +++ b/gtsam/nonlinear/NonlinearOptimizerParams.h @@ -113,6 +113,17 @@ public: virtual void print(const std::string& str = "") const; + bool equals(const NonlinearOptimizerParams& other, double tol = 1e-9) const { + return maxIterations == other.getMaxIterations() + && std::abs(relativeErrorTol - other.getRelativeErrorTol()) <= tol + && std::abs(absoluteErrorTol - other.getAbsoluteErrorTol()) <= tol + && std::abs(errorTol - other.getErrorTol()) <= tol + && verbosityTranslator(verbosity) == other.getVerbosity(); + // && orderingType.equals(other.getOrderingType()_; + // && linearSolverType == other.getLinearSolverType(); + // TODO: check ordering, iterativeParams, and iterationsHook + } + inline bool isMultifrontal() const { return (linearSolverType == MULTIFRONTAL_CHOLESKY) || (linearSolverType == MULTIFRONTAL_QR); diff --git a/tests/testNonlinearOptimizer.cpp b/tests/testNonlinearOptimizer.cpp index 6415174d5..295721cc4 100644 --- a/tests/testNonlinearOptimizer.cpp +++ b/tests/testNonlinearOptimizer.cpp @@ -48,6 +48,19 @@ const double tol = 1e-5; using symbol_shorthand::X; using symbol_shorthand::L; +/* ************************************************************************* */ +TEST( NonlinearOptimizer, paramsEquals ) +{ + // default constructors lead to two identical params + GaussNewtonParams gnParams1; + GaussNewtonParams gnParams2; + CHECK(gnParams1.equals(gnParams2)); + + // but the params become different if we change something in gnParams2 + gnParams2.setVerbosity("DELTA"); + CHECK(!gnParams1.equals(gnParams2)); +} + /* ************************************************************************* */ TEST( NonlinearOptimizer, iterateLM ) { From 90dd2c703548cb9c5ab6fcaa69bbde0423262941 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 13:05:54 -0500 Subject: [PATCH 062/261] params parsed correctly --- tests/testGncOptimizer.cpp | 90 ++++++++++++++++++++++++++------------ 1 file changed, 62 insertions(+), 28 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 878808505..1d3057335 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -37,44 +38,51 @@ public: // using BaseOptimizer = BaseOptimizerParameters::OptimizerType; GncParams(const BaseOptimizerParameters& baseOptimizerParams): baseOptimizerParams(baseOptimizerParams) {} + // default constructor + GncParams(): baseOptimizerParams() {} + BaseOptimizerParameters baseOptimizerParams; /// any other specific GNC parameters: }; /* ************************************************************************* */ -//template -//class GncOptimizer { -// public: -// // types etc -// -// private: -// FG INITIAL GncParameters params_; -// -// public: -// GncOptimizer(FG, INITIAL, const GncParameters& params) : params(params) { -// // Check that all noise models are Gaussian -// } -// +template +class GncOptimizer { +public: + // types etc + +private: + NonlinearFactorGraph nfg_; + Values state_; + GncParameters params_; + +public: + GncOptimizer(const NonlinearFactorGraph& graph, + const Values& initialValues, const GncParameters& params = GncParameters()) : + nfg_(graph), state_(initialValues), params_(params) { + // TODO: Check that all noise models are Gaussian + } + // Values optimize() const { // NonlinearFactorGraph currentGraph = graph_; -// for (i : {1, 2, 3}) { -// BaseOptimizer::Optimizer baseOptimizer(currentGraph, initial); -// VALUES currentSolution = baseOptimizer.optimize(); -// if (converged) { -// return currentSolution; -// } -// graph_i = this->makeGraph(currentSolution); +// for (i : {1, 2, 3}) { +// BaseOptimizer::Optimizer baseOptimizer(currentGraph, initial); +// VALUES currentSolution = baseOptimizer.optimize(); +// if (converged) { +// return currentSolution; // } +// graph_i = this->makeGraph(currentSolution); // } +//} + +//NonlinearFactorGraph makeGraph(const Values& currentSolution) const { +// // calculate some weights +// this->calculateWeights(); +// // copy the graph with new weights // -// NonlinearFactorGraph makeGraph(const Values& currentSolution) const { -// // calculate some weights -// this->calculateWeights(); -// // copy the graph with new weights -// -// } -//}; +//} +}; ///* ************************************************************************* */ //TEST(GncOptimizer, calculateWeights) { @@ -84,6 +92,32 @@ public: //TEST(GncOptimizer, copyGraph) { //} +/* ************************************************************************* */ +TEST(GncOptimizer, gncParamsConstructor) { + + //check params are correctly parsed + LevenbergMarquardtParams lmParams; + GncParams gncParams1(lmParams); + CHECK(lmParams.equals(gncParams1.baseOptimizerParams)); + + // check also default constructor + GncParams gncParams1b; + CHECK(lmParams.equals(gncParams1b.baseOptimizerParams)); + + // and check params become different if we change lmParams + lmParams.setVerbosity("DELTA"); + CHECK(!lmParams.equals(gncParams1.baseOptimizerParams)); + + // and same for GN + GaussNewtonParams gnParams; + GncParams gncParams2(gnParams); + CHECK(gnParams.equals(gncParams2.baseOptimizerParams)); + + // check default constructor + GncParams gncParams2b; + CHECK(gnParams.equals(gncParams2b.baseOptimizerParams)); +} + /* ************************************************************************* */ TEST(GncOptimizer, makeGraph) { // has to have Gaussian noise models ! @@ -95,7 +129,7 @@ TEST(GncOptimizer, makeGraph) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); -// auto gnc = GncOptimizer(fg, initial, gncParams); + auto gnc = GncOptimizer>(fg, initial, gncParams); // NonlinearFactorGraph actual = gnc.makeGraph(initial); } From f897fa81a948dcf13e27c002096a44dee40dab14 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 15:14:41 -0500 Subject: [PATCH 063/261] added gnc loop --- tests/testGncOptimizer.cpp | 206 +++++++++++++++++++++++++++++++------ 1 file changed, 174 insertions(+), 32 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 1d3057335..87ac26841 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -29,21 +29,70 @@ using namespace gtsam; using symbol_shorthand::X; using symbol_shorthand::L; +static double tol = 1e-7; /* ************************************************************************* */ template class GncParams { public: - // using BaseOptimizer = BaseOptimizerParameters::OptimizerType; - GncParams(const BaseOptimizerParameters& baseOptimizerParams): baseOptimizerParams(baseOptimizerParams) {} + /** See NonlinearOptimizerParams::verbosity */ + enum RobustLossType { + GM /*Geman McClure*/, TLS /*Truncated least squares*/ + }; + + // using BaseOptimizer = GaussNewtonOptimizer; // BaseOptimizerParameters::OptimizerType; + + GncParams(const BaseOptimizerParameters& baseOptimizerParams): + baseOptimizerParams(baseOptimizerParams), + lossType(GM), /* default loss*/ + maxIterations(100), /* maximum number of iterations*/ + barcSq(1.0), /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ + muStep(1.4){}/* multiplicative factor to reduce/increase the mu in gnc */ // default constructor GncParams(): baseOptimizerParams() {} BaseOptimizerParameters baseOptimizerParams; - /// any other specific GNC parameters: + RobustLossType lossType; + size_t maxIterations; + double barcSq; + double muStep; + + void setLossType(RobustLossType type){ lossType = type; } + void setMaxIterations(size_t maxIter){ + std::cout + << "setMaxIterations: changing the max number of iterations might lead to less accurate solutions and is not recommended! " + << std::endl; + maxIterations = maxIter; + } + void setInlierThreshold(double inth){ barcSq = inth; } + void setMuStep(double step){ muStep = step; } + + /// equals + bool equals(const GncParams& other, double tol = 1e-9) const { + return baseOptimizerParams.equals(other.baseOptimizerParams) + && lossType == other.lossType + && maxIterations == other.maxIterations + && std::fabs(barcSq - other.barcSq) <= tol + && std::fabs(muStep - other.muStep) <= tol; + } + + /// print function + void print(const std::string& str) const { + std::cout << str << "\n"; + switch(lossType) { + case GM: std::cout << "lossType: Geman McClure" << "\n"; break; + default: + throw std::runtime_error( + "GncParams::print: unknown loss type."); + } + std::cout << "maxIterations: " << maxIterations << "\n"; + std::cout << "barcSq: " << barcSq << "\n"; + std::cout << "muStep: " << muStep << "\n"; + baseOptimizerParams.print(str); + } }; /* ************************************************************************* */ @@ -64,33 +113,88 @@ public: // TODO: Check that all noise models are Gaussian } -// Values optimize() const { -// NonlinearFactorGraph currentGraph = graph_; -// for (i : {1, 2, 3}) { -// BaseOptimizer::Optimizer baseOptimizer(currentGraph, initial); -// VALUES currentSolution = baseOptimizer.optimize(); -// if (converged) { -// return currentSolution; -// } -// graph_i = this->makeGraph(currentSolution); -// } -//} + NonlinearFactorGraph getFactors() const { return NonlinearFactorGraph(nfg_); } + Values getState() const { return Values(state_); } + GncParameters getParams() const { return GncParameters(params_); } -//NonlinearFactorGraph makeGraph(const Values& currentSolution) const { -// // calculate some weights -// this->calculateWeights(); -// // copy the graph with new weights -// -//} + /// implement GNC main loop, including graduating nonconvexity with mu + Values optimize() { + // start by assuming all measurements are inliers + Vector weights = Vector::Ones(nfg_.size()); + GaussNewtonOptimizer baseOptimizer(nfg_,state_); + Values result = baseOptimizer.optimize(); + double mu = initializeMu(); + for(size_t iter=0; iter < params_.maxIterations; iter++){ + // weights update + weights = calculateWeights(result, mu); + + // variable/values update + NonlinearFactorGraph graph_iter = this->makeGraph(weights); + GaussNewtonOptimizer baseOptimizer_iter(graph_iter, state_); + Values result = baseOptimizer.optimize(); + + // stopping condition + if( checkMuConvergence(mu) ) { break; } + + // otherwise update mu + mu = updateMu(mu); + } + return result; + } + + /// initialize the gnc parameter mu such that loss is approximately convex + double initializeMu() const { + // compute largest error across all factors + double rmax_sq = 0.0; + for (size_t i = 0; i < nfg_.size(); i++) { + if(nfg_[i]){ + rmax_sq = std::max(rmax_sq, nfg_[i]->error(state_)); + } + } + // set initial mu + switch(params_.lossType) { + case GncParameters::GM: + return 2*rmax_sq / params_.barcSq; // initial mu + default: + throw std::runtime_error( + "GncOptimizer::initializeMu: called with unknown loss type."); + } + } + + /// update the gnc parameter mu to gradually increase nonconvexity + double updateMu(const double mu) const { + switch(params_.lossType) { + case GncParameters::GM: + return std::max(1.0 , mu / params_.muStep); // reduce mu, but saturate at 1 + default: + throw std::runtime_error( + "GncOptimizer::updateMu: called with unknown loss type."); + } + } + + /// check if we have reached the value of mu for which the surrogate loss matches the original loss + bool checkMuConvergence(const double mu) const { + switch(params_.lossType) { + case GncParameters::GM: + return std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function + default: + throw std::runtime_error( + "GncOptimizer::checkMuConvergence: called with unknown loss type."); + } + } + + /// create a graph where each factor is weighted by the gnc weights + NonlinearFactorGraph makeGraph(const Vector& weights) const { + return NonlinearFactorGraph(nfg_); + } + + /// calculate gnc weights + Vector calculateWeights(const Values currentEstimate, const double mu){ + Vector weights = Vector::Ones(nfg_.size()); + return weights; + } }; -///* ************************************************************************* */ -//TEST(GncOptimizer, calculateWeights) { -//} -// -///* ************************************************************************* */ -//TEST(GncOptimizer, copyGraph) { -//} /* ************************************************************************* */ TEST(GncOptimizer, gncParamsConstructor) { @@ -106,7 +210,7 @@ TEST(GncOptimizer, gncParamsConstructor) { // and check params become different if we change lmParams lmParams.setVerbosity("DELTA"); - CHECK(!lmParams.equals(gncParams1.baseOptimizerParams)); + CHECK(! lmParams.equals(gncParams1.baseOptimizerParams)); // and same for GN GaussNewtonParams gnParams; @@ -116,9 +220,44 @@ TEST(GncOptimizer, gncParamsConstructor) { // check default constructor GncParams gncParams2b; CHECK(gnParams.equals(gncParams2b.baseOptimizerParams)); + + // change something at the gncParams level + GncParams gncParams2c(gncParams2b); + gncParams2c.setLossType(GncParams::RobustLossType::TLS); + CHECK(! gncParams2c.equals(gncParams2b.baseOptimizerParams)); } /* ************************************************************************* */ +TEST(GncOptimizer, gncConstructor) { + // has to have Gaussian noise models ! + auto fg = example::createReallyNonlinearFactorGraph(); // just a unary factor on a 2D point + + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + auto gnc = GncOptimizer>(fg, initial, gncParams); + + CHECK(gnc.getFactors().equals(fg)); + CHECK(gnc.getState().equals(initial)); + CHECK(gnc.getParams().equals(gncParams)); +} + +///* ************************************************************************* */ +//TEST(GncOptimizer, calculateWeights) { +//} +// +///* ************************************************************************* */ +//TEST(GncOptimizer, calculateWeights) { +//} +// +///* ************************************************************************* */ +//TEST(GncOptimizer, copyGraph) { +//} + +/* ************************************************************************* * TEST(GncOptimizer, makeGraph) { // has to have Gaussian noise models ! auto fg = example::createReallyNonlinearFactorGraph(); // just a unary factor on a 2D point @@ -134,7 +273,7 @@ TEST(GncOptimizer, makeGraph) { // NonlinearFactorGraph actual = gnc.makeGraph(initial); } -/* ************************************************************************* * +/* ************************************************************************* */ TEST(GncOptimizer, optimize) { // has to have Gaussian noise models ! auto fg = example::createReallyNonlinearFactorGraph(); @@ -144,10 +283,13 @@ TEST(GncOptimizer, optimize) { initial.insert(X(1), p0); LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); - auto gnc = GncOptimizer(fg, initial, gncParams); + GncParams gncParams(lmParams); + auto gnc = GncOptimizer>(fg, initial, gncParams); + + gncParams.print(""); + Values actual = gnc.optimize(); - DOUBLES_EQUAL(0, fg.error(actual2), tol); + DOUBLES_EQUAL(0, fg.error(actual), tol); } /* ************************************************************************* */ From a33c50fcefb42dd85276624b83366d1aedfc0c46 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 15:46:12 -0500 Subject: [PATCH 064/261] now we have very cool tests! --- tests/smallExample.h | 47 ++++++++++++++++++++++++++++++++++++++ tests/testGncOptimizer.cpp | 37 +++++++++++++++++++++++++----- 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/tests/smallExample.h b/tests/smallExample.h index 0c933d106..271fb0581 100644 --- a/tests/smallExample.h +++ b/tests/smallExample.h @@ -363,6 +363,53 @@ inline NonlinearFactorGraph createReallyNonlinearFactorGraph() { return *sharedReallyNonlinearFactorGraph(); } +/* ************************************************************************* */ +inline NonlinearFactorGraph sharedNonRobustFactorGraphWithOutliers() { + using symbol_shorthand::X; + boost::shared_ptr fg(new NonlinearFactorGraph); + Point2 z(0.0, 0.0); + double sigma = 0.1; + boost::shared_ptr factor( + new smallOptimize::UnaryFactor(z, noiseModel::Isotropic::Sigma(2,sigma), X(1))); + // 3 noiseless inliers + fg->push_back(factor); + fg->push_back(factor); + fg->push_back(factor); + + // 1 outlier + Point2 z_out(1.0, 0.0); + boost::shared_ptr factor_out( + new smallOptimize::UnaryFactor(z_out, noiseModel::Isotropic::Sigma(2,sigma), X(1))); + fg->push_back(factor_out); + + return *fg; +} + +/* ************************************************************************* */ +inline NonlinearFactorGraph sharedRobustFactorGraphWithOutliers() { + using symbol_shorthand::X; + boost::shared_ptr fg(new NonlinearFactorGraph); + Point2 z(0.0, 0.0); + double sigma = 0.1; + auto gmNoise = noiseModel::Robust::Create( + noiseModel::mEstimator::GemanMcClure::Create(1.0), noiseModel::Isotropic::Sigma(2,sigma)); + boost::shared_ptr factor( + new smallOptimize::UnaryFactor(z, gmNoise, X(1))); + // 3 noiseless inliers + fg->push_back(factor); + fg->push_back(factor); + fg->push_back(factor); + + // 1 outlier + Point2 z_out(1.0, 0.0); + boost::shared_ptr factor_out( + new smallOptimize::UnaryFactor(z_out, gmNoise, X(1))); + fg->push_back(factor_out); + + return *fg; +} + + /* ************************************************************************* */ inline std::pair createNonlinearSmoother(int T) { using namespace impl; diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 87ac26841..1951e51f1 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -253,9 +253,6 @@ TEST(GncOptimizer, gncConstructor) { //TEST(GncOptimizer, calculateWeights) { //} // -///* ************************************************************************* */ -//TEST(GncOptimizer, copyGraph) { -//} /* ************************************************************************* * TEST(GncOptimizer, makeGraph) { @@ -274,7 +271,7 @@ TEST(GncOptimizer, makeGraph) { } /* ************************************************************************* */ -TEST(GncOptimizer, optimize) { +TEST(GncOptimizer, optimizeSimple) { // has to have Gaussian noise models ! auto fg = example::createReallyNonlinearFactorGraph(); @@ -286,12 +283,40 @@ TEST(GncOptimizer, optimize) { GncParams gncParams(lmParams); auto gnc = GncOptimizer>(fg, initial, gncParams); - gncParams.print(""); - Values actual = gnc.optimize(); DOUBLES_EQUAL(0, fg.error(actual), tol); } +/* ************************************************************************* */ +TEST(GncOptimizer, optimize) { + // has to have Gaussian noise models ! + auto fg = example::sharedNonRobustFactorGraphWithOutliers(); + + Point2 p0(1, 0); + Values initial; + initial.insert(X(1), p0); + + // try with nonrobust cost function and standard GN + GaussNewtonParams gnParams; + GaussNewtonOptimizer gn(fg, initial, gnParams); + Values gn_results = gn.optimize(); + // converges to incorrect point due to lack of robustness to an outlier, ideal solution is Point2(0,0) + CHECK(assert_equal(gn_results.at(X(1)), Point2(1.31812,0.0), 1e-3)); + + // try with robust loss function and standard GN + auto fg_robust = example::sharedRobustFactorGraphWithOutliers(); // same as fg, but with factors wrapped in Geman McClure losses + GaussNewtonOptimizer gn2(fg_robust, initial, gnParams); + Values gn2_results = gn2.optimize(); + // converges to incorrect point, this time due to the nonconvexity of the loss + CHECK(assert_equal(gn2_results.at(X(1)), Point2(1.18712,0.0), 1e-3)); + + // .. but graduated nonconvexity ensures both robustness and convergence in the face of nonconvexity + GncParams gncParams(gnParams); + auto gnc = GncOptimizer>(fg, initial, gncParams); + Values gnc_result = gnc.optimize(); + CHECK(assert_equal(gnc_result.at(X(1)), Point2(0.0,0.0), 1e-3)); +} + /* ************************************************************************* */ int main() { TestResult tr; From 52225998fe64536ce42a514133cb92cc28b6a912 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 16:10:03 -0500 Subject: [PATCH 065/261] 2 tests to go --- tests/testGncOptimizer.cpp | 80 ++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 7 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 1951e51f1..bfea5977a 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -15,6 +15,9 @@ * @author Jingnan Shi * @author Luca Carlone * @author Frank Dellaert + * + * Implementation of the paper: Yang, Antonante, Tzoumas, Carlone, "Graduated Non-Convexity for Robust Spatial Perception: + * From Non-Minimal Solvers to Global Outlier Rejection", RAL, 2020. (arxiv version: https://arxiv.org/pdf/1909.08605.pdf) */ #include @@ -190,12 +193,23 @@ public: /// calculate gnc weights Vector calculateWeights(const Values currentEstimate, const double mu){ - Vector weights = Vector::Ones(nfg_.size()); - return weights; + Vector weights = Vector::Zero(nfg_.size()); + switch(params_.lossType) { + case GncParameters::GM: + for (size_t k = 0; k < nfg_.size(); k++) { + if(nfg_[k]){ + double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual + weights[k] = std::pow( ( mu*mu )/( u2_k + mu*mu ) , 2); + } + } + return weights; + default: + throw std::runtime_error( + "GncOptimizer::calculateWeights: called with unknown loss type."); + } } }; - /* ************************************************************************* */ TEST(GncOptimizer, gncParamsConstructor) { @@ -245,10 +259,62 @@ TEST(GncOptimizer, gncConstructor) { CHECK(gnc.getParams().equals(gncParams)); } -///* ************************************************************************* */ -//TEST(GncOptimizer, calculateWeights) { -//} -// +/* ************************************************************************* */ +TEST(GncOptimizer, initializeMu) { + // has to have Gaussian noise models ! + auto fg = example::createReallyNonlinearFactorGraph(); + + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setLossType(GncParams::RobustLossType::GM); + auto gnc = GncOptimizer>(fg, initial, gncParams); + EXPECT_DOUBLES_EQUAL(gnc.initializeMu(), 2 * 198.999, 1e-3); // according to rmk 5 in the gnc paper: m0 = 2 rmax^2 / barcSq (barcSq=1 in this example) +} + +/* ************************************************************************* */ +TEST(GncOptimizer, updateMu) { + // has to have Gaussian noise models ! + auto fg = example::createReallyNonlinearFactorGraph(); + + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setLossType(GncParams::RobustLossType::GM); + auto gnc = GncOptimizer>(fg, initial, gncParams); + + double mu = 5.0; + EXPECT_DOUBLES_EQUAL(gnc.updateMu(mu), mu / 1.4, tol); + + // check it correctly saturates to 1 for GM + mu = 1.2; + EXPECT_DOUBLES_EQUAL(gnc.updateMu(mu), 1.0, tol); +} + +/* ************************************************************************* */ +TEST(GncOptimizer, checkMuConvergence) { + // has to have Gaussian noise models ! + auto fg = example::createReallyNonlinearFactorGraph(); + + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setLossType(GncParams::RobustLossType::GM); + auto gnc = GncOptimizer>(fg, initial, gncParams); + + double mu = 1.0; + CHECK(gnc.checkMuConvergence(mu)); +} + ///* ************************************************************************* */ //TEST(GncOptimizer, calculateWeights) { //} From 7c22c2c4027fe552831b295955011ddd9d9936e1 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 16:18:36 -0500 Subject: [PATCH 066/261] simplified small test to make it more understandable --- tests/smallExample.h | 17 +++++++++-------- tests/testGncOptimizer.cpp | 6 +++--- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/tests/smallExample.h b/tests/smallExample.h index 271fb0581..70cda1eb0 100644 --- a/tests/smallExample.h +++ b/tests/smallExample.h @@ -369,8 +369,9 @@ inline NonlinearFactorGraph sharedNonRobustFactorGraphWithOutliers() { boost::shared_ptr fg(new NonlinearFactorGraph); Point2 z(0.0, 0.0); double sigma = 0.1; - boost::shared_ptr factor( - new smallOptimize::UnaryFactor(z, noiseModel::Isotropic::Sigma(2,sigma), X(1))); + + boost::shared_ptr> factor( + new PriorFactor(X(1), z, noiseModel::Isotropic::Sigma(2,sigma))); // 3 noiseless inliers fg->push_back(factor); fg->push_back(factor); @@ -378,8 +379,8 @@ inline NonlinearFactorGraph sharedNonRobustFactorGraphWithOutliers() { // 1 outlier Point2 z_out(1.0, 0.0); - boost::shared_ptr factor_out( - new smallOptimize::UnaryFactor(z_out, noiseModel::Isotropic::Sigma(2,sigma), X(1))); + boost::shared_ptr> factor_out( + new PriorFactor(X(1), z_out, noiseModel::Isotropic::Sigma(2,sigma))); fg->push_back(factor_out); return *fg; @@ -393,8 +394,8 @@ inline NonlinearFactorGraph sharedRobustFactorGraphWithOutliers() { double sigma = 0.1; auto gmNoise = noiseModel::Robust::Create( noiseModel::mEstimator::GemanMcClure::Create(1.0), noiseModel::Isotropic::Sigma(2,sigma)); - boost::shared_ptr factor( - new smallOptimize::UnaryFactor(z, gmNoise, X(1))); + boost::shared_ptr> factor( + new PriorFactor(X(1), z, gmNoise)); // 3 noiseless inliers fg->push_back(factor); fg->push_back(factor); @@ -402,8 +403,8 @@ inline NonlinearFactorGraph sharedRobustFactorGraphWithOutliers() { // 1 outlier Point2 z_out(1.0, 0.0); - boost::shared_ptr factor_out( - new smallOptimize::UnaryFactor(z_out, gmNoise, X(1))); + boost::shared_ptr> factor_out( + new PriorFactor(X(1), z_out, gmNoise)); fg->push_back(factor_out); return *fg; diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index bfea5977a..d770f58a8 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -367,20 +367,20 @@ TEST(GncOptimizer, optimize) { GaussNewtonOptimizer gn(fg, initial, gnParams); Values gn_results = gn.optimize(); // converges to incorrect point due to lack of robustness to an outlier, ideal solution is Point2(0,0) - CHECK(assert_equal(gn_results.at(X(1)), Point2(1.31812,0.0), 1e-3)); + CHECK(assert_equal(Point2(0.25,0.0), gn_results.at(X(1)), 1e-3)); // try with robust loss function and standard GN auto fg_robust = example::sharedRobustFactorGraphWithOutliers(); // same as fg, but with factors wrapped in Geman McClure losses GaussNewtonOptimizer gn2(fg_robust, initial, gnParams); Values gn2_results = gn2.optimize(); // converges to incorrect point, this time due to the nonconvexity of the loss - CHECK(assert_equal(gn2_results.at(X(1)), Point2(1.18712,0.0), 1e-3)); + CHECK(assert_equal(Point2(0.999706,0.0), gn2_results.at(X(1)), 1e-3)); // .. but graduated nonconvexity ensures both robustness and convergence in the face of nonconvexity GncParams gncParams(gnParams); auto gnc = GncOptimizer>(fg, initial, gncParams); Values gnc_result = gnc.optimize(); - CHECK(assert_equal(gnc_result.at(X(1)), Point2(0.0,0.0), 1e-3)); + CHECK(assert_equal(Point2(0.0,0.0), gnc_result.at(X(1)), 1e-3)); } /* ************************************************************************* */ From 0f07251cf515c8a06c56b3898933ff719f413fa6 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 16:31:32 -0500 Subject: [PATCH 067/261] 1 test to go --- tests/testGncOptimizer.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index d770f58a8..a31f4b677 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -195,7 +195,7 @@ public: Vector calculateWeights(const Values currentEstimate, const double mu){ Vector weights = Vector::Zero(nfg_.size()); switch(params_.lossType) { - case GncParameters::GM: + case GncParameters::GM: // use eq (12) in GNC paper for (size_t k = 0; k < nfg_.size(); k++) { if(nfg_[k]){ double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual @@ -315,10 +315,29 @@ TEST(GncOptimizer, checkMuConvergence) { CHECK(gnc.checkMuConvergence(mu)); } -///* ************************************************************************* */ -//TEST(GncOptimizer, calculateWeights) { -//} -// +/* ************************************************************************* */ +TEST(GncOptimizer, calculateWeights) { + // has to have Gaussian noise models ! + auto fg = example::sharedNonRobustFactorGraphWithOutliers(); + + Point2 p0(0, 0); + Values initial; + initial.insert(X(1), p0); + + // we have 4 factors, 3 with zero errors (inliers), 1 with error 50 = 0.5 * 1/sigma^2 || [1;0] - [0;0] ||^2 (outlier) + Vector weights_expected = Vector::Zero(4); + weights_expected[0] = 1.0; // zero error + weights_expected[1] = 1.0; // zero error + weights_expected[2] = 1.0; // zero error + weights_expected[3] = std::pow(1.0 / (50.0 + 1.0),2); // outlier, error = 50 + + GaussNewtonParams gnParams; + GncParams gncParams(gnParams); + auto gnc = GncOptimizer>(fg, initial, gncParams); + double mu = 1.0; + Vector weights_actual = gnc.calculateWeights(initial,mu); + CHECK(assert_equal(weights_expected, weights_actual, tol)); +} /* ************************************************************************* * TEST(GncOptimizer, makeGraph) { From e99188095fc017233dd0765beadd498c2e8fb1f5 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 17:14:34 -0500 Subject: [PATCH 068/261] stuck on conversion of noise model --- tests/testGncOptimizer.cpp | 68 +++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index a31f4b677..a2dcafc81 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -113,7 +113,15 @@ public: GncOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, const GncParameters& params = GncParameters()) : nfg_(graph), state_(initialValues), params_(params) { - // TODO: Check that all noise models are Gaussian + + // make sure all noiseModels are Gaussian or convert to Gaussian + for (size_t i = 0; i < nfg_.size(); i++) { + if(nfg_[i]){ + // NonlinearFactor factor = nfg_[i]->clone(); + nfg_[i]-> + + } + } } NonlinearFactorGraph getFactors() const { return NonlinearFactorGraph(nfg_); } @@ -199,7 +207,7 @@ public: for (size_t k = 0; k < nfg_.size(); k++) { if(nfg_[k]){ double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual - weights[k] = std::pow( ( mu*mu )/( u2_k + mu*mu ) , 2); + weights[k] = std::pow( ( mu*params_.barcSq )/( u2_k + mu*params_.barcSq ) , 2); } } return weights; @@ -259,6 +267,25 @@ TEST(GncOptimizer, gncConstructor) { CHECK(gnc.getParams().equals(gncParams)); } +/* ************************************************************************* */ +TEST(GncOptimizer, gncConstructorWithRobustGraphAsInput) { + // simple graph with Gaussian noise model + auto fg = example::createReallyNonlinearFactorGraph(); + // same graph with robust noise model + auto fg_robust = example::sharedRobustFactorGraphWithOutliers(); + + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + auto gnc = GncOptimizer>(fg_robust, initial, gncParams); + + // make sure that when parsing the graph is transformed into one without robust loss + CHECK( fg.equals(gnc.getFactors()) ); +} + /* ************************************************************************* */ TEST(GncOptimizer, initializeMu) { // has to have Gaussian noise models ! @@ -337,22 +364,33 @@ TEST(GncOptimizer, calculateWeights) { double mu = 1.0; Vector weights_actual = gnc.calculateWeights(initial,mu); CHECK(assert_equal(weights_expected, weights_actual, tol)); + + mu = 2.0; + double barcSq = 5.0; + weights_expected[3] = std::pow(mu*barcSq / (50.0 + mu*barcSq),2); // outlier, error = 50 + gncParams.setInlierThreshold(barcSq); + auto gnc2 = GncOptimizer>(fg, initial, gncParams); + weights_actual = gnc2.calculateWeights(initial,mu); + CHECK(assert_equal(weights_expected, weights_actual, tol)); } -/* ************************************************************************* * +/* ************************************************************************* */ TEST(GncOptimizer, makeGraph) { - // has to have Gaussian noise models ! - auto fg = example::createReallyNonlinearFactorGraph(); // just a unary factor on a 2D point - - Point2 p0(3, 3); - Values initial; - initial.insert(X(1), p0); - - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); - auto gnc = GncOptimizer>(fg, initial, gncParams); - -// NonlinearFactorGraph actual = gnc.makeGraph(initial); +// // simple graph with Gaussian noise model +// auto fg = example::createReallyNonlinearFactorGraph(); +// // same graph with robust noise model +// auto fg_robust = example::sharedRobustFactorGraphWithOutliers(); +// +// Point2 p0(3, 3); +// Values initial; +// initial.insert(X(1), p0); +// +// LevenbergMarquardtParams lmParams; +// GncParams gncParams(lmParams); +// auto gnc = GncOptimizer>(fg_robust, initial, gncParams); +// +// // make sure that when parsing the graph is transformed into one without robust loss +// CHECK( fg.equals(gnc.getFactors()) ); } /* ************************************************************************* */ From 5db6894b66d387c051ba593c43c3b013482349d0 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 18:25:38 -0500 Subject: [PATCH 069/261] finally I have a way to properly change the noise model! --- gtsam/nonlinear/NonlinearFactor.cpp | 8 ++++++++ gtsam/nonlinear/NonlinearFactor.h | 6 ++++++ tests/smallExample.h | 15 +++++++++++++++ tests/testNonlinearFactor.cpp | 20 ++++++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/gtsam/nonlinear/NonlinearFactor.cpp b/gtsam/nonlinear/NonlinearFactor.cpp index 1cfcba274..8b8d2da6c 100644 --- a/gtsam/nonlinear/NonlinearFactor.cpp +++ b/gtsam/nonlinear/NonlinearFactor.cpp @@ -76,6 +76,14 @@ bool NoiseModelFactor::equals(const NonlinearFactor& f, double tol) const { && noiseModel_->equals(*e->noiseModel_, tol))); } +/* ************************************************************************* */ +NoiseModelFactor::shared_ptr NoiseModelFactor::cloneWithNewNoiseModel( + const SharedNoiseModel newNoise) const { + NoiseModelFactor::shared_ptr new_factor = boost::dynamic_pointer_cast(clone()); + new_factor->noiseModel_ = newNoise; + return new_factor; +} + /* ************************************************************************* */ static void check(const SharedNoiseModel& noiseModel, size_t m) { if (noiseModel && m != noiseModel->dim()) diff --git a/gtsam/nonlinear/NonlinearFactor.h b/gtsam/nonlinear/NonlinearFactor.h index 80fbfbb11..00311fb87 100644 --- a/gtsam/nonlinear/NonlinearFactor.h +++ b/gtsam/nonlinear/NonlinearFactor.h @@ -244,6 +244,12 @@ public: */ boost::shared_ptr linearize(const Values& x) const override; + /** + * Creates a shared_ptr clone of the + * factor with a new noise model + */ + shared_ptr cloneWithNewNoiseModel(const SharedNoiseModel newNoise) const; + private: /** Serialization function */ friend class boost::serialization::access; diff --git a/tests/smallExample.h b/tests/smallExample.h index 70cda1eb0..944899e70 100644 --- a/tests/smallExample.h +++ b/tests/smallExample.h @@ -342,10 +342,25 @@ struct UnaryFactor: public gtsam::NoiseModelFactor1 { return (h(x) - z_); } + gtsam::NonlinearFactor::shared_ptr clone() const override { + return boost::static_pointer_cast( + gtsam::NonlinearFactor::shared_ptr(new UnaryFactor(*this))); } }; } +/* ************************************************************************* */ +inline NonlinearFactorGraph nonlinearFactorGraphWithGivenSigma(const double sigma) { + using symbol_shorthand::X; + using symbol_shorthand::L; + boost::shared_ptr fg(new NonlinearFactorGraph); + Point2 z(1.0, 0.0); + boost::shared_ptr factor( + new smallOptimize::UnaryFactor(z, noiseModel::Isotropic::Sigma(2,sigma), X(1))); + fg->push_back(factor); + return *fg; +} + /* ************************************************************************* */ inline boost::shared_ptr sharedReallyNonlinearFactorGraph() { using symbol_shorthand::X; diff --git a/tests/testNonlinearFactor.cpp b/tests/testNonlinearFactor.cpp index 662b071df..84bba850b 100644 --- a/tests/testNonlinearFactor.cpp +++ b/tests/testNonlinearFactor.cpp @@ -233,6 +233,26 @@ TEST( NonlinearFactor, linearize_constraint2 ) CHECK(assert_equal((const GaussianFactor&)expected, *actual)); } +/* ************************************************************************* */ +TEST( NonlinearFactor, cloneWithNewNoiseModel ) +{ + // create original factor + double sigma1 = 0.1; + NonlinearFactorGraph nfg = example::nonlinearFactorGraphWithGivenSigma(sigma1); + + // create expected + double sigma2 = 10; + NonlinearFactorGraph expected = example::nonlinearFactorGraphWithGivenSigma(sigma2); + + // create actual + NonlinearFactorGraph actual; + SharedNoiseModel noise2 = noiseModel::Isotropic::Sigma(2,sigma2); + actual.push_back( boost::dynamic_pointer_cast(nfg[0])->cloneWithNewNoiseModel(noise2) ); + + // check it's all good + CHECK(assert_equal(expected, actual)); +} + /* ************************************************************************* */ class TestFactor4 : public NoiseModelFactor4 { public: From 7ce0641b4382c2d97cd8cd181a577bb5f3ad841d Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 18:28:31 -0500 Subject: [PATCH 070/261] working on make graph --- tests/testGncOptimizer.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index a2dcafc81..e80ad7974 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -112,14 +112,18 @@ private: public: GncOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, const GncParameters& params = GncParameters()) : - nfg_(graph), state_(initialValues), params_(params) { + state_(initialValues), params_(params) { // make sure all noiseModels are Gaussian or convert to Gaussian - for (size_t i = 0; i < nfg_.size(); i++) { - if(nfg_[i]){ - // NonlinearFactor factor = nfg_[i]->clone(); - nfg_[i]-> - + for (size_t i = 0; i < graph.size(); i++) { + if(graph[i]){ + auto &factor = boost::dynamic_pointer_cast(nfg_[i]); + auto &robust = boost::dynamic_pointer_cast(factor->noiseModel()); + if(robust){ // if the factor has a robust loss, we have to change it: + nfg_.push_back(factor->cloneWithNewNoiseModel(factor->noiseModel())); + }{ // else we directly push it back + nfg_.push_back(factor); + } } } } From 556fa83e9fbd866259b12b3a2a47def67ae12eb5 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 19:00:08 -0500 Subject: [PATCH 071/261] new constructor test which gets rid of robust loss now passes! --- tests/testGncOptimizer.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index e80ad7974..502eff520 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -115,14 +115,17 @@ public: state_(initialValues), params_(params) { // make sure all noiseModels are Gaussian or convert to Gaussian + nfg_.resize(graph.size()); for (size_t i = 0; i < graph.size(); i++) { if(graph[i]){ - auto &factor = boost::dynamic_pointer_cast(nfg_[i]); - auto &robust = boost::dynamic_pointer_cast(factor->noiseModel()); + NoiseModelFactor::shared_ptr factor = boost::dynamic_pointer_cast(graph[i]); + noiseModel::Robust::shared_ptr robust = boost::dynamic_pointer_cast(factor->noiseModel()); if(robust){ // if the factor has a robust loss, we have to change it: - nfg_.push_back(factor->cloneWithNewNoiseModel(factor->noiseModel())); - }{ // else we directly push it back - nfg_.push_back(factor); + SharedNoiseModel gaussianNoise = robust->noise(); + NoiseModelFactor::shared_ptr gaussianFactor = factor->cloneWithNewNoiseModel(gaussianNoise); + nfg_[i] = gaussianFactor; + } else{ // else we directly push it back + nfg_[i] = factor; } } } @@ -274,7 +277,7 @@ TEST(GncOptimizer, gncConstructor) { /* ************************************************************************* */ TEST(GncOptimizer, gncConstructorWithRobustGraphAsInput) { // simple graph with Gaussian noise model - auto fg = example::createReallyNonlinearFactorGraph(); + auto fg = example::sharedNonRobustFactorGraphWithOutliers(); // same graph with robust noise model auto fg_robust = example::sharedRobustFactorGraphWithOutliers(); @@ -285,7 +288,9 @@ TEST(GncOptimizer, gncConstructorWithRobustGraphAsInput) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); auto gnc = GncOptimizer>(fg_robust, initial, gncParams); - +// fg.print("fg\n"); +// fg_robust.print("fg_robust\n"); +// gnc.getFactors().print("gnc\n"); // make sure that when parsing the graph is transformed into one without robust loss CHECK( fg.equals(gnc.getFactors()) ); } From 9e3263f2b1177d5770a6107ed31ca252bea1405c Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 19:29:42 -0500 Subject: [PATCH 072/261] yay! only the final monster to go! --- tests/testGncOptimizer.cpp | 64 +++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 502eff520..73584882f 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -147,7 +147,7 @@ public: weights = calculateWeights(result, mu); // variable/values update - NonlinearFactorGraph graph_iter = this->makeGraph(weights); + NonlinearFactorGraph graph_iter = this->makeWeightedGraph(weights); GaussNewtonOptimizer baseOptimizer_iter(graph_iter, state_); Values result = baseOptimizer.optimize(); @@ -202,8 +202,25 @@ public: } /// create a graph where each factor is weighted by the gnc weights - NonlinearFactorGraph makeGraph(const Vector& weights) const { - return NonlinearFactorGraph(nfg_); + NonlinearFactorGraph makeWeightedGraph(const Vector& weights) const { + // make sure all noiseModels are Gaussian or convert to Gaussian + NonlinearFactorGraph newGraph; + newGraph.resize(nfg_.size()); + for (size_t i = 0; i < nfg_.size(); i++) { + if(nfg_[i]){ + NoiseModelFactor::shared_ptr factor = boost::dynamic_pointer_cast(nfg_[i]); + noiseModel::Gaussian::shared_ptr noiseModel = boost::dynamic_pointer_cast(factor->noiseModel()); + if(noiseModel){ + Matrix newInfo = weights[i] * noiseModel->information(); + SharedNoiseModel newNoiseModel = noiseModel::Gaussian::Information(newInfo); + newGraph[i] = factor->cloneWithNewNoiseModel(newNoiseModel); + }else{ + throw std::runtime_error( + "GncOptimizer::makeWeightedGraph: unexpected non-Gaussian noise model."); + } + } + } + return newGraph; } /// calculate gnc weights @@ -384,22 +401,31 @@ TEST(GncOptimizer, calculateWeights) { } /* ************************************************************************* */ -TEST(GncOptimizer, makeGraph) { -// // simple graph with Gaussian noise model -// auto fg = example::createReallyNonlinearFactorGraph(); -// // same graph with robust noise model -// auto fg_robust = example::sharedRobustFactorGraphWithOutliers(); -// -// Point2 p0(3, 3); -// Values initial; -// initial.insert(X(1), p0); -// -// LevenbergMarquardtParams lmParams; -// GncParams gncParams(lmParams); -// auto gnc = GncOptimizer>(fg_robust, initial, gncParams); -// -// // make sure that when parsing the graph is transformed into one without robust loss -// CHECK( fg.equals(gnc.getFactors()) ); +TEST(GncOptimizer, makeWeightedGraph) { + // create original factor + double sigma1 = 0.1; + NonlinearFactorGraph nfg = example::nonlinearFactorGraphWithGivenSigma(sigma1); + + // create expected + double sigma2 = 10; + NonlinearFactorGraph expected = example::nonlinearFactorGraphWithGivenSigma(sigma2); + + // create weights + Vector weights = Vector::Ones(1); // original info:1/0.1^2 = 100. New info: 1/10^2 = 0.01. Ratio is 10-4 + weights[0] = 1e-4; + + // create actual + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + auto gnc = GncOptimizer>(nfg, initial, gncParams); + NonlinearFactorGraph actual = gnc.makeWeightedGraph(weights); + + // check it's all good + CHECK(assert_equal(expected, actual)); } /* ************************************************************************* */ From d8fc330be4388e700a8f982b534bcb09c424ac45 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Fri, 27 Nov 2020 19:35:12 -0500 Subject: [PATCH 073/261] Assign pointer to prevent errors --- examples/ImuFactorsExample.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ImuFactorsExample.cpp b/examples/ImuFactorsExample.cpp index a8a9715e0..793927d7e 100644 --- a/examples/ImuFactorsExample.cpp +++ b/examples/ImuFactorsExample.cpp @@ -125,7 +125,7 @@ int main(int argc, char* argv[]) { output_filename = var_map["output_filename"].as(); use_isam = var_map["use_isam"].as(); - ISAM2* isam2; + ISAM2* isam2 = 0; if (use_isam) { printf("Using ISAM2\n"); ISAM2Params parameters; From cb115560ecaf8808c3ccd98a0c31a152ff332d7b Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Fri, 27 Nov 2020 19:36:57 -0500 Subject: [PATCH 074/261] fixes to plot code --- python/gtsam/utils/plot.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/python/gtsam/utils/plot.py b/python/gtsam/utils/plot.py index b2c2ab879..7f48d03a3 100644 --- a/python/gtsam/utils/plot.py +++ b/python/gtsam/utils/plot.py @@ -36,18 +36,15 @@ def set_axes_equal(fignum): ax.set_zlim3d([origin[2] - radius, origin[2] + radius]) -def ellipsoid(xc, yc, zc, rx, ry, rz, n): +def ellipsoid(rx, ry, rz, n): """ Numpy equivalent of Matlab's ellipsoid function. Args: - xc (double): Center of ellipsoid in X-axis. - yc (double): Center of ellipsoid in Y-axis. - zc (double): Center of ellipsoid in Z-axis. rx (double): Radius of ellipsoid in X-axis. ry (double): Radius of ellipsoid in Y-axis. rz (double): Radius of ellipsoid in Z-axis. - n (int): The granularity of the ellipsoid plotted. + n (int): The granularity of the ellipsoid plotted. Returns: tuple[numpy.ndarray]: The points in the x, y and z axes to use for the surface plot. @@ -72,7 +69,8 @@ def plot_covariance_ellipse_3d(axes, origin, P, scale=1, n=8, alpha=0.5): Args: axes (matplotlib.axes.Axes): Matplotlib axes. origin (gtsam.Point3): The origin in the world frame. - P (numpy.ndarray): The marginal covariance matrix of the 3D point which will be represented as an ellipse. + P (numpy.ndarray): The marginal covariance matrix of the 3D point + which will be represented as an ellipse. scale (float): Scaling factor of the radii of the covariance ellipse. n (int): Defines the granularity of the ellipse. Higher values indicate finer ellipses. alpha (float): Transparency value for the plotted surface in the range [0, 1]. @@ -85,7 +83,7 @@ def plot_covariance_ellipse_3d(axes, origin, P, scale=1, n=8, alpha=0.5): rx, ry, rz = radii # generate data for "unrotated" ellipsoid - xc, yc, zc = ellipsoid(0, 0, 0, rx, ry, rz, n) + xc, yc, zc = ellipsoid(rx, ry, rz, n) # rotate data with orientation matrix U and center c data = np.kron(U[:, 0:1], xc) + np.kron(U[:, 1:2], yc) + \ @@ -106,7 +104,8 @@ def plot_pose2_on_axes(axes, pose, axis_length=0.1, covariance=None): axes (matplotlib.axes.Axes): Matplotlib axes. pose (gtsam.Pose2): The pose to be plotted. axis_length (float): The length of the camera axes. - covariance (numpy.ndarray): Marginal covariance matrix to plot the uncertainty of the estimation. + covariance (numpy.ndarray): Marginal covariance matrix to plot + the uncertainty of the estimation. """ # get rotation and translation (center) gRp = pose.rotation().matrix() # rotation from pose to global @@ -146,7 +145,8 @@ def plot_pose2(fignum, pose, axis_length=0.1, covariance=None, fignum (int): Integer representing the figure number to use for plotting. pose (gtsam.Pose2): The pose to be plotted. axis_length (float): The length of the camera axes. - covariance (numpy.ndarray): Marginal covariance matrix to plot the uncertainty of the estimation. + covariance (numpy.ndarray): Marginal covariance matrix to plot + the uncertainty of the estimation. axis_labels (iterable[string]): List of axis labels to set. """ # get figure object @@ -215,7 +215,8 @@ def plot_3d_points(fignum, values, linespec="g*", marginals=None, fignum (int): Integer representing the figure number to use for plotting. values (gtsam.Values): Values dictionary consisting of points to be plotted. linespec (string): String representing formatting options for Matplotlib. - marginals (numpy.ndarray): Marginal covariance matrix to plot the uncertainty of the estimation. + marginals (numpy.ndarray): Marginal covariance matrix to plot the + uncertainty of the estimation. title (string): The title of the plot. axis_labels (iterable[string]): List of axis labels to set. """ @@ -238,6 +239,7 @@ def plot_3d_points(fignum, values, linespec="g*", marginals=None, continue # I guess it's not a Point3 + fig = plt.figure(fignum) fig.suptitle(title) fig.canvas.set_window_title(title.lower()) From 7eea8cd8ba1c84ebe8cbaa18ef6b7d1ab7f5a04a Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Fri, 27 Nov 2020 19:37:18 -0500 Subject: [PATCH 075/261] suppress warnings from clang as well --- gtsam/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/CMakeLists.txt b/gtsam/CMakeLists.txt index 37c4a1f88..e0e037f52 100644 --- a/gtsam/CMakeLists.txt +++ b/gtsam/CMakeLists.txt @@ -199,7 +199,7 @@ if(WIN32) else() if("${CMAKE_BUILD_TYPE}" STREQUAL "Release") # Suppress all warnings from 3rd party sources. - set_source_files_properties(${3rdparty_srcs} PROPERTIES COMPILE_FLAGS "-w") + set_source_files_properties(${3rdparty_srcs} PROPERTIES COMPILE_FLAGS "-w -Wno-everything") else() set_source_files_properties(${3rdparty_srcs} PROPERTIES COMPILE_FLAGS "-Wno-error") endif() From dab00907b9a6aac0802ed44ceb9eee2cd8be13da Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 22:07:16 -0500 Subject: [PATCH 076/261] added verbosity --- tests/testGncOptimizer.cpp | 49 ++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 73584882f..630b0c92b 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -38,8 +38,12 @@ static double tol = 1e-7; template class GncParams { public: + /** Verbosity levels */ + enum VerbosityGNC { + SILENT = 0, SUMMARY, VALUES + }; - /** See NonlinearOptimizerParams::verbosity */ + /** Choice of robust loss function for GNC */ enum RobustLossType { GM /*Geman McClure*/, TLS /*Truncated least squares*/ }; @@ -51,7 +55,8 @@ public: lossType(GM), /* default loss*/ maxIterations(100), /* maximum number of iterations*/ barcSq(1.0), /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ - muStep(1.4){}/* multiplicative factor to reduce/increase the mu in gnc */ + muStep(1.4), /* multiplicative factor to reduce/increase the mu in gnc */ + verbosityGNC(SILENT){}/* verbosity level */ // default constructor GncParams(): baseOptimizerParams() {} @@ -62,16 +67,18 @@ public: size_t maxIterations; double barcSq; double muStep; + VerbosityGNC verbosityGNC; - void setLossType(RobustLossType type){ lossType = type; } - void setMaxIterations(size_t maxIter){ + void setLossType(const RobustLossType type){ lossType = type; } + void setMaxIterations(const size_t maxIter){ std::cout << "setMaxIterations: changing the max number of iterations might lead to less accurate solutions and is not recommended! " << std::endl; maxIterations = maxIter; } - void setInlierThreshold(double inth){ barcSq = inth; } - void setMuStep(double step){ muStep = step; } + void setInlierThreshold(const double inth){ barcSq = inth; } + void setMuStep(const double step){ muStep = step; } + void setVerbosityGNC(const VerbosityGNC verbosity) { verbosityGNC = verbosity; } /// equals bool equals(const GncParams& other, double tol = 1e-9) const { @@ -79,7 +86,8 @@ public: && lossType == other.lossType && maxIterations == other.maxIterations && std::fabs(barcSq - other.barcSq) <= tol - && std::fabs(muStep - other.muStep) <= tol; + && std::fabs(muStep - other.muStep) <= tol + && verbosityGNC == other.verbosityGNC; } /// print function @@ -94,6 +102,7 @@ public: std::cout << "maxIterations: " << maxIterations << "\n"; std::cout << "barcSq: " << barcSq << "\n"; std::cout << "muStep: " << muStep << "\n"; + std::cout << "verbosityGNC: " << verbosityGNC << "\n"; baseOptimizerParams.print(str); } }; @@ -143,16 +152,31 @@ public: Values result = baseOptimizer.optimize(); double mu = initializeMu(); for(size_t iter=0; iter < params_.maxIterations; iter++){ + + // display info + if (params_.verbosityGNC >= GncParameters::VerbosityGNC::VALUES){ + result.print("result\n"); + std::cout << "mu: " << mu << std::endl; + std::cout << "weights: " << weights << std::endl; + } // weights update weights = calculateWeights(result, mu); // variable/values update NonlinearFactorGraph graph_iter = this->makeWeightedGraph(weights); GaussNewtonOptimizer baseOptimizer_iter(graph_iter, state_); - Values result = baseOptimizer.optimize(); + result = baseOptimizer.optimize(); // stopping condition - if( checkMuConvergence(mu) ) { break; } + if( checkMuConvergence(mu) ) { + // display info + if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY){ + std::cout << "final iterations: " << iter << std::endl; + std::cout << "final mu: " << mu << std::endl; + std::cout << "final weights: " << weights << std::endl; + } + break; + } // otherwise update mu mu = updateMu(mu); @@ -160,7 +184,7 @@ public: return result; } - /// initialize the gnc parameter mu such that loss is approximately convex + /// initialize the gnc parameter mu such that loss is approximately convex (remark 5 in GNC paper) double initializeMu() const { // compute largest error across all factors double rmax_sq = 0.0; @@ -305,9 +329,7 @@ TEST(GncOptimizer, gncConstructorWithRobustGraphAsInput) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); auto gnc = GncOptimizer>(fg_robust, initial, gncParams); -// fg.print("fg\n"); -// fg_robust.print("fg_robust\n"); -// gnc.getFactors().print("gnc\n"); + // make sure that when parsing the graph is transformed into one without robust loss CHECK( fg.equals(gnc.getFactors()) ); } @@ -470,6 +492,7 @@ TEST(GncOptimizer, optimize) { // .. but graduated nonconvexity ensures both robustness and convergence in the face of nonconvexity GncParams gncParams(gnParams); + gncParams.setVerbosityGNC(GncParams::VerbosityGNC::VALUES); auto gnc = GncOptimizer>(fg, initial, gncParams); Values gnc_result = gnc.optimize(); CHECK(assert_equal(Point2(0.0,0.0), gnc_result.at(X(1)), 1e-3)); From ef4774188136492116f067839e2d2122911d1b0d Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 22:22:14 -0500 Subject: [PATCH 077/261] ladies and gents... GNC! --- tests/testGncOptimizer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 630b0c92b..383544c6e 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -48,7 +48,7 @@ public: GM /*Geman McClure*/, TLS /*Truncated least squares*/ }; - // using BaseOptimizer = GaussNewtonOptimizer; // BaseOptimizerParameters::OptimizerType; + using BaseOptimizer = GaussNewtonOptimizer; // BaseOptimizerParameters::OptimizerType; GncParams(const BaseOptimizerParameters& baseOptimizerParams): baseOptimizerParams(baseOptimizerParams), @@ -165,7 +165,7 @@ public: // variable/values update NonlinearFactorGraph graph_iter = this->makeWeightedGraph(weights); GaussNewtonOptimizer baseOptimizer_iter(graph_iter, state_); - result = baseOptimizer.optimize(); + result = baseOptimizer_iter.optimize(); // stopping condition if( checkMuConvergence(mu) ) { @@ -492,7 +492,7 @@ TEST(GncOptimizer, optimize) { // .. but graduated nonconvexity ensures both robustness and convergence in the face of nonconvexity GncParams gncParams(gnParams); - gncParams.setVerbosityGNC(GncParams::VerbosityGNC::VALUES); + // gncParams.setVerbosityGNC(GncParams::VerbosityGNC::SUMMARY); auto gnc = GncOptimizer>(fg, initial, gncParams); Values gnc_result = gnc.optimize(); CHECK(assert_equal(Point2(0.0,0.0), gnc_result.at(X(1)), 1e-3)); From c4644a0d61e76f1b895d8c3c8fe7a70be4e8d55d Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 22:50:41 -0500 Subject: [PATCH 078/261] added functionality to fix weights --- tests/testGncOptimizer.cpp | 86 +++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 383544c6e..2e7692bec 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -51,34 +51,34 @@ public: using BaseOptimizer = GaussNewtonOptimizer; // BaseOptimizerParameters::OptimizerType; GncParams(const BaseOptimizerParameters& baseOptimizerParams): - baseOptimizerParams(baseOptimizerParams), - lossType(GM), /* default loss*/ - maxIterations(100), /* maximum number of iterations*/ - barcSq(1.0), /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ - muStep(1.4), /* multiplicative factor to reduce/increase the mu in gnc */ - verbosityGNC(SILENT){}/* verbosity level */ + baseOptimizerParams(baseOptimizerParams) {} // default constructor GncParams(): baseOptimizerParams() {} BaseOptimizerParameters baseOptimizerParams; /// any other specific GNC parameters: - RobustLossType lossType; - size_t maxIterations; - double barcSq; - double muStep; - VerbosityGNC verbosityGNC; + RobustLossType lossType = GM; /* default loss*/ + size_t maxIterations = 100; /* maximum number of iterations*/ + double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ + double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ + VerbosityGNC verbosityGNC = SILENT; /* verbosity level */ + std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ void setLossType(const RobustLossType type){ lossType = type; } void setMaxIterations(const size_t maxIter){ std::cout - << "setMaxIterations: changing the max number of iterations might lead to less accurate solutions and is not recommended! " + << "setMaxIterations: changing the max nr of iters might lead to less accurate solutions and is not recommended! " << std::endl; maxIterations = maxIter; } void setInlierThreshold(const double inth){ barcSq = inth; } void setMuStep(const double step){ muStep = step; } void setVerbosityGNC(const VerbosityGNC verbosity) { verbosityGNC = verbosity; } + void setKnownInliers(const std::vector knownIn) { + for(size_t i=0; i= GncParameters::VerbosityGNC::VALUES){ result.print("result\n"); std::cout << "mu: " << mu << std::endl; - std::cout << "weights: " << weights << std::endl; + std::cout << "weights: " << weights_ << std::endl; } // weights update - weights = calculateWeights(result, mu); + weights_ = calculateWeights(result, mu); // variable/values update - NonlinearFactorGraph graph_iter = this->makeWeightedGraph(weights); + NonlinearFactorGraph graph_iter = this->makeWeightedGraph(weights_); GaussNewtonOptimizer baseOptimizer_iter(graph_iter, state_); result = baseOptimizer_iter.optimize(); @@ -173,7 +179,7 @@ public: if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY){ std::cout << "final iterations: " << iter << std::endl; std::cout << "final mu: " << mu << std::endl; - std::cout << "final weights: " << weights << std::endl; + std::cout << "final weights: " << weights_ << std::endl; } break; } @@ -249,10 +255,20 @@ public: /// calculate gnc weights Vector calculateWeights(const Values currentEstimate, const double mu){ - Vector weights = Vector::Zero(nfg_.size()); + Vector weights = Vector::Ones(nfg_.size()); + + // do not update the weights that the user has decided are known inliers + std::vector allWeights; + for (size_t k = 0; k < nfg_.size(); k++) {allWeights.push_back(k);} + std::vector unknownWeights; + std::set_difference(allWeights.begin(), allWeights.end(), + params_.knownInliers.begin(), params_.knownInliers.end(), + std::inserter(unknownWeights, unknownWeights.begin())); + + // update weights of known inlier/outlier measurements switch(params_.lossType) { case GncParameters::GM: // use eq (12) in GNC paper - for (size_t k = 0; k < nfg_.size(); k++) { + for (size_t k : unknownWeights) { if(nfg_[k]){ double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual weights[k] = std::pow( ( mu*params_.barcSq )/( u2_k + mu*params_.barcSq ) , 2); @@ -498,6 +514,36 @@ TEST(GncOptimizer, optimize) { CHECK(assert_equal(Point2(0.0,0.0), gnc_result.at(X(1)), 1e-3)); } +/* ************************************************************************* */ +TEST(GncOptimizer, optimizeWithKnownInliers) { + // has to have Gaussian noise models ! + auto fg = example::sharedNonRobustFactorGraphWithOutliers(); + + Point2 p0(1, 0); + Values initial; + initial.insert(X(1), p0); + + std::vector knownInliers; + knownInliers.push_back(0); + knownInliers.push_back(1); + knownInliers.push_back(2); + + // nonconvexity with known inliers + GncParams gncParams = GncParams(); + gncParams.setKnownInliers(knownInliers); + // gncParams.setVerbosityGNC(GncParams::VerbosityGNC::VALUES); + auto gnc = GncOptimizer>(fg, initial, gncParams); + + Values gnc_result = gnc.optimize(); + CHECK(assert_equal(Point2(0.0,0.0), gnc_result.at(X(1)), 1e-3)); + + // check weights were actually fixed: + Vector finalWeights = gnc.getWeights(); + DOUBLES_EQUAL(1.0, finalWeights[0], tol); + DOUBLES_EQUAL(1.0, finalWeights[1], tol); + DOUBLES_EQUAL(1.0, finalWeights[2], tol); +} + /* ************************************************************************* */ int main() { TestResult tr; From 7699f04820cd94558a062666f7fdbb5b1502d3ba Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 22:54:51 -0500 Subject: [PATCH 079/261] correct formatting --- tests/testGncOptimizer.cpp | 275 +++++++++++++++++++++---------------- 1 file changed, 155 insertions(+), 120 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 2e7692bec..65abc2042 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -35,7 +35,7 @@ using symbol_shorthand::L; static double tol = 1e-7; /* ************************************************************************* */ -template +template class GncParams { public: /** Verbosity levels */ @@ -50,11 +50,14 @@ public: using BaseOptimizer = GaussNewtonOptimizer; // BaseOptimizerParameters::OptimizerType; - GncParams(const BaseOptimizerParameters& baseOptimizerParams): - baseOptimizerParams(baseOptimizerParams) {} + GncParams(const BaseOptimizerParameters& baseOptimizerParams) : + baseOptimizerParams(baseOptimizerParams) { + } // default constructor - GncParams(): baseOptimizerParams() {} + GncParams() : + baseOptimizerParams() { + } BaseOptimizerParameters baseOptimizerParams; /// any other specific GNC parameters: @@ -62,29 +65,36 @@ public: size_t maxIterations = 100; /* maximum number of iterations*/ double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ - VerbosityGNC verbosityGNC = SILENT; /* verbosity level */ + VerbosityGNC verbosityGNC = SILENT; /* verbosity level */ std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ - void setLossType(const RobustLossType type){ lossType = type; } - void setMaxIterations(const size_t maxIter){ + void setLossType(const RobustLossType type) { + lossType = type; + } + void setMaxIterations(const size_t maxIter) { std::cout - << "setMaxIterations: changing the max nr of iters might lead to less accurate solutions and is not recommended! " - << std::endl; + << "setMaxIterations: changing the max nr of iters might lead to less accurate solutions and is not recommended! " + << std::endl; maxIterations = maxIter; } - void setInlierThreshold(const double inth){ barcSq = inth; } - void setMuStep(const double step){ muStep = step; } - void setVerbosityGNC(const VerbosityGNC verbosity) { verbosityGNC = verbosity; } + void setInlierThreshold(const double inth) { + barcSq = inth; + } + void setMuStep(const double step) { + muStep = step; + } + void setVerbosityGNC(const VerbosityGNC verbosity) { + verbosityGNC = verbosity; + } void setKnownInliers(const std::vector knownIn) { - for(size_t i=0; i(graph[i]); - noiseModel::Robust::shared_ptr robust = boost::dynamic_pointer_cast(factor->noiseModel()); - if(robust){ // if the factor has a robust loss, we have to change it: + if (graph[i]) { + NoiseModelFactor::shared_ptr factor = boost::dynamic_pointer_cast< + NoiseModelFactor>(graph[i]); + noiseModel::Robust::shared_ptr robust = boost::dynamic_pointer_cast< + noiseModel::Robust>(factor->noiseModel()); + if (robust) { // if the factor has a robust loss, we have to change it: SharedNoiseModel gaussianNoise = robust->noise(); - NoiseModelFactor::shared_ptr gaussianFactor = factor->cloneWithNewNoiseModel(gaussianNoise); + NoiseModelFactor::shared_ptr gaussianFactor = + factor->cloneWithNewNoiseModel(gaussianNoise); nfg_[i] = gaussianFactor; - } else{ // else we directly push it back + } else { // else we directly push it back nfg_[i] = factor; } } @@ -145,22 +159,30 @@ public: } /// getter functions - NonlinearFactorGraph getFactors() const { return NonlinearFactorGraph(nfg_); } - Values getState() const { return Values(state_); } - GncParameters getParams() const { return GncParameters(params_); } - Vector getWeights() const {return weights_;} + NonlinearFactorGraph getFactors() const { + return NonlinearFactorGraph(nfg_); + } + Values getState() const { + return Values(state_); + } + GncParameters getParams() const { + return GncParameters(params_); + } + Vector getWeights() const { + return weights_; + } /// implement GNC main loop, including graduating nonconvexity with mu Values optimize() { // start by assuming all measurements are inliers weights_ = Vector::Ones(nfg_.size()); - GaussNewtonOptimizer baseOptimizer(nfg_,state_); + GaussNewtonOptimizer baseOptimizer(nfg_, state_); Values result = baseOptimizer.optimize(); double mu = initializeMu(); - for(size_t iter=0; iter < params_.maxIterations; iter++){ + for (size_t iter = 0; iter < params_.maxIterations; iter++) { // display info - if (params_.verbosityGNC >= GncParameters::VerbosityGNC::VALUES){ + if (params_.verbosityGNC >= GncParameters::VerbosityGNC::VALUES) { result.print("result\n"); std::cout << "mu: " << mu << std::endl; std::cout << "weights: " << weights_ << std::endl; @@ -174,9 +196,9 @@ public: result = baseOptimizer_iter.optimize(); // stopping condition - if( checkMuConvergence(mu) ) { + if (checkMuConvergence(mu)) { // display info - if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY){ + if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { std::cout << "final iterations: " << iter << std::endl; std::cout << "final mu: " << mu << std::endl; std::cout << "final weights: " << weights_ << std::endl; @@ -195,14 +217,14 @@ public: // compute largest error across all factors double rmax_sq = 0.0; for (size_t i = 0; i < nfg_.size(); i++) { - if(nfg_[i]){ + if (nfg_[i]) { rmax_sq = std::max(rmax_sq, nfg_[i]->error(state_)); } } // set initial mu - switch(params_.lossType) { + switch (params_.lossType) { case GncParameters::GM: - return 2*rmax_sq / params_.barcSq; // initial mu + return 2 * rmax_sq / params_.barcSq; // initial mu default: throw std::runtime_error( "GncOptimizer::initializeMu: called with unknown loss type."); @@ -211,9 +233,9 @@ public: /// update the gnc parameter mu to gradually increase nonconvexity double updateMu(const double mu) const { - switch(params_.lossType) { + switch (params_.lossType) { case GncParameters::GM: - return std::max(1.0 , mu / params_.muStep); // reduce mu, but saturate at 1 + return std::max(1.0, mu / params_.muStep); // reduce mu, but saturate at 1 default: throw std::runtime_error( "GncOptimizer::updateMu: called with unknown loss type."); @@ -222,7 +244,7 @@ public: /// check if we have reached the value of mu for which the surrogate loss matches the original loss bool checkMuConvergence(const double mu) const { - switch(params_.lossType) { + switch (params_.lossType) { case GncParameters::GM: return std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function default: @@ -237,16 +259,20 @@ public: NonlinearFactorGraph newGraph; newGraph.resize(nfg_.size()); for (size_t i = 0; i < nfg_.size(); i++) { - if(nfg_[i]){ - NoiseModelFactor::shared_ptr factor = boost::dynamic_pointer_cast(nfg_[i]); - noiseModel::Gaussian::shared_ptr noiseModel = boost::dynamic_pointer_cast(factor->noiseModel()); - if(noiseModel){ + if (nfg_[i]) { + NoiseModelFactor::shared_ptr factor = boost::dynamic_pointer_cast< + NoiseModelFactor>(nfg_[i]); + noiseModel::Gaussian::shared_ptr noiseModel = + boost::dynamic_pointer_cast( + factor->noiseModel()); + if (noiseModel) { Matrix newInfo = weights[i] * noiseModel->information(); - SharedNoiseModel newNoiseModel = noiseModel::Gaussian::Information(newInfo); + SharedNoiseModel newNoiseModel = noiseModel::Gaussian::Information( + newInfo); newGraph[i] = factor->cloneWithNewNoiseModel(newNoiseModel); - }else{ + } else { throw std::runtime_error( - "GncOptimizer::makeWeightedGraph: unexpected non-Gaussian noise model."); + "GncOptimizer::makeWeightedGraph: unexpected non-Gaussian noise model."); } } } @@ -254,24 +280,27 @@ public: } /// calculate gnc weights - Vector calculateWeights(const Values currentEstimate, const double mu){ + Vector calculateWeights(const Values currentEstimate, const double mu) { Vector weights = Vector::Ones(nfg_.size()); // do not update the weights that the user has decided are known inliers std::vector allWeights; - for (size_t k = 0; k < nfg_.size(); k++) {allWeights.push_back(k);} + for (size_t k = 0; k < nfg_.size(); k++) { + allWeights.push_back(k); + } std::vector unknownWeights; std::set_difference(allWeights.begin(), allWeights.end(), params_.knownInliers.begin(), params_.knownInliers.end(), std::inserter(unknownWeights, unknownWeights.begin())); // update weights of known inlier/outlier measurements - switch(params_.lossType) { + switch (params_.lossType) { case GncParameters::GM: // use eq (12) in GNC paper for (size_t k : unknownWeights) { - if(nfg_[k]){ + if (nfg_[k]) { double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual - weights[k] = std::pow( ( mu*params_.barcSq )/( u2_k + mu*params_.barcSq ) , 2); + weights[k] = std::pow( + (mu * params_.barcSq) / (u2_k + mu * params_.barcSq), 2); } } return weights; @@ -284,7 +313,6 @@ public: /* ************************************************************************* */ TEST(GncOptimizer, gncParamsConstructor) { - //check params are correctly parsed LevenbergMarquardtParams lmParams; GncParams gncParams1(lmParams); @@ -296,7 +324,7 @@ TEST(GncOptimizer, gncParamsConstructor) { // and check params become different if we change lmParams lmParams.setVerbosity("DELTA"); - CHECK(! lmParams.equals(gncParams1.baseOptimizerParams)); + CHECK(!lmParams.equals(gncParams1.baseOptimizerParams)); // and same for GN GaussNewtonParams gnParams; @@ -310,7 +338,7 @@ TEST(GncOptimizer, gncParamsConstructor) { // change something at the gncParams level GncParams gncParams2c(gncParams2b); gncParams2c.setLossType(GncParams::RobustLossType::TLS); - CHECK(! gncParams2c.equals(gncParams2b.baseOptimizerParams)); + CHECK(!gncParams2c.equals(gncParams2b.baseOptimizerParams)); } /* ************************************************************************* */ @@ -324,7 +352,8 @@ TEST(GncOptimizer, gncConstructor) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); - auto gnc = GncOptimizer>(fg, initial, gncParams); + auto gnc = GncOptimizer>(fg, initial, + gncParams); CHECK(gnc.getFactors().equals(fg)); CHECK(gnc.getState().equals(initial)); @@ -333,7 +362,6 @@ TEST(GncOptimizer, gncConstructor) { /* ************************************************************************* */ TEST(GncOptimizer, gncConstructorWithRobustGraphAsInput) { - // simple graph with Gaussian noise model auto fg = example::sharedNonRobustFactorGraphWithOutliers(); // same graph with robust noise model auto fg_robust = example::sharedRobustFactorGraphWithOutliers(); @@ -344,15 +372,15 @@ TEST(GncOptimizer, gncConstructorWithRobustGraphAsInput) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); - auto gnc = GncOptimizer>(fg_robust, initial, gncParams); + auto gnc = GncOptimizer>(fg_robust, + initial, gncParams); // make sure that when parsing the graph is transformed into one without robust loss - CHECK( fg.equals(gnc.getFactors()) ); + CHECK(fg.equals(gnc.getFactors())); } /* ************************************************************************* */ TEST(GncOptimizer, initializeMu) { - // has to have Gaussian noise models ! auto fg = example::createReallyNonlinearFactorGraph(); Point2 p0(3, 3); @@ -361,8 +389,10 @@ TEST(GncOptimizer, initializeMu) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); - gncParams.setLossType(GncParams::RobustLossType::GM); - auto gnc = GncOptimizer>(fg, initial, gncParams); + gncParams.setLossType( + GncParams::RobustLossType::GM); + auto gnc = GncOptimizer>(fg, initial, + gncParams); EXPECT_DOUBLES_EQUAL(gnc.initializeMu(), 2 * 198.999, 1e-3); // according to rmk 5 in the gnc paper: m0 = 2 rmax^2 / barcSq (barcSq=1 in this example) } @@ -377,8 +407,10 @@ TEST(GncOptimizer, updateMu) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); - gncParams.setLossType(GncParams::RobustLossType::GM); - auto gnc = GncOptimizer>(fg, initial, gncParams); + gncParams.setLossType( + GncParams::RobustLossType::GM); + auto gnc = GncOptimizer>(fg, initial, + gncParams); double mu = 5.0; EXPECT_DOUBLES_EQUAL(gnc.updateMu(mu), mu / 1.4, tol); @@ -399,8 +431,10 @@ TEST(GncOptimizer, checkMuConvergence) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); - gncParams.setLossType(GncParams::RobustLossType::GM); - auto gnc = GncOptimizer>(fg, initial, gncParams); + gncParams.setLossType( + GncParams::RobustLossType::GM); + auto gnc = GncOptimizer>(fg, initial, + gncParams); double mu = 1.0; CHECK(gnc.checkMuConvergence(mu)); @@ -408,67 +442,69 @@ TEST(GncOptimizer, checkMuConvergence) { /* ************************************************************************* */ TEST(GncOptimizer, calculateWeights) { - // has to have Gaussian noise models ! - auto fg = example::sharedNonRobustFactorGraphWithOutliers(); + auto fg = example::sharedNonRobustFactorGraphWithOutliers(); - Point2 p0(0, 0); - Values initial; - initial.insert(X(1), p0); + Point2 p0(0, 0); + Values initial; + initial.insert(X(1), p0); - // we have 4 factors, 3 with zero errors (inliers), 1 with error 50 = 0.5 * 1/sigma^2 || [1;0] - [0;0] ||^2 (outlier) - Vector weights_expected = Vector::Zero(4); - weights_expected[0] = 1.0; // zero error - weights_expected[1] = 1.0; // zero error - weights_expected[2] = 1.0; // zero error - weights_expected[3] = std::pow(1.0 / (50.0 + 1.0),2); // outlier, error = 50 + // we have 4 factors, 3 with zero errors (inliers), 1 with error 50 = 0.5 * 1/sigma^2 || [1;0] - [0;0] ||^2 (outlier) + Vector weights_expected = Vector::Zero(4); + weights_expected[0] = 1.0; // zero error + weights_expected[1] = 1.0; // zero error + weights_expected[2] = 1.0; // zero error + weights_expected[3] = std::pow(1.0 / (50.0 + 1.0), 2); // outlier, error = 50 - GaussNewtonParams gnParams; - GncParams gncParams(gnParams); - auto gnc = GncOptimizer>(fg, initial, gncParams); - double mu = 1.0; - Vector weights_actual = gnc.calculateWeights(initial,mu); - CHECK(assert_equal(weights_expected, weights_actual, tol)); + GaussNewtonParams gnParams; + GncParams gncParams(gnParams); + auto gnc = GncOptimizer>(fg, initial, gncParams); + double mu = 1.0; + Vector weights_actual = gnc.calculateWeights(initial, mu); + CHECK(assert_equal(weights_expected, weights_actual, tol)); - mu = 2.0; - double barcSq = 5.0; - weights_expected[3] = std::pow(mu*barcSq / (50.0 + mu*barcSq),2); // outlier, error = 50 - gncParams.setInlierThreshold(barcSq); - auto gnc2 = GncOptimizer>(fg, initial, gncParams); - weights_actual = gnc2.calculateWeights(initial,mu); - CHECK(assert_equal(weights_expected, weights_actual, tol)); + mu = 2.0; + double barcSq = 5.0; + weights_expected[3] = std::pow(mu * barcSq / (50.0 + mu * barcSq), 2); // outlier, error = 50 + gncParams.setInlierThreshold(barcSq); + auto gnc2 = GncOptimizer>(fg, initial, + gncParams); + weights_actual = gnc2.calculateWeights(initial, mu); + CHECK(assert_equal(weights_expected, weights_actual, tol)); } /* ************************************************************************* */ TEST(GncOptimizer, makeWeightedGraph) { // create original factor - double sigma1 = 0.1; - NonlinearFactorGraph nfg = example::nonlinearFactorGraphWithGivenSigma(sigma1); + double sigma1 = 0.1; + NonlinearFactorGraph nfg = example::nonlinearFactorGraphWithGivenSigma( + sigma1); - // create expected - double sigma2 = 10; - NonlinearFactorGraph expected = example::nonlinearFactorGraphWithGivenSigma(sigma2); + // create expected + double sigma2 = 10; + NonlinearFactorGraph expected = example::nonlinearFactorGraphWithGivenSigma( + sigma2); - // create weights - Vector weights = Vector::Ones(1); // original info:1/0.1^2 = 100. New info: 1/10^2 = 0.01. Ratio is 10-4 - weights[0] = 1e-4; + // create weights + Vector weights = Vector::Ones(1); // original info:1/0.1^2 = 100. New info: 1/10^2 = 0.01. Ratio is 10-4 + weights[0] = 1e-4; - // create actual - Point2 p0(3, 3); - Values initial; - initial.insert(X(1), p0); + // create actual + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); - auto gnc = GncOptimizer>(nfg, initial, gncParams); - NonlinearFactorGraph actual = gnc.makeWeightedGraph(weights); + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + auto gnc = GncOptimizer>(nfg, initial, + gncParams); + NonlinearFactorGraph actual = gnc.makeWeightedGraph(weights); - // check it's all good - CHECK(assert_equal(expected, actual)); + // check it's all good + CHECK(assert_equal(expected, actual)); } /* ************************************************************************* */ TEST(GncOptimizer, optimizeSimple) { - // has to have Gaussian noise models ! auto fg = example::createReallyNonlinearFactorGraph(); Point2 p0(3, 3); @@ -477,7 +513,8 @@ TEST(GncOptimizer, optimizeSimple) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); - auto gnc = GncOptimizer>(fg, initial, gncParams); + auto gnc = GncOptimizer>(fg, initial, + gncParams); Values actual = gnc.optimize(); DOUBLES_EQUAL(0, fg.error(actual), tol); @@ -485,7 +522,6 @@ TEST(GncOptimizer, optimizeSimple) { /* ************************************************************************* */ TEST(GncOptimizer, optimize) { - // has to have Gaussian noise models ! auto fg = example::sharedNonRobustFactorGraphWithOutliers(); Point2 p0(1, 0); @@ -497,26 +533,25 @@ TEST(GncOptimizer, optimize) { GaussNewtonOptimizer gn(fg, initial, gnParams); Values gn_results = gn.optimize(); // converges to incorrect point due to lack of robustness to an outlier, ideal solution is Point2(0,0) - CHECK(assert_equal(Point2(0.25,0.0), gn_results.at(X(1)), 1e-3)); + CHECK(assert_equal(Point2(0.25, 0.0), gn_results.at(X(1)), 1e-3)); // try with robust loss function and standard GN auto fg_robust = example::sharedRobustFactorGraphWithOutliers(); // same as fg, but with factors wrapped in Geman McClure losses GaussNewtonOptimizer gn2(fg_robust, initial, gnParams); Values gn2_results = gn2.optimize(); // converges to incorrect point, this time due to the nonconvexity of the loss - CHECK(assert_equal(Point2(0.999706,0.0), gn2_results.at(X(1)), 1e-3)); + CHECK(assert_equal(Point2(0.999706, 0.0), gn2_results.at(X(1)), 1e-3)); // .. but graduated nonconvexity ensures both robustness and convergence in the face of nonconvexity GncParams gncParams(gnParams); // gncParams.setVerbosityGNC(GncParams::VerbosityGNC::SUMMARY); auto gnc = GncOptimizer>(fg, initial, gncParams); Values gnc_result = gnc.optimize(); - CHECK(assert_equal(Point2(0.0,0.0), gnc_result.at(X(1)), 1e-3)); + CHECK(assert_equal(Point2(0.0, 0.0), gnc_result.at(X(1)), 1e-3)); } /* ************************************************************************* */ TEST(GncOptimizer, optimizeWithKnownInliers) { - // has to have Gaussian noise models ! auto fg = example::sharedNonRobustFactorGraphWithOutliers(); Point2 p0(1, 0); @@ -535,7 +570,7 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { auto gnc = GncOptimizer>(fg, initial, gncParams); Values gnc_result = gnc.optimize(); - CHECK(assert_equal(Point2(0.0,0.0), gnc_result.at(X(1)), 1e-3)); + CHECK(assert_equal(Point2(0.0, 0.0), gnc_result.at(X(1)), 1e-3)); // check weights were actually fixed: Vector finalWeights = gnc.getWeights(); From 786d4bbf9a6609b536493a6e4fe1c64a3f1fccda Mon Sep 17 00:00:00 2001 From: lcarlone Date: Fri, 27 Nov 2020 23:12:26 -0500 Subject: [PATCH 080/261] done - PGO works like a charm! --- tests/testGncOptimizer.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 65abc2042..8415ec3cc 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -20,6 +20,8 @@ * From Non-Minimal Solvers to Global Outlier Rejection", RAL, 2020. (arxiv version: https://arxiv.org/pdf/1909.08605.pdf) */ +#include + #include #include #include @@ -579,6 +581,42 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { DOUBLES_EQUAL(1.0, finalWeights[2], tol); } +/* ************************************************************************* */ +TEST(GncOptimizer, optimizeSmallPoseGraph) { + /// load small pose graph + const string filename = findExampleDataFile("w100.graph"); + NonlinearFactorGraph::shared_ptr graph; + Values::shared_ptr initial; + boost::tie(graph, initial) = load2D(filename); + // Add a Gaussian prior on first poses + Pose2 priorMean(0.0, 0.0, 0.0); // prior at origin + SharedDiagonal priorNoise = noiseModel::Diagonal::Sigmas(Vector3(0.01, 0.01, 0.01)); + graph -> addPrior(0, priorMean, priorNoise); + + /// get expected values by optimizing outlier-free graph + Values expected = LevenbergMarquardtOptimizer(*graph, *initial).optimize(); + + // add a few outliers + SharedDiagonal betweenNoise = noiseModel::Diagonal::Sigmas(Vector3(0.1, 0.1, 0.01)); + graph->push_back( BetweenFactor(90 , 50 , Pose2(), betweenNoise) ); // some arbitrary and incorrect between factor + + /// get expected values by optimizing outlier-free graph + Values expectedWithOutliers = LevenbergMarquardtOptimizer(*graph, *initial).optimize(); + // as expected, the following test fails due to the presence of an outlier! + // CHECK(assert_equal(expected, expectedWithOutliers, 1e-3)); + + // GNC + // Note: in difficult instances, we set the odometry measurements to be inliers, + // but this problem is simple enought to succeed even without that assumption + // std::vector knownInliers; + GncParams gncParams = GncParams(); + auto gnc = GncOptimizer>(*graph, *initial, gncParams); + Values actual = gnc.optimize(); + + // compare + CHECK(assert_equal(expected, actual, 1e-3)); // yay! we are robust to outliers! +} + /* ************************************************************************* */ int main() { TestResult tr; From cc54b18fe508139e11e51517a5c7c29090161762 Mon Sep 17 00:00:00 2001 From: Sushmita Date: Sat, 28 Nov 2020 15:49:08 -0500 Subject: [PATCH 081/261] docs fixed and error threshold reduced --- gtsam/geometry/triangulation.h | 7 ++--- python/gtsam/tests/test_Triangulation.py | 34 +++++++++++++----------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/gtsam/geometry/triangulation.h b/gtsam/geometry/triangulation.h index 01daab361..23ea7e50b 100644 --- a/gtsam/geometry/triangulation.h +++ b/gtsam/geometry/triangulation.h @@ -18,14 +18,14 @@ #pragma once -#include +#include +#include #include +#include #include #include #include #include -#include -#include namespace gtsam { @@ -496,6 +496,7 @@ TriangulationResult triangulateSafe(const CameraSet& cameras, } } +// Vector of Cameras - used by the Python/MATLAB wrapper typedef CameraSet> CameraSetCal3Bundler; typedef CameraSet> CameraSetCal3_S2; diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index c358152ae..96a6a5c4a 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -15,7 +15,9 @@ import numpy as np import gtsam as g from gtsam.utils.test_case import GtsamTestCase from gtsam import Cal3_S2, Cal3Bundler, Rot3, Pose3, \ - PinholeCameraCal3_S2, Point3, Point2Vector, Pose3Vector, triangulatePoint3, CameraSetCal3_S2, CameraSetCal3Bundler, PinholeCameraCal3Bundler + PinholeCameraCal3_S2, PinholeCameraCal3Bundler, Point3, \ + Point2Vector, Pose3Vector, triangulatePoint3, \ + CameraSetCal3_S2, CameraSetCal3Bundler class TestVisualISAMExample(GtsamTestCase): def setUp(self): @@ -80,62 +82,62 @@ class TestVisualISAMExample(GtsamTestCase): # self.gtsamAssertEquals(landmark, triangulated_landmark,1e-9) def test_distinct_Ks(self): + # two cameras K1 = Cal3_S2(1500, 1200, 0, 640, 480) camera1 = PinholeCameraCal3_S2(self.pose1, K1) K2 = Cal3_S2(1600, 1300, 0, 650, 440) camera2 = PinholeCameraCal3_S2(self.pose2, K2) + cameras = CameraSetCal3_S2() + cameras.append(camera1) + cameras.append(camera2) + # landmark ~5 meters infront of camera landmark = Point3(5, 0.5, 1.2) # 1. Project two landmarks into two cameras and triangulate z1 = camera1.project(landmark) z2 = camera2.project(landmark) - # two cameras + measurements = Point2Vector() - cameras = CameraSetCal3_S2() - measurements.append(z1) measurements.append(z2) - cameras.append(camera1) - cameras.append(camera2) optimize = True rank_tol = 1e-9 triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol, optimize) - self.gtsamAssertEquals(landmark, triangulated_landmark, 1e-2) + self.gtsamAssertEquals(landmark, triangulated_landmark, 1e-9) def test_distinct_Ks_Bundler(self): + # two cameras K1 = Cal3Bundler(1500, 0, 0, 640, 480) camera1 = PinholeCameraCal3Bundler(self.pose1, K1) - K2 = Cal3Bundler(1500, 0, 0, 640, 480) + K2 = Cal3Bundler(1600, 0, 0, 650, 440) camera2 = PinholeCameraCal3Bundler(self.pose2, K2) + cameras = CameraSetCal3Bundler() + cameras.append(camera1) + cameras.append(camera2) + # landmark ~5 meters infront of camera landmark = Point3(5, 0.5, 1.2) # 1. Project two landmarks into two cameras and triangulate z1 = camera1.project(landmark) z2 = camera2.project(landmark) - # two cameras - measurements = Point2Vector() - cameras = CameraSetCal3Bundler() + measurements = Point2Vector() measurements.append(z1) measurements.append(z2) - cameras.append(camera1) - cameras.append(camera2) optimize = True rank_tol = 1e-9 triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol, optimize) - self.gtsamAssertEquals(landmark, triangulated_landmark, 1e-2) - - + self.gtsamAssertEquals(landmark, triangulated_landmark, 1e-9) if __name__ == "__main__": unittest.main() From 362afce86443afffbf9e539c3b0b527187f7a14d Mon Sep 17 00:00:00 2001 From: Sushmita Date: Sat, 28 Nov 2020 17:34:04 -0500 Subject: [PATCH 082/261] moved landmark variable to setup --- python/gtsam/tests/test_Triangulation.py | 42 ++++++++++-------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index 96a6a5c4a..8e0af3094 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -29,6 +29,9 @@ class TestVisualISAMExample(GtsamTestCase): # create second camera 1 meter to the right of first camera self.pose2 = self.pose1.compose(Pose3(Rot3(), Point3(1, 0, 0))) + # landmark ~5 meters infront of camera + self.landmark = Point3(5, 0.5, 1.2) + def test_TriangulationExample(self): # Some common constants @@ -36,12 +39,9 @@ class TestVisualISAMExample(GtsamTestCase): camera1 = PinholeCameraCal3_S2(self.pose1, sharedCal) camera2 = PinholeCameraCal3_S2(self.pose2, sharedCal) - # landmark ~5 meters infront of camera - landmark = Point3(5, 0.5, 1.2) - # 1. Project two landmarks into two cameras and triangulate - z1 = camera1.project(landmark) - z2 = camera2.project(landmark) + z1 = camera1.project(self.landmark) + z2 = camera2.project(self.landmark) # twoPoses poses = Pose3Vector() @@ -56,7 +56,7 @@ class TestVisualISAMExample(GtsamTestCase): rank_tol = 1e-9 triangulated_landmark = triangulatePoint3(poses,sharedCal, measurements, rank_tol, optimize) - self.gtsamAssertEquals(landmark, triangulated_landmark,1e-9) + self.gtsamAssertEquals(self.landmark, triangulated_landmark,1e-9) # 2. Add some noise and try again: result should be ~ (4.995, 0.499167, 1.19814) measurements = Point2Vector() @@ -64,22 +64,22 @@ class TestVisualISAMExample(GtsamTestCase): measurements.append(z2 - np.array([-0.2, 0.3])) triangulated_landmark = triangulatePoint3(poses,sharedCal, measurements, rank_tol, optimize) - self.gtsamAssertEquals(landmark, triangulated_landmark,1e-2) + self.gtsamAssertEquals(self.landmark, triangulated_landmark,1e-2) # # # two Poses with Bundler Calibration # bundlerCal = Cal3Bundler(1500, 0, 0, 640, 480) # camera1 = PinholeCameraCal3Bundler(pose1, bundlerCal) # camera2 = PinholeCameraCal3Bundler(pose2, bundlerCal) # - # z1 = camera1.project(landmark) - # z2 = camera2.project(landmark) + # z1 = camera1.project(self.landmark) + # z2 = camera2.project(self.landmark) # # measurements = Point2Vector() # measurements.append(z1) # measurements.append(z2) # # triangulated_landmark = triangulatePoint3(poses,bundlerCal, measurements, rank_tol, optimize) - # self.gtsamAssertEquals(landmark, triangulated_landmark,1e-9) + # self.gtsamAssertEquals(self.landmark, triangulated_landmark,1e-9) def test_distinct_Ks(self): # two cameras @@ -93,12 +93,9 @@ class TestVisualISAMExample(GtsamTestCase): cameras.append(camera1) cameras.append(camera2) - # landmark ~5 meters infront of camera - landmark = Point3(5, 0.5, 1.2) - - # 1. Project two landmarks into two cameras and triangulate - z1 = camera1.project(landmark) - z2 = camera2.project(landmark) + # Project two landmarks into two cameras and triangulate + z1 = camera1.project(self.landmark) + z2 = camera2.project(self.landmark) measurements = Point2Vector() measurements.append(z1) @@ -108,7 +105,7 @@ class TestVisualISAMExample(GtsamTestCase): rank_tol = 1e-9 triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol, optimize) - self.gtsamAssertEquals(landmark, triangulated_landmark, 1e-9) + self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) def test_distinct_Ks_Bundler(self): # two cameras @@ -122,12 +119,9 @@ class TestVisualISAMExample(GtsamTestCase): cameras.append(camera1) cameras.append(camera2) - # landmark ~5 meters infront of camera - landmark = Point3(5, 0.5, 1.2) - - # 1. Project two landmarks into two cameras and triangulate - z1 = camera1.project(landmark) - z2 = camera2.project(landmark) + # Project two landmarks into two cameras and triangulate + z1 = camera1.project(self.landmark) + z2 = camera2.project(self.landmark) measurements = Point2Vector() measurements.append(z1) @@ -137,7 +131,7 @@ class TestVisualISAMExample(GtsamTestCase): rank_tol = 1e-9 triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol, optimize) - self.gtsamAssertEquals(landmark, triangulated_landmark, 1e-9) + self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) if __name__ == "__main__": unittest.main() From b4f1db5a013a297bd6f89bad22ef2b9b0a90d621 Mon Sep 17 00:00:00 2001 From: Sushmita Date: Sat, 28 Nov 2020 22:50:05 -0500 Subject: [PATCH 083/261] push back arguments changed to const reference --- gtsam/gtsam.i | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 28ed01111..f6c2da853 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -1119,7 +1119,7 @@ class CameraSetCal3Bundler { // structure specific methods gtsam::PinholeCameraCal3Bundler at(size_t i) const; - void push_back(gtsam::PinholeCameraCal3Bundler& cam) const; + void push_back(const gtsam::PinholeCameraCal3Bundler& cam); }; class CameraSetCal3_S2 { @@ -1132,7 +1132,7 @@ class CameraSetCal3_S2 { // structure specific methods gtsam::PinholeCameraCal3_S2 at(size_t i) const; - void push_back(gtsam::PinholeCameraCal3_S2& cam) const; + void push_back(const gtsam::PinholeCameraCal3_S2& cam); }; #include From e484a70b5f5aa588dae4c74130228092bf20e160 Mon Sep 17 00:00:00 2001 From: Sushmita Date: Sat, 28 Nov 2020 23:21:55 -0500 Subject: [PATCH 084/261] removed commented code --- python/gtsam/tests/test_Triangulation.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index 8e0af3094..e57fbb6ab 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -65,21 +65,6 @@ class TestVisualISAMExample(GtsamTestCase): triangulated_landmark = triangulatePoint3(poses,sharedCal, measurements, rank_tol, optimize) self.gtsamAssertEquals(self.landmark, triangulated_landmark,1e-2) - # - # # two Poses with Bundler Calibration - # bundlerCal = Cal3Bundler(1500, 0, 0, 640, 480) - # camera1 = PinholeCameraCal3Bundler(pose1, bundlerCal) - # camera2 = PinholeCameraCal3Bundler(pose2, bundlerCal) - # - # z1 = camera1.project(self.landmark) - # z2 = camera2.project(self.landmark) - # - # measurements = Point2Vector() - # measurements.append(z1) - # measurements.append(z2) - # - # triangulated_landmark = triangulatePoint3(poses,bundlerCal, measurements, rank_tol, optimize) - # self.gtsamAssertEquals(self.landmark, triangulated_landmark,1e-9) def test_distinct_Ks(self): # two cameras From 4bc250e7c04c4b91a3f15715d0e70dd82ede388b Mon Sep 17 00:00:00 2001 From: akrishnan86 Date: Sat, 28 Nov 2020 23:44:20 -0800 Subject: [PATCH 085/261] new test doesnt pass --- gtsam/sfm/TranslationRecovery.cpp | 53 +++++++++++++--- gtsam/sfm/TranslationRecovery.h | 6 +- tests/testTranslationRecovery.cpp | 100 +++++++++++++++++++++++++++--- 3 files changed, 141 insertions(+), 18 deletions(-) diff --git a/gtsam/sfm/TranslationRecovery.cpp b/gtsam/sfm/TranslationRecovery.cpp index 319129840..8821d490b 100644 --- a/gtsam/sfm/TranslationRecovery.cpp +++ b/gtsam/sfm/TranslationRecovery.cpp @@ -16,8 +16,7 @@ * @brief Source code for recovering translations when rotations are given */ -#include - +#include #include #include #include @@ -27,11 +26,39 @@ #include #include #include +#include #include +#include +#include + using namespace gtsam; using namespace std; +TranslationRecovery::TranslationRecovery( + const TranslationRecovery::TranslationEdges &relativeTranslations, + const LevenbergMarquardtParams &lmParams) + : params_(lmParams) { + TranslationEdges tempRelativeTranslations; + DSFMap sameTranslationDSF; + + for (const auto &edge : relativeTranslations) { + Key key1 = sameTranslationDSF.find(edge.key1()); + Key key2 = sameTranslationDSF.find(edge.key2()); + if (key1 != key2 && edge.measured().equals(Unit3(0.0, 0.0, 0.0))) { + sameTranslationDSF.merge(key1, key2); + } + } + for (const auto &edge : relativeTranslations) { + Key key1 = sameTranslationDSF.find(edge.key1()); + Key key2 = sameTranslationDSF.find(edge.key2()); + if (key1 == key2) continue; + relativeTranslations_.emplace_back(key1, key2, edge.measured(), + edge.noiseModel()); + } + sameTranslationNodes_ = sameTranslationDSF.sets(); +} + NonlinearFactorGraph TranslationRecovery::buildGraph() const { NonlinearFactorGraph graph; @@ -44,13 +71,14 @@ NonlinearFactorGraph TranslationRecovery::buildGraph() const { return graph; } -void TranslationRecovery::addPrior(const double scale, - NonlinearFactorGraph *graph, - const SharedNoiseModel &priorNoiseModel) const { +void TranslationRecovery::addPrior( + const double scale, NonlinearFactorGraph *graph, + const SharedNoiseModel &priorNoiseModel) const { auto edge = relativeTranslations_.begin(); - graph->emplace_shared >(edge->key1(), Point3(0, 0, 0), priorNoiseModel); - graph->emplace_shared >(edge->key2(), scale * edge->measured().point3(), - edge->noiseModel()); + graph->emplace_shared >(edge->key1(), Point3(0, 0, 0), + priorNoiseModel); + graph->emplace_shared >( + edge->key2(), scale * edge->measured().point3(), edge->noiseModel()); } Values TranslationRecovery::initalizeRandomly() const { @@ -77,6 +105,15 @@ Values TranslationRecovery::run(const double scale) const { const Values initial = initalizeRandomly(); LevenbergMarquardtOptimizer lm(graph, initial, params_); Values result = lm.optimize(); + + for (const auto &sameTranslationKeys : sameTranslationNodes_) { + Key optimizedKey = sameTranslationKeys.first; + std::set duplicateKeys = sameTranslationKeys.second; + for (const Key duplicateKey : duplicateKeys) { + if (result.exists(duplicateKey)) continue; + result.insert(duplicateKey, result.at(optimizedKey)); + } + } return result; } diff --git a/gtsam/sfm/TranslationRecovery.h b/gtsam/sfm/TranslationRecovery.h index d5538f91b..c3492d067 100644 --- a/gtsam/sfm/TranslationRecovery.h +++ b/gtsam/sfm/TranslationRecovery.h @@ -23,6 +23,8 @@ #include #include +#include +#include namespace gtsam { @@ -54,6 +56,7 @@ class TranslationRecovery { private: TranslationEdges relativeTranslations_; LevenbergMarquardtParams params_; + std::map> sameTranslationNodes_; public: /** @@ -67,8 +70,7 @@ class TranslationRecovery { * default LM parameters. */ TranslationRecovery(const TranslationEdges &relativeTranslations, - const LevenbergMarquardtParams &lmParams = LevenbergMarquardtParams()) - : relativeTranslations_(relativeTranslations), params_(lmParams) {} + const LevenbergMarquardtParams &lmParams = LevenbergMarquardtParams()); /** * @brief Build the factor graph to do the optimization. diff --git a/tests/testTranslationRecovery.cpp b/tests/testTranslationRecovery.cpp index eb34ba803..84ed577f1 100644 --- a/tests/testTranslationRecovery.cpp +++ b/tests/testTranslationRecovery.cpp @@ -16,9 +16,8 @@ * @brief test recovering translations when rotations are given. */ -#include - #include +#include #include using namespace std; @@ -49,14 +48,14 @@ TEST(TranslationRecovery, BAL) { poses, {{0, 1}, {0, 2}, {1, 2}}); // Check - Unit3 w_aZb_stored; // measurement between 0 and 1 stored for next unit test - for(auto& unitTranslation : relativeTranslations) { - const Pose3 wTa = poses.at(unitTranslation.key1()), + Unit3 w_aZb_stored; // measurement between 0 and 1 stored for next unit test + for (auto& unitTranslation : relativeTranslations) { + const Pose3 wTa = poses.at(unitTranslation.key1()), wTb = poses.at(unitTranslation.key2()); const Point3 Ta = wTa.translation(), Tb = wTb.translation(); const Unit3 w_aZb = unitTranslation.measured(); EXPECT(assert_equal(Unit3(Tb - Ta), w_aZb)); - if(unitTranslation.key1() == 0 && unitTranslation.key2() == 1) { + if (unitTranslation.key1() == 0 && unitTranslation.key2() == 1) { w_aZb_stored = unitTranslation.measured(); } } @@ -77,14 +76,99 @@ TEST(TranslationRecovery, BAL) { Point3 Ta = poses.at(0).translation(); Point3 Tb = poses.at(1).translation(); Point3 Tc = poses.at(2).translation(); - Point3 expected = - (Tc - Ta) * (scale / (Tb - Ta).norm()); + Point3 expected = (Tc - Ta) * (scale / (Tb - Ta).norm()); EXPECT(assert_equal(expected, result.at(2), 1e-4)); // TODO(frank): how to get stats back? // EXPECT_DOUBLES_EQUAL(0.0199833, actualError, 1e-5); } +TEST(TranslationRecovery, ZeroRelativeTranslations) { + // Create a graph with 3 cameras. + // __ __ + // \/ \/ + // 0 _____ 1 + // 2 <| + // + // 0 and 1 face in the same direction but have a translation offset. 2 is at + // the same point as 1 but is rotated, with very little FOV overlap. + Values poses; + poses.insert(0, Pose3(Rot3(), Point3())); + poses.insert(1, Pose3(Rot3(), Point3(2, 0, 0))); + poses.insert(2, Pose3(Rot3::RzRyRx(-M_PI / 2, 0, 0), Point3(2, 0, 0))); + + auto relativeTranslations = + TranslationRecovery::SimulateMeasurements(poses, {{0, 1}, {1, 2}}); + + // Check + for (auto& unitTranslation : relativeTranslations) { + const Pose3 wTa = poses.at(unitTranslation.key1()), + wTb = poses.at(unitTranslation.key2()); + const Point3 Ta = wTa.translation(), Tb = wTb.translation(); + const Unit3 w_aZb = unitTranslation.measured(); + EXPECT(assert_equal(Unit3(Tb - Ta), w_aZb)); + } + + TranslationRecovery algorithm(relativeTranslations); + const auto graph = algorithm.buildGraph(); + EXPECT_LONGS_EQUAL(1, graph.size()); + + // Translation recovery, version 1 + const double scale = 2.0; + const auto result = algorithm.run(scale); + + // Check result for first two translations, determined by prior + EXPECT(assert_equal(Point3(0, 0, 0), result.at(0))); + EXPECT(assert_equal(Point3(2, 0, 0), result.at(1))); + EXPECT(assert_equal(Point3(2, 0, 0), result.at(2))); +} + +TEST(TranslationRecovery, ZeroRelativeTranslations4Cameras) { + // Create a graph with 4 cameras. + // __ __ + // \/ \/ + // 0 _____ 1 + // \ 2 <| + // \ / + // 3 + // + // 0 and 1 face in the same direction but have a translation offset. 2 is at + // the same point as 1 but is rotated, with very little FOV overlap. 3 is in + // the same direction as 0 and 1, in between 0 and 1, with some Y axis offset. + + Values poses; + poses.insert(0, Pose3(Rot3(), Point3())); + poses.insert(1, Pose3(Rot3(), Point3(2, 0, 0))); + poses.insert(2, Pose3(Rot3::RzRyRx(-M_PI / 2, 0, 0), Point3(2, 0, 0))); + poses.insert(3, Pose3(Rot3(), Point3(1, -1, 0))); + + auto relativeTranslations = TranslationRecovery::SimulateMeasurements( + poses, {{0, 1}, {1, 2}, {1, 3}, {3, 0}}); + + // Check + for (auto& unitTranslation : relativeTranslations) { + const Pose3 wTa = poses.at(unitTranslation.key1()), + wTb = poses.at(unitTranslation.key2()); + const Point3 Ta = wTa.translation(), Tb = wTb.translation(); + const Unit3 w_aZb = unitTranslation.measured(); + EXPECT(assert_equal(Unit3(Tb - Ta), w_aZb)); + } + + TranslationRecovery algorithm(relativeTranslations); + const auto graph = algorithm.buildGraph(); + EXPECT_LONGS_EQUAL(3, graph.size()); + + // Translation recovery, version 1 + const double scale = 2.0; + const auto result = algorithm.run(scale); + + // Check result for first two translations, determined by prior + EXPECT(assert_equal(Point3(0, 0, 0), result.at(0))); + EXPECT(assert_equal(Point3(2, 0, 0), result.at(1))); + EXPECT(assert_equal(Point3(2, 0, 0), result.at(2))); + EXPECT(assert_equal(Point3(1, -1, 0), result.at(3))); +} + /* ************************************************************************* */ int main() { TestResult tr; From 8d009c2fcf55e41ac7c7b7f30859322cf47bcb67 Mon Sep 17 00:00:00 2001 From: akrishnan86 Date: Mon, 30 Nov 2020 00:30:19 -0800 Subject: [PATCH 086/261] translation recovery unit tests pass --- gtsam/sfm/TranslationRecovery.cpp | 2 +- gtsam/sfm/TranslationRecovery.h | 25 ++--- tests/testTranslationRecovery.cpp | 167 +++++++++++++++++++++--------- 3 files changed, 132 insertions(+), 62 deletions(-) diff --git a/gtsam/sfm/TranslationRecovery.cpp b/gtsam/sfm/TranslationRecovery.cpp index 8821d490b..8d27136e3 100644 --- a/gtsam/sfm/TranslationRecovery.cpp +++ b/gtsam/sfm/TranslationRecovery.cpp @@ -11,7 +11,7 @@ /** * @file TranslationRecovery.cpp - * @author Frank Dellaert + * @author Frank Dellaert, Akshay Krishnan * @date March 2020 * @brief Source code for recovering translations when rotations are given */ diff --git a/gtsam/sfm/TranslationRecovery.h b/gtsam/sfm/TranslationRecovery.h index c3492d067..9ffe45685 100644 --- a/gtsam/sfm/TranslationRecovery.h +++ b/gtsam/sfm/TranslationRecovery.h @@ -16,16 +16,16 @@ * @brief Recovering translations in an epipolar graph when rotations are given. */ +#include +#include +#include +#include + #include #include #include #include -#include -#include -#include -#include - namespace gtsam { // Set up an optimization problem for the unknown translations Ti in the world @@ -63,14 +63,15 @@ class TranslationRecovery { * @brief Construct a new Translation Recovery object * * @param relativeTranslations the relative translations, in world coordinate - * frames, vector of BinaryMeasurements of Unit3, where each key of a measurement - * is a point in 3D. + * frames, vector of BinaryMeasurements of Unit3, where each key of a + * measurement is a point in 3D. * @param lmParams (optional) gtsam::LavenbergMarquardtParams that can be * used to modify the parameters for the LM optimizer. By default, uses the - * default LM parameters. + * default LM parameters. */ - TranslationRecovery(const TranslationEdges &relativeTranslations, - const LevenbergMarquardtParams &lmParams = LevenbergMarquardtParams()); + TranslationRecovery( + const TranslationEdges &relativeTranslations, + const LevenbergMarquardtParams &lmParams = LevenbergMarquardtParams()); /** * @brief Build the factor graph to do the optimization. @@ -110,8 +111,8 @@ class TranslationRecovery { * * @param poses SE(3) ground truth poses stored as Values * @param edges pairs (a,b) for which a measurement w_aZb will be generated. - * @return TranslationEdges vector of binary measurements where the keys are - * the cameras and the measurement is the simulated Unit3 translation + * @return TranslationEdges vector of binary measurements where the keys are + * the cameras and the measurement is the simulated Unit3 translation * direction between the cameras. */ static TranslationEdges SimulateMeasurements( diff --git a/tests/testTranslationRecovery.cpp b/tests/testTranslationRecovery.cpp index 84ed577f1..e4fbd9219 100644 --- a/tests/testTranslationRecovery.cpp +++ b/tests/testTranslationRecovery.cpp @@ -11,18 +11,29 @@ /** * @file testTranslationRecovery.cpp - * @author Frank Dellaert + * @author Frank Dellaert, Akshay Krishnan * @date March 2020 * @brief test recovering translations when rotations are given. */ #include + #include #include using namespace std; using namespace gtsam; +// Returns the Unit3 direction as measured in the binary measurement, but +// computed from the input poses. Helper function used in the unit tests. +Unit3 GetDirectionFromPoses(const Values& poses, + const BinaryMeasurement& unitTranslation) { + const Pose3 wTa = poses.at(unitTranslation.key1()), + wTb = poses.at(unitTranslation.key2()); + const Point3 Ta = wTa.translation(), Tb = wTb.translation(); + return Unit3(Tb - Ta); +} + /* ************************************************************************* */ // We read the BAL file, which has 3 cameras in it, with poses. We then assume // the rotations are correct, but translations have to be estimated from @@ -47,30 +58,25 @@ TEST(TranslationRecovery, BAL) { const auto relativeTranslations = TranslationRecovery::SimulateMeasurements( poses, {{0, 1}, {0, 2}, {1, 2}}); - // Check - Unit3 w_aZb_stored; // measurement between 0 and 1 stored for next unit test + // Check simulated measurements. for (auto& unitTranslation : relativeTranslations) { - const Pose3 wTa = poses.at(unitTranslation.key1()), - wTb = poses.at(unitTranslation.key2()); - const Point3 Ta = wTa.translation(), Tb = wTb.translation(); - const Unit3 w_aZb = unitTranslation.measured(); - EXPECT(assert_equal(Unit3(Tb - Ta), w_aZb)); - if (unitTranslation.key1() == 0 && unitTranslation.key2() == 1) { - w_aZb_stored = unitTranslation.measured(); - } + EXPECT(assert_equal(GetDirectionFromPoses(poses, unitTranslation), + unitTranslation.measured())); } TranslationRecovery algorithm(relativeTranslations); const auto graph = algorithm.buildGraph(); EXPECT_LONGS_EQUAL(3, graph.size()); - // Translation recovery, version 1 + // Run translation recovery const double scale = 2.0; const auto result = algorithm.run(scale); // Check result for first two translations, determined by prior EXPECT(assert_equal(Point3(0, 0, 0), result.at(0))); - EXPECT(assert_equal(Point3(2 * w_aZb_stored.point3()), result.at(1))); + EXPECT(assert_equal( + Point3(2 * GetDirectionFromPoses(poses, relativeTranslations[0])), + result.at(1))); // Check that the third translations is correct Point3 Ta = poses.at(0).translation(); @@ -83,53 +89,120 @@ TEST(TranslationRecovery, BAL) { // EXPECT_DOUBLES_EQUAL(0.0199833, actualError, 1e-5); } -TEST(TranslationRecovery, ZeroRelativeTranslations) { - // Create a graph with 3 cameras. +TEST(TranslationRecovery, TwoPointTest) { + // Create a dataset with 2 poses. // __ __ // \/ \/ // 0 _____ 1 - // 2 <| // - // 0 and 1 face in the same direction but have a translation offset. 2 is at - // the same point as 1 but is rotated, with very little FOV overlap. + // 0 and 1 face in the same direction but have a translation offset. Values poses; - poses.insert(0, Pose3(Rot3(), Point3())); - poses.insert(1, Pose3(Rot3(), Point3(2, 0, 0))); - poses.insert(2, Pose3(Rot3::RzRyRx(-M_PI / 2, 0, 0), Point3(2, 0, 0))); + poses.insert(0, Pose3(Rot3(), Point3(0, 0, 0))); + poses.insert(1, Pose3(Rot3(), Point3(2, 0, 0))); auto relativeTranslations = - TranslationRecovery::SimulateMeasurements(poses, {{0, 1}, {1, 2}}); + TranslationRecovery::SimulateMeasurements(poses, {{0, 1}}); - // Check + // Check simulated measurements. for (auto& unitTranslation : relativeTranslations) { - const Pose3 wTa = poses.at(unitTranslation.key1()), - wTb = poses.at(unitTranslation.key2()); - const Point3 Ta = wTa.translation(), Tb = wTb.translation(); - const Unit3 w_aZb = unitTranslation.measured(); - EXPECT(assert_equal(Unit3(Tb - Ta), w_aZb)); + EXPECT(assert_equal(GetDirectionFromPoses(poses, unitTranslation), + unitTranslation.measured())); } TranslationRecovery algorithm(relativeTranslations); const auto graph = algorithm.buildGraph(); EXPECT_LONGS_EQUAL(1, graph.size()); - // Translation recovery, version 1 - const double scale = 2.0; - const auto result = algorithm.run(scale); + // Run translation recovery + const auto result = algorithm.run(/*scale=*/2.0); // Check result for first two translations, determined by prior EXPECT(assert_equal(Point3(0, 0, 0), result.at(0))); EXPECT(assert_equal(Point3(2, 0, 0), result.at(1))); +} + +TEST(TranslationRecovery, ThreePointTest) { + // Create a dataset with 3 poses. + // __ __ + // \/ \/ + // 0 _____ 1 + // \ __ / + // \\// + // 3 + // + // 0 and 1 face in the same direction but have a translation offset. 3 is in + // the same direction as 0 and 1, in between 0 and 1, with some Y axis offset. + + Values poses; + poses.insert(0, Pose3(Rot3(), Point3(0, 0, 0))); + poses.insert(1, Pose3(Rot3(), Point3(2, 0, 0))); + poses.insert(3, Pose3(Rot3(), Point3(1, -1, 0))); + + auto relativeTranslations = TranslationRecovery::SimulateMeasurements( + poses, {{0, 1}, {1, 3}, {3, 0}}); + + // Check simulated measurements. + for (auto& unitTranslation : relativeTranslations) { + EXPECT(assert_equal(GetDirectionFromPoses(poses, unitTranslation), + unitTranslation.measured())); + } + + TranslationRecovery algorithm(relativeTranslations); + const auto graph = algorithm.buildGraph(); + EXPECT_LONGS_EQUAL(3, graph.size()); + + const auto result = algorithm.run(/*scale=*/2.0); + + // Check result + EXPECT(assert_equal(Point3(0, 0, 0), result.at(0))); + EXPECT(assert_equal(Point3(2, 0, 0), result.at(1))); + EXPECT(assert_equal(Point3(1, -1, 0), result.at(3))); +} + +TEST(TranslationRecovery, TwoPointsAndZeroTranslation) { + // Create a dataset with 3 poses. + // __ __ + // \/ \/ + // 0 _____ 1 + // 2 <| + // + // 0 and 1 face in the same direction but have a translation offset. 2 is at + // the same point as 1 but is rotated, with little FOV overlap. + Values poses; + poses.insert(0, Pose3(Rot3(), Point3(0, 0, 0))); + poses.insert(1, Pose3(Rot3(), Point3(2, 0, 0))); + poses.insert(2, Pose3(Rot3::RzRyRx(-M_PI / 2, 0, 0), Point3(2, 0, 0))); + + auto relativeTranslations = + TranslationRecovery::SimulateMeasurements(poses, {{0, 1}, {1, 2}}); + + // Check simulated measurements. + for (auto& unitTranslation : relativeTranslations) { + EXPECT(assert_equal(GetDirectionFromPoses(poses, unitTranslation), + unitTranslation.measured())); + } + + TranslationRecovery algorithm(relativeTranslations); + const auto graph = algorithm.buildGraph(); + // There is only 1 non-zero translation edge. + EXPECT_LONGS_EQUAL(1, graph.size()); + + // Run translation recovery + const auto result = algorithm.run(/*scale=*/2.0); + + // Check result + EXPECT(assert_equal(Point3(0, 0, 0), result.at(0))); + EXPECT(assert_equal(Point3(2, 0, 0), result.at(1))); EXPECT(assert_equal(Point3(2, 0, 0), result.at(2))); } -TEST(TranslationRecovery, ZeroRelativeTranslations4Cameras) { - // Create a graph with 4 cameras. +TEST(TranslationRecovery, ThreePointsAndZeroTranslation) { + // Create a dataset with 4 poses. // __ __ // \/ \/ // 0 _____ 1 - // \ 2 <| - // \ / + // \ __ 2 <| + // \\// // 3 // // 0 and 1 face in the same direction but have a translation offset. 2 is at @@ -137,32 +210,28 @@ TEST(TranslationRecovery, ZeroRelativeTranslations4Cameras) { // the same direction as 0 and 1, in between 0 and 1, with some Y axis offset. Values poses; - poses.insert(0, Pose3(Rot3(), Point3())); - poses.insert(1, Pose3(Rot3(), Point3(2, 0, 0))); - poses.insert(2, Pose3(Rot3::RzRyRx(-M_PI / 2, 0, 0), Point3(2, 0, 0))); - poses.insert(3, Pose3(Rot3(), Point3(1, -1, 0))); + poses.insert(0, Pose3(Rot3(), Point3(0, 0, 0))); + poses.insert(1, Pose3(Rot3(), Point3(2, 0, 0))); + poses.insert(2, Pose3(Rot3::RzRyRx(-M_PI / 2, 0, 0), Point3(2, 0, 0))); + poses.insert(3, Pose3(Rot3(), Point3(1, -1, 0))); auto relativeTranslations = TranslationRecovery::SimulateMeasurements( poses, {{0, 1}, {1, 2}, {1, 3}, {3, 0}}); - // Check + // Check simulated measurements. for (auto& unitTranslation : relativeTranslations) { - const Pose3 wTa = poses.at(unitTranslation.key1()), - wTb = poses.at(unitTranslation.key2()); - const Point3 Ta = wTa.translation(), Tb = wTb.translation(); - const Unit3 w_aZb = unitTranslation.measured(); - EXPECT(assert_equal(Unit3(Tb - Ta), w_aZb)); + EXPECT(assert_equal(GetDirectionFromPoses(poses, unitTranslation), + unitTranslation.measured())); } TranslationRecovery algorithm(relativeTranslations); const auto graph = algorithm.buildGraph(); EXPECT_LONGS_EQUAL(3, graph.size()); - // Translation recovery, version 1 - const double scale = 2.0; - const auto result = algorithm.run(scale); + // Run translation recovery + const auto result = algorithm.run(/*scale=*/2.0); - // Check result for first two translations, determined by prior + // Check result EXPECT(assert_equal(Point3(0, 0, 0), result.at(0))); EXPECT(assert_equal(Point3(2, 0, 0), result.at(1))); EXPECT(assert_equal(Point3(2, 0, 0), result.at(2))); From e4c738dabf9b603cdbd26e2214611bd211bbcde9 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 06:40:54 -0500 Subject: [PATCH 087/261] Deprecate SimpleCamera properly --- gtsam/geometry/SimpleCamera.cpp | 2 ++ gtsam/geometry/SimpleCamera.h | 17 ++++++++-- gtsam/gtsam.i | 59 +++++---------------------------- 3 files changed, 25 insertions(+), 53 deletions(-) diff --git a/gtsam/geometry/SimpleCamera.cpp b/gtsam/geometry/SimpleCamera.cpp index 6134ae3d4..d1a5ed330 100644 --- a/gtsam/geometry/SimpleCamera.cpp +++ b/gtsam/geometry/SimpleCamera.cpp @@ -21,6 +21,7 @@ namespace gtsam { +#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V41 SimpleCamera simpleCamera(const Matrix34& P) { // P = [A|a] = s K cRw [I|-T], with s the unknown scale @@ -45,5 +46,6 @@ namespace gtsam { return SimpleCamera(Pose3(wRc, T), Cal3_S2(K(0, 0), K(1, 1), K(0, 1), K(0, 2), K(1, 2))); } +#endif } diff --git a/gtsam/geometry/SimpleCamera.h b/gtsam/geometry/SimpleCamera.h index 82f26aee2..04746ba6f 100644 --- a/gtsam/geometry/SimpleCamera.h +++ b/gtsam/geometry/SimpleCamera.h @@ -19,14 +19,23 @@ #pragma once #include -#include +#include +#include +#include #include +#include namespace gtsam { - /// A simple camera class with a Cal3_S2 calibration -typedef gtsam::PinholeCamera PinholeCameraCal3_S2; + /// Convenient aliases for Pinhole camera classes with different calibrations. + /// Also needed as forward declarations in the wrapper. + using PinholeCameraCal3_S2 = gtsam::PinholeCamera; + using PinholeCameraCal3Bundler = gtsam::PinholeCamera; + //TODO Need to fix issue 621 for this to work with wrapper + // using PinholeCameraCal3DS2 = gtsam::PinholeCamera; + // using PinholeCameraCal3Unified = gtsam::PinholeCamera; +#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V41 /** * @deprecated: SimpleCamera for backwards compatability with GTSAM 3.x * Use PinholeCameraCal3_S2 instead @@ -140,4 +149,6 @@ struct traits : public internal::Manifold {}; template struct Range : HasRange {}; +#endif + } // namespace gtsam diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 1b4d976da..eb36e73a3 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -329,7 +329,7 @@ virtual class Value { }; #include -template +template virtual class GenericValue : gtsam::Value { void serializable() const; }; @@ -1059,52 +1059,12 @@ class PinholeCamera { void serialize() const; }; +// Forward declaration of PinholeCameraCalX is defined here. #include -virtual class SimpleCamera { - // Standard Constructors and Named Constructors - SimpleCamera(); - SimpleCamera(const gtsam::Pose3& pose); - SimpleCamera(const gtsam::Pose3& pose, const gtsam::Cal3_S2& K); - static gtsam::SimpleCamera Level(const gtsam::Cal3_S2& K, const gtsam::Pose2& pose, double height); - static gtsam::SimpleCamera Level(const gtsam::Pose2& pose, double height); - static gtsam::SimpleCamera Lookat(const gtsam::Point3& eye, const gtsam::Point3& target, - const gtsam::Point3& upVector, const gtsam::Cal3_S2& K); - static gtsam::SimpleCamera Lookat(const gtsam::Point3& eye, const gtsam::Point3& target, - const gtsam::Point3& upVector); - - // Testable - void print(string s) const; - bool equals(const gtsam::SimpleCamera& camera, double tol) const; - - // Standard Interface - gtsam::Pose3 pose() const; - gtsam::Cal3_S2 calibration() const; - - // Manifold - gtsam::SimpleCamera retract(Vector d) const; - Vector localCoordinates(const gtsam::SimpleCamera& T2) const; - size_t dim() const; - static size_t Dim(); - - // Transformations and measurement functions - static gtsam::Point2 Project(const gtsam::Point3& cameraPoint); - pair projectSafe(const gtsam::Point3& pw) const; - gtsam::Point2 project(const gtsam::Point3& point); - gtsam::Point3 backproject(const gtsam::Point2& p, double depth) const; - double range(const gtsam::Point3& point); - double range(const gtsam::Pose3& pose); - - // enabling serialization functionality - void serialize() const; - -}; - -gtsam::SimpleCamera simpleCamera(const Matrix& P); - // Some typedefs for common camera types // PinholeCameraCal3_S2 is the same as SimpleCamera above typedef gtsam::PinholeCamera PinholeCameraCal3_S2; -//TODO (Issue 237) due to lack of jacobians of Cal3DS2_Base::calibrate, PinholeCamera does not apply to Cal3DS2/Unified +//TODO (Issue 621) due to lack of jacobians of Cal3DS2_Base::calibrate, PinholeCamera does not apply to Cal3DS2/Unified //typedef gtsam::PinholeCamera PinholeCameraCal3DS2; //typedef gtsam::PinholeCamera PinholeCameraCal3Unified; typedef gtsam::PinholeCamera PinholeCameraCal3Bundler; @@ -1150,7 +1110,7 @@ gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, gtsam::Cal3Bundler* sharedCal, const gtsam::Point2Vector& measurements, double rank_tol, bool optimize); - + //************************************************************************* // Symbolic //************************************************************************* @@ -2069,7 +2029,7 @@ class NonlinearFactorGraph { gtsam::KeySet keys() const; gtsam::KeyVector keyVector() const; - template, gtsam::imuBias::ConstantBias}> + template, gtsam::imuBias::ConstantBias}> void addPrior(size_t key, const T& prior, const gtsam::noiseModel::Base* noiseModel); // NonlinearFactorGraph @@ -2493,7 +2453,7 @@ class ISAM2 { template , + gtsam::PinholeCameraCal3_S2, gtsam::PinholeCamera, Vector, Matrix}> VALUE calculateEstimate(size_t key) const; gtsam::Values calculateBestEstimate() const; @@ -2527,12 +2487,11 @@ class NonlinearISAM { //************************************************************************* // Nonlinear factor types //************************************************************************* -#include #include #include #include -template}> +template}> virtual class PriorFactor : gtsam::NoiseModelFactor { PriorFactor(size_t key, const T& prior, const gtsam::noiseModel::Base* noiseModel); T prior() const; @@ -2556,7 +2515,7 @@ virtual class BetweenFactor : gtsam::NoiseModelFactor { template virtual class NonlinearEquality : gtsam::NoiseModelFactor { // Constructor - forces exact evaluation @@ -2675,7 +2634,7 @@ virtual class GeneralSFMFactor : gtsam::NoiseModelFactor { gtsam::Point2 measured() const; }; typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3_S2; -//TODO (Issue 237) due to lack of jacobians of Cal3DS2_Base::calibrate, GeneralSFMFactor does not apply to Cal3DS2 +//TODO (Issue 621) due to lack of jacobians of Cal3DS2_Base::calibrate, GeneralSFMFactor does not apply to Cal3DS2 //typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; typedef gtsam::GeneralSFMFactor, gtsam::Point3> GeneralSFMFactorCal3Bundler; From 2703307a430cf7dd6ea58dd63e95d8b6795ba30c Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 06:44:45 -0500 Subject: [PATCH 088/261] deprecate SimpleCamera tests --- gtsam/geometry/tests/testSimpleCamera.cpp | 4 ++++ gtsam_unstable/slam/serialization.cpp | 27 ++++++++++++++------- tests/testSerializationSLAM.cpp | 29 +++++++++++------------ 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/gtsam/geometry/tests/testSimpleCamera.cpp b/gtsam/geometry/tests/testSimpleCamera.cpp index edf122d3c..18a25c553 100644 --- a/gtsam/geometry/tests/testSimpleCamera.cpp +++ b/gtsam/geometry/tests/testSimpleCamera.cpp @@ -26,6 +26,8 @@ using namespace std; using namespace gtsam; +#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V41 + static const Cal3_S2 K(625, 625, 0, 0, 0); static const Pose3 pose1(Rot3(Vector3(1, -1, -1).asDiagonal()), @@ -149,6 +151,8 @@ TEST( SimpleCamera, simpleCamera) CHECK(assert_equal(expected, actual,1e-1)); } +#endif + /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } /* ************************************************************************* */ diff --git a/gtsam_unstable/slam/serialization.cpp b/gtsam_unstable/slam/serialization.cpp index 8a661f2ef..803e4353a 100644 --- a/gtsam_unstable/slam/serialization.cpp +++ b/gtsam_unstable/slam/serialization.cpp @@ -43,7 +43,6 @@ typedef PriorFactor PriorFactorPose3; typedef PriorFactor PriorFactorCal3_S2; typedef PriorFactor PriorFactorCal3DS2; typedef PriorFactor PriorFactorCalibratedCamera; -typedef PriorFactor PriorFactorSimpleCamera; typedef PriorFactor PriorFactorPinholeCameraCal3_S2; typedef PriorFactor PriorFactorStereoCamera; @@ -68,7 +67,6 @@ typedef NonlinearEquality NonlinearEqualityPose3; typedef NonlinearEquality NonlinearEqualityCal3_S2; typedef NonlinearEquality NonlinearEqualityCal3DS2; typedef NonlinearEquality NonlinearEqualityCalibratedCamera; -typedef NonlinearEquality NonlinearEqualitySimpleCamera; typedef NonlinearEquality NonlinearEqualityPinholeCameraCal3_S2; typedef NonlinearEquality NonlinearEqualityStereoCamera; @@ -77,10 +75,8 @@ typedef RangeFactor RangeFactor3D; typedef RangeFactor RangeFactorPose2; typedef RangeFactor RangeFactorPose3; typedef RangeFactor RangeFactorCalibratedCameraPoint; -typedef RangeFactor RangeFactorSimpleCameraPoint; typedef RangeFactor RangeFactorPinholeCameraCal3_S2Point; typedef RangeFactor RangeFactorCalibratedCamera; -typedef RangeFactor RangeFactorSimpleCamera; typedef RangeFactor RangeFactorPinholeCameraCal3_S2; typedef BearingRangeFactor BearingRangeFactor2D; @@ -90,6 +86,7 @@ typedef GenericProjectionFactor GenericProjectionFactorC typedef GenericProjectionFactor GenericProjectionFactorCal3DS2; typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3_S2; +//TODO fix issue 621 //typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; typedef gtsam::GeneralSFMFactor2 GeneralSFMFactor2Cal3_S2; @@ -129,7 +126,6 @@ GTSAM_VALUE_EXPORT(gtsam::Cal3_S2); GTSAM_VALUE_EXPORT(gtsam::Cal3DS2); GTSAM_VALUE_EXPORT(gtsam::Cal3_S2Stereo); GTSAM_VALUE_EXPORT(gtsam::CalibratedCamera); -GTSAM_VALUE_EXPORT(gtsam::SimpleCamera); GTSAM_VALUE_EXPORT(gtsam::PinholeCameraCal3_S2); GTSAM_VALUE_EXPORT(gtsam::StereoCamera); @@ -150,7 +146,6 @@ BOOST_CLASS_EXPORT_GUID(PriorFactorPose3, "gtsam::PriorFactorPose3"); BOOST_CLASS_EXPORT_GUID(PriorFactorCal3_S2, "gtsam::PriorFactorCal3_S2"); BOOST_CLASS_EXPORT_GUID(PriorFactorCal3DS2, "gtsam::PriorFactorCal3DS2"); BOOST_CLASS_EXPORT_GUID(PriorFactorCalibratedCamera, "gtsam::PriorFactorCalibratedCamera"); -BOOST_CLASS_EXPORT_GUID(PriorFactorSimpleCamera, "gtsam::PriorFactorSimpleCamera"); BOOST_CLASS_EXPORT_GUID(PriorFactorStereoCamera, "gtsam::PriorFactorStereoCamera"); BOOST_CLASS_EXPORT_GUID(BetweenFactorLieVector, "gtsam::BetweenFactorLieVector"); @@ -174,7 +169,6 @@ BOOST_CLASS_EXPORT_GUID(NonlinearEqualityPose3, "gtsam::NonlinearEqualityPose3") BOOST_CLASS_EXPORT_GUID(NonlinearEqualityCal3_S2, "gtsam::NonlinearEqualityCal3_S2"); BOOST_CLASS_EXPORT_GUID(NonlinearEqualityCal3DS2, "gtsam::NonlinearEqualityCal3DS2"); BOOST_CLASS_EXPORT_GUID(NonlinearEqualityCalibratedCamera, "gtsam::NonlinearEqualityCalibratedCamera"); -BOOST_CLASS_EXPORT_GUID(NonlinearEqualitySimpleCamera, "gtsam::NonlinearEqualitySimpleCamera"); BOOST_CLASS_EXPORT_GUID(NonlinearEqualityStereoCamera, "gtsam::NonlinearEqualityStereoCamera"); BOOST_CLASS_EXPORT_GUID(RangeFactor2D, "gtsam::RangeFactor2D"); @@ -182,9 +176,7 @@ BOOST_CLASS_EXPORT_GUID(RangeFactor3D, "gtsam::RangeFactor3D"); BOOST_CLASS_EXPORT_GUID(RangeFactorPose2, "gtsam::RangeFactorPose2"); BOOST_CLASS_EXPORT_GUID(RangeFactorPose3, "gtsam::RangeFactorPose3"); BOOST_CLASS_EXPORT_GUID(RangeFactorCalibratedCameraPoint, "gtsam::RangeFactorCalibratedCameraPoint"); -BOOST_CLASS_EXPORT_GUID(RangeFactorSimpleCameraPoint, "gtsam::RangeFactorSimpleCameraPoint"); BOOST_CLASS_EXPORT_GUID(RangeFactorCalibratedCamera, "gtsam::RangeFactorCalibratedCamera"); -BOOST_CLASS_EXPORT_GUID(RangeFactorSimpleCamera, "gtsam::RangeFactorSimpleCamera"); BOOST_CLASS_EXPORT_GUID(BearingRangeFactor2D, "gtsam::BearingRangeFactor2D"); @@ -192,12 +184,29 @@ BOOST_CLASS_EXPORT_GUID(GenericProjectionFactorCal3_S2, "gtsam::GenericProjectio BOOST_CLASS_EXPORT_GUID(GenericProjectionFactorCal3DS2, "gtsam::GenericProjectionFactorCal3DS2"); BOOST_CLASS_EXPORT_GUID(GeneralSFMFactorCal3_S2, "gtsam::GeneralSFMFactorCal3_S2"); +//TODO Fix issue 621 //BOOST_CLASS_EXPORT_GUID(GeneralSFMFactorCal3DS2, "gtsam::GeneralSFMFactorCal3DS2"); BOOST_CLASS_EXPORT_GUID(GeneralSFMFactor2Cal3_S2, "gtsam::GeneralSFMFactor2Cal3_S2"); BOOST_CLASS_EXPORT_GUID(GenericStereoFactor3D, "gtsam::GenericStereoFactor3D"); +#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V41 + +typedef PriorFactor PriorFactorSimpleCamera; +typedef NonlinearEquality NonlinearEqualitySimpleCamera; +typedef RangeFactor RangeFactorSimpleCameraPoint; +typedef RangeFactor RangeFactorSimpleCamera; + +GTSAM_VALUE_EXPORT(gtsam::SimpleCamera); +BOOST_CLASS_EXPORT_GUID(PriorFactorSimpleCamera, "gtsam::PriorFactorSimpleCamera"); +BOOST_CLASS_EXPORT_GUID(NonlinearEqualitySimpleCamera, "gtsam::NonlinearEqualitySimpleCamera"); +BOOST_CLASS_EXPORT_GUID(RangeFactorSimpleCameraPoint, "gtsam::RangeFactorSimpleCameraPoint"); +BOOST_CLASS_EXPORT_GUID(RangeFactorSimpleCamera, "gtsam::RangeFactorSimpleCamera"); + +#endif + + /* ************************************************************************* */ // Actual implementations of functions /* ************************************************************************* */ diff --git a/tests/testSerializationSLAM.cpp b/tests/testSerializationSLAM.cpp index 84e521156..53086e921 100644 --- a/tests/testSerializationSLAM.cpp +++ b/tests/testSerializationSLAM.cpp @@ -89,10 +89,8 @@ typedef RangeFactor RangeFactor3D; typedef RangeFactor RangeFactorPose2; typedef RangeFactor RangeFactorPose3; typedef RangeFactor RangeFactorCalibratedCameraPoint; -typedef RangeFactor RangeFactorSimpleCameraPoint; typedef RangeFactor RangeFactorPinholeCameraCal3_S2Point; typedef RangeFactor RangeFactorCalibratedCamera; -typedef RangeFactor RangeFactorSimpleCamera; typedef RangeFactor RangeFactorPinholeCameraCal3_S2; typedef BearingRangeFactor BearingRangeFactor2D; @@ -102,6 +100,7 @@ typedef GenericProjectionFactor GenericProjectionFactorC typedef GenericProjectionFactor GenericProjectionFactorCal3DS2; typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3_S2; +//TODO Fix issue 621 for this to work //typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; typedef gtsam::GeneralSFMFactor2 GeneralSFMFactor2Cal3_S2; @@ -145,7 +144,6 @@ GTSAM_VALUE_EXPORT(gtsam::Cal3_S2); GTSAM_VALUE_EXPORT(gtsam::Cal3DS2); GTSAM_VALUE_EXPORT(gtsam::Cal3_S2Stereo); GTSAM_VALUE_EXPORT(gtsam::CalibratedCamera); -GTSAM_VALUE_EXPORT(gtsam::SimpleCamera); GTSAM_VALUE_EXPORT(gtsam::PinholeCameraCal3_S2); GTSAM_VALUE_EXPORT(gtsam::StereoCamera); @@ -190,9 +188,9 @@ BOOST_CLASS_EXPORT_GUID(RangeFactor3D, "gtsam::RangeFactor3D"); BOOST_CLASS_EXPORT_GUID(RangeFactorPose2, "gtsam::RangeFactorPose2"); BOOST_CLASS_EXPORT_GUID(RangeFactorPose3, "gtsam::RangeFactorPose3"); BOOST_CLASS_EXPORT_GUID(RangeFactorCalibratedCameraPoint, "gtsam::RangeFactorCalibratedCameraPoint"); -BOOST_CLASS_EXPORT_GUID(RangeFactorSimpleCameraPoint, "gtsam::RangeFactorSimpleCameraPoint"); +BOOST_CLASS_EXPORT_GUID(RangeFactorPinholeCameraCal3_S2Point, "gtsam::RangeFactorPinholeCameraCal3_S2Point"); BOOST_CLASS_EXPORT_GUID(RangeFactorCalibratedCamera, "gtsam::RangeFactorCalibratedCamera"); -BOOST_CLASS_EXPORT_GUID(RangeFactorSimpleCamera, "gtsam::RangeFactorSimpleCamera"); +BOOST_CLASS_EXPORT_GUID(RangeFactorPinholeCameraCal3_S2, "gtsam::RangeFactorPinholeCameraCal3_S2"); BOOST_CLASS_EXPORT_GUID(BearingRangeFactor2D, "gtsam::BearingRangeFactor2D"); @@ -200,6 +198,7 @@ BOOST_CLASS_EXPORT_GUID(GenericProjectionFactorCal3_S2, "gtsam::GenericProjectio BOOST_CLASS_EXPORT_GUID(GenericProjectionFactorCal3DS2, "gtsam::GenericProjectionFactorCal3DS2"); BOOST_CLASS_EXPORT_GUID(GeneralSFMFactorCal3_S2, "gtsam::GeneralSFMFactorCal3_S2"); +//TODO fix issue 621 //BOOST_CLASS_EXPORT_GUID(GeneralSFMFactorCal3DS2, "gtsam::GeneralSFMFactorCal3DS2"); BOOST_CLASS_EXPORT_GUID(GeneralSFMFactor2Cal3_S2, "gtsam::GeneralSFMFactor2Cal3_S2"); @@ -352,9 +351,9 @@ TEST (testSerializationSLAM, factors) { RangeFactorPose2 rangeFactorPose2(a08, b08, 2.0, model1); RangeFactorPose3 rangeFactorPose3(a09, b09, 2.0, model1); RangeFactorCalibratedCameraPoint rangeFactorCalibratedCameraPoint(a12, a05, 2.0, model1); - RangeFactorSimpleCameraPoint rangeFactorSimpleCameraPoint(a13, a05, 2.0, model1); + RangeFactorPinholeCameraCal3_S2Point rangeFactorPinholeCameraCal3_S2Point(a13, a05, 2.0, model1); RangeFactorCalibratedCamera rangeFactorCalibratedCamera(a12, b12, 2.0, model1); - RangeFactorSimpleCamera rangeFactorSimpleCamera(a13, b13, 2.0, model1); + RangeFactorPinholeCameraCal3_S2 rangeFactorPinholeCameraCal3_S2(a13, b13, 2.0, model1); BearingRangeFactor2D bearingRangeFactor2D(a08, a03, rot2, 2.0, model2); @@ -405,9 +404,9 @@ TEST (testSerializationSLAM, factors) { graph += rangeFactorPose2; graph += rangeFactorPose3; graph += rangeFactorCalibratedCameraPoint; - graph += rangeFactorSimpleCameraPoint; + graph += rangeFactorPinholeCameraCal3_S2Point; graph += rangeFactorCalibratedCamera; - graph += rangeFactorSimpleCamera; + graph += rangeFactorPinholeCameraCal3_S2; graph += bearingRangeFactor2D; @@ -463,9 +462,9 @@ TEST (testSerializationSLAM, factors) { EXPECT(equalsObj(rangeFactorPose2)); EXPECT(equalsObj(rangeFactorPose3)); EXPECT(equalsObj(rangeFactorCalibratedCameraPoint)); - EXPECT(equalsObj(rangeFactorSimpleCameraPoint)); + EXPECT(equalsObj(rangeFactorPinholeCameraCal3_S2Point)); EXPECT(equalsObj(rangeFactorCalibratedCamera)); - EXPECT(equalsObj(rangeFactorSimpleCamera)); + EXPECT(equalsObj(rangeFactorPinholeCameraCal3_S2)); EXPECT(equalsObj(bearingRangeFactor2D)); @@ -521,9 +520,9 @@ TEST (testSerializationSLAM, factors) { EXPECT(equalsXML(rangeFactorPose2)); EXPECT(equalsXML(rangeFactorPose3)); EXPECT(equalsXML(rangeFactorCalibratedCameraPoint)); - EXPECT(equalsXML(rangeFactorSimpleCameraPoint)); + EXPECT(equalsXML(rangeFactorPinholeCameraCal3_S2Point)); EXPECT(equalsXML(rangeFactorCalibratedCamera)); - EXPECT(equalsXML(rangeFactorSimpleCamera)); + EXPECT(equalsXML(rangeFactorPinholeCameraCal3_S2)); EXPECT(equalsXML(bearingRangeFactor2D)); @@ -579,9 +578,9 @@ TEST (testSerializationSLAM, factors) { EXPECT(equalsBinary(rangeFactorPose2)); EXPECT(equalsBinary(rangeFactorPose3)); EXPECT(equalsBinary(rangeFactorCalibratedCameraPoint)); - EXPECT(equalsBinary(rangeFactorSimpleCameraPoint)); + EXPECT(equalsBinary(rangeFactorPinholeCameraCal3_S2Point)); EXPECT(equalsBinary(rangeFactorCalibratedCamera)); - EXPECT(equalsBinary(rangeFactorSimpleCamera)); + EXPECT(equalsBinary(rangeFactorPinholeCameraCal3_S2)); EXPECT(equalsBinary(bearingRangeFactor2D)); From 5cb45e7e2516ba8059c0a1c3410455754af5e271 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Mon, 30 Nov 2020 10:06:29 -0500 Subject: [PATCH 089/261] Fixed typo --- gtsam/linear/SubgraphBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/linear/SubgraphBuilder.cpp b/gtsam/linear/SubgraphBuilder.cpp index 738c101db..1919d38be 100644 --- a/gtsam/linear/SubgraphBuilder.cpp +++ b/gtsam/linear/SubgraphBuilder.cpp @@ -383,7 +383,7 @@ Subgraph SubgraphBuilder::operator()(const GaussianFactorGraph &gfg) const { const vector tree = buildTree(gfg, forward_ordering, weights); if (tree.size() != n - 1) { throw std::runtime_error( - "SubgraphBuilder::operator() failure: tree.size() != n-1, might caused by disconnected graph"); + "SubgraphBuilder::operator() failure: tree.size() != n-1, might be caused by disconnected graph"); } // Downweight the tree edges to zero. From e1c3314e485b82ba231ea853ac8da01a1d43d14d Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 10:35:34 -0500 Subject: [PATCH 090/261] Jacobians for Camera models - Add jacobians for calibrate function using implicit function theorem - Consistent naming of jacobian parameters - Added tests for jacobians - Some simple formatting - Fixed docs for implicit function theorem - Added parentheses to conform with Google style --- gtsam/geometry/Cal3Bundler.cpp | 4 +- gtsam/geometry/Cal3DS2.h | 4 +- gtsam/geometry/Cal3DS2_Base.cpp | 72 ++++++++++++++++++------ gtsam/geometry/Cal3DS2_Base.h | 42 ++++++++++---- gtsam/geometry/Cal3Unified.cpp | 42 ++++++++++---- gtsam/geometry/Cal3Unified.h | 4 +- gtsam/geometry/tests/testCal3DS2.cpp | 22 ++++++-- gtsam/geometry/tests/testCal3Unified.cpp | 16 ++++++ 8 files changed, 159 insertions(+), 47 deletions(-) diff --git a/gtsam/geometry/Cal3Bundler.cpp b/gtsam/geometry/Cal3Bundler.cpp index b198643b0..36e7bf62d 100644 --- a/gtsam/geometry/Cal3Bundler.cpp +++ b/gtsam/geometry/Cal3Bundler.cpp @@ -124,8 +124,8 @@ Point2 Cal3Bundler::calibrate(const Point2& pi, // We make use of the Implicit Function Theorem to compute the Jacobians from uncalibrate // Given f(pi, pn) = uncalibrate(pn) - pi, and g(pi) = calibrate, we can easily compute the Jacobians // df/pi = -I (pn and pi are independent args) - // Dcal = -inv(H_uncal_pn) * df/pi = -inv(H_uncal_pn) * (-I) = inv(H_uncal_pn) - // Dp = -inv(H_uncal_pn) * df/K = -inv(H_uncal_pn) * H_uncal_K + // Dp = -inv(H_uncal_pn) * df/pi = -inv(H_uncal_pn) * (-I) = inv(H_uncal_pn) + // Dcal = -inv(H_uncal_pn) * df/K = -inv(H_uncal_pn) * H_uncal_K Matrix23 H_uncal_K; Matrix22 H_uncal_pn, H_uncal_pn_inv; diff --git a/gtsam/geometry/Cal3DS2.h b/gtsam/geometry/Cal3DS2.h index 7fd453d45..e66c3d124 100644 --- a/gtsam/geometry/Cal3DS2.h +++ b/gtsam/geometry/Cal3DS2.h @@ -44,8 +44,8 @@ public: Cal3DS2() : Base() {} Cal3DS2(double fx, double fy, double s, double u0, double v0, - double k1, double k2, double p1 = 0.0, double p2 = 0.0) : - Base(fx, fy, s, u0, v0, k1, k2, p1, p2) {} + double k1, double k2, double p1 = 0.0, double p2 = 0.0, double tol = 1e-5) : + Base(fx, fy, s, u0, v0, k1, k2, p1, p2, tol) {} virtual ~Cal3DS2() {} diff --git a/gtsam/geometry/Cal3DS2_Base.cpp b/gtsam/geometry/Cal3DS2_Base.cpp index 6c03883ce..c5ef117a7 100644 --- a/gtsam/geometry/Cal3DS2_Base.cpp +++ b/gtsam/geometry/Cal3DS2_Base.cpp @@ -13,6 +13,7 @@ * @file Cal3DS2_Base.cpp * @date Feb 28, 2010 * @author ydjian + * @author Varun Agrawal */ #include @@ -24,8 +25,17 @@ namespace gtsam { /* ************************************************************************* */ -Cal3DS2_Base::Cal3DS2_Base(const Vector &v): - fx_(v[0]), fy_(v[1]), s_(v[2]), u0_(v[3]), v0_(v[4]), k1_(v[5]), k2_(v[6]), p1_(v[7]), p2_(v[8]){} +Cal3DS2_Base::Cal3DS2_Base(const Vector& v) + : fx_(v(0)), + fy_(v(1)), + s_(v(2)), + u0_(v(3)), + v0_(v(4)), + k1_(v(5)), + k2_(v(6)), + p1_(v(7)), + p2_(v(8)), + tol_(1e-5) {} /* ************************************************************************* */ Matrix3 Cal3DS2_Base::K() const { @@ -94,9 +104,8 @@ static Matrix2 D2dintrinsic(double x, double y, double rr, } /* ************************************************************************* */ -Point2 Cal3DS2_Base::uncalibrate(const Point2& p, - OptionalJacobian<2,9> H1, OptionalJacobian<2,2> H2) const { - +Point2 Cal3DS2_Base::uncalibrate(const Point2& p, OptionalJacobian<2, 9> Dcal, + OptionalJacobian<2, 2> Dp) const { // rr = x^2 + y^2; // g = (1 + k(1)*rr + k(2)*rr^2); // dp = [2*k(3)*x*y + k(4)*(rr + 2*x^2); 2*k(4)*x*y + k(3)*(rr + 2*y^2)]; @@ -115,37 +124,44 @@ Point2 Cal3DS2_Base::uncalibrate(const Point2& p, const double pny = g * y + dy; Matrix2 DK; - if (H1 || H2) DK << fx_, s_, 0.0, fy_; + if (Dcal || Dp) { + DK << fx_, s_, 0.0, fy_; + } // Derivative for calibration - if (H1) - *H1 = D2dcalibration(x, y, xx, yy, xy, rr, r4, pnx, pny, DK); + if (Dcal) { + *Dcal = D2dcalibration(x, y, xx, yy, xy, rr, r4, pnx, pny, DK); + } // Derivative for points - if (H2) - *H2 = D2dintrinsic(x, y, rr, g, k1_, k2_, p1_, p2_, DK); + if (Dp) { + *Dp = D2dintrinsic(x, y, rr, g, k1_, k2_, p1_, p2_, DK); + } // Regular uncalibrate after distortion return Point2(fx_ * pnx + s_ * pny + u0_, fy_ * pny + v0_); } /* ************************************************************************* */ -Point2 Cal3DS2_Base::calibrate(const Point2& pi, const double tol) const { +Point2 Cal3DS2_Base::calibrate(const Point2& pi, OptionalJacobian<2, 9> Dcal, + OptionalJacobian<2, 2> Dp) const { // Use the following fixed point iteration to invert the radial distortion. // pn_{t+1} = (inv(K)*pi - dp(pn_{t})) / g(pn_{t}) - const Point2 invKPi ((1 / fx_) * (pi.x() - u0_ - (s_ / fy_) * (pi.y() - v0_)), - (1 / fy_) * (pi.y() - v0_)); + const Point2 invKPi((1 / fx_) * (pi.x() - u0_ - (s_ / fy_) * (pi.y() - v0_)), + (1 / fy_) * (pi.y() - v0_)); - // initialize by ignoring the distortion at all, might be problematic for pixels around boundary + // initialize by ignoring the distortion at all, might be problematic for + // pixels around boundary Point2 pn = invKPi; // iterate until the uncalibrate is close to the actual pixel coordinate const int maxIterations = 10; int iteration; for (iteration = 0; iteration < maxIterations; ++iteration) { - if (distance2(uncalibrate(pn), pi) <= tol) break; - const double x = pn.x(), y = pn.y(), xy = x * y, xx = x * x, yy = y * y; + if (distance2(uncalibrate(pn), pi) <= tol_) break; + const double px = pn.x(), py = pn.y(), xy = px * py, xx = px * px, + yy = py * py; const double rr = xx + yy; const double g = (1 + k1_ * rr + k2_ * rr * rr); const double dx = 2 * p1_ * xy + p2_ * (rr + 2 * xx); @@ -153,8 +169,28 @@ Point2 Cal3DS2_Base::calibrate(const Point2& pi, const double tol) const { pn = (invKPi - Point2(dx, dy)) / g; } - if ( iteration >= maxIterations ) - throw std::runtime_error("Cal3DS2::calibrate fails to converge. need a better initialization"); + if (iteration >= maxIterations) + throw std::runtime_error( + "Cal3DS2::calibrate fails to converge. need a better initialization"); + + // We make use of the Implicit Function Theorem to compute the Jacobians from uncalibrate + // Given f(pi, pn) = uncalibrate(pn) - pi, and g(pi) = calibrate, we can easily compute the Jacobians + // df/pi = -I (pn and pi are independent args) + // Dp = -inv(H_uncal_pn) * df/pi = -inv(H_uncal_pn) * (-I) = inv(H_uncal_pn) + // Dcal = -inv(H_uncal_pn) * df/K = -inv(H_uncal_pn) * H_uncal_K + Matrix29 H_uncal_K; + Matrix22 H_uncal_pn, H_uncal_pn_inv; + + if (Dcal || Dp) { + // Compute uncalibrate Jacobians + uncalibrate(pn, Dcal ? &H_uncal_K : nullptr, H_uncal_pn); + + H_uncal_pn_inv = H_uncal_pn.inverse(); + + if (Dp) *Dp = H_uncal_pn_inv; + if (Dcal) *Dcal = -H_uncal_pn_inv * H_uncal_K; + + } return pn; } diff --git a/gtsam/geometry/Cal3DS2_Base.h b/gtsam/geometry/Cal3DS2_Base.h index a0ece8bdb..b6d27cda1 100644 --- a/gtsam/geometry/Cal3DS2_Base.h +++ b/gtsam/geometry/Cal3DS2_Base.h @@ -14,6 +14,7 @@ * @brief Calibration of a camera with radial distortion * @date Feb 28, 2010 * @author ydjian + * @author Varun Agrawal */ #pragma once @@ -43,18 +44,38 @@ protected: double fx_, fy_, s_, u0_, v0_ ; // focal length, skew and principal point double k1_, k2_ ; // radial 2nd-order and 4th-order double p1_, p2_ ; // tangential distortion + double tol_; // tolerance value when calibrating public: /// @name Standard Constructors /// @{ - /// Default Constructor with only unit focal length - Cal3DS2_Base() : fx_(1), fy_(1), s_(0), u0_(0), v0_(0), k1_(0), k2_(0), p1_(0), p2_(0) {} + /// Default Constructor with only unit focal length + Cal3DS2_Base() + : fx_(1), + fy_(1), + s_(0), + u0_(0), + v0_(0), + k1_(0), + k2_(0), + p1_(0), + p2_(0), + tol_(1e-5) {} - Cal3DS2_Base(double fx, double fy, double s, double u0, double v0, - double k1, double k2, double p1 = 0.0, double p2 = 0.0) : - fx_(fx), fy_(fy), s_(s), u0_(u0), v0_(v0), k1_(k1), k2_(k2), p1_(p1), p2_(p2) {} + Cal3DS2_Base(double fx, double fy, double s, double u0, double v0, double k1, + double k2, double p1 = 0.0, double p2 = 0.0, double tol = 1e-5) + : fx_(fx), + fy_(fy), + s_(s), + u0_(u0), + v0_(v0), + k1_(k1), + k2_(k2), + p1_(p1), + p2_(p2), + tol_(tol) {} virtual ~Cal3DS2_Base() {} @@ -72,7 +93,7 @@ public: virtual void print(const std::string& s = "") const; /// assert equality up to a tolerance - bool equals(const Cal3DS2_Base& K, double tol = 10e-9) const; + bool equals(const Cal3DS2_Base& K, double tol = 1e-8) const; /// @} /// @name Standard Interface @@ -121,12 +142,12 @@ public: * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates * @return point in (distorted) image coordinates */ - Point2 uncalibrate(const Point2& p, - OptionalJacobian<2,9> Dcal = boost::none, - OptionalJacobian<2,2> Dp = boost::none) const ; + Point2 uncalibrate(const Point2& p, OptionalJacobian<2, 9> Dcal = boost::none, + OptionalJacobian<2, 2> Dp = boost::none) const; /// Convert (distorted) image coordinates uv to intrinsic coordinates xy - Point2 calibrate(const Point2& p, const double tol=1e-5) const; + Point2 calibrate(const Point2& p, OptionalJacobian<2, 9> Dcal = boost::none, + OptionalJacobian<2, 2> Dp = boost::none) const; /// Derivative of uncalibrate wrpt intrinsic coordinates Matrix2 D2d_intrinsic(const Point2& p) const ; @@ -164,6 +185,7 @@ private: ar & BOOST_SERIALIZATION_NVP(k2_); ar & BOOST_SERIALIZATION_NVP(p1_); ar & BOOST_SERIALIZATION_NVP(p2_); + ar & BOOST_SERIALIZATION_NVP(tol_); } /// @} diff --git a/gtsam/geometry/Cal3Unified.cpp b/gtsam/geometry/Cal3Unified.cpp index b1b9c3722..247e77ae1 100644 --- a/gtsam/geometry/Cal3Unified.cpp +++ b/gtsam/geometry/Cal3Unified.cpp @@ -13,6 +13,7 @@ * @file Cal3Unified.cpp * @date Mar 8, 2014 * @author Jing Dong + * @author Varun Agrawal */ #include @@ -54,8 +55,8 @@ bool Cal3Unified::equals(const Cal3Unified& K, double tol) const { /* ************************************************************************* */ // todo: make a fixed sized jacobian version of this Point2 Cal3Unified::uncalibrate(const Point2& p, - OptionalJacobian<2,10> H1, - OptionalJacobian<2,2> H2) const { + OptionalJacobian<2,10> Dcal, + OptionalJacobian<2,2> Dp) const { // this part of code is modified from Cal3DS2, // since the second part of this model (after project to normalized plane) @@ -78,16 +79,16 @@ Point2 Cal3Unified::uncalibrate(const Point2& p, Point2 puncalib = Base::uncalibrate(m, H1base, H2base); // Inlined derivative for calibration - if (H1) { + if (Dcal) { // part1 Vector2 DU; DU << -xs * sqrt_nx * xi_sqrt_nx2, // -ys * sqrt_nx * xi_sqrt_nx2; - *H1 << H1base, H2base * DU; + *Dcal << H1base, H2base * DU; } // Inlined derivative for points - if (H2) { + if (Dp) { // part1 const double denom = 1.0 * xi_sqrt_nx2 / sqrt_nx; const double mid = -(xi * xs*ys) * denom; @@ -95,20 +96,41 @@ Point2 Cal3Unified::uncalibrate(const Point2& p, DU << (sqrt_nx + xi*(ys*ys + 1)) * denom, mid, // mid, (sqrt_nx + xi*(xs*xs + 1)) * denom; - *H2 << H2base * DU; + *Dp << H2base * DU; } return puncalib; } /* ************************************************************************* */ -Point2 Cal3Unified::calibrate(const Point2& pi, const double tol) const { - +Point2 Cal3Unified::calibrate(const Point2& pi, OptionalJacobian<2, 10> Dcal, + OptionalJacobian<2, 2> Dp) const { // calibrate point to Nplane use base class::calibrate() - Point2 pnplane = Base::calibrate(pi, tol); + Point2 pnplane = Base::calibrate(pi); // call nplane to space - return this->nPlaneToSpace(pnplane); + Point2 pn = this->nPlaneToSpace(pnplane); + + // We make use of the Implicit Function Theorem to compute the Jacobians from uncalibrate + // Given f(pi, pn) = uncalibrate(pn) - pi, and g(pi) = calibrate, we can easily compute the Jacobians + // df/pi = -I (pn and pi are independent args) + // Dp = -inv(H_uncal_pn) * df/pi = -inv(H_uncal_pn) * (-I) = inv(H_uncal_pn) + // Dcal = -inv(H_uncal_pn) * df/K = -inv(H_uncal_pn) * H_uncal_K + Eigen::Matrix H_uncal_K; + Matrix22 H_uncal_pn, H_uncal_pn_inv; + + if (Dcal || Dp) { + // Compute uncalibrate Jacobians + uncalibrate(pn, Dcal ? &H_uncal_K : nullptr, H_uncal_pn); + + H_uncal_pn_inv = H_uncal_pn.inverse(); + + if (Dp) *Dp = H_uncal_pn_inv; + if (Dcal) *Dcal = -H_uncal_pn_inv * H_uncal_K; + + } + + return pn; } /* ************************************************************************* */ Point2 Cal3Unified::nPlaneToSpace(const Point2& p) const { diff --git a/gtsam/geometry/Cal3Unified.h b/gtsam/geometry/Cal3Unified.h index 381405d20..6fc37b0d1 100644 --- a/gtsam/geometry/Cal3Unified.h +++ b/gtsam/geometry/Cal3Unified.h @@ -14,6 +14,7 @@ * @brief Unified Calibration Model, see Mei07icra for details * @date Mar 8, 2014 * @author Jing Dong + * @author Varun Agrawal */ /** @@ -99,7 +100,8 @@ public: OptionalJacobian<2,2> Dp = boost::none) const ; /// Conver a pixel coordinate to ideal coordinate - Point2 calibrate(const Point2& p, const double tol=1e-5) const; + Point2 calibrate(const Point2& p, OptionalJacobian<2, 10> Dcal = boost::none, + OptionalJacobian<2, 2> Dp = boost::none) const; /// Convert a 3D point to normalized unit plane Point2 spaceToNPlane(const Point2& p) const; diff --git a/gtsam/geometry/tests/testCal3DS2.cpp b/gtsam/geometry/tests/testCal3DS2.cpp index 416665d46..beed09883 100644 --- a/gtsam/geometry/tests/testCal3DS2.cpp +++ b/gtsam/geometry/tests/testCal3DS2.cpp @@ -74,12 +74,26 @@ TEST( Cal3DS2, Duncalibrate2) CHECK(assert_equal(numerical,separate,1e-5)); } -/* ************************************************************************* */ -TEST( Cal3DS2, assert_equal) -{ - CHECK(assert_equal(K,K,1e-5)); +Point2 calibrate_(const Cal3DS2& k, const Point2& pt) { + return k.calibrate(pt); } +/* ************************************************************************* */ +TEST( Cal3DS2, Dcalibrate) +{ + Point2 pn(0.5, 0.5); + Point2 pi = K.uncalibrate(pn); + Matrix Dcal, Dp; + K.calibrate(pi, Dcal, Dp); + Matrix numerical1 = numericalDerivative21(calibrate_, K, pi, 1e-7); + CHECK(assert_equal(numerical1, Dcal, 1e-5)); + Matrix numerical2 = numericalDerivative22(calibrate_, K, pi, 1e-7); + CHECK(assert_equal(numerical2, Dp, 1e-5)); +} + +/* ************************************************************************* */ +TEST(Cal3DS2, assert_equal) { CHECK(assert_equal(K, K, 1e-5)); } + /* ************************************************************************* */ TEST( Cal3DS2, retract) { diff --git a/gtsam/geometry/tests/testCal3Unified.cpp b/gtsam/geometry/tests/testCal3Unified.cpp index 2c5ffd7fb..8abb6fe04 100644 --- a/gtsam/geometry/tests/testCal3Unified.cpp +++ b/gtsam/geometry/tests/testCal3Unified.cpp @@ -82,6 +82,22 @@ TEST( Cal3Unified, Duncalibrate2) CHECK(assert_equal(numerical,computed,1e-6)); } +Point2 calibrate_(const Cal3Unified& k, const Point2& pt) { + return k.calibrate(pt); +} + +/* ************************************************************************* */ +TEST( Cal3Unified, Dcalibrate) +{ + Point2 pi = K.uncalibrate(p); + Matrix Dcal, Dp; + K.calibrate(pi, Dcal, Dp); + Matrix numerical1 = numericalDerivative21(calibrate_, K, pi); + CHECK(assert_equal(numerical1,Dcal,1e-5)); + Matrix numerical2 = numericalDerivative22(calibrate_, K, pi); + CHECK(assert_equal(numerical2,Dp,1e-5)); +} + /* ************************************************************************* */ TEST( Cal3Unified, assert_equal) { From d9018a9593a7dc1009986ceb3d01ebf0362d5a93 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 10:40:39 -0500 Subject: [PATCH 091/261] update Python test --- python/gtsam/tests/test_SimpleCamera.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/python/gtsam/tests/test_SimpleCamera.py b/python/gtsam/tests/test_SimpleCamera.py index efdfec561..358eb1f48 100644 --- a/python/gtsam/tests/test_SimpleCamera.py +++ b/python/gtsam/tests/test_SimpleCamera.py @@ -14,11 +14,12 @@ import unittest import numpy as np import gtsam -from gtsam import Cal3_S2, Point3, Pose2, Pose3, Rot3, SimpleCamera +from gtsam import Cal3_S2, Point3, Pose2, Pose3, Rot3, PinholeCameraCal3_S2 as SimpleCamera from gtsam.utils.test_case import GtsamTestCase K = Cal3_S2(625, 625, 0, 0, 0) + class TestSimpleCamera(GtsamTestCase): def test_constructor(self): @@ -29,15 +30,15 @@ class TestSimpleCamera(GtsamTestCase): def test_level2(self): # Create a level camera, looking in Y-direction - pose2 = Pose2(0.4,0.3,math.pi/2.0) + pose2 = Pose2(0.4, 0.3, math.pi/2.0) camera = SimpleCamera.Level(K, pose2, 0.1) # expected - x = Point3(1,0,0) - y = Point3(0,0,-1) - z = Point3(0,1,0) - wRc = Rot3(x,y,z) - expected = Pose3(wRc,Point3(0.4,0.3,0.1)) + x = Point3(1, 0, 0) + y = Point3(0, 0, -1) + z = Point3(0, 1, 0) + wRc = Rot3(x, y, z) + expected = Pose3(wRc, Point3(0.4, 0.3, 0.1)) self.gtsamAssertEquals(camera.pose(), expected, 1e-9) From f8eece464dc78c23602867a2479efc4f19518cdc Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 10:43:58 -0500 Subject: [PATCH 092/261] Revert "FIx indentation for Values-inl.h" This reverts commit 5749565e526f932941db53bec1f0a742ec35e005. --- gtsam/nonlinear/Values-inl.h | 161 +++++++++++++++++------------------ 1 file changed, 80 insertions(+), 81 deletions(-) diff --git a/gtsam/nonlinear/Values-inl.h b/gtsam/nonlinear/Values-inl.h index ba4ed54d3..6829e859b 100644 --- a/gtsam/nonlinear/Values-inl.h +++ b/gtsam/nonlinear/Values-inl.h @@ -259,98 +259,97 @@ namespace gtsam { } /* ************************************************************************* */ - template<> - inline bool Values::filterHelper(const boost::function filter, - const ConstKeyValuePair& key_value) { - // Filter and check the type - return filter(key_value.key); - } + template<> + inline bool Values::filterHelper(const boost::function filter, + const ConstKeyValuePair& key_value) { + // Filter and check the type + return filter(key_value.key); + } - /* ************************************************************************* */ + /* ************************************************************************* */ - namespace internal { + namespace internal { - // Check the type and throw exception if incorrect - // Generic version, partially specialized below for various Eigen Matrix types - template - struct handle { - ValueType operator()(Key j, const Value* const pointer) { - try { - // value returns a const ValueType&, and the return makes a copy !!!!! - return dynamic_cast&>(*pointer).value(); - } catch (std::bad_cast&) { - throw ValuesIncorrectType(j, typeid(*pointer), typeid(ValueType)); - } - } - }; + // Check the type and throw exception if incorrect + // Generic version, partially specialized below for various Eigen Matrix types + template + struct handle { + ValueType operator()(Key j, const Value* const pointer) { + try { + // value returns a const ValueType&, and the return makes a copy !!!!! + return dynamic_cast&>(*pointer).value(); + } catch (std::bad_cast&) { + throw ValuesIncorrectType(j, typeid(*pointer), typeid(ValueType)); + } + } + }; - template - struct handle_matrix; + template + struct handle_matrix; - // Handle dynamic matrices - template - struct handle_matrix, true> { - Eigen::Matrix operator()(Key j, const Value* const pointer) { - try { - // value returns a const Matrix&, and the return makes a copy !!!!! - return dynamic_cast>&>(*pointer).value(); - } catch (std::bad_cast&) { - // If a fixed matrix was stored, we end up here as well. - throw ValuesIncorrectType(j, typeid(*pointer), typeid(Eigen::Matrix)); - } - } - }; + // Handle dynamic matrices + template + struct handle_matrix, true> { + Eigen::Matrix operator()(Key j, const Value* const pointer) { + try { + // value returns a const Matrix&, and the return makes a copy !!!!! + return dynamic_cast>&>(*pointer).value(); + } catch (std::bad_cast&) { + // If a fixed matrix was stored, we end up here as well. + throw ValuesIncorrectType(j, typeid(*pointer), typeid(Eigen::Matrix)); + } + } + }; - // Handle fixed matrices - template - struct handle_matrix, false> { - Eigen::Matrix operator()(Key j, const Value* const pointer) { - try { - // value returns a const MatrixMN&, and the return makes a copy !!!!! - return dynamic_cast>&>(*pointer).value(); - } catch (std::bad_cast&) { - Matrix A; - try { - // Check if a dynamic matrix was stored - A = handle_matrix()(j, pointer); // will throw if not.... - } catch (const ValuesIncorrectType&) { - // Or a dynamic vector - A = handle_matrix()(j, pointer); // will throw if not.... - } - // Yes: check size, and throw if not a match - if (A.rows() != M || A.cols() != N) - throw NoMatchFoundForFixed(M, N, A.rows(), A.cols()); - else - return A; // copy but not malloc - } - } - }; + // Handle fixed matrices + template + struct handle_matrix, false> { + Eigen::Matrix operator()(Key j, const Value* const pointer) { + try { + // value returns a const MatrixMN&, and the return makes a copy !!!!! + return dynamic_cast>&>(*pointer).value(); + } catch (std::bad_cast&) { + Matrix A; + try { + // Check if a dynamic matrix was stored + A = handle_matrix()(j, pointer); // will throw if not.... + } catch (const ValuesIncorrectType&) { + // Or a dynamic vector + A = handle_matrix()(j, pointer); // will throw if not.... + } + // Yes: check size, and throw if not a match + if (A.rows() != M || A.cols() != N) + throw NoMatchFoundForFixed(M, N, A.rows(), A.cols()); + else + return A; // copy but not malloc + } + } + }; - // Handle matrices - template - struct handle> { - Eigen::Matrix operator()(Key j, const Value* const pointer) { - return handle_matrix, - (M == Eigen::Dynamic || N == Eigen::Dynamic)>()(j, pointer); - } - }; + // Handle matrices + template + struct handle> { + Eigen::Matrix operator()(Key j, const Value* const pointer) { + return handle_matrix, + (M == Eigen::Dynamic || N == Eigen::Dynamic)>()(j, pointer); + } + }; - } // internal + } // internal - /* ************************************************************************* - */ - template - const ValueType Values::at(Key j) const { - // Find the item - KeyValueMap::const_iterator item = values_.find(j); + /* ************************************************************************* */ + template + const ValueType Values::at(Key j) const { + // Find the item + KeyValueMap::const_iterator item = values_.find(j); - // Throw exception if it does not exist - if (item == values_.end()) throw ValuesKeyDoesNotExist("at", j); + // Throw exception if it does not exist + if (item == values_.end()) throw ValuesKeyDoesNotExist("at", j); - // Check the type and throw exception if incorrect - // h() split in two lines to avoid internal compiler error (MSVC2017) - auto h = internal::handle(); - return h(j, item->second); + // Check the type and throw exception if incorrect + // h() split in two lines to avoid internal compiler error (MSVC2017) + auto h = internal::handle(); + return h(j, item->second); } /* ************************************************************************* */ From cb3a766b30677d662f462a2ee2086a8fb329c892 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 13:19:13 -0500 Subject: [PATCH 093/261] uncomment calibration applications --- gtsam/geometry/SimpleCamera.h | 5 ++--- gtsam/gtsam.i | 10 ++++------ gtsam_unstable/slam/serialization.cpp | 6 ++---- tests/testSerializationSLAM.cpp | 6 ++---- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/gtsam/geometry/SimpleCamera.h b/gtsam/geometry/SimpleCamera.h index 04746ba6f..aa00222c7 100644 --- a/gtsam/geometry/SimpleCamera.h +++ b/gtsam/geometry/SimpleCamera.h @@ -31,9 +31,8 @@ namespace gtsam { /// Also needed as forward declarations in the wrapper. using PinholeCameraCal3_S2 = gtsam::PinholeCamera; using PinholeCameraCal3Bundler = gtsam::PinholeCamera; - //TODO Need to fix issue 621 for this to work with wrapper - // using PinholeCameraCal3DS2 = gtsam::PinholeCamera; - // using PinholeCameraCal3Unified = gtsam::PinholeCamera; + using PinholeCameraCal3DS2 = gtsam::PinholeCamera; + using PinholeCameraCal3Unified = gtsam::PinholeCamera; #ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V41 /** diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index eb36e73a3..2e1920641 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -881,7 +881,7 @@ virtual class Cal3DS2_Base { // Action on Point2 gtsam::Point2 uncalibrate(const gtsam::Point2& p) const; - gtsam::Point2 calibrate(const gtsam::Point2& p, double tol) const; + gtsam::Point2 calibrate(const gtsam::Point2& p) const; // enabling serialization functionality void serialize() const; @@ -1064,9 +1064,8 @@ class PinholeCamera { // Some typedefs for common camera types // PinholeCameraCal3_S2 is the same as SimpleCamera above typedef gtsam::PinholeCamera PinholeCameraCal3_S2; -//TODO (Issue 621) due to lack of jacobians of Cal3DS2_Base::calibrate, PinholeCamera does not apply to Cal3DS2/Unified -//typedef gtsam::PinholeCamera PinholeCameraCal3DS2; -//typedef gtsam::PinholeCamera PinholeCameraCal3Unified; +typedef gtsam::PinholeCamera PinholeCameraCal3DS2; +typedef gtsam::PinholeCamera PinholeCameraCal3Unified; typedef gtsam::PinholeCamera PinholeCameraCal3Bundler; #include @@ -2634,8 +2633,7 @@ virtual class GeneralSFMFactor : gtsam::NoiseModelFactor { gtsam::Point2 measured() const; }; typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3_S2; -//TODO (Issue 621) due to lack of jacobians of Cal3DS2_Base::calibrate, GeneralSFMFactor does not apply to Cal3DS2 -//typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; +typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; typedef gtsam::GeneralSFMFactor, gtsam::Point3> GeneralSFMFactorCal3Bundler; template diff --git a/gtsam_unstable/slam/serialization.cpp b/gtsam_unstable/slam/serialization.cpp index 803e4353a..88a94fd51 100644 --- a/gtsam_unstable/slam/serialization.cpp +++ b/gtsam_unstable/slam/serialization.cpp @@ -86,8 +86,7 @@ typedef GenericProjectionFactor GenericProjectionFactorC typedef GenericProjectionFactor GenericProjectionFactorCal3DS2; typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3_S2; -//TODO fix issue 621 -//typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; +typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; typedef gtsam::GeneralSFMFactor2 GeneralSFMFactor2Cal3_S2; @@ -184,8 +183,7 @@ BOOST_CLASS_EXPORT_GUID(GenericProjectionFactorCal3_S2, "gtsam::GenericProjectio BOOST_CLASS_EXPORT_GUID(GenericProjectionFactorCal3DS2, "gtsam::GenericProjectionFactorCal3DS2"); BOOST_CLASS_EXPORT_GUID(GeneralSFMFactorCal3_S2, "gtsam::GeneralSFMFactorCal3_S2"); -//TODO Fix issue 621 -//BOOST_CLASS_EXPORT_GUID(GeneralSFMFactorCal3DS2, "gtsam::GeneralSFMFactorCal3DS2"); +BOOST_CLASS_EXPORT_GUID(GeneralSFMFactorCal3DS2, "gtsam::GeneralSFMFactorCal3DS2"); BOOST_CLASS_EXPORT_GUID(GeneralSFMFactor2Cal3_S2, "gtsam::GeneralSFMFactor2Cal3_S2"); diff --git a/tests/testSerializationSLAM.cpp b/tests/testSerializationSLAM.cpp index 53086e921..2e99aff71 100644 --- a/tests/testSerializationSLAM.cpp +++ b/tests/testSerializationSLAM.cpp @@ -100,8 +100,7 @@ typedef GenericProjectionFactor GenericProjectionFactorC typedef GenericProjectionFactor GenericProjectionFactorCal3DS2; typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3_S2; -//TODO Fix issue 621 for this to work -//typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; +typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; typedef gtsam::GeneralSFMFactor2 GeneralSFMFactor2Cal3_S2; @@ -198,8 +197,7 @@ BOOST_CLASS_EXPORT_GUID(GenericProjectionFactorCal3_S2, "gtsam::GenericProjectio BOOST_CLASS_EXPORT_GUID(GenericProjectionFactorCal3DS2, "gtsam::GenericProjectionFactorCal3DS2"); BOOST_CLASS_EXPORT_GUID(GeneralSFMFactorCal3_S2, "gtsam::GeneralSFMFactorCal3_S2"); -//TODO fix issue 621 -//BOOST_CLASS_EXPORT_GUID(GeneralSFMFactorCal3DS2, "gtsam::GeneralSFMFactorCal3DS2"); +BOOST_CLASS_EXPORT_GUID(GeneralSFMFactorCal3DS2, "gtsam::GeneralSFMFactorCal3DS2"); BOOST_CLASS_EXPORT_GUID(GeneralSFMFactor2Cal3_S2, "gtsam::GeneralSFMFactor2Cal3_S2"); From fba918ce96ae19029767eb850b1f89ca47a20962 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 17:30:34 -0500 Subject: [PATCH 094/261] Removed unnecessary copy constructor and robust noise model is caller's responsibility --- gtsam/sfm/BinaryMeasurement.h | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/gtsam/sfm/BinaryMeasurement.h b/gtsam/sfm/BinaryMeasurement.h index f27383175..99e553f7a 100644 --- a/gtsam/sfm/BinaryMeasurement.h +++ b/gtsam/sfm/BinaryMeasurement.h @@ -47,41 +47,10 @@ private: public: BinaryMeasurement(Key key1, Key key2, const T &measured, - const SharedNoiseModel &model = nullptr, - bool useHuber = false) + const SharedNoiseModel &model = nullptr) : Factor(std::vector({key1, key2})), measured_(measured), - noiseModel_(model) { - if (useHuber) { - const auto &robust = - boost::dynamic_pointer_cast(this->noiseModel_); - if (!robust) { - // make robust - this->noiseModel_ = noiseModel::Robust::Create( - noiseModel::mEstimator::Huber::Create(1.345), this->noiseModel_); - } - } - } - - /** - * Copy constructor to allow for making existing BinaryMeasurements as robust - * in a functional way. - * - * @param measurement BinaryMeasurement object. - * @param useHuber Boolean flag indicating whether to use Huber noise model. - */ - BinaryMeasurement(const BinaryMeasurement& measurement, bool useHuber = false) { - *this = measurement; - if (useHuber) { - const auto &robust = - boost::dynamic_pointer_cast(this->noiseModel_); - if (!robust) { - // make robust - this->noiseModel_ = noiseModel::Robust::Create( - noiseModel::mEstimator::Huber::Create(1.345), this->noiseModel_); - } - } - } + noiseModel_(model) {} /// @name Standard Interface /// @{ From fd74ae933065a3d615b31bf3feb4f32552fd53c5 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 17:31:08 -0500 Subject: [PATCH 095/261] throw runtime errors and explicitly form robust noise model --- gtsam/sfm/ShonanAveraging.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 53a2222e4..1d3166a89 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -343,10 +343,8 @@ static double Kappa(const BinaryMeasurement &measurement) { const auto &robust = boost::dynamic_pointer_cast( measurement.noiseModel()); if (robust) { - std::cout << "Verification of optimality does not work with robust cost " - "function" - << std::endl; - sigma = 1; // setting arbitrary value + throw std::runtime_error( + "Verification of optimality does not work with robust cost function"); } else { throw std::invalid_argument( "Shonan averaging noise models must be isotropic (but robust losses " @@ -804,8 +802,10 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, // Optimize until convergence at this level Qstar = tryOptimizingAt(p, initialSOp); if(parameters_.useHuber){ // in this case, there is no optimality verification - if(pMin!=pMax) - std::cout << "When using robust norm, Shonan only tests a single rank" << std::endl; + if (pMin != pMax) { + throw std::runtime_error( + "When using robust norm, Shonan only tests a single rank"); + } const Values SO3Values = roundSolution(Qstar); return std::make_pair(SO3Values, 0); } @@ -876,9 +876,11 @@ static BinaryMeasurement convert( "parseMeasurements can only convert Pose3 measurements " "with Gaussian noise models."); const Matrix6 M = gaussian->covariance(); - return BinaryMeasurement( - f->key1(), f->key2(), f->measured().rotation(), - noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3), true)); + auto model = noiseModel::Robust::Create( + noiseModel::mEstimator::Huber::Create(1.345), + noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3))); + return BinaryMeasurement(f->key1(), f->key2(), f->measured().rotation(), + model); } static ShonanAveraging3::Measurements extractRot3Measurements( From 9d15afaab1f1b56c9acb2bf577a14138c171d2de Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 17:31:49 -0500 Subject: [PATCH 096/261] makeNoiseModelRobust assumes responsibility for robustifying noise models --- gtsam/sfm/ShonanAveraging.h | 42 ++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index 7dd87391a..5cb34c419 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -83,13 +83,13 @@ struct GTSAM_EXPORT ShonanAveragingParameters { void setUseHuber(bool value) { useHuber = value; } bool getUseHuber() { return useHuber; } + /// Print the parameters and flags used for rotation averaging. void print() const { std::cout << " ShonanAveragingParameters: " << std::endl; - std::cout << " alpha: " << alpha << std::endl; - std::cout << " beta: " << beta << std::endl; - std::cout << " gamma: " << gamma << std::endl; - std::cout << " useHuber: " << useHuber << std::endl; - std::cout << " --------------------------" << std::endl; + std::cout << " alpha: " << alpha << std::endl; + std::cout << " beta: " << beta << std::endl; + std::cout << " gamma: " << gamma << std::endl; + std::cout << " useHuber: " << useHuber << std::endl; } }; @@ -164,11 +164,33 @@ class GTSAM_EXPORT ShonanAveraging { return measurements_[k]; } - /// wrap factors with robust Huber loss - Measurements makeNoiseModelRobust(const Measurements& measurements) const { - Measurements robustMeasurements = measurements; - for (auto &measurement : robustMeasurements) { - measurement = BinaryMeasurement(measurement, true); + /** + * Update factors to use robust Huber loss. + * + * @param measurements Vector of BinaryMeasurements. + * @param k Huber noise model threshold. + */ + Measurements makeNoiseModelRobust(const Measurements &measurements, + double k = 1.345) const { + Measurements robustMeasurements; + for (auto &measurement : measurements) { + + auto model = measurement.noiseModel(); + const auto &robust = + boost::dynamic_pointer_cast(model); + + SharedNoiseModel robust_model; + // Check if the noise model is already robust + if (robust) { + robust_model = model; + } else { + // make robust + robust_model = noiseModel::Robust::Create( + noiseModel::mEstimator::Huber::Create(k), model); + } + BinaryMeasurement meas(measurement.key1(), measurement.key2(), + measurement.measured(), robust_model); + robustMeasurements.push_back(meas); } return robustMeasurements; } From 3e6efe3a51355007f9ab2d1d6f6a61ba417de42b Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 17:32:02 -0500 Subject: [PATCH 097/261] use goto flow --- gtsam/slam/FrobeniusFactor.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/gtsam/slam/FrobeniusFactor.cpp b/gtsam/slam/FrobeniusFactor.cpp index 8c70a1ebb..8c0baaf38 100644 --- a/gtsam/slam/FrobeniusFactor.cpp +++ b/gtsam/slam/FrobeniusFactor.cpp @@ -26,7 +26,6 @@ namespace gtsam { SharedNoiseModel ConvertNoiseModel(const SharedNoiseModel &model, size_t d, bool defaultToUnit) { double sigma = 1.0; - bool exit = false; if (model != nullptr) { const auto &robust = boost::dynamic_pointer_cast(model); @@ -40,7 +39,7 @@ ConvertNoiseModel(const SharedNoiseModel &model, size_t d, bool defaultToUnit) { size_t n = sigmas.size(); if (n == 1) { sigma = sigmas(0); // Rot2 - exit = true; + goto exit; } else if (n == 3 || n == 6) { sigma = sigmas(2); // Pose2, Rot3, or Pose3 @@ -49,13 +48,13 @@ ConvertNoiseModel(const SharedNoiseModel &model, size_t d, bool defaultToUnit) { throw std::runtime_error("Can only convert isotropic rotation noise"); } } - exit = true; + goto exit; } - if (!defaultToUnit && !exit) { + if (!defaultToUnit) { throw std::runtime_error("Can only convert Pose2/Pose3 noise models"); } } - + exit: auto isoModel = noiseModel::Isotropic::Sigma(d, sigma); const auto &robust = boost::dynamic_pointer_cast(model); if (robust) { From 799788672f14fc53b1cfebeaa055fb6c48ad8353 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 17:32:16 -0500 Subject: [PATCH 098/261] formatting --- examples/ShonanAveragingCLI.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/examples/ShonanAveragingCLI.cpp b/examples/ShonanAveragingCLI.cpp index 322622228..9970f45da 100644 --- a/examples/ShonanAveragingCLI.cpp +++ b/examples/ShonanAveragingCLI.cpp @@ -25,7 +25,8 @@ * Read 3D dataset sphere25000.txt and output to shonan.g2o (default) * ./ShonanAveragingCLI -i spere2500.txt * - * If you prefer using a robust Huber loss, you can add the option "-h true", for instance + * If you prefer using a robust Huber loss, you can add the option "-h true", + * for instance * ./ShonanAveragingCLI -i spere2500.txt -u true */ @@ -62,9 +63,9 @@ int main(int argc, char* argv[]) { "dimension,d", po::value(&d)->default_value(3), "Optimize over 2D or 3D rotations")( "useHuberLoss,h", po::value(&useHuberLoss)->default_value(false), - "set True to use Huber loss")( - "pMin,p", po::value(&pMin)->default_value(3), - "set to use desired rank pMin")( + "set True to use Huber loss")("pMin,p", + po::value(&pMin)->default_value(3), + "set to use desired rank pMin")( "seed,s", po::value(&seed)->default_value(42), "Random seed for initial estimate"); po::variables_map vm; @@ -97,9 +98,9 @@ int main(int argc, char* argv[]) { cout << "Running Shonan averaging for SO(2) on " << inputFile << endl; ShonanAveraging2::Parameters parameters(lmParams); parameters.setUseHuber(useHuberLoss); - ShonanAveraging2 shonan(inputFile,parameters); + ShonanAveraging2 shonan(inputFile, parameters); auto initial = shonan.initializeRandomly(rng); - auto result = shonan.run(initial,pMin); + auto result = shonan.run(initial, pMin); // Parse file again to set up translation problem, adding a prior boost::tie(inputGraph, posesInFile) = load2D(inputFile); @@ -113,9 +114,9 @@ int main(int argc, char* argv[]) { cout << "Running Shonan averaging for SO(3) on " << inputFile << endl; ShonanAveraging3::Parameters parameters(lmParams); parameters.setUseHuber(useHuberLoss); - ShonanAveraging3 shonan(inputFile,parameters); + ShonanAveraging3 shonan(inputFile, parameters); auto initial = shonan.initializeRandomly(rng); - auto result = shonan.run(initial,pMin); + auto result = shonan.run(initial, pMin); // Parse file again to set up translation problem, adding a prior boost::tie(inputGraph, posesInFile) = load3D(inputFile); From a8f4f1eb08b917a6ef30c007980119138b2f7ba4 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Mon, 30 Nov 2020 17:35:43 -0500 Subject: [PATCH 099/261] Added more description to the toyExample.g2o --- gtsam/sfm/tests/testShonanAveraging.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gtsam/sfm/tests/testShonanAveraging.cpp b/gtsam/sfm/tests/testShonanAveraging.cpp index cf35a42cf..172166116 100644 --- a/gtsam/sfm/tests/testShonanAveraging.cpp +++ b/gtsam/sfm/tests/testShonanAveraging.cpp @@ -98,6 +98,9 @@ TEST(ShonanAveraging3, checkSubgraph) { gtsam::LevenbergMarquardtParams::CeresDefaults(), "SUBGRAPH"); ShonanAveraging3::Measurements measurements; + // The toyExample.g2o has 5 vertices, from 0-4 + // The edges are: 1-2, 2-3, 3-4, 3-1, 1-4, 0-1, + // which can build a connected graph auto subgraphShonan = fromExampleName("toyExample.g2o", params); // Create initial random estimation From 7391c103ec0d6e74713c3316311d3096ad4953ea Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 17:51:50 -0500 Subject: [PATCH 100/261] fix tests --- gtsam/sfm/ShonanAveraging.cpp | 5 +++-- gtsam/sfm/tests/testBinaryMeasurement.cpp | 10 +++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 1d3166a89..e08bc4dd6 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -343,8 +343,9 @@ static double Kappa(const BinaryMeasurement &measurement) { const auto &robust = boost::dynamic_pointer_cast( measurement.noiseModel()); if (robust) { - throw std::runtime_error( - "Verification of optimality does not work with robust cost function"); + std::cout << "Verification of optimality does not work with robust cost " + "function" + << std::endl; } else { throw std::invalid_argument( "Shonan averaging noise models must be isotropic (but robust losses " diff --git a/gtsam/sfm/tests/testBinaryMeasurement.cpp b/gtsam/sfm/tests/testBinaryMeasurement.cpp index a079f7e04..ae13e54c4 100644 --- a/gtsam/sfm/tests/testBinaryMeasurement.cpp +++ b/gtsam/sfm/tests/testBinaryMeasurement.cpp @@ -66,8 +66,10 @@ TEST(BinaryMeasurement, Rot3) { /* ************************************************************************* */ TEST(BinaryMeasurement, Rot3MakeRobust) { + auto huber_model = noiseModel::Robust::Create( + noiseModel::mEstimator::Huber::Create(1.345), rot3_model); BinaryMeasurement rot3Measurement(kKey1, kKey2, rot3Measured, - rot3_model, true); + huber_model); EXPECT_LONGS_EQUAL(rot3Measurement.key1(), kKey1); EXPECT_LONGS_EQUAL(rot3Measurement.key2(), kKey2); @@ -75,12 +77,6 @@ TEST(BinaryMeasurement, Rot3MakeRobust) { const auto &robust = boost::dynamic_pointer_cast( rot3Measurement.noiseModel()); EXPECT(robust); - - // test that if we call it again nothing changes: - rot3Measurement = BinaryMeasurement(rot3Measurement, true); - const auto &robust2 = boost::dynamic_pointer_cast( - rot3Measurement.noiseModel()); - EXPECT(robust2); } /* ************************************************************************* */ From a00d37005bbcd2f6702be15d58ac8312a531b163 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 18:21:36 -0500 Subject: [PATCH 101/261] Don't throw error for Kappa and test parameter print --- gtsam/sfm/ShonanAveraging.cpp | 1 + gtsam/sfm/tests/testShonanAveraging.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index e08bc4dd6..bc3783a27 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -346,6 +346,7 @@ static double Kappa(const BinaryMeasurement &measurement) { std::cout << "Verification of optimality does not work with robust cost " "function" << std::endl; + sigma = 1; // setting arbitrary value } else { throw std::invalid_argument( "Shonan averaging noise models must be isotropic (but robust losses " diff --git a/gtsam/sfm/tests/testShonanAveraging.cpp b/gtsam/sfm/tests/testShonanAveraging.cpp index 9242b94a3..002109454 100644 --- a/gtsam/sfm/tests/testShonanAveraging.cpp +++ b/gtsam/sfm/tests/testShonanAveraging.cpp @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -329,7 +330,11 @@ TEST(ShonanAveraging2, noisyToyGraphWithHuber) { ShonanAveraging2::Parameters parameters(lmParams); auto measurements = parseMeasurements(g2oFile); parameters.setUseHuber(true); - parameters.print(); + string parameters_print = + " ShonanAveragingParameters: \n alpha: 0\n beta: 1\n gamma: 0\n " + "useHuber: 1\n"; + assert_print_equal(parameters_print, parameters); + ShonanAveraging2 shonan(measurements, parameters); EXPECT_LONGS_EQUAL(4, shonan.nrUnknowns()); From 844cbead2b4d6e429af9004c1e13262a0ea8faa2 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Mon, 30 Nov 2020 18:52:33 -0500 Subject: [PATCH 102/261] Added dense matrix test case in power/acc --- .../tests/testAcceleratedPowerMethod.cpp | 50 ++++++++++++++++++- gtsam/linear/tests/testPowerMethod.cpp | 43 +++++++++++++++- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp index dd593e7d3..c7c8e8a55 100644 --- a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp +++ b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp @@ -63,7 +63,7 @@ TEST(AcceleratedPowerMethod, acceleratedPowerIteration) { } /* ************************************************************************* */ -TEST(AcceleratedPowerMethod, useFactorGraph) { +TEST(AcceleratedPowerMethod, useFactorGraphSparse) { // Let's make a scalar synchronization graph with 4 nodes GaussianFactorGraph fg; auto model = noiseModel::Unit::Create(1); @@ -102,6 +102,54 @@ TEST(AcceleratedPowerMethod, useFactorGraph) { EXPECT_DOUBLES_EQUAL(0, ritzResidual, 1e-5); } +/* ************************************************************************* */ +TEST(AcceleratedPowerMethod, useFactorGraphDense) { + // Let's make a scalar synchronization graph with 10 nodes + GaussianFactorGraph fg; + auto model = noiseModel::Unit::Create(1); + // Each node has an edge with all the others + for (size_t j = 0; j < 10; j++) { + fg.add(X(j), -I_1x1, X((j + 1)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 2)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 3)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 4)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 5)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 6)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 7)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 8)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 9)%10 ), I_1x1, Vector1::Zero(), model); + } + + // Get eigenvalues and eigenvectors with Eigen + auto L = fg.hessian(); + Eigen::EigenSolver solver(L.first); + + // find the index of the max eigenvalue + size_t maxIdx = 0; + for (auto i = 0; i < solver.eigenvalues().rows(); ++i) { + if (solver.eigenvalues()(i).real() >= solver.eigenvalues()(maxIdx).real()) + maxIdx = i; + } + // Store the max eigenvalue and its according eigenvector + const auto ev1 = solver.eigenvalues()(maxIdx).real(); + + Vector disturb = Vector10::Random(); + disturb.normalize(); + Vector initial = L.first.row(0); + double magnitude = initial.norm(); + initial += 0.03 * magnitude * disturb; + AcceleratedPowerMethod apf(L.first, initial); + apf.compute(100, 1e-5); + // Check if the eigenvalue is the maximum eigen value + EXPECT_DOUBLES_EQUAL(ev1, apf.eigenvalue(), 1e-8); + + // Check if the according ritz residual converged to the threshold + Vector actual1 = apf.eigenvector(); + const double ritzValue = actual1.dot(L.first * actual1); + const double ritzResidual = (L.first * actual1 - ritzValue * actual1).norm(); + EXPECT_DOUBLES_EQUAL(0, ritzResidual, 1e-5); +} + /* ************************************************************************* */ int main() { TestResult tr; diff --git a/gtsam/linear/tests/testPowerMethod.cpp b/gtsam/linear/tests/testPowerMethod.cpp index 2e0f2152b..7adfd0aa5 100644 --- a/gtsam/linear/tests/testPowerMethod.cpp +++ b/gtsam/linear/tests/testPowerMethod.cpp @@ -61,7 +61,7 @@ TEST(PowerMethod, powerIteration) { } /* ************************************************************************* */ -TEST(PowerMethod, useFactorGraph) { +TEST(PowerMethod, useFactorGraphSparse) { // Let's make a scalar synchronization graph with 4 nodes GaussianFactorGraph fg; auto model = noiseModel::Unit::Create(1); @@ -93,6 +93,47 @@ TEST(PowerMethod, useFactorGraph) { EXPECT_DOUBLES_EQUAL(0, ritzResidual, 1e-5); } +/* ************************************************************************* */ +TEST(PowerMethod, useFactorGraphDense) { + // Let's make a scalar synchronization graph with 10 nodes + GaussianFactorGraph fg; + auto model = noiseModel::Unit::Create(1); + // Each node has an edge with all the others + for (size_t j = 0; j < 10; j++) { + fg.add(X(j), -I_1x1, X((j + 1)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 2)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 3)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 4)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 5)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 6)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 7)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 8)%10 ), I_1x1, Vector1::Zero(), model); + fg.add(X(j), -I_1x1, X((j + 9)%10 ), I_1x1, Vector1::Zero(), model); + } + + // Get eigenvalues and eigenvectors with Eigen + auto L = fg.hessian(); + Eigen::EigenSolver solver(L.first); + + // find the index of the max eigenvalue + size_t maxIdx = 0; + for (auto i = 0; i < solver.eigenvalues().rows(); ++i) { + if (solver.eigenvalues()(i).real() >= solver.eigenvalues()(maxIdx).real()) + maxIdx = i; + } + // Store the max eigenvalue and its according eigenvector + const auto ev1 = solver.eigenvalues()(maxIdx).real(); + + Vector initial = Vector10::Random(); + PowerMethod pf(L.first, initial); + pf.compute(100, 1e-5); + EXPECT_DOUBLES_EQUAL(ev1, pf.eigenvalue(), 1e-8); + auto actual2 = pf.eigenvector(); + const double ritzValue = actual2.dot(L.first * actual2); + const double ritzResidual = (L.first * actual2 - ritzValue * actual2).norm(); + EXPECT_DOUBLES_EQUAL(0, ritzResidual, 1e-5); +} + /* ************************************************************************* */ int main() { TestResult tr; From 845b6c55b3dc86a4172b480b1fb50a8ac4b5cb7d Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 30 Nov 2020 22:41:11 -0500 Subject: [PATCH 103/261] added Imu parameter units to doc --- doc/ImuFactor.lyx | 180 ++++++++++++++++++++++++++++++++++++++++++---- doc/ImuFactor.pdf | Bin 198168 -> 176165 bytes 2 files changed, 165 insertions(+), 15 deletions(-) diff --git a/doc/ImuFactor.lyx b/doc/ImuFactor.lyx index 0922a3e9c..55b7201e5 100644 --- a/doc/ImuFactor.lyx +++ b/doc/ImuFactor.lyx @@ -1,5 +1,5 @@ -#LyX 2.0 created this file. For more info see http://www.lyx.org/ -\lyxformat 413 +#LyX 2.1 created this file. For more info see http://www.lyx.org/ +\lyxformat 474 \begin_document \begin_header \textclass article @@ -12,13 +12,13 @@ \font_roman default \font_sans default \font_typewriter default +\font_math auto \font_default_family default \use_non_tex_fonts false \font_sc false \font_osf false \font_sf_scale 100 \font_tt_scale 100 - \graphics default \default_output_format default \output_sync 0 @@ -29,15 +29,24 @@ \use_hyperref false \papersize default \use_geometry true -\use_amsmath 1 -\use_esint 1 -\use_mhchem 1 -\use_mathdots 1 +\use_package amsmath 1 +\use_package amssymb 1 +\use_package cancel 1 +\use_package esint 1 +\use_package mathdots 1 +\use_package mathtools 1 +\use_package mhchem 1 +\use_package stackrel 1 +\use_package stmaryrd 1 +\use_package undertilde 1 \cite_engine basic +\cite_engine_type default +\biblio_style plain \use_bibtopic false \use_indices false \paperorientation portrait \suppress_date false +\justification true \use_refstyle 1 \index Index \shortcut idx @@ -244,7 +253,7 @@ X(t)=\left\{ R_{0},P_{0}+V_{0}t,V_{0}\right\} then the differential equation describing the trajectory is \begin_inset Formula \[ -\dot{X}(t)=\left[0_{3x3},V_{0},0_{3x1}\right],\,\,\,\,\, X(0)=\left\{ R_{0},P_{0},V_{0}\right\} +\dot{X}(t)=\left[0_{3x3},V_{0},0_{3x1}\right],\,\,\,\,\,X(0)=\left\{ R_{0},P_{0},V_{0}\right\} \] \end_inset @@ -602,7 +611,7 @@ key "Iserles00an" , \begin_inset Formula \begin{equation} -\dot{R}(t)=F(R,t),\,\,\,\, R(0)=R_{0}\label{eq:diffSo3} +\dot{R}(t)=F(R,t),\,\,\,\,R(0)=R_{0}\label{eq:diffSo3} \end{equation} \end_inset @@ -947,8 +956,8 @@ Or, as another way to state this, if we solve the differential equations \begin_inset Formula \begin{eqnarray*} \dot{\theta}(t) & = & H(\theta)^{-1}\,\omega^{b}(t)\\ -\dot{p}(t) & = & R_{0}^{T}\, V_{0}+v(t)\\ -\dot{v}(t) & = & R_{0}^{T}\, g+R_{b}^{0}(t)a^{b}(t) +\dot{p}(t) & = & R_{0}^{T}\,V_{0}+v(t)\\ +\dot{v}(t) & = & R_{0}^{T}\,g+R_{b}^{0}(t)a^{b}(t) \end{eqnarray*} \end_inset @@ -1015,7 +1024,7 @@ v(t)=v_{g}(t)+v_{a}(t) evolving as \begin_inset Formula \begin{eqnarray*} -\dot{v}_{g}(t) & = & R_{i}^{T}\, g\\ +\dot{v}_{g}(t) & = & R_{i}^{T}\,g\\ \dot{v}_{a}(t) & = & R_{b}^{i}(t)a^{b}(t) \end{eqnarray*} @@ -1041,7 +1050,7 @@ p(t)=p_{i}(t)+p_{g}(t)+p_{v}(t) evolving as \begin_inset Formula \begin{eqnarray*} -\dot{p}_{i}(t) & = & R_{i}^{T}\, V_{i}\\ +\dot{p}_{i}(t) & = & R_{i}^{T}\,V_{i}\\ \dot{p}_{g}(t) & = & v_{g}(t)=R_{i}^{T}gt\\ \dot{p}_{v}(t) & = & v_{a}(t) \end{eqnarray*} @@ -1096,7 +1105,7 @@ Predict the NavState from \begin_inset Formula \[ -X_{j}=\mathcal{R}_{X_{i}}(\zeta(t_{ij}))=\left\{ \Phi_{R_{0}}\left(\theta(t_{ij})\right),P_{i}+V_{i}t_{ij}+\frac{gt_{ij}^{2}}{2}+R_{i}\, p_{v}(t_{ij}),V_{i}+gt_{ij}+R_{i}\, v_{a}(t_{ij})\right\} +X_{j}=\mathcal{R}_{X_{i}}(\zeta(t_{ij}))=\left\{ \Phi_{R_{0}}\left(\theta(t_{ij})\right),P_{i}+V_{i}t_{ij}+\frac{gt_{ij}^{2}}{2}+R_{i}\,p_{v}(t_{ij}),V_{i}+gt_{ij}+R_{i}\,v_{a}(t_{ij})\right\} \] \end_inset @@ -1372,7 +1381,7 @@ B_{k}=\left[\begin{array}{c} 0_{3\times3}\\ R_{k}\frac{\Delta_{t}}{2}^{2}\\ R_{k}\Delta_{t} -\end{array}\right],\,\,\,\, C_{k}=\left[\begin{array}{c} +\end{array}\right],\,\,\,\,C_{k}=\left[\begin{array}{c} H(\theta_{k})^{-1}\Delta_{t}\\ 0_{3\times3}\\ 0_{3\times3} @@ -1382,6 +1391,147 @@ H(\theta_{k})^{-1}\Delta_{t}\\ \end_inset +\end_layout + +\begin_layout Subsubsection* +Units +\end_layout + +\begin_layout Standard +The units of the IMU are as follows: +\end_layout + +\begin_layout Standard +\begin_inset Tabular + + + + + + +\begin_inset Text + +\begin_layout Plain Layout +Parameter +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Units +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +gyro_noise_sigma +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $rad/s/\sqrt{Hz}$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +accel_noise_sigma +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $m/s^{2}/\sqrt{Hz}$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +gyro_bias_rw_sigma +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $rad/s$ +\end_inset + + or +\begin_inset Formula $rad\sqrt{Hz}/s$ +\end_inset + + +\end_layout + +\end_inset + + + + +\begin_inset Text + +\begin_layout Plain Layout +accel_bias_rw_sigma +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +\begin_inset Formula $m/s^{2}$ +\end_inset + +or +\begin_inset Formula $m\sqrt{Hz}/s^{2}$ +\end_inset + + +\end_layout + +\end_inset + + + + +\end_inset + + \end_layout \begin_layout Standard diff --git a/doc/ImuFactor.pdf b/doc/ImuFactor.pdf index 0b13c1f5948de38aa6454732ca20367cc630c62c..adec08aa3e0e689a9e494b1fc0a21aecc06b2368 100644 GIT binary patch literal 176165 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≧xk)SWRXQIBB@^t}Tq)>?wLOM+iQ%_%~^ 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νa~I*fu9(YyyD)6XtSN1zDMtK%+z?{m(le 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�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 J4MR Date: Mon, 30 Nov 2020 22:41:21 -0500 Subject: [PATCH 104/261] formatting --- cmake/GtsamTesting.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/GtsamTesting.cmake b/cmake/GtsamTesting.cmake index 3b42ffa21..4f32d90a5 100644 --- a/cmake/GtsamTesting.cmake +++ b/cmake/GtsamTesting.cmake @@ -88,7 +88,7 @@ enable_testing() option(GTSAM_BUILD_TESTS "Enable/Disable building of tests" ON) option(GTSAM_BUILD_EXAMPLES_ALWAYS "Build examples with 'make all' (build with 'make examples' if not)" ON) - option(GTSAM_BUILD_TIMING_ALWAYS "Build timing scripts with 'make all' (build with 'make timing' if not" OFF) +option(GTSAM_BUILD_TIMING_ALWAYS "Build timing scripts with 'make all' (build with 'make timing' if not" OFF) # Add option for combining unit tests if(MSVC OR XCODE_VERSION) From 012820b7fa6d7c5f5339036f6f2da38e9335e3ac Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 1 Dec 2020 00:39:32 -0500 Subject: [PATCH 105/261] Common function to compute Jacobians of calibrate method --- gtsam/geometry/Cal3Bundler.cpp | 19 +--------- gtsam/geometry/Cal3Bundler.h | 1 + gtsam/geometry/Cal3DS2_Base.cpp | 22 ++---------- gtsam/geometry/Cal3DS2_Base.h | 44 ++++++++++++++++++++--- gtsam/geometry/Cal3Fisheye.cpp | 9 +++-- gtsam/geometry/Cal3Fisheye.h | 13 ++++--- gtsam/geometry/Cal3Unified.cpp | 19 +--------- gtsam/geometry/tests/testCal3DFisheye.cpp | 17 +++++++++ 8 files changed, 76 insertions(+), 68 deletions(-) diff --git a/gtsam/geometry/Cal3Bundler.cpp b/gtsam/geometry/Cal3Bundler.cpp index 36e7bf62d..a73bfec52 100644 --- a/gtsam/geometry/Cal3Bundler.cpp +++ b/gtsam/geometry/Cal3Bundler.cpp @@ -121,24 +121,7 @@ Point2 Cal3Bundler::calibrate(const Point2& pi, throw std::runtime_error( "Cal3Bundler::calibrate fails to converge. need a better initialization"); - // We make use of the Implicit Function Theorem to compute the Jacobians from uncalibrate - // Given f(pi, pn) = uncalibrate(pn) - pi, and g(pi) = calibrate, we can easily compute the Jacobians - // df/pi = -I (pn and pi are independent args) - // Dp = -inv(H_uncal_pn) * df/pi = -inv(H_uncal_pn) * (-I) = inv(H_uncal_pn) - // Dcal = -inv(H_uncal_pn) * df/K = -inv(H_uncal_pn) * H_uncal_K - Matrix23 H_uncal_K; - Matrix22 H_uncal_pn, H_uncal_pn_inv; - - if (Dcal || Dp) { - // Compute uncalibrate Jacobians - uncalibrate(pn, Dcal ? &H_uncal_K : nullptr, H_uncal_pn); - - H_uncal_pn_inv = H_uncal_pn.inverse(); - - if (Dp) *Dp = H_uncal_pn_inv; - if (Dcal) *Dcal = -H_uncal_pn_inv * H_uncal_K; - - } + calibrateJacobians(*this, pn, Dcal, Dp); return pn; } diff --git a/gtsam/geometry/Cal3Bundler.h b/gtsam/geometry/Cal3Bundler.h index 2e3fab002..da43112d9 100644 --- a/gtsam/geometry/Cal3Bundler.h +++ b/gtsam/geometry/Cal3Bundler.h @@ -18,6 +18,7 @@ #pragma once +#include #include namespace gtsam { diff --git a/gtsam/geometry/Cal3DS2_Base.cpp b/gtsam/geometry/Cal3DS2_Base.cpp index c5ef117a7..d175259f2 100644 --- a/gtsam/geometry/Cal3DS2_Base.cpp +++ b/gtsam/geometry/Cal3DS2_Base.cpp @@ -34,8 +34,7 @@ Cal3DS2_Base::Cal3DS2_Base(const Vector& v) k1_(v(5)), k2_(v(6)), p1_(v(7)), - p2_(v(8)), - tol_(1e-5) {} + p2_(v(8)) {} /* ************************************************************************* */ Matrix3 Cal3DS2_Base::K() const { @@ -173,24 +172,7 @@ Point2 Cal3DS2_Base::calibrate(const Point2& pi, OptionalJacobian<2, 9> Dcal, throw std::runtime_error( "Cal3DS2::calibrate fails to converge. need a better initialization"); - // We make use of the Implicit Function Theorem to compute the Jacobians from uncalibrate - // Given f(pi, pn) = uncalibrate(pn) - pi, and g(pi) = calibrate, we can easily compute the Jacobians - // df/pi = -I (pn and pi are independent args) - // Dp = -inv(H_uncal_pn) * df/pi = -inv(H_uncal_pn) * (-I) = inv(H_uncal_pn) - // Dcal = -inv(H_uncal_pn) * df/K = -inv(H_uncal_pn) * H_uncal_K - Matrix29 H_uncal_K; - Matrix22 H_uncal_pn, H_uncal_pn_inv; - - if (Dcal || Dp) { - // Compute uncalibrate Jacobians - uncalibrate(pn, Dcal ? &H_uncal_K : nullptr, H_uncal_pn); - - H_uncal_pn_inv = H_uncal_pn.inverse(); - - if (Dp) *Dp = H_uncal_pn_inv; - if (Dcal) *Dcal = -H_uncal_pn_inv * H_uncal_K; - - } + calibrateJacobians(*this, pn, Dcal, Dp); return pn; } diff --git a/gtsam/geometry/Cal3DS2_Base.h b/gtsam/geometry/Cal3DS2_Base.h index b6d27cda1..c9b53c29b 100644 --- a/gtsam/geometry/Cal3DS2_Base.h +++ b/gtsam/geometry/Cal3DS2_Base.h @@ -23,6 +23,39 @@ namespace gtsam { +/** + * Function which makes use of the Implicit Function Theorem to compute the + * Jacobians of `calibrate` using `uncalibrate`. + * Given f(pi, pn) = uncalibrate(pn) - pi, and g(pi) = calibrate, we can + * easily compute the Jacobians: + * df/pi = -I (pn and pi are independent args) + * Dp = -inv(H_uncal_pn) * df/pi = -inv(H_uncal_pn) * (-I) = inv(H_uncal_pn) + * Dcal = -inv(H_uncal_pn) * df/K = -inv(H_uncal_pn) * H_uncal_K + * + * @tparam T Calibration model. + * @tparam Dim The number of parameters in the calibration model. + * @param p Calibrated point. + * @param Dcal optional 2*p Jacobian wrpt `p` Cal3DS2 parameters. + * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates. + */ +template +void calibrateJacobians(const T& calibration, const Point2& pn, + OptionalJacobian<2, Dim> Dcal = boost::none, + OptionalJacobian<2, 2> Dp = boost::none) { + if (Dcal || Dp) { + Eigen::Matrix H_uncal_K; + Matrix22 H_uncal_pn, H_uncal_pn_inv; + + // Compute uncalibrate Jacobians + calibration.uncalibrate(pn, H_uncal_K, H_uncal_pn); + + H_uncal_pn_inv = H_uncal_pn.inverse(); + + if (Dp) *Dp = H_uncal_pn_inv; + if (Dcal) *Dcal = -H_uncal_pn_inv * H_uncal_K; + } +} + /** * @brief Calibration of a camera with radial distortion * @addtogroup geometry @@ -40,14 +73,15 @@ namespace gtsam { class GTSAM_EXPORT Cal3DS2_Base { protected: - - double fx_, fy_, s_, u0_, v0_ ; // focal length, skew and principal point - double k1_, k2_ ; // radial 2nd-order and 4th-order - double p1_, p2_ ; // tangential distortion - double tol_; // tolerance value when calibrating + double fx_, fy_, s_, u0_, v0_; // focal length, skew and principal point + double k1_, k2_; // radial 2nd-order and 4th-order + double p1_, p2_; // tangential distortion + double tol_ = 1e-5; // tolerance value when calibrating public: + enum { dimension = 9 }; + /// @name Standard Constructors /// @{ diff --git a/gtsam/geometry/Cal3Fisheye.cpp b/gtsam/geometry/Cal3Fisheye.cpp index f7794fafb..1ed1826ad 100644 --- a/gtsam/geometry/Cal3Fisheye.cpp +++ b/gtsam/geometry/Cal3Fisheye.cpp @@ -122,14 +122,15 @@ Point2 Cal3Fisheye::uncalibrate(const Point2& p, OptionalJacobian<2, 9> H1, } /* ************************************************************************* */ -Point2 Cal3Fisheye::calibrate(const Point2& uv, const double tol) const { +Point2 Cal3Fisheye::calibrate(const Point2& uv, OptionalJacobian<2, 9> Dcal, + OptionalJacobian<2, 2> Dp) const { // initial gues just inverts the pinhole model const double u = uv.x(), v = uv.y(); const double yd = (v - v0_) / fy_; const double xd = (u - s_ * yd - u0_) / fx_; Point2 pi(xd, yd); - // Perform newtons method, break when solution converges past tol, + // Perform newtons method, break when solution converges past tol_, // throw exception if max iterations are reached const int maxIterations = 10; int iteration; @@ -140,7 +141,7 @@ Point2 Cal3Fisheye::calibrate(const Point2& uv, const double tol) const { const Point2 uv_hat = uncalibrate(pi, boost::none, jac); // Test convergence - if ((uv_hat - uv).norm() < tol) break; + if ((uv_hat - uv).norm() < tol_) break; // Newton's method update step pi = pi - jac.inverse() * (uv_hat - uv); @@ -151,6 +152,8 @@ Point2 Cal3Fisheye::calibrate(const Point2& uv, const double tol) const { "Cal3Fisheye::calibrate fails to converge. need a better " "initialization"); + calibrateJacobians(*this, pi, Dcal, Dp); + return pi; } diff --git a/gtsam/geometry/Cal3Fisheye.h b/gtsam/geometry/Cal3Fisheye.h index e24fe074f..5487019f6 100644 --- a/gtsam/geometry/Cal3Fisheye.h +++ b/gtsam/geometry/Cal3Fisheye.h @@ -14,10 +14,12 @@ * @brief Calibration of a fisheye camera * @date Apr 8, 2020 * @author ghaggin + * @author Varun Agrawal */ #pragma once +#include #include #include @@ -48,6 +50,7 @@ class GTSAM_EXPORT Cal3Fisheye { private: double fx_, fy_, s_, u0_, v0_; // focal length, skew and principal point double k1_, k2_, k3_, k4_; // fisheye distortion coefficients + double tol_ = 1e-5; // tolerance value when calibrating public: enum { dimension = 9 }; @@ -59,11 +62,11 @@ class GTSAM_EXPORT Cal3Fisheye { /// Default Constructor with only unit focal length Cal3Fisheye() - : fx_(1), fy_(1), s_(0), u0_(0), v0_(0), k1_(0), k2_(0), k3_(0), k4_(0) {} + : fx_(1), fy_(1), s_(0), u0_(0), v0_(0), k1_(0), k2_(0), k3_(0), k4_(0), tol_(1e-5) {} Cal3Fisheye(const double fx, const double fy, const double s, const double u0, const double v0, const double k1, const double k2, - const double k3, const double k4) + const double k3, const double k4, double tol = 1e-5) : fx_(fx), fy_(fy), s_(s), @@ -72,7 +75,8 @@ class GTSAM_EXPORT Cal3Fisheye { k1_(k1), k2_(k2), k3_(k3), - k4_(k4) {} + k4_(k4), + tol_(tol) {} virtual ~Cal3Fisheye() {} @@ -139,7 +143,8 @@ class GTSAM_EXPORT Cal3Fisheye { /// Convert (distorted) image coordinates [u;v] to intrinsic coordinates [x_i, /// y_i] - Point2 calibrate(const Point2& p, const double tol = 1e-5) const; + Point2 calibrate(const Point2& p, OptionalJacobian<2, 9> Dcal = boost::none, + OptionalJacobian<2, 2> Dp = boost::none) const; /// @} /// @name Testable diff --git a/gtsam/geometry/Cal3Unified.cpp b/gtsam/geometry/Cal3Unified.cpp index 247e77ae1..f4ce0ed75 100644 --- a/gtsam/geometry/Cal3Unified.cpp +++ b/gtsam/geometry/Cal3Unified.cpp @@ -111,24 +111,7 @@ Point2 Cal3Unified::calibrate(const Point2& pi, OptionalJacobian<2, 10> Dcal, // call nplane to space Point2 pn = this->nPlaneToSpace(pnplane); - // We make use of the Implicit Function Theorem to compute the Jacobians from uncalibrate - // Given f(pi, pn) = uncalibrate(pn) - pi, and g(pi) = calibrate, we can easily compute the Jacobians - // df/pi = -I (pn and pi are independent args) - // Dp = -inv(H_uncal_pn) * df/pi = -inv(H_uncal_pn) * (-I) = inv(H_uncal_pn) - // Dcal = -inv(H_uncal_pn) * df/K = -inv(H_uncal_pn) * H_uncal_K - Eigen::Matrix H_uncal_K; - Matrix22 H_uncal_pn, H_uncal_pn_inv; - - if (Dcal || Dp) { - // Compute uncalibrate Jacobians - uncalibrate(pn, Dcal ? &H_uncal_K : nullptr, H_uncal_pn); - - H_uncal_pn_inv = H_uncal_pn.inverse(); - - if (Dp) *Dp = H_uncal_pn_inv; - if (Dcal) *Dcal = -H_uncal_pn_inv * H_uncal_K; - - } + calibrateJacobians(*this, pn, Dcal, Dp); return pn; } diff --git a/gtsam/geometry/tests/testCal3DFisheye.cpp b/gtsam/geometry/tests/testCal3DFisheye.cpp index 9317fb737..6bfbe3e46 100644 --- a/gtsam/geometry/tests/testCal3DFisheye.cpp +++ b/gtsam/geometry/tests/testCal3DFisheye.cpp @@ -181,6 +181,23 @@ TEST(Cal3Fisheye, calibrate3) { CHECK(assert_equal(xi_hat, xi)); } +Point2 calibrate_(const Cal3Fisheye& k, const Point2& pt) { + return k.calibrate(pt); +} + +/* ************************************************************************* */ +TEST(Cal3Fisheye, Dcalibrate) +{ + Point2 p(0.5, 0.5); + Point2 pi = K.uncalibrate(p); + Matrix Dcal, Dp; + K.calibrate(pi, Dcal, Dp); + Matrix numerical1 = numericalDerivative21(calibrate_, K, pi); + CHECK(assert_equal(numerical1,Dcal,1e-5)); + Matrix numerical2 = numericalDerivative22(calibrate_, K, pi); + CHECK(assert_equal(numerical2,Dp,1e-5)); +} + /* ************************************************************************* */ int main() { TestResult tr; From 602db46f449fc2f9a2629dcce291f4e9a74edd2c Mon Sep 17 00:00:00 2001 From: akrishnan86 Date: Tue, 1 Dec 2020 01:33:43 -0800 Subject: [PATCH 106/261] changing test names and adding documentation --- gtsam/sfm/TranslationRecovery.cpp | 20 ++++++++++++++----- tests/testTranslationRecovery.cpp | 32 +++++++++++++++---------------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/gtsam/sfm/TranslationRecovery.cpp b/gtsam/sfm/TranslationRecovery.cpp index 8d27136e3..d4100b00a 100644 --- a/gtsam/sfm/TranslationRecovery.cpp +++ b/gtsam/sfm/TranslationRecovery.cpp @@ -39,9 +39,13 @@ TranslationRecovery::TranslationRecovery( const TranslationRecovery::TranslationEdges &relativeTranslations, const LevenbergMarquardtParams &lmParams) : params_(lmParams) { - TranslationEdges tempRelativeTranslations; - DSFMap sameTranslationDSF; + // Some relative translations may be zero. We treat nodes that have a zero + // relativeTranslation as a single node. + // A DSFMap is used to find sets of nodes that have a zero relative + // translation. Add the nodes in each edge to the DSFMap, and merge nodes that + // are connected by a zero relative translation. + DSFMap sameTranslationDSF; for (const auto &edge : relativeTranslations) { Key key1 = sameTranslationDSF.find(edge.key1()); Key key2 = sameTranslationDSF.find(edge.key2()); @@ -49,6 +53,7 @@ TranslationRecovery::TranslationRecovery( sameTranslationDSF.merge(key1, key2); } } + // Use only those edges for which two keys have a distinct root in the DSFMap. for (const auto &edge : relativeTranslations) { Key key1 = sameTranslationDSF.find(edge.key1()); Key key2 = sameTranslationDSF.find(edge.key2()); @@ -56,6 +61,7 @@ TranslationRecovery::TranslationRecovery( relativeTranslations_.emplace_back(key1, key2, edge.measured(), edge.noiseModel()); } + // Store the DSF map for post-processing results. sameTranslationNodes_ = sameTranslationDSF.sets(); } @@ -106,9 +112,13 @@ Values TranslationRecovery::run(const double scale) const { LevenbergMarquardtOptimizer lm(graph, initial, params_); Values result = lm.optimize(); - for (const auto &sameTranslationKeys : sameTranslationNodes_) { - Key optimizedKey = sameTranslationKeys.first; - std::set duplicateKeys = sameTranslationKeys.second; + // Nodes that were not optimized are stored in sameTranslationNodes_ as a map + // from a key that was optimized to keys that were not optimized. Iterate over + // map and add results for keys not optimized. + for (const auto &optimizedAndDuplicateKeys : sameTranslationNodes_) { + Key optimizedKey = optimizedAndDuplicateKeys.first; + std::set duplicateKeys = optimizedAndDuplicateKeys.second; + // Add the result for the duplicate key if it does not already exist. for (const Key duplicateKey : duplicateKeys) { if (result.exists(duplicateKey)) continue; result.insert(duplicateKey, result.at(optimizedKey)); diff --git a/tests/testTranslationRecovery.cpp b/tests/testTranslationRecovery.cpp index e4fbd9219..7260fd5af 100644 --- a/tests/testTranslationRecovery.cpp +++ b/tests/testTranslationRecovery.cpp @@ -89,7 +89,7 @@ TEST(TranslationRecovery, BAL) { // EXPECT_DOUBLES_EQUAL(0.0199833, actualError, 1e-5); } -TEST(TranslationRecovery, TwoPointTest) { +TEST(TranslationRecovery, TwoPoseTest) { // Create a dataset with 2 poses. // __ __ // \/ \/ @@ -114,14 +114,14 @@ TEST(TranslationRecovery, TwoPointTest) { EXPECT_LONGS_EQUAL(1, graph.size()); // Run translation recovery - const auto result = algorithm.run(/*scale=*/2.0); + const auto result = algorithm.run(/*scale=*/3.0); // Check result for first two translations, determined by prior EXPECT(assert_equal(Point3(0, 0, 0), result.at(0))); - EXPECT(assert_equal(Point3(2, 0, 0), result.at(1))); + EXPECT(assert_equal(Point3(3, 0, 0), result.at(1))); } -TEST(TranslationRecovery, ThreePointTest) { +TEST(TranslationRecovery, ThreePoseTest) { // Create a dataset with 3 poses. // __ __ // \/ \/ @@ -151,15 +151,15 @@ TEST(TranslationRecovery, ThreePointTest) { const auto graph = algorithm.buildGraph(); EXPECT_LONGS_EQUAL(3, graph.size()); - const auto result = algorithm.run(/*scale=*/2.0); + const auto result = algorithm.run(/*scale=*/3.0); // Check result EXPECT(assert_equal(Point3(0, 0, 0), result.at(0))); - EXPECT(assert_equal(Point3(2, 0, 0), result.at(1))); - EXPECT(assert_equal(Point3(1, -1, 0), result.at(3))); + EXPECT(assert_equal(Point3(3, 0, 0), result.at(1))); + EXPECT(assert_equal(Point3(1.5, -1.5, 0), result.at(3))); } -TEST(TranslationRecovery, TwoPointsAndZeroTranslation) { +TEST(TranslationRecovery, ThreePosesIncludingZeroTranslation) { // Create a dataset with 3 poses. // __ __ // \/ \/ @@ -188,15 +188,15 @@ TEST(TranslationRecovery, TwoPointsAndZeroTranslation) { EXPECT_LONGS_EQUAL(1, graph.size()); // Run translation recovery - const auto result = algorithm.run(/*scale=*/2.0); + const auto result = algorithm.run(/*scale=*/3.0); // Check result EXPECT(assert_equal(Point3(0, 0, 0), result.at(0))); - EXPECT(assert_equal(Point3(2, 0, 0), result.at(1))); - EXPECT(assert_equal(Point3(2, 0, 0), result.at(2))); + EXPECT(assert_equal(Point3(3, 0, 0), result.at(1))); + EXPECT(assert_equal(Point3(3, 0, 0), result.at(2))); } -TEST(TranslationRecovery, ThreePointsAndZeroTranslation) { +TEST(TranslationRecovery, FourPosesIncludingZeroTranslation) { // Create a dataset with 4 poses. // __ __ // \/ \/ @@ -229,13 +229,13 @@ TEST(TranslationRecovery, ThreePointsAndZeroTranslation) { EXPECT_LONGS_EQUAL(3, graph.size()); // Run translation recovery - const auto result = algorithm.run(/*scale=*/2.0); + const auto result = algorithm.run(/*scale=*/4.0); // Check result EXPECT(assert_equal(Point3(0, 0, 0), result.at(0))); - EXPECT(assert_equal(Point3(2, 0, 0), result.at(1))); - EXPECT(assert_equal(Point3(2, 0, 0), result.at(2))); - EXPECT(assert_equal(Point3(1, -1, 0), result.at(3))); + EXPECT(assert_equal(Point3(4, 0, 0), result.at(1))); + EXPECT(assert_equal(Point3(4, 0, 0), result.at(2))); + EXPECT(assert_equal(Point3(2, -2, 0), result.at(3))); } /* ************************************************************************* */ From 1bf7588f72de0d624efdab11de475d9d94aa16ab Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 1 Dec 2020 12:02:44 -0500 Subject: [PATCH 107/261] Revert "added Imu parameter units to doc" This reverts commit 845b6c55b3dc86a4172b480b1fb50a8ac4b5cb7d. --- doc/ImuFactor.lyx | 180 ++++------------------------------------------ doc/ImuFactor.pdf | Bin 176165 -> 198168 bytes 2 files changed, 15 insertions(+), 165 deletions(-) diff --git a/doc/ImuFactor.lyx b/doc/ImuFactor.lyx index 55b7201e5..0922a3e9c 100644 --- a/doc/ImuFactor.lyx +++ b/doc/ImuFactor.lyx @@ -1,5 +1,5 @@ -#LyX 2.1 created this file. For more info see http://www.lyx.org/ -\lyxformat 474 +#LyX 2.0 created this file. For more info see http://www.lyx.org/ +\lyxformat 413 \begin_document \begin_header \textclass article @@ -12,13 +12,13 @@ \font_roman default \font_sans default \font_typewriter default -\font_math auto \font_default_family default \use_non_tex_fonts false \font_sc false \font_osf false \font_sf_scale 100 \font_tt_scale 100 + \graphics default \default_output_format default \output_sync 0 @@ -29,24 +29,15 @@ \use_hyperref false \papersize default \use_geometry true -\use_package amsmath 1 -\use_package amssymb 1 -\use_package cancel 1 -\use_package esint 1 -\use_package mathdots 1 -\use_package mathtools 1 -\use_package mhchem 1 -\use_package stackrel 1 -\use_package stmaryrd 1 -\use_package undertilde 1 +\use_amsmath 1 +\use_esint 1 +\use_mhchem 1 +\use_mathdots 1 \cite_engine basic -\cite_engine_type default -\biblio_style plain \use_bibtopic false \use_indices false \paperorientation portrait \suppress_date false -\justification true \use_refstyle 1 \index Index \shortcut idx @@ -253,7 +244,7 @@ X(t)=\left\{ R_{0},P_{0}+V_{0}t,V_{0}\right\} then the differential equation describing the trajectory is \begin_inset Formula \[ -\dot{X}(t)=\left[0_{3x3},V_{0},0_{3x1}\right],\,\,\,\,\,X(0)=\left\{ R_{0},P_{0},V_{0}\right\} +\dot{X}(t)=\left[0_{3x3},V_{0},0_{3x1}\right],\,\,\,\,\, X(0)=\left\{ R_{0},P_{0},V_{0}\right\} \] \end_inset @@ -611,7 +602,7 @@ key "Iserles00an" , \begin_inset Formula \begin{equation} -\dot{R}(t)=F(R,t),\,\,\,\,R(0)=R_{0}\label{eq:diffSo3} +\dot{R}(t)=F(R,t),\,\,\,\, R(0)=R_{0}\label{eq:diffSo3} \end{equation} \end_inset @@ -956,8 +947,8 @@ Or, as another way to state this, if we solve the differential equations \begin_inset Formula \begin{eqnarray*} \dot{\theta}(t) & = & H(\theta)^{-1}\,\omega^{b}(t)\\ -\dot{p}(t) & = & R_{0}^{T}\,V_{0}+v(t)\\ -\dot{v}(t) & = & R_{0}^{T}\,g+R_{b}^{0}(t)a^{b}(t) +\dot{p}(t) & = & R_{0}^{T}\, V_{0}+v(t)\\ +\dot{v}(t) & = & R_{0}^{T}\, g+R_{b}^{0}(t)a^{b}(t) \end{eqnarray*} \end_inset @@ -1024,7 +1015,7 @@ v(t)=v_{g}(t)+v_{a}(t) evolving as \begin_inset Formula \begin{eqnarray*} -\dot{v}_{g}(t) & = & R_{i}^{T}\,g\\ +\dot{v}_{g}(t) & = & R_{i}^{T}\, g\\ \dot{v}_{a}(t) & = & R_{b}^{i}(t)a^{b}(t) \end{eqnarray*} @@ -1050,7 +1041,7 @@ p(t)=p_{i}(t)+p_{g}(t)+p_{v}(t) evolving as \begin_inset Formula \begin{eqnarray*} -\dot{p}_{i}(t) & = & R_{i}^{T}\,V_{i}\\ +\dot{p}_{i}(t) & = & R_{i}^{T}\, V_{i}\\ \dot{p}_{g}(t) & = & v_{g}(t)=R_{i}^{T}gt\\ \dot{p}_{v}(t) & = & v_{a}(t) \end{eqnarray*} @@ -1105,7 +1096,7 @@ Predict the NavState from \begin_inset Formula \[ -X_{j}=\mathcal{R}_{X_{i}}(\zeta(t_{ij}))=\left\{ \Phi_{R_{0}}\left(\theta(t_{ij})\right),P_{i}+V_{i}t_{ij}+\frac{gt_{ij}^{2}}{2}+R_{i}\,p_{v}(t_{ij}),V_{i}+gt_{ij}+R_{i}\,v_{a}(t_{ij})\right\} +X_{j}=\mathcal{R}_{X_{i}}(\zeta(t_{ij}))=\left\{ \Phi_{R_{0}}\left(\theta(t_{ij})\right),P_{i}+V_{i}t_{ij}+\frac{gt_{ij}^{2}}{2}+R_{i}\, p_{v}(t_{ij}),V_{i}+gt_{ij}+R_{i}\, v_{a}(t_{ij})\right\} \] \end_inset @@ -1381,7 +1372,7 @@ B_{k}=\left[\begin{array}{c} 0_{3\times3}\\ R_{k}\frac{\Delta_{t}}{2}^{2}\\ R_{k}\Delta_{t} -\end{array}\right],\,\,\,\,C_{k}=\left[\begin{array}{c} +\end{array}\right],\,\,\,\, C_{k}=\left[\begin{array}{c} H(\theta_{k})^{-1}\Delta_{t}\\ 0_{3\times3}\\ 0_{3\times3} @@ -1391,147 +1382,6 @@ H(\theta_{k})^{-1}\Delta_{t}\\ \end_inset -\end_layout - -\begin_layout Subsubsection* -Units -\end_layout - -\begin_layout Standard -The units of the IMU are as follows: -\end_layout - -\begin_layout Standard -\begin_inset Tabular - - - - - - -\begin_inset Text - -\begin_layout Plain Layout -Parameter -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -Units -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout -gyro_noise_sigma -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula $rad/s/\sqrt{Hz}$ -\end_inset - - -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout -accel_noise_sigma -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula $m/s^{2}/\sqrt{Hz}$ -\end_inset - - -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout -gyro_bias_rw_sigma -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula $rad/s$ -\end_inset - - or -\begin_inset Formula $rad\sqrt{Hz}/s$ -\end_inset - - -\end_layout - -\end_inset - - - - -\begin_inset Text - -\begin_layout Plain Layout -accel_bias_rw_sigma -\end_layout - -\end_inset - - -\begin_inset Text - -\begin_layout Plain Layout -\begin_inset Formula $m/s^{2}$ -\end_inset - -or -\begin_inset Formula $m\sqrt{Hz}/s^{2}$ -\end_inset - - -\end_layout - -\end_inset - - - - -\end_inset - - \end_layout \begin_layout Standard diff --git a/doc/ImuFactor.pdf b/doc/ImuFactor.pdf index adec08aa3e0e689a9e494b1fc0a21aecc06b2368..0b13c1f5948de38aa6454732ca20367cc630c62c 100644 GIT binary patch delta 186214 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�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≧xk)SWRXQIBB@^t}Tq)>?wLOM+iQ%_%~^ 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νa~I*fu9(YyyD)6XtSN1zDMtK%+z?{m(le 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 Date: Tue, 1 Dec 2020 12:02:56 -0500 Subject: [PATCH 108/261] Revert "formatting" This reverts commit 31bf4b38ca2c31e355ec628169874d919845862d. --- cmake/GtsamTesting.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/GtsamTesting.cmake b/cmake/GtsamTesting.cmake index 4f32d90a5..3b42ffa21 100644 --- a/cmake/GtsamTesting.cmake +++ b/cmake/GtsamTesting.cmake @@ -88,7 +88,7 @@ enable_testing() option(GTSAM_BUILD_TESTS "Enable/Disable building of tests" ON) option(GTSAM_BUILD_EXAMPLES_ALWAYS "Build examples with 'make all' (build with 'make examples' if not)" ON) -option(GTSAM_BUILD_TIMING_ALWAYS "Build timing scripts with 'make all' (build with 'make timing' if not" OFF) + option(GTSAM_BUILD_TIMING_ALWAYS "Build timing scripts with 'make all' (build with 'make timing' if not" OFF) # Add option for combining unit tests if(MSVC OR XCODE_VERSION) From 6d2e306aa8781eedf4af470259609858e480e2a0 Mon Sep 17 00:00:00 2001 From: akrishnan86 Date: Tue, 1 Dec 2020 09:10:32 -0800 Subject: [PATCH 109/261] documenting member variables --- gtsam/sfm/TranslationRecovery.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gtsam/sfm/TranslationRecovery.h b/gtsam/sfm/TranslationRecovery.h index 9ffe45685..c99836853 100644 --- a/gtsam/sfm/TranslationRecovery.h +++ b/gtsam/sfm/TranslationRecovery.h @@ -54,8 +54,14 @@ class TranslationRecovery { using TranslationEdges = std::vector>; private: + // Translation directions between camera pairs. TranslationEdges relativeTranslations_; + + // Parameters used by the LM Optimizer. LevenbergMarquardtParams params_; + + // Map from a key in the graph to a set of keys that share the same + // translation. std::map> sameTranslationNodes_; public: From a4d443efe913a6bb62228b15dc972441d36e6b3d Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 1 Dec 2020 12:14:57 -0500 Subject: [PATCH 110/261] Added units for imu noise and bias sigmas --- gtsam/navigation/ImuBias.h | 4 ++-- gtsam/navigation/PreintegratedRotation.h | 4 +++- gtsam/navigation/PreintegrationParams.h | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/gtsam/navigation/ImuBias.h b/gtsam/navigation/ImuBias.h index d52b4eb29..fad952232 100644 --- a/gtsam/navigation/ImuBias.h +++ b/gtsam/navigation/ImuBias.h @@ -29,8 +29,8 @@ namespace imuBias { class GTSAM_EXPORT ConstantBias { private: - Vector3 biasAcc_; - Vector3 biasGyro_; + Vector3 biasAcc_; ///< The units for stddev are σ = m/s² or m √Hz/s² + Vector3 biasGyro_; ///< The units for stddev are σ = rad/s or rad √Hz/s public: /// dimension of the variable - used to autodetect sizes diff --git a/gtsam/navigation/PreintegratedRotation.h b/gtsam/navigation/PreintegratedRotation.h index 0e0559a32..e52d28e1e 100644 --- a/gtsam/navigation/PreintegratedRotation.h +++ b/gtsam/navigation/PreintegratedRotation.h @@ -29,7 +29,9 @@ namespace gtsam { /// Parameters for pre-integration: /// Usage: Create just a single Params and pass a shared pointer to the constructor struct GTSAM_EXPORT PreintegratedRotationParams { - Matrix3 gyroscopeCovariance; ///< continuous-time "Covariance" of gyroscope measurements + /// Continuous-time "Covariance" of gyroscope measurements + /// The units for stddev are σ = rad/s/√Hz + Matrix3 gyroscopeCovariance; boost::optional omegaCoriolis; ///< Coriolis constant boost::optional body_P_sensor; ///< The pose of the sensor in the body frame diff --git a/gtsam/navigation/PreintegrationParams.h b/gtsam/navigation/PreintegrationParams.h index ce1f0e734..960f67e24 100644 --- a/gtsam/navigation/PreintegrationParams.h +++ b/gtsam/navigation/PreintegrationParams.h @@ -24,7 +24,9 @@ namespace gtsam { /// Parameters for pre-integration: /// Usage: Create just a single Params and pass a shared pointer to the constructor struct GTSAM_EXPORT PreintegrationParams: PreintegratedRotationParams { - Matrix3 accelerometerCovariance; ///< continuous-time "Covariance" of accelerometer + /// Continuous-time "Covariance" of accelerometer + /// The units for stddev are σ = m/s²/√Hz + Matrix3 accelerometerCovariance; Matrix3 integrationCovariance; ///< continuous-time "Covariance" describing integration uncertainty bool use2ndOrderCoriolis; ///< Whether to use second order Coriolis integration Vector3 n_gravity; ///< Gravity vector in nav frame From 06d4933e1bf6c80830f079f3c6dc0baa43e7c1e1 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 1 Dec 2020 12:46:05 -0500 Subject: [PATCH 111/261] common header file for all calibration models --- gtsam/geometry/Cal3.h | 66 +++++++++++++++++++++++++++++++++++ gtsam/geometry/Cal3Bundler.h | 2 +- gtsam/geometry/Cal3DS2_Base.h | 34 +----------------- gtsam/geometry/Cal3Fisheye.h | 2 +- 4 files changed, 69 insertions(+), 35 deletions(-) create mode 100644 gtsam/geometry/Cal3.h diff --git a/gtsam/geometry/Cal3.h b/gtsam/geometry/Cal3.h new file mode 100644 index 000000000..d9e12f7d2 --- /dev/null +++ b/gtsam/geometry/Cal3.h @@ -0,0 +1,66 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file Cal3.h + * @brief Common code for all Calibration models. + * @author Varun Agrawal + */ + +/** + * @addtogroup geometry + */ + +#pragma once + +#include + +namespace gtsam { + +/** + * Function which makes use of the Implicit Function Theorem to compute the + * Jacobians of `calibrate` using `uncalibrate`. + * This is useful when there are iterative operations in the `calibrate` + * function which make computing jacobians difficult. + * + * Given f(pi, pn) = uncalibrate(pn) - pi, and g(pi) = calibrate, we can + * easily compute the Jacobians: + * df/pi = -I (pn and pi are independent args) + * Dp = -inv(H_uncal_pn) * df/pi = -inv(H_uncal_pn) * (-I) = inv(H_uncal_pn) + * Dcal = -inv(H_uncal_pn) * df/K = -inv(H_uncal_pn) * H_uncal_K + * + * @tparam Cal Calibration model. + * @tparam Dim The number of parameters in the calibration model. + * @param p Calibrated point. + * @param Dcal optional 2*p Jacobian wrpt `p` Cal3DS2 parameters. + * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates. + */ +template +void calibrateJacobians(const Cal& calibration, const Point2& pn, + OptionalJacobian<2, Dim> Dcal = boost::none, + OptionalJacobian<2, 2> Dp = boost::none) { + if (Dcal || Dp) { + Eigen::Matrix H_uncal_K; + Matrix22 H_uncal_pn, H_uncal_pn_inv; + + // Compute uncalibrate Jacobians + calibration.uncalibrate(pn, Dcal ? &H_uncal_K : nullptr, H_uncal_pn); + + H_uncal_pn_inv = H_uncal_pn.inverse(); + + if (Dp) *Dp = H_uncal_pn_inv; + if (Dcal) *Dcal = -H_uncal_pn_inv * H_uncal_K; + } +} + +//TODO(Varun) Make common base class for all calibration models. + +} // \ namespace gtsam diff --git a/gtsam/geometry/Cal3Bundler.h b/gtsam/geometry/Cal3Bundler.h index da43112d9..8c836b504 100644 --- a/gtsam/geometry/Cal3Bundler.h +++ b/gtsam/geometry/Cal3Bundler.h @@ -18,7 +18,7 @@ #pragma once -#include +#include #include namespace gtsam { diff --git a/gtsam/geometry/Cal3DS2_Base.h b/gtsam/geometry/Cal3DS2_Base.h index c9b53c29b..dbd6478e1 100644 --- a/gtsam/geometry/Cal3DS2_Base.h +++ b/gtsam/geometry/Cal3DS2_Base.h @@ -19,43 +19,11 @@ #pragma once +#include #include namespace gtsam { -/** - * Function which makes use of the Implicit Function Theorem to compute the - * Jacobians of `calibrate` using `uncalibrate`. - * Given f(pi, pn) = uncalibrate(pn) - pi, and g(pi) = calibrate, we can - * easily compute the Jacobians: - * df/pi = -I (pn and pi are independent args) - * Dp = -inv(H_uncal_pn) * df/pi = -inv(H_uncal_pn) * (-I) = inv(H_uncal_pn) - * Dcal = -inv(H_uncal_pn) * df/K = -inv(H_uncal_pn) * H_uncal_K - * - * @tparam T Calibration model. - * @tparam Dim The number of parameters in the calibration model. - * @param p Calibrated point. - * @param Dcal optional 2*p Jacobian wrpt `p` Cal3DS2 parameters. - * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates. - */ -template -void calibrateJacobians(const T& calibration, const Point2& pn, - OptionalJacobian<2, Dim> Dcal = boost::none, - OptionalJacobian<2, 2> Dp = boost::none) { - if (Dcal || Dp) { - Eigen::Matrix H_uncal_K; - Matrix22 H_uncal_pn, H_uncal_pn_inv; - - // Compute uncalibrate Jacobians - calibration.uncalibrate(pn, H_uncal_K, H_uncal_pn); - - H_uncal_pn_inv = H_uncal_pn.inverse(); - - if (Dp) *Dp = H_uncal_pn_inv; - if (Dcal) *Dcal = -H_uncal_pn_inv * H_uncal_K; - } -} - /** * @brief Calibration of a camera with radial distortion * @addtogroup geometry diff --git a/gtsam/geometry/Cal3Fisheye.h b/gtsam/geometry/Cal3Fisheye.h index 5487019f6..77e122f21 100644 --- a/gtsam/geometry/Cal3Fisheye.h +++ b/gtsam/geometry/Cal3Fisheye.h @@ -19,7 +19,7 @@ #pragma once -#include +#include #include #include From 04fb3390bebfddfe13dd758417779ca6ff1105d4 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 1 Dec 2020 16:02:25 -0500 Subject: [PATCH 112/261] Base class for all calibration models --- gtsam/geometry/Cal3.cpp | 72 ++++++++++++++++++++++ gtsam/geometry/Cal3.h | 131 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 gtsam/geometry/Cal3.cpp diff --git a/gtsam/geometry/Cal3.cpp b/gtsam/geometry/Cal3.cpp new file mode 100644 index 000000000..240d01e12 --- /dev/null +++ b/gtsam/geometry/Cal3.cpp @@ -0,0 +1,72 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file Cal3.cpp + * @brief Common code for all calibration models. + * @author Frank Dellaert + */ + +#include + +#include +#include +#include + +namespace gtsam { +using namespace std; + +/* ************************************************************************* */ +Cal3::Cal3(double fov, int w, int h) + : s_(0), u0_((double)w / 2.0), v0_((double)h / 2.0) { + double a = fov * M_PI / 360.0; // fov/2 in radians + fx_ = + (double)w / (2.0 * tan(a)); // old formula: fx_ = (double) w * tan(a); + fy_ = fx_; +} + +/* ************************************************************************* */ +Cal3::Cal3(const std::string& path) + : fx_(320), fy_(320), s_(0), u0_(320), v0_(140) { + char buffer[200]; + buffer[0] = 0; + sprintf(buffer, "%s/calibration_info.txt", path.c_str()); + std::ifstream infile(buffer, std::ios::in); + + if (infile) + infile >> fx_ >> fy_ >> s_ >> u0_ >> v0_; + else { + throw std::runtime_error("Cal3: Unable to load the calibration"); + } + + infile.close(); +} + +/* ************************************************************************* */ +ostream& operator<<(ostream& os, const Cal3& cal) { + os << "{fx: " << cal.fx() << ", fy: " << cal.fy() << ", s:" << cal.skew() + << ", px:" << cal.px() << ", py:" << cal.py() << "}"; + return os; +} + +/* ************************************************************************* */ +void Cal3::print(const std::string& s) const { gtsam::print((Matrix)K(), s); } + +/* ************************************************************************* */ +bool Cal3::equals(const Cal3& K, double tol) const { + return (std::abs(fx_ - K.fx_) < tol) && (std::abs(fy_ - K.fy_) < tol) && + (std::abs(s_ - K.s_) < tol) && (std::abs(u0_ - K.u0_) < tol) && + (std::abs(v0_ - K.v0_) < tol); +} + +/* ************************************************************************* */ + +} // namespace gtsam diff --git a/gtsam/geometry/Cal3.h b/gtsam/geometry/Cal3.h index d9e12f7d2..13cd4de69 100644 --- a/gtsam/geometry/Cal3.h +++ b/gtsam/geometry/Cal3.h @@ -30,7 +30,7 @@ namespace gtsam { * Jacobians of `calibrate` using `uncalibrate`. * This is useful when there are iterative operations in the `calibrate` * function which make computing jacobians difficult. - * + * * Given f(pi, pn) = uncalibrate(pn) - pi, and g(pi) = calibrate, we can * easily compute the Jacobians: * df/pi = -I (pn and pi are independent args) @@ -61,6 +61,133 @@ void calibrateJacobians(const Cal& calibration, const Point2& pn, } } -//TODO(Varun) Make common base class for all calibration models. +/** + * @brief Common base class for all calibration models. + * @addtogroup geometry + * \nosubgrouping + */ +class GTSAM_EXPORT Cal3 { + protected: + double fx_, fy_, s_, u0_, v0_; + + public: + enum { dimension = 5 }; + typedef boost::shared_ptr + shared_ptr; ///< shared pointer to calibration object + + /// @name Standard Constructors + /// @{ + + /// Create a default calibration that leaves coordinates unchanged + Cal3() : fx_(1), fy_(1), s_(0), u0_(0), v0_(0) {} + + /// constructor from doubles + Cal3(double fx, double fy, double s, double u0, double v0) + : fx_(fx), fy_(fy), s_(s), u0_(u0), v0_(v0) {} + + /// constructor from vector + Cal3(const Vector& d) + : fx_(d(0)), fy_(d(1)), s_(d(2)), u0_(d(3)), v0_(d(4)) {} + + /** + * Easy constructor, takes fov in degrees, asssumes zero skew, unit aspect + * @param fov field of view in degrees + * @param w image width + * @param h image height + */ + Cal3(double fov, int w, int h); + + /// @} + /// @name Advanced Constructors + /// @{ + + /// load calibration from location (default name is calibration_info.txt) + Cal3(const std::string& path); + + /// @} + /// @name Testable + /// @{ + + /// Output stream operator + GTSAM_EXPORT friend std::ostream& operator<<(std::ostream& os, + const Cal3& cal); + + /// print with optional string + virtual void print(const std::string& s = "Cal3") const; + + /// Check if equal up to specified tolerance + bool equals(const Cal3& K, double tol = 10e-9) const; + + /// @} + /// @name Standard Interface + /// @{ + + /// focal length x + inline double fx() const { return fx_; } + + /// focal length y + inline double fy() const { return fy_; } + + /// aspect ratio + inline double aspectRatio() const { return fx_ / fy_; } + + /// skew + inline double skew() const { return s_; } + + /// image center in x + inline double px() const { return u0_; } + + /// image center in y + inline double py() const { return v0_; } + + /// return the principal point + Point2 principalPoint() const { return Point2(u0_, v0_); } + + /// vectorized form (column-wise) + Vector5 vector() const { + Vector5 v; + v << fx_, fy_, s_, u0_, v0_; + return v; + } + + /// return calibration matrix K + Matrix3 K() const { + Matrix3 K; + K << fx_, s_, u0_, 0.0, fy_, v0_, 0.0, 0.0, 1.0; + return K; + } + +#ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V41 + /** @deprecated The following function has been deprecated, use K above */ + Matrix3 matrix() const { return K(); } +#endif + + /// return inverted calibration matrix inv(K) + Matrix3 matrix_inverse() const { + const double fxy = fx_ * fy_, sv0 = s_ * v0_, fyu0 = fy_ * u0_; + Matrix3 K_inverse; + K_inverse << 1.0 / fx_, -s_ / fxy, (sv0 - fyu0) / fxy, 0.0, 1.0 / fy_, + -v0_ / fy_, 0.0, 0.0, 1.0; + return K_inverse; + } + + /// @} + /// @name Advanced Interface + /// @{ + + private: + /// Serialization function + friend class boost::serialization::access; + template + void serialize(Archive& ar, const unsigned int /*version*/) { + ar& BOOST_SERIALIZATION_NVP(fx_); + ar& BOOST_SERIALIZATION_NVP(fy_); + ar& BOOST_SERIALIZATION_NVP(s_); + ar& BOOST_SERIALIZATION_NVP(u0_); + ar& BOOST_SERIALIZATION_NVP(v0_); + } + + /// @} +}; } // \ namespace gtsam From ad66a5927dc2512b14e1f0cfa9931c9e0b39ca9d Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 1 Dec 2020 16:03:47 -0500 Subject: [PATCH 113/261] Refactor Cal3_S2 and Cal3_S2Stereo classes --- gtsam/geometry/Cal3_S2.cpp | 87 ++++--------- gtsam/geometry/Cal3_S2.h | 188 ++++++++------------------- gtsam/geometry/Cal3_S2Stereo.cpp | 13 +- gtsam/geometry/Cal3_S2Stereo.h | 59 +++------ gtsam/geometry/tests/testCal3_S2.cpp | 1 - 5 files changed, 102 insertions(+), 246 deletions(-) diff --git a/gtsam/geometry/Cal3_S2.cpp b/gtsam/geometry/Cal3_S2.cpp index b3d1be4b6..12635abdd 100644 --- a/gtsam/geometry/Cal3_S2.cpp +++ b/gtsam/geometry/Cal3_S2.cpp @@ -24,93 +24,52 @@ namespace gtsam { using namespace std; -/* ************************************************************************* */ -Cal3_S2::Cal3_S2(double fov, int w, int h) : - s_(0), u0_((double) w / 2.0), v0_((double) h / 2.0) { - double a = fov * M_PI / 360.0; // fov/2 in radians - fx_ = (double) w / (2.0 * tan(a)); // old formula: fx_ = (double) w * tan(a); - fy_ = fx_; -} - -/* ************************************************************************* */ -Cal3_S2::Cal3_S2(const std::string &path) : - fx_(320), fy_(320), s_(0), u0_(320), v0_(140) { - - char buffer[200]; - buffer[0] = 0; - sprintf(buffer, "%s/calibration_info.txt", path.c_str()); - std::ifstream infile(buffer, std::ios::in); - - if (infile) - infile >> fx_ >> fy_ >> s_ >> u0_ >> v0_; - else { - throw std::runtime_error("Cal3_S2: Unable to load the calibration"); - } - - infile.close(); -} - /* ************************************************************************* */ ostream& operator<<(ostream& os, const Cal3_S2& cal) { - os << "{fx: " << cal.fx() << ", fy: " << cal.fy() << ", s:" << cal.skew() << ", px:" << cal.px() - << ", py:" << cal.py() << "}"; + os << "{fx: " << cal.fx() << ", fy: " << cal.fy() << ", s:" << cal.skew() + << ", px:" << cal.px() << ", py:" << cal.py() << "}"; return os; } /* ************************************************************************* */ void Cal3_S2::print(const std::string& s) const { - gtsam::print((Matrix)matrix(), s); + gtsam::print((Matrix)K(), s); } /* ************************************************************************* */ bool Cal3_S2::equals(const Cal3_S2& K, double tol) const { - if (std::abs(fx_ - K.fx_) > tol) - return false; - if (std::abs(fy_ - K.fy_) > tol) - return false; - if (std::abs(s_ - K.s_) > tol) - return false; - if (std::abs(u0_ - K.u0_) > tol) - return false; - if (std::abs(v0_ - K.v0_) > tol) - return false; - return true; + return Cal3::equals(K, tol); } /* ************************************************************************* */ Point2 Cal3_S2::uncalibrate(const Point2& p, OptionalJacobian<2, 5> Dcal, - OptionalJacobian<2, 2> Dp) const { + OptionalJacobian<2, 2> Dp) const { const double x = p.x(), y = p.y(); - if (Dcal) - *Dcal << x, 0.0, y, 1.0, 0.0, 0.0, y, 0.0, 0.0, 1.0; - if (Dp) - *Dp << fx_, s_, 0.0, fy_; + if (Dcal) *Dcal << x, 0.0, y, 1.0, 0.0, 0.0, y, 0.0, 0.0, 1.0; + if (Dp) *Dp << fx_, s_, 0.0, fy_; return Point2(fx_ * x + s_ * y + u0_, fy_ * y + v0_); } /* ************************************************************************* */ -Point2 Cal3_S2::calibrate(const Point2& p, OptionalJacobian<2,5> Dcal, - OptionalJacobian<2,2> Dp) const { - const double u = p.x(), v = p.y(); - double delta_u = u - u0_, delta_v = v - v0_; - double inv_fx = 1/ fx_, inv_fy = 1/fy_; - double inv_fy_delta_v = inv_fy * delta_v, inv_fx_s_inv_fy = inv_fx * s_ * inv_fy; - Point2 point(inv_fx * (delta_u - s_ * inv_fy_delta_v), - inv_fy_delta_v); - if(Dcal) - *Dcal << - inv_fx * point.x(), inv_fx * s_ * inv_fy * inv_fy_delta_v, -inv_fx * point.y(), - -inv_fx, inv_fx_s_inv_fy, - 0, -inv_fy * point.y(), 0, 0, -inv_fy; - if(Dp) - *Dp << inv_fx, -inv_fx_s_inv_fy, 0, inv_fy; - return point; +Point2 Cal3_S2::calibrate(const Point2& p, OptionalJacobian<2, 5> Dcal, + OptionalJacobian<2, 2> Dp) const { + const double u = p.x(), v = p.y(); + double delta_u = u - u0_, delta_v = v - v0_; + double inv_fx = 1 / fx_, inv_fy = 1 / fy_; + double inv_fy_delta_v = inv_fy * delta_v, + inv_fx_s_inv_fy = inv_fx * s_ * inv_fy; + Point2 point(inv_fx * (delta_u - s_ * inv_fy_delta_v), inv_fy_delta_v); + if (Dcal) + *Dcal << -inv_fx * point.x(), inv_fx * s_ * inv_fy * inv_fy_delta_v, + -inv_fx * point.y(), -inv_fx, inv_fx_s_inv_fy, 0, -inv_fy * point.y(), + 0, 0, -inv_fy; + if (Dp) *Dp << inv_fx, -inv_fx_s_inv_fy, 0, inv_fy; + return point; } /* ************************************************************************* */ -Vector3 Cal3_S2::calibrate(const Vector3& p) const { - return matrix_inverse() * p; -} +Vector3 Cal3_S2::calibrate(const Vector3& p) const { return matrix_inverse() * p; } /* ************************************************************************* */ -} // namespace gtsam +} // namespace gtsam diff --git a/gtsam/geometry/Cal3_S2.h b/gtsam/geometry/Cal3_S2.h index f2848d0a3..aef27323e 100644 --- a/gtsam/geometry/Cal3_S2.h +++ b/gtsam/geometry/Cal3_S2.h @@ -21,6 +21,7 @@ #pragma once +#include #include namespace gtsam { @@ -30,31 +31,24 @@ namespace gtsam { * @addtogroup geometry * \nosubgrouping */ -class GTSAM_EXPORT Cal3_S2 { -private: - double fx_, fy_, s_, u0_, v0_; - -public: +class GTSAM_EXPORT Cal3_S2 : public Cal3 { + public: enum { dimension = 5 }; - typedef boost::shared_ptr shared_ptr; ///< shared pointer to calibration object + typedef boost::shared_ptr + shared_ptr; ///< shared pointer to calibration object /// @name Standard Constructors /// @{ /// Create a default calibration that leaves coordinates unchanged - Cal3_S2() : - fx_(1), fy_(1), s_(0), u0_(0), v0_(0) { - } + Cal3_S2() : Cal3() {} /// constructor from doubles - Cal3_S2(double fx, double fy, double s, double u0, double v0) : - fx_(fx), fy_(fy), s_(s), u0_(u0), v0_(v0) { - } + Cal3_S2(double fx, double fy, double s, double u0, double v0) + : Cal3(fx, fy, s, u0, v0) {} /// constructor from vector - Cal3_S2(const Vector &d) : - fx_(d(0)), fy_(d(1)), s_(d(2)), u0_(d(3)), v0_(d(4)) { - } + Cal3_S2(const Vector& d) : Cal3(d) {} /** * Easy constructor, takes fov in degrees, asssumes zero skew, unit aspect @@ -62,132 +56,59 @@ public: * @param w image width * @param h image height */ - Cal3_S2(double fov, int w, int h); + Cal3_S2(double fov, int w, int h) : Cal3(fov, w, h) {} - /// @} - /// @name Advanced Constructors - /// @{ + /** + * Convert intrinsic coordinates xy to image coordinates uv, fixed derivaitves + * @param p point in intrinsic coordinates + * @param Dcal optional 2*5 Jacobian wrpt Cal3 parameters + * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates + * @return point in image coordinates + */ + Point2 uncalibrate(const Point2& p, OptionalJacobian<2, 5> Dcal = boost::none, + OptionalJacobian<2, 2> Dp = boost::none) const; - /// load calibration from location (default name is calibration_info.txt) - Cal3_S2(const std::string &path); + /** + * Convert image coordinates uv to intrinsic coordinates xy + * @param p point in image coordinates + * @param Dcal optional 2*5 Jacobian wrpt Cal3 parameters + * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates + * @return point in intrinsic coordinates + */ + Point2 calibrate(const Point2& p, OptionalJacobian<2, 5> Dcal = boost::none, + OptionalJacobian<2, 2> Dp = boost::none) const; + + /** + * Convert homogeneous image coordinates to intrinsic coordinates + * @param p point in image coordinates + * @return point in intrinsic coordinates + */ + Vector3 calibrate(const Vector3& p) const; /// @} /// @name Testable /// @{ /// Output stream operator - GTSAM_EXPORT friend std::ostream &operator<<(std::ostream &os, const Cal3_S2& cal); + GTSAM_EXPORT friend std::ostream& operator<<(std::ostream& os, + const Cal3_S2& cal); /// print with optional string - void print(const std::string& s = "Cal3_S2") const; + void print(const std::string& s = "Cal3_S2") const override; /// Check if equal up to specified tolerance bool equals(const Cal3_S2& K, double tol = 10e-9) const; - /// @} - /// @name Standard Interface - /// @{ - - /// focal length x - inline double fx() const { - return fx_; - } - - /// focal length y - inline double fy() const { - return fy_; - } - - /// aspect ratio - inline double aspectRatio() const { - return fx_/fy_; - } - - /// skew - inline double skew() const { - return s_; - } - - /// image center in x - inline double px() const { - return u0_; - } - - /// image center in y - inline double py() const { - return v0_; - } - - /// return the principal point - Point2 principalPoint() const { - return Point2(u0_, v0_); - } - - /// vectorized form (column-wise) - Vector5 vector() const { - Vector5 v; - v << fx_, fy_, s_, u0_, v0_; - return v; - } - - /// return calibration matrix K - Matrix3 K() const { - Matrix3 K; - K << fx_, s_, u0_, 0.0, fy_, v0_, 0.0, 0.0, 1.0; - return K; - } - - /** @deprecated The following function has been deprecated, use K above */ - Matrix3 matrix() const { - return K(); - } - - /// return inverted calibration matrix inv(K) - Matrix3 matrix_inverse() const { - const double fxy = fx_ * fy_, sv0 = s_ * v0_, fyu0 = fy_ * u0_; - Matrix3 K_inverse; - K_inverse << 1.0 / fx_, -s_ / fxy, (sv0 - fyu0) / fxy, 0.0, - 1.0 / fy_, -v0_ / fy_, 0.0, 0.0, 1.0; - return K_inverse; - } - - /** - * convert intrinsic coordinates xy to image coordinates uv, fixed derivaitves - * @param p point in intrinsic coordinates - * @param Dcal optional 2*5 Jacobian wrpt Cal3_S2 parameters - * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates - * @return point in image coordinates - */ - Point2 uncalibrate(const Point2& p, OptionalJacobian<2,5> Dcal = boost::none, - OptionalJacobian<2,2> Dp = boost::none) const; - - /** - * convert image coordinates uv to intrinsic coordinates xy - * @param p point in image coordinates - * @param Dcal optional 2*5 Jacobian wrpt Cal3_S2 parameters - * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates - * @return point in intrinsic coordinates - */ - Point2 calibrate(const Point2& p, OptionalJacobian<2,5> Dcal = boost::none, - OptionalJacobian<2,2> Dp = boost::none) const; - - /** - * convert homogeneous image coordinates to intrinsic coordinates - * @param p point in image coordinates - * @return point in intrinsic coordinates - */ - Vector3 calibrate(const Vector3& p) const; - /// "Between", subtracts calibrations. between(p,q) == compose(inverse(p),q) inline Cal3_S2 between(const Cal3_S2& q, - OptionalJacobian<5,5> H1=boost::none, - OptionalJacobian<5,5> H2=boost::none) const { - if(H1) *H1 = -I_5x5; - if(H2) *H2 = I_5x5; - return Cal3_S2(q.fx_-fx_, q.fy_-fy_, q.s_-s_, q.u0_-u0_, q.v0_-v0_); + OptionalJacobian<5, 5> H1 = boost::none, + OptionalJacobian<5, 5> H2 = boost::none) const { + if (H1) *H1 = -I_5x5; + if (H2) *H2 = I_5x5; + return Cal3_S2(q.fx_ - fx_, q.fy_ - fy_, q.s_ - s_, q.u0_ - u0_, + q.v0_ - v0_); } - /// @} /// @name Manifold /// @{ @@ -212,27 +133,22 @@ public: /// @name Advanced Interface /// @{ -private: - + private: /// Serialization function friend class boost::serialization::access; - template - void serialize(Archive & ar, const unsigned int /*version*/) { - ar & BOOST_SERIALIZATION_NVP(fx_); - ar & BOOST_SERIALIZATION_NVP(fy_); - ar & BOOST_SERIALIZATION_NVP(s_); - ar & BOOST_SERIALIZATION_NVP(u0_); - ar & BOOST_SERIALIZATION_NVP(v0_); + template + void serialize(Archive& ar, const unsigned int /*version*/) { + ar& boost::serialization::make_nvp( + "Cal3_S2", boost::serialization::base_object(*this)); } /// @} - }; -template<> +template <> struct traits : public internal::Manifold {}; -template<> +template <> struct traits : public internal::Manifold {}; -} // \ namespace gtsam +} // \ namespace gtsam diff --git a/gtsam/geometry/Cal3_S2Stereo.cpp b/gtsam/geometry/Cal3_S2Stereo.cpp index 9b5aea4ed..b4e70202e 100644 --- a/gtsam/geometry/Cal3_S2Stereo.cpp +++ b/gtsam/geometry/Cal3_S2Stereo.cpp @@ -24,16 +24,17 @@ using namespace std; /* ************************************************************************* */ void Cal3_S2Stereo::print(const std::string& s) const { - K_.print(s+"K: "); - std::cout << s << "Baseline: " << b_ << std::endl; - } + std::cout << s << (s != "" ? " " : ""); + print("K: "); + std::cout << "Baseline: " << b_ << std::endl; +} /* ************************************************************************* */ bool Cal3_S2Stereo::equals(const Cal3_S2Stereo& other, double tol) const { - if (std::abs(b_ - other.b_) > tol) return false; - return K_.equals(other.K_,tol); + const Cal3_S2* base = dynamic_cast(&other); + return Cal3_S2::equals(*base, tol) && (std::abs(b_ - other.baseline()) < tol); } /* ************************************************************************* */ -} // namespace gtsam +} // namespace gtsam diff --git a/gtsam/geometry/Cal3_S2Stereo.h b/gtsam/geometry/Cal3_S2Stereo.h index a6eb41b60..258cd0434 100644 --- a/gtsam/geometry/Cal3_S2Stereo.h +++ b/gtsam/geometry/Cal3_S2Stereo.h @@ -27,43 +27,40 @@ namespace gtsam { * @addtogroup geometry * \nosubgrouping */ - class GTSAM_EXPORT Cal3_S2Stereo { + class GTSAM_EXPORT Cal3_S2Stereo : public Cal3_S2 { private: - - Cal3_S2 K_; double b_; public: enum { dimension = 6 }; - typedef boost::shared_ptr shared_ptr; ///< shared pointer to stereo calibration object + ///< shared pointer to stereo calibration object + typedef boost::shared_ptr shared_ptr; /// @name Standard Constructors /// @ /// default calibration leaves coordinates unchanged - Cal3_S2Stereo() : - K_(1, 1, 0, 0, 0), b_(1.0) { - } + Cal3_S2Stereo() : Cal3_S2(1, 1, 0, 0, 0), b_(1.0) {} /// constructor from doubles - Cal3_S2Stereo(double fx, double fy, double s, double u0, double v0, double b) : - K_(fx, fy, s, u0, v0), b_(b) { - } + Cal3_S2Stereo(double fx, double fy, double s, double u0, double v0, + double b) + : Cal3_S2(fx, fy, s, u0, v0), b_(b) {} /// constructor from vector - Cal3_S2Stereo(const Vector &d): K_(d(0), d(1), d(2), d(3), d(4)), b_(d(5)){} + Cal3_S2Stereo(const Vector& d) + : Cal3_S2(d(0), d(1), d(2), d(3), d(4)), b_(d(5)) {} /// easy constructor; field-of-view in degrees, assumes zero skew - Cal3_S2Stereo(double fov, int w, int h, double b) : - K_(fov, w, h), b_(b) { - } + Cal3_S2Stereo(double fov, int w, int h, double b) + : Cal3_S2(fov, w, h), b_(b) {} /// @} /// @name Testable /// @{ - void print(const std::string& s = "") const; + void print(const std::string& s = "") const override; /// Check if equal up to specified tolerance bool equals(const Cal3_S2Stereo& other, double tol = 10e-9) const; @@ -73,28 +70,10 @@ namespace gtsam { /// @{ /// return calibration, same for left and right - const Cal3_S2& calibration() const { return K_;} + const Cal3_S2& calibration() const { return *this; } /// return calibration matrix K, same for left and right - Matrix matrix() const { return K_.matrix();} - - /// focal length x - inline double fx() const { return K_.fx();} - - /// focal length x - inline double fy() const { return K_.fy();} - - /// skew - inline double skew() const { return K_.skew();} - - /// image center in x - inline double px() const { return K_.px();} - - /// image center in y - inline double py() const { return K_.py();} - - /// return the principal point - Point2 principalPoint() const { return K_.principalPoint();} + Matrix3 K() const { return K(); } /// return baseline inline double baseline() const { return b_; } @@ -102,7 +81,7 @@ namespace gtsam { /// vectorized form (column-wise) Vector6 vector() const { Vector6 v; - v << K_.vector(), b_; + v << vector(), b_; return v; } @@ -118,7 +97,8 @@ namespace gtsam { /// Given 6-dim tangent vector, create new calibration inline Cal3_S2Stereo retract(const Vector& d) const { - return Cal3_S2Stereo(K_.fx() + d(0), K_.fy() + d(1), K_.skew() + d(2), K_.px() + d(3), K_.py() + d(4), b_ + d(5)); + return Cal3_S2Stereo(fx() + d(0), fy() + d(1), skew() + d(2), px() + d(3), + py() + d(4), b_ + d(5)); } /// Unretraction for the calibration @@ -137,8 +117,9 @@ namespace gtsam { template void serialize(Archive & ar, const unsigned int /*version*/) { - ar & BOOST_SERIALIZATION_NVP(K_); - ar & BOOST_SERIALIZATION_NVP(b_); + ar& boost::serialization::make_nvp( + "Cal3_S2", boost::serialization::base_object(*this)); + ar& BOOST_SERIALIZATION_NVP(b_); } /// @} diff --git a/gtsam/geometry/tests/testCal3_S2.cpp b/gtsam/geometry/tests/testCal3_S2.cpp index 55ea32e32..f7c8fb6b6 100644 --- a/gtsam/geometry/tests/testCal3_S2.cpp +++ b/gtsam/geometry/tests/testCal3_S2.cpp @@ -125,7 +125,6 @@ TEST(Cal3_S2, between) { EXPECT(assert_equal(Cal3_S2(0,1,2,3,4), k1.between(k2, H1, H2))); EXPECT(assert_equal(-I_5x5, H1)); EXPECT(assert_equal(I_5x5, H2)); - } /* ************************************************************************* */ From 42b053740232b5b64347fecdf89441c0a73f28f9 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 1 Dec 2020 17:23:10 -0500 Subject: [PATCH 114/261] Refactor all Cal3D based models --- gtsam/geometry/Cal3DS2.cpp | 8 +-- gtsam/geometry/Cal3DS2.h | 1 + gtsam/geometry/Cal3DS2_Base.cpp | 28 ++------ gtsam/geometry/Cal3DS2_Base.h | 119 +++++++++++--------------------- gtsam/geometry/Cal3Unified.cpp | 15 ++-- 5 files changed, 54 insertions(+), 117 deletions(-) diff --git a/gtsam/geometry/Cal3DS2.cpp b/gtsam/geometry/Cal3DS2.cpp index 070d16c6c..b4595a4dc 100644 --- a/gtsam/geometry/Cal3DS2.cpp +++ b/gtsam/geometry/Cal3DS2.cpp @@ -13,6 +13,7 @@ * @file Cal3DS2.cpp * @date Feb 28, 2010 * @author ydjian + * @author Varun Agrawal */ #include @@ -30,11 +31,8 @@ void Cal3DS2::print(const std::string& s_) const { /* ************************************************************************* */ bool Cal3DS2::equals(const Cal3DS2& K, double tol) const { - if (std::abs(fx_ - K.fx_) > tol || std::abs(fy_ - K.fy_) > tol || std::abs(s_ - K.s_) > tol || - std::abs(u0_ - K.u0_) > tol || std::abs(v0_ - K.v0_) > tol || std::abs(k1_ - K.k1_) > tol || - std::abs(k2_ - K.k2_) > tol || std::abs(p1_ - K.p1_) > tol || std::abs(p2_ - K.p2_) > tol) - return false; - return true; + const Cal3DS2_Base* base = dynamic_cast(&K); + return Cal3DS2_Base::equals(*base, tol); } /* ************************************************************************* */ diff --git a/gtsam/geometry/Cal3DS2.h b/gtsam/geometry/Cal3DS2.h index e66c3d124..fe08fc5fb 100644 --- a/gtsam/geometry/Cal3DS2.h +++ b/gtsam/geometry/Cal3DS2.h @@ -14,6 +14,7 @@ * @brief Calibration of a camera with radial distortion, calculations in base class Cal3DS2_Base * @date Feb 28, 2010 * @author ydjian + * @autho Varun Agrawal */ #pragma once diff --git a/gtsam/geometry/Cal3DS2_Base.cpp b/gtsam/geometry/Cal3DS2_Base.cpp index d175259f2..016c9dfa2 100644 --- a/gtsam/geometry/Cal3DS2_Base.cpp +++ b/gtsam/geometry/Cal3DS2_Base.cpp @@ -24,25 +24,6 @@ namespace gtsam { -/* ************************************************************************* */ -Cal3DS2_Base::Cal3DS2_Base(const Vector& v) - : fx_(v(0)), - fy_(v(1)), - s_(v(2)), - u0_(v(3)), - v0_(v(4)), - k1_(v(5)), - k2_(v(6)), - p1_(v(7)), - p2_(v(8)) {} - -/* ************************************************************************* */ -Matrix3 Cal3DS2_Base::K() const { - Matrix3 K; - K << fx_, s_, u0_, 0.0, fy_, v0_, 0.0, 0.0, 1.0; - return K; -} - /* ************************************************************************* */ Vector9 Cal3DS2_Base::vector() const { Vector9 v; @@ -58,11 +39,10 @@ void Cal3DS2_Base::print(const std::string& s_) const { /* ************************************************************************* */ bool Cal3DS2_Base::equals(const Cal3DS2_Base& K, double tol) const { - if (std::abs(fx_ - K.fx_) > tol || std::abs(fy_ - K.fy_) > tol || std::abs(s_ - K.s_) > tol || - std::abs(u0_ - K.u0_) > tol || std::abs(v0_ - K.v0_) > tol || std::abs(k1_ - K.k1_) > tol || - std::abs(k2_ - K.k2_) > tol || std::abs(p1_ - K.p1_) > tol || std::abs(p2_ - K.p2_) > tol) - return false; - return true; + const Cal3* base = dynamic_cast(&K); + return Cal3::equals(*base, tol) && std::fabs(k1_ - K.k1_) < tol && + std::fabs(k2_ - K.k2_) < tol && std::fabs(p1_ - K.p1_) < tol && + std::fabs(p2_ - K.p2_) < tol; } /* ************************************************************************* */ diff --git a/gtsam/geometry/Cal3DS2_Base.h b/gtsam/geometry/Cal3DS2_Base.h index dbd6478e1..536fb1161 100644 --- a/gtsam/geometry/Cal3DS2_Base.h +++ b/gtsam/geometry/Cal3DS2_Base.h @@ -34,50 +34,34 @@ namespace gtsam { * but using only k1,k2,p1, and p2 coefficients. * K = [ fx s u0 ; 0 fy v0 ; 0 0 1 ] * rr = Pn.x^2 + Pn.y^2 - * \hat{Pn} = (1 + k1*rr + k2*rr^2 ) Pn + [ 2*p1 Pn.x Pn.y + p2 (rr + 2 Pn.x^2) ; + * \hat{Pn} = (1 + k1*rr + k2*rr^2 ) Pn + [ 2*p1 Pn.x Pn.y + p2 (rr + 2 Pn.x^2) + * ; * p1 (rr + 2 Pn.y^2) + 2*p2 Pn.x Pn.y ] * pi = K*Pn */ -class GTSAM_EXPORT Cal3DS2_Base { - -protected: - double fx_, fy_, s_, u0_, v0_; // focal length, skew and principal point - double k1_, k2_; // radial 2nd-order and 4th-order - double p1_, p2_; // tangential distortion - double tol_ = 1e-5; // tolerance value when calibrating - -public: +class GTSAM_EXPORT Cal3DS2_Base : public Cal3 { + protected: + double k1_, k2_; // radial 2nd-order and 4th-order + double p1_, p2_; // tangential distortion + double tol_ = 1e-5; // tolerance value when calibrating + public: enum { dimension = 9 }; /// @name Standard Constructors /// @{ - /// Default Constructor with only unit focal length - Cal3DS2_Base() - : fx_(1), - fy_(1), - s_(0), - u0_(0), - v0_(0), - k1_(0), - k2_(0), - p1_(0), - p2_(0), - tol_(1e-5) {} + /// Default Constructor with only unit focal length + Cal3DS2_Base() : Cal3(), k1_(0), k2_(0), p1_(0), p2_(0), tol_(1e-5) {} - Cal3DS2_Base(double fx, double fy, double s, double u0, double v0, double k1, - double k2, double p1 = 0.0, double p2 = 0.0, double tol = 1e-5) - : fx_(fx), - fy_(fy), - s_(s), - u0_(u0), - v0_(v0), - k1_(k1), - k2_(k2), - p1_(p1), - p2_(p2), - tol_(tol) {} + Cal3DS2_Base(double fx, double fy, double s, double u0, double v0, double k1, + double k2, double p1 = 0.0, double p2 = 0.0, double tol = 1e-5) + : Cal3(fx, fy, s, u0, v0), + k1_(k1), + k2_(k2), + p1_(p1), + p2_(p2), + tol_(tol) {} virtual ~Cal3DS2_Base() {} @@ -85,14 +69,19 @@ public: /// @name Advanced Constructors /// @{ - Cal3DS2_Base(const Vector &v) ; + Cal3DS2_Base(const Vector& v) + : Cal3(v(0), v(1), v(2), v(3), v(4)), + k1_(v(5)), + k2_(v(6)), + p1_(v(7)), + p2_(v(8)) {} /// @} /// @name Testable /// @{ /// print with optional string - virtual void print(const std::string& s = "") const; + void print(const std::string& s = "") const override; /// assert equality up to a tolerance bool equals(const Cal3DS2_Base& K, double tol = 1e-8) const; @@ -101,35 +90,17 @@ public: /// @name Standard Interface /// @{ - /// focal length x - inline double fx() const { return fx_;} - - /// focal length x - inline double fy() const { return fy_;} - - /// skew - inline double skew() const { return s_;} - - /// image center in x - inline double px() const { return u0_;} - - /// image center in y - inline double py() const { return v0_;} - /// First distortion coefficient - inline double k1() const { return k1_;} + inline double k1() const { return k1_; } /// Second distortion coefficient - inline double k2() const { return k2_;} + inline double k2() const { return k2_; } /// First tangential distortion coefficient - inline double p1() const { return p1_;} + inline double p1() const { return p1_; } /// Second tangential distortion coefficient - inline double p2() const { return p2_;} - - /// return calibration matrix -- not really applicable - Matrix3 K() const; + inline double p2() const { return p2_; } /// return distortion parameter vector Vector4 k() const { return Vector4(k1_, k2_, p1_, p2_); } @@ -152,10 +123,10 @@ public: OptionalJacobian<2, 2> Dp = boost::none) const; /// Derivative of uncalibrate wrpt intrinsic coordinates - Matrix2 D2d_intrinsic(const Point2& p) const ; + Matrix2 D2d_intrinsic(const Point2& p) const; /// Derivative of uncalibrate wrpt the calibration parameters - Matrix29 D2d_calibration(const Point2& p) const ; + Matrix29 D2d_calibration(const Point2& p) const; /// @} /// @name Clone @@ -168,31 +139,23 @@ public: /// @} -private: - + private: /// @name Advanced Interface /// @{ /** Serialization function */ friend class boost::serialization::access; - template - void serialize(Archive & ar, const unsigned int /*version*/) - { - ar & BOOST_SERIALIZATION_NVP(fx_); - ar & BOOST_SERIALIZATION_NVP(fy_); - ar & BOOST_SERIALIZATION_NVP(s_); - ar & BOOST_SERIALIZATION_NVP(u0_); - ar & BOOST_SERIALIZATION_NVP(v0_); - ar & BOOST_SERIALIZATION_NVP(k1_); - ar & BOOST_SERIALIZATION_NVP(k2_); - ar & BOOST_SERIALIZATION_NVP(p1_); - ar & BOOST_SERIALIZATION_NVP(p2_); - ar & BOOST_SERIALIZATION_NVP(tol_); + template + void serialize(Archive& ar, const unsigned int /*version*/) { + ar& boost::serialization::make_nvp( + "Cal3DS2_Base", boost::serialization::base_object(*this)); + ar& BOOST_SERIALIZATION_NVP(k1_); + ar& BOOST_SERIALIZATION_NVP(k2_); + ar& BOOST_SERIALIZATION_NVP(p1_); + ar& BOOST_SERIALIZATION_NVP(p2_); + ar& BOOST_SERIALIZATION_NVP(tol_); } /// @} - }; - } - diff --git a/gtsam/geometry/Cal3Unified.cpp b/gtsam/geometry/Cal3Unified.cpp index f4ce0ed75..dc963a46e 100644 --- a/gtsam/geometry/Cal3Unified.cpp +++ b/gtsam/geometry/Cal3Unified.cpp @@ -26,8 +26,8 @@ namespace gtsam { /* ************************************************************************* */ -Cal3Unified::Cal3Unified(const Vector &v): - Base(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]), xi_(v[9]) {} +Cal3Unified::Cal3Unified(const Vector& v) + : Base(v(0), v(1), v(2), v(3), v(4), v(5), v(6), v(7), v(8)), xi_(v(9)) {} /* ************************************************************************* */ Vector10 Cal3Unified::vector() const { @@ -44,12 +44,8 @@ void Cal3Unified::print(const std::string& s) const { /* ************************************************************************* */ bool Cal3Unified::equals(const Cal3Unified& K, double tol) const { - if (std::abs(fx_ - K.fx_) > tol || std::abs(fy_ - K.fy_) > tol || std::abs(s_ - K.s_) > tol || - std::abs(u0_ - K.u0_) > tol || std::abs(v0_ - K.v0_) > tol || std::abs(k1_ - K.k1_) > tol || - std::abs(k2_ - K.k2_) > tol || std::abs(p1_ - K.p1_) > tol || std::abs(p2_ - K.p2_) > tol || - std::abs(xi_ - K.xi_) > tol) - return false; - return true; + const Cal3DS2_Base* base = dynamic_cast(&K); + return Cal3DS2_Base::equals(*base, tol) && std::fabs(xi_ - K.xi_) < tol; } /* ************************************************************************* */ @@ -144,7 +140,6 @@ Vector10 Cal3Unified::localCoordinates(const Cal3Unified& T2) const { return T2.vector() - vector(); } -} /* ************************************************************************* */ - +} // \ namespace gtsam From 17e9b73fb620b70a854c6747004da3f9aa9d4013 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 1 Dec 2020 17:23:42 -0500 Subject: [PATCH 115/261] Refactor Bundler and Fisheye models --- gtsam/geometry/Cal3Bundler.cpp | 30 ++---------- gtsam/geometry/Cal3Bundler.h | 66 ++++++++++++++------------- gtsam/geometry/Cal3Fisheye.cpp | 42 +++-------------- gtsam/geometry/Cal3Fisheye.h | 83 ++++++++++++++-------------------- 4 files changed, 79 insertions(+), 142 deletions(-) diff --git a/gtsam/geometry/Cal3Bundler.cpp b/gtsam/geometry/Cal3Bundler.cpp index a73bfec52..8c524e1cc 100644 --- a/gtsam/geometry/Cal3Bundler.cpp +++ b/gtsam/geometry/Cal3Bundler.cpp @@ -23,16 +23,6 @@ namespace gtsam { -/* ************************************************************************* */ -Cal3Bundler::Cal3Bundler() : - f_(1), k1_(0), k2_(0), u0_(0), v0_(0), tol_(1e-5) { -} - -/* ************************************************************************* */ -Cal3Bundler::Cal3Bundler(double f, double k1, double k2, double u0, double v0, - double tol) - : f_(f), k1_(k1), k2_(k2), u0_(u0), v0_(v0), tol_(tol) {} - /* ************************************************************************* */ Matrix3 Cal3Bundler::K() const { Matrix3 K; @@ -59,11 +49,9 @@ void Cal3Bundler::print(const std::string& s) const { /* ************************************************************************* */ bool Cal3Bundler::equals(const Cal3Bundler& K, double tol) const { - if (std::abs(f_ - K.f_) > tol || std::abs(k1_ - K.k1_) > tol - || std::abs(k2_ - K.k2_) > tol || std::abs(u0_ - K.u0_) > tol - || std::abs(v0_ - K.v0_) > tol) - return false; - return true; + return (std::fabs(f_ - K.f_) < tol && std::fabs(k1_ - K.k1_) < tol && + std::fabs(k2_ - K.k2_) < tol && std::fabs(u0_ - K.u0_) < tol && + std::fabs(v0_ - K.v0_) < tol); } /* ************************************************************************* */ @@ -150,14 +138,4 @@ Matrix25 Cal3Bundler::D2d_intrinsic_calibration(const Point2& p) const { return H; } -/* ************************************************************************* */ -Cal3Bundler Cal3Bundler::retract(const Vector& d) const { - return Cal3Bundler(f_ + d(0), k1_ + d(1), k2_ + d(2), u0_, v0_); -} - -/* ************************************************************************* */ -Vector3 Cal3Bundler::localCoordinates(const Cal3Bundler& T2) const { - return T2.vector() - vector(); -} - -} +} // \ namespace gtsam diff --git a/gtsam/geometry/Cal3Bundler.h b/gtsam/geometry/Cal3Bundler.h index 8c836b504..dc99f5259 100644 --- a/gtsam/geometry/Cal3Bundler.h +++ b/gtsam/geometry/Cal3Bundler.h @@ -28,15 +28,17 @@ namespace gtsam { * @addtogroup geometry * \nosubgrouping */ -class GTSAM_EXPORT Cal3Bundler { +class GTSAM_EXPORT Cal3Bundler : public Cal3 { -private: + private: double f_; ///< focal length double k1_, k2_; ///< radial distortion - double u0_, v0_; ///< image center, not a parameter to be optimized but a constant double tol_; ///< tolerance value when calibrating -public: + // NOTE: image center parameters (u0, v0) are not optimized + // but are constants. + + public: enum { dimension = 3 }; @@ -44,7 +46,7 @@ public: /// @{ /// Default constructor - Cal3Bundler(); + Cal3Bundler() : Cal3(), f_(1), k1_(0), k2_(0), tol_(1e-5) {} /** * Constructor @@ -56,7 +58,8 @@ public: * @param tol optional calibration tolerance value */ Cal3Bundler(double f, double k1, double k2, double u0 = 0, double v0 = 0, - double tol = 1e-5); + double tol = 1e-5) + : Cal3(f, f, 0, u0, v0), f_(f), k1_(k1), k2_(k2), tol_(tol) {} virtual ~Cal3Bundler() {} @@ -65,7 +68,7 @@ public: /// @{ /// print with optional string - void print(const std::string& s = "") const; + void print(const std::string& s = "") const override; /// assert equality up to a tolerance bool equals(const Cal3Bundler& K, double tol = 10e-9) const; @@ -74,11 +77,6 @@ public: /// @name Standard Interface /// @{ - Matrix3 K() const; ///< Standard 3*3 calibration matrix - Vector4 k() const; ///< Radial distortion parameters (4 of them, 2 0) - - Vector3 vector() const; - /// focal length x inline double fx() const { return f_; @@ -109,6 +107,11 @@ public: return v0_; } + Matrix3 K() const; ///< Standard 3*3 calibration matrix + Vector4 k() const; ///< Radial distortion parameters (4 of them, 2 0) + + Vector3 vector() const; + #ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V41 /// get parameter u0 inline double u0() const { @@ -121,12 +124,11 @@ public: } #endif - /** * @brief: convert intrinsic coordinates xy to image coordinates uv * Version of uncalibrate with derivatives * @param p point in intrinsic coordinates - * @param Dcal optional 2*3 Jacobian wrpt CalBundler parameters + * @param Dcal optional 2*3 Jacobian wrpt Cal3Bundler parameters * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates * @return point in image coordinates */ @@ -158,23 +160,23 @@ public: /// @name Manifold /// @{ + /// return DOF, dimensionality of tangent space + virtual size_t dim() const { return dimension; } + + /// return DOF, dimensionality of tangent space + static size_t Dim() { return dimension; } + /// Update calibration with tangent space delta - Cal3Bundler retract(const Vector& d) const; + inline Cal3Bundler retract(const Vector& d) const { + return Cal3Bundler(f_ + d(0), k1_ + d(1), k2_ + d(2), u0_, v0_); + } /// Calculate local coordinates to another calibration - Vector3 localCoordinates(const Cal3Bundler& T2) const; - - /// dimensionality - virtual size_t dim() const { - return 3; + Vector3 localCoordinates(const Cal3Bundler& T2) const { + return T2.vector() - vector(); } - /// dimensionality - static size_t Dim() { - return 3; - } - -private: + private: /// @} /// @name Advanced Interface @@ -184,12 +186,12 @@ private: friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int /*version*/) { - ar & BOOST_SERIALIZATION_NVP(f_); - ar & BOOST_SERIALIZATION_NVP(k1_); - ar & BOOST_SERIALIZATION_NVP(k2_); - ar & BOOST_SERIALIZATION_NVP(u0_); - ar & BOOST_SERIALIZATION_NVP(v0_); - ar & BOOST_SERIALIZATION_NVP(tol_); + ar& boost::serialization::make_nvp( + "Cal3Bundler", boost::serialization::base_object(*this)); + ar& BOOST_SERIALIZATION_NVP(f_); + ar& BOOST_SERIALIZATION_NVP(k1_); + ar& BOOST_SERIALIZATION_NVP(k2_); + ar& BOOST_SERIALIZATION_NVP(tol_); } /// @} diff --git a/gtsam/geometry/Cal3Fisheye.cpp b/gtsam/geometry/Cal3Fisheye.cpp index 1ed1826ad..55020f581 100644 --- a/gtsam/geometry/Cal3Fisheye.cpp +++ b/gtsam/geometry/Cal3Fisheye.cpp @@ -13,6 +13,7 @@ * @file Cal3Fisheye.cpp * @date Apr 8, 2020 * @author ghaggin + * @author Varun Agrawal */ #include @@ -23,18 +24,6 @@ namespace gtsam { -/* ************************************************************************* */ -Cal3Fisheye::Cal3Fisheye(const Vector9& v) - : fx_(v[0]), - fy_(v[1]), - s_(v[2]), - u0_(v[3]), - v0_(v[4]), - k1_(v[5]), - k2_(v[6]), - k3_(v[7]), - k4_(v[8]) {} - /* ************************************************************************* */ Vector9 Cal3Fisheye::vector() const { Vector9 v; @@ -42,13 +31,6 @@ Vector9 Cal3Fisheye::vector() const { return v; } -/* ************************************************************************* */ -Matrix3 Cal3Fisheye::K() const { - Matrix3 K; - K << fx_, s_, u0_, 0.0, fy_, v0_, 0.0, 0.0, 1.0; - return K; -} - /* ************************************************************************* */ double Cal3Fisheye::Scaling(double r) { static constexpr double threshold = 1e-8; @@ -165,24 +147,12 @@ void Cal3Fisheye::print(const std::string& s_) const { /* ************************************************************************* */ bool Cal3Fisheye::equals(const Cal3Fisheye& K, double tol) const { - if (std::abs(fx_ - K.fx_) > tol || std::abs(fy_ - K.fy_) > tol || - std::abs(s_ - K.s_) > tol || std::abs(u0_ - K.u0_) > tol || - std::abs(v0_ - K.v0_) > tol || std::abs(k1_ - K.k1_) > tol || - std::abs(k2_ - K.k2_) > tol || std::abs(k3_ - K.k3_) > tol || - std::abs(k4_ - K.k4_) > tol) - return false; - return true; + const Cal3* base = dynamic_cast(&K); + return Cal3::equals(*base, tol) && std::fabs(k1_ - K.k1_) < tol && + std::fabs(k2_ - K.k2_) < tol && std::fabs(k3_ - K.k3_) < tol && + std::fabs(k4_ - K.k4_) < tol; } /* ************************************************************************* */ -Cal3Fisheye Cal3Fisheye::retract(const Vector& d) const { - return Cal3Fisheye(vector() + d); -} -/* ************************************************************************* */ -Vector Cal3Fisheye::localCoordinates(const Cal3Fisheye& T2) const { - return T2.vector() - vector(); -} - -} // namespace gtsam -/* ************************************************************************* */ +} // \ namespace gtsam diff --git a/gtsam/geometry/Cal3Fisheye.h b/gtsam/geometry/Cal3Fisheye.h index 77e122f21..0d8921bd9 100644 --- a/gtsam/geometry/Cal3Fisheye.h +++ b/gtsam/geometry/Cal3Fisheye.h @@ -46,11 +46,10 @@ namespace gtsam { * K = [fx s u0; 0 fy v0 ;0 0 1] * [u; v; 1] = K*[x_d; y_d; 1] */ -class GTSAM_EXPORT Cal3Fisheye { +class GTSAM_EXPORT Cal3Fisheye : public Cal3 { private: - double fx_, fy_, s_, u0_, v0_; // focal length, skew and principal point - double k1_, k2_, k3_, k4_; // fisheye distortion coefficients - double tol_ = 1e-5; // tolerance value when calibrating + double k1_, k2_, k3_, k4_; ///< fisheye distortion coefficients + double tol_ = 1e-5; ///< tolerance value when calibrating public: enum { dimension = 9 }; @@ -61,17 +60,12 @@ class GTSAM_EXPORT Cal3Fisheye { /// @{ /// Default Constructor with only unit focal length - Cal3Fisheye() - : fx_(1), fy_(1), s_(0), u0_(0), v0_(0), k1_(0), k2_(0), k3_(0), k4_(0), tol_(1e-5) {} + Cal3Fisheye() : Cal3(), k1_(0), k2_(0), k3_(0), k4_(0), tol_(1e-5) {} Cal3Fisheye(const double fx, const double fy, const double s, const double u0, const double v0, const double k1, const double k2, const double k3, const double k4, double tol = 1e-5) - : fx_(fx), - fy_(fy), - s_(s), - u0_(u0), - v0_(v0), + : Cal3(fx, fy, s, u0, v0), k1_(k1), k2_(k2), k3_(k3), @@ -84,27 +78,17 @@ class GTSAM_EXPORT Cal3Fisheye { /// @name Advanced Constructors /// @{ - explicit Cal3Fisheye(const Vector9& v); + explicit Cal3Fisheye(const Vector9& v) + : Cal3(v(0), v(1), v(2), v(3), v(4)), + k1_(v(5)), + k2_(v(6)), + k3_(v(7)), + k4_(v(8)) {} /// @} /// @name Standard Interface /// @{ - /// focal length x - inline double fx() const { return fx_; } - - /// focal length x - inline double fy() const { return fy_; } - - /// skew - inline double skew() const { return s_; } - - /// image center in x - inline double px() const { return u0_; } - - /// image center in y - inline double py() const { return v0_; } - /// First distortion coefficient inline double k1() const { return k1_; } @@ -117,9 +101,6 @@ class GTSAM_EXPORT Cal3Fisheye { /// Second tangential distortion coefficient inline double k4() const { return k4_; } - /// return calibration matrix - Matrix3 K() const; - /// return distortion parameter vector Vector4 k() const { return Vector4(k1_, k2_, k3_, k4_); } @@ -133,16 +114,21 @@ class GTSAM_EXPORT Cal3Fisheye { * @brief convert intrinsic coordinates [x_i; y_i] to (distorted) image * coordinates [u; v] * @param p point in intrinsic coordinates - * @param Dcal optional 2*9 Jacobian wrpt intrinsic parameters (fx, fy, ..., - * k4) + * @param Dcal optional 2*9 Jacobian wrpt intrinsic parameters * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates (xi, yi) * @return point in (distorted) image coordinates */ Point2 uncalibrate(const Point2& p, OptionalJacobian<2, 9> Dcal = boost::none, OptionalJacobian<2, 2> Dp = boost::none) const; - /// Convert (distorted) image coordinates [u;v] to intrinsic coordinates [x_i, - /// y_i] + /** + * Convert (distorted) image coordinates [u;v] to intrinsic coordinates [x_i, + * y_i] + * @param p point in image coordinates + * @param Dcal optional 2*9 Jacobian wrpt intrinsic parameters + * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates (xi, yi) + * @return point in intrinsic coordinates + */ Point2 calibrate(const Point2& p, OptionalJacobian<2, 9> Dcal = boost::none, OptionalJacobian<2, 2> Dp = boost::none) const; @@ -151,7 +137,7 @@ class GTSAM_EXPORT Cal3Fisheye { /// @{ /// print with optional string - virtual void print(const std::string& s = "") const; + virtual void print(const std::string& s = "") const override; /// assert equality up to a tolerance bool equals(const Cal3Fisheye& K, double tol = 10e-9) const; @@ -160,17 +146,21 @@ class GTSAM_EXPORT Cal3Fisheye { /// @name Manifold /// @{ + /// Return dimensions of calibration manifold object + virtual size_t dim() const { return dimension; } + + /// Return dimensions of calibration manifold object + static size_t Dim() { return dimension; } + /// Given delta vector, update calibration - Cal3Fisheye retract(const Vector& d) const; + inline Cal3Fisheye retract(const Vector& d) const { + return Cal3Fisheye(vector() + d); + } /// Given a different calibration, calculate update to obtain it - Vector localCoordinates(const Cal3Fisheye& T2) const; - - /// Return dimensions of calibration manifold object - virtual size_t dim() const { return 9; } - - /// Return dimensions of calibration manifold object - static size_t Dim() { return 9; } + Vector localCoordinates(const Cal3Fisheye& T2) const { + return T2.vector() - vector(); + } /// @} /// @name Clone @@ -191,11 +181,8 @@ class GTSAM_EXPORT Cal3Fisheye { friend class boost::serialization::access; template void serialize(Archive& ar, const unsigned int /*version*/) { - ar& BOOST_SERIALIZATION_NVP(fx_); - ar& BOOST_SERIALIZATION_NVP(fy_); - ar& BOOST_SERIALIZATION_NVP(s_); - ar& BOOST_SERIALIZATION_NVP(u0_); - ar& BOOST_SERIALIZATION_NVP(v0_); + ar& boost::serialization::make_nvp( + "Cal3Fisheye", boost::serialization::base_object(*this)); ar& BOOST_SERIALIZATION_NVP(k1_); ar& BOOST_SERIALIZATION_NVP(k2_); ar& BOOST_SERIALIZATION_NVP(k3_); From 8daa6a77295988802caea09db4b8ff9d2236a007 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 1 Dec 2020 17:24:04 -0500 Subject: [PATCH 116/261] Minor updates --- gtsam/geometry/Cal3.cpp | 8 ++++---- gtsam/geometry/Cal3.h | 4 ++-- gtsam/geometry/Cal3DS2.h | 2 +- gtsam/geometry/Cal3DS2_Base.h | 6 +++--- gtsam/geometry/Cal3Unified.h | 2 +- gtsam/geometry/Cal3_S2Stereo.cpp | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/gtsam/geometry/Cal3.cpp b/gtsam/geometry/Cal3.cpp index 240d01e12..31e9bf834 100644 --- a/gtsam/geometry/Cal3.cpp +++ b/gtsam/geometry/Cal3.cpp @@ -62,11 +62,11 @@ void Cal3::print(const std::string& s) const { gtsam::print((Matrix)K(), s); } /* ************************************************************************* */ bool Cal3::equals(const Cal3& K, double tol) const { - return (std::abs(fx_ - K.fx_) < tol) && (std::abs(fy_ - K.fy_) < tol) && - (std::abs(s_ - K.s_) < tol) && (std::abs(u0_ - K.u0_) < tol) && - (std::abs(v0_ - K.v0_) < tol); + return (std::fabs(fx_ - K.fx_) < tol) && (std::fabs(fy_ - K.fy_) < tol) && + (std::fabs(s_ - K.s_) < tol) && (std::fabs(u0_ - K.u0_) < tol) && + (std::fabs(v0_ - K.v0_) < tol); } /* ************************************************************************* */ -} // namespace gtsam +} // \ namespace gtsam diff --git a/gtsam/geometry/Cal3.h b/gtsam/geometry/Cal3.h index 13cd4de69..7384fe958 100644 --- a/gtsam/geometry/Cal3.h +++ b/gtsam/geometry/Cal3.h @@ -68,7 +68,7 @@ void calibrateJacobians(const Cal& calibration, const Point2& pn, */ class GTSAM_EXPORT Cal3 { protected: - double fx_, fy_, s_, u0_, v0_; + double fx_, fy_, s_, u0_, v0_; ///< focal length, skew and principal point public: enum { dimension = 5 }; @@ -113,7 +113,7 @@ class GTSAM_EXPORT Cal3 { const Cal3& cal); /// print with optional string - virtual void print(const std::string& s = "Cal3") const; + virtual void print(const std::string& s = "") const; /// Check if equal up to specified tolerance bool equals(const Cal3& K, double tol = 10e-9) const; diff --git a/gtsam/geometry/Cal3DS2.h b/gtsam/geometry/Cal3DS2.h index fe08fc5fb..58ccae04f 100644 --- a/gtsam/geometry/Cal3DS2.h +++ b/gtsam/geometry/Cal3DS2.h @@ -32,7 +32,7 @@ namespace gtsam { */ class GTSAM_EXPORT Cal3DS2 : public Cal3DS2_Base { - typedef Cal3DS2_Base Base; + using Base = Cal3DS2_Base; public: diff --git a/gtsam/geometry/Cal3DS2_Base.h b/gtsam/geometry/Cal3DS2_Base.h index 536fb1161..0c6a4a3cd 100644 --- a/gtsam/geometry/Cal3DS2_Base.h +++ b/gtsam/geometry/Cal3DS2_Base.h @@ -41,9 +41,9 @@ namespace gtsam { */ class GTSAM_EXPORT Cal3DS2_Base : public Cal3 { protected: - double k1_, k2_; // radial 2nd-order and 4th-order - double p1_, p2_; // tangential distortion - double tol_ = 1e-5; // tolerance value when calibrating + double k1_, k2_; ///< radial 2nd-order and 4th-order + double p1_, p2_; ///< tangential distortion + double tol_ = 1e-5; ///< tolerance value when calibrating public: enum { dimension = 9 }; diff --git a/gtsam/geometry/Cal3Unified.h b/gtsam/geometry/Cal3Unified.h index 6fc37b0d1..7a0931ff5 100644 --- a/gtsam/geometry/Cal3Unified.h +++ b/gtsam/geometry/Cal3Unified.h @@ -47,7 +47,7 @@ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { private: - double xi_; // mirror parameter + double xi_; ///< mirror parameter public: diff --git a/gtsam/geometry/Cal3_S2Stereo.cpp b/gtsam/geometry/Cal3_S2Stereo.cpp index b4e70202e..43f0fb12f 100644 --- a/gtsam/geometry/Cal3_S2Stereo.cpp +++ b/gtsam/geometry/Cal3_S2Stereo.cpp @@ -32,7 +32,7 @@ void Cal3_S2Stereo::print(const std::string& s) const { /* ************************************************************************* */ bool Cal3_S2Stereo::equals(const Cal3_S2Stereo& other, double tol) const { const Cal3_S2* base = dynamic_cast(&other); - return Cal3_S2::equals(*base, tol) && (std::abs(b_ - other.baseline()) < tol); + return Cal3_S2::equals(*base, tol) && (std::fabs(b_ - other.baseline()) < tol); } /* ************************************************************************* */ From f9041846cedac352c4f913eac9c5559675c901c9 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 1 Dec 2020 17:37:06 -0500 Subject: [PATCH 117/261] Remove deprecated calibration method from wrapper --- gtsam/gtsam.i | 1 - 1 file changed, 1 deletion(-) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 2e1920641..e405e533c 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -852,7 +852,6 @@ class Cal3_S2 { gtsam::Point2 principalPoint() const; Vector vector() const; Matrix K() const; - Matrix matrix() const; Matrix matrix_inverse() const; // enabling serialization functionality From 9bc63fa5a943253363091349cc9d04209ccff601 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 1 Dec 2020 17:46:03 -0500 Subject: [PATCH 118/261] replace typedef with using --- gtsam/geometry/Cal3.h | 4 ++-- gtsam/geometry/Cal3Fisheye.h | 4 ++-- gtsam/geometry/Cal3Unified.h | 4 ++-- gtsam/geometry/Cal3_S2.h | 5 +++-- gtsam/geometry/Cal3_S2Stereo.h | 9 +++++---- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/gtsam/geometry/Cal3.h b/gtsam/geometry/Cal3.h index 7384fe958..5ce7be8ca 100644 --- a/gtsam/geometry/Cal3.h +++ b/gtsam/geometry/Cal3.h @@ -72,8 +72,8 @@ class GTSAM_EXPORT Cal3 { public: enum { dimension = 5 }; - typedef boost::shared_ptr - shared_ptr; ///< shared pointer to calibration object + ///< shared pointer to calibration object + using shared_ptr = boost::shared_ptr; /// @name Standard Constructors /// @{ diff --git a/gtsam/geometry/Cal3Fisheye.h b/gtsam/geometry/Cal3Fisheye.h index 0d8921bd9..3eaf9f46d 100644 --- a/gtsam/geometry/Cal3Fisheye.h +++ b/gtsam/geometry/Cal3Fisheye.h @@ -53,8 +53,8 @@ class GTSAM_EXPORT Cal3Fisheye : public Cal3 { public: enum { dimension = 9 }; - typedef boost::shared_ptr - shared_ptr; ///< shared pointer to fisheye calibration object + ///< shared pointer to fisheye calibration object + using shared_ptr = boost::shared_ptr; /// @name Standard Constructors /// @{ diff --git a/gtsam/geometry/Cal3Unified.h b/gtsam/geometry/Cal3Unified.h index 7a0931ff5..673d9e2c9 100644 --- a/gtsam/geometry/Cal3Unified.h +++ b/gtsam/geometry/Cal3Unified.h @@ -42,8 +42,8 @@ namespace gtsam { */ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { - typedef Cal3Unified This; - typedef Cal3DS2_Base Base; + using This = Cal3Unified; + using Base = Cal3DS2_Base; private: diff --git a/gtsam/geometry/Cal3_S2.h b/gtsam/geometry/Cal3_S2.h index aef27323e..0a6b0e164 100644 --- a/gtsam/geometry/Cal3_S2.h +++ b/gtsam/geometry/Cal3_S2.h @@ -34,8 +34,9 @@ namespace gtsam { class GTSAM_EXPORT Cal3_S2 : public Cal3 { public: enum { dimension = 5 }; - typedef boost::shared_ptr - shared_ptr; ///< shared pointer to calibration object + + ///< shared pointer to calibration object + using shared_ptr = boost::shared_ptr; /// @name Standard Constructors /// @{ diff --git a/gtsam/geometry/Cal3_S2Stereo.h b/gtsam/geometry/Cal3_S2Stereo.h index 258cd0434..585807543 100644 --- a/gtsam/geometry/Cal3_S2Stereo.h +++ b/gtsam/geometry/Cal3_S2Stereo.h @@ -28,14 +28,15 @@ namespace gtsam { * \nosubgrouping */ class GTSAM_EXPORT Cal3_S2Stereo : public Cal3_S2 { - private: + private: double b_; - public: + public: enum { dimension = 6 }; + ///< shared pointer to stereo calibration object - typedef boost::shared_ptr shared_ptr; + using shared_ptr = boost::shared_ptr; /// @name Standard Constructors /// @ @@ -111,7 +112,7 @@ namespace gtsam { /// @name Advanced Interface /// @{ - private: + private: /** Serialization function */ friend class boost::serialization::access; template From 8fd2d9842426e452207b39daab0c8901243889d5 Mon Sep 17 00:00:00 2001 From: Sushmita Date: Tue, 1 Dec 2020 19:31:44 -0500 Subject: [PATCH 119/261] templated functions where possible --- gtsam/geometry/triangulation.h | 7 +++-- gtsam/gtsam.i | 34 +++++++++--------------- python/CMakeLists.txt | 2 -- python/gtsam/preamble.h | 4 +-- python/gtsam/specializations.h | 4 +-- python/gtsam/tests/test_Triangulation.py | 2 +- 6 files changed, 22 insertions(+), 31 deletions(-) diff --git a/gtsam/geometry/triangulation.h b/gtsam/geometry/triangulation.h index 23ea7e50b..617d09da7 100644 --- a/gtsam/geometry/triangulation.h +++ b/gtsam/geometry/triangulation.h @@ -497,8 +497,11 @@ TriangulationResult triangulateSafe(const CameraSet& cameras, } // Vector of Cameras - used by the Python/MATLAB wrapper -typedef CameraSet> CameraSetCal3Bundler; -typedef CameraSet> CameraSetCal3_S2; +//typedef CameraSet> CameraSetCal3Bundler; +//typedef CameraSet> CameraSetCal3_S2; + +using CameraSetCal3Bundler = CameraSet>; +using CameraSetCal3_S2 = CameraSet>; } // \namespace gtsam diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index f6c2da853..a8b1cf4f4 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -1109,31 +1109,22 @@ typedef gtsam::PinholeCamera PinholeCameraCal3_S2; //typedef gtsam::PinholeCamera PinholeCameraCal3Unified; typedef gtsam::PinholeCamera PinholeCameraCal3Bundler; -class CameraSetCal3Bundler { - CameraSetCal3Bundler(); +template +class CameraSet { + CameraSet(); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // // common STL methods + // size_t size() const; + // bool empty() const; + // void clear(); - // structure specific methods - gtsam::PinholeCameraCal3Bundler at(size_t i) const; - void push_back(const gtsam::PinholeCameraCal3Bundler& cam); + // // structure specific methods + // T at(size_t i) const; + void push_back(const T& cam); }; -class CameraSetCal3_S2 { - CameraSetCal3_S2(); - - // common STL methods - size_t size() const; - bool empty() const; - void clear(); - - // structure specific methods - gtsam::PinholeCameraCal3_S2 at(size_t i) const; - void push_back(const gtsam::PinholeCameraCal3_S2& cam); -}; +typedef gtsam::CameraSet CameraSetCal3_S2; +typedef gtsam::CameraSet CameraSetCal3Bundler; #include class StereoCamera { @@ -1166,7 +1157,6 @@ class StereoCamera { #include -// Templates appear not yet supported for free functions gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, gtsam::Cal3_S2* sharedCal, const gtsam::Point2Vector& measurements, double rank_tol, bool optimize); diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index a318a483b..00b537340 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -38,8 +38,6 @@ set(ignore gtsam::Pose3Vector gtsam::KeyVector gtsam::BinaryMeasurementsUnit3 - gtsam::CameraSetCal3Bundler - gtsam::CameraSetCal3_S2 gtsam::KeyPairDoubleMap) pybind_wrap(gtsam_py # target diff --git a/python/gtsam/preamble.h b/python/gtsam/preamble.h index b56766c72..92ad14797 100644 --- a/python/gtsam/preamble.h +++ b/python/gtsam/preamble.h @@ -10,5 +10,5 @@ PYBIND11_MAKE_OPAQUE(std::vector); PYBIND11_MAKE_OPAQUE(std::vector > >); PYBIND11_MAKE_OPAQUE(std::vector > >); PYBIND11_MAKE_OPAQUE(std::vector); -PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); -PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); +//PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); +//PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); diff --git a/python/gtsam/specializations.h b/python/gtsam/specializations.h index 431697aac..8f97c2dae 100644 --- a/python/gtsam/specializations.h +++ b/python/gtsam/specializations.h @@ -13,5 +13,5 @@ py::bind_vector > >(m_, "Bina py::bind_map(m_, "IndexPairSetMap"); py::bind_vector(m_, "IndexPairVector"); py::bind_map(m_, "KeyPairDoubleMap"); -py::bind_vector > >(m_, "CameraSetCal3_S2"); -py::bind_vector > >(m_, "CameraSetCal3Bundler"); +// py::bind_vector > >(m_, "CameraSetCal3_S2"); +// py::bind_vector > >(m_, "CameraSetCal3Bundler"); diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index e57fbb6ab..a1adcd2c9 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -56,7 +56,7 @@ class TestVisualISAMExample(GtsamTestCase): rank_tol = 1e-9 triangulated_landmark = triangulatePoint3(poses,sharedCal, measurements, rank_tol, optimize) - self.gtsamAssertEquals(self.landmark, triangulated_landmark,1e-9) + self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) # 2. Add some noise and try again: result should be ~ (4.995, 0.499167, 1.19814) measurements = Point2Vector() From 77b6595998a9fc52589d9e60001ac9d7ba2eeac8 Mon Sep 17 00:00:00 2001 From: Sushmita Date: Tue, 1 Dec 2020 21:56:05 -0500 Subject: [PATCH 120/261] removed push_back method from cameraset wrapper --- gtsam/gtsam.i | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index b7a49b9ac..954d74f05 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -1079,7 +1079,7 @@ class CameraSet { // // structure specific methods // T at(size_t i) const; - void push_back(const T& cam); + // void push_back(const T& cam); }; typedef gtsam::CameraSet CameraSetCal3_S2; From 2e3943346936f31de9649d503d8d9ebca3c9bc7d Mon Sep 17 00:00:00 2001 From: Sushmita Date: Tue, 1 Dec 2020 23:21:21 -0500 Subject: [PATCH 121/261] added utility functions and code cleanup --- gtsam/geometry/triangulation.h | 3 --- gtsam/gtsam.i | 16 ++++++++-------- python/gtsam/preamble.h | 2 -- python/gtsam/specializations.h | 2 -- python/gtsam/tests/test_Triangulation.py | 8 ++++---- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/gtsam/geometry/triangulation.h b/gtsam/geometry/triangulation.h index 617d09da7..1df9efd22 100644 --- a/gtsam/geometry/triangulation.h +++ b/gtsam/geometry/triangulation.h @@ -497,9 +497,6 @@ TriangulationResult triangulateSafe(const CameraSet& cameras, } // Vector of Cameras - used by the Python/MATLAB wrapper -//typedef CameraSet> CameraSetCal3Bundler; -//typedef CameraSet> CameraSetCal3_S2; - using CameraSetCal3Bundler = CameraSet>; using CameraSetCal3_S2 = CameraSet>; diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 954d74f05..8596106e4 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -1068,18 +1068,18 @@ typedef gtsam::PinholeCamera PinholeCameraCal3DS2; typedef gtsam::PinholeCamera PinholeCameraCal3Unified; typedef gtsam::PinholeCamera PinholeCameraCal3Bundler; -template +template class CameraSet { CameraSet(); - // // common STL methods - // size_t size() const; - // bool empty() const; - // void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // // structure specific methods - // T at(size_t i) const; - // void push_back(const T& cam); + // structure specific methods + T at(size_t i) const; + void push_back(const T& cam); }; typedef gtsam::CameraSet CameraSetCal3_S2; diff --git a/python/gtsam/preamble.h b/python/gtsam/preamble.h index 92ad14797..6166f615e 100644 --- a/python/gtsam/preamble.h +++ b/python/gtsam/preamble.h @@ -10,5 +10,3 @@ PYBIND11_MAKE_OPAQUE(std::vector); PYBIND11_MAKE_OPAQUE(std::vector > >); PYBIND11_MAKE_OPAQUE(std::vector > >); PYBIND11_MAKE_OPAQUE(std::vector); -//PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); -//PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); diff --git a/python/gtsam/specializations.h b/python/gtsam/specializations.h index 8f97c2dae..cacad874c 100644 --- a/python/gtsam/specializations.h +++ b/python/gtsam/specializations.h @@ -13,5 +13,3 @@ py::bind_vector > >(m_, "Bina py::bind_map(m_, "IndexPairSetMap"); py::bind_vector(m_, "IndexPairVector"); py::bind_map(m_, "KeyPairDoubleMap"); -// py::bind_vector > >(m_, "CameraSetCal3_S2"); -// py::bind_vector > >(m_, "CameraSetCal3Bundler"); diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index a1adcd2c9..2a9851d04 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -75,8 +75,8 @@ class TestVisualISAMExample(GtsamTestCase): camera2 = PinholeCameraCal3_S2(self.pose2, K2) cameras = CameraSetCal3_S2() - cameras.append(camera1) - cameras.append(camera2) + cameras.push_back(camera1) + cameras.push_back(camera2) # Project two landmarks into two cameras and triangulate z1 = camera1.project(self.landmark) @@ -101,8 +101,8 @@ class TestVisualISAMExample(GtsamTestCase): camera2 = PinholeCameraCal3Bundler(self.pose2, K2) cameras = CameraSetCal3Bundler() - cameras.append(camera1) - cameras.append(camera2) + cameras.push_back(camera1) + cameras.push_back(camera2) # Project two landmarks into two cameras and triangulate z1 = camera1.project(self.landmark) From 04597feaa4268325295679a85953c03b37b04063 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 2 Dec 2020 05:45:20 -0500 Subject: [PATCH 122/261] modernized default constructors --- gtsam/geometry/Cal3.h | 10 ++++++---- gtsam/geometry/Cal3Bundler.h | 10 +++++----- gtsam/geometry/Cal3DS2.h | 10 +++++----- gtsam/geometry/Cal3DS2_Base.h | 10 +++++----- gtsam/geometry/Cal3Fisheye.h | 7 ++++--- gtsam/geometry/Cal3Unified.cpp | 6 +----- gtsam/geometry/Cal3Unified.h | 26 +++++++++++++------------- gtsam/geometry/Cal3_S2.h | 4 ++-- gtsam/geometry/Cal3_S2Stereo.h | 7 ++++--- 9 files changed, 45 insertions(+), 45 deletions(-) diff --git a/gtsam/geometry/Cal3.h b/gtsam/geometry/Cal3.h index 5ce7be8ca..6d3973080 100644 --- a/gtsam/geometry/Cal3.h +++ b/gtsam/geometry/Cal3.h @@ -68,7 +68,9 @@ void calibrateJacobians(const Cal& calibration, const Point2& pn, */ class GTSAM_EXPORT Cal3 { protected: - double fx_, fy_, s_, u0_, v0_; ///< focal length, skew and principal point + double fx_ = 1.0f, fy_ = 1.0f; ///< focal length + double s_ = 0.0f; ///< skew + double u0_ = 0.0f, v0_ = 0.0f; ///< principal point public: enum { dimension = 5 }; @@ -79,14 +81,14 @@ class GTSAM_EXPORT Cal3 { /// @{ /// Create a default calibration that leaves coordinates unchanged - Cal3() : fx_(1), fy_(1), s_(0), u0_(0), v0_(0) {} + Cal3() = default; /// constructor from doubles Cal3(double fx, double fy, double s, double u0, double v0) : fx_(fx), fy_(fy), s_(s), u0_(u0), v0_(v0) {} /// constructor from vector - Cal3(const Vector& d) + Cal3(const Vector5& d) : fx_(d(0)), fy_(d(1)), s_(d(2)), u0_(d(3)), v0_(d(4)) {} /** @@ -162,7 +164,7 @@ class GTSAM_EXPORT Cal3 { Matrix3 matrix() const { return K(); } #endif - /// return inverted calibration matrix inv(K) + /// Return inverted calibration matrix inv(K) Matrix3 matrix_inverse() const { const double fxy = fx_ * fy_, sv0 = s_ * v0_, fyu0 = fy_ * u0_; Matrix3 K_inverse; diff --git a/gtsam/geometry/Cal3Bundler.h b/gtsam/geometry/Cal3Bundler.h index dc99f5259..d128c329b 100644 --- a/gtsam/geometry/Cal3Bundler.h +++ b/gtsam/geometry/Cal3Bundler.h @@ -31,12 +31,12 @@ namespace gtsam { class GTSAM_EXPORT Cal3Bundler : public Cal3 { private: - double f_; ///< focal length - double k1_, k2_; ///< radial distortion - double tol_; ///< tolerance value when calibrating + double f_ = 1.0f; ///< focal length + double k1_ = 0.0f, k2_ = 0.0f; ///< radial distortion + double tol_ = 1e-5; ///< tolerance value when calibrating // NOTE: image center parameters (u0, v0) are not optimized - // but are constants. + // but are treated as constants. public: @@ -46,7 +46,7 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { /// @{ /// Default constructor - Cal3Bundler() : Cal3(), f_(1), k1_(0), k2_(0), tol_(1e-5) {} + Cal3Bundler() = default; /** * Constructor diff --git a/gtsam/geometry/Cal3DS2.h b/gtsam/geometry/Cal3DS2.h index 58ccae04f..03a4d8d46 100644 --- a/gtsam/geometry/Cal3DS2.h +++ b/gtsam/geometry/Cal3DS2.h @@ -42,11 +42,11 @@ public: /// @{ /// Default Constructor with only unit focal length - Cal3DS2() : Base() {} + Cal3DS2() = default; - Cal3DS2(double fx, double fy, double s, double u0, double v0, - double k1, double k2, double p1 = 0.0, double p2 = 0.0, double tol = 1e-5) : - Base(fx, fy, s, u0, v0, k1, k2, p1, p2, tol) {} + Cal3DS2(double fx, double fy, double s, double u0, double v0, double k1, + double k2, double p1 = 0.0, double p2 = 0.0, double tol = 1e-5) + : Base(fx, fy, s, u0, v0, k1, k2, p1, p2, tol) {} virtual ~Cal3DS2() {} @@ -54,7 +54,7 @@ public: /// @name Advanced Constructors /// @{ - Cal3DS2(const Vector &v) : Base(v) {} + Cal3DS2(const Vector9 &v) : Base(v) {} /// @} /// @name Testable diff --git a/gtsam/geometry/Cal3DS2_Base.h b/gtsam/geometry/Cal3DS2_Base.h index 0c6a4a3cd..e0de6af61 100644 --- a/gtsam/geometry/Cal3DS2_Base.h +++ b/gtsam/geometry/Cal3DS2_Base.h @@ -41,9 +41,9 @@ namespace gtsam { */ class GTSAM_EXPORT Cal3DS2_Base : public Cal3 { protected: - double k1_, k2_; ///< radial 2nd-order and 4th-order - double p1_, p2_; ///< tangential distortion - double tol_ = 1e-5; ///< tolerance value when calibrating + double k1_ = 0.0f, k2_ = 0.0f; ///< radial 2nd-order and 4th-order + double p1_ = 0.0f, p2_ = 0.0f; ///< tangential distortion + double tol_ = 1e-5; ///< tolerance value when calibrating public: enum { dimension = 9 }; @@ -52,7 +52,7 @@ class GTSAM_EXPORT Cal3DS2_Base : public Cal3 { /// @{ /// Default Constructor with only unit focal length - Cal3DS2_Base() : Cal3(), k1_(0), k2_(0), p1_(0), p2_(0), tol_(1e-5) {} + Cal3DS2_Base() = default; Cal3DS2_Base(double fx, double fy, double s, double u0, double v0, double k1, double k2, double p1 = 0.0, double p2 = 0.0, double tol = 1e-5) @@ -69,7 +69,7 @@ class GTSAM_EXPORT Cal3DS2_Base : public Cal3 { /// @name Advanced Constructors /// @{ - Cal3DS2_Base(const Vector& v) + Cal3DS2_Base(const Vector9& v) : Cal3(v(0), v(1), v(2), v(3), v(4)), k1_(v(5)), k2_(v(6)), diff --git a/gtsam/geometry/Cal3Fisheye.h b/gtsam/geometry/Cal3Fisheye.h index 3eaf9f46d..f41a9b0d7 100644 --- a/gtsam/geometry/Cal3Fisheye.h +++ b/gtsam/geometry/Cal3Fisheye.h @@ -48,8 +48,9 @@ namespace gtsam { */ class GTSAM_EXPORT Cal3Fisheye : public Cal3 { private: - double k1_, k2_, k3_, k4_; ///< fisheye distortion coefficients - double tol_ = 1e-5; ///< tolerance value when calibrating + double k1_ = 0.0f, k2_ = 0.0f; ///< fisheye distortion coefficients + double k3_ = 0.0f, k4_ = 0.0f; ///< fisheye distortion coefficients + double tol_ = 1e-5; ///< tolerance value when calibrating public: enum { dimension = 9 }; @@ -60,7 +61,7 @@ class GTSAM_EXPORT Cal3Fisheye : public Cal3 { /// @{ /// Default Constructor with only unit focal length - Cal3Fisheye() : Cal3(), k1_(0), k2_(0), k3_(0), k4_(0), tol_(1e-5) {} + Cal3Fisheye() = default; Cal3Fisheye(const double fx, const double fy, const double s, const double u0, const double v0, const double k1, const double k2, diff --git a/gtsam/geometry/Cal3Unified.cpp b/gtsam/geometry/Cal3Unified.cpp index dc963a46e..d260dd725 100644 --- a/gtsam/geometry/Cal3Unified.cpp +++ b/gtsam/geometry/Cal3Unified.cpp @@ -25,10 +25,6 @@ namespace gtsam { -/* ************************************************************************* */ -Cal3Unified::Cal3Unified(const Vector& v) - : Base(v(0), v(1), v(2), v(3), v(4), v(5), v(6), v(7), v(8)), xi_(v(9)) {} - /* ************************************************************************* */ Vector10 Cal3Unified::vector() const { Vector10 v; @@ -136,7 +132,7 @@ Cal3Unified Cal3Unified::retract(const Vector& d) const { } /* ************************************************************************* */ -Vector10 Cal3Unified::localCoordinates(const Cal3Unified& T2) const { +Vector Cal3Unified::localCoordinates(const Cal3Unified& T2) const { return T2.vector() - vector(); } diff --git a/gtsam/geometry/Cal3Unified.h b/gtsam/geometry/Cal3Unified.h index 673d9e2c9..e1368db4c 100644 --- a/gtsam/geometry/Cal3Unified.h +++ b/gtsam/geometry/Cal3Unified.h @@ -45,11 +45,10 @@ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { using This = Cal3Unified; using Base = Cal3DS2_Base; -private: + private: + double xi_ = 0.0f; ///< mirror parameter - double xi_; ///< mirror parameter - -public: + public: enum { dimension = 10 }; @@ -57,11 +56,11 @@ public: /// @{ /// Default Constructor with only unit focal length - Cal3Unified() : Base(), xi_(0) {} + Cal3Unified() = default; - Cal3Unified(double fx, double fy, double s, double u0, double v0, - double k1, double k2, double p1 = 0.0, double p2 = 0.0, double xi = 0.0) : - Base(fx, fy, s, u0, v0, k1, k2, p1, p2), xi_(xi) {} + Cal3Unified(double fx, double fy, double s, double u0, double v0, double k1, + double k2, double p1 = 0.0, double p2 = 0.0, double xi = 0.0) + : Base(fx, fy, s, u0, v0, k1, k2, p1, p2), xi_(xi) {} virtual ~Cal3Unified() {} @@ -69,7 +68,8 @@ public: /// @name Advanced Constructors /// @{ - Cal3Unified(const Vector &v) ; + Cal3Unified(const Vector10& v) + : Base(v(0), v(1), v(2), v(3), v(4), v(5), v(6), v(7), v(8)), xi_(v(9)) {} /// @} /// @name Testable @@ -88,6 +88,9 @@ public: /// mirror parameter inline double xi() const { return xi_;} + /// Return all parameters as a vector + Vector10 vector() const ; + /** * convert intrinsic coordinates xy to image coordinates uv * @param p point in intrinsic coordinates @@ -117,7 +120,7 @@ public: Cal3Unified retract(const Vector& d) const ; /// Given a different calibration, calculate update to obtain it - Vector10 localCoordinates(const Cal3Unified& T2) const ; + Vector localCoordinates(const Cal3Unified& T2) const ; /// Return dimensions of calibration manifold object virtual size_t dim() const { return dimension ; } @@ -125,9 +128,6 @@ public: /// Return dimensions of calibration manifold object static size_t Dim() { return dimension; } - /// Return all parameters as a vector - Vector10 vector() const ; - /// @} private: diff --git a/gtsam/geometry/Cal3_S2.h b/gtsam/geometry/Cal3_S2.h index 0a6b0e164..37edc46c4 100644 --- a/gtsam/geometry/Cal3_S2.h +++ b/gtsam/geometry/Cal3_S2.h @@ -42,14 +42,14 @@ class GTSAM_EXPORT Cal3_S2 : public Cal3 { /// @{ /// Create a default calibration that leaves coordinates unchanged - Cal3_S2() : Cal3() {} + Cal3_S2() = default; /// constructor from doubles Cal3_S2(double fx, double fy, double s, double u0, double v0) : Cal3(fx, fy, s, u0, v0) {} /// constructor from vector - Cal3_S2(const Vector& d) : Cal3(d) {} + Cal3_S2(const Vector5& d) : Cal3(d) {} /** * Easy constructor, takes fov in degrees, asssumes zero skew, unit aspect diff --git a/gtsam/geometry/Cal3_S2Stereo.h b/gtsam/geometry/Cal3_S2Stereo.h index 585807543..0c68ef6b4 100644 --- a/gtsam/geometry/Cal3_S2Stereo.h +++ b/gtsam/geometry/Cal3_S2Stereo.h @@ -29,7 +29,7 @@ namespace gtsam { */ class GTSAM_EXPORT Cal3_S2Stereo : public Cal3_S2 { private: - double b_; + double b_ = 1.0f; ///< Stereo baseline. public: @@ -42,7 +42,7 @@ namespace gtsam { /// @ /// default calibration leaves coordinates unchanged - Cal3_S2Stereo() : Cal3_S2(1, 1, 0, 0, 0), b_(1.0) {} + Cal3_S2Stereo() = default; /// constructor from doubles Cal3_S2Stereo(double fx, double fy, double s, double u0, double v0, @@ -50,7 +50,7 @@ namespace gtsam { : Cal3_S2(fx, fy, s, u0, v0), b_(b) {} /// constructor from vector - Cal3_S2Stereo(const Vector& d) + Cal3_S2Stereo(const Vector6& d) : Cal3_S2(d(0), d(1), d(2), d(3), d(4)), b_(d(5)) {} /// easy constructor; field-of-view in degrees, assumes zero skew @@ -61,6 +61,7 @@ namespace gtsam { /// @name Testable /// @{ + /// print with optional string void print(const std::string& s = "") const override; /// Check if equal up to specified tolerance From 355d2cff0619c3a07f08213c0815e2adc63f5f5f Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 2 Dec 2020 06:11:02 -0500 Subject: [PATCH 123/261] Cal3 code improvements --- gtsam/geometry/Cal3.cpp | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/gtsam/geometry/Cal3.cpp b/gtsam/geometry/Cal3.cpp index 31e9bf834..6183c6e5e 100644 --- a/gtsam/geometry/Cal3.cpp +++ b/gtsam/geometry/Cal3.cpp @@ -22,28 +22,25 @@ #include namespace gtsam { -using namespace std; /* ************************************************************************* */ Cal3::Cal3(double fov, int w, int h) : s_(0), u0_((double)w / 2.0), v0_((double)h / 2.0) { double a = fov * M_PI / 360.0; // fov/2 in radians - fx_ = - (double)w / (2.0 * tan(a)); // old formula: fx_ = (double) w * tan(a); + // old formula: fx_ = (double) w * tan(a); + fx_ = double(w) / (2.0 * tan(a)); fy_ = fx_; } /* ************************************************************************* */ Cal3::Cal3(const std::string& path) : fx_(320), fy_(320), s_(0), u0_(320), v0_(140) { - char buffer[200]; - buffer[0] = 0; - sprintf(buffer, "%s/calibration_info.txt", path.c_str()); + const auto buffer = path + std::string("/calibration_info.txt"); std::ifstream infile(buffer, std::ios::in); - if (infile) + if (infile) { infile >> fx_ >> fy_ >> s_ >> u0_ >> v0_; - else { + } else { throw std::runtime_error("Cal3: Unable to load the calibration"); } @@ -51,9 +48,9 @@ Cal3::Cal3(const std::string& path) } /* ************************************************************************* */ -ostream& operator<<(ostream& os, const Cal3& cal) { - os << "{fx: " << cal.fx() << ", fy: " << cal.fy() << ", s:" << cal.skew() - << ", px:" << cal.px() << ", py:" << cal.py() << "}"; +std::ostream& operator<<(std::ostream& os, const Cal3& cal) { + os << "{ fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() + << ", px: " << cal.px() << ", py: " << cal.py() << " }"; return os; } @@ -62,9 +59,9 @@ void Cal3::print(const std::string& s) const { gtsam::print((Matrix)K(), s); } /* ************************************************************************* */ bool Cal3::equals(const Cal3& K, double tol) const { - return (std::fabs(fx_ - K.fx_) < tol) && (std::fabs(fy_ - K.fy_) < tol) && - (std::fabs(s_ - K.s_) < tol) && (std::fabs(u0_ - K.u0_) < tol) && - (std::fabs(v0_ - K.v0_) < tol); + return (std::fabs(fx_ - K.fx_) < tol && std::fabs(fy_ - K.fy_) < tol && + std::fabs(s_ - K.s_) < tol && std::fabs(u0_ - K.u0_) < tol && + std::fabs(v0_ - K.v0_) < tol); } /* ************************************************************************* */ From 25b6146633967855166a1518ea93be01048de5e5 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 2 Dec 2020 06:11:50 -0500 Subject: [PATCH 124/261] matrix_inverse() -> inverse() --- gtsam/geometry/Cal3.h | 2 +- gtsam/geometry/Cal3_S2.cpp | 9 ++++----- gtsam/gtsam.i | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/gtsam/geometry/Cal3.h b/gtsam/geometry/Cal3.h index 6d3973080..b1a61c592 100644 --- a/gtsam/geometry/Cal3.h +++ b/gtsam/geometry/Cal3.h @@ -165,7 +165,7 @@ class GTSAM_EXPORT Cal3 { #endif /// Return inverted calibration matrix inv(K) - Matrix3 matrix_inverse() const { + Matrix3 inverse() const { const double fxy = fx_ * fy_, sv0 = s_ * v0_, fyu0 = fy_ * u0_; Matrix3 K_inverse; K_inverse << 1.0 / fx_, -s_ / fxy, (sv0 - fyu0) / fxy, 0.0, 1.0 / fy_, diff --git a/gtsam/geometry/Cal3_S2.cpp b/gtsam/geometry/Cal3_S2.cpp index 12635abdd..2d830a4a3 100644 --- a/gtsam/geometry/Cal3_S2.cpp +++ b/gtsam/geometry/Cal3_S2.cpp @@ -22,12 +22,11 @@ #include namespace gtsam { -using namespace std; /* ************************************************************************* */ -ostream& operator<<(ostream& os, const Cal3_S2& cal) { - os << "{fx: " << cal.fx() << ", fy: " << cal.fy() << ", s:" << cal.skew() - << ", px:" << cal.px() << ", py:" << cal.py() << "}"; +std::ostream& operator<<(std::ostream& os, const Cal3_S2& cal) { + os << "{ fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() + << ", px: " << cal.px() << ", py: " << cal.py() << " }"; return os; } @@ -68,7 +67,7 @@ Point2 Cal3_S2::calibrate(const Point2& p, OptionalJacobian<2, 5> Dcal, } /* ************************************************************************* */ -Vector3 Cal3_S2::calibrate(const Vector3& p) const { return matrix_inverse() * p; } +Vector3 Cal3_S2::calibrate(const Vector3& p) const { return inverse() * p; } /* ************************************************************************* */ diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index e405e533c..493c1d7db 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -852,7 +852,7 @@ class Cal3_S2 { gtsam::Point2 principalPoint() const; Vector vector() const; Matrix K() const; - Matrix matrix_inverse() const; + Matrix inverse() const; // enabling serialization functionality void serialize() const; From f7d9710543e1a0d7f899159916d260afd92ecfd5 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 2 Dec 2020 06:13:35 -0500 Subject: [PATCH 125/261] remove using-namespace and fix print test --- gtsam/geometry/Cal3_S2Stereo.cpp | 11 +++++++++-- gtsam/geometry/tests/testCal3_S2.cpp | 4 ++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/gtsam/geometry/Cal3_S2Stereo.cpp b/gtsam/geometry/Cal3_S2Stereo.cpp index 43f0fb12f..3bf7c3468 100644 --- a/gtsam/geometry/Cal3_S2Stereo.cpp +++ b/gtsam/geometry/Cal3_S2Stereo.cpp @@ -20,7 +20,14 @@ #include namespace gtsam { -using namespace std; + +/* ************************************************************************* */ +std::ostream& operator<<(std::ostream& os, const Cal3_S2Stereo& cal) { + os << "{ fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() + << ", px: " << cal.px() << ", py: " << cal.py() + << ", b: " << cal.baseline() << " }"; + return os; +} /* ************************************************************************* */ void Cal3_S2Stereo::print(const std::string& s) const { @@ -32,7 +39,7 @@ void Cal3_S2Stereo::print(const std::string& s) const { /* ************************************************************************* */ bool Cal3_S2Stereo::equals(const Cal3_S2Stereo& other, double tol) const { const Cal3_S2* base = dynamic_cast(&other); - return Cal3_S2::equals(*base, tol) && (std::fabs(b_ - other.baseline()) < tol); + return (Cal3_S2::equals(*base, tol) && std::fabs(b_ - other.baseline()) < tol); } /* ************************************************************************* */ diff --git a/gtsam/geometry/tests/testCal3_S2.cpp b/gtsam/geometry/tests/testCal3_S2.cpp index f7c8fb6b6..64e807aaf 100644 --- a/gtsam/geometry/tests/testCal3_S2.cpp +++ b/gtsam/geometry/tests/testCal3_S2.cpp @@ -131,8 +131,8 @@ TEST(Cal3_S2, between) { TEST(Cal3_S2, Print) { Cal3_S2 cal(5, 5, 5, 5, 5); std::stringstream os; - os << "{fx: " << cal.fx() << ", fy: " << cal.fy() << ", s:" << cal.skew() << ", px:" << cal.px() - << ", py:" << cal.py() << "}"; + os << "{ fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() + << ", px: " << cal.px() << ", py: " << cal.py() << " }"; EXPECT(assert_stdout_equal(os.str(), cal)); } From 916771c02caa14feed8fdc863c41d97c9d1a07b4 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 2 Dec 2020 08:04:36 -0500 Subject: [PATCH 126/261] Added tests for printing, plus small formatting --- gtsam/geometry/tests/testCal3Bundler.cpp | 29 +++-- gtsam/geometry/tests/testCal3DFisheye.cpp | 14 ++- gtsam/geometry/tests/testCal3DS2.cpp | 26 ++-- gtsam/geometry/tests/testCal3Unified.cpp | 35 ++++-- gtsam/geometry/tests/testCal3_S2.cpp | 20 +-- gtsam/geometry/tests/testCal3_S2Stereo.cpp | 136 +++++++++++++++++++++ 6 files changed, 222 insertions(+), 38 deletions(-) create mode 100644 gtsam/geometry/tests/testCal3_S2Stereo.cpp diff --git a/gtsam/geometry/tests/testCal3Bundler.cpp b/gtsam/geometry/tests/testCal3Bundler.cpp index 448600266..75aa50a25 100644 --- a/gtsam/geometry/tests/testCal3Bundler.cpp +++ b/gtsam/geometry/tests/testCal3Bundler.cpp @@ -11,11 +11,12 @@ /** * @file testCal3Bundler.cpp - * @brief Unit tests for transform derivatives + * @brief Unit tests for Bundler calibration model. */ #include #include +#include #include #include @@ -28,7 +29,7 @@ static Cal3Bundler K(500, 1e-3, 1e-3, 1000, 2000); static Point2 p(2,3); /* ************************************************************************* */ -TEST( Cal3Bundler, vector) +TEST(Cal3Bundler, vector) { Cal3Bundler K; Vector expected(3); @@ -37,7 +38,7 @@ TEST( Cal3Bundler, vector) } /* ************************************************************************* */ -TEST( Cal3Bundler, uncalibrate) +TEST(Cal3Bundler, uncalibrate) { Vector v = K.vector() ; double r = p.x()*p.x() + p.y()*p.y() ; @@ -47,7 +48,7 @@ TEST( Cal3Bundler, uncalibrate) CHECK(assert_equal(expected,actual)); } -TEST( Cal3Bundler, calibrate ) +TEST(Cal3Bundler, calibrate ) { Point2 pn(0.5, 0.5); Point2 pi = K.uncalibrate(pn); @@ -61,7 +62,7 @@ Point2 uncalibrate_(const Cal3Bundler& k, const Point2& pt) { return k.uncalibra Point2 calibrate_(const Cal3Bundler& k, const Point2& pt) { return k.calibrate(pt); } /* ************************************************************************* */ -TEST( Cal3Bundler, Duncalibrate) +TEST(Cal3Bundler, Duncalibrate) { Matrix Dcal, Dp; Point2 actual = K.uncalibrate(p, Dcal, Dp); @@ -74,7 +75,7 @@ TEST( Cal3Bundler, Duncalibrate) } /* ************************************************************************* */ -TEST( Cal3Bundler, Dcalibrate) +TEST(Cal3Bundler, Dcalibrate) { Matrix Dcal, Dp; Point2 pn(0.5, 0.5); @@ -88,22 +89,32 @@ TEST( Cal3Bundler, Dcalibrate) } /* ************************************************************************* */ -TEST( Cal3Bundler, assert_equal) +TEST(Cal3Bundler, assert_equal) { CHECK(assert_equal(K,K,1e-7)); } /* ************************************************************************* */ -TEST( Cal3Bundler, retract) +TEST(Cal3Bundler, retract) { Cal3Bundler expected(510, 2e-3, 2e-3, 1000, 2000); - Vector d(3); + Vector3 d; d << 10, 1e-3, 1e-3; Cal3Bundler actual = K.retract(d); CHECK(assert_equal(expected,actual,1e-7)); CHECK(assert_equal(d,K.localCoordinates(actual),1e-7)); } +/* ************************************************************************* */ +TEST(Cal3_S2, Print) { + Cal3Bundler cal(1, 2, 3, 4, 5); + std::stringstream os; + os << "f: " << cal.fx() << ", k1: " << cal.k1() << ", k2: " << cal.k2() + << ", px: " << cal.px() << ", py: " << cal.py(); + + EXPECT(assert_stdout_equal(os.str(), cal)); +} + /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } /* ************************************************************************* */ diff --git a/gtsam/geometry/tests/testCal3DFisheye.cpp b/gtsam/geometry/tests/testCal3DFisheye.cpp index 6bfbe3e46..85e661728 100644 --- a/gtsam/geometry/tests/testCal3DFisheye.cpp +++ b/gtsam/geometry/tests/testCal3DFisheye.cpp @@ -10,12 +10,13 @@ * -------------------------------------------------------------------------- */ /** - * @file testCal3DFisheye.cpp + * @file testCal3Fisheye.cpp * @brief Unit tests for fisheye calibration class * @author ghaggin */ #include +#include #include #include #include @@ -198,6 +199,17 @@ TEST(Cal3Fisheye, Dcalibrate) CHECK(assert_equal(numerical2,Dp,1e-5)); } +/* ************************************************************************* */ +TEST(Cal3Fisheye, Print) { + Cal3Fisheye cal(1, 2, 3, 4, 5, 6, 7, 8, 9); + std::stringstream os; + os << "fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() + << ", px: " << cal.px() << ", py: " << cal.py() << ", k1: " << cal.k1() + << ", k2: " << cal.k2() << ", k3: " << cal.k3() << ", k4: " << cal.k4(); + + EXPECT(assert_stdout_equal(os.str(), cal)); +} + /* ************************************************************************* */ int main() { TestResult tr; diff --git a/gtsam/geometry/tests/testCal3DS2.cpp b/gtsam/geometry/tests/testCal3DS2.cpp index beed09883..b382e85f3 100644 --- a/gtsam/geometry/tests/testCal3DS2.cpp +++ b/gtsam/geometry/tests/testCal3DS2.cpp @@ -11,12 +11,13 @@ /** * @file testCal3DS2.cpp - * @brief Unit tests for transform derivatives + * @brief Unit tests for Cal3DS2 calibration model. */ #include #include +#include #include #include @@ -29,7 +30,7 @@ static Cal3DS2 K(500, 100, 0.1, 320, 240, 1e-3, 2.0*1e-3, 3.0*1e-3, 4.0*1e-3); static Point2 p(2,3); /* ************************************************************************* */ -TEST( Cal3DS2, uncalibrate) +TEST(Cal3DS2, uncalibrate) { Vector k = K.k() ; double r = p.x()*p.x() + p.y()*p.y() ; @@ -43,7 +44,7 @@ TEST( Cal3DS2, uncalibrate) CHECK(assert_equal(q,p_i)); } -TEST( Cal3DS2, calibrate ) +TEST(Cal3DS2, calibrate ) { Point2 pn(0.5, 0.5); Point2 pi = K.uncalibrate(pn); @@ -54,7 +55,7 @@ TEST( Cal3DS2, calibrate ) Point2 uncalibrate_(const Cal3DS2& k, const Point2& pt) { return k.uncalibrate(pt); } /* ************************************************************************* */ -TEST( Cal3DS2, Duncalibrate1) +TEST(Cal3DS2, Duncalibrate1) { Matrix computed; K.uncalibrate(p, computed, boost::none); @@ -65,7 +66,7 @@ TEST( Cal3DS2, Duncalibrate1) } /* ************************************************************************* */ -TEST( Cal3DS2, Duncalibrate2) +TEST(Cal3DS2, Duncalibrate2) { Matrix computed; K.uncalibrate(p, boost::none, computed); Matrix numerical = numericalDerivative22(uncalibrate_, K, p, 1e-7); @@ -79,7 +80,7 @@ Point2 calibrate_(const Cal3DS2& k, const Point2& pt) { } /* ************************************************************************* */ -TEST( Cal3DS2, Dcalibrate) +TEST(Cal3DS2, Dcalibrate) { Point2 pn(0.5, 0.5); Point2 pi = K.uncalibrate(pn); @@ -95,7 +96,7 @@ TEST( Cal3DS2, Dcalibrate) TEST(Cal3DS2, assert_equal) { CHECK(assert_equal(K, K, 1e-5)); } /* ************************************************************************* */ -TEST( Cal3DS2, retract) +TEST(Cal3DS2, retract) { Cal3DS2 expected(500 + 1, 100 + 2, 0.1 + 3, 320 + 4, 240 + 5, 1e-3 + 6, 2.0 * 1e-3 + 7, 3.0 * 1e-3 + 8, 4.0 * 1e-3 + 9); @@ -106,6 +107,17 @@ TEST( Cal3DS2, retract) CHECK(assert_equal(d,K.localCoordinates(actual),1e-7)); } +/* ************************************************************************* */ +TEST(Cal3DS2, Print) { + Cal3DS2 cal(1, 2, 3, 4, 5, 6, 7, 8, 9); + std::stringstream os; + os << "fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() + << ", px: " << cal.px() << ", py: " << cal.py() << ", k1: " << cal.k1() + << ", k2: " << cal.k2() << ", p1: " << cal.p1() << ", p2: " << cal.p2(); + + EXPECT(assert_stdout_equal(os.str(), cal)); +} + /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } /* ************************************************************************* */ diff --git a/gtsam/geometry/tests/testCal3Unified.cpp b/gtsam/geometry/tests/testCal3Unified.cpp index 8abb6fe04..41a1d3ad9 100644 --- a/gtsam/geometry/tests/testCal3Unified.cpp +++ b/gtsam/geometry/tests/testCal3Unified.cpp @@ -10,12 +10,13 @@ * -------------------------------------------------------------------------- */ /** - * @file testCal3Unify.cpp - * @brief Unit tests for transform derivatives + * @file testCal3Unified.cpp + * @brief Unit tests for Cal3Unified calibration model. */ #include #include +#include #include #include @@ -39,7 +40,7 @@ static Cal3Unified K(100, 105, 0.0, 320, 240, 1e-3, 2.0*1e-3, 3.0*1e-3, 4.0*1e-3 static Point2 p(0.5, 0.7); /* ************************************************************************* */ -TEST( Cal3Unified, uncalibrate) +TEST(Cal3Unified, uncalibrate) { Point2 p_i(364.7791831734982, 305.6677211952602) ; Point2 q = K.uncalibrate(p); @@ -47,7 +48,7 @@ TEST( Cal3Unified, uncalibrate) } /* ************************************************************************* */ -TEST( Cal3Unified, spaceNplane) +TEST(Cal3Unified, spaceNplane) { Point2 q = K.spaceToNPlane(p); CHECK(assert_equal(Point2(0.441731600049497, 0.618424240069295), q)); @@ -55,7 +56,7 @@ TEST( Cal3Unified, spaceNplane) } /* ************************************************************************* */ -TEST( Cal3Unified, calibrate) +TEST(Cal3Unified, calibrate) { Point2 pi = K.uncalibrate(p); Point2 pn_hat = K.calibrate(pi); @@ -65,7 +66,7 @@ TEST( Cal3Unified, calibrate) Point2 uncalibrate_(const Cal3Unified& k, const Point2& pt) { return k.uncalibrate(pt); } /* ************************************************************************* */ -TEST( Cal3Unified, Duncalibrate1) +TEST(Cal3Unified, Duncalibrate1) { Matrix computed; K.uncalibrate(p, computed, boost::none); @@ -74,7 +75,7 @@ TEST( Cal3Unified, Duncalibrate1) } /* ************************************************************************* */ -TEST( Cal3Unified, Duncalibrate2) +TEST(Cal3Unified, Duncalibrate2) { Matrix computed; K.uncalibrate(p, boost::none, computed); @@ -87,7 +88,7 @@ Point2 calibrate_(const Cal3Unified& k, const Point2& pt) { } /* ************************************************************************* */ -TEST( Cal3Unified, Dcalibrate) +TEST(Cal3Unified, Dcalibrate) { Point2 pi = K.uncalibrate(p); Matrix Dcal, Dp; @@ -99,13 +100,13 @@ TEST( Cal3Unified, Dcalibrate) } /* ************************************************************************* */ -TEST( Cal3Unified, assert_equal) +TEST(Cal3Unified, assert_equal) { CHECK(assert_equal(K,K,1e-9)); } /* ************************************************************************* */ -TEST( Cal3Unified, retract) +TEST(Cal3Unified, retract) { Cal3Unified expected(100 + 2, 105 + 3, 0.0 + 4, 320 + 5, 240 + 6, 1e-3 + 7, 2.0*1e-3 + 8, 3.0*1e-3 + 9, 4.0*1e-3 + 10, 0.1 + 1); @@ -117,7 +118,7 @@ TEST( Cal3Unified, retract) } /* ************************************************************************* */ -TEST( Cal3Unified, DerivedValue) +TEST(Cal3Unified, DerivedValue) { Values values; Cal3Unified cal(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); @@ -129,6 +130,18 @@ TEST( Cal3Unified, DerivedValue) CHECK(assert_equal(cal,calafter,1e-9)); } +/* ************************************************************************* */ +TEST(Cal3Unified, Print) { + Cal3Unified cal(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + std::stringstream os; + os << "fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() + << ", px: " << cal.px() << ", py: " << cal.py() << ", k1: " << cal.k1() + << ", k2: " << cal.k2() << ", p1: " << cal.p1() << ", p2: " << cal.p2() + << ", xi: " << cal.xi(); + + EXPECT(assert_stdout_equal(os.str(), cal)); +} + /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } /* ************************************************************************* */ diff --git a/gtsam/geometry/tests/testCal3_S2.cpp b/gtsam/geometry/tests/testCal3_S2.cpp index 64e807aaf..3317addff 100644 --- a/gtsam/geometry/tests/testCal3_S2.cpp +++ b/gtsam/geometry/tests/testCal3_S2.cpp @@ -11,7 +11,7 @@ /** * @file testCal3_S2.cpp - * @brief Unit tests for transform derivatives + * @brief Unit tests for basic Cal3_S2 calibration model. */ #include @@ -31,7 +31,7 @@ static Point2 p_uv(1320.3, 1740); static Point2 p_xy(2, 3); /* ************************************************************************* */ -TEST( Cal3_S2, easy_constructor) +TEST(Cal3_S2, easy_constructor) { Cal3_S2 expected(554.256, 554.256, 0, 640 / 2, 480 / 2); @@ -43,7 +43,7 @@ TEST( Cal3_S2, easy_constructor) } /* ************************************************************************* */ -TEST( Cal3_S2, calibrate) +TEST(Cal3_S2, calibrate) { Point2 intrinsic(2,3); Point2 expectedimage(1320.3, 1740); @@ -53,7 +53,7 @@ TEST( Cal3_S2, calibrate) } /* ************************************************************************* */ -TEST( Cal3_S2, calibrate_homogeneous) { +TEST(Cal3_S2, calibrate_homogeneous) { Vector3 intrinsic(2, 3, 1); Vector3 image(1320.3, 1740, 1); CHECK(assert_equal((Vector)intrinsic,(Vector)K.calibrate(image))); @@ -61,7 +61,7 @@ TEST( Cal3_S2, calibrate_homogeneous) { /* ************************************************************************* */ Point2 uncalibrate_(const Cal3_S2& k, const Point2& pt) { return k.uncalibrate(pt); } -TEST( Cal3_S2, Duncalibrate1) +TEST(Cal3_S2, Duncalibrate1) { Matrix25 computed; K.uncalibrate(p, computed, boost::none); Matrix numerical = numericalDerivative21(uncalibrate_, K, p); @@ -69,7 +69,7 @@ TEST( Cal3_S2, Duncalibrate1) } /* ************************************************************************* */ -TEST( Cal3_S2, Duncalibrate2) +TEST(Cal3_S2, Duncalibrate2) { Matrix computed; K.uncalibrate(p, boost::none, computed); Matrix numerical = numericalDerivative22(uncalibrate_, K, p); @@ -98,7 +98,7 @@ TEST(Cal3_S2, Dcalibrate2) } /* ************************************************************************* */ -TEST( Cal3_S2, assert_equal) +TEST(Cal3_S2, assert_equal) { CHECK(assert_equal(K,K,1e-9)); @@ -107,7 +107,7 @@ TEST( Cal3_S2, assert_equal) } /* ************************************************************************* */ -TEST( Cal3_S2, retract) +TEST(Cal3_S2, retract) { Cal3_S2 expected(500+1, 500+2, 0.1+3, 640 / 2+4, 480 / 2+5); Vector d(5); @@ -131,8 +131,8 @@ TEST(Cal3_S2, between) { TEST(Cal3_S2, Print) { Cal3_S2 cal(5, 5, 5, 5, 5); std::stringstream os; - os << "{ fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() - << ", px: " << cal.px() << ", py: " << cal.py() << " }"; + os << "fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() + << ", px: " << cal.px() << ", py: " << cal.py(); EXPECT(assert_stdout_equal(os.str(), cal)); } diff --git a/gtsam/geometry/tests/testCal3_S2Stereo.cpp b/gtsam/geometry/tests/testCal3_S2Stereo.cpp new file mode 100644 index 000000000..9c93b7496 --- /dev/null +++ b/gtsam/geometry/tests/testCal3_S2Stereo.cpp @@ -0,0 +1,136 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file testCal3_S2Stereo.cpp + * @brief Unit tests for stereo-rig calibration model. + */ + +#include +#include +#include +#include +#include + +using namespace gtsam; + +GTSAM_CONCEPT_TESTABLE_INST(Cal3_S2Stereo) +GTSAM_CONCEPT_MANIFOLD_INST(Cal3_S2Stereo) + +static Cal3_S2Stereo K(500, 500, 0.1, 640 / 2, 480 / 2, 1); +static Point2 p(1, -2); +static Point2 p_uv(1320.3, 1740); +static Point2 p_xy(2, 3); + +/* ************************************************************************* */ +TEST(Cal3_S2Stereo, easy_constructor) { + Cal3_S2Stereo expected(554.256, 554.256, 0, 640 / 2, 480 / 2, 3); + + double fov = 60; // degrees + size_t w = 640, h = 480; + Cal3_S2Stereo actual(fov, w, h, 3); + + CHECK(assert_equal(expected, actual, 1e-3)); +} + +/* ************************************************************************* */ +TEST(Cal3_S2Stereo, calibrate) { + Point2 intrinsic(2, 3); + Point2 expectedimage(1320.3, 1740); + Point2 imagecoordinates = K.uncalibrate(intrinsic); + CHECK(assert_equal(expectedimage, imagecoordinates)); + CHECK(assert_equal(intrinsic, K.calibrate(imagecoordinates))); +} + +/* ************************************************************************* */ +TEST(Cal3_S2Stereo, calibrate_homogeneous) { + Vector3 intrinsic(2, 3, 1); + Vector3 image(1320.3, 1740, 1); + CHECK(assert_equal((Vector)intrinsic, (Vector)K.calibrate(image))); +} + +//TODO(Varun) Add calibrate and uncalibrate methods +// /* ************************************************************************* */ +// Point2 uncalibrate_(const Cal3_S2Stereo& k, const Point2& pt) { +// return k.uncalibrate(pt); +// } + +// TEST(Cal3_S2Stereo, Duncalibrate1) { +// Matrix26 computed; +// K.uncalibrate(p, computed, boost::none); +// Matrix numerical = numericalDerivative21(uncalibrate_, K, p); +// CHECK(assert_equal(numerical, computed, 1e-8)); +// } + +// /* ************************************************************************* */ +// TEST(Cal3_S2Stereo, Duncalibrate2) { +// Matrix computed; +// K.uncalibrate(p, boost::none, computed); +// Matrix numerical = numericalDerivative22(uncalibrate_, K, p); +// CHECK(assert_equal(numerical, computed, 1e-9)); +// } + +// Point2 calibrate_(const Cal3_S2Stereo& k, const Point2& pt) { +// return k.calibrate(pt); +// } +// /* ************************************************************************* */ +// TEST(Cal3_S2Stereo, Dcalibrate1) { +// Matrix computed; +// Point2 expected = K.calibrate(p_uv, computed, boost::none); +// Matrix numerical = numericalDerivative21(calibrate_, K, p_uv); +// CHECK(assert_equal(expected, p_xy, 1e-8)); +// CHECK(assert_equal(numerical, computed, 1e-8)); +// } + +// /* ************************************************************************* */ +// TEST(Cal3_S2Stereo, Dcalibrate2) { +// Matrix computed; +// Point2 expected = K.calibrate(p_uv, boost::none, computed); +// Matrix numerical = numericalDerivative22(calibrate_, K, p_uv); +// CHECK(assert_equal(expected, p_xy, 1e-8)); +// CHECK(assert_equal(numerical, computed, 1e-8)); +// } + +/* ************************************************************************* */ +TEST(Cal3_S2Stereo, assert_equal) { + CHECK(assert_equal(K, K, 1e-9)); + + Cal3_S2Stereo K1(500, 500, 0.1, 640 / 2, 480 / 2, 1); + CHECK(assert_equal(K, K1, 1e-9)); +} + +/* ************************************************************************* */ +TEST(Cal3_S2Stereo, retract) { + Cal3_S2Stereo expected(500 + 1, 500 + 2, 0.1 + 3, 640 / 2 + 4, 480 / 2 + 5, + 7); + Vector6 d; + d << 1, 2, 3, 4, 5, 6; + Cal3_S2Stereo actual = K.retract(d); + CHECK(assert_equal(expected, actual, 1e-7)); + CHECK(assert_equal(d, K.localCoordinates(actual), 1e-7)); +} + +/* ************************************************************************* */ +TEST(Cal3_S2Stereo, Print) { + Cal3_S2Stereo cal(5, 5, 5, 5, 5, 2); + std::stringstream os; + os << "fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() + << ", px: " << cal.px() << ", py: " << cal.py() + << ", b: " << cal.baseline(); + EXPECT(assert_stdout_equal(os.str(), cal)); +} + +/* ************************************************************************* */ +int main() { + TestResult tr; + return TestRegistry::runAllTests(tr); +} +/* ************************************************************************* */ From e488dc8e9c5be5f04ec597c69b363848478939b9 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 2 Dec 2020 08:19:19 -0500 Subject: [PATCH 127/261] stream printing for all calibration models --- gtsam/geometry/Cal3.cpp | 4 ++-- gtsam/geometry/Cal3Bundler.cpp | 7 +++++++ gtsam/geometry/Cal3Bundler.h | 4 ++++ gtsam/geometry/Cal3DS2.cpp | 6 ++++++ gtsam/geometry/Cal3DS2.h | 4 ++++ gtsam/geometry/Cal3DS2_Base.cpp | 8 ++++++++ gtsam/geometry/Cal3DS2_Base.h | 4 ++++ gtsam/geometry/Cal3Fisheye.cpp | 8 ++++++++ gtsam/geometry/Cal3Fisheye.h | 4 ++++ gtsam/geometry/Cal3Unified.cpp | 7 +++++++ gtsam/geometry/Cal3Unified.h | 4 ++++ gtsam/geometry/Cal3_S2.cpp | 4 ++-- gtsam/geometry/Cal3_S2Stereo.cpp | 7 +++---- gtsam/geometry/Cal3_S2Stereo.h | 7 +++++-- 14 files changed, 68 insertions(+), 10 deletions(-) diff --git a/gtsam/geometry/Cal3.cpp b/gtsam/geometry/Cal3.cpp index 6183c6e5e..ec39d7eda 100644 --- a/gtsam/geometry/Cal3.cpp +++ b/gtsam/geometry/Cal3.cpp @@ -49,8 +49,8 @@ Cal3::Cal3(const std::string& path) /* ************************************************************************* */ std::ostream& operator<<(std::ostream& os, const Cal3& cal) { - os << "{ fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() - << ", px: " << cal.px() << ", py: " << cal.py() << " }"; + os << "fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() + << ", px: " << cal.px() << ", py: " << cal.py(); return os; } diff --git a/gtsam/geometry/Cal3Bundler.cpp b/gtsam/geometry/Cal3Bundler.cpp index 8c524e1cc..af2f881d8 100644 --- a/gtsam/geometry/Cal3Bundler.cpp +++ b/gtsam/geometry/Cal3Bundler.cpp @@ -42,6 +42,13 @@ Vector3 Cal3Bundler::vector() const { return Vector3(f_, k1_, k2_); } +/* ************************************************************************* */ +std::ostream& operator<<(std::ostream& os, const Cal3Bundler& cal) { + os << "f: " << cal.fx() << ", k1: " << cal.k1() << ", k2: " << cal.k2() + << ", px: " << cal.px() << ", py: " << cal.py(); + return os; +} + /* ************************************************************************* */ void Cal3Bundler::print(const std::string& s) const { gtsam::print((Vector)(Vector(5) << f_, k1_, k2_, u0_, v0_).finished(), s + ".K"); diff --git a/gtsam/geometry/Cal3Bundler.h b/gtsam/geometry/Cal3Bundler.h index d128c329b..76703f96f 100644 --- a/gtsam/geometry/Cal3Bundler.h +++ b/gtsam/geometry/Cal3Bundler.h @@ -67,6 +67,10 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { /// @name Testable /// @{ + /// Output stream operator + GTSAM_EXPORT friend std::ostream& operator<<(std::ostream& os, + const Cal3Bundler& cal); + /// print with optional string void print(const std::string& s = "") const override; diff --git a/gtsam/geometry/Cal3DS2.cpp b/gtsam/geometry/Cal3DS2.cpp index b4595a4dc..71aa2738d 100644 --- a/gtsam/geometry/Cal3DS2.cpp +++ b/gtsam/geometry/Cal3DS2.cpp @@ -24,6 +24,12 @@ namespace gtsam { +/* ************************************************************************* */ +std::ostream& operator<<(std::ostream& os, const Cal3DS2& cal) { + os << (Cal3DS2_Base&)cal; + return os; +} + /* ************************************************************************* */ void Cal3DS2::print(const std::string& s_) const { Base::print(s_); diff --git a/gtsam/geometry/Cal3DS2.h b/gtsam/geometry/Cal3DS2.h index 03a4d8d46..d0bed8652 100644 --- a/gtsam/geometry/Cal3DS2.h +++ b/gtsam/geometry/Cal3DS2.h @@ -60,6 +60,10 @@ public: /// @name Testable /// @{ + /// Output stream operator + GTSAM_EXPORT friend std::ostream& operator<<(std::ostream& os, + const Cal3DS2& cal); + /// print with optional string void print(const std::string& s = "") const override; diff --git a/gtsam/geometry/Cal3DS2_Base.cpp b/gtsam/geometry/Cal3DS2_Base.cpp index 016c9dfa2..2741d0736 100644 --- a/gtsam/geometry/Cal3DS2_Base.cpp +++ b/gtsam/geometry/Cal3DS2_Base.cpp @@ -31,6 +31,14 @@ Vector9 Cal3DS2_Base::vector() const { return v; } +/* ************************************************************************* */ +std::ostream& operator<<(std::ostream& os, const Cal3DS2_Base& cal) { + os << (Cal3&)cal; + os << ", k1: " << cal.k1() << ", k2: " << cal.k2() << ", p1: " << cal.p1() + << ", p2: " << cal.p2(); + return os; +} + /* ************************************************************************* */ void Cal3DS2_Base::print(const std::string& s_) const { gtsam::print((Matrix)K(), s_ + ".K"); diff --git a/gtsam/geometry/Cal3DS2_Base.h b/gtsam/geometry/Cal3DS2_Base.h index e0de6af61..713fa4e0e 100644 --- a/gtsam/geometry/Cal3DS2_Base.h +++ b/gtsam/geometry/Cal3DS2_Base.h @@ -80,6 +80,10 @@ class GTSAM_EXPORT Cal3DS2_Base : public Cal3 { /// @name Testable /// @{ + /// Output stream operator + GTSAM_EXPORT friend std::ostream& operator<<(std::ostream& os, + const Cal3DS2_Base& cal); + /// print with optional string void print(const std::string& s = "") const override; diff --git a/gtsam/geometry/Cal3Fisheye.cpp b/gtsam/geometry/Cal3Fisheye.cpp index 55020f581..b9e60acee 100644 --- a/gtsam/geometry/Cal3Fisheye.cpp +++ b/gtsam/geometry/Cal3Fisheye.cpp @@ -139,6 +139,14 @@ Point2 Cal3Fisheye::calibrate(const Point2& uv, OptionalJacobian<2, 9> Dcal, return pi; } +/* ************************************************************************* */ +std::ostream& operator<<(std::ostream& os, const Cal3Fisheye& cal) { + os << (Cal3&)cal; + os << ", k1: " << cal.k1() << ", k2: " << cal.k2() << ", k3: " << cal.k3() + << ", k4: " << cal.k4(); + return os; +} + /* ************************************************************************* */ void Cal3Fisheye::print(const std::string& s_) const { gtsam::print((Matrix)K(), s_ + ".K"); diff --git a/gtsam/geometry/Cal3Fisheye.h b/gtsam/geometry/Cal3Fisheye.h index f41a9b0d7..738b2275d 100644 --- a/gtsam/geometry/Cal3Fisheye.h +++ b/gtsam/geometry/Cal3Fisheye.h @@ -137,6 +137,10 @@ class GTSAM_EXPORT Cal3Fisheye : public Cal3 { /// @name Testable /// @{ + /// Output stream operator + GTSAM_EXPORT friend std::ostream& operator<<(std::ostream& os, + const Cal3Fisheye& cal); + /// print with optional string virtual void print(const std::string& s = "") const override; diff --git a/gtsam/geometry/Cal3Unified.cpp b/gtsam/geometry/Cal3Unified.cpp index d260dd725..80613bbf2 100644 --- a/gtsam/geometry/Cal3Unified.cpp +++ b/gtsam/geometry/Cal3Unified.cpp @@ -32,6 +32,13 @@ Vector10 Cal3Unified::vector() const { return v; } +/* ************************************************************************* */ +std::ostream& operator<<(std::ostream& os, const Cal3Unified& cal) { + os << (Cal3DS2_Base&)cal; + os << ", xi: " << cal.xi(); + return os; +} + /* ************************************************************************* */ void Cal3Unified::print(const std::string& s) const { Base::print(s); diff --git a/gtsam/geometry/Cal3Unified.h b/gtsam/geometry/Cal3Unified.h index e1368db4c..a2c5ebc5c 100644 --- a/gtsam/geometry/Cal3Unified.h +++ b/gtsam/geometry/Cal3Unified.h @@ -75,6 +75,10 @@ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { /// @name Testable /// @{ + /// Output stream operator + GTSAM_EXPORT friend std::ostream& operator<<(std::ostream& os, + const Cal3Unified& cal); + /// print with optional string void print(const std::string& s = "") const override; diff --git a/gtsam/geometry/Cal3_S2.cpp b/gtsam/geometry/Cal3_S2.cpp index 2d830a4a3..98c7bea38 100644 --- a/gtsam/geometry/Cal3_S2.cpp +++ b/gtsam/geometry/Cal3_S2.cpp @@ -25,8 +25,8 @@ namespace gtsam { /* ************************************************************************* */ std::ostream& operator<<(std::ostream& os, const Cal3_S2& cal) { - os << "{ fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() - << ", px: " << cal.px() << ", py: " << cal.py() << " }"; + // Use the base class version since it is identical. + os << (Cal3&)cal; return os; } diff --git a/gtsam/geometry/Cal3_S2Stereo.cpp b/gtsam/geometry/Cal3_S2Stereo.cpp index 3bf7c3468..8bd733e95 100644 --- a/gtsam/geometry/Cal3_S2Stereo.cpp +++ b/gtsam/geometry/Cal3_S2Stereo.cpp @@ -23,16 +23,15 @@ namespace gtsam { /* ************************************************************************* */ std::ostream& operator<<(std::ostream& os, const Cal3_S2Stereo& cal) { - os << "{ fx: " << cal.fx() << ", fy: " << cal.fy() << ", s: " << cal.skew() - << ", px: " << cal.px() << ", py: " << cal.py() - << ", b: " << cal.baseline() << " }"; + os << (Cal3_S2&)cal; + os << ", b: " << cal.baseline(); return os; } /* ************************************************************************* */ void Cal3_S2Stereo::print(const std::string& s) const { std::cout << s << (s != "" ? " " : ""); - print("K: "); + std::cout << "K: " << (Matrix)K() << std::endl; std::cout << "Baseline: " << b_ << std::endl; } diff --git a/gtsam/geometry/Cal3_S2Stereo.h b/gtsam/geometry/Cal3_S2Stereo.h index 0c68ef6b4..94341ec37 100644 --- a/gtsam/geometry/Cal3_S2Stereo.h +++ b/gtsam/geometry/Cal3_S2Stereo.h @@ -61,6 +61,10 @@ namespace gtsam { /// @name Testable /// @{ + /// Output stream operator + GTSAM_EXPORT friend std::ostream& operator<<(std::ostream& os, + const Cal3_S2Stereo& cal); + /// print with optional string void print(const std::string& s = "") const override; @@ -83,7 +87,7 @@ namespace gtsam { /// vectorized form (column-wise) Vector6 vector() const { Vector6 v; - v << vector(), b_; + v << Cal3_S2::vector(), b_; return v; } @@ -108,7 +112,6 @@ namespace gtsam { return T2.vector() - vector(); } - /// @} /// @name Advanced Interface /// @{ From ecb0af57fdad66ea6e5c8bd1b1bbec5585e3fb96 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 2 Dec 2020 08:36:23 -0500 Subject: [PATCH 128/261] Improved constructor for loading parameters from file --- gtsam/geometry/Cal3.cpp | 5 ++--- gtsam/geometry/Cal3.h | 10 +++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/gtsam/geometry/Cal3.cpp b/gtsam/geometry/Cal3.cpp index ec39d7eda..6210a6065 100644 --- a/gtsam/geometry/Cal3.cpp +++ b/gtsam/geometry/Cal3.cpp @@ -33,12 +33,11 @@ Cal3::Cal3(double fov, int w, int h) } /* ************************************************************************* */ -Cal3::Cal3(const std::string& path) - : fx_(320), fy_(320), s_(0), u0_(320), v0_(140) { +Cal3::Cal3(const std::string& path) { const auto buffer = path + std::string("/calibration_info.txt"); std::ifstream infile(buffer, std::ios::in); - if (infile) { + if (infile && !infile.eof()) { infile >> fx_ >> fy_ >> s_ >> u0_ >> v0_; } else { throw std::runtime_error("Cal3: Unable to load the calibration"); diff --git a/gtsam/geometry/Cal3.h b/gtsam/geometry/Cal3.h index b1a61c592..712414c82 100644 --- a/gtsam/geometry/Cal3.h +++ b/gtsam/geometry/Cal3.h @@ -103,7 +103,15 @@ class GTSAM_EXPORT Cal3 { /// @name Advanced Constructors /// @{ - /// load calibration from location (default name is calibration_info.txt) + /** + * Load calibration parameters from `calibration_info.txt` file located in + * `path` directory. + * + * The contents of calibration file should be the 5 parameters in order: + * `fx, fy, s, u0, v0` + * + * @param path path to directory containing `calibration_info.txt`. + */ Cal3(const std::string& path); /// @} From fc0fd1a12533b3913f2e69b78eb74920310e6962 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 2 Dec 2020 16:19:05 -0500 Subject: [PATCH 129/261] Override dim(), cleanup, and add unicode --- gtsam/geometry/Cal3.cpp | 9 +++++++- gtsam/geometry/Cal3.h | 16 +++++++-------- gtsam/geometry/Cal3Bundler.cpp | 22 ++++++++++++-------- gtsam/geometry/Cal3Bundler.h | 26 ++++++++---------------- gtsam/geometry/Cal3DS2.h | 4 ++-- gtsam/geometry/Cal3DS2_Base.cpp | 6 +++--- gtsam/geometry/Cal3DS2_Base.h | 15 +++++++++----- gtsam/geometry/Cal3Fisheye.h | 8 ++++---- gtsam/geometry/Cal3Unified.h | 12 +++++------ gtsam/geometry/Cal3_S2.cpp | 5 +++-- gtsam/geometry/Cal3_S2.h | 5 +---- gtsam/geometry/Cal3_S2Stereo.h | 6 +++--- gtsam/geometry/tests/testCal3Bundler.cpp | 23 ++++++++------------- 13 files changed, 78 insertions(+), 79 deletions(-) diff --git a/gtsam/geometry/Cal3.cpp b/gtsam/geometry/Cal3.cpp index 6210a6065..41de47f46 100644 --- a/gtsam/geometry/Cal3.cpp +++ b/gtsam/geometry/Cal3.cpp @@ -27,7 +27,6 @@ namespace gtsam { Cal3::Cal3(double fov, int w, int h) : s_(0), u0_((double)w / 2.0), v0_((double)h / 2.0) { double a = fov * M_PI / 360.0; // fov/2 in radians - // old formula: fx_ = (double) w * tan(a); fx_ = double(w) / (2.0 * tan(a)); fy_ = fx_; } @@ -63,6 +62,14 @@ bool Cal3::equals(const Cal3& K, double tol) const { std::fabs(v0_ - K.v0_) < tol); } +Matrix3 Cal3::inverse() const { + const double fxy = fx_ * fy_, sv0 = s_ * v0_, fyu0 = fy_ * u0_; + Matrix3 K_inverse; + K_inverse << 1.0 / fx_, -s_ / fxy, (sv0 - fyu0) / fxy, 0.0, 1.0 / fy_, + -v0_ / fy_, 0.0, 0.0, 1.0; + return K_inverse; +} + /* ************************************************************************* */ } // \ namespace gtsam diff --git a/gtsam/geometry/Cal3.h b/gtsam/geometry/Cal3.h index 712414c82..74c9868f3 100644 --- a/gtsam/geometry/Cal3.h +++ b/gtsam/geometry/Cal3.h @@ -161,7 +161,7 @@ class GTSAM_EXPORT Cal3 { } /// return calibration matrix K - Matrix3 K() const { + virtual Matrix3 K() const { Matrix3 K; K << fx_, s_, u0_, 0.0, fy_, v0_, 0.0, 0.0, 1.0; return K; @@ -173,13 +173,13 @@ class GTSAM_EXPORT Cal3 { #endif /// Return inverted calibration matrix inv(K) - Matrix3 inverse() const { - const double fxy = fx_ * fy_, sv0 = s_ * v0_, fyu0 = fy_ * u0_; - Matrix3 K_inverse; - K_inverse << 1.0 / fx_, -s_ / fxy, (sv0 - fyu0) / fxy, 0.0, 1.0 / fy_, - -v0_ / fy_, 0.0, 0.0, 1.0; - return K_inverse; - } + Matrix3 inverse() const; + + /// return DOF, dimensionality of tangent space + inline virtual size_t dim() const { return Dim(); } + + /// return DOF, dimensionality of tangent space + inline static size_t Dim() { return dimension; } /// @} /// @name Advanced Interface diff --git a/gtsam/geometry/Cal3Bundler.cpp b/gtsam/geometry/Cal3Bundler.cpp index af2f881d8..31beac73e 100644 --- a/gtsam/geometry/Cal3Bundler.cpp +++ b/gtsam/geometry/Cal3Bundler.cpp @@ -25,8 +25,9 @@ namespace gtsam { /* ************************************************************************* */ Matrix3 Cal3Bundler::K() const { + // This function is needed to ensure skew = 0; Matrix3 K; - K << f_, 0, u0_, 0, f_, v0_, 0, 0, 1; + K << fx_, 0, u0_, 0, fy_, v0_, 0, 0, 1.0; return K; } @@ -39,7 +40,7 @@ Vector4 Cal3Bundler::k() const { /* ************************************************************************* */ Vector3 Cal3Bundler::vector() const { - return Vector3(f_, k1_, k2_); + return Vector3(fx_, k1_, k2_); } /* ************************************************************************* */ @@ -51,12 +52,13 @@ std::ostream& operator<<(std::ostream& os, const Cal3Bundler& cal) { /* ************************************************************************* */ void Cal3Bundler::print(const std::string& s) const { - gtsam::print((Vector)(Vector(5) << f_, k1_, k2_, u0_, v0_).finished(), s + ".K"); + gtsam::print((Vector)(Vector(5) << fx_, k1_, k2_, u0_, v0_).finished(), s + ".K"); } /* ************************************************************************* */ bool Cal3Bundler::equals(const Cal3Bundler& K, double tol) const { - return (std::fabs(f_ - K.f_) < tol && std::fabs(k1_ - K.k1_) < tol && + const Cal3* base = dynamic_cast(&K); + return (Cal3::equals(*base, tol) && std::fabs(k1_ - K.k1_) < tol && std::fabs(k2_ - K.k2_) < tol && std::fabs(u0_ - K.u0_) < tol && std::fabs(v0_ - K.v0_) < tol); } @@ -64,14 +66,16 @@ bool Cal3Bundler::equals(const Cal3Bundler& K, double tol) const { /* ************************************************************************* */ Point2 Cal3Bundler::uncalibrate(const Point2& p, // OptionalJacobian<2, 3> Dcal, OptionalJacobian<2, 2> Dp) const { - // r = x^2 + y^2; - // g = (1 + k(1)*r + k(2)*r^2); + // r = x² + y²; + // g = (1 + k(1)*r + k(2)*r²); // pi(:,i) = g * pn(:,i) const double x = p.x(), y = p.y(); const double r = x * x + y * y; const double g = 1. + (k1_ + k2_ * r) * r; const double u = g * x, v = g * y; + const double f_ = fx_; + // Derivatives make use of intermediate variables above if (Dcal) { double rx = r * x, ry = r * y; @@ -92,9 +96,9 @@ Point2 Cal3Bundler::uncalibrate(const Point2& p, // Point2 Cal3Bundler::calibrate(const Point2& pi, OptionalJacobian<2, 3> Dcal, OptionalJacobian<2, 2> Dp) const { - // Copied from Cal3DS2 :-( - // but specialized with k1,k2 non-zero only and fx=fy and s=0 - double x = (pi.x() - u0_)/f_, y = (pi.y() - v0_)/f_; + // Copied from Cal3DS2 + // but specialized with k1, k2 non-zero only and fx=fy and s=0 + double x = (pi.x() - u0_) / fx_, y = (pi.y() - v0_) / fx_; const Point2 invKPi(x, y); // initialize by ignoring the distortion at all, might be problematic for pixels around boundary diff --git a/gtsam/geometry/Cal3Bundler.h b/gtsam/geometry/Cal3Bundler.h index 76703f96f..50b392096 100644 --- a/gtsam/geometry/Cal3Bundler.h +++ b/gtsam/geometry/Cal3Bundler.h @@ -14,6 +14,7 @@ * @brief Calibration used by Bundler * @date Sep 25, 2010 * @author Yong Dian Jian + * @author Varun Agrawal */ #pragma once @@ -31,11 +32,11 @@ namespace gtsam { class GTSAM_EXPORT Cal3Bundler : public Cal3 { private: - double f_ = 1.0f; ///< focal length double k1_ = 0.0f, k2_ = 0.0f; ///< radial distortion double tol_ = 1e-5; ///< tolerance value when calibrating - // NOTE: image center parameters (u0, v0) are not optimized + // NOTE: We use the base class fx to represent the common focal length. + // Also, image center parameters (u0, v0) are not optimized // but are treated as constants. public: @@ -59,7 +60,7 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { */ Cal3Bundler(double f, double k1, double k2, double u0 = 0, double v0 = 0, double tol = 1e-5) - : Cal3(f, f, 0, u0, v0), f_(f), k1_(k1), k2_(k2), tol_(tol) {} + : Cal3(f, f, 0, u0, v0), k1_(k1), k2_(k2), tol_(tol) {} virtual ~Cal3Bundler() {} @@ -81,16 +82,6 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { /// @name Standard Interface /// @{ - /// focal length x - inline double fx() const { - return f_; - } - - /// focal length y - inline double fy() const { - return f_; - } - /// distorsion parameter k1 inline double k1() const { return k1_; @@ -111,7 +102,7 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { return v0_; } - Matrix3 K() const; ///< Standard 3*3 calibration matrix + Matrix3 K() const override; ///< Standard 3*3 calibration matrix Vector4 k() const; ///< Radial distortion parameters (4 of them, 2 0) Vector3 vector() const; @@ -165,14 +156,14 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { /// @{ /// return DOF, dimensionality of tangent space - virtual size_t dim() const { return dimension; } + virtual size_t dim() const override { return Dim(); } /// return DOF, dimensionality of tangent space - static size_t Dim() { return dimension; } + inline static size_t Dim() { return dimension; } /// Update calibration with tangent space delta inline Cal3Bundler retract(const Vector& d) const { - return Cal3Bundler(f_ + d(0), k1_ + d(1), k2_ + d(2), u0_, v0_); + return Cal3Bundler(fx_ + d(0), k1_ + d(1), k2_ + d(2), u0_, v0_); } /// Calculate local coordinates to another calibration @@ -192,7 +183,6 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { void serialize(Archive & ar, const unsigned int /*version*/) { ar& boost::serialization::make_nvp( "Cal3Bundler", boost::serialization::base_object(*this)); - ar& BOOST_SERIALIZATION_NVP(f_); ar& BOOST_SERIALIZATION_NVP(k1_); ar& BOOST_SERIALIZATION_NVP(k2_); ar& BOOST_SERIALIZATION_NVP(tol_); diff --git a/gtsam/geometry/Cal3DS2.h b/gtsam/geometry/Cal3DS2.h index d0bed8652..ad4406b76 100644 --- a/gtsam/geometry/Cal3DS2.h +++ b/gtsam/geometry/Cal3DS2.h @@ -81,10 +81,10 @@ public: Vector localCoordinates(const Cal3DS2& T2) const ; /// Return dimensions of calibration manifold object - virtual size_t dim() const { return dimension ; } + virtual size_t dim() const override { return Dim(); } /// Return dimensions of calibration manifold object - static size_t Dim() { return dimension; } + inline static size_t Dim() { return dimension; } /// @} /// @name Clone diff --git a/gtsam/geometry/Cal3DS2_Base.cpp b/gtsam/geometry/Cal3DS2_Base.cpp index 2741d0736..71ce32ccb 100644 --- a/gtsam/geometry/Cal3DS2_Base.cpp +++ b/gtsam/geometry/Cal3DS2_Base.cpp @@ -93,9 +93,9 @@ static Matrix2 D2dintrinsic(double x, double y, double rr, /* ************************************************************************* */ Point2 Cal3DS2_Base::uncalibrate(const Point2& p, OptionalJacobian<2, 9> Dcal, OptionalJacobian<2, 2> Dp) const { - // rr = x^2 + y^2; - // g = (1 + k(1)*rr + k(2)*rr^2); - // dp = [2*k(3)*x*y + k(4)*(rr + 2*x^2); 2*k(4)*x*y + k(3)*(rr + 2*y^2)]; + // r² = x² + y²; + // g = (1 + k(1)*r² + k(2)*r⁴); + // dp = [2*k(3)*x*y + k(4)*(r² + 2*x²); 2*k(4)*x*y + k(3)*(r² + 2*y²)]; // pi(:,i) = g * pn(:,i) + dp; const double x = p.x(), y = p.y(), xy = x * y, xx = x * x, yy = y * y; const double rr = xx + yy; diff --git a/gtsam/geometry/Cal3DS2_Base.h b/gtsam/geometry/Cal3DS2_Base.h index 713fa4e0e..23e138838 100644 --- a/gtsam/geometry/Cal3DS2_Base.h +++ b/gtsam/geometry/Cal3DS2_Base.h @@ -33,11 +33,10 @@ namespace gtsam { * http://docs.opencv.org/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html * but using only k1,k2,p1, and p2 coefficients. * K = [ fx s u0 ; 0 fy v0 ; 0 0 1 ] - * rr = Pn.x^2 + Pn.y^2 - * \hat{Pn} = (1 + k1*rr + k2*rr^2 ) Pn + [ 2*p1 Pn.x Pn.y + p2 (rr + 2 Pn.x^2) - * ; - * p1 (rr + 2 Pn.y^2) + 2*p2 Pn.x Pn.y ] - * pi = K*Pn + * r² = P.x² + P.y² + * P̂ = (1 + k1*r² + k2*r⁴) P + [ (2*p1 P.x P.y) + p2 (r² + 2 Pn.x²) + * p1 (r² + 2 Pn.y²) + (2*p2 Pn.x Pn.y) ] + * pi = K*P̂ */ class GTSAM_EXPORT Cal3DS2_Base : public Cal3 { protected: @@ -132,6 +131,12 @@ class GTSAM_EXPORT Cal3DS2_Base : public Cal3 { /// Derivative of uncalibrate wrpt the calibration parameters Matrix29 D2d_calibration(const Point2& p) const; + /// return DOF, dimensionality of tangent space + virtual size_t dim() const override { return Dim(); } + + /// return DOF, dimensionality of tangent space + inline static size_t Dim() { return dimension; } + /// @} /// @name Clone /// @{ diff --git a/gtsam/geometry/Cal3Fisheye.h b/gtsam/geometry/Cal3Fisheye.h index 738b2275d..a394d2000 100644 --- a/gtsam/geometry/Cal3Fisheye.h +++ b/gtsam/geometry/Cal3Fisheye.h @@ -38,9 +38,9 @@ namespace gtsam { * Intrinsic coordinates: * [x_i;y_i] = [x/z; y/z] * Distorted coordinates: - * r^2 = (x_i)^2 + (y_i)^2 + * r² = (x_i)² + (y_i)² * th = atan(r) - * th_d = th(1 + k1*th^2 + k2*th^4 + k3*th^6 + k4*th^8) + * th_d = th(1 + k1*th² + k2*th⁴ + k3*th⁶ + k4*th⁸) * [x_d; y_d] = (th_d / r)*[x_i; y_i] * Pixel coordinates: * K = [fx s u0; 0 fy v0 ;0 0 1] @@ -152,10 +152,10 @@ class GTSAM_EXPORT Cal3Fisheye : public Cal3 { /// @{ /// Return dimensions of calibration manifold object - virtual size_t dim() const { return dimension; } + virtual size_t dim() const override { return Dim(); } /// Return dimensions of calibration manifold object - static size_t Dim() { return dimension; } + inline static size_t Dim() { return dimension; } /// Given delta vector, update calibration inline Cal3Fisheye retract(const Vector& d) const { diff --git a/gtsam/geometry/Cal3Unified.h b/gtsam/geometry/Cal3Unified.h index a2c5ebc5c..4c456ec24 100644 --- a/gtsam/geometry/Cal3Unified.h +++ b/gtsam/geometry/Cal3Unified.h @@ -34,10 +34,10 @@ namespace gtsam { * * Similar to Cal3DS2, does distortion but has additional mirror parameter xi * K = [ fx s u0 ; 0 fy v0 ; 0 0 1 ] - * Pn = [ P.x / (1 + xi * \sqrt{P.x^2 + P.y^2 + 1}), P.y / (1 + xi * \sqrt{P.x^2 + P.y^2 + 1})] - * rr = Pn.x^2 + Pn.y^2 - * \hat{pn} = (1 + k1*rr + k2*rr^2 ) pn + [ 2*k3 pn.x pn.y + k4 (rr + 2 Pn.x^2) ; - * k3 (rr + 2 Pn.y^2) + 2*k4 pn.x pn.y ] + * Pn = [ P.x / (1 + xi * \sqrt{P.x² + P.y² + 1}), P.y / (1 + xi * \sqrt{P.x² + P.y² + 1})] + * r² = Pn.x² + Pn.y² + * \hat{pn} = (1 + k1*r² + k2*r⁴ ) pn + [ 2*k3 pn.x pn.y + k4 (r² + 2 Pn.x²) ; + * k3 (rr + 2 Pn.y²) + 2*k4 pn.x pn.y ] * pi = K*pn */ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { @@ -127,10 +127,10 @@ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { Vector localCoordinates(const Cal3Unified& T2) const ; /// Return dimensions of calibration manifold object - virtual size_t dim() const { return dimension ; } + virtual size_t dim() const override { return Dim(); } /// Return dimensions of calibration manifold object - static size_t Dim() { return dimension; } + inline static size_t Dim() { return dimension; } /// @} diff --git a/gtsam/geometry/Cal3_S2.cpp b/gtsam/geometry/Cal3_S2.cpp index 98c7bea38..f97082ddf 100644 --- a/gtsam/geometry/Cal3_S2.cpp +++ b/gtsam/geometry/Cal3_S2.cpp @@ -55,8 +55,9 @@ Point2 Cal3_S2::calibrate(const Point2& p, OptionalJacobian<2, 5> Dcal, const double u = p.x(), v = p.y(); double delta_u = u - u0_, delta_v = v - v0_; double inv_fx = 1 / fx_, inv_fy = 1 / fy_; - double inv_fy_delta_v = inv_fy * delta_v, - inv_fx_s_inv_fy = inv_fx * s_ * inv_fy; + double inv_fy_delta_v = inv_fy * delta_v; + double inv_fx_s_inv_fy = inv_fx * s_ * inv_fy; + Point2 point(inv_fx * (delta_u - s_ * inv_fy_delta_v), inv_fy_delta_v); if (Dcal) *Dcal << -inv_fx * point.x(), inv_fx * s_ * inv_fy * inv_fy_delta_v, diff --git a/gtsam/geometry/Cal3_S2.h b/gtsam/geometry/Cal3_S2.h index 37edc46c4..93b98a7e1 100644 --- a/gtsam/geometry/Cal3_S2.h +++ b/gtsam/geometry/Cal3_S2.h @@ -115,10 +115,7 @@ class GTSAM_EXPORT Cal3_S2 : public Cal3 { /// @{ /// return DOF, dimensionality of tangent space - inline size_t dim() const { return dimension; } - - /// return DOF, dimensionality of tangent space - static size_t Dim() { return dimension; } + inline static size_t Dim() { return dimension; } /// Given 5-dim tangent vector, create new calibration inline Cal3_S2 retract(const Vector& d) const { diff --git a/gtsam/geometry/Cal3_S2Stereo.h b/gtsam/geometry/Cal3_S2Stereo.h index 94341ec37..ee316251a 100644 --- a/gtsam/geometry/Cal3_S2Stereo.h +++ b/gtsam/geometry/Cal3_S2Stereo.h @@ -79,7 +79,7 @@ namespace gtsam { const Cal3_S2& calibration() const { return *this; } /// return calibration matrix K, same for left and right - Matrix3 K() const { return K(); } + Matrix3 K() const override { return Cal3_S2::K(); } /// return baseline inline double baseline() const { return b_; } @@ -96,10 +96,10 @@ namespace gtsam { /// @{ /// return DOF, dimensionality of tangent space - inline size_t dim() const { return dimension; } + inline size_t dim() const override { return Dim(); } /// return DOF, dimensionality of tangent space - static size_t Dim() { return dimension; } + inline static size_t Dim() { return dimension; } /// Given 6-dim tangent vector, create new calibration inline Cal3_S2Stereo retract(const Vector& d) const { diff --git a/gtsam/geometry/tests/testCal3Bundler.cpp b/gtsam/geometry/tests/testCal3Bundler.cpp index 75aa50a25..eac8d1044 100644 --- a/gtsam/geometry/tests/testCal3Bundler.cpp +++ b/gtsam/geometry/tests/testCal3Bundler.cpp @@ -29,8 +29,7 @@ static Cal3Bundler K(500, 1e-3, 1e-3, 1000, 2000); static Point2 p(2,3); /* ************************************************************************* */ -TEST(Cal3Bundler, vector) -{ +TEST(Cal3Bundler, vector) { Cal3Bundler K; Vector expected(3); expected << 1, 0, 0; @@ -38,8 +37,7 @@ TEST(Cal3Bundler, vector) } /* ************************************************************************* */ -TEST(Cal3Bundler, uncalibrate) -{ +TEST(Cal3Bundler, uncalibrate) { Vector v = K.vector() ; double r = p.x()*p.x() + p.y()*p.y() ; double g = v[0]*(1+v[1]*r+v[2]*r*r) ; @@ -48,8 +46,7 @@ TEST(Cal3Bundler, uncalibrate) CHECK(assert_equal(expected,actual)); } -TEST(Cal3Bundler, calibrate ) -{ +TEST(Cal3Bundler, calibrate ) { Point2 pn(0.5, 0.5); Point2 pi = K.uncalibrate(pn); Point2 pn_hat = K.calibrate(pi); @@ -62,8 +59,7 @@ Point2 uncalibrate_(const Cal3Bundler& k, const Point2& pt) { return k.uncalibra Point2 calibrate_(const Cal3Bundler& k, const Point2& pt) { return k.calibrate(pt); } /* ************************************************************************* */ -TEST(Cal3Bundler, Duncalibrate) -{ +TEST(Cal3Bundler, Duncalibrate) { Matrix Dcal, Dp; Point2 actual = K.uncalibrate(p, Dcal, Dp); Point2 expected(2182, 3773); @@ -75,8 +71,7 @@ TEST(Cal3Bundler, Duncalibrate) } /* ************************************************************************* */ -TEST(Cal3Bundler, Dcalibrate) -{ +TEST(Cal3Bundler, Dcalibrate) { Matrix Dcal, Dp; Point2 pn(0.5, 0.5); Point2 pi = K.uncalibrate(pn); @@ -89,15 +84,15 @@ TEST(Cal3Bundler, Dcalibrate) } /* ************************************************************************* */ -TEST(Cal3Bundler, assert_equal) -{ +TEST(Cal3Bundler, assert_equal) { CHECK(assert_equal(K,K,1e-7)); } /* ************************************************************************* */ -TEST(Cal3Bundler, retract) -{ +TEST(Cal3Bundler, retract) { Cal3Bundler expected(510, 2e-3, 2e-3, 1000, 2000); + EXPECT_LONGS_EQUAL(3, expected.dim()); + Vector3 d; d << 10, 1e-3, 1e-3; Cal3Bundler actual = K.retract(d); From 0a55d31702e546ead6e82a4ea859992db0c7e9ce Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 2 Dec 2020 17:14:29 -0500 Subject: [PATCH 130/261] Added tests for checking calibration model dimensions --- gtsam/geometry/tests/testCal3Bundler.cpp | 3 ++ gtsam/geometry/tests/testCal3DFisheye.cpp | 6 +++- gtsam/geometry/tests/testCal3DS2.cpp | 9 +++-- gtsam/geometry/tests/testCal3Unified.cpp | 9 +++-- gtsam/geometry/tests/testCal3_S2.cpp | 42 +++++++++++----------- gtsam/geometry/tests/testCal3_S2Stereo.cpp | 3 ++ 6 files changed, 45 insertions(+), 27 deletions(-) diff --git a/gtsam/geometry/tests/testCal3Bundler.cpp b/gtsam/geometry/tests/testCal3Bundler.cpp index eac8d1044..8e6fe983f 100644 --- a/gtsam/geometry/tests/testCal3Bundler.cpp +++ b/gtsam/geometry/tests/testCal3Bundler.cpp @@ -93,6 +93,9 @@ TEST(Cal3Bundler, retract) { Cal3Bundler expected(510, 2e-3, 2e-3, 1000, 2000); EXPECT_LONGS_EQUAL(3, expected.dim()); + EXPECT_LONGS_EQUAL(Cal3Bundler::Dim(), 3); + EXPECT_LONGS_EQUAL(expected.dim(), 3); + Vector3 d; d << 10, 1e-3, 1e-3; Cal3Bundler actual = K.retract(d); diff --git a/gtsam/geometry/tests/testCal3DFisheye.cpp b/gtsam/geometry/tests/testCal3DFisheye.cpp index 85e661728..7a73e7490 100644 --- a/gtsam/geometry/tests/testCal3DFisheye.cpp +++ b/gtsam/geometry/tests/testCal3DFisheye.cpp @@ -42,7 +42,11 @@ TEST(Cal3Fisheye, retract) { Cal3Fisheye expected(K.fx() + 1, K.fy() + 2, K.skew() + 3, K.px() + 4, K.py() + 5, K.k1() + 6, K.k2() + 7, K.k3() + 8, K.k4() + 9); - Vector d(9); + + EXPECT_LONGS_EQUAL(Cal3Fisheye::Dim(), 9); + EXPECT_LONGS_EQUAL(expected.dim(), 9); + + Vector9 d; d << 1, 2, 3, 4, 5, 6, 7, 8, 9; Cal3Fisheye actual = K.retract(d); CHECK(assert_equal(expected, actual, 1e-7)); diff --git a/gtsam/geometry/tests/testCal3DS2.cpp b/gtsam/geometry/tests/testCal3DS2.cpp index b382e85f3..e4dc3e806 100644 --- a/gtsam/geometry/tests/testCal3DS2.cpp +++ b/gtsam/geometry/tests/testCal3DS2.cpp @@ -96,11 +96,14 @@ TEST(Cal3DS2, Dcalibrate) TEST(Cal3DS2, assert_equal) { CHECK(assert_equal(K, K, 1e-5)); } /* ************************************************************************* */ -TEST(Cal3DS2, retract) -{ +TEST(Cal3DS2, retract) { Cal3DS2 expected(500 + 1, 100 + 2, 0.1 + 3, 320 + 4, 240 + 5, 1e-3 + 6, 2.0 * 1e-3 + 7, 3.0 * 1e-3 + 8, 4.0 * 1e-3 + 9); - Vector d(9); + + EXPECT_LONGS_EQUAL(Cal3DS2::Dim(), 9); + EXPECT_LONGS_EQUAL(expected.dim(), 9); + + Vector9 d; d << 1,2,3,4,5,6,7,8,9; Cal3DS2 actual = K.retract(d); CHECK(assert_equal(expected,actual,1e-7)); diff --git a/gtsam/geometry/tests/testCal3Unified.cpp b/gtsam/geometry/tests/testCal3Unified.cpp index 41a1d3ad9..ff759d1cd 100644 --- a/gtsam/geometry/tests/testCal3Unified.cpp +++ b/gtsam/geometry/tests/testCal3Unified.cpp @@ -106,11 +106,14 @@ TEST(Cal3Unified, assert_equal) } /* ************************************************************************* */ -TEST(Cal3Unified, retract) -{ +TEST(Cal3Unified, retract) { Cal3Unified expected(100 + 2, 105 + 3, 0.0 + 4, 320 + 5, 240 + 6, 1e-3 + 7, 2.0*1e-3 + 8, 3.0*1e-3 + 9, 4.0*1e-3 + 10, 0.1 + 1); - Vector d(10); + + EXPECT_LONGS_EQUAL(Cal3Unified::Dim(), 10); + EXPECT_LONGS_EQUAL(expected.dim(), 10); + + Vector10 d; d << 2, 3, 4, 5, 6, 7, 8, 9, 10, 1; Cal3Unified actual = K.retract(d); CHECK(assert_equal(expected,actual,1e-9)); diff --git a/gtsam/geometry/tests/testCal3_S2.cpp b/gtsam/geometry/tests/testCal3_S2.cpp index 3317addff..9b7941c91 100644 --- a/gtsam/geometry/tests/testCal3_S2.cpp +++ b/gtsam/geometry/tests/testCal3_S2.cpp @@ -31,8 +31,7 @@ static Point2 p_uv(1320.3, 1740); static Point2 p_xy(2, 3); /* ************************************************************************* */ -TEST(Cal3_S2, easy_constructor) -{ +TEST(Cal3_S2, Constructor) { Cal3_S2 expected(554.256, 554.256, 0, 640 / 2, 480 / 2); double fov = 60; // degrees @@ -43,8 +42,7 @@ TEST(Cal3_S2, easy_constructor) } /* ************************************************************************* */ -TEST(Cal3_S2, calibrate) -{ +TEST(Cal3_S2, Calibrate) { Point2 intrinsic(2,3); Point2 expectedimage(1320.3, 1740); Point2 imagecoordinates = K.uncalibrate(intrinsic); @@ -53,33 +51,36 @@ TEST(Cal3_S2, calibrate) } /* ************************************************************************* */ -TEST(Cal3_S2, calibrate_homogeneous) { +TEST(Cal3_S2, CalibrateHomogeneous) { Vector3 intrinsic(2, 3, 1); Vector3 image(1320.3, 1740, 1); CHECK(assert_equal((Vector)intrinsic,(Vector)K.calibrate(image))); } /* ************************************************************************* */ -Point2 uncalibrate_(const Cal3_S2& k, const Point2& pt) { return k.uncalibrate(pt); } -TEST(Cal3_S2, Duncalibrate1) -{ +Point2 uncalibrate_(const Cal3_S2& k, const Point2& pt) { + return k.uncalibrate(pt); +} + +TEST(Cal3_S2, Duncalibrate1) { Matrix25 computed; K.uncalibrate(p, computed, boost::none); Matrix numerical = numericalDerivative21(uncalibrate_, K, p); CHECK(assert_equal(numerical,computed,1e-8)); } /* ************************************************************************* */ -TEST(Cal3_S2, Duncalibrate2) -{ +TEST(Cal3_S2, Duncalibrate2) { Matrix computed; K.uncalibrate(p, boost::none, computed); Matrix numerical = numericalDerivative22(uncalibrate_, K, p); CHECK(assert_equal(numerical,computed,1e-9)); } -Point2 calibrate_(const Cal3_S2& k, const Point2& pt) {return k.calibrate(pt); } +Point2 calibrate_(const Cal3_S2& k, const Point2& pt) { + return k.calibrate(pt); +} + /* ************************************************************************* */ -TEST(Cal3_S2, Dcalibrate1) -{ +TEST(Cal3_S2, Dcalibrate1) { Matrix computed; Point2 expected = K.calibrate(p_uv, computed, boost::none); Matrix numerical = numericalDerivative21(calibrate_, K, p_uv); @@ -88,8 +89,7 @@ TEST(Cal3_S2, Dcalibrate1) } /* ************************************************************************* */ -TEST(Cal3_S2, Dcalibrate2) -{ +TEST(Cal3_S2, Dcalibrate2) { Matrix computed; Point2 expected = K.calibrate(p_uv, boost::none, computed); Matrix numerical = numericalDerivative22(calibrate_, K, p_uv); @@ -98,8 +98,7 @@ TEST(Cal3_S2, Dcalibrate2) } /* ************************************************************************* */ -TEST(Cal3_S2, assert_equal) -{ +TEST(Cal3_S2, Equal) { CHECK(assert_equal(K,K,1e-9)); Cal3_S2 K1(500, 500, 0.1, 640 / 2, 480 / 2); @@ -107,10 +106,13 @@ TEST(Cal3_S2, assert_equal) } /* ************************************************************************* */ -TEST(Cal3_S2, retract) -{ +TEST(Cal3_S2, Retract) { Cal3_S2 expected(500+1, 500+2, 0.1+3, 640 / 2+4, 480 / 2+5); - Vector d(5); + + EXPECT_LONGS_EQUAL(Cal3_S2::Dim(), 5); + EXPECT_LONGS_EQUAL(expected.dim(), 5); + + Vector5 d; d << 1,2,3,4,5; Cal3_S2 actual = K.retract(d); CHECK(assert_equal(expected,actual,1e-7)); diff --git a/gtsam/geometry/tests/testCal3_S2Stereo.cpp b/gtsam/geometry/tests/testCal3_S2Stereo.cpp index 9c93b7496..f823a8b97 100644 --- a/gtsam/geometry/tests/testCal3_S2Stereo.cpp +++ b/gtsam/geometry/tests/testCal3_S2Stereo.cpp @@ -111,6 +111,9 @@ TEST(Cal3_S2Stereo, assert_equal) { TEST(Cal3_S2Stereo, retract) { Cal3_S2Stereo expected(500 + 1, 500 + 2, 0.1 + 3, 640 / 2 + 4, 480 / 2 + 5, 7); + EXPECT_LONGS_EQUAL(Cal3_S2Stereo::Dim(), 6); + EXPECT_LONGS_EQUAL(expected.dim(), 6); + Vector6 d; d << 1, 2, 3, 4, 5, 6; Cal3_S2Stereo actual = K.retract(d); From 70bab8e00c0e310c9bd2c9fa1486e6723861f093 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 2 Dec 2020 17:15:10 -0500 Subject: [PATCH 131/261] Consistent and better formatting --- gtsam/geometry/Cal3Bundler.cpp | 27 ++-- gtsam/geometry/Cal3Bundler.h | 47 ++---- gtsam/geometry/Cal3DS2.cpp | 11 +- gtsam/geometry/Cal3DS2.h | 33 ++-- gtsam/geometry/Cal3DS2_Base.cpp | 29 ++-- gtsam/geometry/Cal3Unified.h | 41 +++-- gtsam/geometry/Cal3_S2Stereo.cpp | 3 +- gtsam/geometry/Cal3_S2Stereo.h | 179 ++++++++++----------- gtsam/geometry/tests/testCal3Bundler.cpp | 47 +++--- gtsam/geometry/tests/testCal3DFisheye.cpp | 7 +- gtsam/geometry/tests/testCal3DS2.cpp | 73 ++++----- gtsam/geometry/tests/testCal3Unified.cpp | 67 ++++---- gtsam/geometry/tests/testCal3_S2.cpp | 61 +++---- gtsam/geometry/tests/testCal3_S2Stereo.cpp | 52 +----- 14 files changed, 298 insertions(+), 379 deletions(-) diff --git a/gtsam/geometry/Cal3Bundler.cpp b/gtsam/geometry/Cal3Bundler.cpp index 31beac73e..e03562452 100644 --- a/gtsam/geometry/Cal3Bundler.cpp +++ b/gtsam/geometry/Cal3Bundler.cpp @@ -15,11 +15,11 @@ * @author ydjian */ -#include #include +#include +#include #include #include -#include namespace gtsam { @@ -39,9 +39,7 @@ Vector4 Cal3Bundler::k() const { } /* ************************************************************************* */ -Vector3 Cal3Bundler::vector() const { - return Vector3(fx_, k1_, k2_); -} +Vector3 Cal3Bundler::vector() const { return Vector3(fx_, k1_, k2_); } /* ************************************************************************* */ std::ostream& operator<<(std::ostream& os, const Cal3Bundler& cal) { @@ -52,7 +50,8 @@ std::ostream& operator<<(std::ostream& os, const Cal3Bundler& cal) { /* ************************************************************************* */ void Cal3Bundler::print(const std::string& s) const { - gtsam::print((Vector)(Vector(5) << fx_, k1_, k2_, u0_, v0_).finished(), s + ".K"); + gtsam::print((Vector)(Vector(5) << fx_, k1_, k2_, u0_, v0_).finished(), + s + ".K"); } /* ************************************************************************* */ @@ -64,8 +63,8 @@ bool Cal3Bundler::equals(const Cal3Bundler& K, double tol) const { } /* ************************************************************************* */ -Point2 Cal3Bundler::uncalibrate(const Point2& p, // - OptionalJacobian<2, 3> Dcal, OptionalJacobian<2, 2> Dp) const { +Point2 Cal3Bundler::uncalibrate(const Point2& p, OptionalJacobian<2, 3> Dcal, + OptionalJacobian<2, 2> Dp) const { // r = x² + y²; // g = (1 + k(1)*r + k(2)*r²); // pi(:,i) = g * pn(:,i) @@ -93,23 +92,22 @@ Point2 Cal3Bundler::uncalibrate(const Point2& p, // } /* ************************************************************************* */ -Point2 Cal3Bundler::calibrate(const Point2& pi, - OptionalJacobian<2, 3> Dcal, +Point2 Cal3Bundler::calibrate(const Point2& pi, OptionalJacobian<2, 3> Dcal, OptionalJacobian<2, 2> Dp) const { // Copied from Cal3DS2 // but specialized with k1, k2 non-zero only and fx=fy and s=0 double x = (pi.x() - u0_) / fx_, y = (pi.y() - v0_) / fx_; const Point2 invKPi(x, y); - // initialize by ignoring the distortion at all, might be problematic for pixels around boundary + // initialize by ignoring the distortion at all, might be problematic for + // pixels around boundary Point2 pn(x, y); // iterate until the uncalibrate is close to the actual pixel coordinate const int maxIterations = 10; int iteration; for (iteration = 0; iteration < maxIterations; ++iteration) { - if (distance2(uncalibrate(pn), pi) <= tol_) - break; + if (distance2(uncalibrate(pn), pi) <= tol_) break; const double px = pn.x(), py = pn.y(), xx = px * px, yy = py * py; const double rr = xx + yy; const double g = (1 + k1_ * rr + k2_ * rr * rr); @@ -118,7 +116,8 @@ Point2 Cal3Bundler::calibrate(const Point2& pi, if (iteration >= maxIterations) throw std::runtime_error( - "Cal3Bundler::calibrate fails to converge. need a better initialization"); + "Cal3Bundler::calibrate fails to converge. need a better " + "initialization"); calibrateJacobians(*this, pn, Dcal, Dp); diff --git a/gtsam/geometry/Cal3Bundler.h b/gtsam/geometry/Cal3Bundler.h index 50b392096..0016ded2d 100644 --- a/gtsam/geometry/Cal3Bundler.h +++ b/gtsam/geometry/Cal3Bundler.h @@ -30,7 +30,6 @@ namespace gtsam { * \nosubgrouping */ class GTSAM_EXPORT Cal3Bundler : public Cal3 { - private: double k1_ = 0.0f, k2_ = 0.0f; ///< radial distortion double tol_ = 1e-5; ///< tolerance value when calibrating @@ -40,7 +39,6 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { // but are treated as constants. public: - enum { dimension = 3 }; /// @name Standard Constructors @@ -83,40 +81,28 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { /// @{ /// distorsion parameter k1 - inline double k1() const { - return k1_; - } + inline double k1() const { return k1_; } /// distorsion parameter k2 - inline double k2() const { - return k2_; - } + inline double k2() const { return k2_; } /// image center in x - inline double px() const { - return u0_; - } + inline double px() const { return u0_; } /// image center in y - inline double py() const { - return v0_; - } + inline double py() const { return v0_; } - Matrix3 K() const override; ///< Standard 3*3 calibration matrix - Vector4 k() const; ///< Radial distortion parameters (4 of them, 2 0) + Matrix3 K() const override; ///< Standard 3*3 calibration matrix + Vector4 k() const; ///< Radial distortion parameters (4 of them, 2 0) Vector3 vector() const; #ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V41 /// get parameter u0 - inline double u0() const { - return u0_; - } + inline double u0() const { return u0_; } /// get parameter v0 - inline double v0() const { - return v0_; - } + inline double v0() const { return v0_; } #endif /** @@ -128,7 +114,7 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { * @return point in image coordinates */ Point2 uncalibrate(const Point2& p, OptionalJacobian<2, 3> Dcal = boost::none, - OptionalJacobian<2, 2> Dp = boost::none) const; + OptionalJacobian<2, 2> Dp = boost::none) const; /** * Convert a pixel coordinate to ideal coordinate xy @@ -138,8 +124,7 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates * @return point in intrinsic coordinates */ - Point2 calibrate(const Point2& pi, - OptionalJacobian<2, 3> Dcal = boost::none, + Point2 calibrate(const Point2& pi, OptionalJacobian<2, 3> Dcal = boost::none, OptionalJacobian<2, 2> Dp = boost::none) const; /// @deprecated might be removed in next release, use uncalibrate @@ -172,15 +157,14 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { } private: - /// @} /// @name Advanced Interface /// @{ /** Serialization function */ friend class boost::serialization::access; - template - void serialize(Archive & ar, const unsigned int /*version*/) { + template + void serialize(Archive& ar, const unsigned int /*version*/) { ar& boost::serialization::make_nvp( "Cal3Bundler", boost::serialization::base_object(*this)); ar& BOOST_SERIALIZATION_NVP(k1_); @@ -189,13 +173,12 @@ class GTSAM_EXPORT Cal3Bundler : public Cal3 { } /// @} - }; -template<> +template <> struct traits : public internal::Manifold {}; -template<> +template <> struct traits : public internal::Manifold {}; -} // namespace gtsam +} // namespace gtsam diff --git a/gtsam/geometry/Cal3DS2.cpp b/gtsam/geometry/Cal3DS2.cpp index 71aa2738d..f93386ea7 100644 --- a/gtsam/geometry/Cal3DS2.cpp +++ b/gtsam/geometry/Cal3DS2.cpp @@ -16,11 +16,11 @@ * @author Varun Agrawal */ -#include #include +#include +#include #include #include -#include namespace gtsam { @@ -31,9 +31,7 @@ std::ostream& operator<<(std::ostream& os, const Cal3DS2& cal) { } /* ************************************************************************* */ -void Cal3DS2::print(const std::string& s_) const { - Base::print(s_); -} +void Cal3DS2::print(const std::string& s_) const { Base::print(s_); } /* ************************************************************************* */ bool Cal3DS2::equals(const Cal3DS2& K, double tol) const { @@ -50,8 +48,5 @@ Cal3DS2 Cal3DS2::retract(const Vector& d) const { Vector Cal3DS2::localCoordinates(const Cal3DS2& T2) const { return T2.vector() - vector(); } - } /* ************************************************************************* */ - - diff --git a/gtsam/geometry/Cal3DS2.h b/gtsam/geometry/Cal3DS2.h index ad4406b76..58d35c2ec 100644 --- a/gtsam/geometry/Cal3DS2.h +++ b/gtsam/geometry/Cal3DS2.h @@ -11,7 +11,8 @@ /** * @file Cal3DS2.h - * @brief Calibration of a camera with radial distortion, calculations in base class Cal3DS2_Base + * @brief Calibration of a camera with radial distortion, calculations in base + * class Cal3DS2_Base * @date Feb 28, 2010 * @author ydjian * @autho Varun Agrawal @@ -31,11 +32,9 @@ namespace gtsam { * \nosubgrouping */ class GTSAM_EXPORT Cal3DS2 : public Cal3DS2_Base { - using Base = Cal3DS2_Base; -public: - + public: enum { dimension = 9 }; /// @name Standard Constructors @@ -54,7 +53,7 @@ public: /// @name Advanced Constructors /// @{ - Cal3DS2(const Vector9 &v) : Base(v) {} + Cal3DS2(const Vector9& v) : Base(v) {} /// @} /// @name Testable @@ -75,10 +74,10 @@ public: /// @{ /// Given delta vector, update calibration - Cal3DS2 retract(const Vector& d) const ; + Cal3DS2 retract(const Vector& d) const; /// Given a different calibration, calculate update to obtain it - Vector localCoordinates(const Cal3DS2& T2) const ; + Vector localCoordinates(const Cal3DS2& T2) const; /// Return dimensions of calibration manifold object virtual size_t dim() const override { return Dim(); } @@ -97,30 +96,24 @@ public: /// @} - -private: - + private: /// @name Advanced Interface /// @{ /** Serialization function */ friend class boost::serialization::access; - template - void serialize(Archive & ar, const unsigned int /*version*/) - { - ar & boost::serialization::make_nvp("Cal3DS2", - boost::serialization::base_object(*this)); + template + void serialize(Archive& ar, const unsigned int /*version*/) { + ar& boost::serialization::make_nvp( + "Cal3DS2", boost::serialization::base_object(*this)); } /// @} - }; -template<> +template <> struct traits : public internal::Manifold {}; -template<> +template <> struct traits : public internal::Manifold {}; - } - diff --git a/gtsam/geometry/Cal3DS2_Base.cpp b/gtsam/geometry/Cal3DS2_Base.cpp index 71ce32ccb..a3f7026b9 100644 --- a/gtsam/geometry/Cal3DS2_Base.cpp +++ b/gtsam/geometry/Cal3DS2_Base.cpp @@ -16,11 +16,11 @@ * @author Varun Agrawal */ -#include #include +#include +#include #include #include -#include namespace gtsam { @@ -54,23 +54,23 @@ bool Cal3DS2_Base::equals(const Cal3DS2_Base& K, double tol) const { } /* ************************************************************************* */ -static Matrix29 D2dcalibration(double x, double y, double xx, - double yy, double xy, double rr, double r4, double pnx, double pny, - const Matrix2& DK) { +static Matrix29 D2dcalibration(double x, double y, double xx, double yy, + double xy, double rr, double r4, double pnx, + double pny, const Matrix2& DK) { Matrix25 DR1; DR1 << pnx, 0.0, pny, 1.0, 0.0, 0.0, pny, 0.0, 0.0, 1.0; Matrix24 DR2; - DR2 << x * rr, x * r4, 2 * xy, rr + 2 * xx, // - y * rr, y * r4, rr + 2 * yy, 2 * xy; + DR2 << x * rr, x * r4, 2 * xy, rr + 2 * xx, // + y * rr, y * r4, rr + 2 * yy, 2 * xy; Matrix29 D; D << DR1, DK * DR2; return D; } /* ************************************************************************* */ -static Matrix2 D2dintrinsic(double x, double y, double rr, - double g, double k1, double k2, double p1, double p2, - const Matrix2& DK) { +static Matrix2 D2dintrinsic(double x, double y, double rr, double g, double k1, + double k2, double p1, double p2, + const Matrix2& DK) { const double drdx = 2. * x; const double drdy = 2. * y; const double dgdx = k1 * drdx + k2 * 2. * rr * drdx; @@ -84,8 +84,8 @@ static Matrix2 D2dintrinsic(double x, double y, double rr, const double dDydy = 2. * p2 * x + p1 * (drdy + 4. * y); Matrix2 DR; - DR << g + x * dgdx + dDxdx, x * dgdy + dDxdy, // - y * dgdx + dDydx, g + y * dgdy + dDydy; + DR << g + x * dgdx + dDxdx, x * dgdy + dDxdy, // + y * dgdx + dDydx, g + y * dgdy + dDydy; return DK * DR; } @@ -100,7 +100,7 @@ Point2 Cal3DS2_Base::uncalibrate(const Point2& p, OptionalJacobian<2, 9> Dcal, const double x = p.x(), y = p.y(), xy = x * y, xx = x * x, yy = y * y; const double rr = xx + yy; const double r4 = rr * rr; - const double g = 1. + k1_ * rr + k2_ * r4; // scaling factor + const double g = 1. + k1_ * rr + k2_ * r4; // scaling factor // tangential component const double dx = 2. * p1_ * xy + p2_ * (rr + 2. * xx); @@ -190,8 +190,5 @@ Matrix29 Cal3DS2_Base::D2d_calibration(const Point2& p) const { DK << fx_, s_, 0.0, fy_; return D2dcalibration(x, y, xx, yy, xy, rr, r4, pnx, pny, DK); } - } /* ************************************************************************* */ - - diff --git a/gtsam/geometry/Cal3Unified.h b/gtsam/geometry/Cal3Unified.h index 4c456ec24..ee388c8c1 100644 --- a/gtsam/geometry/Cal3Unified.h +++ b/gtsam/geometry/Cal3Unified.h @@ -28,20 +28,21 @@ namespace gtsam { /** - * @brief Calibration of a omni-directional camera with mirror + lens radial distortion + * @brief Calibration of a omni-directional camera with mirror + lens radial + * distortion * @addtogroup geometry * \nosubgrouping * * Similar to Cal3DS2, does distortion but has additional mirror parameter xi * K = [ fx s u0 ; 0 fy v0 ; 0 0 1 ] - * Pn = [ P.x / (1 + xi * \sqrt{P.x² + P.y² + 1}), P.y / (1 + xi * \sqrt{P.x² + P.y² + 1})] + * Pn = [ P.x / (1 + xi * \sqrt{P.x² + P.y² + 1}), P.y / (1 + xi * \sqrt{P.x² + + * P.y² + 1})] * r² = Pn.x² + Pn.y² * \hat{pn} = (1 + k1*r² + k2*r⁴ ) pn + [ 2*k3 pn.x pn.y + k4 (r² + 2 Pn.x²) ; * k3 (rr + 2 Pn.y²) + 2*k4 pn.x pn.y ] * pi = K*pn */ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { - using This = Cal3Unified; using Base = Cal3DS2_Base; @@ -49,7 +50,6 @@ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { double xi_ = 0.0f; ///< mirror parameter public: - enum { dimension = 10 }; /// @name Standard Constructors @@ -90,10 +90,10 @@ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { /// @{ /// mirror parameter - inline double xi() const { return xi_;} + inline double xi() const { return xi_; } /// Return all parameters as a vector - Vector10 vector() const ; + Vector10 vector() const; /** * convert intrinsic coordinates xy to image coordinates uv @@ -103,8 +103,8 @@ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { * @return point in image coordinates */ Point2 uncalibrate(const Point2& p, - OptionalJacobian<2,10> Dcal = boost::none, - OptionalJacobian<2,2> Dp = boost::none) const ; + OptionalJacobian<2, 10> Dcal = boost::none, + OptionalJacobian<2, 2> Dp = boost::none) const; /// Conver a pixel coordinate to ideal coordinate Point2 calibrate(const Point2& p, OptionalJacobian<2, 10> Dcal = boost::none, @@ -121,10 +121,10 @@ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { /// @{ /// Given delta vector, update calibration - Cal3Unified retract(const Vector& d) const ; + Cal3Unified retract(const Vector& d) const; /// Given a different calibration, calculate update to obtain it - Vector localCoordinates(const Cal3Unified& T2) const ; + Vector localCoordinates(const Cal3Unified& T2) const; /// Return dimensions of calibration manifold object virtual size_t dim() const override { return Dim(); } @@ -134,25 +134,20 @@ class GTSAM_EXPORT Cal3Unified : public Cal3DS2_Base { /// @} -private: - + private: /** Serialization function */ friend class boost::serialization::access; - template - void serialize(Archive & ar, const unsigned int /*version*/) - { - ar & boost::serialization::make_nvp("Cal3Unified", - boost::serialization::base_object(*this)); - ar & BOOST_SERIALIZATION_NVP(xi_); + template + void serialize(Archive& ar, const unsigned int /*version*/) { + ar& boost::serialization::make_nvp( + "Cal3Unified", boost::serialization::base_object(*this)); + ar& BOOST_SERIALIZATION_NVP(xi_); } - }; -template<> +template <> struct traits : public internal::Manifold {}; -template<> +template <> struct traits : public internal::Manifold {}; - } - diff --git a/gtsam/geometry/Cal3_S2Stereo.cpp b/gtsam/geometry/Cal3_S2Stereo.cpp index 8bd733e95..56ceaf516 100644 --- a/gtsam/geometry/Cal3_S2Stereo.cpp +++ b/gtsam/geometry/Cal3_S2Stereo.cpp @@ -38,7 +38,8 @@ void Cal3_S2Stereo::print(const std::string& s) const { /* ************************************************************************* */ bool Cal3_S2Stereo::equals(const Cal3_S2Stereo& other, double tol) const { const Cal3_S2* base = dynamic_cast(&other); - return (Cal3_S2::equals(*base, tol) && std::fabs(b_ - other.baseline()) < tol); + return (Cal3_S2::equals(*base, tol) && + std::fabs(b_ - other.baseline()) < tol); } /* ************************************************************************* */ diff --git a/gtsam/geometry/Cal3_S2Stereo.h b/gtsam/geometry/Cal3_S2Stereo.h index ee316251a..d7bf34e61 100644 --- a/gtsam/geometry/Cal3_S2Stereo.h +++ b/gtsam/geometry/Cal3_S2Stereo.h @@ -22,121 +22,116 @@ namespace gtsam { - /** - * @brief The most common 5DOF 3D->2D calibration, stereo version - * @addtogroup geometry - * \nosubgrouping - */ - class GTSAM_EXPORT Cal3_S2Stereo : public Cal3_S2 { - private: - double b_ = 1.0f; ///< Stereo baseline. +/** + * @brief The most common 5DOF 3D->2D calibration, stereo version + * @addtogroup geometry + * \nosubgrouping + */ +class GTSAM_EXPORT Cal3_S2Stereo : public Cal3_S2 { + private: + double b_ = 1.0f; ///< Stereo baseline. - public: + public: + enum { dimension = 6 }; - enum { dimension = 6 }; + ///< shared pointer to stereo calibration object + using shared_ptr = boost::shared_ptr; - ///< shared pointer to stereo calibration object - using shared_ptr = boost::shared_ptr; + /// @name Standard Constructors + /// @ - /// @name Standard Constructors - /// @ + /// default calibration leaves coordinates unchanged + Cal3_S2Stereo() = default; - /// default calibration leaves coordinates unchanged - Cal3_S2Stereo() = default; + /// constructor from doubles + Cal3_S2Stereo(double fx, double fy, double s, double u0, double v0, double b) + : Cal3_S2(fx, fy, s, u0, v0), b_(b) {} - /// constructor from doubles - Cal3_S2Stereo(double fx, double fy, double s, double u0, double v0, - double b) - : Cal3_S2(fx, fy, s, u0, v0), b_(b) {} + /// constructor from vector + Cal3_S2Stereo(const Vector6& d) + : Cal3_S2(d(0), d(1), d(2), d(3), d(4)), b_(d(5)) {} - /// constructor from vector - Cal3_S2Stereo(const Vector6& d) - : Cal3_S2(d(0), d(1), d(2), d(3), d(4)), b_(d(5)) {} + /// easy constructor; field-of-view in degrees, assumes zero skew + Cal3_S2Stereo(double fov, int w, int h, double b) + : Cal3_S2(fov, w, h), b_(b) {} - /// easy constructor; field-of-view in degrees, assumes zero skew - Cal3_S2Stereo(double fov, int w, int h, double b) - : Cal3_S2(fov, w, h), b_(b) {} + /// @} + /// @name Testable + /// @{ - /// @} - /// @name Testable - /// @{ + /// Output stream operator + GTSAM_EXPORT friend std::ostream& operator<<(std::ostream& os, + const Cal3_S2Stereo& cal); - /// Output stream operator - GTSAM_EXPORT friend std::ostream& operator<<(std::ostream& os, - const Cal3_S2Stereo& cal); + /// print with optional string + void print(const std::string& s = "") const override; - /// print with optional string - void print(const std::string& s = "") const override; + /// Check if equal up to specified tolerance + bool equals(const Cal3_S2Stereo& other, double tol = 10e-9) const; - /// Check if equal up to specified tolerance - bool equals(const Cal3_S2Stereo& other, double tol = 10e-9) const; + /// @} + /// @name Standard Interface + /// @{ - /// @} - /// @name Standard Interface - /// @{ + /// return calibration, same for left and right + const Cal3_S2& calibration() const { return *this; } - /// return calibration, same for left and right - const Cal3_S2& calibration() const { return *this; } + /// return calibration matrix K, same for left and right + Matrix3 K() const override { return Cal3_S2::K(); } - /// return calibration matrix K, same for left and right - Matrix3 K() const override { return Cal3_S2::K(); } + /// return baseline + inline double baseline() const { return b_; } - /// return baseline - inline double baseline() const { return b_; } + /// vectorized form (column-wise) + Vector6 vector() const { + Vector6 v; + v << Cal3_S2::vector(), b_; + return v; + } - /// vectorized form (column-wise) - Vector6 vector() const { - Vector6 v; - v << Cal3_S2::vector(), b_; - return v; - } + /// @} + /// @name Manifold + /// @{ - /// @} - /// @name Manifold - /// @{ + /// return DOF, dimensionality of tangent space + inline size_t dim() const override { return Dim(); } - /// return DOF, dimensionality of tangent space - inline size_t dim() const override { return Dim(); } + /// return DOF, dimensionality of tangent space + inline static size_t Dim() { return dimension; } - /// return DOF, dimensionality of tangent space - inline static size_t Dim() { return dimension; } + /// Given 6-dim tangent vector, create new calibration + inline Cal3_S2Stereo retract(const Vector& d) const { + return Cal3_S2Stereo(fx() + d(0), fy() + d(1), skew() + d(2), px() + d(3), + py() + d(4), b_ + d(5)); + } - /// Given 6-dim tangent vector, create new calibration - inline Cal3_S2Stereo retract(const Vector& d) const { - return Cal3_S2Stereo(fx() + d(0), fy() + d(1), skew() + d(2), px() + d(3), - py() + d(4), b_ + d(5)); - } + /// Unretraction for the calibration + Vector6 localCoordinates(const Cal3_S2Stereo& T2) const { + return T2.vector() - vector(); + } - /// Unretraction for the calibration - Vector6 localCoordinates(const Cal3_S2Stereo& T2) const { - return T2.vector() - vector(); - } + /// @} + /// @name Advanced Interface + /// @{ - /// @} - /// @name Advanced Interface - /// @{ + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(Archive& ar, const unsigned int /*version*/) { + ar& boost::serialization::make_nvp( + "Cal3_S2", boost::serialization::base_object(*this)); + ar& BOOST_SERIALIZATION_NVP(b_); + } + /// @} +}; - private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(Archive & ar, const unsigned int /*version*/) - { - ar& boost::serialization::make_nvp( - "Cal3_S2", boost::serialization::base_object(*this)); - ar& BOOST_SERIALIZATION_NVP(b_); - } - /// @} +// Define GTSAM traits +template <> +struct traits : public internal::Manifold {}; - }; +template <> +struct traits : public internal::Manifold { +}; - // Define GTSAM traits - template<> - struct traits : public internal::Manifold { - }; - - template<> - struct traits : public internal::Manifold { - }; - -} // \ namespace gtsam +} // \ namespace gtsam diff --git a/gtsam/geometry/tests/testCal3Bundler.cpp b/gtsam/geometry/tests/testCal3Bundler.cpp index 8e6fe983f..b821d295b 100644 --- a/gtsam/geometry/tests/testCal3Bundler.cpp +++ b/gtsam/geometry/tests/testCal3Bundler.cpp @@ -26,27 +26,27 @@ GTSAM_CONCEPT_TESTABLE_INST(Cal3Bundler) GTSAM_CONCEPT_MANIFOLD_INST(Cal3Bundler) static Cal3Bundler K(500, 1e-3, 1e-3, 1000, 2000); -static Point2 p(2,3); +static Point2 p(2, 3); /* ************************************************************************* */ TEST(Cal3Bundler, vector) { Cal3Bundler K; Vector expected(3); expected << 1, 0, 0; - CHECK(assert_equal(expected,K.vector())); + CHECK(assert_equal(expected, K.vector())); } /* ************************************************************************* */ TEST(Cal3Bundler, uncalibrate) { - Vector v = K.vector() ; - double r = p.x()*p.x() + p.y()*p.y() ; - double g = v[0]*(1+v[1]*r+v[2]*r*r) ; - Point2 expected (1000+g*p.x(), 2000+g*p.y()) ; + Vector v = K.vector(); + double r = p.x() * p.x() + p.y() * p.y(); + double g = v[0] * (1 + v[1] * r + v[2] * r * r); + Point2 expected(1000 + g * p.x(), 2000 + g * p.y()); Point2 actual = K.uncalibrate(p); - CHECK(assert_equal(expected,actual)); + CHECK(assert_equal(expected, actual)); } -TEST(Cal3Bundler, calibrate ) { +TEST(Cal3Bundler, calibrate) { Point2 pn(0.5, 0.5); Point2 pi = K.uncalibrate(pn); Point2 pn_hat = K.calibrate(pi); @@ -54,20 +54,24 @@ TEST(Cal3Bundler, calibrate ) { } /* ************************************************************************* */ -Point2 uncalibrate_(const Cal3Bundler& k, const Point2& pt) { return k.uncalibrate(pt); } +Point2 uncalibrate_(const Cal3Bundler& k, const Point2& pt) { + return k.uncalibrate(pt); +} -Point2 calibrate_(const Cal3Bundler& k, const Point2& pt) { return k.calibrate(pt); } +Point2 calibrate_(const Cal3Bundler& k, const Point2& pt) { + return k.calibrate(pt); +} /* ************************************************************************* */ TEST(Cal3Bundler, Duncalibrate) { Matrix Dcal, Dp; Point2 actual = K.uncalibrate(p, Dcal, Dp); Point2 expected(2182, 3773); - CHECK(assert_equal(expected,actual,1e-7)); + CHECK(assert_equal(expected, actual, 1e-7)); Matrix numerical1 = numericalDerivative21(uncalibrate_, K, p); Matrix numerical2 = numericalDerivative22(uncalibrate_, K, p); - CHECK(assert_equal(numerical1,Dcal,1e-7)); - CHECK(assert_equal(numerical2,Dp,1e-7)); + CHECK(assert_equal(numerical1, Dcal, 1e-7)); + CHECK(assert_equal(numerical2, Dp, 1e-7)); } /* ************************************************************************* */ @@ -79,14 +83,12 @@ TEST(Cal3Bundler, Dcalibrate) { CHECK(assert_equal(pn, actual, 1e-7)); Matrix numerical1 = numericalDerivative21(calibrate_, K, pi); Matrix numerical2 = numericalDerivative22(calibrate_, K, pi); - CHECK(assert_equal(numerical1,Dcal,1e-5)); - CHECK(assert_equal(numerical2,Dp,1e-5)); + CHECK(assert_equal(numerical1, Dcal, 1e-5)); + CHECK(assert_equal(numerical2, Dp, 1e-5)); } /* ************************************************************************* */ -TEST(Cal3Bundler, assert_equal) { - CHECK(assert_equal(K,K,1e-7)); -} +TEST(Cal3Bundler, assert_equal) { CHECK(assert_equal(K, K, 1e-7)); } /* ************************************************************************* */ TEST(Cal3Bundler, retract) { @@ -99,8 +101,8 @@ TEST(Cal3Bundler, retract) { Vector3 d; d << 10, 1e-3, 1e-3; Cal3Bundler actual = K.retract(d); - CHECK(assert_equal(expected,actual,1e-7)); - CHECK(assert_equal(d,K.localCoordinates(actual),1e-7)); + CHECK(assert_equal(expected, actual, 1e-7)); + CHECK(assert_equal(d, K.localCoordinates(actual), 1e-7)); } /* ************************************************************************* */ @@ -114,5 +116,8 @@ TEST(Cal3_S2, Print) { } /* ************************************************************************* */ -int main() { TestResult tr; return TestRegistry::runAllTests(tr); } +int main() { + TestResult tr; + return TestRegistry::runAllTests(tr); +} /* ************************************************************************* */ diff --git a/gtsam/geometry/tests/testCal3DFisheye.cpp b/gtsam/geometry/tests/testCal3DFisheye.cpp index 7a73e7490..28064a92c 100644 --- a/gtsam/geometry/tests/testCal3DFisheye.cpp +++ b/gtsam/geometry/tests/testCal3DFisheye.cpp @@ -191,16 +191,15 @@ Point2 calibrate_(const Cal3Fisheye& k, const Point2& pt) { } /* ************************************************************************* */ -TEST(Cal3Fisheye, Dcalibrate) -{ +TEST(Cal3Fisheye, Dcalibrate) { Point2 p(0.5, 0.5); Point2 pi = K.uncalibrate(p); Matrix Dcal, Dp; K.calibrate(pi, Dcal, Dp); Matrix numerical1 = numericalDerivative21(calibrate_, K, pi); - CHECK(assert_equal(numerical1,Dcal,1e-5)); + CHECK(assert_equal(numerical1, Dcal, 1e-5)); Matrix numerical2 = numericalDerivative22(calibrate_, K, pi); - CHECK(assert_equal(numerical2,Dp,1e-5)); + CHECK(assert_equal(numerical2, Dp, 1e-5)); } /* ************************************************************************* */ diff --git a/gtsam/geometry/tests/testCal3DS2.cpp b/gtsam/geometry/tests/testCal3DS2.cpp index e4dc3e806..7ef6e5001 100644 --- a/gtsam/geometry/tests/testCal3DS2.cpp +++ b/gtsam/geometry/tests/testCal3DS2.cpp @@ -14,7 +14,6 @@ * @brief Unit tests for Cal3DS2 calibration model. */ - #include #include #include @@ -26,53 +25,53 @@ using namespace gtsam; GTSAM_CONCEPT_TESTABLE_INST(Cal3DS2) GTSAM_CONCEPT_MANIFOLD_INST(Cal3DS2) -static Cal3DS2 K(500, 100, 0.1, 320, 240, 1e-3, 2.0*1e-3, 3.0*1e-3, 4.0*1e-3); -static Point2 p(2,3); +static Cal3DS2 K(500, 100, 0.1, 320, 240, 1e-3, 2.0 * 1e-3, 3.0 * 1e-3, + 4.0 * 1e-3); +static Point2 p(2, 3); /* ************************************************************************* */ -TEST(Cal3DS2, uncalibrate) -{ - Vector k = K.k() ; - double r = p.x()*p.x() + p.y()*p.y() ; - double g = 1+k[0]*r+k[1]*r*r ; - double tx = 2*k[2]*p.x()*p.y() + k[3]*(r+2*p.x()*p.x()) ; - double ty = k[2]*(r+2*p.y()*p.y()) + 2*k[3]*p.x()*p.y() ; - Vector v_hat = (Vector(3) << g*p.x() + tx, g*p.y() + ty, 1.0).finished(); - Vector v_i = K.K() * v_hat ; - Point2 p_i(v_i(0)/v_i(2), v_i(1)/v_i(2)) ; +TEST(Cal3DS2, Uncalibrate) { + Vector k = K.k(); + double r = p.x() * p.x() + p.y() * p.y(); + double g = 1 + k[0] * r + k[1] * r * r; + double tx = 2 * k[2] * p.x() * p.y() + k[3] * (r + 2 * p.x() * p.x()); + double ty = k[2] * (r + 2 * p.y() * p.y()) + 2 * k[3] * p.x() * p.y(); + Vector v_hat = (Vector(3) << g * p.x() + tx, g * p.y() + ty, 1.0).finished(); + Vector v_i = K.K() * v_hat; + Point2 p_i(v_i(0) / v_i(2), v_i(1) / v_i(2)); Point2 q = K.uncalibrate(p); - CHECK(assert_equal(q,p_i)); + CHECK(assert_equal(q, p_i)); } -TEST(Cal3DS2, calibrate ) -{ +TEST(Cal3DS2, Calibrate) { Point2 pn(0.5, 0.5); Point2 pi = K.uncalibrate(pn); Point2 pn_hat = K.calibrate(pi); - CHECK( traits::Equals(pn, pn_hat, 1e-5)); + CHECK(traits::Equals(pn, pn_hat, 1e-5)); } -Point2 uncalibrate_(const Cal3DS2& k, const Point2& pt) { return k.uncalibrate(pt); } +Point2 uncalibrate_(const Cal3DS2& k, const Point2& pt) { + return k.uncalibrate(pt); +} /* ************************************************************************* */ -TEST(Cal3DS2, Duncalibrate1) -{ +TEST(Cal3DS2, Duncalibrate1) { Matrix computed; K.uncalibrate(p, computed, boost::none); Matrix numerical = numericalDerivative21(uncalibrate_, K, p, 1e-7); - CHECK(assert_equal(numerical,computed,1e-5)); + CHECK(assert_equal(numerical, computed, 1e-5)); Matrix separate = K.D2d_calibration(p); - CHECK(assert_equal(numerical,separate,1e-5)); + CHECK(assert_equal(numerical, separate, 1e-5)); } /* ************************************************************************* */ -TEST(Cal3DS2, Duncalibrate2) -{ - Matrix computed; K.uncalibrate(p, boost::none, computed); +TEST(Cal3DS2, Duncalibrate2) { + Matrix computed; + K.uncalibrate(p, boost::none, computed); Matrix numerical = numericalDerivative22(uncalibrate_, K, p, 1e-7); - CHECK(assert_equal(numerical,computed,1e-5)); + CHECK(assert_equal(numerical, computed, 1e-5)); Matrix separate = K.D2d_intrinsic(p); - CHECK(assert_equal(numerical,separate,1e-5)); + CHECK(assert_equal(numerical, separate, 1e-5)); } Point2 calibrate_(const Cal3DS2& k, const Point2& pt) { @@ -80,8 +79,7 @@ Point2 calibrate_(const Cal3DS2& k, const Point2& pt) { } /* ************************************************************************* */ -TEST(Cal3DS2, Dcalibrate) -{ +TEST(Cal3DS2, Dcalibrate) { Point2 pn(0.5, 0.5); Point2 pi = K.uncalibrate(pn); Matrix Dcal, Dp; @@ -93,21 +91,21 @@ TEST(Cal3DS2, Dcalibrate) } /* ************************************************************************* */ -TEST(Cal3DS2, assert_equal) { CHECK(assert_equal(K, K, 1e-5)); } +TEST(Cal3DS2, Equal) { CHECK(assert_equal(K, K, 1e-5)); } /* ************************************************************************* */ -TEST(Cal3DS2, retract) { +TEST(Cal3DS2, Retract) { Cal3DS2 expected(500 + 1, 100 + 2, 0.1 + 3, 320 + 4, 240 + 5, 1e-3 + 6, - 2.0 * 1e-3 + 7, 3.0 * 1e-3 + 8, 4.0 * 1e-3 + 9); + 2.0 * 1e-3 + 7, 3.0 * 1e-3 + 8, 4.0 * 1e-3 + 9); EXPECT_LONGS_EQUAL(Cal3DS2::Dim(), 9); EXPECT_LONGS_EQUAL(expected.dim(), 9); Vector9 d; - d << 1,2,3,4,5,6,7,8,9; + d << 1, 2, 3, 4, 5, 6, 7, 8, 9; Cal3DS2 actual = K.retract(d); - CHECK(assert_equal(expected,actual,1e-7)); - CHECK(assert_equal(d,K.localCoordinates(actual),1e-7)); + CHECK(assert_equal(expected, actual, 1e-7)); + CHECK(assert_equal(d, K.localCoordinates(actual), 1e-7)); } /* ************************************************************************* */ @@ -122,5 +120,8 @@ TEST(Cal3DS2, Print) { } /* ************************************************************************* */ -int main() { TestResult tr; return TestRegistry::runAllTests(tr); } +int main() { + TestResult tr; + return TestRegistry::runAllTests(tr); +} /* ************************************************************************* */ diff --git a/gtsam/geometry/tests/testCal3Unified.cpp b/gtsam/geometry/tests/testCal3Unified.cpp index ff759d1cd..648bb358c 100644 --- a/gtsam/geometry/tests/testCal3Unified.cpp +++ b/gtsam/geometry/tests/testCal3Unified.cpp @@ -20,8 +20,8 @@ #include #include -#include #include +#include using namespace gtsam; @@ -36,51 +36,49 @@ V = [0.1, 1e-3, 2.0*1e-3, 3.0*1e-3, 4.0*1e-3, 0, 0, 100, 105, 320, 240]; matlab toolbox available at http://homepages.laas.fr/~cmei/index.php/Toolbox */ -static Cal3Unified K(100, 105, 0.0, 320, 240, 1e-3, 2.0*1e-3, 3.0*1e-3, 4.0*1e-3, 0.1); +static Cal3Unified K(100, 105, 0.0, 320, 240, 1e-3, 2.0 * 1e-3, 3.0 * 1e-3, + 4.0 * 1e-3, 0.1); static Point2 p(0.5, 0.7); /* ************************************************************************* */ -TEST(Cal3Unified, uncalibrate) -{ - Point2 p_i(364.7791831734982, 305.6677211952602) ; +TEST(Cal3Unified, Uncalibrate) { + Point2 p_i(364.7791831734982, 305.6677211952602); Point2 q = K.uncalibrate(p); - CHECK(assert_equal(q,p_i)); + CHECK(assert_equal(q, p_i)); } /* ************************************************************************* */ -TEST(Cal3Unified, spaceNplane) -{ +TEST(Cal3Unified, SpaceNplane) { Point2 q = K.spaceToNPlane(p); CHECK(assert_equal(Point2(0.441731600049497, 0.618424240069295), q)); CHECK(assert_equal(p, K.nPlaneToSpace(q))); } /* ************************************************************************* */ -TEST(Cal3Unified, calibrate) -{ +TEST(Cal3Unified, Calibrate) { Point2 pi = K.uncalibrate(p); Point2 pn_hat = K.calibrate(pi); - CHECK( traits::Equals(p, pn_hat, 1e-8)); + CHECK(traits::Equals(p, pn_hat, 1e-8)); } -Point2 uncalibrate_(const Cal3Unified& k, const Point2& pt) { return k.uncalibrate(pt); } +Point2 uncalibrate_(const Cal3Unified& k, const Point2& pt) { + return k.uncalibrate(pt); +} /* ************************************************************************* */ -TEST(Cal3Unified, Duncalibrate1) -{ +TEST(Cal3Unified, Duncalibrate1) { Matrix computed; K.uncalibrate(p, computed, boost::none); Matrix numerical = numericalDerivative21(uncalibrate_, K, p, 1e-7); - CHECK(assert_equal(numerical,computed,1e-6)); + CHECK(assert_equal(numerical, computed, 1e-6)); } /* ************************************************************************* */ -TEST(Cal3Unified, Duncalibrate2) -{ +TEST(Cal3Unified, Duncalibrate2) { Matrix computed; K.uncalibrate(p, boost::none, computed); Matrix numerical = numericalDerivative22(uncalibrate_, K, p, 1e-7); - CHECK(assert_equal(numerical,computed,1e-6)); + CHECK(assert_equal(numerical, computed, 1e-6)); } Point2 calibrate_(const Cal3Unified& k, const Point2& pt) { @@ -88,27 +86,24 @@ Point2 calibrate_(const Cal3Unified& k, const Point2& pt) { } /* ************************************************************************* */ -TEST(Cal3Unified, Dcalibrate) -{ +TEST(Cal3Unified, Dcalibrate) { Point2 pi = K.uncalibrate(p); Matrix Dcal, Dp; K.calibrate(pi, Dcal, Dp); Matrix numerical1 = numericalDerivative21(calibrate_, K, pi); - CHECK(assert_equal(numerical1,Dcal,1e-5)); + CHECK(assert_equal(numerical1, Dcal, 1e-5)); Matrix numerical2 = numericalDerivative22(calibrate_, K, pi); - CHECK(assert_equal(numerical2,Dp,1e-5)); + CHECK(assert_equal(numerical2, Dp, 1e-5)); } /* ************************************************************************* */ -TEST(Cal3Unified, assert_equal) -{ - CHECK(assert_equal(K,K,1e-9)); -} +TEST(Cal3Unified, Equal) { CHECK(assert_equal(K, K, 1e-9)); } /* ************************************************************************* */ -TEST(Cal3Unified, retract) { - Cal3Unified expected(100 + 2, 105 + 3, 0.0 + 4, 320 + 5, 240 + 6, - 1e-3 + 7, 2.0*1e-3 + 8, 3.0*1e-3 + 9, 4.0*1e-3 + 10, 0.1 + 1); +TEST(Cal3Unified, Retract) { + Cal3Unified expected(100 + 2, 105 + 3, 0.0 + 4, 320 + 5, 240 + 6, 1e-3 + 7, + 2.0 * 1e-3 + 8, 3.0 * 1e-3 + 9, 4.0 * 1e-3 + 10, + 0.1 + 1); EXPECT_LONGS_EQUAL(Cal3Unified::Dim(), 10); EXPECT_LONGS_EQUAL(expected.dim(), 10); @@ -116,13 +111,12 @@ TEST(Cal3Unified, retract) { Vector10 d; d << 2, 3, 4, 5, 6, 7, 8, 9, 10, 1; Cal3Unified actual = K.retract(d); - CHECK(assert_equal(expected,actual,1e-9)); - CHECK(assert_equal(d,K.localCoordinates(actual),1e-9)); + CHECK(assert_equal(expected, actual, 1e-9)); + CHECK(assert_equal(d, K.localCoordinates(actual), 1e-9)); } /* ************************************************************************* */ -TEST(Cal3Unified, DerivedValue) -{ +TEST(Cal3Unified, DerivedValue) { Values values; Cal3Unified cal(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Key key = 1; @@ -130,7 +124,7 @@ TEST(Cal3Unified, DerivedValue) Cal3Unified calafter = values.at(key); - CHECK(assert_equal(cal,calafter,1e-9)); + CHECK(assert_equal(cal, calafter, 1e-9)); } /* ************************************************************************* */ @@ -146,5 +140,8 @@ TEST(Cal3Unified, Print) { } /* ************************************************************************* */ -int main() { TestResult tr; return TestRegistry::runAllTests(tr); } +int main() { + TestResult tr; + return TestRegistry::runAllTests(tr); +} /* ************************************************************************* */ diff --git a/gtsam/geometry/tests/testCal3_S2.cpp b/gtsam/geometry/tests/testCal3_S2.cpp index 9b7941c91..41be5ea8e 100644 --- a/gtsam/geometry/tests/testCal3_S2.cpp +++ b/gtsam/geometry/tests/testCal3_S2.cpp @@ -34,27 +34,27 @@ static Point2 p_xy(2, 3); TEST(Cal3_S2, Constructor) { Cal3_S2 expected(554.256, 554.256, 0, 640 / 2, 480 / 2); - double fov = 60; // degrees - size_t w=640,h=480; - Cal3_S2 actual(fov,w,h); + double fov = 60; // degrees + size_t w = 640, h = 480; + Cal3_S2 actual(fov, w, h); - CHECK(assert_equal(expected,actual,1e-3)); + CHECK(assert_equal(expected, actual, 1e-3)); } /* ************************************************************************* */ TEST(Cal3_S2, Calibrate) { - Point2 intrinsic(2,3); + Point2 intrinsic(2, 3); Point2 expectedimage(1320.3, 1740); Point2 imagecoordinates = K.uncalibrate(intrinsic); - CHECK(assert_equal(expectedimage,imagecoordinates)); - CHECK(assert_equal(intrinsic,K.calibrate(imagecoordinates))); + CHECK(assert_equal(expectedimage, imagecoordinates)); + CHECK(assert_equal(intrinsic, K.calibrate(imagecoordinates))); } /* ************************************************************************* */ TEST(Cal3_S2, CalibrateHomogeneous) { Vector3 intrinsic(2, 3, 1); Vector3 image(1320.3, 1740, 1); - CHECK(assert_equal((Vector)intrinsic,(Vector)K.calibrate(image))); + CHECK(assert_equal((Vector)intrinsic, (Vector)K.calibrate(image))); } /* ************************************************************************* */ @@ -63,16 +63,18 @@ Point2 uncalibrate_(const Cal3_S2& k, const Point2& pt) { } TEST(Cal3_S2, Duncalibrate1) { - Matrix25 computed; K.uncalibrate(p, computed, boost::none); + Matrix25 computed; + K.uncalibrate(p, computed, boost::none); Matrix numerical = numericalDerivative21(uncalibrate_, K, p); - CHECK(assert_equal(numerical,computed,1e-8)); + CHECK(assert_equal(numerical, computed, 1e-8)); } /* ************************************************************************* */ TEST(Cal3_S2, Duncalibrate2) { - Matrix computed; K.uncalibrate(p, boost::none, computed); + Matrix computed; + K.uncalibrate(p, boost::none, computed); Matrix numerical = numericalDerivative22(uncalibrate_, K, p); - CHECK(assert_equal(numerical,computed,1e-9)); + CHECK(assert_equal(numerical, computed, 1e-9)); } Point2 calibrate_(const Cal3_S2& k, const Point2& pt) { @@ -81,42 +83,42 @@ Point2 calibrate_(const Cal3_S2& k, const Point2& pt) { /* ************************************************************************* */ TEST(Cal3_S2, Dcalibrate1) { - Matrix computed; - Point2 expected = K.calibrate(p_uv, computed, boost::none); - Matrix numerical = numericalDerivative21(calibrate_, K, p_uv); - CHECK(assert_equal(expected, p_xy, 1e-8)); - CHECK(assert_equal(numerical, computed, 1e-8)); + Matrix computed; + Point2 expected = K.calibrate(p_uv, computed, boost::none); + Matrix numerical = numericalDerivative21(calibrate_, K, p_uv); + CHECK(assert_equal(expected, p_xy, 1e-8)); + CHECK(assert_equal(numerical, computed, 1e-8)); } /* ************************************************************************* */ TEST(Cal3_S2, Dcalibrate2) { - Matrix computed; - Point2 expected = K.calibrate(p_uv, boost::none, computed); - Matrix numerical = numericalDerivative22(calibrate_, K, p_uv); - CHECK(assert_equal(expected, p_xy, 1e-8)); - CHECK(assert_equal(numerical, computed, 1e-8)); + Matrix computed; + Point2 expected = K.calibrate(p_uv, boost::none, computed); + Matrix numerical = numericalDerivative22(calibrate_, K, p_uv); + CHECK(assert_equal(expected, p_xy, 1e-8)); + CHECK(assert_equal(numerical, computed, 1e-8)); } /* ************************************************************************* */ TEST(Cal3_S2, Equal) { - CHECK(assert_equal(K,K,1e-9)); + CHECK(assert_equal(K, K, 1e-9)); Cal3_S2 K1(500, 500, 0.1, 640 / 2, 480 / 2); - CHECK(assert_equal(K,K1,1e-9)); + CHECK(assert_equal(K, K1, 1e-9)); } /* ************************************************************************* */ TEST(Cal3_S2, Retract) { - Cal3_S2 expected(500+1, 500+2, 0.1+3, 640 / 2+4, 480 / 2+5); + Cal3_S2 expected(500 + 1, 500 + 2, 0.1 + 3, 640 / 2 + 4, 480 / 2 + 5); EXPECT_LONGS_EQUAL(Cal3_S2::Dim(), 5); EXPECT_LONGS_EQUAL(expected.dim(), 5); Vector5 d; - d << 1,2,3,4,5; + d << 1, 2, 3, 4, 5; Cal3_S2 actual = K.retract(d); - CHECK(assert_equal(expected,actual,1e-7)); - CHECK(assert_equal(d,K.localCoordinates(actual),1e-7)); + CHECK(assert_equal(expected, actual, 1e-7)); + CHECK(assert_equal(d, K.localCoordinates(actual), 1e-7)); } /* ************************************************************************* */ @@ -124,7 +126,7 @@ TEST(Cal3_S2, between) { Cal3_S2 k1(5, 5, 5, 5, 5), k2(5, 6, 7, 8, 9); Matrix H1, H2; - EXPECT(assert_equal(Cal3_S2(0,1,2,3,4), k1.between(k2, H1, H2))); + EXPECT(assert_equal(Cal3_S2(0, 1, 2, 3, 4), k1.between(k2, H1, H2))); EXPECT(assert_equal(-I_5x5, H1)); EXPECT(assert_equal(I_5x5, H2)); } @@ -145,4 +147,3 @@ int main() { return TestRegistry::runAllTests(tr); } /* ************************************************************************* */ - diff --git a/gtsam/geometry/tests/testCal3_S2Stereo.cpp b/gtsam/geometry/tests/testCal3_S2Stereo.cpp index f823a8b97..e6a591b5f 100644 --- a/gtsam/geometry/tests/testCal3_S2Stereo.cpp +++ b/gtsam/geometry/tests/testCal3_S2Stereo.cpp @@ -31,7 +31,7 @@ static Point2 p_uv(1320.3, 1740); static Point2 p_xy(2, 3); /* ************************************************************************* */ -TEST(Cal3_S2Stereo, easy_constructor) { +TEST(Cal3_S2Stereo, Constructor) { Cal3_S2Stereo expected(554.256, 554.256, 0, 640 / 2, 480 / 2, 3); double fov = 60; // degrees @@ -42,7 +42,7 @@ TEST(Cal3_S2Stereo, easy_constructor) { } /* ************************************************************************* */ -TEST(Cal3_S2Stereo, calibrate) { +TEST(Cal3_S2Stereo, Calibrate) { Point2 intrinsic(2, 3); Point2 expectedimage(1320.3, 1740); Point2 imagecoordinates = K.uncalibrate(intrinsic); @@ -51,56 +51,14 @@ TEST(Cal3_S2Stereo, calibrate) { } /* ************************************************************************* */ -TEST(Cal3_S2Stereo, calibrate_homogeneous) { +TEST(Cal3_S2Stereo, CalibrateHomogeneous) { Vector3 intrinsic(2, 3, 1); Vector3 image(1320.3, 1740, 1); CHECK(assert_equal((Vector)intrinsic, (Vector)K.calibrate(image))); } -//TODO(Varun) Add calibrate and uncalibrate methods -// /* ************************************************************************* */ -// Point2 uncalibrate_(const Cal3_S2Stereo& k, const Point2& pt) { -// return k.uncalibrate(pt); -// } - -// TEST(Cal3_S2Stereo, Duncalibrate1) { -// Matrix26 computed; -// K.uncalibrate(p, computed, boost::none); -// Matrix numerical = numericalDerivative21(uncalibrate_, K, p); -// CHECK(assert_equal(numerical, computed, 1e-8)); -// } - -// /* ************************************************************************* */ -// TEST(Cal3_S2Stereo, Duncalibrate2) { -// Matrix computed; -// K.uncalibrate(p, boost::none, computed); -// Matrix numerical = numericalDerivative22(uncalibrate_, K, p); -// CHECK(assert_equal(numerical, computed, 1e-9)); -// } - -// Point2 calibrate_(const Cal3_S2Stereo& k, const Point2& pt) { -// return k.calibrate(pt); -// } -// /* ************************************************************************* */ -// TEST(Cal3_S2Stereo, Dcalibrate1) { -// Matrix computed; -// Point2 expected = K.calibrate(p_uv, computed, boost::none); -// Matrix numerical = numericalDerivative21(calibrate_, K, p_uv); -// CHECK(assert_equal(expected, p_xy, 1e-8)); -// CHECK(assert_equal(numerical, computed, 1e-8)); -// } - -// /* ************************************************************************* */ -// TEST(Cal3_S2Stereo, Dcalibrate2) { -// Matrix computed; -// Point2 expected = K.calibrate(p_uv, boost::none, computed); -// Matrix numerical = numericalDerivative22(calibrate_, K, p_uv); -// CHECK(assert_equal(expected, p_xy, 1e-8)); -// CHECK(assert_equal(numerical, computed, 1e-8)); -// } - /* ************************************************************************* */ -TEST(Cal3_S2Stereo, assert_equal) { +TEST(Cal3_S2Stereo, Equal) { CHECK(assert_equal(K, K, 1e-9)); Cal3_S2Stereo K1(500, 500, 0.1, 640 / 2, 480 / 2, 1); @@ -108,7 +66,7 @@ TEST(Cal3_S2Stereo, assert_equal) { } /* ************************************************************************* */ -TEST(Cal3_S2Stereo, retract) { +TEST(Cal3_S2Stereo, Retract) { Cal3_S2Stereo expected(500 + 1, 500 + 2, 0.1 + 3, 640 / 2 + 4, 480 / 2 + 5, 7); EXPECT_LONGS_EQUAL(Cal3_S2Stereo::Dim(), 6); From 3ddc999f43e1bc7add36ab9e115f1b14b6c21548 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 2 Dec 2020 17:24:21 -0500 Subject: [PATCH 132/261] additional formatting --- gtsam/geometry/Cal3Unified.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/gtsam/geometry/Cal3Unified.cpp b/gtsam/geometry/Cal3Unified.cpp index 80613bbf2..11aabcaa7 100644 --- a/gtsam/geometry/Cal3Unified.cpp +++ b/gtsam/geometry/Cal3Unified.cpp @@ -16,10 +16,10 @@ * @author Varun Agrawal */ -#include #include -#include +#include #include +#include #include @@ -53,10 +53,8 @@ bool Cal3Unified::equals(const Cal3Unified& K, double tol) const { /* ************************************************************************* */ // todo: make a fixed sized jacobian version of this -Point2 Cal3Unified::uncalibrate(const Point2& p, - OptionalJacobian<2,10> Dcal, - OptionalJacobian<2,2> Dp) const { - +Point2 Cal3Unified::uncalibrate(const Point2& p, OptionalJacobian<2, 10> Dcal, + OptionalJacobian<2, 2> Dp) const { // this part of code is modified from Cal3DS2, // since the second part of this model (after project to normalized plane) // is same as Cal3DS2 @@ -69,19 +67,19 @@ Point2 Cal3Unified::uncalibrate(const Point2& p, const double sqrt_nx = sqrt(xs * xs + ys * ys + 1.0); const double xi_sqrt_nx = 1.0 / (1 + xi * sqrt_nx); const double xi_sqrt_nx2 = xi_sqrt_nx * xi_sqrt_nx; - const double x = xs * xi_sqrt_nx, y = ys * xi_sqrt_nx; // points on NPlane + const double x = xs * xi_sqrt_nx, y = ys * xi_sqrt_nx; // points on NPlane // Part2: project NPlane point to pixel plane: use Cal3DS2 - Point2 m(x,y); + Point2 m(x, y); Matrix29 H1base; - Matrix2 H2base; // jacobians from Base class + Matrix2 H2base; // jacobians from Base class Point2 puncalib = Base::uncalibrate(m, H1base, H2base); // Inlined derivative for calibration if (Dcal) { // part1 Vector2 DU; - DU << -xs * sqrt_nx * xi_sqrt_nx2, // + DU << -xs * sqrt_nx * xi_sqrt_nx2, // -ys * sqrt_nx * xi_sqrt_nx2; *Dcal << H1base, H2base * DU; } @@ -90,10 +88,10 @@ Point2 Cal3Unified::uncalibrate(const Point2& p, if (Dp) { // part1 const double denom = 1.0 * xi_sqrt_nx2 / sqrt_nx; - const double mid = -(xi * xs*ys) * denom; + const double mid = -(xi * xs * ys) * denom; Matrix2 DU; - DU << (sqrt_nx + xi*(ys*ys + 1)) * denom, mid, // - mid, (sqrt_nx + xi*(xs*xs + 1)) * denom; + DU << (sqrt_nx + xi * (ys * ys + 1)) * denom, mid, // + mid, (sqrt_nx + xi * (xs * xs + 1)) * denom; *Dp << H2base * DU; } @@ -116,7 +114,6 @@ Point2 Cal3Unified::calibrate(const Point2& pi, OptionalJacobian<2, 10> Dcal, } /* ************************************************************************* */ Point2 Cal3Unified::nPlaneToSpace(const Point2& p) const { - const double x = p.x(), y = p.y(); const double xy2 = x * x + y * y; const double sq_xy = (xi_ + sqrt(1 + (1 - xi_ * xi_) * xy2)) / (xy2 + 1); @@ -126,7 +123,6 @@ Point2 Cal3Unified::nPlaneToSpace(const Point2& p) const { /* ************************************************************************* */ Point2 Cal3Unified::spaceToNPlane(const Point2& p) const { - const double x = p.x(), y = p.y(); const double sq_xy = 1 + xi_ * sqrt(x * x + y * y + 1); From 9611db8130bb1dd1e8175ed6de46b0a1586998d7 Mon Sep 17 00:00:00 2001 From: Jose Luis Blanco Claraco Date: Thu, 3 Dec 2020 09:06:44 +0100 Subject: [PATCH 133/261] SymbolGenerator: add chr() and made constexpr-capable --- gtsam/inference/Symbol.h | 5 +++-- gtsam/inference/tests/testKey.cpp | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/gtsam/inference/Symbol.h b/gtsam/inference/Symbol.h index 469082f16..42cdbb1c3 100644 --- a/gtsam/inference/Symbol.h +++ b/gtsam/inference/Symbol.h @@ -167,10 +167,11 @@ inline Key Z(std::uint64_t j) { return Symbol('z', j); } /** Generates symbol shorthands with alternative names different than the * one-letter predefined ones. */ class SymbolGenerator { - const char c_; + const unsigned char c_; public: - SymbolGenerator(const char c) : c_(c) {} + constexpr SymbolGenerator(const unsigned char c) : c_(c) {} Symbol operator()(const std::uint64_t j) const { return Symbol(c_, j); } + constexpr unsigned char chr() const { return c_; } }; /// traits diff --git a/gtsam/inference/tests/testKey.cpp b/gtsam/inference/tests/testKey.cpp index 64674c36f..98c5d36bf 100644 --- a/gtsam/inference/tests/testKey.cpp +++ b/gtsam/inference/tests/testKey.cpp @@ -59,6 +59,12 @@ TEST(Key, SymbolGenerator) { EXPECT(assert_equal(a1, ddz1)); } +/* ************************************************************************* */ +TEST(Key, SymbolGeneratorConstexpr) { + constexpr auto Z = gtsam::SymbolGenerator('x'); + EXPECT(assert_equal(Z.chr(), 'x')); +} + /* ************************************************************************* */ template Key KeyTestValue(); From b788fb14c062be9d32613f07e5daf1fe3b13d938 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 3 Dec 2020 14:33:03 -0500 Subject: [PATCH 134/261] mark getters as const --- gtsam/sfm/ShonanAveraging.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index 5cb34c419..ad8d2944a 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -69,19 +69,19 @@ struct GTSAM_EXPORT ShonanAveragingParameters { double getOptimalityThreshold() const { return optimalityThreshold; } void setAnchor(size_t index, const Rot &value) { anchor = {index, value}; } - std::pair getAnchor() { return anchor; } + std::pair getAnchor() const { return anchor; } void setAnchorWeight(double value) { alpha = value; } - double getAnchorWeight() { return alpha; } + double getAnchorWeight() const { return alpha; } void setKarcherWeight(double value) { beta = value; } - double getKarcherWeight() { return beta; } + double getKarcherWeight() const { return beta; } void setGaugesWeight(double value) { gamma = value; } - double getGaugesWeight() { return gamma; } + double getGaugesWeight() const { return gamma; } void setUseHuber(bool value) { useHuber = value; } - bool getUseHuber() { return useHuber; } + bool getUseHuber() const { return useHuber; } /// Print the parameters and flags used for rotation averaging. void print() const { From 636d5f4f1ca262cbe94f64e180620f930f720f49 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 3 Dec 2020 14:34:18 -0500 Subject: [PATCH 135/261] Helper method to robustify measurements --- gtsam/sfm/ShonanAveraging.cpp | 34 +++++++++++++--------------------- gtsam/sfm/ShonanAveraging.h | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index bc3783a27..8fed0538d 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -812,7 +812,7 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, return std::make_pair(SO3Values, 0); } - // Check certificate of global optimzality + // Check certificate of global optimality Vector minEigenVector; double minEigenValue = computeMinEigenValue(Qstar, &minEigenVector); if (minEigenValue > parameters_.optimalityThreshold) { @@ -837,17 +837,13 @@ template class ShonanAveraging<2>; ShonanAveraging2::ShonanAveraging2(const Measurements &measurements, const Parameters ¶meters) - : ShonanAveraging<2>(parameters.useHuber - ? makeNoiseModelRobust(measurements) - : measurements, + : ShonanAveraging<2>(maybeRobust(measurements, parameters.getUseHuber()), parameters) {} ShonanAveraging2::ShonanAveraging2(string g2oFile, const Parameters ¶meters) - : ShonanAveraging<2>( - parameters.useHuber - ? makeNoiseModelRobust(parseMeasurements(g2oFile)) - : parseMeasurements(g2oFile), - parameters) {} + : ShonanAveraging<2>(maybeRobust(parseMeasurements(g2oFile), + parameters.getUseHuber()), + parameters) {} /* ************************************************************************* */ // Explicit instantiation for d=3 @@ -855,15 +851,13 @@ template class ShonanAveraging<3>; ShonanAveraging3::ShonanAveraging3(const Measurements &measurements, const Parameters ¶meters) - : ShonanAveraging<3>(parameters.useHuber? - makeNoiseModelRobust(measurements) : measurements, parameters) {} + : ShonanAveraging<3>(maybeRobust(measurements, parameters.getUseHuber()), + parameters) {} ShonanAveraging3::ShonanAveraging3(string g2oFile, const Parameters ¶meters) - : ShonanAveraging<3>( - parameters.useHuber - ? makeNoiseModelRobust(parseMeasurements(g2oFile)) - : parseMeasurements(g2oFile), - parameters) {} + : ShonanAveraging<3>(maybeRobust(parseMeasurements(g2oFile), + parameters.getUseHuber()), + parameters) {} // TODO(frank): Deprecate after we land pybind wrapper @@ -895,11 +889,9 @@ static ShonanAveraging3::Measurements extractRot3Measurements( ShonanAveraging3::ShonanAveraging3(const BetweenFactorPose3s &factors, const Parameters ¶meters) - : ShonanAveraging<3>( - parameters.useHuber - ? makeNoiseModelRobust(extractRot3Measurements(factors)) - : extractRot3Measurements(factors), - parameters) {} + : ShonanAveraging<3>(maybeRobust(extractRot3Measurements(factors), + parameters.getUseHuber()), + parameters) {} /* ************************************************************************* */ } // namespace gtsam diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index ad8d2944a..48d873a1a 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -389,6 +389,22 @@ class GTSAM_EXPORT ShonanAveraging { std::pair run(const Values &initialEstimate, size_t pMin = d, size_t pMax = 10) const; /// @} + + /** + * Helper function to convert measurements to robust noise model + * if flag is set. + * + * @tparam T the type of measurement, e.g. Rot3. + * @param measurements vector of BinaryMeasurements of type T. + * @param useRobustModel flag indicating whether use robust noise model + * instead. + */ + template + inline std::vector> maybeRobust( + const std::vector> &measurements, + bool useRobustModel = false) const { + return useRobustModel ? makeNoiseModelRobust(measurements) : measurements; + } }; // Subclasses for d=2 and d=3 that explicitly instantiate, as well as provide a From 07605d4005da8248066665de1252636213c7ade5 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 3 Dec 2020 20:08:57 -0500 Subject: [PATCH 136/261] calibrate and uncalibrate for Cal3_S2Stereo model --- gtsam/geometry/Cal3_S2.cpp | 3 +- gtsam/geometry/Cal3_S2Stereo.cpp | 28 ++++++++++++++++++ gtsam/geometry/Cal3_S2Stereo.h | 27 +++++++++++++++++ gtsam/geometry/tests/testCal3_S2Stereo.cpp | 34 +++++++++++++++++++++- 4 files changed, 90 insertions(+), 2 deletions(-) diff --git a/gtsam/geometry/Cal3_S2.cpp b/gtsam/geometry/Cal3_S2.cpp index f97082ddf..1a76c3f6f 100644 --- a/gtsam/geometry/Cal3_S2.cpp +++ b/gtsam/geometry/Cal3_S2.cpp @@ -59,10 +59,11 @@ Point2 Cal3_S2::calibrate(const Point2& p, OptionalJacobian<2, 5> Dcal, double inv_fx_s_inv_fy = inv_fx * s_ * inv_fy; Point2 point(inv_fx * (delta_u - s_ * inv_fy_delta_v), inv_fy_delta_v); - if (Dcal) + if (Dcal) { *Dcal << -inv_fx * point.x(), inv_fx * s_ * inv_fy * inv_fy_delta_v, -inv_fx * point.y(), -inv_fx, inv_fx_s_inv_fy, 0, -inv_fy * point.y(), 0, 0, -inv_fy; + } if (Dp) *Dp << inv_fx, -inv_fx_s_inv_fy, 0, inv_fy; return point; } diff --git a/gtsam/geometry/Cal3_S2Stereo.cpp b/gtsam/geometry/Cal3_S2Stereo.cpp index 56ceaf516..9ef8c83a3 100644 --- a/gtsam/geometry/Cal3_S2Stereo.cpp +++ b/gtsam/geometry/Cal3_S2Stereo.cpp @@ -42,6 +42,34 @@ bool Cal3_S2Stereo::equals(const Cal3_S2Stereo& other, double tol) const { std::fabs(b_ - other.baseline()) < tol); } +/* ************************************************************************* */ +Point2 Cal3_S2Stereo::uncalibrate(const Point2& p, OptionalJacobian<2, 6> Dcal, + OptionalJacobian<2, 2> Dp) const { + const double x = p.x(), y = p.y(); + if (Dcal) *Dcal << x, 0.0, y, 1.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 1.0, 0.0; + if (Dp) *Dp << fx_, s_, 0.0, fy_; + return Point2(fx_ * x + s_ * y + u0_, fy_ * y + v0_); +} + +/* ************************************************************************* */ +Point2 Cal3_S2Stereo::calibrate(const Point2& p, OptionalJacobian<2, 6> Dcal, + OptionalJacobian<2, 2> Dp) const { + const double u = p.x(), v = p.y(); + double delta_u = u - u0_, delta_v = v - v0_; + double inv_fx = 1 / fx_, inv_fy = 1 / fy_; + double inv_fy_delta_v = inv_fy * delta_v; + double inv_fx_s_inv_fy = inv_fx * s_ * inv_fy; + + Point2 point(inv_fx * (delta_u - s_ * inv_fy_delta_v), inv_fy_delta_v); + if (Dcal) { + *Dcal << -inv_fx * point.x(), inv_fx * s_ * inv_fy * inv_fy_delta_v, + -inv_fx * point.y(), -inv_fx, inv_fx_s_inv_fy, 0, 0, + -inv_fy * point.y(), 0, 0, -inv_fy, 0; + } + if (Dp) *Dp << inv_fx, -inv_fx_s_inv_fy, 0, inv_fy; + return point; +} + /* ************************************************************************* */ } // namespace gtsam diff --git a/gtsam/geometry/Cal3_S2Stereo.h b/gtsam/geometry/Cal3_S2Stereo.h index d7bf34e61..01e48a816 100644 --- a/gtsam/geometry/Cal3_S2Stereo.h +++ b/gtsam/geometry/Cal3_S2Stereo.h @@ -55,6 +55,33 @@ class GTSAM_EXPORT Cal3_S2Stereo : public Cal3_S2 { Cal3_S2Stereo(double fov, int w, int h, double b) : Cal3_S2(fov, w, h), b_(b) {} + /** + * Convert intrinsic coordinates xy to image coordinates uv, fixed derivaitves + * @param p point in intrinsic coordinates + * @param Dcal optional 2*6 Jacobian wrpt Cal3_S2Stereo parameters + * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates + * @return point in image coordinates + */ + Point2 uncalibrate(const Point2& p, OptionalJacobian<2, 6> Dcal = boost::none, + OptionalJacobian<2, 2> Dp = boost::none) const; + + /** + * Convert image coordinates uv to intrinsic coordinates xy + * @param p point in image coordinates + * @param Dcal optional 2*6 Jacobian wrpt Cal3_S2Stereo parameters + * @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates + * @return point in intrinsic coordinates + */ + Point2 calibrate(const Point2& p, OptionalJacobian<2, 6> Dcal = boost::none, + OptionalJacobian<2, 2> Dp = boost::none) const; + + /** + * Convert homogeneous image coordinates to intrinsic coordinates + * @param p point in image coordinates + * @return point in intrinsic coordinates + */ + using Cal3_S2::calibrate; + /// @} /// @name Testable /// @{ diff --git a/gtsam/geometry/tests/testCal3_S2Stereo.cpp b/gtsam/geometry/tests/testCal3_S2Stereo.cpp index e6a591b5f..070eee8fe 100644 --- a/gtsam/geometry/tests/testCal3_S2Stereo.cpp +++ b/gtsam/geometry/tests/testCal3_S2Stereo.cpp @@ -54,7 +54,39 @@ TEST(Cal3_S2Stereo, Calibrate) { TEST(Cal3_S2Stereo, CalibrateHomogeneous) { Vector3 intrinsic(2, 3, 1); Vector3 image(1320.3, 1740, 1); - CHECK(assert_equal((Vector)intrinsic, (Vector)K.calibrate(image))); + CHECK(assert_equal(intrinsic, K.calibrate(image))); +} + +/* ************************************************************************* */ +Point2 uncalibrate_(const Cal3_S2Stereo& k, const Point2& pt) { + return k.uncalibrate(pt); +} + +TEST(Cal3_S2Stereo, Duncalibrate) { + Matrix26 Dcal; + Matrix22 Dp; + K.uncalibrate(p, Dcal, Dp); + + Matrix numerical1 = numericalDerivative21(uncalibrate_, K, p); + CHECK(assert_equal(numerical1, Dcal, 1e-8)); + Matrix numerical2 = numericalDerivative22(uncalibrate_, K, p); + CHECK(assert_equal(numerical2, Dp, 1e-9)); +} + +Point2 calibrate_(const Cal3_S2Stereo& K, const Point2& pt) { + return K.calibrate(pt); +} +/* ************************************************************************* */ +TEST(Cal3_S2Stereo, Dcalibrate) { + Matrix26 Dcal; + Matrix22 Dp; + Point2 expected = K.calibrate(p_uv, Dcal, Dp); + CHECK(assert_equal(expected, p_xy, 1e-8)); + + Matrix numerical1 = numericalDerivative21(calibrate_, K, p_uv); + CHECK(assert_equal(numerical1, Dcal, 1e-8)); + Matrix numerical2 = numericalDerivative22(calibrate_, K, p_uv); + CHECK(assert_equal(numerical2, Dp, 1e-8)); } /* ************************************************************************* */ From 06aa4ef780379ec4c20e6b3d7f1b41bb2181b19c Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 3 Dec 2020 20:27:59 -0500 Subject: [PATCH 137/261] throw error if robust model used but not specified in parameters --- gtsam/sfm/ShonanAveraging.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 8fed0538d..58921988b 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -332,8 +332,9 @@ double ShonanAveraging::cost(const Values &values) const { /* ************************************************************************* */ // Get kappa from noise model -template -static double Kappa(const BinaryMeasurement &measurement) { +template +static double Kappa(const BinaryMeasurement &measurement, + const ShonanAveragingParameters ¶meters) { const auto &isotropic = boost::dynamic_pointer_cast( measurement.noiseModel()); double sigma; @@ -343,10 +344,13 @@ static double Kappa(const BinaryMeasurement &measurement) { const auto &robust = boost::dynamic_pointer_cast( measurement.noiseModel()); if (robust) { - std::cout << "Verification of optimality does not work with robust cost " - "function" - << std::endl; - sigma = 1; // setting arbitrary value + if (parameters.getUseHuber()) { + // Cannot verify optimality, setting arbitrary value + sigma = 1; + } else { + throw std::invalid_argument( + "Robust cost function is invalid unless useHuber is set."); + } } else { throw std::invalid_argument( "Shonan averaging noise models must be isotropic (but robust losses " @@ -372,7 +376,7 @@ Sparse ShonanAveraging::buildD() const { const auto &keys = measurement.keys(); // Get kappa from noise model - double kappa = Kappa(measurement); + double kappa = Kappa(measurement, parameters_); const size_t di = d * keys[0], dj = d * keys[1]; for (size_t k = 0; k < d; k++) { @@ -410,7 +414,7 @@ Sparse ShonanAveraging::buildQ() const { const auto Rij = measurement.measured().matrix(); // Get kappa from noise model - double kappa = Kappa(measurement); + double kappa = Kappa(measurement, parameters_); const size_t di = d * keys[0], dj = d * keys[1]; for (size_t r = 0; r < d; r++) { @@ -803,7 +807,8 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, for (size_t p = pMin; p <= pMax; p++) { // Optimize until convergence at this level Qstar = tryOptimizingAt(p, initialSOp); - if(parameters_.useHuber){ // in this case, there is no optimality verification + if (parameters_ + .useHuber) { // in this case, there is no optimality verification if (pMin != pMax) { throw std::runtime_error( "When using robust norm, Shonan only tests a single rank"); From 7125179e4ba318094c4fb6c685e2c774675175ad Mon Sep 17 00:00:00 2001 From: Sushmita Date: Thu, 3 Dec 2020 20:58:51 -0500 Subject: [PATCH 138/261] added cmake and preamble --- gtsam/gtsam.i | 14 ++++++++------ python/CMakeLists.txt | 2 ++ python/gtsam/preamble.h | 2 ++ python/gtsam/specializations.h | 2 ++ 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 8596106e4..127a6fe45 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -1072,18 +1072,19 @@ template class CameraSet { CameraSet(); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // // common STL methods + // size_t size() const; + // bool empty() const; + // void clear(); // structure specific methods T at(size_t i) const; void push_back(const T& cam); }; -typedef gtsam::CameraSet CameraSetCal3_S2; -typedef gtsam::CameraSet CameraSetCal3Bundler; +// typedefs added here for shorter type name and to enforce uniformity in naming conventions +//typedef gtsam::CameraSet CameraSetCal3_S2; +//typedef gtsam::CameraSet CameraSetCal3Bundler; #include class StereoCamera { @@ -1116,6 +1117,7 @@ class StereoCamera { #include +// Templates appear not yet supported for free functions - issue raised at borglab/wrap#14 to add support gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, gtsam::Cal3_S2* sharedCal, const gtsam::Point2Vector& measurements, double rank_tol, bool optimize); diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 00b537340..bfe08a76a 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -82,6 +82,8 @@ set(ignore gtsam::KeyVector gtsam::FixedLagSmootherKeyTimestampMapValue gtsam::BinaryMeasurementsUnit3 + gtsam::CameraSetCal3_S2 + gtsam::CameraSetCal3Bundler gtsam::KeyPairDoubleMap) pybind_wrap(gtsam_unstable_py # target diff --git a/python/gtsam/preamble.h b/python/gtsam/preamble.h index 6166f615e..c8a577431 100644 --- a/python/gtsam/preamble.h +++ b/python/gtsam/preamble.h @@ -10,3 +10,5 @@ PYBIND11_MAKE_OPAQUE(std::vector); PYBIND11_MAKE_OPAQUE(std::vector > >); PYBIND11_MAKE_OPAQUE(std::vector > >); PYBIND11_MAKE_OPAQUE(std::vector); +PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); +PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); \ No newline at end of file diff --git a/python/gtsam/specializations.h b/python/gtsam/specializations.h index cacad874c..431697aac 100644 --- a/python/gtsam/specializations.h +++ b/python/gtsam/specializations.h @@ -13,3 +13,5 @@ py::bind_vector > >(m_, "Bina py::bind_map(m_, "IndexPairSetMap"); py::bind_vector(m_, "IndexPairVector"); py::bind_map(m_, "KeyPairDoubleMap"); +py::bind_vector > >(m_, "CameraSetCal3_S2"); +py::bind_vector > >(m_, "CameraSetCal3Bundler"); From adf3ce557484f9a3937b3d1ae238ddbb16e60ebd Mon Sep 17 00:00:00 2001 From: Sushmita Date: Thu, 3 Dec 2020 20:59:16 -0500 Subject: [PATCH 139/261] moved measurement generation to separate function --- python/gtsam/tests/test_Triangulation.py | 118 ++++++++++------------- 1 file changed, 53 insertions(+), 65 deletions(-) diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index 2a9851d04..c04766804 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -18,104 +18,92 @@ from gtsam import Cal3_S2, Cal3Bundler, Rot3, Pose3, \ PinholeCameraCal3_S2, PinholeCameraCal3Bundler, Point3, \ Point2Vector, Pose3Vector, triangulatePoint3, \ CameraSetCal3_S2, CameraSetCal3Bundler +from numpy.core.records import array class TestVisualISAMExample(GtsamTestCase): + """ Tests for triangulation with shared and individual calibrations """ + def setUp(self): - # Set up two camera poses + """ Set up two camera poses """ # Looking along X-axis, 1 meter above ground plane (x-y) upright = Rot3.Ypr(-np.pi / 2, 0., -np.pi / 2) - self.pose1 = Pose3(upright, Point3(0, 0, 1)) + pose1 = Pose3(upright, Point3(0, 0, 1)) # create second camera 1 meter to the right of first camera - self.pose2 = self.pose1.compose(Pose3(Rot3(), Point3(1, 0, 0))) + pose2 = pose1.compose(Pose3(Rot3(), Point3(1, 0, 0))) + # twoPoses + self.poses = Pose3Vector() + self.poses.append(pose1) + self.poses.append(pose2) # landmark ~5 meters infront of camera self.landmark = Point3(5, 0.5, 1.2) + + def generate_measurements(self, calibration, camera_model, *cal_params): + """ Generate vector of measurements for given calibration and camera model + Args: + calibration: Camera calibration e.g. Cal3_S2 + camera_model: Camera model e.g. PinholeCameraCal3_S2 + cal_params: (list of) camera parameters e.g. K1, K2 + Returns: + vector of measurements and cameras + """ + + cameras = [] + measurements = Point2Vector() + for k, pose in zip(cal_params, self.poses): + K = calibration(*k) + camera = camera_model(pose, K) + cameras.append(camera) + z = camera.project(self.landmark) + measurements.append(z) + + return measurements, cameras def test_TriangulationExample(self): + """ Tests triangulation with shared Cal3_S2 calibration""" # Some common constants - sharedCal = Cal3_S2(1500, 1200, 0, 640, 480) - camera1 = PinholeCameraCal3_S2(self.pose1, sharedCal) - camera2 = PinholeCameraCal3_S2(self.pose2, sharedCal) + sharedCal = (1500, 1200, 0, 640, 480) + measurements, _ = self.generate_measurements(Cal3_S2, PinholeCameraCal3_S2, sharedCal, sharedCal) - # 1. Project two landmarks into two cameras and triangulate - z1 = camera1.project(self.landmark) - z2 = camera2.project(self.landmark) - - # twoPoses - poses = Pose3Vector() - measurements = Point2Vector() - - poses.append(self.pose1) - poses.append(self.pose2) - measurements.append(z1) - measurements.append(z2) - - optimize = True - rank_tol = 1e-9 - - triangulated_landmark = triangulatePoint3(poses,sharedCal, measurements, rank_tol, optimize) + triangulated_landmark = triangulatePoint3(self.poses,Cal3_S2(sharedCal), measurements, rank_tol=1e-9, optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) # 2. Add some noise and try again: result should be ~ (4.995, 0.499167, 1.19814) - measurements = Point2Vector() - measurements.append(z1 - np.array([0.1, 0.5])) - measurements.append(z2 - np.array([-0.2, 0.3])) + measurements_noisy = Point2Vector() + measurements_noisy.append(measurements[0] - np.array([0.1, 0.5])) + measurements_noisy.append(measurements[1] - np.array([-0.2, 0.3])) - triangulated_landmark = triangulatePoint3(poses,sharedCal, measurements, rank_tol, optimize) + triangulated_landmark = triangulatePoint3(self.poses,Cal3_S2(sharedCal), measurements_noisy, rank_tol=1e-9, optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark,1e-2) def test_distinct_Ks(self): + """ Tests triangulation with individual Cal3_S2 calibrations """ # two cameras - K1 = Cal3_S2(1500, 1200, 0, 640, 480) - camera1 = PinholeCameraCal3_S2(self.pose1, K1) - - K2 = Cal3_S2(1600, 1300, 0, 650, 440) - camera2 = PinholeCameraCal3_S2(self.pose2, K2) + K1 = (1500, 1200, 0, 640, 480) + K2 = (1600, 1300, 0, 650, 440) + measurements, camera_list = self.generate_measurements(Cal3_S2, PinholeCameraCal3_S2, K1, K2) cameras = CameraSetCal3_S2() - cameras.push_back(camera1) - cameras.push_back(camera2) + for camera in camera_list: + cameras.append(camera) - # Project two landmarks into two cameras and triangulate - z1 = camera1.project(self.landmark) - z2 = camera2.project(self.landmark) - - measurements = Point2Vector() - measurements.append(z1) - measurements.append(z2) - - optimize = True - rank_tol = 1e-9 - - triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol, optimize) + triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol=1e-9, optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) def test_distinct_Ks_Bundler(self): + """ Tests triangulation with individual Cal3Bundler calibrations""" # two cameras - K1 = Cal3Bundler(1500, 0, 0, 640, 480) - camera1 = PinholeCameraCal3Bundler(self.pose1, K1) - - K2 = Cal3Bundler(1600, 0, 0, 650, 440) - camera2 = PinholeCameraCal3Bundler(self.pose2, K2) + K1 = (1500, 0, 0, 640, 480) + K2 = (1600, 0, 0, 650, 440) + measurements, camera_list = self.generate_measurements(Cal3Bundler, PinholeCameraCal3Bundler, K1, K2) cameras = CameraSetCal3Bundler() - cameras.push_back(camera1) - cameras.push_back(camera2) + for camera in camera_list: + cameras.append(camera) - # Project two landmarks into two cameras and triangulate - z1 = camera1.project(self.landmark) - z2 = camera2.project(self.landmark) - - measurements = Point2Vector() - measurements.append(z1) - measurements.append(z2) - - optimize = True - rank_tol = 1e-9 - - triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol, optimize) + triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol=1e-9, optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) if __name__ == "__main__": From 8be6890b206c761bb1f334f4f7ab6fcfa7ccbff0 Mon Sep 17 00:00:00 2001 From: Sushmita Date: Thu, 3 Dec 2020 21:10:10 -0500 Subject: [PATCH 140/261] code formatted --- gtsam/geometry/triangulation.h | 702 +-- gtsam/gtsam.i | 5372 +++++++++++----------- python/gtsam/preamble.h | 10 +- python/gtsam/specializations.h | 18 +- python/gtsam/tests/test_Triangulation.py | 14 +- 5 files changed, 3155 insertions(+), 2961 deletions(-) diff --git a/gtsam/geometry/triangulation.h b/gtsam/geometry/triangulation.h index 1df9efd22..e22b35e56 100644 --- a/gtsam/geometry/triangulation.h +++ b/gtsam/geometry/triangulation.h @@ -27,49 +27,52 @@ #include #include -namespace gtsam { +namespace gtsam +{ -/// Exception thrown by triangulateDLT when SVD returns rank < 3 -class GTSAM_EXPORT TriangulationUnderconstrainedException: public std::runtime_error { -public: - TriangulationUnderconstrainedException() : - std::runtime_error("Triangulation Underconstrained Exception.") { - } -}; + /// Exception thrown by triangulateDLT when SVD returns rank < 3 + class GTSAM_EXPORT TriangulationUnderconstrainedException : public std::runtime_error + { + public: + TriangulationUnderconstrainedException() : std::runtime_error("Triangulation Underconstrained Exception.") + { + } + }; -/// Exception thrown by triangulateDLT when landmark is behind one or more of the cameras -class GTSAM_EXPORT TriangulationCheiralityException: public std::runtime_error { -public: - TriangulationCheiralityException() : - std::runtime_error( - "Triangulation Cheirality Exception: The resulting landmark is behind one or more cameras.") { - } -}; + /// Exception thrown by triangulateDLT when landmark is behind one or more of the cameras + class GTSAM_EXPORT TriangulationCheiralityException : public std::runtime_error + { + public: + TriangulationCheiralityException() : std::runtime_error( + "Triangulation Cheirality Exception: The resulting landmark is behind one or more cameras.") + { + } + }; -/** + /** * DLT triangulation: See Hartley and Zisserman, 2nd Ed., page 312 * @param projection_matrices Projection matrices (K*P^-1) * @param measurements 2D measurements * @param rank_tol SVD rank tolerance * @return Triangulated point, in homogeneous coordinates */ -GTSAM_EXPORT Vector4 triangulateHomogeneousDLT( - const std::vector>& projection_matrices, - const Point2Vector& measurements, double rank_tol = 1e-9); + GTSAM_EXPORT Vector4 triangulateHomogeneousDLT( + const std::vector> &projection_matrices, + const Point2Vector &measurements, double rank_tol = 1e-9); -/** + /** * DLT triangulation: See Hartley and Zisserman, 2nd Ed., page 312 * @param projection_matrices Projection matrices (K*P^-1) * @param measurements 2D measurements * @param rank_tol SVD rank tolerance * @return Triangulated Point3 */ -GTSAM_EXPORT Point3 triangulateDLT( - const std::vector>& projection_matrices, - const Point2Vector& measurements, - double rank_tol = 1e-9); + GTSAM_EXPORT Point3 triangulateDLT( + const std::vector> &projection_matrices, + const Point2Vector &measurements, + double rank_tol = 1e-9); -/** + /** * Create a factor graph with projection factors from poses and one calibration * @param poses Camera poses * @param sharedCal shared pointer to single calibration object (monocular only!) @@ -78,27 +81,29 @@ GTSAM_EXPORT Point3 triangulateDLT( * @param initialEstimate * @return graph and initial values */ -template -std::pair triangulationGraph( - const std::vector& poses, boost::shared_ptr sharedCal, - const Point2Vector& measurements, Key landmarkKey, - const Point3& initialEstimate) { - Values values; - values.insert(landmarkKey, initialEstimate); // Initial landmark value - NonlinearFactorGraph graph; - static SharedNoiseModel unit2(noiseModel::Unit::Create(2)); - static SharedNoiseModel prior_model(noiseModel::Isotropic::Sigma(6, 1e-6)); - for (size_t i = 0; i < measurements.size(); i++) { - const Pose3& pose_i = poses[i]; - typedef PinholePose Camera; - Camera camera_i(pose_i, sharedCal); - graph.emplace_shared > // - (camera_i, measurements[i], unit2, landmarkKey); + template + std::pair triangulationGraph( + const std::vector &poses, boost::shared_ptr sharedCal, + const Point2Vector &measurements, Key landmarkKey, + const Point3 &initialEstimate) + { + Values values; + values.insert(landmarkKey, initialEstimate); // Initial landmark value + NonlinearFactorGraph graph; + static SharedNoiseModel unit2(noiseModel::Unit::Create(2)); + static SharedNoiseModel prior_model(noiseModel::Isotropic::Sigma(6, 1e-6)); + for (size_t i = 0; i < measurements.size(); i++) + { + const Pose3 &pose_i = poses[i]; + typedef PinholePose Camera; + Camera camera_i(pose_i, sharedCal); + graph.emplace_shared> // + (camera_i, measurements[i], unit2, landmarkKey); + } + return std::make_pair(graph, values); } - return std::make_pair(graph, values); -} -/** + /** * Create a factor graph with projection factors from pinhole cameras * (each camera has a pose and calibration) * @param cameras pinhole cameras (monocular or stereo) @@ -107,35 +112,37 @@ std::pair triangulationGraph( * @param initialEstimate * @return graph and initial values */ -template -std::pair triangulationGraph( - const CameraSet& cameras, - const typename CAMERA::MeasurementVector& measurements, Key landmarkKey, - const Point3& initialEstimate) { - Values values; - values.insert(landmarkKey, initialEstimate); // Initial landmark value - NonlinearFactorGraph graph; - static SharedNoiseModel unit(noiseModel::Unit::Create( - traits::dimension)); - for (size_t i = 0; i < measurements.size(); i++) { - const CAMERA& camera_i = cameras[i]; - graph.emplace_shared > // - (camera_i, measurements[i], unit, landmarkKey); + template + std::pair triangulationGraph( + const CameraSet &cameras, + const typename CAMERA::MeasurementVector &measurements, Key landmarkKey, + const Point3 &initialEstimate) + { + Values values; + values.insert(landmarkKey, initialEstimate); // Initial landmark value + NonlinearFactorGraph graph; + static SharedNoiseModel unit(noiseModel::Unit::Create( + traits::dimension)); + for (size_t i = 0; i < measurements.size(); i++) + { + const CAMERA &camera_i = cameras[i]; + graph.emplace_shared> // + (camera_i, measurements[i], unit, landmarkKey); + } + return std::make_pair(graph, values); } - return std::make_pair(graph, values); -} -/** + /** * Optimize for triangulation * @param graph nonlinear factors for projection * @param values initial values * @param landmarkKey to refer to landmark * @return refined Point3 */ -GTSAM_EXPORT Point3 optimize(const NonlinearFactorGraph& graph, - const Values& values, Key landmarkKey); + GTSAM_EXPORT Point3 optimize(const NonlinearFactorGraph &graph, + const Values &values, Key landmarkKey); -/** + /** * Given an initial estimate , refine a point using measurements in several cameras * @param poses Camera poses * @param sharedCal shared pointer to single calibration object @@ -143,63 +150,69 @@ GTSAM_EXPORT Point3 optimize(const NonlinearFactorGraph& graph, * @param initialEstimate * @return refined Point3 */ -template -Point3 triangulateNonlinear(const std::vector& poses, - boost::shared_ptr sharedCal, - const Point2Vector& measurements, const Point3& initialEstimate) { + template + Point3 triangulateNonlinear(const std::vector &poses, + boost::shared_ptr sharedCal, + const Point2Vector &measurements, const Point3 &initialEstimate) + { - // Create a factor graph and initial values - Values values; - NonlinearFactorGraph graph; - boost::tie(graph, values) = triangulationGraph // - (poses, sharedCal, measurements, Symbol('p', 0), initialEstimate); + // Create a factor graph and initial values + Values values; + NonlinearFactorGraph graph; + boost::tie(graph, values) = triangulationGraph // + (poses, sharedCal, measurements, Symbol('p', 0), initialEstimate); - return optimize(graph, values, Symbol('p', 0)); -} + return optimize(graph, values, Symbol('p', 0)); + } -/** + /** * Given an initial estimate , refine a point using measurements in several cameras * @param cameras pinhole cameras (monocular or stereo) * @param measurements 2D measurements * @param initialEstimate * @return refined Point3 */ -template -Point3 triangulateNonlinear( - const CameraSet& cameras, - const typename CAMERA::MeasurementVector& measurements, const Point3& initialEstimate) { + template + Point3 triangulateNonlinear( + const CameraSet &cameras, + const typename CAMERA::MeasurementVector &measurements, const Point3 &initialEstimate) + { - // Create a factor graph and initial values - Values values; - NonlinearFactorGraph graph; - boost::tie(graph, values) = triangulationGraph // - (cameras, measurements, Symbol('p', 0), initialEstimate); + // Create a factor graph and initial values + Values values; + NonlinearFactorGraph graph; + boost::tie(graph, values) = triangulationGraph // + (cameras, measurements, Symbol('p', 0), initialEstimate); - return optimize(graph, values, Symbol('p', 0)); -} + return optimize(graph, values, Symbol('p', 0)); + } -/** + /** * Create a 3*4 camera projection matrix from calibration and pose. * Functor for partial application on calibration * @param pose The camera pose * @param cal The calibration * @return Returns a Matrix34 */ -template -struct CameraProjectionMatrix { - CameraProjectionMatrix(const CALIBRATION& calibration) : - K_(calibration.K()) { - } - Matrix34 operator()(const Pose3& pose) const { - return K_ * (pose.inverse().matrix()).block<3, 4>(0, 0); - } -private: - const Matrix3 K_; -public: - GTSAM_MAKE_ALIGNED_OPERATOR_NEW -}; + template + struct CameraProjectionMatrix + { + CameraProjectionMatrix(const CALIBRATION &calibration) : K_(calibration.K()) + { + } + Matrix34 operator()(const Pose3 &pose) const + { + return K_ * (pose.inverse().matrix()).block<3, 4>(0, 0); + } -/** + private: + const Matrix3 K_; + + public: + GTSAM_MAKE_ALIGNED_OPERATOR_NEW + }; + + /** * Function to triangulate 3D landmark point from an arbitrary number * of poses (at least 2) using the DLT. The function checks that the * resulting point lies in front of all cameras, but has no other checks @@ -211,43 +224,45 @@ public: * @param optimize Flag to turn on nonlinear refinement of triangulation * @return Returns a Point3 */ -template -Point3 triangulatePoint3(const std::vector& poses, - boost::shared_ptr sharedCal, - const Point2Vector& measurements, double rank_tol = 1e-9, - bool optimize = false) { + template + Point3 triangulatePoint3(const std::vector &poses, + boost::shared_ptr sharedCal, + const Point2Vector &measurements, double rank_tol = 1e-9, + bool optimize = false) + { - assert(poses.size() == measurements.size()); - if (poses.size() < 2) - throw(TriangulationUnderconstrainedException()); + assert(poses.size() == measurements.size()); + if (poses.size() < 2) + throw(TriangulationUnderconstrainedException()); - // construct projection matrices from poses & calibration - std::vector> projection_matrices; - CameraProjectionMatrix createP(*sharedCal); // partially apply - for(const Pose3& pose: poses) - projection_matrices.push_back(createP(pose)); + // construct projection matrices from poses & calibration + std::vector> projection_matrices; + CameraProjectionMatrix createP(*sharedCal); // partially apply + for (const Pose3 &pose : poses) + projection_matrices.push_back(createP(pose)); - // Triangulate linearly - Point3 point = triangulateDLT(projection_matrices, measurements, rank_tol); + // Triangulate linearly + Point3 point = triangulateDLT(projection_matrices, measurements, rank_tol); - // Then refine using non-linear optimization - if (optimize) - point = triangulateNonlinear // - (poses, sharedCal, measurements, point); + // Then refine using non-linear optimization + if (optimize) + point = triangulateNonlinear // + (poses, sharedCal, measurements, point); #ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION - // verify that the triangulated point lies in front of all cameras - for(const Pose3& pose: poses) { - const Point3& p_local = pose.transformTo(point); - if (p_local.z() <= 0) - throw(TriangulationCheiralityException()); - } + // verify that the triangulated point lies in front of all cameras + for (const Pose3 &pose : poses) + { + const Point3 &p_local = pose.transformTo(point); + if (p_local.z() <= 0) + throw(TriangulationCheiralityException()); + } #endif - return point; -} + return point; + } -/** + /** * Function to triangulate 3D landmark point from an arbitrary number * of poses (at least 2) using the DLT. This function is similar to the one * above, except that each camera has its own calibration. The function @@ -259,72 +274,76 @@ Point3 triangulatePoint3(const std::vector& poses, * @param optimize Flag to turn on nonlinear refinement of triangulation * @return Returns a Point3 */ -template -Point3 triangulatePoint3( - const CameraSet& cameras, - const typename CAMERA::MeasurementVector& measurements, double rank_tol = 1e-9, - bool optimize = false) { + template + Point3 triangulatePoint3( + const CameraSet &cameras, + const typename CAMERA::MeasurementVector &measurements, double rank_tol = 1e-9, + bool optimize = false) + { - size_t m = cameras.size(); - assert(measurements.size() == m); + size_t m = cameras.size(); + assert(measurements.size() == m); - if (m < 2) - throw(TriangulationUnderconstrainedException()); + if (m < 2) + throw(TriangulationUnderconstrainedException()); - // construct projection matrices from poses & calibration - std::vector> projection_matrices; - for(const CAMERA& camera: cameras) - projection_matrices.push_back( - CameraProjectionMatrix(camera.calibration())( - camera.pose())); - Point3 point = triangulateDLT(projection_matrices, measurements, rank_tol); + // construct projection matrices from poses & calibration + std::vector> projection_matrices; + for (const CAMERA &camera : cameras) + projection_matrices.push_back( + CameraProjectionMatrix(camera.calibration())( + camera.pose())); + Point3 point = triangulateDLT(projection_matrices, measurements, rank_tol); - // The n refine using non-linear optimization - if (optimize) - point = triangulateNonlinear(cameras, measurements, point); + // The n refine using non-linear optimization + if (optimize) + point = triangulateNonlinear(cameras, measurements, point); #ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION - // verify that the triangulated point lies in front of all cameras - for(const CAMERA& camera: cameras) { - const Point3& p_local = camera.pose().transformTo(point); - if (p_local.z() <= 0) - throw(TriangulationCheiralityException()); - } + // verify that the triangulated point lies in front of all cameras + for (const CAMERA &camera : cameras) + { + const Point3 &p_local = camera.pose().transformTo(point); + if (p_local.z() <= 0) + throw(TriangulationCheiralityException()); + } #endif - return point; -} + return point; + } -/// Pinhole-specific version -template -Point3 triangulatePoint3( - const CameraSet >& cameras, - const Point2Vector& measurements, double rank_tol = 1e-9, - bool optimize = false) { - return triangulatePoint3 > // - (cameras, measurements, rank_tol, optimize); -} + /// Pinhole-specific version + template + Point3 triangulatePoint3( + const CameraSet> &cameras, + const Point2Vector &measurements, double rank_tol = 1e-9, + bool optimize = false) + { + return triangulatePoint3> // + (cameras, measurements, rank_tol, optimize); + } -struct GTSAM_EXPORT TriangulationParameters { + struct GTSAM_EXPORT TriangulationParameters + { - double rankTolerance; ///< threshold to decide whether triangulation is result.degenerate - ///< (the rank is the number of singular values of the triangulation matrix which are larger than rankTolerance) - bool enableEPI; ///< if set to true, will refine triangulation using LM + double rankTolerance; ///< threshold to decide whether triangulation is result.degenerate + ///< (the rank is the number of singular values of the triangulation matrix which are larger than rankTolerance) + bool enableEPI; ///< if set to true, will refine triangulation using LM - /** + /** * if the landmark is triangulated at distance larger than this, * result is flagged as degenerate. */ - double landmarkDistanceThreshold; // + double landmarkDistanceThreshold; // - /** + /** * If this is nonnegative the we will check if the average reprojection error * is smaller than this threshold after triangulation, otherwise result is * flagged as degenerate. */ - double dynamicOutlierRejectionThreshold; + double dynamicOutlierRejectionThreshold; - /** + /** * Constructor * @param rankTol tolerance used to check if point triangulation is degenerate * @param enableEPI if true refine triangulation with embedded LM iterations @@ -332,173 +351,194 @@ struct GTSAM_EXPORT TriangulationParameters { * @param dynamicOutlierRejectionThreshold or if average error larger than this * */ - TriangulationParameters(const double _rankTolerance = 1.0, - const bool _enableEPI = false, double _landmarkDistanceThreshold = -1, - double _dynamicOutlierRejectionThreshold = -1) : - rankTolerance(_rankTolerance), enableEPI(_enableEPI), // - landmarkDistanceThreshold(_landmarkDistanceThreshold), // - dynamicOutlierRejectionThreshold(_dynamicOutlierRejectionThreshold) { - } + TriangulationParameters(const double _rankTolerance = 1.0, + const bool _enableEPI = false, double _landmarkDistanceThreshold = -1, + double _dynamicOutlierRejectionThreshold = -1) : rankTolerance(_rankTolerance), enableEPI(_enableEPI), // + landmarkDistanceThreshold(_landmarkDistanceThreshold), // + dynamicOutlierRejectionThreshold(_dynamicOutlierRejectionThreshold) + { + } - // stream to output - friend std::ostream &operator<<(std::ostream &os, - const TriangulationParameters& p) { - os << "rankTolerance = " << p.rankTolerance << std::endl; - os << "enableEPI = " << p.enableEPI << std::endl; - os << "landmarkDistanceThreshold = " << p.landmarkDistanceThreshold - << std::endl; - os << "dynamicOutlierRejectionThreshold = " - << p.dynamicOutlierRejectionThreshold << std::endl; - return os; - } + // stream to output + friend std::ostream &operator<<(std::ostream &os, + const TriangulationParameters &p) + { + os << "rankTolerance = " << p.rankTolerance << std::endl; + os << "enableEPI = " << p.enableEPI << std::endl; + os << "landmarkDistanceThreshold = " << p.landmarkDistanceThreshold + << std::endl; + os << "dynamicOutlierRejectionThreshold = " + << p.dynamicOutlierRejectionThreshold << std::endl; + return os; + } -private: + private: + /// Serialization function + friend class boost::serialization::access; + template + void serialize(ARCHIVE &ar, const unsigned int version) + { + ar &BOOST_SERIALIZATION_NVP(rankTolerance); + ar &BOOST_SERIALIZATION_NVP(enableEPI); + ar &BOOST_SERIALIZATION_NVP(landmarkDistanceThreshold); + ar &BOOST_SERIALIZATION_NVP(dynamicOutlierRejectionThreshold); + } + }; - /// Serialization function - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(rankTolerance); - ar & BOOST_SERIALIZATION_NVP(enableEPI); - ar & BOOST_SERIALIZATION_NVP(landmarkDistanceThreshold); - ar & BOOST_SERIALIZATION_NVP(dynamicOutlierRejectionThreshold); - } -}; - -/** + /** * TriangulationResult is an optional point, along with the reasons why it is invalid. */ -class TriangulationResult: public boost::optional { - enum Status { - VALID, DEGENERATE, BEHIND_CAMERA, OUTLIER, FAR_POINT - }; - Status status_; - TriangulationResult(Status s) : - status_(s) { - } -public: + class TriangulationResult : public boost::optional + { + enum Status + { + VALID, + DEGENERATE, + BEHIND_CAMERA, + OUTLIER, + FAR_POINT + }; + Status status_; + TriangulationResult(Status s) : status_(s) + { + } - /** + public: + /** * Default constructor, only for serialization */ - TriangulationResult() {} + TriangulationResult() {} - /** + /** * Constructor */ - TriangulationResult(const Point3& p) : - status_(VALID) { - reset(p); - } - static TriangulationResult Degenerate() { - return TriangulationResult(DEGENERATE); - } - static TriangulationResult Outlier() { - return TriangulationResult(OUTLIER); - } - static TriangulationResult FarPoint() { - return TriangulationResult(FAR_POINT); - } - static TriangulationResult BehindCamera() { - return TriangulationResult(BEHIND_CAMERA); - } - bool valid() const { - return status_ == VALID; - } - bool degenerate() const { - return status_ == DEGENERATE; - } - bool outlier() const { - return status_ == OUTLIER; - } - bool farPoint() const { - return status_ == FAR_POINT; - } - bool behindCamera() const { - return status_ == BEHIND_CAMERA; - } - // stream to output - friend std::ostream &operator<<(std::ostream &os, - const TriangulationResult& result) { - if (result) - os << "point = " << *result << std::endl; - else - os << "no point, status = " << result.status_ << std::endl; - return os; - } - -private: - - /// Serialization function - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int version) { - ar & BOOST_SERIALIZATION_NVP(status_); - } -}; - -/// triangulateSafe: extensive checking of the outcome -template -TriangulationResult triangulateSafe(const CameraSet& cameras, - const typename CAMERA::MeasurementVector& measured, - const TriangulationParameters& params) { - - size_t m = cameras.size(); - - // if we have a single pose the corresponding factor is uninformative - if (m < 2) - return TriangulationResult::Degenerate(); - else - // We triangulate the 3D position of the landmark - try { - Point3 point = triangulatePoint3(cameras, measured, - params.rankTolerance, params.enableEPI); - - // Check landmark distance and re-projection errors to avoid outliers - size_t i = 0; - double maxReprojError = 0.0; - for(const CAMERA& camera: cameras) { - const Pose3& pose = camera.pose(); - if (params.landmarkDistanceThreshold > 0 - && distance3(pose.translation(), point) - > params.landmarkDistanceThreshold) - return TriangulationResult::FarPoint(); -#ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION - // verify that the triangulated point lies in front of all cameras - // Only needed if this was not yet handled by exception - const Point3& p_local = pose.transformTo(point); - if (p_local.z() <= 0) - return TriangulationResult::BehindCamera(); -#endif - // Check reprojection error - if (params.dynamicOutlierRejectionThreshold > 0) { - const Point2& zi = measured.at(i); - Point2 reprojectionError(camera.project(point) - zi); - maxReprojError = std::max(maxReprojError, reprojectionError.norm()); - } - i += 1; - } - // Flag as degenerate if average reprojection error is too large - if (params.dynamicOutlierRejectionThreshold > 0 - && maxReprojError > params.dynamicOutlierRejectionThreshold) - return TriangulationResult::Outlier(); - - // all good! - return TriangulationResult(point); - } catch (TriangulationUnderconstrainedException&) { - // This exception is thrown if - // 1) There is a single pose for triangulation - this should not happen because we checked the number of poses before - // 2) The rank of the matrix used for triangulation is < 3: rotation-only, parallel cameras (or motion towards the landmark) - return TriangulationResult::Degenerate(); - } catch (TriangulationCheiralityException&) { - // point is behind one of the cameras: can be the case of close-to-parallel cameras or may depend on outliers - return TriangulationResult::BehindCamera(); + TriangulationResult(const Point3 &p) : status_(VALID) + { + reset(p); + } + static TriangulationResult Degenerate() + { + return TriangulationResult(DEGENERATE); + } + static TriangulationResult Outlier() + { + return TriangulationResult(OUTLIER); + } + static TriangulationResult FarPoint() + { + return TriangulationResult(FAR_POINT); + } + static TriangulationResult BehindCamera() + { + return TriangulationResult(BEHIND_CAMERA); + } + bool valid() const + { + return status_ == VALID; + } + bool degenerate() const + { + return status_ == DEGENERATE; + } + bool outlier() const + { + return status_ == OUTLIER; + } + bool farPoint() const + { + return status_ == FAR_POINT; + } + bool behindCamera() const + { + return status_ == BEHIND_CAMERA; + } + // stream to output + friend std::ostream &operator<<(std::ostream &os, + const TriangulationResult &result) + { + if (result) + os << "point = " << *result << std::endl; + else + os << "no point, status = " << result.status_ << std::endl; + return os; } -} -// Vector of Cameras - used by the Python/MATLAB wrapper -using CameraSetCal3Bundler = CameraSet>; -using CameraSetCal3_S2 = CameraSet>; + private: + /// Serialization function + friend class boost::serialization::access; + template + void serialize(ARCHIVE &ar, const unsigned int version) + { + ar &BOOST_SERIALIZATION_NVP(status_); + } + }; -} // \namespace gtsam + /// triangulateSafe: extensive checking of the outcome + template + TriangulationResult triangulateSafe(const CameraSet &cameras, + const typename CAMERA::MeasurementVector &measured, + const TriangulationParameters ¶ms) + { + size_t m = cameras.size(); + + // if we have a single pose the corresponding factor is uninformative + if (m < 2) + return TriangulationResult::Degenerate(); + else + // We triangulate the 3D position of the landmark + try + { + Point3 point = triangulatePoint3(cameras, measured, + params.rankTolerance, params.enableEPI); + + // Check landmark distance and re-projection errors to avoid outliers + size_t i = 0; + double maxReprojError = 0.0; + for (const CAMERA &camera : cameras) + { + const Pose3 &pose = camera.pose(); + if (params.landmarkDistanceThreshold > 0 && distance3(pose.translation(), point) > params.landmarkDistanceThreshold) + return TriangulationResult::FarPoint(); +#ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION + // verify that the triangulated point lies in front of all cameras + // Only needed if this was not yet handled by exception + const Point3 &p_local = pose.transformTo(point); + if (p_local.z() <= 0) + return TriangulationResult::BehindCamera(); +#endif + // Check reprojection error + if (params.dynamicOutlierRejectionThreshold > 0) + { + const Point2 &zi = measured.at(i); + Point2 reprojectionError(camera.project(point) - zi); + maxReprojError = std::max(maxReprojError, reprojectionError.norm()); + } + i += 1; + } + // Flag as degenerate if average reprojection error is too large + if (params.dynamicOutlierRejectionThreshold > 0 && maxReprojError > params.dynamicOutlierRejectionThreshold) + return TriangulationResult::Outlier(); + + // all good! + return TriangulationResult(point); + } + catch (TriangulationUnderconstrainedException &) + { + // This exception is thrown if + // 1) There is a single pose for triangulation - this should not happen because we checked the number of poses before + // 2) The rank of the matrix used for triangulation is < 3: rotation-only, parallel cameras (or motion towards the landmark) + return TriangulationResult::Degenerate(); + } + catch (TriangulationCheiralityException &) + { + // point is behind one of the cameras: can be the case of close-to-parallel cameras or may depend on outliers + return TriangulationResult::BehindCamera(); + } + } + + // Vector of Cameras - used by the Python/MATLAB wrapper + using CameraSetCal3Bundler = CameraSet>; + using CameraSetCal3_S2 = CameraSet>; + +} // namespace gtsam diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 127a6fe45..1ab2425ec 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -118,1140 +118,1176 @@ * - TODO: Add generalized serialization support via boost.serialization with hooks to matlab save/load */ -namespace gtsam { +namespace gtsam +{ // Actually a FastList #include -class KeyList { - KeyList(); - KeyList(const gtsam::KeyList& other); + class KeyList + { + KeyList(); + KeyList(const gtsam::KeyList &other); - // Note: no print function + // Note: no print function - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - size_t front() const; - size_t back() const; - void push_back(size_t key); - void push_front(size_t key); - void pop_back(); - void pop_front(); - void sort(); - void remove(size_t key); + // structure specific methods + size_t front() const; + size_t back() const; + void push_back(size_t key); + void push_front(size_t key); + void pop_back(); + void pop_front(); + void sort(); + void remove(size_t key); - void serialize() const; -}; + void serialize() const; + }; -// Actually a FastSet -class KeySet { - KeySet(); - KeySet(const gtsam::KeySet& set); - KeySet(const gtsam::KeyVector& vector); - KeySet(const gtsam::KeyList& list); + // Actually a FastSet + class KeySet + { + KeySet(); + KeySet(const gtsam::KeySet &set); + KeySet(const gtsam::KeyVector &vector); + KeySet(const gtsam::KeyList &list); - // Testable - void print(string s) const; - bool equals(const gtsam::KeySet& other) const; + // Testable + void print(string s) const; + bool equals(const gtsam::KeySet &other) const; - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - void insert(size_t key); - void merge(const gtsam::KeySet& other); - bool erase(size_t key); // returns true if value was removed - bool count(size_t key) const; // returns true if value exists + // structure specific methods + void insert(size_t key); + void merge(const gtsam::KeySet &other); + bool erase(size_t key); // returns true if value was removed + bool count(size_t key) const; // returns true if value exists - void serialize() const; -}; + void serialize() const; + }; -// Actually a vector -class KeyVector { - KeyVector(); - KeyVector(const gtsam::KeyVector& other); + // Actually a vector + class KeyVector + { + KeyVector(); + KeyVector(const gtsam::KeyVector &other); - // Note: no print function + // Note: no print function - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - size_t at(size_t i) const; - size_t front() const; - size_t back() const; - void push_back(size_t key) const; + // structure specific methods + size_t at(size_t i) const; + size_t front() const; + size_t back() const; + void push_back(size_t key) const; - void serialize() const; -}; + void serialize() const; + }; -// Actually a FastMap -class KeyGroupMap { - KeyGroupMap(); + // Actually a FastMap + class KeyGroupMap + { + KeyGroupMap(); - // Note: no print function + // Note: no print function - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - size_t at(size_t key) const; - int erase(size_t key); - bool insert2(size_t key, int val); -}; + // structure specific methods + size_t at(size_t key) const; + int erase(size_t key); + bool insert2(size_t key, int val); + }; -// Actually a FastSet -class FactorIndexSet { - FactorIndexSet(); - FactorIndexSet(const gtsam::FactorIndexSet& set); + // Actually a FastSet + class FactorIndexSet + { + FactorIndexSet(); + FactorIndexSet(const gtsam::FactorIndexSet &set); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - void insert(size_t factorIndex); - bool erase(size_t factorIndex); // returns true if value was removed - bool count(size_t factorIndex) const; // returns true if value exists -}; + // structure specific methods + void insert(size_t factorIndex); + bool erase(size_t factorIndex); // returns true if value was removed + bool count(size_t factorIndex) const; // returns true if value exists + }; -// Actually a vector -class FactorIndices { - FactorIndices(); - FactorIndices(const gtsam::FactorIndices& other); + // Actually a vector + class FactorIndices + { + FactorIndices(); + FactorIndices(const gtsam::FactorIndices &other); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - size_t at(size_t i) const; - size_t front() const; - size_t back() const; - void push_back(size_t factorIndex) const; -}; + // structure specific methods + size_t at(size_t i) const; + size_t front() const; + size_t back() const; + void push_back(size_t factorIndex) const; + }; -//************************************************************************* -// base -//************************************************************************* + //************************************************************************* + // base + //************************************************************************* -/** gtsam namespace functions */ + /** gtsam namespace functions */ #include -bool isDebugVersion(); + bool isDebugVersion(); #include -class IndexPair { - IndexPair(); - IndexPair(size_t i, size_t j); - size_t i() const; - size_t j() const; -}; + class IndexPair + { + IndexPair(); + IndexPair(size_t i, size_t j); + size_t i() const; + size_t j() const; + }; -// template -// class DSFMap { -// DSFMap(); -// KEY find(const KEY& key) const; -// void merge(const KEY& x, const KEY& y); -// std::map sets(); -// }; + // template + // class DSFMap { + // DSFMap(); + // KEY find(const KEY& key) const; + // void merge(const KEY& x, const KEY& y); + // std::map sets(); + // }; -class IndexPairSet { - IndexPairSet(); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + class IndexPairSet + { + IndexPairSet(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - void insert(gtsam::IndexPair key); - bool erase(gtsam::IndexPair key); // returns true if value was removed - bool count(gtsam::IndexPair key) const; // returns true if value exists -}; + // structure specific methods + void insert(gtsam::IndexPair key); + bool erase(gtsam::IndexPair key); // returns true if value was removed + bool count(gtsam::IndexPair key) const; // returns true if value exists + }; -class IndexPairVector { - IndexPairVector(); - IndexPairVector(const gtsam::IndexPairVector& other); + class IndexPairVector + { + IndexPairVector(); + IndexPairVector(const gtsam::IndexPairVector &other); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - gtsam::IndexPair at(size_t i) const; - void push_back(gtsam::IndexPair key) const; -}; + // structure specific methods + gtsam::IndexPair at(size_t i) const; + void push_back(gtsam::IndexPair key) const; + }; -gtsam::IndexPairVector IndexPairSetAsArray(gtsam::IndexPairSet& set); + gtsam::IndexPairVector IndexPairSetAsArray(gtsam::IndexPairSet &set); -class IndexPairSetMap { - IndexPairSetMap(); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + class IndexPairSetMap + { + IndexPairSetMap(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - gtsam::IndexPairSet at(gtsam::IndexPair& key); -}; + // structure specific methods + gtsam::IndexPairSet at(gtsam::IndexPair &key); + }; -class DSFMapIndexPair { - DSFMapIndexPair(); - gtsam::IndexPair find(const gtsam::IndexPair& key) const; - void merge(const gtsam::IndexPair& x, const gtsam::IndexPair& y); - gtsam::IndexPairSetMap sets(); -}; + class DSFMapIndexPair + { + DSFMapIndexPair(); + gtsam::IndexPair find(const gtsam::IndexPair &key) const; + void merge(const gtsam::IndexPair &x, const gtsam::IndexPair &y); + gtsam::IndexPairSetMap sets(); + }; #include -bool linear_independent(Matrix A, Matrix B, double tol); + bool linear_independent(Matrix A, Matrix B, double tol); #include -virtual class Value { - // No constructors because this is an abstract class + virtual class Value + { + // No constructors because this is an abstract class - // Testable - void print(string s) const; + // Testable + void print(string s) const; - // Manifold - size_t dim() const; -}; + // Manifold + size_t dim() const; + }; #include -template -virtual class GenericValue : gtsam::Value { - void serializable() const; -}; + template + virtual class GenericValue : gtsam::Value + { + void serializable() const; + }; -//************************************************************************* -// geometry -//************************************************************************* + //************************************************************************* + // geometry + //************************************************************************* #include -class Point2 { - // Standard Constructors - Point2(); - Point2(double x, double y); - Point2(Vector v); + class Point2 + { + // Standard Constructors + Point2(); + Point2(double x, double y); + Point2(Vector v); - // Testable - void print(string s) const; - bool equals(const gtsam::Point2& point, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Point2 &point, double tol) const; - // Group - static gtsam::Point2 identity(); + // Group + static gtsam::Point2 identity(); - // Standard Interface - double x() const; - double y() const; - Vector vector() const; - double distance(const gtsam::Point2& p2) const; - double norm() const; + // Standard Interface + double x() const; + double y() const; + Vector vector() const; + double distance(const gtsam::Point2 &p2) const; + double norm() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; // std::vector #include -class Point2Vector -{ - // Constructors - Point2Vector(); - Point2Vector(const gtsam::Point2Vector& v); + class Point2Vector + { + // Constructors + Point2Vector(); + Point2Vector(const gtsam::Point2Vector &v); - //Capacity - size_t size() const; - size_t max_size() const; - void resize(size_t sz); - size_t capacity() const; - bool empty() const; - void reserve(size_t n); + //Capacity + size_t size() const; + size_t max_size() const; + void resize(size_t sz); + size_t capacity() const; + bool empty() const; + void reserve(size_t n); - //Element access - gtsam::Point2 at(size_t n) const; - gtsam::Point2 front() const; - gtsam::Point2 back() const; + //Element access + gtsam::Point2 at(size_t n) const; + gtsam::Point2 front() const; + gtsam::Point2 back() const; - //Modifiers - void assign(size_t n, const gtsam::Point2& u); - void push_back(const gtsam::Point2& x); - void pop_back(); -}; + //Modifiers + void assign(size_t n, const gtsam::Point2 &u); + void push_back(const gtsam::Point2 &x); + void pop_back(); + }; #include -class StereoPoint2 { - // Standard Constructors - StereoPoint2(); - StereoPoint2(double uL, double uR, double v); + class StereoPoint2 + { + // Standard Constructors + StereoPoint2(); + StereoPoint2(double uL, double uR, double v); - // Testable - void print(string s) const; - bool equals(const gtsam::StereoPoint2& point, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::StereoPoint2 &point, double tol) const; - // Group - static gtsam::StereoPoint2 identity(); - gtsam::StereoPoint2 inverse() const; - gtsam::StereoPoint2 compose(const gtsam::StereoPoint2& p2) const; - gtsam::StereoPoint2 between(const gtsam::StereoPoint2& p2) const; + // Group + static gtsam::StereoPoint2 identity(); + gtsam::StereoPoint2 inverse() const; + gtsam::StereoPoint2 compose(const gtsam::StereoPoint2 &p2) const; + gtsam::StereoPoint2 between(const gtsam::StereoPoint2 &p2) const; - // Manifold - gtsam::StereoPoint2 retract(Vector v) const; - Vector localCoordinates(const gtsam::StereoPoint2& p) const; + // Manifold + gtsam::StereoPoint2 retract(Vector v) const; + Vector localCoordinates(const gtsam::StereoPoint2 &p) const; - // Lie Group - static gtsam::StereoPoint2 Expmap(Vector v); - static Vector Logmap(const gtsam::StereoPoint2& p); + // Lie Group + static gtsam::StereoPoint2 Expmap(Vector v); + static Vector Logmap(const gtsam::StereoPoint2 &p); - // Standard Interface - Vector vector() const; - double uL() const; - double uR() const; - double v() const; + // Standard Interface + Vector vector() const; + double uL() const; + double uR() const; + double v() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -class Point3 { - // Standard Constructors - Point3(); - Point3(double x, double y, double z); - Point3(Vector v); + class Point3 + { + // Standard Constructors + Point3(); + Point3(double x, double y, double z); + Point3(Vector v); - // Testable - void print(string s) const; - bool equals(const gtsam::Point3& p, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Point3 &p, double tol) const; - // Group - static gtsam::Point3 identity(); + // Group + static gtsam::Point3 identity(); - // Standard Interface - Vector vector() const; - double x() const; - double y() const; - double z() const; + // Standard Interface + Vector vector() const; + double x() const; + double y() const; + double z() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -class Rot2 { - // Standard Constructors and Named Constructors - Rot2(); - Rot2(double theta); - static gtsam::Rot2 fromAngle(double theta); - static gtsam::Rot2 fromDegrees(double theta); - static gtsam::Rot2 fromCosSin(double c, double s); + class Rot2 + { + // Standard Constructors and Named Constructors + Rot2(); + Rot2(double theta); + static gtsam::Rot2 fromAngle(double theta); + static gtsam::Rot2 fromDegrees(double theta); + static gtsam::Rot2 fromCosSin(double c, double s); - // Testable - void print(string s) const; - bool equals(const gtsam::Rot2& rot, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Rot2 &rot, double tol) const; - // Group - static gtsam::Rot2 identity(); - gtsam::Rot2 inverse(); - gtsam::Rot2 compose(const gtsam::Rot2& p2) const; - gtsam::Rot2 between(const gtsam::Rot2& p2) const; + // Group + static gtsam::Rot2 identity(); + gtsam::Rot2 inverse(); + gtsam::Rot2 compose(const gtsam::Rot2 &p2) const; + gtsam::Rot2 between(const gtsam::Rot2 &p2) const; - // Manifold - gtsam::Rot2 retract(Vector v) const; - Vector localCoordinates(const gtsam::Rot2& p) const; + // Manifold + gtsam::Rot2 retract(Vector v) const; + Vector localCoordinates(const gtsam::Rot2 &p) const; - // Lie Group - static gtsam::Rot2 Expmap(Vector v); - static Vector Logmap(const gtsam::Rot2& p); - Vector logmap(const gtsam::Rot2& p); + // Lie Group + static gtsam::Rot2 Expmap(Vector v); + static Vector Logmap(const gtsam::Rot2 &p); + Vector logmap(const gtsam::Rot2 &p); - // Group Action on Point2 - gtsam::Point2 rotate(const gtsam::Point2& point) const; - gtsam::Point2 unrotate(const gtsam::Point2& point) const; + // Group Action on Point2 + gtsam::Point2 rotate(const gtsam::Point2 &point) const; + gtsam::Point2 unrotate(const gtsam::Point2 &point) const; - // Standard Interface - static gtsam::Rot2 relativeBearing(const gtsam::Point2& d); // Ignoring derivative - static gtsam::Rot2 atan2(double y, double x); - double theta() const; - double degrees() const; - double c() const; - double s() const; - Matrix matrix() const; + // Standard Interface + static gtsam::Rot2 relativeBearing(const gtsam::Point2 &d); // Ignoring derivative + static gtsam::Rot2 atan2(double y, double x); + double theta() const; + double degrees() const; + double c() const; + double s() const; + Matrix matrix() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -class SO3 { - // Standard Constructors - SO3(); - SO3(Matrix R); - static gtsam::SO3 FromMatrix(Matrix R); - static gtsam::SO3 AxisAngle(const Vector axis, double theta); - static gtsam::SO3 ClosestTo(const Matrix M); + class SO3 + { + // Standard Constructors + SO3(); + SO3(Matrix R); + static gtsam::SO3 FromMatrix(Matrix R); + static gtsam::SO3 AxisAngle(const Vector axis, double theta); + static gtsam::SO3 ClosestTo(const Matrix M); - // Testable - void print(string s) const; - bool equals(const gtsam::SO3& other, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::SO3 &other, double tol) const; - // Group - static gtsam::SO3 identity(); - gtsam::SO3 inverse() const; - gtsam::SO3 between(const gtsam::SO3& R) const; - gtsam::SO3 compose(const gtsam::SO3& R) const; + // Group + static gtsam::SO3 identity(); + gtsam::SO3 inverse() const; + gtsam::SO3 between(const gtsam::SO3 &R) const; + gtsam::SO3 compose(const gtsam::SO3 &R) const; - // Manifold - gtsam::SO3 retract(Vector v) const; - Vector localCoordinates(const gtsam::SO3& R) const; - static gtsam::SO3 Expmap(Vector v); + // Manifold + gtsam::SO3 retract(Vector v) const; + Vector localCoordinates(const gtsam::SO3 &R) const; + static gtsam::SO3 Expmap(Vector v); - // Other methods - Vector vec() const; - Matrix matrix() const; -}; + // Other methods + Vector vec() const; + Matrix matrix() const; + }; #include -class SO4 { - // Standard Constructors - SO4(); - SO4(Matrix R); - static gtsam::SO4 FromMatrix(Matrix R); + class SO4 + { + // Standard Constructors + SO4(); + SO4(Matrix R); + static gtsam::SO4 FromMatrix(Matrix R); - // Testable - void print(string s) const; - bool equals(const gtsam::SO4& other, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::SO4 &other, double tol) const; - // Group - static gtsam::SO4 identity(); - gtsam::SO4 inverse() const; - gtsam::SO4 between(const gtsam::SO4& Q) const; - gtsam::SO4 compose(const gtsam::SO4& Q) const; + // Group + static gtsam::SO4 identity(); + gtsam::SO4 inverse() const; + gtsam::SO4 between(const gtsam::SO4 &Q) const; + gtsam::SO4 compose(const gtsam::SO4 &Q) const; - // Manifold - gtsam::SO4 retract(Vector v) const; - Vector localCoordinates(const gtsam::SO4& Q) const; - static gtsam::SO4 Expmap(Vector v); + // Manifold + gtsam::SO4 retract(Vector v) const; + Vector localCoordinates(const gtsam::SO4 &Q) const; + static gtsam::SO4 Expmap(Vector v); - // Other methods - Vector vec() const; - Matrix matrix() const; -}; + // Other methods + Vector vec() const; + Matrix matrix() const; + }; #include -class SOn { - // Standard Constructors - SOn(size_t n); - static gtsam::SOn FromMatrix(Matrix R); - static gtsam::SOn Lift(size_t n, Matrix R); + class SOn + { + // Standard Constructors + SOn(size_t n); + static gtsam::SOn FromMatrix(Matrix R); + static gtsam::SOn Lift(size_t n, Matrix R); - // Testable - void print(string s) const; - bool equals(const gtsam::SOn& other, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::SOn &other, double tol) const; - // Group - static gtsam::SOn identity(); - gtsam::SOn inverse() const; - gtsam::SOn between(const gtsam::SOn& Q) const; - gtsam::SOn compose(const gtsam::SOn& Q) const; + // Group + static gtsam::SOn identity(); + gtsam::SOn inverse() const; + gtsam::SOn between(const gtsam::SOn &Q) const; + gtsam::SOn compose(const gtsam::SOn &Q) const; - // Manifold - gtsam::SOn retract(Vector v) const; - Vector localCoordinates(const gtsam::SOn& Q) const; - static gtsam::SOn Expmap(Vector v); + // Manifold + gtsam::SOn retract(Vector v) const; + Vector localCoordinates(const gtsam::SOn &Q) const; + static gtsam::SOn Expmap(Vector v); - // Other methods - Vector vec() const; - Matrix matrix() const; + // Other methods + Vector vec() const; + Matrix matrix() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -class Quaternion { - double w() const; - double x() const; - double y() const; - double z() const; - Vector coeffs() const; -}; + class Quaternion + { + double w() const; + double x() const; + double y() const; + double z() const; + Vector coeffs() const; + }; #include -class Rot3 { - // Standard Constructors and Named Constructors - Rot3(); - Rot3(Matrix R); - Rot3(const gtsam::Point3& col1, const gtsam::Point3& col2, const gtsam::Point3& col3); - Rot3(double R11, double R12, double R13, - double R21, double R22, double R23, - double R31, double R32, double R33); - Rot3(double w, double x, double y, double z); + class Rot3 + { + // Standard Constructors and Named Constructors + Rot3(); + Rot3(Matrix R); + Rot3(const gtsam::Point3 &col1, const gtsam::Point3 &col2, const gtsam::Point3 &col3); + Rot3(double R11, double R12, double R13, + double R21, double R22, double R23, + double R31, double R32, double R33); + Rot3(double w, double x, double y, double z); - static gtsam::Rot3 Rx(double t); - static gtsam::Rot3 Ry(double t); - static gtsam::Rot3 Rz(double t); - static gtsam::Rot3 RzRyRx(double x, double y, double z); - static gtsam::Rot3 RzRyRx(Vector xyz); - static gtsam::Rot3 Yaw(double t); // positive yaw is to right (as in aircraft heading) - static gtsam::Rot3 Pitch(double t); // positive pitch is up (increasing aircraft altitude) - static gtsam::Rot3 Roll(double t); // positive roll is to right (increasing yaw in aircraft) - static gtsam::Rot3 Ypr(double y, double p, double r); - static gtsam::Rot3 Quaternion(double w, double x, double y, double z); - static gtsam::Rot3 AxisAngle(const gtsam::Point3& axis, double angle); - static gtsam::Rot3 Rodrigues(Vector v); - static gtsam::Rot3 Rodrigues(double wx, double wy, double wz); - static gtsam::Rot3 ClosestTo(const Matrix M); + static gtsam::Rot3 Rx(double t); + static gtsam::Rot3 Ry(double t); + static gtsam::Rot3 Rz(double t); + static gtsam::Rot3 RzRyRx(double x, double y, double z); + static gtsam::Rot3 RzRyRx(Vector xyz); + static gtsam::Rot3 Yaw(double t); // positive yaw is to right (as in aircraft heading) + static gtsam::Rot3 Pitch(double t); // positive pitch is up (increasing aircraft altitude) + static gtsam::Rot3 Roll(double t); // positive roll is to right (increasing yaw in aircraft) + static gtsam::Rot3 Ypr(double y, double p, double r); + static gtsam::Rot3 Quaternion(double w, double x, double y, double z); + static gtsam::Rot3 AxisAngle(const gtsam::Point3 &axis, double angle); + static gtsam::Rot3 Rodrigues(Vector v); + static gtsam::Rot3 Rodrigues(double wx, double wy, double wz); + static gtsam::Rot3 ClosestTo(const Matrix M); - // Testable - void print(string s) const; - bool equals(const gtsam::Rot3& rot, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Rot3 &rot, double tol) const; - // Group - static gtsam::Rot3 identity(); + // Group + static gtsam::Rot3 identity(); gtsam::Rot3 inverse() const; - gtsam::Rot3 compose(const gtsam::Rot3& p2) const; - gtsam::Rot3 between(const gtsam::Rot3& p2) const; + gtsam::Rot3 compose(const gtsam::Rot3 &p2) const; + gtsam::Rot3 between(const gtsam::Rot3 &p2) const; - // Manifold - //gtsam::Rot3 retractCayley(Vector v) const; // TODO, does not exist in both Matrix and Quaternion options - gtsam::Rot3 retract(Vector v) const; - Vector localCoordinates(const gtsam::Rot3& p) const; + // Manifold + //gtsam::Rot3 retractCayley(Vector v) const; // TODO, does not exist in both Matrix and Quaternion options + gtsam::Rot3 retract(Vector v) const; + Vector localCoordinates(const gtsam::Rot3 &p) const; - // Group Action on Point3 - gtsam::Point3 rotate(const gtsam::Point3& p) const; - gtsam::Point3 unrotate(const gtsam::Point3& p) const; + // Group Action on Point3 + gtsam::Point3 rotate(const gtsam::Point3 &p) const; + gtsam::Point3 unrotate(const gtsam::Point3 &p) const; - // Standard Interface - static gtsam::Rot3 Expmap(Vector v); - static Vector Logmap(const gtsam::Rot3& p); - Vector logmap(const gtsam::Rot3& p); - Matrix matrix() const; - Matrix transpose() const; - gtsam::Point3 column(size_t index) const; - Vector xyz() const; - Vector ypr() const; - Vector rpy() const; - double roll() const; - double pitch() const; - double yaw() const; - pair axisAngle() const; - gtsam::Quaternion toQuaternion() const; - Vector quaternion() const; - gtsam::Rot3 slerp(double t, const gtsam::Rot3& other) const; + // Standard Interface + static gtsam::Rot3 Expmap(Vector v); + static Vector Logmap(const gtsam::Rot3 &p); + Vector logmap(const gtsam::Rot3 &p); + Matrix matrix() const; + Matrix transpose() const; + gtsam::Point3 column(size_t index) const; + Vector xyz() const; + Vector ypr() const; + Vector rpy() const; + double roll() const; + double pitch() const; + double yaw() const; + pair axisAngle() const; + gtsam::Quaternion toQuaternion() const; + Vector quaternion() const; + gtsam::Rot3 slerp(double t, const gtsam::Rot3 &other) const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -class Pose2 { - // Standard Constructor - Pose2(); - Pose2(const gtsam::Pose2& other); - Pose2(double x, double y, double theta); - Pose2(double theta, const gtsam::Point2& t); - Pose2(const gtsam::Rot2& r, const gtsam::Point2& t); - Pose2(Vector v); + class Pose2 + { + // Standard Constructor + Pose2(); + Pose2(const gtsam::Pose2 &other); + Pose2(double x, double y, double theta); + Pose2(double theta, const gtsam::Point2 &t); + Pose2(const gtsam::Rot2 &r, const gtsam::Point2 &t); + Pose2(Vector v); - // Testable - void print(string s) const; - bool equals(const gtsam::Pose2& pose, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Pose2 &pose, double tol) const; - // Group - static gtsam::Pose2 identity(); - gtsam::Pose2 inverse() const; - gtsam::Pose2 compose(const gtsam::Pose2& p2) const; - gtsam::Pose2 between(const gtsam::Pose2& p2) const; + // Group + static gtsam::Pose2 identity(); + gtsam::Pose2 inverse() const; + gtsam::Pose2 compose(const gtsam::Pose2 &p2) const; + gtsam::Pose2 between(const gtsam::Pose2 &p2) const; - // Manifold - gtsam::Pose2 retract(Vector v) const; - Vector localCoordinates(const gtsam::Pose2& p) const; + // Manifold + gtsam::Pose2 retract(Vector v) const; + Vector localCoordinates(const gtsam::Pose2 &p) const; - // Lie Group - static gtsam::Pose2 Expmap(Vector v); - static Vector Logmap(const gtsam::Pose2& p); - Vector logmap(const gtsam::Pose2& p); - static Matrix ExpmapDerivative(Vector v); - static Matrix LogmapDerivative(const gtsam::Pose2& v); - Matrix AdjointMap() const; - Vector Adjoint(Vector xi) const; - static Matrix adjointMap_(Vector v); - static Vector adjoint_(Vector xi, Vector y); - static Vector adjointTranspose(Vector xi, Vector y); - static Matrix wedge(double vx, double vy, double w); + // Lie Group + static gtsam::Pose2 Expmap(Vector v); + static Vector Logmap(const gtsam::Pose2 &p); + Vector logmap(const gtsam::Pose2 &p); + static Matrix ExpmapDerivative(Vector v); + static Matrix LogmapDerivative(const gtsam::Pose2 &v); + Matrix AdjointMap() const; + Vector Adjoint(Vector xi) const; + static Matrix adjointMap_(Vector v); + static Vector adjoint_(Vector xi, Vector y); + static Vector adjointTranspose(Vector xi, Vector y); + static Matrix wedge(double vx, double vy, double w); - // Group Actions on Point2 - gtsam::Point2 transformFrom(const gtsam::Point2& p) const; - gtsam::Point2 transformTo(const gtsam::Point2& p) const; + // Group Actions on Point2 + gtsam::Point2 transformFrom(const gtsam::Point2 &p) const; + gtsam::Point2 transformTo(const gtsam::Point2 &p) const; - // Standard Interface - double x() const; - double y() const; - double theta() const; - gtsam::Rot2 bearing(const gtsam::Point2& point) const; - double range(const gtsam::Point2& point) const; - gtsam::Point2 translation() const; - gtsam::Rot2 rotation() const; - Matrix matrix() const; + // Standard Interface + double x() const; + double y() const; + double theta() const; + gtsam::Rot2 bearing(const gtsam::Point2 &point) const; + double range(const gtsam::Point2 &point) const; + gtsam::Point2 translation() const; + gtsam::Rot2 rotation() const; + Matrix matrix() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -class Pose3 { - // Standard Constructors - Pose3(); - Pose3(const gtsam::Pose3& other); - Pose3(const gtsam::Rot3& r, const gtsam::Point3& t); - Pose3(const gtsam::Pose2& pose2); - Pose3(Matrix mat); + class Pose3 + { + // Standard Constructors + Pose3(); + Pose3(const gtsam::Pose3 &other); + Pose3(const gtsam::Rot3 &r, const gtsam::Point3 &t); + Pose3(const gtsam::Pose2 &pose2); + Pose3(Matrix mat); - // Testable - void print(string s) const; - bool equals(const gtsam::Pose3& pose, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Pose3 &pose, double tol) const; - // Group - static gtsam::Pose3 identity(); - gtsam::Pose3 inverse() const; - gtsam::Pose3 compose(const gtsam::Pose3& pose) const; - gtsam::Pose3 between(const gtsam::Pose3& pose) const; + // Group + static gtsam::Pose3 identity(); + gtsam::Pose3 inverse() const; + gtsam::Pose3 compose(const gtsam::Pose3 &pose) const; + gtsam::Pose3 between(const gtsam::Pose3 &pose) const; - // Manifold - gtsam::Pose3 retract(Vector v) const; - Vector localCoordinates(const gtsam::Pose3& pose) const; + // Manifold + gtsam::Pose3 retract(Vector v) const; + Vector localCoordinates(const gtsam::Pose3 &pose) const; - // Lie Group - static gtsam::Pose3 Expmap(Vector v); - static Vector Logmap(const gtsam::Pose3& pose); - Vector logmap(const gtsam::Pose3& pose); - Matrix AdjointMap() const; - Vector Adjoint(Vector xi) const; - static Matrix adjointMap_(Vector xi); - static Vector adjoint_(Vector xi, Vector y); - static Vector adjointTranspose(Vector xi, Vector y); - static Matrix ExpmapDerivative(Vector xi); - static Matrix LogmapDerivative(const gtsam::Pose3& xi); - static Matrix wedge(double wx, double wy, double wz, double vx, double vy, double vz); + // Lie Group + static gtsam::Pose3 Expmap(Vector v); + static Vector Logmap(const gtsam::Pose3 &pose); + Vector logmap(const gtsam::Pose3 &pose); + Matrix AdjointMap() const; + Vector Adjoint(Vector xi) const; + static Matrix adjointMap_(Vector xi); + static Vector adjoint_(Vector xi, Vector y); + static Vector adjointTranspose(Vector xi, Vector y); + static Matrix ExpmapDerivative(Vector xi); + static Matrix LogmapDerivative(const gtsam::Pose3 &xi); + static Matrix wedge(double wx, double wy, double wz, double vx, double vy, double vz); - // Group Action on Point3 - gtsam::Point3 transformFrom(const gtsam::Point3& point) const; - gtsam::Point3 transformTo(const gtsam::Point3& point) const; + // Group Action on Point3 + gtsam::Point3 transformFrom(const gtsam::Point3 &point) const; + gtsam::Point3 transformTo(const gtsam::Point3 &point) const; - // Standard Interface - gtsam::Rot3 rotation() const; - gtsam::Point3 translation() const; - double x() const; - double y() const; - double z() const; - Matrix matrix() const; - gtsam::Pose3 transformPoseFrom(const gtsam::Pose3& pose) const; - gtsam::Pose3 transformPoseTo(const gtsam::Pose3& pose) const; - double range(const gtsam::Point3& point); - double range(const gtsam::Pose3& pose); + // Standard Interface + gtsam::Rot3 rotation() const; + gtsam::Point3 translation() const; + double x() const; + double y() const; + double z() const; + Matrix matrix() const; + gtsam::Pose3 transformPoseFrom(const gtsam::Pose3 &pose) const; + gtsam::Pose3 transformPoseTo(const gtsam::Pose3 &pose) const; + double range(const gtsam::Point3 &point); + double range(const gtsam::Pose3 &pose); - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; // std::vector #include -class Pose3Vector -{ - Pose3Vector(); - size_t size() const; - bool empty() const; - gtsam::Pose3 at(size_t n) const; - void push_back(const gtsam::Pose3& pose); -}; + class Pose3Vector + { + Pose3Vector(); + size_t size() const; + bool empty() const; + gtsam::Pose3 at(size_t n) const; + void push_back(const gtsam::Pose3 &pose); + }; #include -class Unit3 { - // Standard Constructors - Unit3(); - Unit3(const gtsam::Point3& pose); + class Unit3 + { + // Standard Constructors + Unit3(); + Unit3(const gtsam::Point3 &pose); - // Testable - void print(string s) const; - bool equals(const gtsam::Unit3& pose, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Unit3 &pose, double tol) const; - // Other functionality - Matrix basis() const; - Matrix skew() const; - gtsam::Point3 point3() const; + // Other functionality + Matrix basis() const; + Matrix skew() const; + gtsam::Point3 point3() const; - // Manifold - static size_t Dim(); - size_t dim() const; - gtsam::Unit3 retract(Vector v) const; - Vector localCoordinates(const gtsam::Unit3& s) const; -}; + // Manifold + static size_t Dim(); + size_t dim() const; + gtsam::Unit3 retract(Vector v) const; + Vector localCoordinates(const gtsam::Unit3 &s) const; + }; #include -class EssentialMatrix { - // Standard Constructors - EssentialMatrix(const gtsam::Rot3& aRb, const gtsam::Unit3& aTb); + class EssentialMatrix + { + // Standard Constructors + EssentialMatrix(const gtsam::Rot3 &aRb, const gtsam::Unit3 &aTb); - // Testable - void print(string s) const; - bool equals(const gtsam::EssentialMatrix& pose, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::EssentialMatrix &pose, double tol) const; - // Manifold - static size_t Dim(); - size_t dim() const; - gtsam::EssentialMatrix retract(Vector v) const; - Vector localCoordinates(const gtsam::EssentialMatrix& s) const; + // Manifold + static size_t Dim(); + size_t dim() const; + gtsam::EssentialMatrix retract(Vector v) const; + Vector localCoordinates(const gtsam::EssentialMatrix &s) const; - // Other methods: - gtsam::Rot3 rotation() const; - gtsam::Unit3 direction() const; - Matrix matrix() const; - double error(Vector vA, Vector vB); -}; + // Other methods: + gtsam::Rot3 rotation() const; + gtsam::Unit3 direction() const; + Matrix matrix() const; + double error(Vector vA, Vector vB); + }; #include -class Cal3_S2 { - // Standard Constructors - Cal3_S2(); - Cal3_S2(double fx, double fy, double s, double u0, double v0); - Cal3_S2(Vector v); - Cal3_S2(double fov, int w, int h); + class Cal3_S2 + { + // Standard Constructors + Cal3_S2(); + Cal3_S2(double fx, double fy, double s, double u0, double v0); + Cal3_S2(Vector v); + Cal3_S2(double fov, int w, int h); - // Testable - void print(string s) const; - bool equals(const gtsam::Cal3_S2& rhs, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Cal3_S2 &rhs, double tol) const; - // Manifold - static size_t Dim(); - size_t dim() const; - gtsam::Cal3_S2 retract(Vector v) const; - Vector localCoordinates(const gtsam::Cal3_S2& c) const; + // Manifold + static size_t Dim(); + size_t dim() const; + gtsam::Cal3_S2 retract(Vector v) const; + Vector localCoordinates(const gtsam::Cal3_S2 &c) const; - // Action on Point2 - gtsam::Point2 calibrate(const gtsam::Point2& p) const; - gtsam::Point2 uncalibrate(const gtsam::Point2& p) const; + // Action on Point2 + gtsam::Point2 calibrate(const gtsam::Point2 &p) const; + gtsam::Point2 uncalibrate(const gtsam::Point2 &p) const; - // Standard Interface - double fx() const; - double fy() const; - double skew() const; - double px() const; - double py() const; - gtsam::Point2 principalPoint() const; - Vector vector() const; - Matrix K() const; - Matrix matrix() const; - Matrix matrix_inverse() const; + // Standard Interface + double fx() const; + double fy() const; + double skew() const; + double px() const; + double py() const; + gtsam::Point2 principalPoint() const; + Vector vector() const; + Matrix K() const; + Matrix matrix() const; + Matrix matrix_inverse() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -virtual class Cal3DS2_Base { - // Standard Constructors - Cal3DS2_Base(); + virtual class Cal3DS2_Base + { + // Standard Constructors + Cal3DS2_Base(); - // Testable - void print(string s) const; + // Testable + void print(string s) const; - // Standard Interface - double fx() const; - double fy() const; - double skew() const; - double px() const; - double py() const; - double k1() const; - double k2() const; - Matrix K() const; - Vector k() const; - Vector vector() const; + // Standard Interface + double fx() const; + double fy() const; + double skew() const; + double px() const; + double py() const; + double k1() const; + double k2() const; + Matrix K() const; + Vector k() const; + Vector vector() const; - // Action on Point2 - gtsam::Point2 uncalibrate(const gtsam::Point2& p) const; - gtsam::Point2 calibrate(const gtsam::Point2& p) const; + // Action on Point2 + gtsam::Point2 uncalibrate(const gtsam::Point2 &p) const; + gtsam::Point2 calibrate(const gtsam::Point2 &p) const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -virtual class Cal3DS2 : gtsam::Cal3DS2_Base { - // Standard Constructors - Cal3DS2(); - Cal3DS2(double fx, double fy, double s, double u0, double v0, double k1, double k2); - Cal3DS2(double fx, double fy, double s, double u0, double v0, double k1, double k2, double p1, double p2); - Cal3DS2(Vector v); + virtual class Cal3DS2 : gtsam::Cal3DS2_Base + { + // Standard Constructors + Cal3DS2(); + Cal3DS2(double fx, double fy, double s, double u0, double v0, double k1, double k2); + Cal3DS2(double fx, double fy, double s, double u0, double v0, double k1, double k2, double p1, double p2); + Cal3DS2(Vector v); - // Testable - bool equals(const gtsam::Cal3DS2& rhs, double tol) const; + // Testable + bool equals(const gtsam::Cal3DS2 &rhs, double tol) const; - // Manifold - size_t dim() const; - static size_t Dim(); - gtsam::Cal3DS2 retract(Vector v) const; - Vector localCoordinates(const gtsam::Cal3DS2& c) const; + // Manifold + size_t dim() const; + static size_t Dim(); + gtsam::Cal3DS2 retract(Vector v) const; + Vector localCoordinates(const gtsam::Cal3DS2 &c) const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -virtual class Cal3Unified : gtsam::Cal3DS2_Base { - // Standard Constructors - Cal3Unified(); - Cal3Unified(double fx, double fy, double s, double u0, double v0, double k1, double k2); - Cal3Unified(double fx, double fy, double s, double u0, double v0, double k1, double k2, double p1, double p2, double xi); - Cal3Unified(Vector v); + virtual class Cal3Unified : gtsam::Cal3DS2_Base + { + // Standard Constructors + Cal3Unified(); + Cal3Unified(double fx, double fy, double s, double u0, double v0, double k1, double k2); + Cal3Unified(double fx, double fy, double s, double u0, double v0, double k1, double k2, double p1, double p2, double xi); + Cal3Unified(Vector v); - // Testable - bool equals(const gtsam::Cal3Unified& rhs, double tol) const; + // Testable + bool equals(const gtsam::Cal3Unified &rhs, double tol) const; - // Standard Interface - double xi() const; - gtsam::Point2 spaceToNPlane(const gtsam::Point2& p) const; - gtsam::Point2 nPlaneToSpace(const gtsam::Point2& p) const; + // Standard Interface + double xi() const; + gtsam::Point2 spaceToNPlane(const gtsam::Point2 &p) const; + gtsam::Point2 nPlaneToSpace(const gtsam::Point2 &p) const; - // Manifold - size_t dim() const; - static size_t Dim(); - gtsam::Cal3Unified retract(Vector v) const; - Vector localCoordinates(const gtsam::Cal3Unified& c) const; + // Manifold + size_t dim() const; + static size_t Dim(); + gtsam::Cal3Unified retract(Vector v) const; + Vector localCoordinates(const gtsam::Cal3Unified &c) const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -class Cal3_S2Stereo { - // Standard Constructors - Cal3_S2Stereo(); - Cal3_S2Stereo(double fx, double fy, double s, double u0, double v0, double b); - Cal3_S2Stereo(Vector v); + class Cal3_S2Stereo + { + // Standard Constructors + Cal3_S2Stereo(); + Cal3_S2Stereo(double fx, double fy, double s, double u0, double v0, double b); + Cal3_S2Stereo(Vector v); - // Testable - void print(string s) const; - bool equals(const gtsam::Cal3_S2Stereo& K, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Cal3_S2Stereo &K, double tol) const; - // Standard Interface - double fx() const; - double fy() const; - double skew() const; - double px() const; - double py() const; - gtsam::Point2 principalPoint() const; - double baseline() const; -}; + // Standard Interface + double fx() const; + double fy() const; + double skew() const; + double px() const; + double py() const; + gtsam::Point2 principalPoint() const; + double baseline() const; + }; #include -class Cal3Bundler { - // Standard Constructors - Cal3Bundler(); - Cal3Bundler(double fx, double k1, double k2, double u0, double v0); - Cal3Bundler(double fx, double k1, double k2, double u0, double v0, double tol); + class Cal3Bundler + { + // Standard Constructors + Cal3Bundler(); + Cal3Bundler(double fx, double k1, double k2, double u0, double v0); + Cal3Bundler(double fx, double k1, double k2, double u0, double v0, double tol); - // Testable - void print(string s) const; - bool equals(const gtsam::Cal3Bundler& rhs, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Cal3Bundler &rhs, double tol) const; - // Manifold - static size_t Dim(); - size_t dim() const; - gtsam::Cal3Bundler retract(Vector v) const; - Vector localCoordinates(const gtsam::Cal3Bundler& c) const; + // Manifold + static size_t Dim(); + size_t dim() const; + gtsam::Cal3Bundler retract(Vector v) const; + Vector localCoordinates(const gtsam::Cal3Bundler &c) const; - // Action on Point2 - gtsam::Point2 calibrate(const gtsam::Point2& p) const; - gtsam::Point2 uncalibrate(const gtsam::Point2& p) const; + // Action on Point2 + gtsam::Point2 calibrate(const gtsam::Point2 &p) const; + gtsam::Point2 uncalibrate(const gtsam::Point2 &p) const; - // Standard Interface - double fx() const; - double fy() const; - double k1() const; - double k2() const; - double px() const; - double py() const; - Vector vector() const; - Vector k() const; - Matrix K() const; + // Standard Interface + double fx() const; + double fy() const; + double k1() const; + double k2() const; + double px() const; + double py() const; + Vector vector() const; + Vector k() const; + Matrix K() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -class CalibratedCamera { - // Standard Constructors and Named Constructors - CalibratedCamera(); - CalibratedCamera(const gtsam::Pose3& pose); - CalibratedCamera(Vector v); - static gtsam::CalibratedCamera Level(const gtsam::Pose2& pose2, double height); + class CalibratedCamera + { + // Standard Constructors and Named Constructors + CalibratedCamera(); + CalibratedCamera(const gtsam::Pose3 &pose); + CalibratedCamera(Vector v); + static gtsam::CalibratedCamera Level(const gtsam::Pose2 &pose2, double height); - // Testable - void print(string s) const; - bool equals(const gtsam::CalibratedCamera& camera, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::CalibratedCamera &camera, double tol) const; - // Manifold - static size_t Dim(); - size_t dim() const; - gtsam::CalibratedCamera retract(Vector d) const; - Vector localCoordinates(const gtsam::CalibratedCamera& T2) const; + // Manifold + static size_t Dim(); + size_t dim() const; + gtsam::CalibratedCamera retract(Vector d) const; + Vector localCoordinates(const gtsam::CalibratedCamera &T2) const; - // Action on Point3 - gtsam::Point2 project(const gtsam::Point3& point) const; - static gtsam::Point2 Project(const gtsam::Point3& cameraPoint); + // Action on Point3 + gtsam::Point2 project(const gtsam::Point3 &point) const; + static gtsam::Point2 Project(const gtsam::Point3 &cameraPoint); - // Standard Interface - gtsam::Pose3 pose() const; - double range(const gtsam::Point3& p) const; // TODO: Other overloaded range methods + // Standard Interface + gtsam::Pose3 pose() const; + double range(const gtsam::Point3 &p) const; // TODO: Other overloaded range methods - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -template -class PinholeCamera { - // Standard Constructors and Named Constructors - PinholeCamera(); - PinholeCamera(const gtsam::Pose3& pose); - PinholeCamera(const gtsam::Pose3& pose, const CALIBRATION& K); - static This Level(const CALIBRATION& K, const gtsam::Pose2& pose, double height); - static This Level(const gtsam::Pose2& pose, double height); - static This Lookat(const gtsam::Point3& eye, const gtsam::Point3& target, - const gtsam::Point3& upVector, const CALIBRATION& K); + template + class PinholeCamera + { + // Standard Constructors and Named Constructors + PinholeCamera(); + PinholeCamera(const gtsam::Pose3 &pose); + PinholeCamera(const gtsam::Pose3 &pose, const CALIBRATION &K); + static This Level(const CALIBRATION &K, const gtsam::Pose2 &pose, double height); + static This Level(const gtsam::Pose2 &pose, double height); + static This Lookat(const gtsam::Point3 &eye, const gtsam::Point3 &target, + const gtsam::Point3 &upVector, const CALIBRATION &K); - // Testable - void print(string s) const; - bool equals(const This& camera, double tol) const; + // Testable + void print(string s) const; + bool equals(const This &camera, double tol) const; - // Standard Interface - gtsam::Pose3 pose() const; - CALIBRATION calibration() const; + // Standard Interface + gtsam::Pose3 pose() const; + CALIBRATION calibration() const; - // Manifold - This retract(Vector d) const; - Vector localCoordinates(const This& T2) const; - size_t dim() const; - static size_t Dim(); + // Manifold + This retract(Vector d) const; + Vector localCoordinates(const This &T2) const; + size_t dim() const; + static size_t Dim(); - // Transformations and measurement functions - static gtsam::Point2 Project(const gtsam::Point3& cameraPoint); - pair projectSafe(const gtsam::Point3& pw) const; - gtsam::Point2 project(const gtsam::Point3& point); - gtsam::Point3 backproject(const gtsam::Point2& p, double depth) const; - double range(const gtsam::Point3& point); - double range(const gtsam::Pose3& pose); + // Transformations and measurement functions + static gtsam::Point2 Project(const gtsam::Point3 &cameraPoint); + pair projectSafe(const gtsam::Point3 &pw) const; + gtsam::Point2 project(const gtsam::Point3 &point); + gtsam::Point3 backproject(const gtsam::Point2 &p, double depth) const; + double range(const gtsam::Point3 &point); + double range(const gtsam::Pose3 &pose); - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; // Forward declaration of PinholeCameraCalX is defined here. #include -// Some typedefs for common camera types -// PinholeCameraCal3_S2 is the same as SimpleCamera above -typedef gtsam::PinholeCamera PinholeCameraCal3_S2; -typedef gtsam::PinholeCamera PinholeCameraCal3DS2; -typedef gtsam::PinholeCamera PinholeCameraCal3Unified; -typedef gtsam::PinholeCamera PinholeCameraCal3Bundler; + // Some typedefs for common camera types + // PinholeCameraCal3_S2 is the same as SimpleCamera above + typedef gtsam::PinholeCamera PinholeCameraCal3_S2; + typedef gtsam::PinholeCamera PinholeCameraCal3DS2; + typedef gtsam::PinholeCamera PinholeCameraCal3Unified; + typedef gtsam::PinholeCamera PinholeCameraCal3Bundler; -template -class CameraSet { - CameraSet(); + template + class CameraSet + { + CameraSet(); + // structure specific methods + T at(size_t i) const; + void push_back(const T &cam); + }; - // // common STL methods - // size_t size() const; - // bool empty() const; - // void clear(); - - // structure specific methods - T at(size_t i) const; - void push_back(const T& cam); -}; - -// typedefs added here for shorter type name and to enforce uniformity in naming conventions -//typedef gtsam::CameraSet CameraSetCal3_S2; -//typedef gtsam::CameraSet CameraSetCal3Bundler; + // typedefs added here for shorter type name and to enforce uniformity in naming conventions + //typedef gtsam::CameraSet CameraSetCal3_S2; + //typedef gtsam::CameraSet CameraSetCal3Bundler; #include -class StereoCamera { - // Standard Constructors and Named Constructors - StereoCamera(); - StereoCamera(const gtsam::Pose3& pose, const gtsam::Cal3_S2Stereo* K); + class StereoCamera + { + // Standard Constructors and Named Constructors + StereoCamera(); + StereoCamera(const gtsam::Pose3 &pose, const gtsam::Cal3_S2Stereo *K); - // Testable - void print(string s) const; - bool equals(const gtsam::StereoCamera& camera, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::StereoCamera &camera, double tol) const; - // Standard Interface - gtsam::Pose3 pose() const; - double baseline() const; - gtsam::Cal3_S2Stereo calibration() const; + // Standard Interface + gtsam::Pose3 pose() const; + double baseline() const; + gtsam::Cal3_S2Stereo calibration() const; - // Manifold - gtsam::StereoCamera retract(Vector d) const; - Vector localCoordinates(const gtsam::StereoCamera& T2) const; - size_t dim() const; - static size_t Dim(); + // Manifold + gtsam::StereoCamera retract(Vector d) const; + Vector localCoordinates(const gtsam::StereoCamera &T2) const; + size_t dim() const; + static size_t Dim(); - // Transformations and measurement functions - gtsam::StereoPoint2 project(const gtsam::Point3& point); - gtsam::Point3 backproject(const gtsam::StereoPoint2& p) const; + // Transformations and measurement functions + gtsam::StereoPoint2 project(const gtsam::Point3 &point); + gtsam::Point3 backproject(const gtsam::StereoPoint2 &p) const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -// Templates appear not yet supported for free functions - issue raised at borglab/wrap#14 to add support -gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, - gtsam::Cal3_S2* sharedCal, const gtsam::Point2Vector& measurements, - double rank_tol, bool optimize); -gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, - gtsam::Cal3DS2* sharedCal, const gtsam::Point2Vector& measurements, - double rank_tol, bool optimize); -gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, - gtsam::Cal3Bundler* sharedCal, const gtsam::Point2Vector& measurements, - double rank_tol, bool optimize); -gtsam::Point3 triangulatePoint3(const gtsam::CameraSetCal3_S2& cameras, - const gtsam::Point2Vector& measurements, double rank_tol, - bool optimize); -gtsam::Point3 triangulatePoint3(const gtsam::CameraSetCal3Bundler& cameras, - const gtsam::Point2Vector& measurements, double rank_tol, - bool optimize); - -//************************************************************************* -// Symbolic -//************************************************************************* + // Templates appear not yet supported for free functions - issue raised at borglab/wrap#14 to add support + gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector &poses, + gtsam::Cal3_S2 *sharedCal, const gtsam::Point2Vector &measurements, + double rank_tol, bool optimize); + gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector &poses, + gtsam::Cal3DS2 *sharedCal, const gtsam::Point2Vector &measurements, + double rank_tol, bool optimize); + gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector &poses, + gtsam::Cal3Bundler *sharedCal, const gtsam::Point2Vector &measurements, + double rank_tol, bool optimize); + gtsam::Point3 triangulatePoint3(const gtsam::CameraSetCal3_S2 &cameras, + const gtsam::Point2Vector &measurements, double rank_tol, + bool optimize); + gtsam::Point3 triangulatePoint3(const gtsam::CameraSetCal3Bundler &cameras, + const gtsam::Point2Vector &measurements, double rank_tol, + bool optimize); + + //************************************************************************* + // Symbolic + //************************************************************************* #include -virtual class SymbolicFactor { - // Standard Constructors and Named Constructors - SymbolicFactor(const gtsam::SymbolicFactor& f); - SymbolicFactor(); - SymbolicFactor(size_t j); - SymbolicFactor(size_t j1, size_t j2); - SymbolicFactor(size_t j1, size_t j2, size_t j3); - SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4); - SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4, size_t j5); - SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4, size_t j5, size_t j6); - static gtsam::SymbolicFactor FromKeys(const gtsam::KeyVector& js); + virtual class SymbolicFactor + { + // Standard Constructors and Named Constructors + SymbolicFactor(const gtsam::SymbolicFactor &f); + SymbolicFactor(); + SymbolicFactor(size_t j); + SymbolicFactor(size_t j1, size_t j2); + SymbolicFactor(size_t j1, size_t j2, size_t j3); + SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4); + SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4, size_t j5); + SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4, size_t j5, size_t j6); + static gtsam::SymbolicFactor FromKeys(const gtsam::KeyVector &js); - // From Factor - size_t size() const; - void print(string s) const; - bool equals(const gtsam::SymbolicFactor& other, double tol) const; - gtsam::KeyVector keys(); -}; + // From Factor + size_t size() const; + void print(string s) const; + bool equals(const gtsam::SymbolicFactor &other, double tol) const; + gtsam::KeyVector keys(); + }; #include -virtual class SymbolicFactorGraph { - SymbolicFactorGraph(); - SymbolicFactorGraph(const gtsam::SymbolicBayesNet& bayesNet); - SymbolicFactorGraph(const gtsam::SymbolicBayesTree& bayesTree); + virtual class SymbolicFactorGraph + { + SymbolicFactorGraph(); + SymbolicFactorGraph(const gtsam::SymbolicBayesNet &bayesNet); + SymbolicFactorGraph(const gtsam::SymbolicBayesTree &bayesTree); - // From FactorGraph - void push_back(gtsam::SymbolicFactor* factor); - void print(string s) const; - bool equals(const gtsam::SymbolicFactorGraph& rhs, double tol) const; - size_t size() const; - bool exists(size_t idx) const; + // From FactorGraph + void push_back(gtsam::SymbolicFactor *factor); + void print(string s) const; + bool equals(const gtsam::SymbolicFactorGraph &rhs, double tol) const; + size_t size() const; + bool exists(size_t idx) const; - // Standard interface - gtsam::KeySet keys() const; - void push_back(const gtsam::SymbolicFactorGraph& graph); - void push_back(const gtsam::SymbolicBayesNet& bayesNet); - void push_back(const gtsam::SymbolicBayesTree& bayesTree); + // Standard interface + gtsam::KeySet keys() const; + void push_back(const gtsam::SymbolicFactorGraph &graph); + void push_back(const gtsam::SymbolicBayesNet &bayesNet); + void push_back(const gtsam::SymbolicBayesTree &bayesTree); - //Advanced Interface - void push_factor(size_t key); - void push_factor(size_t key1, size_t key2); - void push_factor(size_t key1, size_t key2, size_t key3); - void push_factor(size_t key1, size_t key2, size_t key3, size_t key4); + //Advanced Interface + void push_factor(size_t key); + void push_factor(size_t key1, size_t key2); + void push_factor(size_t key1, size_t key2, size_t key3); + void push_factor(size_t key1, size_t key2, size_t key3, size_t key4); - gtsam::SymbolicBayesNet* eliminateSequential(); - gtsam::SymbolicBayesNet* eliminateSequential(const gtsam::Ordering& ordering); - gtsam::SymbolicBayesTree* eliminateMultifrontal(); - gtsam::SymbolicBayesTree* eliminateMultifrontal(const gtsam::Ordering& ordering); - pair eliminatePartialSequential( - const gtsam::Ordering& ordering); - pair eliminatePartialSequential( - const gtsam::KeyVector& keys); - pair eliminatePartialMultifrontal( - const gtsam::Ordering& ordering); - pair eliminatePartialMultifrontal( - const gtsam::KeyVector& keys); - gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(const gtsam::Ordering& ordering); - gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(const gtsam::KeyVector& key_vector); - gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(const gtsam::Ordering& ordering, - const gtsam::Ordering& marginalizedVariableOrdering); - gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(const gtsam::KeyVector& key_vector, - const gtsam::Ordering& marginalizedVariableOrdering); - gtsam::SymbolicFactorGraph* marginal(const gtsam::KeyVector& key_vector); -}; + gtsam::SymbolicBayesNet *eliminateSequential(); + gtsam::SymbolicBayesNet *eliminateSequential(const gtsam::Ordering &ordering); + gtsam::SymbolicBayesTree *eliminateMultifrontal(); + gtsam::SymbolicBayesTree *eliminateMultifrontal(const gtsam::Ordering &ordering); + pair eliminatePartialSequential( + const gtsam::Ordering &ordering); + pair eliminatePartialSequential( + const gtsam::KeyVector &keys); + pair eliminatePartialMultifrontal( + const gtsam::Ordering &ordering); + pair eliminatePartialMultifrontal( + const gtsam::KeyVector &keys); + gtsam::SymbolicBayesNet *marginalMultifrontalBayesNet(const gtsam::Ordering &ordering); + gtsam::SymbolicBayesNet *marginalMultifrontalBayesNet(const gtsam::KeyVector &key_vector); + gtsam::SymbolicBayesNet *marginalMultifrontalBayesNet(const gtsam::Ordering &ordering, + const gtsam::Ordering &marginalizedVariableOrdering); + gtsam::SymbolicBayesNet *marginalMultifrontalBayesNet(const gtsam::KeyVector &key_vector, + const gtsam::Ordering &marginalizedVariableOrdering); + gtsam::SymbolicFactorGraph *marginal(const gtsam::KeyVector &key_vector); + }; #include -virtual class SymbolicConditional : gtsam::SymbolicFactor { - // Standard Constructors and Named Constructors - SymbolicConditional(); - SymbolicConditional(const gtsam::SymbolicConditional& other); - SymbolicConditional(size_t key); - SymbolicConditional(size_t key, size_t parent); - SymbolicConditional(size_t key, size_t parent1, size_t parent2); - SymbolicConditional(size_t key, size_t parent1, size_t parent2, size_t parent3); - static gtsam::SymbolicConditional FromKeys(const gtsam::KeyVector& keys, size_t nrFrontals); + virtual class SymbolicConditional : gtsam::SymbolicFactor + { + // Standard Constructors and Named Constructors + SymbolicConditional(); + SymbolicConditional(const gtsam::SymbolicConditional &other); + SymbolicConditional(size_t key); + SymbolicConditional(size_t key, size_t parent); + SymbolicConditional(size_t key, size_t parent1, size_t parent2); + SymbolicConditional(size_t key, size_t parent1, size_t parent2, size_t parent3); + static gtsam::SymbolicConditional FromKeys(const gtsam::KeyVector &keys, size_t nrFrontals); - // Testable - void print(string s) const; - bool equals(const gtsam::SymbolicConditional& other, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::SymbolicConditional &other, double tol) const; - // Standard interface - size_t nrFrontals() const; - size_t nrParents() const; -}; + // Standard interface + size_t nrFrontals() const; + size_t nrParents() const; + }; #include -class SymbolicBayesNet { - SymbolicBayesNet(); - SymbolicBayesNet(const gtsam::SymbolicBayesNet& other); - // Testable - void print(string s) const; - bool equals(const gtsam::SymbolicBayesNet& other, double tol) const; + class SymbolicBayesNet + { + SymbolicBayesNet(); + SymbolicBayesNet(const gtsam::SymbolicBayesNet &other); + // Testable + void print(string s) const; + bool equals(const gtsam::SymbolicBayesNet &other, double tol) const; - // Standard interface - size_t size() const; - void saveGraph(string s) const; - gtsam::SymbolicConditional* at(size_t idx) const; - gtsam::SymbolicConditional* front() const; - gtsam::SymbolicConditional* back() const; - void push_back(gtsam::SymbolicConditional* conditional); - void push_back(const gtsam::SymbolicBayesNet& bayesNet); -}; + // Standard interface + size_t size() const; + void saveGraph(string s) const; + gtsam::SymbolicConditional *at(size_t idx) const; + gtsam::SymbolicConditional *front() const; + gtsam::SymbolicConditional *back() const; + void push_back(gtsam::SymbolicConditional *conditional); + void push_back(const gtsam::SymbolicBayesNet &bayesNet); + }; #include -class SymbolicBayesTree { + class SymbolicBayesTree + { //Constructors SymbolicBayesTree(); - SymbolicBayesTree(const gtsam::SymbolicBayesTree& other); + SymbolicBayesTree(const gtsam::SymbolicBayesTree &other); // Testable void print(string s); - bool equals(const gtsam::SymbolicBayesTree& other, double tol) const; + bool equals(const gtsam::SymbolicBayesTree &other, double tol) const; //Standard Interface //size_t findParentClique(const gtsam::IndexVector& parents) const; @@ -1261,969 +1297,1019 @@ class SymbolicBayesTree { void deleteCachedShortcuts(); size_t numCachedSeparatorMarginals() const; - gtsam::SymbolicConditional* marginalFactor(size_t key) const; - gtsam::SymbolicFactorGraph* joint(size_t key1, size_t key2) const; - gtsam::SymbolicBayesNet* jointBayesNet(size_t key1, size_t key2) const; -}; + gtsam::SymbolicConditional *marginalFactor(size_t key) const; + gtsam::SymbolicFactorGraph *joint(size_t key1, size_t key2) const; + gtsam::SymbolicBayesNet *jointBayesNet(size_t key1, size_t key2) const; + }; -// class SymbolicBayesTreeClique { -// BayesTreeClique(); -// BayesTreeClique(CONDITIONAL* conditional); -// // BayesTreeClique(const pair& result) : Base(result) {} -// -// bool equals(const This& other, double tol) const; -// void print(string s) const; -// void printTree() const; // Default indent of "" -// void printTree(string indent) const; -// size_t numCachedSeparatorMarginals() const; -// -// CONDITIONAL* conditional() const; -// bool isRoot() const; -// size_t treeSize() const; -// // const std::list& children() const { return children_; } -// // derived_ptr parent() const { return parent_.lock(); } -// -// // TODO: need wrapped versions graphs, BayesNet -// // BayesNet shortcut(derived_ptr root, Eliminate function) const; -// // FactorGraph marginal(derived_ptr root, Eliminate function) const; -// // FactorGraph joint(derived_ptr C2, derived_ptr root, Eliminate function) const; -// -// void deleteCachedShortcuts(); -// }; + // class SymbolicBayesTreeClique { + // BayesTreeClique(); + // BayesTreeClique(CONDITIONAL* conditional); + // // BayesTreeClique(const pair& result) : Base(result) {} + // + // bool equals(const This& other, double tol) const; + // void print(string s) const; + // void printTree() const; // Default indent of "" + // void printTree(string indent) const; + // size_t numCachedSeparatorMarginals() const; + // + // CONDITIONAL* conditional() const; + // bool isRoot() const; + // size_t treeSize() const; + // // const std::list& children() const { return children_; } + // // derived_ptr parent() const { return parent_.lock(); } + // + // // TODO: need wrapped versions graphs, BayesNet + // // BayesNet shortcut(derived_ptr root, Eliminate function) const; + // // FactorGraph marginal(derived_ptr root, Eliminate function) const; + // // FactorGraph joint(derived_ptr C2, derived_ptr root, Eliminate function) const; + // + // void deleteCachedShortcuts(); + // }; #include -class VariableIndex { - // Standard Constructors and Named Constructors - VariableIndex(); - // TODO: Templetize constructor when wrap supports it - //template - //VariableIndex(const T& factorGraph, size_t nVariables); - //VariableIndex(const T& factorGraph); - VariableIndex(const gtsam::SymbolicFactorGraph& sfg); - VariableIndex(const gtsam::GaussianFactorGraph& gfg); - VariableIndex(const gtsam::NonlinearFactorGraph& fg); - VariableIndex(const gtsam::VariableIndex& other); + class VariableIndex + { + // Standard Constructors and Named Constructors + VariableIndex(); + // TODO: Templetize constructor when wrap supports it + //template + //VariableIndex(const T& factorGraph, size_t nVariables); + //VariableIndex(const T& factorGraph); + VariableIndex(const gtsam::SymbolicFactorGraph &sfg); + VariableIndex(const gtsam::GaussianFactorGraph &gfg); + VariableIndex(const gtsam::NonlinearFactorGraph &fg); + VariableIndex(const gtsam::VariableIndex &other); - // Testable - bool equals(const gtsam::VariableIndex& other, double tol) const; - void print(string s) const; + // Testable + bool equals(const gtsam::VariableIndex &other, double tol) const; + void print(string s) const; - // Standard interface - size_t size() const; - size_t nFactors() const; - size_t nEntries() const; -}; + // Standard interface + size_t size() const; + size_t nFactors() const; + size_t nEntries() const; + }; -//************************************************************************* -// linear -//************************************************************************* + //************************************************************************* + // linear + //************************************************************************* -namespace noiseModel { + namespace noiseModel + { #include -virtual class Base { - void print(string s) const; - // Methods below are available for all noise models. However, can't add them - // because wrap (incorrectly) thinks robust classes derive from this Base as well. - // bool isConstrained() const; - // bool isUnit() const; - // size_t dim() const; - // Vector sigmas() const; -}; + virtual class Base + { + void print(string s) const; + // Methods below are available for all noise models. However, can't add them + // because wrap (incorrectly) thinks robust classes derive from this Base as well. + // bool isConstrained() const; + // bool isUnit() const; + // size_t dim() const; + // Vector sigmas() const; + }; -virtual class Gaussian : gtsam::noiseModel::Base { - static gtsam::noiseModel::Gaussian* Information(Matrix R); - static gtsam::noiseModel::Gaussian* SqrtInformation(Matrix R); - static gtsam::noiseModel::Gaussian* Covariance(Matrix R); + virtual class Gaussian : gtsam::noiseModel::Base + { + static gtsam::noiseModel::Gaussian *Information(Matrix R); + static gtsam::noiseModel::Gaussian *SqrtInformation(Matrix R); + static gtsam::noiseModel::Gaussian *Covariance(Matrix R); - bool equals(gtsam::noiseModel::Base& expected, double tol); + bool equals(gtsam::noiseModel::Base &expected, double tol); - // access to noise model - Matrix R() const; - Matrix information() const; - Matrix covariance() const; + // access to noise model + Matrix R() const; + Matrix information() const; + Matrix covariance() const; - // Whitening operations - Vector whiten(Vector v) const; - Vector unwhiten(Vector v) const; - Matrix Whiten(Matrix H) const; + // Whitening operations + Vector whiten(Vector v) const; + Vector unwhiten(Vector v) const; + Matrix Whiten(Matrix H) const; - // enabling serialization functionality - void serializable() const; -}; + // enabling serialization functionality + void serializable() const; + }; -virtual class Diagonal : gtsam::noiseModel::Gaussian { - static gtsam::noiseModel::Diagonal* Sigmas(Vector sigmas); - static gtsam::noiseModel::Diagonal* Variances(Vector variances); - static gtsam::noiseModel::Diagonal* Precisions(Vector precisions); - Matrix R() const; + virtual class Diagonal : gtsam::noiseModel::Gaussian + { + static gtsam::noiseModel::Diagonal *Sigmas(Vector sigmas); + static gtsam::noiseModel::Diagonal *Variances(Vector variances); + static gtsam::noiseModel::Diagonal *Precisions(Vector precisions); + Matrix R() const; - // access to noise model - Vector sigmas() const; - Vector invsigmas() const; - Vector precisions() const; + // access to noise model + Vector sigmas() const; + Vector invsigmas() const; + Vector precisions() const; - // enabling serialization functionality - void serializable() const; -}; + // enabling serialization functionality + void serializable() const; + }; -virtual class Constrained : gtsam::noiseModel::Diagonal { - static gtsam::noiseModel::Constrained* MixedSigmas(Vector mu, Vector sigmas); - static gtsam::noiseModel::Constrained* MixedSigmas(double m, Vector sigmas); - static gtsam::noiseModel::Constrained* MixedVariances(Vector mu, Vector variances); - static gtsam::noiseModel::Constrained* MixedVariances(Vector variances); - static gtsam::noiseModel::Constrained* MixedPrecisions(Vector mu, Vector precisions); - static gtsam::noiseModel::Constrained* MixedPrecisions(Vector precisions); + virtual class Constrained : gtsam::noiseModel::Diagonal + { + static gtsam::noiseModel::Constrained *MixedSigmas(Vector mu, Vector sigmas); + static gtsam::noiseModel::Constrained *MixedSigmas(double m, Vector sigmas); + static gtsam::noiseModel::Constrained *MixedVariances(Vector mu, Vector variances); + static gtsam::noiseModel::Constrained *MixedVariances(Vector variances); + static gtsam::noiseModel::Constrained *MixedPrecisions(Vector mu, Vector precisions); + static gtsam::noiseModel::Constrained *MixedPrecisions(Vector precisions); - static gtsam::noiseModel::Constrained* All(size_t dim); - static gtsam::noiseModel::Constrained* All(size_t dim, double mu); + static gtsam::noiseModel::Constrained *All(size_t dim); + static gtsam::noiseModel::Constrained *All(size_t dim, double mu); - gtsam::noiseModel::Constrained* unit() const; + gtsam::noiseModel::Constrained *unit() const; - // enabling serialization functionality - void serializable() const; -}; + // enabling serialization functionality + void serializable() const; + }; -virtual class Isotropic : gtsam::noiseModel::Diagonal { - static gtsam::noiseModel::Isotropic* Sigma(size_t dim, double sigma); - static gtsam::noiseModel::Isotropic* Variance(size_t dim, double varianace); - static gtsam::noiseModel::Isotropic* Precision(size_t dim, double precision); + virtual class Isotropic : gtsam::noiseModel::Diagonal + { + static gtsam::noiseModel::Isotropic *Sigma(size_t dim, double sigma); + static gtsam::noiseModel::Isotropic *Variance(size_t dim, double varianace); + static gtsam::noiseModel::Isotropic *Precision(size_t dim, double precision); - // access to noise model - double sigma() const; + // access to noise model + double sigma() const; - // enabling serialization functionality - void serializable() const; -}; + // enabling serialization functionality + void serializable() const; + }; -virtual class Unit : gtsam::noiseModel::Isotropic { - static gtsam::noiseModel::Unit* Create(size_t dim); + virtual class Unit : gtsam::noiseModel::Isotropic + { + static gtsam::noiseModel::Unit *Create(size_t dim); - // enabling serialization functionality - void serializable() const; -}; + // enabling serialization functionality + void serializable() const; + }; -namespace mEstimator { -virtual class Base { - void print(string s) const; -}; + namespace mEstimator + { + virtual class Base + { + void print(string s) const; + }; -virtual class Null: gtsam::noiseModel::mEstimator::Base { - Null(); - static gtsam::noiseModel::mEstimator::Null* Create(); + virtual class Null : gtsam::noiseModel::mEstimator::Base + { + Null(); + static gtsam::noiseModel::mEstimator::Null *Create(); - // enabling serialization functionality - void serializable() const; + // enabling serialization functionality + void serializable() const; - double weight(double error) const; - double loss(double error) const; -}; + double weight(double error) const; + double loss(double error) const; + }; -virtual class Fair: gtsam::noiseModel::mEstimator::Base { - Fair(double c); - static gtsam::noiseModel::mEstimator::Fair* Create(double c); + virtual class Fair : gtsam::noiseModel::mEstimator::Base + { + Fair(double c); + static gtsam::noiseModel::mEstimator::Fair *Create(double c); - // enabling serialization functionality - void serializable() const; + // enabling serialization functionality + void serializable() const; - double weight(double error) const; - double loss(double error) const; -}; + double weight(double error) const; + double loss(double error) const; + }; -virtual class Huber: gtsam::noiseModel::mEstimator::Base { - Huber(double k); - static gtsam::noiseModel::mEstimator::Huber* Create(double k); + virtual class Huber : gtsam::noiseModel::mEstimator::Base + { + Huber(double k); + static gtsam::noiseModel::mEstimator::Huber *Create(double k); - // enabling serialization functionality - void serializable() const; + // enabling serialization functionality + void serializable() const; - double weight(double error) const; - double loss(double error) const; -}; + double weight(double error) const; + double loss(double error) const; + }; -virtual class Cauchy: gtsam::noiseModel::mEstimator::Base { - Cauchy(double k); - static gtsam::noiseModel::mEstimator::Cauchy* Create(double k); + virtual class Cauchy : gtsam::noiseModel::mEstimator::Base + { + Cauchy(double k); + static gtsam::noiseModel::mEstimator::Cauchy *Create(double k); - // enabling serialization functionality - void serializable() const; + // enabling serialization functionality + void serializable() const; - double weight(double error) const; - double loss(double error) const; -}; + double weight(double error) const; + double loss(double error) const; + }; -virtual class Tukey: gtsam::noiseModel::mEstimator::Base { - Tukey(double k); - static gtsam::noiseModel::mEstimator::Tukey* Create(double k); + virtual class Tukey : gtsam::noiseModel::mEstimator::Base + { + Tukey(double k); + static gtsam::noiseModel::mEstimator::Tukey *Create(double k); - // enabling serialization functionality - void serializable() const; + // enabling serialization functionality + void serializable() const; - double weight(double error) const; - double loss(double error) const; -}; + double weight(double error) const; + double loss(double error) const; + }; -virtual class Welsch: gtsam::noiseModel::mEstimator::Base { - Welsch(double k); - static gtsam::noiseModel::mEstimator::Welsch* Create(double k); + virtual class Welsch : gtsam::noiseModel::mEstimator::Base + { + Welsch(double k); + static gtsam::noiseModel::mEstimator::Welsch *Create(double k); - // enabling serialization functionality - void serializable() const; + // enabling serialization functionality + void serializable() const; - double weight(double error) const; - double loss(double error) const; -}; + double weight(double error) const; + double loss(double error) const; + }; -virtual class GemanMcClure: gtsam::noiseModel::mEstimator::Base { - GemanMcClure(double c); - static gtsam::noiseModel::mEstimator::GemanMcClure* Create(double c); + virtual class GemanMcClure : gtsam::noiseModel::mEstimator::Base + { + GemanMcClure(double c); + static gtsam::noiseModel::mEstimator::GemanMcClure *Create(double c); - // enabling serialization functionality - void serializable() const; + // enabling serialization functionality + void serializable() const; - double weight(double error) const; - double loss(double error) const; -}; + double weight(double error) const; + double loss(double error) const; + }; -virtual class DCS: gtsam::noiseModel::mEstimator::Base { - DCS(double c); - static gtsam::noiseModel::mEstimator::DCS* Create(double c); + virtual class DCS : gtsam::noiseModel::mEstimator::Base + { + DCS(double c); + static gtsam::noiseModel::mEstimator::DCS *Create(double c); - // enabling serialization functionality - void serializable() const; + // enabling serialization functionality + void serializable() const; - double weight(double error) const; - double loss(double error) const; -}; + double weight(double error) const; + double loss(double error) const; + }; -virtual class L2WithDeadZone: gtsam::noiseModel::mEstimator::Base { - L2WithDeadZone(double k); - static gtsam::noiseModel::mEstimator::L2WithDeadZone* Create(double k); + virtual class L2WithDeadZone : gtsam::noiseModel::mEstimator::Base + { + L2WithDeadZone(double k); + static gtsam::noiseModel::mEstimator::L2WithDeadZone *Create(double k); - // enabling serialization functionality - void serializable() const; + // enabling serialization functionality + void serializable() const; - double weight(double error) const; - double loss(double error) const; -}; + double weight(double error) const; + double loss(double error) const; + }; -}///\namespace mEstimator + } // namespace mEstimator -virtual class Robust : gtsam::noiseModel::Base { - Robust(const gtsam::noiseModel::mEstimator::Base* robust, const gtsam::noiseModel::Base* noise); - static gtsam::noiseModel::Robust* Create(const gtsam::noiseModel::mEstimator::Base* robust, const gtsam::noiseModel::Base* noise); + virtual class Robust : gtsam::noiseModel::Base + { + Robust(const gtsam::noiseModel::mEstimator::Base *robust, const gtsam::noiseModel::Base *noise); + static gtsam::noiseModel::Robust *Create(const gtsam::noiseModel::mEstimator::Base *robust, const gtsam::noiseModel::Base *noise); - // enabling serialization functionality - void serializable() const; -}; + // enabling serialization functionality + void serializable() const; + }; -}///\namespace noiseModel + } // namespace noiseModel #include -class Sampler { - // Constructors - Sampler(gtsam::noiseModel::Diagonal* model, int seed); - Sampler(Vector sigmas, int seed); + class Sampler + { + // Constructors + Sampler(gtsam::noiseModel::Diagonal *model, int seed); + Sampler(Vector sigmas, int seed); - // Standard Interface - size_t dim() const; - Vector sigmas() const; - gtsam::noiseModel::Diagonal* model() const; - Vector sample(); -}; + // Standard Interface + size_t dim() const; + Vector sigmas() const; + gtsam::noiseModel::Diagonal *model() const; + Vector sample(); + }; #include -class VectorValues { + class VectorValues + { //Constructors - VectorValues(); - VectorValues(const gtsam::VectorValues& other); + VectorValues(); + VectorValues(const gtsam::VectorValues &other); - //Named Constructors - static gtsam::VectorValues Zero(const gtsam::VectorValues& model); + //Named Constructors + static gtsam::VectorValues Zero(const gtsam::VectorValues &model); - //Standard Interface - size_t size() const; - size_t dim(size_t j) const; - bool exists(size_t j) const; - void print(string s) const; - bool equals(const gtsam::VectorValues& expected, double tol) const; - void insert(size_t j, Vector value); - Vector vector() const; - Vector at(size_t j) const; - void update(const gtsam::VectorValues& values); + //Standard Interface + size_t size() const; + size_t dim(size_t j) const; + bool exists(size_t j) const; + void print(string s) const; + bool equals(const gtsam::VectorValues &expected, double tol) const; + void insert(size_t j, Vector value); + Vector vector() const; + Vector at(size_t j) const; + void update(const gtsam::VectorValues &values); - //Advanced Interface - void setZero(); + //Advanced Interface + void setZero(); - gtsam::VectorValues add(const gtsam::VectorValues& c) const; - void addInPlace(const gtsam::VectorValues& c); - gtsam::VectorValues subtract(const gtsam::VectorValues& c) const; - gtsam::VectorValues scale(double a) const; - void scaleInPlace(double a); + gtsam::VectorValues add(const gtsam::VectorValues &c) const; + void addInPlace(const gtsam::VectorValues &c); + gtsam::VectorValues subtract(const gtsam::VectorValues &c) const; + gtsam::VectorValues scale(double a) const; + void scaleInPlace(double a); - bool hasSameStructure(const gtsam::VectorValues& other) const; - double dot(const gtsam::VectorValues& V) const; - double norm() const; - double squaredNorm() const; + bool hasSameStructure(const gtsam::VectorValues &other) const; + double dot(const gtsam::VectorValues &V) const; + double norm() const; + double squaredNorm() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -virtual class GaussianFactor { - gtsam::KeyVector keys() const; - void print(string s) const; - bool equals(const gtsam::GaussianFactor& lf, double tol) const; - double error(const gtsam::VectorValues& c) const; - gtsam::GaussianFactor* clone() const; - gtsam::GaussianFactor* negate() const; - Matrix augmentedInformation() const; - Matrix information() const; - Matrix augmentedJacobian() const; - pair jacobian() const; - size_t size() const; - bool empty() const; -}; + virtual class GaussianFactor + { + gtsam::KeyVector keys() const; + void print(string s) const; + bool equals(const gtsam::GaussianFactor &lf, double tol) const; + double error(const gtsam::VectorValues &c) const; + gtsam::GaussianFactor *clone() const; + gtsam::GaussianFactor *negate() const; + Matrix augmentedInformation() const; + Matrix information() const; + Matrix augmentedJacobian() const; + pair jacobian() const; + size_t size() const; + bool empty() const; + }; #include -virtual class JacobianFactor : gtsam::GaussianFactor { - //Constructors - JacobianFactor(); - JacobianFactor(const gtsam::GaussianFactor& factor); - JacobianFactor(Vector b_in); - JacobianFactor(size_t i1, Matrix A1, Vector b, - const gtsam::noiseModel::Diagonal* model); - JacobianFactor(size_t i1, Matrix A1, size_t i2, Matrix A2, Vector b, - const gtsam::noiseModel::Diagonal* model); - JacobianFactor(size_t i1, Matrix A1, size_t i2, Matrix A2, size_t i3, Matrix A3, - Vector b, const gtsam::noiseModel::Diagonal* model); - JacobianFactor(const gtsam::GaussianFactorGraph& graph); + virtual class JacobianFactor : gtsam::GaussianFactor + { + //Constructors + JacobianFactor(); + JacobianFactor(const gtsam::GaussianFactor &factor); + JacobianFactor(Vector b_in); + JacobianFactor(size_t i1, Matrix A1, Vector b, + const gtsam::noiseModel::Diagonal *model); + JacobianFactor(size_t i1, Matrix A1, size_t i2, Matrix A2, Vector b, + const gtsam::noiseModel::Diagonal *model); + JacobianFactor(size_t i1, Matrix A1, size_t i2, Matrix A2, size_t i3, Matrix A3, + Vector b, const gtsam::noiseModel::Diagonal *model); + JacobianFactor(const gtsam::GaussianFactorGraph &graph); - //Testable - void print(string s) const; - void printKeys(string s) const; - bool equals(const gtsam::GaussianFactor& lf, double tol) const; - size_t size() const; - Vector unweighted_error(const gtsam::VectorValues& c) const; - Vector error_vector(const gtsam::VectorValues& c) const; - double error(const gtsam::VectorValues& c) const; + //Testable + void print(string s) const; + void printKeys(string s) const; + bool equals(const gtsam::GaussianFactor &lf, double tol) const; + size_t size() const; + Vector unweighted_error(const gtsam::VectorValues &c) const; + Vector error_vector(const gtsam::VectorValues &c) const; + double error(const gtsam::VectorValues &c) const; - //Standard Interface - Matrix getA() const; - Vector getb() const; - size_t rows() const; - size_t cols() const; - bool isConstrained() const; - pair jacobianUnweighted() const; - Matrix augmentedJacobianUnweighted() const; + //Standard Interface + Matrix getA() const; + Vector getb() const; + size_t rows() const; + size_t cols() const; + bool isConstrained() const; + pair jacobianUnweighted() const; + Matrix augmentedJacobianUnweighted() const; - void transposeMultiplyAdd(double alpha, Vector e, gtsam::VectorValues& x) const; - gtsam::JacobianFactor whiten() const; + void transposeMultiplyAdd(double alpha, Vector e, gtsam::VectorValues &x) const; + gtsam::JacobianFactor whiten() const; - pair eliminate(const gtsam::Ordering& keys) const; + pair eliminate(const gtsam::Ordering &keys) const; - void setModel(bool anyConstrained, Vector sigmas); + void setModel(bool anyConstrained, Vector sigmas); - gtsam::noiseModel::Diagonal* get_model() const; + gtsam::noiseModel::Diagonal *get_model() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -virtual class HessianFactor : gtsam::GaussianFactor { - //Constructors - HessianFactor(); - HessianFactor(const gtsam::GaussianFactor& factor); - HessianFactor(size_t j, Matrix G, Vector g, double f); - HessianFactor(size_t j, Vector mu, Matrix Sigma); - HessianFactor(size_t j1, size_t j2, Matrix G11, Matrix G12, Vector g1, Matrix G22, - Vector g2, double f); - HessianFactor(size_t j1, size_t j2, size_t j3, Matrix G11, Matrix G12, Matrix G13, - Vector g1, Matrix G22, Matrix G23, Vector g2, Matrix G33, Vector g3, - double f); - HessianFactor(const gtsam::GaussianFactorGraph& factors); + virtual class HessianFactor : gtsam::GaussianFactor + { + //Constructors + HessianFactor(); + HessianFactor(const gtsam::GaussianFactor &factor); + HessianFactor(size_t j, Matrix G, Vector g, double f); + HessianFactor(size_t j, Vector mu, Matrix Sigma); + HessianFactor(size_t j1, size_t j2, Matrix G11, Matrix G12, Vector g1, Matrix G22, + Vector g2, double f); + HessianFactor(size_t j1, size_t j2, size_t j3, Matrix G11, Matrix G12, Matrix G13, + Vector g1, Matrix G22, Matrix G23, Vector g2, Matrix G33, Vector g3, + double f); + HessianFactor(const gtsam::GaussianFactorGraph &factors); - //Testable - size_t size() const; - void print(string s) const; - void printKeys(string s) const; - bool equals(const gtsam::GaussianFactor& lf, double tol) const; - double error(const gtsam::VectorValues& c) const; + //Testable + size_t size() const; + void print(string s) const; + void printKeys(string s) const; + bool equals(const gtsam::GaussianFactor &lf, double tol) const; + double error(const gtsam::VectorValues &c) const; - //Standard Interface - size_t rows() const; - Matrix information() const; - double constantTerm() const; - Vector linearTerm() const; + //Standard Interface + size_t rows() const; + Matrix information() const; + double constantTerm() const; + Vector linearTerm() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -class GaussianFactorGraph { - GaussianFactorGraph(); - GaussianFactorGraph(const gtsam::GaussianBayesNet& bayesNet); - GaussianFactorGraph(const gtsam::GaussianBayesTree& bayesTree); + class GaussianFactorGraph + { + GaussianFactorGraph(); + GaussianFactorGraph(const gtsam::GaussianBayesNet &bayesNet); + GaussianFactorGraph(const gtsam::GaussianBayesTree &bayesTree); - // From FactorGraph - void print(string s) const; - bool equals(const gtsam::GaussianFactorGraph& lfgraph, double tol) const; - size_t size() const; - gtsam::GaussianFactor* at(size_t idx) const; - gtsam::KeySet keys() const; - gtsam::KeyVector keyVector() const; - bool exists(size_t idx) const; + // From FactorGraph + void print(string s) const; + bool equals(const gtsam::GaussianFactorGraph &lfgraph, double tol) const; + size_t size() const; + gtsam::GaussianFactor *at(size_t idx) const; + gtsam::KeySet keys() const; + gtsam::KeyVector keyVector() const; + bool exists(size_t idx) const; - // Building the graph - void push_back(const gtsam::GaussianFactor* factor); - void push_back(const gtsam::GaussianConditional* conditional); - void push_back(const gtsam::GaussianFactorGraph& graph); - void push_back(const gtsam::GaussianBayesNet& bayesNet); - void push_back(const gtsam::GaussianBayesTree& bayesTree); - void add(const gtsam::GaussianFactor& factor); - void add(Vector b); - void add(size_t key1, Matrix A1, Vector b, const gtsam::noiseModel::Diagonal* model); - void add(size_t key1, Matrix A1, size_t key2, Matrix A2, Vector b, - const gtsam::noiseModel::Diagonal* model); - void add(size_t key1, Matrix A1, size_t key2, Matrix A2, size_t key3, Matrix A3, - Vector b, const gtsam::noiseModel::Diagonal* model); + // Building the graph + void push_back(const gtsam::GaussianFactor *factor); + void push_back(const gtsam::GaussianConditional *conditional); + void push_back(const gtsam::GaussianFactorGraph &graph); + void push_back(const gtsam::GaussianBayesNet &bayesNet); + void push_back(const gtsam::GaussianBayesTree &bayesTree); + void add(const gtsam::GaussianFactor &factor); + void add(Vector b); + void add(size_t key1, Matrix A1, Vector b, const gtsam::noiseModel::Diagonal *model); + void add(size_t key1, Matrix A1, size_t key2, Matrix A2, Vector b, + const gtsam::noiseModel::Diagonal *model); + void add(size_t key1, Matrix A1, size_t key2, Matrix A2, size_t key3, Matrix A3, + Vector b, const gtsam::noiseModel::Diagonal *model); - // error and probability - double error(const gtsam::VectorValues& c) const; - double probPrime(const gtsam::VectorValues& c) const; + // error and probability + double error(const gtsam::VectorValues &c) const; + double probPrime(const gtsam::VectorValues &c) const; - gtsam::GaussianFactorGraph clone() const; - gtsam::GaussianFactorGraph negate() const; + gtsam::GaussianFactorGraph clone() const; + gtsam::GaussianFactorGraph negate() const; - // Optimizing and linear algebra - gtsam::VectorValues optimize() const; - gtsam::VectorValues optimize(const gtsam::Ordering& ordering) const; - gtsam::VectorValues optimizeGradientSearch() const; - gtsam::VectorValues gradient(const gtsam::VectorValues& x0) const; - gtsam::VectorValues gradientAtZero() const; + // Optimizing and linear algebra + gtsam::VectorValues optimize() const; + gtsam::VectorValues optimize(const gtsam::Ordering &ordering) const; + gtsam::VectorValues optimizeGradientSearch() const; + gtsam::VectorValues gradient(const gtsam::VectorValues &x0) const; + gtsam::VectorValues gradientAtZero() const; - // Elimination and marginals - gtsam::GaussianBayesNet* eliminateSequential(); - gtsam::GaussianBayesNet* eliminateSequential(const gtsam::Ordering& ordering); - gtsam::GaussianBayesTree* eliminateMultifrontal(); - gtsam::GaussianBayesTree* eliminateMultifrontal(const gtsam::Ordering& ordering); - pair eliminatePartialSequential( - const gtsam::Ordering& ordering); - pair eliminatePartialSequential( - const gtsam::KeyVector& keys); - pair eliminatePartialMultifrontal( - const gtsam::Ordering& ordering); - pair eliminatePartialMultifrontal( - const gtsam::KeyVector& keys); - gtsam::GaussianBayesNet* marginalMultifrontalBayesNet(const gtsam::Ordering& ordering); - gtsam::GaussianBayesNet* marginalMultifrontalBayesNet(const gtsam::KeyVector& key_vector); - gtsam::GaussianBayesNet* marginalMultifrontalBayesNet(const gtsam::Ordering& ordering, - const gtsam::Ordering& marginalizedVariableOrdering); - gtsam::GaussianBayesNet* marginalMultifrontalBayesNet(const gtsam::KeyVector& key_vector, - const gtsam::Ordering& marginalizedVariableOrdering); - gtsam::GaussianFactorGraph* marginal(const gtsam::KeyVector& key_vector); + // Elimination and marginals + gtsam::GaussianBayesNet *eliminateSequential(); + gtsam::GaussianBayesNet *eliminateSequential(const gtsam::Ordering &ordering); + gtsam::GaussianBayesTree *eliminateMultifrontal(); + gtsam::GaussianBayesTree *eliminateMultifrontal(const gtsam::Ordering &ordering); + pair eliminatePartialSequential( + const gtsam::Ordering &ordering); + pair eliminatePartialSequential( + const gtsam::KeyVector &keys); + pair eliminatePartialMultifrontal( + const gtsam::Ordering &ordering); + pair eliminatePartialMultifrontal( + const gtsam::KeyVector &keys); + gtsam::GaussianBayesNet *marginalMultifrontalBayesNet(const gtsam::Ordering &ordering); + gtsam::GaussianBayesNet *marginalMultifrontalBayesNet(const gtsam::KeyVector &key_vector); + gtsam::GaussianBayesNet *marginalMultifrontalBayesNet(const gtsam::Ordering &ordering, + const gtsam::Ordering &marginalizedVariableOrdering); + gtsam::GaussianBayesNet *marginalMultifrontalBayesNet(const gtsam::KeyVector &key_vector, + const gtsam::Ordering &marginalizedVariableOrdering); + gtsam::GaussianFactorGraph *marginal(const gtsam::KeyVector &key_vector); - // Conversion to matrices - Matrix sparseJacobian_() const; - Matrix augmentedJacobian() const; - Matrix augmentedJacobian(const gtsam::Ordering& ordering) const; - pair jacobian() const; - pair jacobian(const gtsam::Ordering& ordering) const; - Matrix augmentedHessian() const; - Matrix augmentedHessian(const gtsam::Ordering& ordering) const; - pair hessian() const; - pair hessian(const gtsam::Ordering& ordering) const; + // Conversion to matrices + Matrix sparseJacobian_() const; + Matrix augmentedJacobian() const; + Matrix augmentedJacobian(const gtsam::Ordering &ordering) const; + pair jacobian() const; + pair jacobian(const gtsam::Ordering &ordering) const; + Matrix augmentedHessian() const; + Matrix augmentedHessian(const gtsam::Ordering &ordering) const; + pair hessian() const; + pair hessian(const gtsam::Ordering &ordering) const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -virtual class GaussianConditional : gtsam::GaussianFactor { - //Constructors - GaussianConditional(size_t key, Vector d, Matrix R, const gtsam::noiseModel::Diagonal* sigmas); - GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S, - const gtsam::noiseModel::Diagonal* sigmas); - GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S, - size_t name2, Matrix T, const gtsam::noiseModel::Diagonal* sigmas); + virtual class GaussianConditional : gtsam::GaussianFactor + { + //Constructors + GaussianConditional(size_t key, Vector d, Matrix R, const gtsam::noiseModel::Diagonal *sigmas); + GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S, + const gtsam::noiseModel::Diagonal *sigmas); + GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S, + size_t name2, Matrix T, const gtsam::noiseModel::Diagonal *sigmas); - //Constructors with no noise model - GaussianConditional(size_t key, Vector d, Matrix R); + //Constructors with no noise model + GaussianConditional(size_t key, Vector d, Matrix R); GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S); GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S, - size_t name2, Matrix T); + size_t name2, Matrix T); - //Standard Interface - void print(string s) const; - bool equals(const gtsam::GaussianConditional &cg, double tol) const; + //Standard Interface + void print(string s) const; + bool equals(const gtsam::GaussianConditional &cg, double tol) const; - //Advanced Interface - gtsam::VectorValues solve(const gtsam::VectorValues& parents) const; - gtsam::VectorValues solveOtherRHS(const gtsam::VectorValues& parents, const gtsam::VectorValues& rhs) const; - void solveTransposeInPlace(gtsam::VectorValues& gy) const; - void scaleFrontalsBySigma(gtsam::VectorValues& gy) const; - Matrix R() const; - Matrix S() const; - Vector d() const; + //Advanced Interface + gtsam::VectorValues solve(const gtsam::VectorValues &parents) const; + gtsam::VectorValues solveOtherRHS(const gtsam::VectorValues &parents, const gtsam::VectorValues &rhs) const; + void solveTransposeInPlace(gtsam::VectorValues &gy) const; + void scaleFrontalsBySigma(gtsam::VectorValues &gy) const; + Matrix R() const; + Matrix S() const; + Vector d() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -virtual class GaussianDensity : gtsam::GaussianConditional { + virtual class GaussianDensity : gtsam::GaussianConditional + { //Constructors - GaussianDensity(size_t key, Vector d, Matrix R, const gtsam::noiseModel::Diagonal* sigmas); + GaussianDensity(size_t key, Vector d, Matrix R, const gtsam::noiseModel::Diagonal *sigmas); - //Standard Interface - void print(string s) const; - bool equals(const gtsam::GaussianDensity &cg, double tol) const; - Vector mean() const; - Matrix covariance() const; -}; + //Standard Interface + void print(string s) const; + bool equals(const gtsam::GaussianDensity &cg, double tol) const; + Vector mean() const; + Matrix covariance() const; + }; #include -virtual class GaussianBayesNet { + virtual class GaussianBayesNet + { //Constructors - GaussianBayesNet(); - GaussianBayesNet(const gtsam::GaussianConditional* conditional); + GaussianBayesNet(); + GaussianBayesNet(const gtsam::GaussianConditional *conditional); - // Testable - void print(string s) const; - bool equals(const gtsam::GaussianBayesNet& other, double tol) const; - size_t size() const; + // Testable + void print(string s) const; + bool equals(const gtsam::GaussianBayesNet &other, double tol) const; + size_t size() const; - // FactorGraph derived interface - // size_t size() const; - gtsam::GaussianConditional* at(size_t idx) const; - gtsam::KeySet keys() const; - bool exists(size_t idx) const; + // FactorGraph derived interface + // size_t size() const; + gtsam::GaussianConditional *at(size_t idx) const; + gtsam::KeySet keys() const; + bool exists(size_t idx) const; - gtsam::GaussianConditional* front() const; - gtsam::GaussianConditional* back() const; - void push_back(gtsam::GaussianConditional* conditional); - void push_back(const gtsam::GaussianBayesNet& bayesNet); + gtsam::GaussianConditional *front() const; + gtsam::GaussianConditional *back() const; + void push_back(gtsam::GaussianConditional *conditional); + void push_back(const gtsam::GaussianBayesNet &bayesNet); - gtsam::VectorValues optimize() const; - gtsam::VectorValues optimize(gtsam::VectorValues& solutionForMissing) const; - gtsam::VectorValues optimizeGradientSearch() const; - gtsam::VectorValues gradient(const gtsam::VectorValues& x0) const; - gtsam::VectorValues gradientAtZero() const; - double error(const gtsam::VectorValues& x) const; - double determinant() const; - double logDeterminant() const; - gtsam::VectorValues backSubstitute(const gtsam::VectorValues& gx) const; - gtsam::VectorValues backSubstituteTranspose(const gtsam::VectorValues& gx) const; -}; + gtsam::VectorValues optimize() const; + gtsam::VectorValues optimize(gtsam::VectorValues &solutionForMissing) const; + gtsam::VectorValues optimizeGradientSearch() const; + gtsam::VectorValues gradient(const gtsam::VectorValues &x0) const; + gtsam::VectorValues gradientAtZero() const; + double error(const gtsam::VectorValues &x) const; + double determinant() const; + double logDeterminant() const; + gtsam::VectorValues backSubstitute(const gtsam::VectorValues &gx) const; + gtsam::VectorValues backSubstituteTranspose(const gtsam::VectorValues &gx) const; + }; #include -virtual class GaussianBayesTree { - // Standard Constructors and Named Constructors - GaussianBayesTree(); - GaussianBayesTree(const gtsam::GaussianBayesTree& other); - bool equals(const gtsam::GaussianBayesTree& other, double tol) const; - void print(string s); - size_t size() const; - bool empty() const; - size_t numCachedSeparatorMarginals() const; - void saveGraph(string s) const; + virtual class GaussianBayesTree + { + // Standard Constructors and Named Constructors + GaussianBayesTree(); + GaussianBayesTree(const gtsam::GaussianBayesTree &other); + bool equals(const gtsam::GaussianBayesTree &other, double tol) const; + void print(string s); + size_t size() const; + bool empty() const; + size_t numCachedSeparatorMarginals() const; + void saveGraph(string s) const; - gtsam::VectorValues optimize() const; - gtsam::VectorValues optimizeGradientSearch() const; - gtsam::VectorValues gradient(const gtsam::VectorValues& x0) const; - gtsam::VectorValues gradientAtZero() const; - double error(const gtsam::VectorValues& x) const; - double determinant() const; - double logDeterminant() const; - Matrix marginalCovariance(size_t key) const; - gtsam::GaussianConditional* marginalFactor(size_t key) const; - gtsam::GaussianFactorGraph* joint(size_t key1, size_t key2) const; - gtsam::GaussianBayesNet* jointBayesNet(size_t key1, size_t key2) const; -}; + gtsam::VectorValues optimize() const; + gtsam::VectorValues optimizeGradientSearch() const; + gtsam::VectorValues gradient(const gtsam::VectorValues &x0) const; + gtsam::VectorValues gradientAtZero() const; + double error(const gtsam::VectorValues &x) const; + double determinant() const; + double logDeterminant() const; + Matrix marginalCovariance(size_t key) const; + gtsam::GaussianConditional *marginalFactor(size_t key) const; + gtsam::GaussianFactorGraph *joint(size_t key1, size_t key2) const; + gtsam::GaussianBayesNet *jointBayesNet(size_t key1, size_t key2) const; + }; #include -class Errors { + class Errors + { //Constructors Errors(); - Errors(const gtsam::VectorValues& V); + Errors(const gtsam::VectorValues &V); //Testable void print(string s); - bool equals(const gtsam::Errors& expected, double tol) const; -}; + bool equals(const gtsam::Errors &expected, double tol) const; + }; #include -class GaussianISAM { - //Constructor - GaussianISAM(); + class GaussianISAM + { + //Constructor + GaussianISAM(); - //Standard Interface - void update(const gtsam::GaussianFactorGraph& newFactors); - void saveGraph(string s) const; - void clear(); -}; + //Standard Interface + void update(const gtsam::GaussianFactorGraph &newFactors); + void saveGraph(string s) const; + void clear(); + }; #include -virtual class IterativeOptimizationParameters { - string getVerbosity() const; - void setVerbosity(string s) ; - void print() const; -}; + virtual class IterativeOptimizationParameters + { + string getVerbosity() const; + void setVerbosity(string s); + void print() const; + }; -//virtual class IterativeSolver { -// IterativeSolver(); -// gtsam::VectorValues optimize (); -//}; + //virtual class IterativeSolver { + // IterativeSolver(); + // gtsam::VectorValues optimize (); + //}; #include -virtual class ConjugateGradientParameters : gtsam::IterativeOptimizationParameters { - ConjugateGradientParameters(); - int getMinIterations() const ; - int getMaxIterations() const ; - int getReset() const; - double getEpsilon_rel() const; - double getEpsilon_abs() const; + virtual class ConjugateGradientParameters : gtsam::IterativeOptimizationParameters + { + ConjugateGradientParameters(); + int getMinIterations() const; + int getMaxIterations() const; + int getReset() const; + double getEpsilon_rel() const; + double getEpsilon_abs() const; - void setMinIterations(int value); - void setMaxIterations(int value); - void setReset(int value); - void setEpsilon_rel(double value); - void setEpsilon_abs(double value); - void print() const; -}; + void setMinIterations(int value); + void setMaxIterations(int value); + void setReset(int value); + void setEpsilon_rel(double value); + void setEpsilon_abs(double value); + void print() const; + }; #include -virtual class PreconditionerParameters { - PreconditionerParameters(); -}; + virtual class PreconditionerParameters + { + PreconditionerParameters(); + }; -virtual class DummyPreconditionerParameters : gtsam::PreconditionerParameters { - DummyPreconditionerParameters(); -}; + virtual class DummyPreconditionerParameters : gtsam::PreconditionerParameters + { + DummyPreconditionerParameters(); + }; #include -virtual class PCGSolverParameters : gtsam::ConjugateGradientParameters { - PCGSolverParameters(); - void print(string s); - void setPreconditionerParams(gtsam::PreconditionerParameters* preconditioner); -}; + virtual class PCGSolverParameters : gtsam::ConjugateGradientParameters + { + PCGSolverParameters(); + void print(string s); + void setPreconditionerParams(gtsam::PreconditionerParameters *preconditioner); + }; #include -virtual class SubgraphSolverParameters : gtsam::ConjugateGradientParameters { - SubgraphSolverParameters(); - void print() const; -}; + virtual class SubgraphSolverParameters : gtsam::ConjugateGradientParameters + { + SubgraphSolverParameters(); + void print() const; + }; -virtual class SubgraphSolver { - SubgraphSolver(const gtsam::GaussianFactorGraph &A, const gtsam::SubgraphSolverParameters ¶meters, const gtsam::Ordering& ordering); - SubgraphSolver(const gtsam::GaussianFactorGraph &Ab1, const gtsam::GaussianFactorGraph* Ab2, const gtsam::SubgraphSolverParameters ¶meters, const gtsam::Ordering& ordering); - gtsam::VectorValues optimize() const; -}; + virtual class SubgraphSolver + { + SubgraphSolver(const gtsam::GaussianFactorGraph &A, const gtsam::SubgraphSolverParameters ¶meters, const gtsam::Ordering &ordering); + SubgraphSolver(const gtsam::GaussianFactorGraph &Ab1, const gtsam::GaussianFactorGraph *Ab2, const gtsam::SubgraphSolverParameters ¶meters, const gtsam::Ordering &ordering); + gtsam::VectorValues optimize() const; + }; #include -class KalmanFilter { - KalmanFilter(size_t n); - // gtsam::GaussianDensity* init(Vector x0, const gtsam::SharedDiagonal& P0); - gtsam::GaussianDensity* init(Vector x0, Matrix P0); - void print(string s) const; - static size_t step(gtsam::GaussianDensity* p); - gtsam::GaussianDensity* predict(gtsam::GaussianDensity* p, Matrix F, - Matrix B, Vector u, const gtsam::noiseModel::Diagonal* modelQ); - gtsam::GaussianDensity* predictQ(gtsam::GaussianDensity* p, Matrix F, - Matrix B, Vector u, Matrix Q); - gtsam::GaussianDensity* predict2(gtsam::GaussianDensity* p, Matrix A0, - Matrix A1, Vector b, const gtsam::noiseModel::Diagonal* model); - gtsam::GaussianDensity* update(gtsam::GaussianDensity* p, Matrix H, - Vector z, const gtsam::noiseModel::Diagonal* model); - gtsam::GaussianDensity* updateQ(gtsam::GaussianDensity* p, Matrix H, - Vector z, Matrix Q); -}; + class KalmanFilter + { + KalmanFilter(size_t n); + // gtsam::GaussianDensity* init(Vector x0, const gtsam::SharedDiagonal& P0); + gtsam::GaussianDensity *init(Vector x0, Matrix P0); + void print(string s) const; + static size_t step(gtsam::GaussianDensity *p); + gtsam::GaussianDensity *predict(gtsam::GaussianDensity *p, Matrix F, + Matrix B, Vector u, const gtsam::noiseModel::Diagonal *modelQ); + gtsam::GaussianDensity *predictQ(gtsam::GaussianDensity *p, Matrix F, + Matrix B, Vector u, Matrix Q); + gtsam::GaussianDensity *predict2(gtsam::GaussianDensity *p, Matrix A0, + Matrix A1, Vector b, const gtsam::noiseModel::Diagonal *model); + gtsam::GaussianDensity *update(gtsam::GaussianDensity *p, Matrix H, + Vector z, const gtsam::noiseModel::Diagonal *model); + gtsam::GaussianDensity *updateQ(gtsam::GaussianDensity *p, Matrix H, + Vector z, Matrix Q); + }; -//************************************************************************* -// nonlinear -//************************************************************************* + //************************************************************************* + // nonlinear + //************************************************************************* #include -size_t symbol(char chr, size_t index); -char symbolChr(size_t key); -size_t symbolIndex(size_t key); + size_t symbol(char chr, size_t index); + char symbolChr(size_t key); + size_t symbolIndex(size_t key); -namespace symbol_shorthand { - size_t A(size_t j); - size_t B(size_t j); - size_t C(size_t j); - size_t D(size_t j); - size_t E(size_t j); - size_t F(size_t j); - size_t G(size_t j); - size_t H(size_t j); - size_t I(size_t j); - size_t J(size_t j); - size_t K(size_t j); - size_t L(size_t j); - size_t M(size_t j); - size_t N(size_t j); - size_t O(size_t j); - size_t P(size_t j); - size_t Q(size_t j); - size_t R(size_t j); - size_t S(size_t j); - size_t T(size_t j); - size_t U(size_t j); - size_t V(size_t j); - size_t W(size_t j); - size_t X(size_t j); - size_t Y(size_t j); - size_t Z(size_t j); -}///\namespace symbol + namespace symbol_shorthand + { + size_t A(size_t j); + size_t B(size_t j); + size_t C(size_t j); + size_t D(size_t j); + size_t E(size_t j); + size_t F(size_t j); + size_t G(size_t j); + size_t H(size_t j); + size_t I(size_t j); + size_t J(size_t j); + size_t K(size_t j); + size_t L(size_t j); + size_t M(size_t j); + size_t N(size_t j); + size_t O(size_t j); + size_t P(size_t j); + size_t Q(size_t j); + size_t R(size_t j); + size_t S(size_t j); + size_t T(size_t j); + size_t U(size_t j); + size_t V(size_t j); + size_t W(size_t j); + size_t X(size_t j); + size_t Y(size_t j); + size_t Z(size_t j); + } // namespace symbol_shorthand -// Default keyformatter -void PrintKeyList (const gtsam::KeyList& keys); -void PrintKeyList (const gtsam::KeyList& keys, string s); -void PrintKeyVector(const gtsam::KeyVector& keys); -void PrintKeyVector(const gtsam::KeyVector& keys, string s); -void PrintKeySet (const gtsam::KeySet& keys); -void PrintKeySet (const gtsam::KeySet& keys, string s); + // Default keyformatter + void PrintKeyList(const gtsam::KeyList &keys); + void PrintKeyList(const gtsam::KeyList &keys, string s); + void PrintKeyVector(const gtsam::KeyVector &keys); + void PrintKeyVector(const gtsam::KeyVector &keys, string s); + void PrintKeySet(const gtsam::KeySet &keys); + void PrintKeySet(const gtsam::KeySet &keys, string s); #include -class LabeledSymbol { - LabeledSymbol(size_t full_key); - LabeledSymbol(const gtsam::LabeledSymbol& key); - LabeledSymbol(unsigned char valType, unsigned char label, size_t j); + class LabeledSymbol + { + LabeledSymbol(size_t full_key); + LabeledSymbol(const gtsam::LabeledSymbol &key); + LabeledSymbol(unsigned char valType, unsigned char label, size_t j); - size_t key() const; - unsigned char label() const; - unsigned char chr() const; - size_t index() const; + size_t key() const; + unsigned char label() const; + unsigned char chr() const; + size_t index() const; - gtsam::LabeledSymbol upper() const; - gtsam::LabeledSymbol lower() const; - gtsam::LabeledSymbol newChr(unsigned char c) const; - gtsam::LabeledSymbol newLabel(unsigned char label) const; + gtsam::LabeledSymbol upper() const; + gtsam::LabeledSymbol lower() const; + gtsam::LabeledSymbol newChr(unsigned char c) const; + gtsam::LabeledSymbol newLabel(unsigned char label) const; - void print(string s) const; -}; + void print(string s) const; + }; -size_t mrsymbol(unsigned char c, unsigned char label, size_t j); -unsigned char mrsymbolChr(size_t key); -unsigned char mrsymbolLabel(size_t key); -size_t mrsymbolIndex(size_t key); + size_t mrsymbol(unsigned char c, unsigned char label, size_t j); + unsigned char mrsymbolChr(size_t key); + unsigned char mrsymbolLabel(size_t key); + size_t mrsymbolIndex(size_t key); #include -class Ordering { - // Standard Constructors and Named Constructors - Ordering(); - Ordering(const gtsam::Ordering& other); + class Ordering + { + // Standard Constructors and Named Constructors + Ordering(); + Ordering(const gtsam::Ordering &other); - // Testable - void print(string s) const; - bool equals(const gtsam::Ordering& ord, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Ordering &ord, double tol) const; - // Standard interface - size_t size() const; - size_t at(size_t key) const; - void push_back(size_t key); + // Standard interface + size_t size() const; + size_t at(size_t key) const; + void push_back(size_t key); - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -class NonlinearFactorGraph { - NonlinearFactorGraph(); - NonlinearFactorGraph(const gtsam::NonlinearFactorGraph& graph); + class NonlinearFactorGraph + { + NonlinearFactorGraph(); + NonlinearFactorGraph(const gtsam::NonlinearFactorGraph &graph); - // FactorGraph - void print(string s) const; - bool equals(const gtsam::NonlinearFactorGraph& fg, double tol) const; - size_t size() const; - bool empty() const; - void remove(size_t i); - void replace(size_t i, gtsam::NonlinearFactor* factors); - void resize(size_t size); - size_t nrFactors() const; - gtsam::NonlinearFactor* at(size_t idx) const; - void push_back(const gtsam::NonlinearFactorGraph& factors); - void push_back(gtsam::NonlinearFactor* factor); - void add(gtsam::NonlinearFactor* factor); - bool exists(size_t idx) const; - gtsam::KeySet keys() const; - gtsam::KeyVector keyVector() const; + // FactorGraph + void print(string s) const; + bool equals(const gtsam::NonlinearFactorGraph &fg, double tol) const; + size_t size() const; + bool empty() const; + void remove(size_t i); + void replace(size_t i, gtsam::NonlinearFactor *factors); + void resize(size_t size); + size_t nrFactors() const; + gtsam::NonlinearFactor *at(size_t idx) const; + void push_back(const gtsam::NonlinearFactorGraph &factors); + void push_back(gtsam::NonlinearFactor *factor); + void add(gtsam::NonlinearFactor *factor); + bool exists(size_t idx) const; + gtsam::KeySet keys() const; + gtsam::KeyVector keyVector() const; - template, gtsam::imuBias::ConstantBias}> - void addPrior(size_t key, const T& prior, const gtsam::noiseModel::Base* noiseModel); + template , gtsam::imuBias::ConstantBias}> + void addPrior(size_t key, const T &prior, const gtsam::noiseModel::Base *noiseModel); - // NonlinearFactorGraph - void printErrors(const gtsam::Values& values) const; - double error(const gtsam::Values& values) const; - double probPrime(const gtsam::Values& values) const; - gtsam::Ordering orderingCOLAMD() const; - // Ordering* orderingCOLAMDConstrained(const gtsam::Values& c, const std::map& constraints) const; - gtsam::GaussianFactorGraph* linearize(const gtsam::Values& values) const; - gtsam::NonlinearFactorGraph clone() const; + // NonlinearFactorGraph + void printErrors(const gtsam::Values &values) const; + double error(const gtsam::Values &values) const; + double probPrime(const gtsam::Values &values) const; + gtsam::Ordering orderingCOLAMD() const; + // Ordering* orderingCOLAMDConstrained(const gtsam::Values& c, const std::map& constraints) const; + gtsam::GaussianFactorGraph *linearize(const gtsam::Values &values) const; + gtsam::NonlinearFactorGraph clone() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -virtual class NonlinearFactor { - // Factor base class - size_t size() const; - gtsam::KeyVector keys() const; - void print(string s) const; - void printKeys(string s) const; - // NonlinearFactor - bool equals(const gtsam::NonlinearFactor& other, double tol) const; - double error(const gtsam::Values& c) const; - size_t dim() const; - bool active(const gtsam::Values& c) const; - gtsam::GaussianFactor* linearize(const gtsam::Values& c) const; - gtsam::NonlinearFactor* clone() const; - // gtsam::NonlinearFactor* rekey(const gtsam::KeyVector& newKeys) const; //TODO: Conversion from KeyVector to std::vector does not happen -}; + virtual class NonlinearFactor + { + // Factor base class + size_t size() const; + gtsam::KeyVector keys() const; + void print(string s) const; + void printKeys(string s) const; + // NonlinearFactor + bool equals(const gtsam::NonlinearFactor &other, double tol) const; + double error(const gtsam::Values &c) const; + size_t dim() const; + bool active(const gtsam::Values &c) const; + gtsam::GaussianFactor *linearize(const gtsam::Values &c) const; + gtsam::NonlinearFactor *clone() const; + // gtsam::NonlinearFactor* rekey(const gtsam::KeyVector& newKeys) const; //TODO: Conversion from KeyVector to std::vector does not happen + }; #include -virtual class NoiseModelFactor: gtsam::NonlinearFactor { - bool equals(const gtsam::NoiseModelFactor& other, double tol) const; - gtsam::noiseModel::Base* noiseModel() const; - Vector unwhitenedError(const gtsam::Values& x) const; - Vector whitenedError(const gtsam::Values& x) const; -}; + virtual class NoiseModelFactor : gtsam::NonlinearFactor + { + bool equals(const gtsam::NoiseModelFactor &other, double tol) const; + gtsam::noiseModel::Base *noiseModel() const; + Vector unwhitenedError(const gtsam::Values &x) const; + Vector whitenedError(const gtsam::Values &x) const; + }; #include -class Values { - Values(); - Values(const gtsam::Values& other); + class Values + { + Values(); + Values(const gtsam::Values &other); - size_t size() const; - bool empty() const; - void clear(); - size_t dim() const; + size_t size() const; + bool empty() const; + void clear(); + size_t dim() const; - void print(string s) const; - bool equals(const gtsam::Values& other, double tol) const; + void print(string s) const; + bool equals(const gtsam::Values &other, double tol) const; - void insert(const gtsam::Values& values); - void update(const gtsam::Values& values); - void erase(size_t j); - void swap(gtsam::Values& values); + void insert(const gtsam::Values &values); + void update(const gtsam::Values &values); + void erase(size_t j); + void swap(gtsam::Values &values); - bool exists(size_t j) const; - gtsam::KeyVector keys() const; + bool exists(size_t j) const; + gtsam::KeyVector keys() const; - gtsam::VectorValues zeroVectors() const; + gtsam::VectorValues zeroVectors() const; - gtsam::Values retract(const gtsam::VectorValues& delta) const; - gtsam::VectorValues localCoordinates(const gtsam::Values& cp) const; + gtsam::Values retract(const gtsam::VectorValues &delta) const; + gtsam::VectorValues localCoordinates(const gtsam::Values &cp) const; - // enabling serialization functionality - void serialize() const; + // enabling serialization functionality + void serialize() const; - // New in 4.0, we have to specialize every insert/update/at to generate wrappers - // Instead of the old: - // void insert(size_t j, const gtsam::Value& value); - // void update(size_t j, const gtsam::Value& val); - // gtsam::Value at(size_t j) const; - - // The order is important: Vector has to precede Point2/Point3 so `atVector` - // can work for those fixed-size vectors. - void insert(size_t j, Vector vector); - void insert(size_t j, Matrix matrix); - void insert(size_t j, const gtsam::Point2& point2); - void insert(size_t j, const gtsam::Point3& point3); - void insert(size_t j, const gtsam::Rot2& rot2); - void insert(size_t j, const gtsam::Pose2& pose2); - void insert(size_t j, const gtsam::SO3& R); - void insert(size_t j, const gtsam::SO4& Q); - void insert(size_t j, const gtsam::SOn& P); - void insert(size_t j, const gtsam::Rot3& rot3); - void insert(size_t j, const gtsam::Pose3& pose3); - void insert(size_t j, const gtsam::Unit3& unit3); - void insert(size_t j, const gtsam::Cal3_S2& cal3_s2); - void insert(size_t j, const gtsam::Cal3DS2& cal3ds2); - void insert(size_t j, const gtsam::Cal3Bundler& cal3bundler); - void insert(size_t j, const gtsam::EssentialMatrix& essential_matrix); - void insert(size_t j, const gtsam::PinholeCameraCal3_S2& simple_camera); - void insert(size_t j, const gtsam::PinholeCamera& camera); - void insert(size_t j, const gtsam::imuBias::ConstantBias& constant_bias); - void insert(size_t j, const gtsam::NavState& nav_state); + // New in 4.0, we have to specialize every insert/update/at to generate wrappers + // Instead of the old: + // void insert(size_t j, const gtsam::Value& value); + // void update(size_t j, const gtsam::Value& val); + // gtsam::Value at(size_t j) const; - void update(size_t j, const gtsam::Point2& point2); - void update(size_t j, const gtsam::Point3& point3); - void update(size_t j, const gtsam::Rot2& rot2); - void update(size_t j, const gtsam::Pose2& pose2); - void update(size_t j, const gtsam::SO3& R); - void update(size_t j, const gtsam::SO4& Q); - void update(size_t j, const gtsam::SOn& P); - void update(size_t j, const gtsam::Rot3& rot3); - void update(size_t j, const gtsam::Pose3& pose3); - void update(size_t j, const gtsam::Unit3& unit3); - void update(size_t j, const gtsam::Cal3_S2& cal3_s2); - void update(size_t j, const gtsam::Cal3DS2& cal3ds2); - void update(size_t j, const gtsam::Cal3Bundler& cal3bundler); - void update(size_t j, const gtsam::EssentialMatrix& essential_matrix); - void update(size_t j, const gtsam::PinholeCameraCal3_S2& simple_camera); - void update(size_t j, const gtsam::PinholeCamera& camera); - void update(size_t j, const gtsam::imuBias::ConstantBias& constant_bias); - void update(size_t j, const gtsam::NavState& nav_state); - void update(size_t j, Vector vector); - void update(size_t j, Matrix matrix); + // The order is important: Vector has to precede Point2/Point3 so `atVector` + // can work for those fixed-size vectors. + void insert(size_t j, Vector vector); + void insert(size_t j, Matrix matrix); + void insert(size_t j, const gtsam::Point2 &point2); + void insert(size_t j, const gtsam::Point3 &point3); + void insert(size_t j, const gtsam::Rot2 &rot2); + void insert(size_t j, const gtsam::Pose2 &pose2); + void insert(size_t j, const gtsam::SO3 &R); + void insert(size_t j, const gtsam::SO4 &Q); + void insert(size_t j, const gtsam::SOn &P); + void insert(size_t j, const gtsam::Rot3 &rot3); + void insert(size_t j, const gtsam::Pose3 &pose3); + void insert(size_t j, const gtsam::Unit3 &unit3); + void insert(size_t j, const gtsam::Cal3_S2 &cal3_s2); + void insert(size_t j, const gtsam::Cal3DS2 &cal3ds2); + void insert(size_t j, const gtsam::Cal3Bundler &cal3bundler); + void insert(size_t j, const gtsam::EssentialMatrix &essential_matrix); + void insert(size_t j, const gtsam::PinholeCameraCal3_S2 &simple_camera); + void insert(size_t j, const gtsam::PinholeCamera &camera); + void insert(size_t j, const gtsam::imuBias::ConstantBias &constant_bias); + void insert(size_t j, const gtsam::NavState &nav_state); - template, gtsam::imuBias::ConstantBias, gtsam::NavState, Vector, Matrix}> - T at(size_t j); + void update(size_t j, const gtsam::Point2 &point2); + void update(size_t j, const gtsam::Point3 &point3); + void update(size_t j, const gtsam::Rot2 &rot2); + void update(size_t j, const gtsam::Pose2 &pose2); + void update(size_t j, const gtsam::SO3 &R); + void update(size_t j, const gtsam::SO4 &Q); + void update(size_t j, const gtsam::SOn &P); + void update(size_t j, const gtsam::Rot3 &rot3); + void update(size_t j, const gtsam::Pose3 &pose3); + void update(size_t j, const gtsam::Unit3 &unit3); + void update(size_t j, const gtsam::Cal3_S2 &cal3_s2); + void update(size_t j, const gtsam::Cal3DS2 &cal3ds2); + void update(size_t j, const gtsam::Cal3Bundler &cal3bundler); + void update(size_t j, const gtsam::EssentialMatrix &essential_matrix); + void update(size_t j, const gtsam::PinholeCameraCal3_S2 &simple_camera); + void update(size_t j, const gtsam::PinholeCamera &camera); + void update(size_t j, const gtsam::imuBias::ConstantBias &constant_bias); + void update(size_t j, const gtsam::NavState &nav_state); + void update(size_t j, Vector vector); + void update(size_t j, Matrix matrix); - /// version for double - void insertDouble(size_t j, double c); - double atDouble(size_t j) const; -}; + template , gtsam::imuBias::ConstantBias, gtsam::NavState, Vector, Matrix}> + T at(size_t j); + + /// version for double + void insertDouble(size_t j, double c); + double atDouble(size_t j) const; + }; #include -class Marginals { - Marginals(const gtsam::NonlinearFactorGraph& graph, - const gtsam::Values& solution); - Marginals(const gtsam::GaussianFactorGraph& gfgraph, - const gtsam::Values& solution); - Marginals(const gtsam::GaussianFactorGraph& gfgraph, - const gtsam::VectorValues& solutionvec); + class Marginals + { + Marginals(const gtsam::NonlinearFactorGraph &graph, + const gtsam::Values &solution); + Marginals(const gtsam::GaussianFactorGraph &gfgraph, + const gtsam::Values &solution); + Marginals(const gtsam::GaussianFactorGraph &gfgraph, + const gtsam::VectorValues &solutionvec); - void print(string s) const; - Matrix marginalCovariance(size_t variable) const; - Matrix marginalInformation(size_t variable) const; - gtsam::JointMarginal jointMarginalCovariance(const gtsam::KeyVector& variables) const; - gtsam::JointMarginal jointMarginalInformation(const gtsam::KeyVector& variables) const; -}; + void print(string s) const; + Matrix marginalCovariance(size_t variable) const; + Matrix marginalInformation(size_t variable) const; + gtsam::JointMarginal jointMarginalCovariance(const gtsam::KeyVector &variables) const; + gtsam::JointMarginal jointMarginalInformation(const gtsam::KeyVector &variables) const; + }; -class JointMarginal { - Matrix at(size_t iVariable, size_t jVariable) const; - Matrix fullMatrix() const; - void print(string s) const; - void print() const; -}; + class JointMarginal + { + Matrix at(size_t iVariable, size_t jVariable) const; + Matrix fullMatrix() const; + void print(string s) const; + void print() const; + }; #include -virtual class LinearContainerFactor : gtsam::NonlinearFactor { + virtual class LinearContainerFactor : gtsam::NonlinearFactor + { - LinearContainerFactor(gtsam::GaussianFactor* factor, const gtsam::Values& linearizationPoint); - LinearContainerFactor(gtsam::GaussianFactor* factor); + LinearContainerFactor(gtsam::GaussianFactor *factor, const gtsam::Values &linearizationPoint); + LinearContainerFactor(gtsam::GaussianFactor *factor); - gtsam::GaussianFactor* factor() const; -// const boost::optional& linearizationPoint() const; + gtsam::GaussianFactor *factor() const; + // const boost::optional& linearizationPoint() const; - bool isJacobian() const; - gtsam::JacobianFactor* toJacobian() const; - gtsam::HessianFactor* toHessian() const; + bool isJacobian() const; + gtsam::JacobianFactor *toJacobian() const; + gtsam::HessianFactor *toHessian() const; - static gtsam::NonlinearFactorGraph ConvertLinearGraph(const gtsam::GaussianFactorGraph& linear_graph, - const gtsam::Values& linearizationPoint); + static gtsam::NonlinearFactorGraph ConvertLinearGraph(const gtsam::GaussianFactorGraph &linear_graph, + const gtsam::Values &linearizationPoint); - static gtsam::NonlinearFactorGraph ConvertLinearGraph(const gtsam::GaussianFactorGraph& linear_graph); + static gtsam::NonlinearFactorGraph ConvertLinearGraph(const gtsam::GaussianFactorGraph &linear_graph); - // enabling serialization functionality - void serializable() const; -}; // \class LinearContainerFactor + // enabling serialization functionality + void serializable() const; + }; // \class LinearContainerFactor // Summarization functionality //#include @@ -2241,196 +2327,210 @@ virtual class LinearContainerFactor : gtsam::NonlinearFactor { // Nonlinear optimizers //************************************************************************* #include -virtual class NonlinearOptimizerParams { - NonlinearOptimizerParams(); - void print(string s) const; + virtual class NonlinearOptimizerParams + { + NonlinearOptimizerParams(); + void print(string s) const; - int getMaxIterations() const; - double getRelativeErrorTol() const; - double getAbsoluteErrorTol() const; - double getErrorTol() const; - string getVerbosity() const; + int getMaxIterations() const; + double getRelativeErrorTol() const; + double getAbsoluteErrorTol() const; + double getErrorTol() const; + string getVerbosity() const; - void setMaxIterations(int value); - void setRelativeErrorTol(double value); - void setAbsoluteErrorTol(double value); - void setErrorTol(double value); - void setVerbosity(string s); + void setMaxIterations(int value); + void setRelativeErrorTol(double value); + void setAbsoluteErrorTol(double value); + void setErrorTol(double value); + void setVerbosity(string s); - string getLinearSolverType() const; - void setLinearSolverType(string solver); + string getLinearSolverType() const; + void setLinearSolverType(string solver); - void setIterativeParams(gtsam::IterativeOptimizationParameters* params); - void setOrdering(const gtsam::Ordering& ordering); - string getOrderingType() const; - void setOrderingType(string ordering); + void setIterativeParams(gtsam::IterativeOptimizationParameters *params); + void setOrdering(const gtsam::Ordering &ordering); + string getOrderingType() const; + void setOrderingType(string ordering); - bool isMultifrontal() const; - bool isSequential() const; - bool isCholmod() const; - bool isIterative() const; -}; + bool isMultifrontal() const; + bool isSequential() const; + bool isCholmod() const; + bool isIterative() const; + }; -bool checkConvergence(double relativeErrorTreshold, - double absoluteErrorTreshold, double errorThreshold, - double currentError, double newError); -bool checkConvergence(const gtsam::NonlinearOptimizerParams& params, - double currentError, double newError); + bool checkConvergence(double relativeErrorTreshold, + double absoluteErrorTreshold, double errorThreshold, + double currentError, double newError); + bool checkConvergence(const gtsam::NonlinearOptimizerParams ¶ms, + double currentError, double newError); #include -virtual class GaussNewtonParams : gtsam::NonlinearOptimizerParams { - GaussNewtonParams(); -}; + virtual class GaussNewtonParams : gtsam::NonlinearOptimizerParams + { + GaussNewtonParams(); + }; #include -virtual class LevenbergMarquardtParams : gtsam::NonlinearOptimizerParams { - LevenbergMarquardtParams(); + virtual class LevenbergMarquardtParams : gtsam::NonlinearOptimizerParams + { + LevenbergMarquardtParams(); - bool getDiagonalDamping() const; - double getlambdaFactor() const; - double getlambdaInitial() const; - double getlambdaLowerBound() const; - double getlambdaUpperBound() const; - bool getUseFixedLambdaFactor(); - string getLogFile() const; - string getVerbosityLM() const; + bool getDiagonalDamping() const; + double getlambdaFactor() const; + double getlambdaInitial() const; + double getlambdaLowerBound() const; + double getlambdaUpperBound() const; + bool getUseFixedLambdaFactor(); + string getLogFile() const; + string getVerbosityLM() const; - void setDiagonalDamping(bool flag); - void setlambdaFactor(double value); - void setlambdaInitial(double value); - void setlambdaLowerBound(double value); - void setlambdaUpperBound(double value); - void setUseFixedLambdaFactor(bool flag); - void setLogFile(string s); - void setVerbosityLM(string s); + void setDiagonalDamping(bool flag); + void setlambdaFactor(double value); + void setlambdaInitial(double value); + void setlambdaLowerBound(double value); + void setlambdaUpperBound(double value); + void setUseFixedLambdaFactor(bool flag); + void setLogFile(string s); + void setVerbosityLM(string s); - static gtsam::LevenbergMarquardtParams LegacyDefaults(); - static gtsam::LevenbergMarquardtParams CeresDefaults(); + static gtsam::LevenbergMarquardtParams LegacyDefaults(); + static gtsam::LevenbergMarquardtParams CeresDefaults(); - static gtsam::LevenbergMarquardtParams EnsureHasOrdering( - gtsam::LevenbergMarquardtParams params, - const gtsam::NonlinearFactorGraph& graph); - static gtsam::LevenbergMarquardtParams ReplaceOrdering( - gtsam::LevenbergMarquardtParams params, const gtsam::Ordering& ordering); -}; + static gtsam::LevenbergMarquardtParams EnsureHasOrdering( + gtsam::LevenbergMarquardtParams params, + const gtsam::NonlinearFactorGraph &graph); + static gtsam::LevenbergMarquardtParams ReplaceOrdering( + gtsam::LevenbergMarquardtParams params, const gtsam::Ordering &ordering); + }; #include -virtual class DoglegParams : gtsam::NonlinearOptimizerParams { - DoglegParams(); + virtual class DoglegParams : gtsam::NonlinearOptimizerParams + { + DoglegParams(); - double getDeltaInitial() const; - string getVerbosityDL() const; + double getDeltaInitial() const; + string getVerbosityDL() const; - void setDeltaInitial(double deltaInitial) const; - void setVerbosityDL(string verbosityDL) const; -}; + void setDeltaInitial(double deltaInitial) const; + void setVerbosityDL(string verbosityDL) const; + }; #include -virtual class NonlinearOptimizer { - gtsam::Values optimize(); - gtsam::Values optimizeSafely(); - double error() const; - int iterations() const; - gtsam::Values values() const; - gtsam::NonlinearFactorGraph graph() const; - gtsam::GaussianFactorGraph* iterate() const; -}; + virtual class NonlinearOptimizer + { + gtsam::Values optimize(); + gtsam::Values optimizeSafely(); + double error() const; + int iterations() const; + gtsam::Values values() const; + gtsam::NonlinearFactorGraph graph() const; + gtsam::GaussianFactorGraph *iterate() const; + }; #include -virtual class GaussNewtonOptimizer : gtsam::NonlinearOptimizer { - GaussNewtonOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues); - GaussNewtonOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues, const gtsam::GaussNewtonParams& params); -}; + virtual class GaussNewtonOptimizer : gtsam::NonlinearOptimizer + { + GaussNewtonOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues); + GaussNewtonOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues, const gtsam::GaussNewtonParams ¶ms); + }; #include -virtual class DoglegOptimizer : gtsam::NonlinearOptimizer { - DoglegOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues); - DoglegOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues, const gtsam::DoglegParams& params); - double getDelta() const; -}; + virtual class DoglegOptimizer : gtsam::NonlinearOptimizer + { + DoglegOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues); + DoglegOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues, const gtsam::DoglegParams ¶ms); + double getDelta() const; + }; #include -virtual class LevenbergMarquardtOptimizer : gtsam::NonlinearOptimizer { - LevenbergMarquardtOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues); - LevenbergMarquardtOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues, const gtsam::LevenbergMarquardtParams& params); - double lambda() const; - void print(string str) const; -}; + virtual class LevenbergMarquardtOptimizer : gtsam::NonlinearOptimizer + { + LevenbergMarquardtOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues); + LevenbergMarquardtOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues, const gtsam::LevenbergMarquardtParams ¶ms); + double lambda() const; + void print(string str) const; + }; #include -class ISAM2GaussNewtonParams { - ISAM2GaussNewtonParams(); + class ISAM2GaussNewtonParams + { + ISAM2GaussNewtonParams(); - void print(string str) const; + void print(string str) const; - /** Getters and Setters for all properties */ - double getWildfireThreshold() const; - void setWildfireThreshold(double wildfireThreshold); -}; + /** Getters and Setters for all properties */ + double getWildfireThreshold() const; + void setWildfireThreshold(double wildfireThreshold); + }; -class ISAM2DoglegParams { - ISAM2DoglegParams(); + class ISAM2DoglegParams + { + ISAM2DoglegParams(); - void print(string str) const; + void print(string str) const; - /** Getters and Setters for all properties */ - double getWildfireThreshold() const; - void setWildfireThreshold(double wildfireThreshold); - double getInitialDelta() const; - void setInitialDelta(double initialDelta); - string getAdaptationMode() const; - void setAdaptationMode(string adaptationMode); - bool isVerbose() const; - void setVerbose(bool verbose); -}; + /** Getters and Setters for all properties */ + double getWildfireThreshold() const; + void setWildfireThreshold(double wildfireThreshold); + double getInitialDelta() const; + void setInitialDelta(double initialDelta); + string getAdaptationMode() const; + void setAdaptationMode(string adaptationMode); + bool isVerbose() const; + void setVerbose(bool verbose); + }; -class ISAM2ThresholdMapValue { - ISAM2ThresholdMapValue(char c, Vector thresholds); - ISAM2ThresholdMapValue(const gtsam::ISAM2ThresholdMapValue& other); -}; + class ISAM2ThresholdMapValue + { + ISAM2ThresholdMapValue(char c, Vector thresholds); + ISAM2ThresholdMapValue(const gtsam::ISAM2ThresholdMapValue &other); + }; -class ISAM2ThresholdMap { - ISAM2ThresholdMap(); - ISAM2ThresholdMap(const gtsam::ISAM2ThresholdMap& other); + class ISAM2ThresholdMap + { + ISAM2ThresholdMap(); + ISAM2ThresholdMap(const gtsam::ISAM2ThresholdMap &other); - // Note: no print function + // Note: no print function - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - void insert(const gtsam::ISAM2ThresholdMapValue& value) const; -}; + // structure specific methods + void insert(const gtsam::ISAM2ThresholdMapValue &value) const; + }; -class ISAM2Params { - ISAM2Params(); + class ISAM2Params + { + ISAM2Params(); - void print(string str) const; + void print(string str) const; - /** Getters and Setters for all properties */ - void setOptimizationParams(const gtsam::ISAM2GaussNewtonParams& gauss_newton__params); - void setOptimizationParams(const gtsam::ISAM2DoglegParams& dogleg_params); - void setRelinearizeThreshold(double threshold); - void setRelinearizeThreshold(const gtsam::ISAM2ThresholdMap& threshold_map); - int getRelinearizeSkip() const; - void setRelinearizeSkip(int relinearizeSkip); - bool isEnableRelinearization() const; - void setEnableRelinearization(bool enableRelinearization); - bool isEvaluateNonlinearError() const; - void setEvaluateNonlinearError(bool evaluateNonlinearError); - string getFactorization() const; - void setFactorization(string factorization); - bool isCacheLinearizedFactors() const; - void setCacheLinearizedFactors(bool cacheLinearizedFactors); - bool isEnableDetailedResults() const; - void setEnableDetailedResults(bool enableDetailedResults); - bool isEnablePartialRelinearizationCheck() const; - void setEnablePartialRelinearizationCheck(bool enablePartialRelinearizationCheck); -}; + /** Getters and Setters for all properties */ + void setOptimizationParams(const gtsam::ISAM2GaussNewtonParams &gauss_newton__params); + void setOptimizationParams(const gtsam::ISAM2DoglegParams &dogleg_params); + void setRelinearizeThreshold(double threshold); + void setRelinearizeThreshold(const gtsam::ISAM2ThresholdMap &threshold_map); + int getRelinearizeSkip() const; + void setRelinearizeSkip(int relinearizeSkip); + bool isEnableRelinearization() const; + void setEnableRelinearization(bool enableRelinearization); + bool isEvaluateNonlinearError() const; + void setEvaluateNonlinearError(bool evaluateNonlinearError); + string getFactorization() const; + void setFactorization(string factorization); + bool isCacheLinearizedFactors() const; + void setCacheLinearizedFactors(bool cacheLinearizedFactors); + bool isEnableDetailedResults() const; + void setEnableDetailedResults(bool enableDetailedResults); + bool isEnablePartialRelinearizationCheck() const; + void setEnablePartialRelinearizationCheck(bool enablePartialRelinearizationCheck); + }; -class ISAM2Clique { + class ISAM2Clique + { //Constructors ISAM2Clique(); @@ -2438,74 +2538,77 @@ class ISAM2Clique { //Standard Interface Vector gradientContribution() const; void print(string s); -}; + }; -class ISAM2Result { - ISAM2Result(); + class ISAM2Result + { + ISAM2Result(); - void print(string str) const; + void print(string str) const; - /** Getters and Setters for all properties */ - size_t getVariablesRelinearized() const; - size_t getVariablesReeliminated() const; - size_t getCliques() const; - double getErrorBefore() const; - double getErrorAfter() const; -}; + /** Getters and Setters for all properties */ + size_t getVariablesRelinearized() const; + size_t getVariablesReeliminated() const; + size_t getCliques() const; + double getErrorBefore() const; + double getErrorAfter() const; + }; -class ISAM2 { - ISAM2(); - ISAM2(const gtsam::ISAM2Params& params); - ISAM2(const gtsam::ISAM2& other); + class ISAM2 + { + ISAM2(); + ISAM2(const gtsam::ISAM2Params ¶ms); + ISAM2(const gtsam::ISAM2 &other); - bool equals(const gtsam::ISAM2& other, double tol) const; - void print(string s) const; - void printStats() const; - void saveGraph(string s) const; + bool equals(const gtsam::ISAM2 &other, double tol) const; + void print(string s) const; + void printStats() const; + void saveGraph(string s) const; - gtsam::ISAM2Result update(); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta, const gtsam::FactorIndices& removeFactorIndices); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta, const gtsam::FactorIndices& removeFactorIndices, const gtsam::KeyGroupMap& constrainedKeys); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta, const gtsam::FactorIndices& removeFactorIndices, gtsam::KeyGroupMap& constrainedKeys, const gtsam::KeyList& noRelinKeys); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta, const gtsam::FactorIndices& removeFactorIndices, gtsam::KeyGroupMap& constrainedKeys, const gtsam::KeyList& noRelinKeys, const gtsam::KeyList& extraReelimKeys); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta, const gtsam::FactorIndices& removeFactorIndices, gtsam::KeyGroupMap& constrainedKeys, const gtsam::KeyList& noRelinKeys, const gtsam::KeyList& extraReelimKeys, bool force_relinearize); + gtsam::ISAM2Result update(); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta, const gtsam::FactorIndices &removeFactorIndices); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta, const gtsam::FactorIndices &removeFactorIndices, const gtsam::KeyGroupMap &constrainedKeys); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta, const gtsam::FactorIndices &removeFactorIndices, gtsam::KeyGroupMap &constrainedKeys, const gtsam::KeyList &noRelinKeys); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta, const gtsam::FactorIndices &removeFactorIndices, gtsam::KeyGroupMap &constrainedKeys, const gtsam::KeyList &noRelinKeys, const gtsam::KeyList &extraReelimKeys); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta, const gtsam::FactorIndices &removeFactorIndices, gtsam::KeyGroupMap &constrainedKeys, const gtsam::KeyList &noRelinKeys, const gtsam::KeyList &extraReelimKeys, bool force_relinearize); - gtsam::Values getLinearizationPoint() const; - gtsam::Values calculateEstimate() const; - template , - Vector, Matrix}> - VALUE calculateEstimate(size_t key) const; - gtsam::Values calculateBestEstimate() const; - Matrix marginalCovariance(size_t key) const; - gtsam::VectorValues getDelta() const; - gtsam::NonlinearFactorGraph getFactorsUnsafe() const; - gtsam::VariableIndex getVariableIndex() const; - gtsam::ISAM2Params params() const; -}; + gtsam::Values getLinearizationPoint() const; + gtsam::Values calculateEstimate() const; + template , + Vector, Matrix}> + VALUE calculateEstimate(size_t key) const; + gtsam::Values calculateBestEstimate() const; + Matrix marginalCovariance(size_t key) const; + gtsam::VectorValues getDelta() const; + gtsam::NonlinearFactorGraph getFactorsUnsafe() const; + gtsam::VariableIndex getVariableIndex() const; + gtsam::ISAM2Params params() const; + }; #include -class NonlinearISAM { - NonlinearISAM(); - NonlinearISAM(int reorderInterval); - void print(string s) const; - void printStats() const; - void saveGraph(string s) const; - gtsam::Values estimate() const; - Matrix marginalCovariance(size_t key) const; - int reorderInterval() const; - int reorderCounter() const; - void update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& initialValues); - void reorder_relinearize(); + class NonlinearISAM + { + NonlinearISAM(); + NonlinearISAM(int reorderInterval); + void print(string s) const; + void printStats() const; + void saveGraph(string s) const; + gtsam::Values estimate() const; + Matrix marginalCovariance(size_t key) const; + int reorderInterval() const; + int reorderCounter() const; + void update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &initialValues); + void reorder_relinearize(); - // These might be expensive as instead of a reference the wrapper will make a copy - gtsam::GaussianISAM bayesTree() const; - gtsam::Values getLinearizationPoint() const; - gtsam::NonlinearFactorGraph getFactorsUnsafe() const; -}; + // These might be expensive as instead of a reference the wrapper will make a copy + gtsam::GaussianISAM bayesTree() const; + gtsam::Values getLinearizationPoint() const; + gtsam::NonlinearFactorGraph getFactorsUnsafe() const; + }; //************************************************************************* // Nonlinear factor types @@ -2514,917 +2617,966 @@ class NonlinearISAM { #include #include -template}> -virtual class PriorFactor : gtsam::NoiseModelFactor { - PriorFactor(size_t key, const T& prior, const gtsam::noiseModel::Base* noiseModel); - T prior() const; - - // enabling serialization functionality - void serialize() const; -}; + template }> + virtual class PriorFactor : gtsam::NoiseModelFactor + { + PriorFactor(size_t key, const T &prior, const gtsam::noiseModel::Base *noiseModel); + T prior() const; + // enabling serialization functionality + void serialize() const; + }; #include -template -virtual class BetweenFactor : gtsam::NoiseModelFactor { - BetweenFactor(size_t key1, size_t key2, const T& relativePose, const gtsam::noiseModel::Base* noiseModel); - T measured() const; + template + virtual class BetweenFactor : gtsam::NoiseModelFactor + { + BetweenFactor(size_t key1, size_t key2, const T &relativePose, const gtsam::noiseModel::Base *noiseModel); + T measured() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -template -virtual class NonlinearEquality : gtsam::NoiseModelFactor { - // Constructor - forces exact evaluation - NonlinearEquality(size_t j, const T& feasible); - // Constructor - allows inexact evaluation - NonlinearEquality(size_t j, const T& feasible, double error_gain); + template + virtual class NonlinearEquality : gtsam::NoiseModelFactor + { + // Constructor - forces exact evaluation + NonlinearEquality(size_t j, const T &feasible); + // Constructor - allows inexact evaluation + NonlinearEquality(size_t j, const T &feasible, double error_gain); - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -template -virtual class RangeFactor : gtsam::NoiseModelFactor { - RangeFactor(size_t key1, size_t key2, double measured, const gtsam::noiseModel::Base* noiseModel); + template + virtual class RangeFactor : gtsam::NoiseModelFactor + { + RangeFactor(size_t key1, size_t key2, double measured, const gtsam::noiseModel::Base *noiseModel); - // enabling serialization functionality - void serialize() const; -}; - -typedef gtsam::RangeFactor RangeFactor2D; -typedef gtsam::RangeFactor RangeFactor3D; -typedef gtsam::RangeFactor RangeFactorPose2; -typedef gtsam::RangeFactor RangeFactorPose3; -typedef gtsam::RangeFactor RangeFactorCalibratedCameraPoint; -typedef gtsam::RangeFactor RangeFactorSimpleCameraPoint; -typedef gtsam::RangeFactor RangeFactorCalibratedCamera; -typedef gtsam::RangeFactor RangeFactorSimpleCamera; + // enabling serialization functionality + void serialize() const; + }; + typedef gtsam::RangeFactor RangeFactor2D; + typedef gtsam::RangeFactor RangeFactor3D; + typedef gtsam::RangeFactor RangeFactorPose2; + typedef gtsam::RangeFactor RangeFactorPose3; + typedef gtsam::RangeFactor RangeFactorCalibratedCameraPoint; + typedef gtsam::RangeFactor RangeFactorSimpleCameraPoint; + typedef gtsam::RangeFactor RangeFactorCalibratedCamera; + typedef gtsam::RangeFactor RangeFactorSimpleCamera; #include -template -virtual class RangeFactorWithTransform : gtsam::NoiseModelFactor { - RangeFactorWithTransform(size_t key1, size_t key2, double measured, const gtsam::noiseModel::Base* noiseModel, const POSE& body_T_sensor); + template + virtual class RangeFactorWithTransform : gtsam::NoiseModelFactor + { + RangeFactorWithTransform(size_t key1, size_t key2, double measured, const gtsam::noiseModel::Base *noiseModel, const POSE &body_T_sensor); - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; -typedef gtsam::RangeFactorWithTransform RangeFactorWithTransform2D; -typedef gtsam::RangeFactorWithTransform RangeFactorWithTransform3D; -typedef gtsam::RangeFactorWithTransform RangeFactorWithTransformPose2; -typedef gtsam::RangeFactorWithTransform RangeFactorWithTransformPose3; + typedef gtsam::RangeFactorWithTransform RangeFactorWithTransform2D; + typedef gtsam::RangeFactorWithTransform RangeFactorWithTransform3D; + typedef gtsam::RangeFactorWithTransform RangeFactorWithTransformPose2; + typedef gtsam::RangeFactorWithTransform RangeFactorWithTransformPose3; #include -template -virtual class BearingFactor : gtsam::NoiseModelFactor { - BearingFactor(size_t key1, size_t key2, const BEARING& measured, const gtsam::noiseModel::Base* noiseModel); + template + virtual class BearingFactor : gtsam::NoiseModelFactor + { + BearingFactor(size_t key1, size_t key2, const BEARING &measured, const gtsam::noiseModel::Base *noiseModel); - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; -typedef gtsam::BearingFactor BearingFactor2D; -typedef gtsam::BearingFactor BearingFactorPose2; + typedef gtsam::BearingFactor BearingFactor2D; + typedef gtsam::BearingFactor BearingFactorPose2; #include -template -class BearingRange { - BearingRange(const BEARING& b, const RANGE& r); - BEARING bearing() const; - RANGE range() const; - static This Measure(const POSE& pose, const POINT& point); - static BEARING MeasureBearing(const POSE& pose, const POINT& point); - static RANGE MeasureRange(const POSE& pose, const POINT& point); - void print(string s) const; -}; + template + class BearingRange + { + BearingRange(const BEARING &b, const RANGE &r); + BEARING bearing() const; + RANGE range() const; + static This Measure(const POSE &pose, const POINT &point); + static BEARING MeasureBearing(const POSE &pose, const POINT &point); + static RANGE MeasureRange(const POSE &pose, const POINT &point); + void print(string s) const; + }; -typedef gtsam::BearingRange BearingRange2D; + typedef gtsam::BearingRange BearingRange2D; #include -template -virtual class BearingRangeFactor : gtsam::NoiseModelFactor { - BearingRangeFactor(size_t poseKey, size_t pointKey, - const BEARING& measuredBearing, const RANGE& measuredRange, - const gtsam::noiseModel::Base* noiseModel); + template + virtual class BearingRangeFactor : gtsam::NoiseModelFactor + { + BearingRangeFactor(size_t poseKey, size_t pointKey, + const BEARING &measuredBearing, const RANGE &measuredRange, + const gtsam::noiseModel::Base *noiseModel); - // enabling serialization functionality - void serialize() const; -}; - -typedef gtsam::BearingRangeFactor BearingRangeFactor2D; -typedef gtsam::BearingRangeFactor BearingRangeFactorPose2; + // enabling serialization functionality + void serialize() const; + }; + typedef gtsam::BearingRangeFactor BearingRangeFactor2D; + typedef gtsam::BearingRangeFactor BearingRangeFactorPose2; #include -template -virtual class GenericProjectionFactor : gtsam::NoiseModelFactor { - GenericProjectionFactor(const gtsam::Point2& measured, const gtsam::noiseModel::Base* noiseModel, - size_t poseKey, size_t pointKey, const CALIBRATION* k); - GenericProjectionFactor(const gtsam::Point2& measured, const gtsam::noiseModel::Base* noiseModel, - size_t poseKey, size_t pointKey, const CALIBRATION* k, const POSE& body_P_sensor); + template + virtual class GenericProjectionFactor : gtsam::NoiseModelFactor + { + GenericProjectionFactor(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *noiseModel, + size_t poseKey, size_t pointKey, const CALIBRATION *k); + GenericProjectionFactor(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *noiseModel, + size_t poseKey, size_t pointKey, const CALIBRATION *k, const POSE &body_P_sensor); - GenericProjectionFactor(const gtsam::Point2& measured, const gtsam::noiseModel::Base* noiseModel, - size_t poseKey, size_t pointKey, const CALIBRATION* k, bool throwCheirality, bool verboseCheirality); - GenericProjectionFactor(const gtsam::Point2& measured, const gtsam::noiseModel::Base* noiseModel, - size_t poseKey, size_t pointKey, const CALIBRATION* k, bool throwCheirality, bool verboseCheirality, - const POSE& body_P_sensor); + GenericProjectionFactor(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *noiseModel, + size_t poseKey, size_t pointKey, const CALIBRATION *k, bool throwCheirality, bool verboseCheirality); + GenericProjectionFactor(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *noiseModel, + size_t poseKey, size_t pointKey, const CALIBRATION *k, bool throwCheirality, bool verboseCheirality, + const POSE &body_P_sensor); - gtsam::Point2 measured() const; - CALIBRATION* calibration() const; - bool verboseCheirality() const; - bool throwCheirality() const; - - // enabling serialization functionality - void serialize() const; -}; -typedef gtsam::GenericProjectionFactor GenericProjectionFactorCal3_S2; -typedef gtsam::GenericProjectionFactor GenericProjectionFactorCal3DS2; + gtsam::Point2 measured() const; + CALIBRATION *calibration() const; + bool verboseCheirality() const; + bool throwCheirality() const; + // enabling serialization functionality + void serialize() const; + }; + typedef gtsam::GenericProjectionFactor GenericProjectionFactorCal3_S2; + typedef gtsam::GenericProjectionFactor GenericProjectionFactorCal3DS2; #include -template -virtual class GeneralSFMFactor : gtsam::NoiseModelFactor { - GeneralSFMFactor(const gtsam::Point2& measured, const gtsam::noiseModel::Base* model, size_t cameraKey, size_t landmarkKey); - gtsam::Point2 measured() const; -}; -typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3_S2; -typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; -typedef gtsam::GeneralSFMFactor, gtsam::Point3> GeneralSFMFactorCal3Bundler; + template + virtual class GeneralSFMFactor : gtsam::NoiseModelFactor + { + GeneralSFMFactor(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *model, size_t cameraKey, size_t landmarkKey); + gtsam::Point2 measured() const; + }; + typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3_S2; + typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; + typedef gtsam::GeneralSFMFactor, gtsam::Point3> GeneralSFMFactorCal3Bundler; -template -virtual class GeneralSFMFactor2 : gtsam::NoiseModelFactor { - GeneralSFMFactor2(const gtsam::Point2& measured, const gtsam::noiseModel::Base* model, size_t poseKey, size_t landmarkKey, size_t calibKey); - gtsam::Point2 measured() const; + template + virtual class GeneralSFMFactor2 : gtsam::NoiseModelFactor + { + GeneralSFMFactor2(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *model, size_t poseKey, size_t landmarkKey, size_t calibKey); + gtsam::Point2 measured() const; - // enabling serialization functionality - void serialize() const; -}; + // enabling serialization functionality + void serialize() const; + }; #include -class SmartProjectionParams { - SmartProjectionParams(); - // TODO(frank): make these work: - // void setLinearizationMode(LinearizationMode linMode); - // void setDegeneracyMode(DegeneracyMode degMode); - void setRankTolerance(double rankTol); - void setEnableEPI(bool enableEPI); - void setLandmarkDistanceThreshold(bool landmarkDistanceThreshold); - void setDynamicOutlierRejectionThreshold(bool dynOutRejectionThreshold); -}; + class SmartProjectionParams + { + SmartProjectionParams(); + // TODO(frank): make these work: + // void setLinearizationMode(LinearizationMode linMode); + // void setDegeneracyMode(DegeneracyMode degMode); + void setRankTolerance(double rankTol); + void setEnableEPI(bool enableEPI); + void setLandmarkDistanceThreshold(bool landmarkDistanceThreshold); + void setDynamicOutlierRejectionThreshold(bool dynOutRejectionThreshold); + }; #include -template -virtual class SmartProjectionPoseFactor: gtsam::NonlinearFactor { + template + virtual class SmartProjectionPoseFactor : gtsam::NonlinearFactor + { - SmartProjectionPoseFactor(const gtsam::noiseModel::Base* noise, - const CALIBRATION* K); - SmartProjectionPoseFactor(const gtsam::noiseModel::Base* noise, - const CALIBRATION* K, - const gtsam::Pose3& body_P_sensor); - SmartProjectionPoseFactor(const gtsam::noiseModel::Base* noise, - const CALIBRATION* K, - const gtsam::SmartProjectionParams& params); - SmartProjectionPoseFactor(const gtsam::noiseModel::Base* noise, - const CALIBRATION* K, - const gtsam::Pose3& body_P_sensor, - const gtsam::SmartProjectionParams& params); + SmartProjectionPoseFactor(const gtsam::noiseModel::Base *noise, + const CALIBRATION *K); + SmartProjectionPoseFactor(const gtsam::noiseModel::Base *noise, + const CALIBRATION *K, + const gtsam::Pose3 &body_P_sensor); + SmartProjectionPoseFactor(const gtsam::noiseModel::Base *noise, + const CALIBRATION *K, + const gtsam::SmartProjectionParams ¶ms); + SmartProjectionPoseFactor(const gtsam::noiseModel::Base *noise, + const CALIBRATION *K, + const gtsam::Pose3 &body_P_sensor, + const gtsam::SmartProjectionParams ¶ms); - void add(const gtsam::Point2& measured_i, size_t poseKey_i); + void add(const gtsam::Point2 &measured_i, size_t poseKey_i); - // enabling serialization functionality - //void serialize() const; -}; - -typedef gtsam::SmartProjectionPoseFactor SmartProjectionPose3Factor; + // enabling serialization functionality + //void serialize() const; + }; + typedef gtsam::SmartProjectionPoseFactor SmartProjectionPose3Factor; #include -template -virtual class GenericStereoFactor : gtsam::NoiseModelFactor { - GenericStereoFactor(const gtsam::StereoPoint2& measured, const gtsam::noiseModel::Base* noiseModel, - size_t poseKey, size_t landmarkKey, const gtsam::Cal3_S2Stereo* K); - gtsam::StereoPoint2 measured() const; - gtsam::Cal3_S2Stereo* calibration() const; + template + virtual class GenericStereoFactor : gtsam::NoiseModelFactor + { + GenericStereoFactor(const gtsam::StereoPoint2 &measured, const gtsam::noiseModel::Base *noiseModel, + size_t poseKey, size_t landmarkKey, const gtsam::Cal3_S2Stereo *K); + gtsam::StereoPoint2 measured() const; + gtsam::Cal3_S2Stereo *calibration() const; - // enabling serialization functionality - void serialize() const; -}; -typedef gtsam::GenericStereoFactor GenericStereoFactor3D; + // enabling serialization functionality + void serialize() const; + }; + typedef gtsam::GenericStereoFactor GenericStereoFactor3D; #include -template -virtual class PoseTranslationPrior : gtsam::NoiseModelFactor { - PoseTranslationPrior(size_t key, const POSE& pose_z, const gtsam::noiseModel::Base* noiseModel); -}; + template + virtual class PoseTranslationPrior : gtsam::NoiseModelFactor + { + PoseTranslationPrior(size_t key, const POSE &pose_z, const gtsam::noiseModel::Base *noiseModel); + }; -typedef gtsam::PoseTranslationPrior PoseTranslationPrior2D; -typedef gtsam::PoseTranslationPrior PoseTranslationPrior3D; + typedef gtsam::PoseTranslationPrior PoseTranslationPrior2D; + typedef gtsam::PoseTranslationPrior PoseTranslationPrior3D; #include -template -virtual class PoseRotationPrior : gtsam::NoiseModelFactor { - PoseRotationPrior(size_t key, const POSE& pose_z, const gtsam::noiseModel::Base* noiseModel); -}; + template + virtual class PoseRotationPrior : gtsam::NoiseModelFactor + { + PoseRotationPrior(size_t key, const POSE &pose_z, const gtsam::noiseModel::Base *noiseModel); + }; -typedef gtsam::PoseRotationPrior PoseRotationPrior2D; -typedef gtsam::PoseRotationPrior PoseRotationPrior3D; + typedef gtsam::PoseRotationPrior PoseRotationPrior2D; + typedef gtsam::PoseRotationPrior PoseRotationPrior3D; #include -virtual class EssentialMatrixFactor : gtsam::NoiseModelFactor { - EssentialMatrixFactor(size_t key, const gtsam::Point2& pA, const gtsam::Point2& pB, - const gtsam::noiseModel::Base* noiseModel); -}; + virtual class EssentialMatrixFactor : gtsam::NoiseModelFactor + { + EssentialMatrixFactor(size_t key, const gtsam::Point2 &pA, const gtsam::Point2 &pB, + const gtsam::noiseModel::Base *noiseModel); + }; #include -class SfmTrack { - SfmTrack(); - SfmTrack(const gtsam::Point3& pt); - const Point3& point3() const; + class SfmTrack + { + SfmTrack(); + SfmTrack(const gtsam::Point3 &pt); + const Point3 &point3() const; - double r; - double g; - double b; - // TODO Need to close wrap#10 to allow this to work. - // std::vector> measurements; + double r; + double g; + double b; + // TODO Need to close wrap#10 to allow this to work. + // std::vector> measurements; - size_t number_measurements() const; - pair measurement(size_t idx) const; - pair siftIndex(size_t idx) const; - void add_measurement(size_t idx, const gtsam::Point2& m); -}; + size_t number_measurements() const; + pair measurement(size_t idx) const; + pair siftIndex(size_t idx) const; + void add_measurement(size_t idx, const gtsam::Point2 &m); + }; -class SfmData { - SfmData(); - size_t number_cameras() const; - size_t number_tracks() const; - gtsam::PinholeCamera camera(size_t idx) const; - gtsam::SfmTrack track(size_t idx) const; - void add_track(const gtsam::SfmTrack& t) ; - void add_camera(const gtsam::SfmCamera& cam); -}; + class SfmData + { + SfmData(); + size_t number_cameras() const; + size_t number_tracks() const; + gtsam::PinholeCamera camera(size_t idx) const; + gtsam::SfmTrack track(size_t idx) const; + void add_track(const gtsam::SfmTrack &t); + void add_camera(const gtsam::SfmCamera &cam); + }; -gtsam::SfmData readBal(string filename); -bool writeBAL(string filename, gtsam::SfmData& data); -gtsam::Values initialCamerasEstimate(const gtsam::SfmData& db); -gtsam::Values initialCamerasAndPointsEstimate(const gtsam::SfmData& db); + gtsam::SfmData readBal(string filename); + bool writeBAL(string filename, gtsam::SfmData &data); + gtsam::Values initialCamerasEstimate(const gtsam::SfmData &db); + gtsam::Values initialCamerasAndPointsEstimate(const gtsam::SfmData &db); -pair load2D(string filename, - gtsam::noiseModel::Diagonal* model, int maxIndex, bool addNoise, bool smart); -pair load2D(string filename, - gtsam::noiseModel::Diagonal* model, int maxIndex, bool addNoise); -pair load2D(string filename, - gtsam::noiseModel::Diagonal* model, int maxIndex); -pair load2D(string filename, - gtsam::noiseModel::Diagonal* model); -pair load2D(string filename); -pair load2D_robust(string filename, - gtsam::noiseModel::Base* model, int maxIndex); -void save2D(const gtsam::NonlinearFactorGraph& graph, - const gtsam::Values& config, gtsam::noiseModel::Diagonal* model, - string filename); + pair load2D(string filename, + gtsam::noiseModel::Diagonal *model, int maxIndex, bool addNoise, bool smart); + pair load2D(string filename, + gtsam::noiseModel::Diagonal *model, int maxIndex, bool addNoise); + pair load2D(string filename, + gtsam::noiseModel::Diagonal *model, int maxIndex); + pair load2D(string filename, + gtsam::noiseModel::Diagonal *model); + pair load2D(string filename); + pair load2D_robust(string filename, + gtsam::noiseModel::Base *model, int maxIndex); + void save2D(const gtsam::NonlinearFactorGraph &graph, + const gtsam::Values &config, gtsam::noiseModel::Diagonal *model, + string filename); -// std::vector::shared_ptr> -// Ignored by pybind -> will be List[BetweenFactorPose2] -class BetweenFactorPose2s -{ - BetweenFactorPose2s(); - size_t size() const; - gtsam::BetweenFactor* at(size_t i) const; - void push_back(const gtsam::BetweenFactor* factor); -}; -gtsam::BetweenFactorPose2s parse2DFactors(string filename); + // std::vector::shared_ptr> + // Ignored by pybind -> will be List[BetweenFactorPose2] + class BetweenFactorPose2s + { + BetweenFactorPose2s(); + size_t size() const; + gtsam::BetweenFactor *at(size_t i) const; + void push_back(const gtsam::BetweenFactor *factor); + }; + gtsam::BetweenFactorPose2s parse2DFactors(string filename); -// std::vector::shared_ptr> -// Ignored by pybind -> will be List[BetweenFactorPose3] -class BetweenFactorPose3s -{ - BetweenFactorPose3s(); - size_t size() const; - gtsam::BetweenFactor* at(size_t i) const; - void push_back(const gtsam::BetweenFactor* factor); -}; -gtsam::BetweenFactorPose3s parse3DFactors(string filename); + // std::vector::shared_ptr> + // Ignored by pybind -> will be List[BetweenFactorPose3] + class BetweenFactorPose3s + { + BetweenFactorPose3s(); + size_t size() const; + gtsam::BetweenFactor *at(size_t i) const; + void push_back(const gtsam::BetweenFactor *factor); + }; + gtsam::BetweenFactorPose3s parse3DFactors(string filename); -pair load3D(string filename); + pair load3D(string filename); -pair readG2o(string filename); -pair readG2o(string filename, bool is3D); -void writeG2o(const gtsam::NonlinearFactorGraph& graph, - const gtsam::Values& estimate, string filename); + pair readG2o(string filename); + pair readG2o(string filename, bool is3D); + void writeG2o(const gtsam::NonlinearFactorGraph &graph, + const gtsam::Values &estimate, string filename); #include -class InitializePose3 { - static gtsam::Values computeOrientationsChordal( - const gtsam::NonlinearFactorGraph& pose3Graph); - static gtsam::Values computeOrientationsGradient( - const gtsam::NonlinearFactorGraph& pose3Graph, - const gtsam::Values& givenGuess, size_t maxIter, const bool setRefFrame); - static gtsam::Values computeOrientationsGradient( - const gtsam::NonlinearFactorGraph& pose3Graph, - const gtsam::Values& givenGuess); - static gtsam::NonlinearFactorGraph buildPose3graph( - const gtsam::NonlinearFactorGraph& graph); - static gtsam::Values initializeOrientations( - const gtsam::NonlinearFactorGraph& graph); - static gtsam::Values initialize(const gtsam::NonlinearFactorGraph& graph, - const gtsam::Values& givenGuess, - bool useGradient); - static gtsam::Values initialize(const gtsam::NonlinearFactorGraph& graph); -}; + class InitializePose3 + { + static gtsam::Values computeOrientationsChordal( + const gtsam::NonlinearFactorGraph &pose3Graph); + static gtsam::Values computeOrientationsGradient( + const gtsam::NonlinearFactorGraph &pose3Graph, + const gtsam::Values &givenGuess, size_t maxIter, const bool setRefFrame); + static gtsam::Values computeOrientationsGradient( + const gtsam::NonlinearFactorGraph &pose3Graph, + const gtsam::Values &givenGuess); + static gtsam::NonlinearFactorGraph buildPose3graph( + const gtsam::NonlinearFactorGraph &graph); + static gtsam::Values initializeOrientations( + const gtsam::NonlinearFactorGraph &graph); + static gtsam::Values initialize(const gtsam::NonlinearFactorGraph &graph, + const gtsam::Values &givenGuess, + bool useGradient); + static gtsam::Values initialize(const gtsam::NonlinearFactorGraph &graph); + }; #include -template -virtual class KarcherMeanFactor : gtsam::NonlinearFactor { - KarcherMeanFactor(const gtsam::KeyVector& keys); -}; + template + virtual class KarcherMeanFactor : gtsam::NonlinearFactor + { + KarcherMeanFactor(const gtsam::KeyVector &keys); + }; #include -gtsam::noiseModel::Isotropic* ConvertNoiseModel( - gtsam::noiseModel::Base* model, size_t d); + gtsam::noiseModel::Isotropic *ConvertNoiseModel( + gtsam::noiseModel::Base *model, size_t d); -template -virtual class FrobeniusFactor : gtsam::NoiseModelFactor { - FrobeniusFactor(size_t key1, size_t key2); - FrobeniusFactor(size_t key1, size_t key2, gtsam::noiseModel::Base* model); + template + virtual class FrobeniusFactor : gtsam::NoiseModelFactor + { + FrobeniusFactor(size_t key1, size_t key2); + FrobeniusFactor(size_t key1, size_t key2, gtsam::noiseModel::Base *model); - Vector evaluateError(const T& R1, const T& R2); -}; + Vector evaluateError(const T &R1, const T &R2); + }; -template -virtual class FrobeniusBetweenFactor : gtsam::NoiseModelFactor { - FrobeniusBetweenFactor(size_t key1, size_t key2, const T& R12); - FrobeniusBetweenFactor(size_t key1, size_t key2, const T& R12, gtsam::noiseModel::Base* model); + template + virtual class FrobeniusBetweenFactor : gtsam::NoiseModelFactor + { + FrobeniusBetweenFactor(size_t key1, size_t key2, const T &R12); + FrobeniusBetweenFactor(size_t key1, size_t key2, const T &R12, gtsam::noiseModel::Base *model); - Vector evaluateError(const T& R1, const T& R2); -}; + Vector evaluateError(const T &R1, const T &R2); + }; #include -virtual class ShonanFactor3 : gtsam::NoiseModelFactor { - ShonanFactor3(size_t key1, size_t key2, const gtsam::Rot3 &R12, - size_t p); - ShonanFactor3(size_t key1, size_t key2, const gtsam::Rot3 &R12, - size_t p, gtsam::noiseModel::Base *model); - Vector evaluateError(const gtsam::SOn &Q1, const gtsam::SOn &Q2); -}; + virtual class ShonanFactor3 : gtsam::NoiseModelFactor + { + ShonanFactor3(size_t key1, size_t key2, const gtsam::Rot3 &R12, + size_t p); + ShonanFactor3(size_t key1, size_t key2, const gtsam::Rot3 &R12, + size_t p, gtsam::noiseModel::Base *model); + Vector evaluateError(const gtsam::SOn &Q1, const gtsam::SOn &Q2); + }; #include -template -class BinaryMeasurement { - BinaryMeasurement(size_t key1, size_t key2, const T& measured, - const gtsam::noiseModel::Base* model); - size_t key1() const; - size_t key2() const; - T measured() const; - gtsam::noiseModel::Base* noiseModel() const; -}; + template + class BinaryMeasurement + { + BinaryMeasurement(size_t key1, size_t key2, const T &measured, + const gtsam::noiseModel::Base *model); + size_t key1() const; + size_t key2() const; + T measured() const; + gtsam::noiseModel::Base *noiseModel() const; + }; -typedef gtsam::BinaryMeasurement BinaryMeasurementUnit3; -typedef gtsam::BinaryMeasurement BinaryMeasurementRot3; + typedef gtsam::BinaryMeasurement BinaryMeasurementUnit3; + typedef gtsam::BinaryMeasurement BinaryMeasurementRot3; -class BinaryMeasurementsUnit3 { - BinaryMeasurementsUnit3(); - size_t size() const; - gtsam::BinaryMeasurement at(size_t idx) const; - void push_back(const gtsam::BinaryMeasurement& measurement); -}; + class BinaryMeasurementsUnit3 + { + BinaryMeasurementsUnit3(); + size_t size() const; + gtsam::BinaryMeasurement at(size_t idx) const; + void push_back(const gtsam::BinaryMeasurement &measurement); + }; #include -// TODO(frank): copy/pasta below until we have integer template paremeters in wrap! + // TODO(frank): copy/pasta below until we have integer template paremeters in wrap! -class ShonanAveragingParameters2 { - ShonanAveragingParameters2(const gtsam::LevenbergMarquardtParams& lm); - ShonanAveragingParameters2(const gtsam::LevenbergMarquardtParams& lm, string method); - gtsam::LevenbergMarquardtParams getLMParams() const; - void setOptimalityThreshold(double value); - double getOptimalityThreshold() const; - void setAnchor(size_t index, const gtsam::Rot2& value); - pair getAnchor(); - void setAnchorWeight(double value); - double getAnchorWeight() const; - void setKarcherWeight(double value); - double getKarcherWeight(); - void setGaugesWeight(double value); - double getGaugesWeight(); -}; + class ShonanAveragingParameters2 + { + ShonanAveragingParameters2(const gtsam::LevenbergMarquardtParams &lm); + ShonanAveragingParameters2(const gtsam::LevenbergMarquardtParams &lm, string method); + gtsam::LevenbergMarquardtParams getLMParams() const; + void setOptimalityThreshold(double value); + double getOptimalityThreshold() const; + void setAnchor(size_t index, const gtsam::Rot2 &value); + pair getAnchor(); + void setAnchorWeight(double value); + double getAnchorWeight() const; + void setKarcherWeight(double value); + double getKarcherWeight(); + void setGaugesWeight(double value); + double getGaugesWeight(); + }; -class ShonanAveragingParameters3 { - ShonanAveragingParameters3(const gtsam::LevenbergMarquardtParams& lm); - ShonanAveragingParameters3(const gtsam::LevenbergMarquardtParams& lm, string method); - gtsam::LevenbergMarquardtParams getLMParams() const; - void setOptimalityThreshold(double value); - double getOptimalityThreshold() const; - void setAnchor(size_t index, const gtsam::Rot3& value); - pair getAnchor(); - void setAnchorWeight(double value); - double getAnchorWeight() const; - void setKarcherWeight(double value); - double getKarcherWeight(); - void setGaugesWeight(double value); - double getGaugesWeight(); -}; + class ShonanAveragingParameters3 + { + ShonanAveragingParameters3(const gtsam::LevenbergMarquardtParams &lm); + ShonanAveragingParameters3(const gtsam::LevenbergMarquardtParams &lm, string method); + gtsam::LevenbergMarquardtParams getLMParams() const; + void setOptimalityThreshold(double value); + double getOptimalityThreshold() const; + void setAnchor(size_t index, const gtsam::Rot3 &value); + pair getAnchor(); + void setAnchorWeight(double value); + double getAnchorWeight() const; + void setKarcherWeight(double value); + double getKarcherWeight(); + void setGaugesWeight(double value); + double getGaugesWeight(); + }; -class ShonanAveraging2 { - ShonanAveraging2(string g2oFile); - ShonanAveraging2(string g2oFile, - const gtsam::ShonanAveragingParameters2 ¶meters); + class ShonanAveraging2 + { + ShonanAveraging2(string g2oFile); + ShonanAveraging2(string g2oFile, + const gtsam::ShonanAveragingParameters2 ¶meters); - // Query properties - size_t nrUnknowns() const; - size_t nrMeasurements() const; - gtsam::Rot2 measured(size_t i); - gtsam::KeyVector keys(size_t i); + // Query properties + size_t nrUnknowns() const; + size_t nrMeasurements() const; + gtsam::Rot2 measured(size_t i); + gtsam::KeyVector keys(size_t i); - // Matrix API (advanced use, debugging) - Matrix denseD() const; - Matrix denseQ() const; - Matrix denseL() const; - // Matrix computeLambda_(Matrix S) const; - Matrix computeLambda_(const gtsam::Values& values) const; - Matrix computeA_(const gtsam::Values& values) const; - double computeMinEigenValue(const gtsam::Values& values) const; - gtsam::Values initializeWithDescent(size_t p, const gtsam::Values& values, - const Vector& minEigenVector, double minEigenValue) const; + // Matrix API (advanced use, debugging) + Matrix denseD() const; + Matrix denseQ() const; + Matrix denseL() const; + // Matrix computeLambda_(Matrix S) const; + Matrix computeLambda_(const gtsam::Values &values) const; + Matrix computeA_(const gtsam::Values &values) const; + double computeMinEigenValue(const gtsam::Values &values) const; + gtsam::Values initializeWithDescent(size_t p, const gtsam::Values &values, + const Vector &minEigenVector, double minEigenValue) const; - // Advanced API - gtsam::NonlinearFactorGraph buildGraphAt(size_t p) const; - gtsam::Values initializeRandomlyAt(size_t p) const; - double costAt(size_t p, const gtsam::Values& values) const; - pair computeMinEigenVector(const gtsam::Values& values) const; - bool checkOptimality(const gtsam::Values& values) const; - gtsam::LevenbergMarquardtOptimizer* createOptimizerAt(size_t p, const gtsam::Values& initial); - // gtsam::Values tryOptimizingAt(size_t p) const; - gtsam::Values tryOptimizingAt(size_t p, const gtsam::Values& initial) const; - gtsam::Values projectFrom(size_t p, const gtsam::Values& values) const; - gtsam::Values roundSolution(const gtsam::Values& values) const; + // Advanced API + gtsam::NonlinearFactorGraph buildGraphAt(size_t p) const; + gtsam::Values initializeRandomlyAt(size_t p) const; + double costAt(size_t p, const gtsam::Values &values) const; + pair computeMinEigenVector(const gtsam::Values &values) const; + bool checkOptimality(const gtsam::Values &values) const; + gtsam::LevenbergMarquardtOptimizer *createOptimizerAt(size_t p, const gtsam::Values &initial); + // gtsam::Values tryOptimizingAt(size_t p) const; + gtsam::Values tryOptimizingAt(size_t p, const gtsam::Values &initial) const; + gtsam::Values projectFrom(size_t p, const gtsam::Values &values) const; + gtsam::Values roundSolution(const gtsam::Values &values) const; - // Basic API - double cost(const gtsam::Values& values) const; - gtsam::Values initializeRandomly() const; - pair run(const gtsam::Values& initial, size_t min_p, size_t max_p) const; -}; + // Basic API + double cost(const gtsam::Values &values) const; + gtsam::Values initializeRandomly() const; + pair run(const gtsam::Values &initial, size_t min_p, size_t max_p) const; + }; -class ShonanAveraging3 { - ShonanAveraging3(string g2oFile); - ShonanAveraging3(string g2oFile, - const gtsam::ShonanAveragingParameters3 ¶meters); - - // TODO(frank): deprecate once we land pybind wrapper - ShonanAveraging3(const gtsam::BetweenFactorPose3s &factors); - ShonanAveraging3(const gtsam::BetweenFactorPose3s &factors, - const gtsam::ShonanAveragingParameters3 ¶meters); + class ShonanAveraging3 + { + ShonanAveraging3(string g2oFile); + ShonanAveraging3(string g2oFile, + const gtsam::ShonanAveragingParameters3 ¶meters); - // Query properties - size_t nrUnknowns() const; - size_t nrMeasurements() const; - gtsam::Rot3 measured(size_t i); - gtsam::KeyVector keys(size_t i); + // TODO(frank): deprecate once we land pybind wrapper + ShonanAveraging3(const gtsam::BetweenFactorPose3s &factors); + ShonanAveraging3(const gtsam::BetweenFactorPose3s &factors, + const gtsam::ShonanAveragingParameters3 ¶meters); - // Matrix API (advanced use, debugging) - Matrix denseD() const; - Matrix denseQ() const; - Matrix denseL() const; - // Matrix computeLambda_(Matrix S) const; - Matrix computeLambda_(const gtsam::Values& values) const; - Matrix computeA_(const gtsam::Values& values) const; - double computeMinEigenValue(const gtsam::Values& values) const; - gtsam::Values initializeWithDescent(size_t p, const gtsam::Values& values, - const Vector& minEigenVector, double minEigenValue) const; + // Query properties + size_t nrUnknowns() const; + size_t nrMeasurements() const; + gtsam::Rot3 measured(size_t i); + gtsam::KeyVector keys(size_t i); - // Advanced API - gtsam::NonlinearFactorGraph buildGraphAt(size_t p) const; - gtsam::Values initializeRandomlyAt(size_t p) const; - double costAt(size_t p, const gtsam::Values& values) const; - pair computeMinEigenVector(const gtsam::Values& values) const; - bool checkOptimality(const gtsam::Values& values) const; - gtsam::LevenbergMarquardtOptimizer* createOptimizerAt(size_t p, const gtsam::Values& initial); - // gtsam::Values tryOptimizingAt(size_t p) const; - gtsam::Values tryOptimizingAt(size_t p, const gtsam::Values& initial) const; - gtsam::Values projectFrom(size_t p, const gtsam::Values& values) const; - gtsam::Values roundSolution(const gtsam::Values& values) const; + // Matrix API (advanced use, debugging) + Matrix denseD() const; + Matrix denseQ() const; + Matrix denseL() const; + // Matrix computeLambda_(Matrix S) const; + Matrix computeLambda_(const gtsam::Values &values) const; + Matrix computeA_(const gtsam::Values &values) const; + double computeMinEigenValue(const gtsam::Values &values) const; + gtsam::Values initializeWithDescent(size_t p, const gtsam::Values &values, + const Vector &minEigenVector, double minEigenValue) const; - // Basic API - double cost(const gtsam::Values& values) const; - gtsam::Values initializeRandomly() const; - pair run(const gtsam::Values& initial, size_t min_p, size_t max_p) const; -}; + // Advanced API + gtsam::NonlinearFactorGraph buildGraphAt(size_t p) const; + gtsam::Values initializeRandomlyAt(size_t p) const; + double costAt(size_t p, const gtsam::Values &values) const; + pair computeMinEigenVector(const gtsam::Values &values) const; + bool checkOptimality(const gtsam::Values &values) const; + gtsam::LevenbergMarquardtOptimizer *createOptimizerAt(size_t p, const gtsam::Values &initial); + // gtsam::Values tryOptimizingAt(size_t p) const; + gtsam::Values tryOptimizingAt(size_t p, const gtsam::Values &initial) const; + gtsam::Values projectFrom(size_t p, const gtsam::Values &values) const; + gtsam::Values roundSolution(const gtsam::Values &values) const; + + // Basic API + double cost(const gtsam::Values &values) const; + gtsam::Values initializeRandomly() const; + pair run(const gtsam::Values &initial, size_t min_p, size_t max_p) const; + }; #include -class KeyPairDoubleMap { - KeyPairDoubleMap(); - KeyPairDoubleMap(const gtsam::KeyPairDoubleMap& other); + class KeyPairDoubleMap + { + KeyPairDoubleMap(); + KeyPairDoubleMap(const gtsam::KeyPairDoubleMap &other); - size_t size() const; - bool empty() const; - void clear(); - size_t at(const pair& keypair) const; -}; + size_t size() const; + bool empty() const; + void clear(); + size_t at(const pair &keypair) const; + }; -class MFAS { - MFAS(const gtsam::BinaryMeasurementsUnit3& relativeTranslations, - const gtsam::Unit3& projectionDirection); + class MFAS + { + MFAS(const gtsam::BinaryMeasurementsUnit3 &relativeTranslations, + const gtsam::Unit3 &projectionDirection); - gtsam::KeyPairDoubleMap computeOutlierWeights() const; - gtsam::KeyVector computeOrdering() const; -}; + gtsam::KeyPairDoubleMap computeOutlierWeights() const; + gtsam::KeyVector computeOrdering() const; + }; #include -class TranslationRecovery { - TranslationRecovery(const gtsam::BinaryMeasurementsUnit3 &relativeTranslations, - const gtsam::LevenbergMarquardtParams &lmParams); - TranslationRecovery( - const gtsam::BinaryMeasurementsUnit3 & relativeTranslations); // default LevenbergMarquardtParams - gtsam::Values run(const double scale) const; - gtsam::Values run() const; // default scale = 1.0 -}; + class TranslationRecovery + { + TranslationRecovery(const gtsam::BinaryMeasurementsUnit3 &relativeTranslations, + const gtsam::LevenbergMarquardtParams &lmParams); + TranslationRecovery( + const gtsam::BinaryMeasurementsUnit3 &relativeTranslations); // default LevenbergMarquardtParams + gtsam::Values run(const double scale) const; + gtsam::Values run() const; // default scale = 1.0 + }; -//************************************************************************* -// Navigation -//************************************************************************* -namespace imuBias { + //************************************************************************* + // Navigation + //************************************************************************* + namespace imuBias + { #include -class ConstantBias { - // Constructors - ConstantBias(); - ConstantBias(Vector biasAcc, Vector biasGyro); + class ConstantBias + { + // Constructors + ConstantBias(); + ConstantBias(Vector biasAcc, Vector biasGyro); - // Testable - void print(string s) const; - bool equals(const gtsam::imuBias::ConstantBias& expected, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::imuBias::ConstantBias &expected, double tol) const; - // Group - static gtsam::imuBias::ConstantBias identity(); - gtsam::imuBias::ConstantBias inverse() const; - gtsam::imuBias::ConstantBias compose(const gtsam::imuBias::ConstantBias& b) const; - gtsam::imuBias::ConstantBias between(const gtsam::imuBias::ConstantBias& b) const; + // Group + static gtsam::imuBias::ConstantBias identity(); + gtsam::imuBias::ConstantBias inverse() const; + gtsam::imuBias::ConstantBias compose(const gtsam::imuBias::ConstantBias &b) const; + gtsam::imuBias::ConstantBias between(const gtsam::imuBias::ConstantBias &b) const; - // Manifold - gtsam::imuBias::ConstantBias retract(Vector v) const; - Vector localCoordinates(const gtsam::imuBias::ConstantBias& b) const; + // Manifold + gtsam::imuBias::ConstantBias retract(Vector v) const; + Vector localCoordinates(const gtsam::imuBias::ConstantBias &b) const; - // Lie Group - static gtsam::imuBias::ConstantBias Expmap(Vector v); - static Vector Logmap(const gtsam::imuBias::ConstantBias& b); + // Lie Group + static gtsam::imuBias::ConstantBias Expmap(Vector v); + static Vector Logmap(const gtsam::imuBias::ConstantBias &b); - // Standard Interface - Vector vector() const; - Vector accelerometer() const; - Vector gyroscope() const; - Vector correctAccelerometer(Vector measurement) const; - Vector correctGyroscope(Vector measurement) const; -}; + // Standard Interface + Vector vector() const; + Vector accelerometer() const; + Vector gyroscope() const; + Vector correctAccelerometer(Vector measurement) const; + Vector correctGyroscope(Vector measurement) const; + }; -}///\namespace imuBias + } // namespace imuBias #include -class NavState { - // Constructors - NavState(); - NavState(const gtsam::Rot3& R, const gtsam::Point3& t, Vector v); - NavState(const gtsam::Pose3& pose, Vector v); + class NavState + { + // Constructors + NavState(); + NavState(const gtsam::Rot3 &R, const gtsam::Point3 &t, Vector v); + NavState(const gtsam::Pose3 &pose, Vector v); - // Testable - void print(string s) const; - bool equals(const gtsam::NavState& expected, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::NavState &expected, double tol) const; - // Access - gtsam::Rot3 attitude() const; - gtsam::Point3 position() const; - Vector velocity() const; - gtsam::Pose3 pose() const; -}; + // Access + gtsam::Rot3 attitude() const; + gtsam::Point3 position() const; + Vector velocity() const; + gtsam::Pose3 pose() const; + }; #include -virtual class PreintegratedRotationParams { - PreintegratedRotationParams(); + virtual class PreintegratedRotationParams + { + PreintegratedRotationParams(); - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegratedRotationParams& expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegratedRotationParams &expected, double tol); - void setGyroscopeCovariance(Matrix cov); - void setOmegaCoriolis(Vector omega); - void setBodyPSensor(const gtsam::Pose3& pose); + void setGyroscopeCovariance(Matrix cov); + void setOmegaCoriolis(Vector omega); + void setBodyPSensor(const gtsam::Pose3 &pose); - Matrix getGyroscopeCovariance() const; + Matrix getGyroscopeCovariance() const; - // TODO(frank): allow optional - // boost::optional getOmegaCoriolis() const; - // boost::optional getBodyPSensor() const; -}; + // TODO(frank): allow optional + // boost::optional getOmegaCoriolis() const; + // boost::optional getBodyPSensor() const; + }; #include -virtual class PreintegrationParams : gtsam::PreintegratedRotationParams { - PreintegrationParams(Vector n_gravity); + virtual class PreintegrationParams : gtsam::PreintegratedRotationParams + { + PreintegrationParams(Vector n_gravity); - static gtsam::PreintegrationParams* MakeSharedD(double g); - static gtsam::PreintegrationParams* MakeSharedU(double g); - static gtsam::PreintegrationParams* MakeSharedD(); // default g = 9.81 - static gtsam::PreintegrationParams* MakeSharedU(); // default g = 9.81 + static gtsam::PreintegrationParams *MakeSharedD(double g); + static gtsam::PreintegrationParams *MakeSharedU(double g); + static gtsam::PreintegrationParams *MakeSharedD(); // default g = 9.81 + static gtsam::PreintegrationParams *MakeSharedU(); // default g = 9.81 - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegrationParams& expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegrationParams &expected, double tol); - void setAccelerometerCovariance(Matrix cov); - void setIntegrationCovariance(Matrix cov); - void setUse2ndOrderCoriolis(bool flag); + void setAccelerometerCovariance(Matrix cov); + void setIntegrationCovariance(Matrix cov); + void setUse2ndOrderCoriolis(bool flag); - Matrix getAccelerometerCovariance() const; - Matrix getIntegrationCovariance() const; - bool getUse2ndOrderCoriolis() const; -}; + Matrix getAccelerometerCovariance() const; + Matrix getIntegrationCovariance() const; + bool getUse2ndOrderCoriolis() const; + }; #include -class PreintegratedImuMeasurements { - // Constructors - PreintegratedImuMeasurements(const gtsam::PreintegrationParams* params); - PreintegratedImuMeasurements(const gtsam::PreintegrationParams* params, - const gtsam::imuBias::ConstantBias& bias); + class PreintegratedImuMeasurements + { + // Constructors + PreintegratedImuMeasurements(const gtsam::PreintegrationParams *params); + PreintegratedImuMeasurements(const gtsam::PreintegrationParams *params, + const gtsam::imuBias::ConstantBias &bias); - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegratedImuMeasurements& expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegratedImuMeasurements &expected, double tol); - // Standard Interface - void integrateMeasurement(Vector measuredAcc, Vector measuredOmega, - double deltaT); - void resetIntegration(); - void resetIntegrationAndSetBias(const gtsam::imuBias::ConstantBias& biasHat); + // Standard Interface + void integrateMeasurement(Vector measuredAcc, Vector measuredOmega, + double deltaT); + void resetIntegration(); + void resetIntegrationAndSetBias(const gtsam::imuBias::ConstantBias &biasHat); - Matrix preintMeasCov() const; - Vector preintegrated() const; - double deltaTij() const; - gtsam::Rot3 deltaRij() const; - Vector deltaPij() const; - Vector deltaVij() const; - gtsam::imuBias::ConstantBias biasHat() const; - Vector biasHatVector() const; - gtsam::NavState predict(const gtsam::NavState& state_i, - const gtsam::imuBias::ConstantBias& bias) const; -}; + Matrix preintMeasCov() const; + Vector preintegrated() const; + double deltaTij() const; + gtsam::Rot3 deltaRij() const; + Vector deltaPij() const; + Vector deltaVij() const; + gtsam::imuBias::ConstantBias biasHat() const; + Vector biasHatVector() const; + gtsam::NavState predict(const gtsam::NavState &state_i, + const gtsam::imuBias::ConstantBias &bias) const; + }; -virtual class ImuFactor: gtsam::NonlinearFactor { - ImuFactor(size_t pose_i, size_t vel_i, size_t pose_j, size_t vel_j, - size_t bias, - const gtsam::PreintegratedImuMeasurements& preintegratedMeasurements); + virtual class ImuFactor : gtsam::NonlinearFactor + { + ImuFactor(size_t pose_i, size_t vel_i, size_t pose_j, size_t vel_j, + size_t bias, + const gtsam::PreintegratedImuMeasurements &preintegratedMeasurements); - // Standard Interface - gtsam::PreintegratedImuMeasurements preintegratedMeasurements() const; - Vector evaluateError(const gtsam::Pose3& pose_i, Vector vel_i, - const gtsam::Pose3& pose_j, Vector vel_j, - const gtsam::imuBias::ConstantBias& bias); -}; + // Standard Interface + gtsam::PreintegratedImuMeasurements preintegratedMeasurements() const; + Vector evaluateError(const gtsam::Pose3 &pose_i, Vector vel_i, + const gtsam::Pose3 &pose_j, Vector vel_j, + const gtsam::imuBias::ConstantBias &bias); + }; #include -virtual class PreintegrationCombinedParams : gtsam::PreintegrationParams { - PreintegrationCombinedParams(Vector n_gravity); + virtual class PreintegrationCombinedParams : gtsam::PreintegrationParams + { + PreintegrationCombinedParams(Vector n_gravity); - static gtsam::PreintegrationCombinedParams* MakeSharedD(double g); - static gtsam::PreintegrationCombinedParams* MakeSharedU(double g); - static gtsam::PreintegrationCombinedParams* MakeSharedD(); // default g = 9.81 - static gtsam::PreintegrationCombinedParams* MakeSharedU(); // default g = 9.81 + static gtsam::PreintegrationCombinedParams *MakeSharedD(double g); + static gtsam::PreintegrationCombinedParams *MakeSharedU(double g); + static gtsam::PreintegrationCombinedParams *MakeSharedD(); // default g = 9.81 + static gtsam::PreintegrationCombinedParams *MakeSharedU(); // default g = 9.81 - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegrationCombinedParams& expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegrationCombinedParams &expected, double tol); - void setBiasAccCovariance(Matrix cov); - void setBiasOmegaCovariance(Matrix cov); - void setBiasAccOmegaInt(Matrix cov); - - Matrix getBiasAccCovariance() const ; - Matrix getBiasOmegaCovariance() const ; - Matrix getBiasAccOmegaInt() const; - -}; + void setBiasAccCovariance(Matrix cov); + void setBiasOmegaCovariance(Matrix cov); + void setBiasAccOmegaInt(Matrix cov); -class PreintegratedCombinedMeasurements { -// Constructors - PreintegratedCombinedMeasurements(const gtsam::PreintegrationCombinedParams* params); - PreintegratedCombinedMeasurements(const gtsam::PreintegrationCombinedParams* params, - const gtsam::imuBias::ConstantBias& bias); - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegratedCombinedMeasurements& expected, - double tol); + Matrix getBiasAccCovariance() const; + Matrix getBiasOmegaCovariance() const; + Matrix getBiasAccOmegaInt() const; + }; - // Standard Interface - void integrateMeasurement(Vector measuredAcc, Vector measuredOmega, - double deltaT); - void resetIntegration(); - void resetIntegrationAndSetBias(const gtsam::imuBias::ConstantBias& biasHat); + class PreintegratedCombinedMeasurements + { + // Constructors + PreintegratedCombinedMeasurements(const gtsam::PreintegrationCombinedParams *params); + PreintegratedCombinedMeasurements(const gtsam::PreintegrationCombinedParams *params, + const gtsam::imuBias::ConstantBias &bias); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegratedCombinedMeasurements &expected, + double tol); - Matrix preintMeasCov() const; - double deltaTij() const; - gtsam::Rot3 deltaRij() const; - Vector deltaPij() const; - Vector deltaVij() const; - gtsam::imuBias::ConstantBias biasHat() const; - Vector biasHatVector() const; - gtsam::NavState predict(const gtsam::NavState& state_i, - const gtsam::imuBias::ConstantBias& bias) const; -}; + // Standard Interface + void integrateMeasurement(Vector measuredAcc, Vector measuredOmega, + double deltaT); + void resetIntegration(); + void resetIntegrationAndSetBias(const gtsam::imuBias::ConstantBias &biasHat); -virtual class CombinedImuFactor: gtsam::NonlinearFactor { - CombinedImuFactor(size_t pose_i, size_t vel_i, size_t pose_j, size_t vel_j, - size_t bias_i, size_t bias_j, - const gtsam::PreintegratedCombinedMeasurements& CombinedPreintegratedMeasurements); + Matrix preintMeasCov() const; + double deltaTij() const; + gtsam::Rot3 deltaRij() const; + Vector deltaPij() const; + Vector deltaVij() const; + gtsam::imuBias::ConstantBias biasHat() const; + Vector biasHatVector() const; + gtsam::NavState predict(const gtsam::NavState &state_i, + const gtsam::imuBias::ConstantBias &bias) const; + }; - // Standard Interface - gtsam::PreintegratedCombinedMeasurements preintegratedMeasurements() const; - Vector evaluateError(const gtsam::Pose3& pose_i, Vector vel_i, - const gtsam::Pose3& pose_j, Vector vel_j, - const gtsam::imuBias::ConstantBias& bias_i, - const gtsam::imuBias::ConstantBias& bias_j); -}; + virtual class CombinedImuFactor : gtsam::NonlinearFactor + { + CombinedImuFactor(size_t pose_i, size_t vel_i, size_t pose_j, size_t vel_j, + size_t bias_i, size_t bias_j, + const gtsam::PreintegratedCombinedMeasurements &CombinedPreintegratedMeasurements); + + // Standard Interface + gtsam::PreintegratedCombinedMeasurements preintegratedMeasurements() const; + Vector evaluateError(const gtsam::Pose3 &pose_i, Vector vel_i, + const gtsam::Pose3 &pose_j, Vector vel_j, + const gtsam::imuBias::ConstantBias &bias_i, + const gtsam::imuBias::ConstantBias &bias_j); + }; #include -class PreintegratedAhrsMeasurements { - // Standard Constructor - PreintegratedAhrsMeasurements(Vector bias, Matrix measuredOmegaCovariance); - PreintegratedAhrsMeasurements(const gtsam::PreintegratedAhrsMeasurements& rhs); + class PreintegratedAhrsMeasurements + { + // Standard Constructor + PreintegratedAhrsMeasurements(Vector bias, Matrix measuredOmegaCovariance); + PreintegratedAhrsMeasurements(const gtsam::PreintegratedAhrsMeasurements &rhs); - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegratedAhrsMeasurements& expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegratedAhrsMeasurements &expected, double tol); - // get Data - gtsam::Rot3 deltaRij() const; - double deltaTij() const; - Vector biasHat() const; + // get Data + gtsam::Rot3 deltaRij() const; + double deltaTij() const; + Vector biasHat() const; - // Standard Interface - void integrateMeasurement(Vector measuredOmega, double deltaT); - void resetIntegration() ; -}; + // Standard Interface + void integrateMeasurement(Vector measuredOmega, double deltaT); + void resetIntegration(); + }; -virtual class AHRSFactor : gtsam::NonlinearFactor { - AHRSFactor(size_t rot_i, size_t rot_j,size_t bias, - const gtsam::PreintegratedAhrsMeasurements& preintegratedMeasurements, Vector omegaCoriolis); - AHRSFactor(size_t rot_i, size_t rot_j, size_t bias, - const gtsam::PreintegratedAhrsMeasurements& preintegratedMeasurements, Vector omegaCoriolis, - const gtsam::Pose3& body_P_sensor); + virtual class AHRSFactor : gtsam::NonlinearFactor + { + AHRSFactor(size_t rot_i, size_t rot_j, size_t bias, + const gtsam::PreintegratedAhrsMeasurements &preintegratedMeasurements, Vector omegaCoriolis); + AHRSFactor(size_t rot_i, size_t rot_j, size_t bias, + const gtsam::PreintegratedAhrsMeasurements &preintegratedMeasurements, Vector omegaCoriolis, + const gtsam::Pose3 &body_P_sensor); - // Standard Interface - gtsam::PreintegratedAhrsMeasurements preintegratedMeasurements() const; - Vector evaluateError(const gtsam::Rot3& rot_i, const gtsam::Rot3& rot_j, - Vector bias) const; - gtsam::Rot3 predict(const gtsam::Rot3& rot_i, Vector bias, - const gtsam::PreintegratedAhrsMeasurements& preintegratedMeasurements, - Vector omegaCoriolis) const; -}; + // Standard Interface + gtsam::PreintegratedAhrsMeasurements preintegratedMeasurements() const; + Vector evaluateError(const gtsam::Rot3 &rot_i, const gtsam::Rot3 &rot_j, + Vector bias) const; + gtsam::Rot3 predict(const gtsam::Rot3 &rot_i, Vector bias, + const gtsam::PreintegratedAhrsMeasurements &preintegratedMeasurements, + Vector omegaCoriolis) const; + }; #include -//virtual class AttitudeFactor : gtsam::NonlinearFactor { -// AttitudeFactor(const Unit3& nZ, const Unit3& bRef); -// AttitudeFactor(); -//}; -virtual class Rot3AttitudeFactor : gtsam::NonlinearFactor{ - Rot3AttitudeFactor(size_t key, const gtsam::Unit3& nZ, const gtsam::noiseModel::Diagonal* model, - const gtsam::Unit3& bRef); - Rot3AttitudeFactor(size_t key, const gtsam::Unit3& nZ, const gtsam::noiseModel::Diagonal* model); - Rot3AttitudeFactor(); - void print(string s) const; - bool equals(const gtsam::NonlinearFactor& expected, double tol) const; - gtsam::Unit3 nZ() const; - gtsam::Unit3 bRef() const; -}; + //virtual class AttitudeFactor : gtsam::NonlinearFactor { + // AttitudeFactor(const Unit3& nZ, const Unit3& bRef); + // AttitudeFactor(); + //}; + virtual class Rot3AttitudeFactor : gtsam::NonlinearFactor + { + Rot3AttitudeFactor(size_t key, const gtsam::Unit3 &nZ, const gtsam::noiseModel::Diagonal *model, + const gtsam::Unit3 &bRef); + Rot3AttitudeFactor(size_t key, const gtsam::Unit3 &nZ, const gtsam::noiseModel::Diagonal *model); + Rot3AttitudeFactor(); + void print(string s) const; + bool equals(const gtsam::NonlinearFactor &expected, double tol) const; + gtsam::Unit3 nZ() const; + gtsam::Unit3 bRef() const; + }; -virtual class Pose3AttitudeFactor : gtsam::NonlinearFactor { - Pose3AttitudeFactor(size_t key, const gtsam::Unit3& nZ, - const gtsam::noiseModel::Diagonal* model, - const gtsam::Unit3& bRef); - Pose3AttitudeFactor(size_t key, const gtsam::Unit3& nZ, - const gtsam::noiseModel::Diagonal* model); - Pose3AttitudeFactor(); - void print(string s) const; - bool equals(const gtsam::NonlinearFactor& expected, double tol) const; - gtsam::Unit3 nZ() const; - gtsam::Unit3 bRef() const; -}; + virtual class Pose3AttitudeFactor : gtsam::NonlinearFactor + { + Pose3AttitudeFactor(size_t key, const gtsam::Unit3 &nZ, + const gtsam::noiseModel::Diagonal *model, + const gtsam::Unit3 &bRef); + Pose3AttitudeFactor(size_t key, const gtsam::Unit3 &nZ, + const gtsam::noiseModel::Diagonal *model); + Pose3AttitudeFactor(); + void print(string s) const; + bool equals(const gtsam::NonlinearFactor &expected, double tol) const; + gtsam::Unit3 nZ() const; + gtsam::Unit3 bRef() const; + }; #include -virtual class GPSFactor : gtsam::NonlinearFactor{ - GPSFactor(size_t key, const gtsam::Point3& gpsIn, - const gtsam::noiseModel::Base* model); + virtual class GPSFactor : gtsam::NonlinearFactor + { + GPSFactor(size_t key, const gtsam::Point3 &gpsIn, + const gtsam::noiseModel::Base *model); - // Testable - void print(string s) const; - bool equals(const gtsam::GPSFactor& expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::GPSFactor &expected, double tol); - // Standard Interface - gtsam::Point3 measurementIn() const; -}; + // Standard Interface + gtsam::Point3 measurementIn() const; + }; -virtual class GPSFactor2 : gtsam::NonlinearFactor { - GPSFactor2(size_t key, const gtsam::Point3& gpsIn, - const gtsam::noiseModel::Base* model); + virtual class GPSFactor2 : gtsam::NonlinearFactor + { + GPSFactor2(size_t key, const gtsam::Point3 &gpsIn, + const gtsam::noiseModel::Base *model); - // Testable - void print(string s) const; - bool equals(const gtsam::GPSFactor2& expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::GPSFactor2 &expected, double tol); - // Standard Interface - gtsam::Point3 measurementIn() const; -}; + // Standard Interface + gtsam::Point3 measurementIn() const; + }; #include -virtual class Scenario { - gtsam::Pose3 pose(double t) const; - Vector omega_b(double t) const; - Vector velocity_n(double t) const; - Vector acceleration_n(double t) const; - gtsam::Rot3 rotation(double t) const; - gtsam::NavState navState(double t) const; - Vector velocity_b(double t) const; - Vector acceleration_b(double t) const; -}; + virtual class Scenario + { + gtsam::Pose3 pose(double t) const; + Vector omega_b(double t) const; + Vector velocity_n(double t) const; + Vector acceleration_n(double t) const; + gtsam::Rot3 rotation(double t) const; + gtsam::NavState navState(double t) const; + Vector velocity_b(double t) const; + Vector acceleration_b(double t) const; + }; -virtual class ConstantTwistScenario : gtsam::Scenario { - ConstantTwistScenario(Vector w, Vector v); - ConstantTwistScenario(Vector w, Vector v, - const gtsam::Pose3& nTb0); -}; + virtual class ConstantTwistScenario : gtsam::Scenario + { + ConstantTwistScenario(Vector w, Vector v); + ConstantTwistScenario(Vector w, Vector v, + const gtsam::Pose3 &nTb0); + }; -virtual class AcceleratingScenario : gtsam::Scenario { - AcceleratingScenario(const gtsam::Rot3& nRb, const gtsam::Point3& p0, - Vector v0, Vector a_n, - Vector omega_b); -}; + virtual class AcceleratingScenario : gtsam::Scenario + { + AcceleratingScenario(const gtsam::Rot3 &nRb, const gtsam::Point3 &p0, + Vector v0, Vector a_n, + Vector omega_b); + }; #include -class ScenarioRunner { - ScenarioRunner(const gtsam::Scenario& scenario, - const gtsam::PreintegrationParams* p, - double imuSampleTime, - const gtsam::imuBias::ConstantBias& bias); - Vector gravity_n() const; - Vector actualAngularVelocity(double t) const; - Vector actualSpecificForce(double t) const; - Vector measuredAngularVelocity(double t) const; - Vector measuredSpecificForce(double t) const; - double imuSampleTime() const; - gtsam::PreintegratedImuMeasurements integrate( - double T, const gtsam::imuBias::ConstantBias& estimatedBias, - bool corrupted) const; - gtsam::NavState predict( - const gtsam::PreintegratedImuMeasurements& pim, - const gtsam::imuBias::ConstantBias& estimatedBias) const; - Matrix estimateCovariance( - double T, size_t N, - const gtsam::imuBias::ConstantBias& estimatedBias) const; - Matrix estimateNoiseCovariance(size_t N) const; -}; + class ScenarioRunner + { + ScenarioRunner(const gtsam::Scenario &scenario, + const gtsam::PreintegrationParams *p, + double imuSampleTime, + const gtsam::imuBias::ConstantBias &bias); + Vector gravity_n() const; + Vector actualAngularVelocity(double t) const; + Vector actualSpecificForce(double t) const; + Vector measuredAngularVelocity(double t) const; + Vector measuredSpecificForce(double t) const; + double imuSampleTime() const; + gtsam::PreintegratedImuMeasurements integrate( + double T, const gtsam::imuBias::ConstantBias &estimatedBias, + bool corrupted) const; + gtsam::NavState predict( + const gtsam::PreintegratedImuMeasurements &pim, + const gtsam::imuBias::ConstantBias &estimatedBias) const; + Matrix estimateCovariance( + double T, size_t N, + const gtsam::imuBias::ConstantBias &estimatedBias) const; + Matrix estimateNoiseCovariance(size_t N) const; + }; -//************************************************************************* -// Utilities -//************************************************************************* + //************************************************************************* + // Utilities + //************************************************************************* -namespace utilities { - - #include - gtsam::KeyList createKeyList(Vector I); - gtsam::KeyList createKeyList(string s, Vector I); - gtsam::KeyVector createKeyVector(Vector I); - gtsam::KeyVector createKeyVector(string s, Vector I); - gtsam::KeySet createKeySet(Vector I); - gtsam::KeySet createKeySet(string s, Vector I); - Matrix extractPoint2(const gtsam::Values& values); - Matrix extractPoint3(const gtsam::Values& values); - gtsam::Values allPose2s(gtsam::Values& values); - Matrix extractPose2(const gtsam::Values& values); - gtsam::Values allPose3s(gtsam::Values& values); - Matrix extractPose3(const gtsam::Values& values); - void perturbPoint2(gtsam::Values& values, double sigma, int seed); - void perturbPose2 (gtsam::Values& values, double sigmaT, double sigmaR, int seed); - void perturbPoint3(gtsam::Values& values, double sigma, int seed); - void insertBackprojections(gtsam::Values& values, const gtsam::PinholeCameraCal3_S2& c, Vector J, Matrix Z, double depth); - void insertProjectionFactors(gtsam::NonlinearFactorGraph& graph, size_t i, Vector J, Matrix Z, const gtsam::noiseModel::Base* model, const gtsam::Cal3_S2* K); - void insertProjectionFactors(gtsam::NonlinearFactorGraph& graph, size_t i, Vector J, Matrix Z, const gtsam::noiseModel::Base* model, const gtsam::Cal3_S2* K, const gtsam::Pose3& body_P_sensor); - Matrix reprojectionErrors(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& values); - gtsam::Values localToWorld(const gtsam::Values& local, const gtsam::Pose2& base); - gtsam::Values localToWorld(const gtsam::Values& local, const gtsam::Pose2& base, const gtsam::KeyVector& keys); - -} //\namespace utilities + namespace utilities + { #include -class RedirectCout { - RedirectCout(); - string str(); -}; + gtsam::KeyList createKeyList(Vector I); + gtsam::KeyList createKeyList(string s, Vector I); + gtsam::KeyVector createKeyVector(Vector I); + gtsam::KeyVector createKeyVector(string s, Vector I); + gtsam::KeySet createKeySet(Vector I); + gtsam::KeySet createKeySet(string s, Vector I); + Matrix extractPoint2(const gtsam::Values &values); + Matrix extractPoint3(const gtsam::Values &values); + gtsam::Values allPose2s(gtsam::Values &values); + Matrix extractPose2(const gtsam::Values &values); + gtsam::Values allPose3s(gtsam::Values &values); + Matrix extractPose3(const gtsam::Values &values); + void perturbPoint2(gtsam::Values &values, double sigma, int seed); + void perturbPose2(gtsam::Values &values, double sigmaT, double sigmaR, int seed); + void perturbPoint3(gtsam::Values &values, double sigma, int seed); + void insertBackprojections(gtsam::Values &values, const gtsam::PinholeCameraCal3_S2 &c, Vector J, Matrix Z, double depth); + void insertProjectionFactors(gtsam::NonlinearFactorGraph &graph, size_t i, Vector J, Matrix Z, const gtsam::noiseModel::Base *model, const gtsam::Cal3_S2 *K); + void insertProjectionFactors(gtsam::NonlinearFactorGraph &graph, size_t i, Vector J, Matrix Z, const gtsam::noiseModel::Base *model, const gtsam::Cal3_S2 *K, const gtsam::Pose3 &body_P_sensor); + Matrix reprojectionErrors(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &values); + gtsam::Values localToWorld(const gtsam::Values &local, const gtsam::Pose2 &base); + gtsam::Values localToWorld(const gtsam::Values &local, const gtsam::Pose2 &base, const gtsam::KeyVector &keys); -} + } // namespace utilities + +#include + class RedirectCout + { + RedirectCout(); + string str(); + }; + +} // namespace gtsam diff --git a/python/gtsam/preamble.h b/python/gtsam/preamble.h index c8a577431..fa98cd171 100644 --- a/python/gtsam/preamble.h +++ b/python/gtsam/preamble.h @@ -5,10 +5,10 @@ PYBIND11_MAKE_OPAQUE(std::vector>); #else PYBIND11_MAKE_OPAQUE(std::vector); #endif -PYBIND11_MAKE_OPAQUE(std::vector >); +PYBIND11_MAKE_OPAQUE(std::vector>); PYBIND11_MAKE_OPAQUE(std::vector); -PYBIND11_MAKE_OPAQUE(std::vector > >); -PYBIND11_MAKE_OPAQUE(std::vector > >); +PYBIND11_MAKE_OPAQUE(std::vector>>); +PYBIND11_MAKE_OPAQUE(std::vector>>); PYBIND11_MAKE_OPAQUE(std::vector); -PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); -PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); \ No newline at end of file +PYBIND11_MAKE_OPAQUE(gtsam::CameraSet>); +PYBIND11_MAKE_OPAQUE(gtsam::CameraSet>); \ No newline at end of file diff --git a/python/gtsam/specializations.h b/python/gtsam/specializations.h index 431697aac..63694f6f4 100644 --- a/python/gtsam/specializations.h +++ b/python/gtsam/specializations.h @@ -1,17 +1,17 @@ // Please refer to: https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html // These are required to save one copy operation on Python calls #ifdef GTSAM_ALLOCATOR_TBB -py::bind_vector > >(m_, "KeyVector"); +py::bind_vector>>(m_, "KeyVector"); #else -py::bind_vector >(m_, "KeyVector"); +py::bind_vector>(m_, "KeyVector"); #endif -py::bind_vector > >(m_, "Point2Vector"); -py::bind_vector >(m_, "Pose3Vector"); -py::bind_vector > > >(m_, "BetweenFactorPose3s"); -py::bind_vector > > >(m_, "BetweenFactorPose2s"); -py::bind_vector > >(m_, "BinaryMeasurementsUnit3"); +py::bind_vector>>(m_, "Point2Vector"); +py::bind_vector>(m_, "Pose3Vector"); +py::bind_vector>>>(m_, "BetweenFactorPose3s"); +py::bind_vector>>>(m_, "BetweenFactorPose2s"); +py::bind_vector>>(m_, "BinaryMeasurementsUnit3"); py::bind_map(m_, "IndexPairSetMap"); py::bind_vector(m_, "IndexPairVector"); py::bind_map(m_, "KeyPairDoubleMap"); -py::bind_vector > >(m_, "CameraSetCal3_S2"); -py::bind_vector > >(m_, "CameraSetCal3Bundler"); +py::bind_vector>>(m_, "CameraSetCal3_S2"); +py::bind_vector>>(m_, "CameraSetCal3Bundler"); diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index c04766804..6d7751356 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -14,11 +14,10 @@ import numpy as np import gtsam as g from gtsam.utils.test_case import GtsamTestCase -from gtsam import Cal3_S2, Cal3Bundler, Rot3, Pose3, \ - PinholeCameraCal3_S2, PinholeCameraCal3Bundler, Point3, \ - Point2Vector, Pose3Vector, triangulatePoint3, \ - CameraSetCal3_S2, CameraSetCal3Bundler -from numpy.core.records import array +from gtsam import Cal3_S2, Cal3Bundler, CameraSetCal3_S2,\ + CameraSetCal3Bundler, PinholeCameraCal3_S2, PinholeCameraCal3Bundler, \ + Point3, Pose3, Point2Vector, Pose3Vector, Rot3, triangulatePoint3 + class TestVisualISAMExample(GtsamTestCase): """ Tests for triangulation with shared and individual calibrations """ @@ -48,7 +47,6 @@ class TestVisualISAMExample(GtsamTestCase): Returns: vector of measurements and cameras """ - cameras = [] measurements = Point2Vector() for k, pose in zip(cal_params, self.poses): @@ -85,6 +83,8 @@ class TestVisualISAMExample(GtsamTestCase): K2 = (1600, 1300, 0, 650, 440) measurements, camera_list = self.generate_measurements(Cal3_S2, PinholeCameraCal3_S2, K1, K2) + + # convert list to CameraSet object cameras = CameraSetCal3_S2() for camera in camera_list: cameras.append(camera) @@ -99,6 +99,8 @@ class TestVisualISAMExample(GtsamTestCase): K2 = (1600, 0, 0, 650, 440) measurements, camera_list = self.generate_measurements(Cal3Bundler, PinholeCameraCal3Bundler, K1, K2) + + # convert list to CameraSet object cameras = CameraSetCal3Bundler() for camera in camera_list: cameras.append(camera) From 2d0945505debdfa4fe9e1afbd308ac644d1b4fa3 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Fri, 4 Dec 2020 16:15:21 -0500 Subject: [PATCH 141/261] disambiguate overloaded base class --- gtsam/geometry/Cal3_S2Stereo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/geometry/Cal3_S2Stereo.h b/gtsam/geometry/Cal3_S2Stereo.h index 01e48a816..ae0052fd5 100644 --- a/gtsam/geometry/Cal3_S2Stereo.h +++ b/gtsam/geometry/Cal3_S2Stereo.h @@ -80,7 +80,7 @@ class GTSAM_EXPORT Cal3_S2Stereo : public Cal3_S2 { * @param p point in image coordinates * @return point in intrinsic coordinates */ - using Cal3_S2::calibrate; + Vector3 calibrate(const Vector3& p) const { return Cal3_S2::calibrate(p); } /// @} /// @name Testable From 44d1d69274886b7dc6885e1ada8159fa89e7c4c2 Mon Sep 17 00:00:00 2001 From: Sushmita Date: Sat, 5 Dec 2020 12:07:39 -0500 Subject: [PATCH 142/261] removed typedef and formatted code --- gtsam/gtsam.i | 4 ---- python/gtsam/tests/test_Triangulation.py | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 1ab2425ec..0d739c138 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -1112,10 +1112,6 @@ namespace gtsam void push_back(const T &cam); }; - // typedefs added here for shorter type name and to enforce uniformity in naming conventions - //typedef gtsam::CameraSet CameraSetCal3_S2; - //typedef gtsam::CameraSet CameraSetCal3Bundler; - #include class StereoCamera { diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index 6d7751356..0dff861f1 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -45,10 +45,11 @@ class TestVisualISAMExample(GtsamTestCase): camera_model: Camera model e.g. PinholeCameraCal3_S2 cal_params: (list of) camera parameters e.g. K1, K2 Returns: - vector of measurements and cameras + list of measurements and cameras """ cameras = [] - measurements = Point2Vector() + measurements = Point2Vector() + for k, pose in zip(cal_params, self.poses): K = calibration(*k) camera = camera_model(pose, K) @@ -63,22 +64,23 @@ class TestVisualISAMExample(GtsamTestCase): """ Tests triangulation with shared Cal3_S2 calibration""" # Some common constants sharedCal = (1500, 1200, 0, 640, 480) + measurements, _ = self.generate_measurements(Cal3_S2, PinholeCameraCal3_S2, sharedCal, sharedCal) - triangulated_landmark = triangulatePoint3(self.poses,Cal3_S2(sharedCal), measurements, rank_tol=1e-9, optimize=True) + triangulated_landmark = triangulatePoint3(self.poses, Cal3_S2(sharedCal), measurements, rank_tol=1e-9, optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) - # 2. Add some noise and try again: result should be ~ (4.995, 0.499167, 1.19814) + # Add some noise and try again: result should be ~ (4.995, 0.499167, 1.19814) measurements_noisy = Point2Vector() measurements_noisy.append(measurements[0] - np.array([0.1, 0.5])) measurements_noisy.append(measurements[1] - np.array([-0.2, 0.3])) - triangulated_landmark = triangulatePoint3(self.poses,Cal3_S2(sharedCal), measurements_noisy, rank_tol=1e-9, optimize=True) - self.gtsamAssertEquals(self.landmark, triangulated_landmark,1e-2) + triangulated_landmark = triangulatePoint3(self.poses, Cal3_S2(sharedCal), measurements_noisy, rank_tol=1e-9, optimize=True) + self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-2) def test_distinct_Ks(self): """ Tests triangulation with individual Cal3_S2 calibrations """ - # two cameras + # two camera parameters K1 = (1500, 1200, 0, 640, 480) K2 = (1600, 1300, 0, 650, 440) @@ -94,7 +96,7 @@ class TestVisualISAMExample(GtsamTestCase): def test_distinct_Ks_Bundler(self): """ Tests triangulation with individual Cal3Bundler calibrations""" - # two cameras + # two camera parameters K1 = (1500, 0, 0, 640, 480) K2 = (1600, 0, 0, 650, 440) From e8897ba1d8ba5116c062dfc162098fc5b3c611a8 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sat, 5 Dec 2020 12:13:58 -0500 Subject: [PATCH 143/261] function to save graph as graphviz file via wrapper --- gtsam/gtsam.i | 1 + gtsam/nonlinear/NonlinearFactorGraph.cpp | 11 +++++++++++ gtsam/nonlinear/NonlinearFactorGraph.h | 7 ++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 493c1d7db..afd1b4314 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -2041,6 +2041,7 @@ class NonlinearFactorGraph { // enabling serialization functionality void serialize() const; + void saveGraph(const string& s) const; }; #include diff --git a/gtsam/nonlinear/NonlinearFactorGraph.cpp b/gtsam/nonlinear/NonlinearFactorGraph.cpp index 0b876f376..3063aa329 100644 --- a/gtsam/nonlinear/NonlinearFactorGraph.cpp +++ b/gtsam/nonlinear/NonlinearFactorGraph.cpp @@ -34,6 +34,7 @@ #endif #include +#include #include using namespace std; @@ -256,6 +257,16 @@ void NonlinearFactorGraph::saveGraph(std::ostream &stm, const Values& values, stm << "}\n"; } +/* ************************************************************************* */ +void NonlinearFactorGraph::saveGraph( + const std::string& file, const Values& values, + const GraphvizFormatting& graphvizFormatting, + const KeyFormatter& keyFormatter) const { + std::ofstream of(file); + saveGraph(of, values, graphvizFormatting, keyFormatter); + of.close(); +} + /* ************************************************************************* */ double NonlinearFactorGraph::error(const Values& values) const { gttic(NonlinearFactorGraph_error); diff --git a/gtsam/nonlinear/NonlinearFactorGraph.h b/gtsam/nonlinear/NonlinearFactorGraph.h index 0e17700d0..f6b17edbc 100644 --- a/gtsam/nonlinear/NonlinearFactorGraph.h +++ b/gtsam/nonlinear/NonlinearFactorGraph.h @@ -11,7 +11,7 @@ /** * @file NonlinearFactorGraph.h - * @brief Factor Graph Constsiting of non-linear factors + * @brief Factor Graph consisting of non-linear factors * @author Frank Dellaert * @author Carlos Nieto * @author Christian Potthast @@ -115,6 +115,11 @@ namespace gtsam { void saveGraph(std::ostream& stm, const Values& values = Values(), const GraphvizFormatting& graphvizFormatting = GraphvizFormatting(), const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; + + /** Write the graph in GraphViz format to file for visualization */ + void saveGraph(const std::string& file, const Values& values = Values(), + const GraphvizFormatting& graphvizFormatting = GraphvizFormatting(), + const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; /** unnormalized error, \f$ 0.5 \sum_i (h_i(X_i)-z)^2/\sigma^2 \f$ in the most common case */ double error(const Values& values) const; From 858884f1e7a74f65a357a2f800141ce30ec0b493 Mon Sep 17 00:00:00 2001 From: Sushmita Date: Sat, 5 Dec 2020 13:16:13 -0500 Subject: [PATCH 144/261] moved camera_set to generate_measurements --- python/gtsam/tests/test_Triangulation.py | 28 ++++++++++-------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index 0dff861f1..901aad0b9 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -38,18 +38,22 @@ class TestVisualISAMExample(GtsamTestCase): # landmark ~5 meters infront of camera self.landmark = Point3(5, 0.5, 1.2) - def generate_measurements(self, calibration, camera_model, *cal_params): + def generate_measurements(self, calibration, camera_model, camera_set, *cal_params): """ Generate vector of measurements for given calibration and camera model Args: calibration: Camera calibration e.g. Cal3_S2 camera_model: Camera model e.g. PinholeCameraCal3_S2 cal_params: (list of) camera parameters e.g. K1, K2 + camera_set: Cameraset object (for individual calibrations) Returns: - list of measurements and cameras + list of measurements and list/CameraSet object for cameras """ - cameras = [] + if camera_set is not None: + cameras = camera_set() + else: + cameras = [] measurements = Point2Vector() - + for k, pose in zip(cal_params, self.poses): K = calibration(*k) camera = camera_model(pose, K) @@ -65,7 +69,7 @@ class TestVisualISAMExample(GtsamTestCase): # Some common constants sharedCal = (1500, 1200, 0, 640, 480) - measurements, _ = self.generate_measurements(Cal3_S2, PinholeCameraCal3_S2, sharedCal, sharedCal) + measurements, _ = self.generate_measurements(Cal3_S2, PinholeCameraCal3_S2, None, sharedCal, sharedCal) triangulated_landmark = triangulatePoint3(self.poses, Cal3_S2(sharedCal), measurements, rank_tol=1e-9, optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) @@ -84,12 +88,7 @@ class TestVisualISAMExample(GtsamTestCase): K1 = (1500, 1200, 0, 640, 480) K2 = (1600, 1300, 0, 650, 440) - measurements, camera_list = self.generate_measurements(Cal3_S2, PinholeCameraCal3_S2, K1, K2) - - # convert list to CameraSet object - cameras = CameraSetCal3_S2() - for camera in camera_list: - cameras.append(camera) + measurements, cameras = self.generate_measurements(Cal3_S2, PinholeCameraCal3_S2, CameraSetCal3_S2, K1, K2) triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol=1e-9, optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) @@ -100,12 +99,7 @@ class TestVisualISAMExample(GtsamTestCase): K1 = (1500, 0, 0, 640, 480) K2 = (1600, 0, 0, 650, 440) - measurements, camera_list = self.generate_measurements(Cal3Bundler, PinholeCameraCal3Bundler, K1, K2) - - # convert list to CameraSet object - cameras = CameraSetCal3Bundler() - for camera in camera_list: - cameras.append(camera) + measurements, cameras = self.generate_measurements(Cal3Bundler, PinholeCameraCal3Bundler, CameraSetCal3Bundler, K1, K2) triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol=1e-9, optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) From fcf2d316848cb54b50513af27f7a1f00501b119b Mon Sep 17 00:00:00 2001 From: lcarlone Date: Sat, 5 Dec 2020 13:47:40 -0500 Subject: [PATCH 145/261] moved class to .h --- gtsam/nonlinear/GncOptimizer.h | 312 +++++++++++++++++++++++++++++++++ tests/testGncOptimizer.cpp | 293 +------------------------------ 2 files changed, 320 insertions(+), 285 deletions(-) create mode 100644 gtsam/nonlinear/GncOptimizer.h diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h new file mode 100644 index 000000000..6601494e8 --- /dev/null +++ b/gtsam/nonlinear/GncOptimizer.h @@ -0,0 +1,312 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file testGncOptimizer.cpp + * @brief Unit tests for GncOptimizer class + * @author Jingnan Shi + * @author Luca Carlone + * @author Frank Dellaert + * + * Implementation of the paper: Yang, Antonante, Tzoumas, Carlone, "Graduated Non-Convexity for Robust Spatial Perception: + * From Non-Minimal Solvers to Global Outlier Rejection", ICRA/RAL, 2020. (arxiv version: https://arxiv.org/pdf/1909.08605.pdf) + * + * See also: + * Antonante, Tzoumas, Yang, Carlone, "Outlier-Robust Estimation: Hardness, Minimally-Tuned Algorithms, and Applications", + * arxiv: https://arxiv.org/pdf/2007.15109.pdf, 2020. + */ + +#pragma once + +#include +#include +#include + +namespace gtsam { + +/* ************************************************************************* */ +template +class GncParams { +public: + /** Verbosity levels */ + enum VerbosityGNC { + SILENT = 0, SUMMARY, VALUES + }; + + /** Choice of robust loss function for GNC */ + enum RobustLossType { + GM /*Geman McClure*/, TLS /*Truncated least squares*/ + }; + + using BaseOptimizer = GaussNewtonOptimizer; // BaseOptimizerParameters::OptimizerType; + + GncParams(const BaseOptimizerParameters& baseOptimizerParams) : + baseOptimizerParams(baseOptimizerParams) { + } + + // default constructor + GncParams() : + baseOptimizerParams() { + } + + BaseOptimizerParameters baseOptimizerParams; + /// any other specific GNC parameters: + RobustLossType lossType = GM; /* default loss*/ + size_t maxIterations = 100; /* maximum number of iterations*/ + double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ + double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ + VerbosityGNC verbosityGNC = SILENT; /* verbosity level */ + std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ + + void setLossType(const RobustLossType type) { + lossType = type; + } + void setMaxIterations(const size_t maxIter) { + std::cout + << "setMaxIterations: changing the max nr of iters might lead to less accurate solutions and is not recommended! " + << std::endl; + maxIterations = maxIter; + } + void setInlierThreshold(const double inth) { + barcSq = inth; + } + void setMuStep(const double step) { + muStep = step; + } + void setVerbosityGNC(const VerbosityGNC verbosity) { + verbosityGNC = verbosity; + } + void setKnownInliers(const std::vector knownIn) { + for (size_t i = 0; i < knownIn.size(); i++) + knownInliers.push_back(knownIn[i]); + } + + /// equals + bool equals(const GncParams& other, double tol = 1e-9) const { + return baseOptimizerParams.equals(other.baseOptimizerParams) + && lossType == other.lossType && maxIterations == other.maxIterations + && std::fabs(barcSq - other.barcSq) <= tol + && std::fabs(muStep - other.muStep) <= tol + && verbosityGNC == other.verbosityGNC + && knownInliers == other.knownInliers; + } + + /// print function + void print(const std::string& str) const { + std::cout << str << "\n"; + switch (lossType) { + case GM: + std::cout << "lossType: Geman McClure" << "\n"; + break; + default: + throw std::runtime_error("GncParams::print: unknown loss type."); + } + std::cout << "maxIterations: " << maxIterations << "\n"; + std::cout << "barcSq: " << barcSq << "\n"; + std::cout << "muStep: " << muStep << "\n"; + std::cout << "verbosityGNC: " << verbosityGNC << "\n"; + for (size_t i = 0; i < knownInliers.size(); i++) + std::cout << "knownInliers: " << knownInliers[i] << "\n"; + baseOptimizerParams.print(str); + } +}; + +/* ************************************************************************* */ +template +class GncOptimizer { +public: + // types etc + +private: + NonlinearFactorGraph nfg_; + Values state_; + GncParameters params_; + Vector weights_; // this could be a local variable in optimize, but it is useful to make it accessible from outside + +public: + GncOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, + const GncParameters& params = GncParameters()) : + state_(initialValues), params_(params) { + + // make sure all noiseModels are Gaussian or convert to Gaussian + nfg_.resize(graph.size()); + for (size_t i = 0; i < graph.size(); i++) { + if (graph[i]) { + NoiseModelFactor::shared_ptr factor = boost::dynamic_pointer_cast< + NoiseModelFactor>(graph[i]); + noiseModel::Robust::shared_ptr robust = boost::dynamic_pointer_cast< + noiseModel::Robust>(factor->noiseModel()); + if (robust) { // if the factor has a robust loss, we have to change it: + SharedNoiseModel gaussianNoise = robust->noise(); + NoiseModelFactor::shared_ptr gaussianFactor = + factor->cloneWithNewNoiseModel(gaussianNoise); + nfg_[i] = gaussianFactor; + } else { // else we directly push it back + nfg_[i] = factor; + } + } + } + } + + /// getter functions + NonlinearFactorGraph getFactors() const { + return NonlinearFactorGraph(nfg_); + } + Values getState() const { + return Values(state_); + } + GncParameters getParams() const { + return GncParameters(params_); + } + Vector getWeights() const { + return weights_; + } + + /// implement GNC main loop, including graduating nonconvexity with mu + Values optimize() { + // start by assuming all measurements are inliers + weights_ = Vector::Ones(nfg_.size()); + GaussNewtonOptimizer baseOptimizer(nfg_, state_); + Values result = baseOptimizer.optimize(); + double mu = initializeMu(); + for (size_t iter = 0; iter < params_.maxIterations; iter++) { + + // display info + if (params_.verbosityGNC >= GncParameters::VerbosityGNC::VALUES) { + result.print("result\n"); + std::cout << "mu: " << mu << std::endl; + std::cout << "weights: " << weights_ << std::endl; + } + // weights update + weights_ = calculateWeights(result, mu); + + // variable/values update + NonlinearFactorGraph graph_iter = this->makeWeightedGraph(weights_); + GaussNewtonOptimizer baseOptimizer_iter(graph_iter, state_); + result = baseOptimizer_iter.optimize(); + + // stopping condition + if (checkMuConvergence(mu)) { + // display info + if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { + std::cout << "final iterations: " << iter << std::endl; + std::cout << "final mu: " << mu << std::endl; + std::cout << "final weights: " << weights_ << std::endl; + } + break; + } + + // otherwise update mu + mu = updateMu(mu); + } + return result; + } + + /// initialize the gnc parameter mu such that loss is approximately convex (remark 5 in GNC paper) + double initializeMu() const { + // compute largest error across all factors + double rmax_sq = 0.0; + for (size_t i = 0; i < nfg_.size(); i++) { + if (nfg_[i]) { + rmax_sq = std::max(rmax_sq, nfg_[i]->error(state_)); + } + } + // set initial mu + switch (params_.lossType) { + case GncParameters::GM: + return 2 * rmax_sq / params_.barcSq; // initial mu + default: + throw std::runtime_error( + "GncOptimizer::initializeMu: called with unknown loss type."); + } + } + + /// update the gnc parameter mu to gradually increase nonconvexity + double updateMu(const double mu) const { + switch (params_.lossType) { + case GncParameters::GM: + return std::max(1.0, mu / params_.muStep); // reduce mu, but saturate at 1 + default: + throw std::runtime_error( + "GncOptimizer::updateMu: called with unknown loss type."); + } + } + + /// check if we have reached the value of mu for which the surrogate loss matches the original loss + bool checkMuConvergence(const double mu) const { + switch (params_.lossType) { + case GncParameters::GM: + return std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function + default: + throw std::runtime_error( + "GncOptimizer::checkMuConvergence: called with unknown loss type."); + } + } + + /// create a graph where each factor is weighted by the gnc weights + NonlinearFactorGraph makeWeightedGraph(const Vector& weights) const { + // make sure all noiseModels are Gaussian or convert to Gaussian + NonlinearFactorGraph newGraph; + newGraph.resize(nfg_.size()); + for (size_t i = 0; i < nfg_.size(); i++) { + if (nfg_[i]) { + NoiseModelFactor::shared_ptr factor = boost::dynamic_pointer_cast< + NoiseModelFactor>(nfg_[i]); + noiseModel::Gaussian::shared_ptr noiseModel = + boost::dynamic_pointer_cast( + factor->noiseModel()); + if (noiseModel) { + Matrix newInfo = weights[i] * noiseModel->information(); + SharedNoiseModel newNoiseModel = noiseModel::Gaussian::Information( + newInfo); + newGraph[i] = factor->cloneWithNewNoiseModel(newNoiseModel); + } else { + throw std::runtime_error( + "GncOptimizer::makeWeightedGraph: unexpected non-Gaussian noise model."); + } + } + } + return newGraph; + } + + /// calculate gnc weights + Vector calculateWeights(const Values currentEstimate, const double mu) { + Vector weights = Vector::Ones(nfg_.size()); + + // do not update the weights that the user has decided are known inliers + std::vector allWeights; + for (size_t k = 0; k < nfg_.size(); k++) { + allWeights.push_back(k); + } + std::vector unknownWeights; + std::set_difference(allWeights.begin(), allWeights.end(), + params_.knownInliers.begin(), params_.knownInliers.end(), + std::inserter(unknownWeights, unknownWeights.begin())); + + // update weights of known inlier/outlier measurements + switch (params_.lossType) { + case GncParameters::GM: // use eq (12) in GNC paper + for (size_t k : unknownWeights) { + if (nfg_[k]) { + double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual + weights[k] = std::pow( + (mu * params_.barcSq) / (u2_k + mu * params_.barcSq), 2); + } + } + return weights; + default: + throw std::runtime_error( + "GncOptimizer::calculateWeights: called with unknown loss type."); + } + } +}; + +} diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 8415ec3cc..5006aa941 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -17,16 +17,16 @@ * @author Frank Dellaert * * Implementation of the paper: Yang, Antonante, Tzoumas, Carlone, "Graduated Non-Convexity for Robust Spatial Perception: - * From Non-Minimal Solvers to Global Outlier Rejection", RAL, 2020. (arxiv version: https://arxiv.org/pdf/1909.08605.pdf) + * From Non-Minimal Solvers to Global Outlier Rejection", ICRA/RAL, 2020. (arxiv version: https://arxiv.org/pdf/1909.08605.pdf) + * + * See also: + * Antonante, Tzoumas, Yang, Carlone, "Outlier-Robust Estimation: Hardness, Minimally-Tuned Algorithms, and Applications", + * arxiv: https://arxiv.org/pdf/2007.15109.pdf, 2020. */ #include - -#include -#include -#include +#include #include - #include using namespace std; @@ -36,283 +36,6 @@ using symbol_shorthand::X; using symbol_shorthand::L; static double tol = 1e-7; -/* ************************************************************************* */ -template -class GncParams { -public: - /** Verbosity levels */ - enum VerbosityGNC { - SILENT = 0, SUMMARY, VALUES - }; - - /** Choice of robust loss function for GNC */ - enum RobustLossType { - GM /*Geman McClure*/, TLS /*Truncated least squares*/ - }; - - using BaseOptimizer = GaussNewtonOptimizer; // BaseOptimizerParameters::OptimizerType; - - GncParams(const BaseOptimizerParameters& baseOptimizerParams) : - baseOptimizerParams(baseOptimizerParams) { - } - - // default constructor - GncParams() : - baseOptimizerParams() { - } - - BaseOptimizerParameters baseOptimizerParams; - /// any other specific GNC parameters: - RobustLossType lossType = GM; /* default loss*/ - size_t maxIterations = 100; /* maximum number of iterations*/ - double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ - double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ - VerbosityGNC verbosityGNC = SILENT; /* verbosity level */ - std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ - - void setLossType(const RobustLossType type) { - lossType = type; - } - void setMaxIterations(const size_t maxIter) { - std::cout - << "setMaxIterations: changing the max nr of iters might lead to less accurate solutions and is not recommended! " - << std::endl; - maxIterations = maxIter; - } - void setInlierThreshold(const double inth) { - barcSq = inth; - } - void setMuStep(const double step) { - muStep = step; - } - void setVerbosityGNC(const VerbosityGNC verbosity) { - verbosityGNC = verbosity; - } - void setKnownInliers(const std::vector knownIn) { - for (size_t i = 0; i < knownIn.size(); i++) - knownInliers.push_back(knownIn[i]); - } - - /// equals - bool equals(const GncParams& other, double tol = 1e-9) const { - return baseOptimizerParams.equals(other.baseOptimizerParams) - && lossType == other.lossType && maxIterations == other.maxIterations - && std::fabs(barcSq - other.barcSq) <= tol - && std::fabs(muStep - other.muStep) <= tol - && verbosityGNC == other.verbosityGNC - && knownInliers == other.knownInliers; - } - - /// print function - void print(const std::string& str) const { - std::cout << str << "\n"; - switch (lossType) { - case GM: - std::cout << "lossType: Geman McClure" << "\n"; - break; - default: - throw std::runtime_error("GncParams::print: unknown loss type."); - } - std::cout << "maxIterations: " << maxIterations << "\n"; - std::cout << "barcSq: " << barcSq << "\n"; - std::cout << "muStep: " << muStep << "\n"; - std::cout << "verbosityGNC: " << verbosityGNC << "\n"; - for (size_t i = 0; i < knownInliers.size(); i++) - std::cout << "knownInliers: " << knownInliers[i] << "\n"; - baseOptimizerParams.print(str); - } -}; - -/* ************************************************************************* */ -template -class GncOptimizer { -public: - // types etc - -private: - NonlinearFactorGraph nfg_; - Values state_; - GncParameters params_; - Vector weights_; // this could be a local variable in optimize, but it is useful to make it accessible from outside - -public: - GncOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, - const GncParameters& params = GncParameters()) : - state_(initialValues), params_(params) { - - // make sure all noiseModels are Gaussian or convert to Gaussian - nfg_.resize(graph.size()); - for (size_t i = 0; i < graph.size(); i++) { - if (graph[i]) { - NoiseModelFactor::shared_ptr factor = boost::dynamic_pointer_cast< - NoiseModelFactor>(graph[i]); - noiseModel::Robust::shared_ptr robust = boost::dynamic_pointer_cast< - noiseModel::Robust>(factor->noiseModel()); - if (robust) { // if the factor has a robust loss, we have to change it: - SharedNoiseModel gaussianNoise = robust->noise(); - NoiseModelFactor::shared_ptr gaussianFactor = - factor->cloneWithNewNoiseModel(gaussianNoise); - nfg_[i] = gaussianFactor; - } else { // else we directly push it back - nfg_[i] = factor; - } - } - } - } - - /// getter functions - NonlinearFactorGraph getFactors() const { - return NonlinearFactorGraph(nfg_); - } - Values getState() const { - return Values(state_); - } - GncParameters getParams() const { - return GncParameters(params_); - } - Vector getWeights() const { - return weights_; - } - - /// implement GNC main loop, including graduating nonconvexity with mu - Values optimize() { - // start by assuming all measurements are inliers - weights_ = Vector::Ones(nfg_.size()); - GaussNewtonOptimizer baseOptimizer(nfg_, state_); - Values result = baseOptimizer.optimize(); - double mu = initializeMu(); - for (size_t iter = 0; iter < params_.maxIterations; iter++) { - - // display info - if (params_.verbosityGNC >= GncParameters::VerbosityGNC::VALUES) { - result.print("result\n"); - std::cout << "mu: " << mu << std::endl; - std::cout << "weights: " << weights_ << std::endl; - } - // weights update - weights_ = calculateWeights(result, mu); - - // variable/values update - NonlinearFactorGraph graph_iter = this->makeWeightedGraph(weights_); - GaussNewtonOptimizer baseOptimizer_iter(graph_iter, state_); - result = baseOptimizer_iter.optimize(); - - // stopping condition - if (checkMuConvergence(mu)) { - // display info - if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { - std::cout << "final iterations: " << iter << std::endl; - std::cout << "final mu: " << mu << std::endl; - std::cout << "final weights: " << weights_ << std::endl; - } - break; - } - - // otherwise update mu - mu = updateMu(mu); - } - return result; - } - - /// initialize the gnc parameter mu such that loss is approximately convex (remark 5 in GNC paper) - double initializeMu() const { - // compute largest error across all factors - double rmax_sq = 0.0; - for (size_t i = 0; i < nfg_.size(); i++) { - if (nfg_[i]) { - rmax_sq = std::max(rmax_sq, nfg_[i]->error(state_)); - } - } - // set initial mu - switch (params_.lossType) { - case GncParameters::GM: - return 2 * rmax_sq / params_.barcSq; // initial mu - default: - throw std::runtime_error( - "GncOptimizer::initializeMu: called with unknown loss type."); - } - } - - /// update the gnc parameter mu to gradually increase nonconvexity - double updateMu(const double mu) const { - switch (params_.lossType) { - case GncParameters::GM: - return std::max(1.0, mu / params_.muStep); // reduce mu, but saturate at 1 - default: - throw std::runtime_error( - "GncOptimizer::updateMu: called with unknown loss type."); - } - } - - /// check if we have reached the value of mu for which the surrogate loss matches the original loss - bool checkMuConvergence(const double mu) const { - switch (params_.lossType) { - case GncParameters::GM: - return std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function - default: - throw std::runtime_error( - "GncOptimizer::checkMuConvergence: called with unknown loss type."); - } - } - - /// create a graph where each factor is weighted by the gnc weights - NonlinearFactorGraph makeWeightedGraph(const Vector& weights) const { - // make sure all noiseModels are Gaussian or convert to Gaussian - NonlinearFactorGraph newGraph; - newGraph.resize(nfg_.size()); - for (size_t i = 0; i < nfg_.size(); i++) { - if (nfg_[i]) { - NoiseModelFactor::shared_ptr factor = boost::dynamic_pointer_cast< - NoiseModelFactor>(nfg_[i]); - noiseModel::Gaussian::shared_ptr noiseModel = - boost::dynamic_pointer_cast( - factor->noiseModel()); - if (noiseModel) { - Matrix newInfo = weights[i] * noiseModel->information(); - SharedNoiseModel newNoiseModel = noiseModel::Gaussian::Information( - newInfo); - newGraph[i] = factor->cloneWithNewNoiseModel(newNoiseModel); - } else { - throw std::runtime_error( - "GncOptimizer::makeWeightedGraph: unexpected non-Gaussian noise model."); - } - } - } - return newGraph; - } - - /// calculate gnc weights - Vector calculateWeights(const Values currentEstimate, const double mu) { - Vector weights = Vector::Ones(nfg_.size()); - - // do not update the weights that the user has decided are known inliers - std::vector allWeights; - for (size_t k = 0; k < nfg_.size(); k++) { - allWeights.push_back(k); - } - std::vector unknownWeights; - std::set_difference(allWeights.begin(), allWeights.end(), - params_.knownInliers.begin(), params_.knownInliers.end(), - std::inserter(unknownWeights, unknownWeights.begin())); - - // update weights of known inlier/outlier measurements - switch (params_.lossType) { - case GncParameters::GM: // use eq (12) in GNC paper - for (size_t k : unknownWeights) { - if (nfg_[k]) { - double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual - weights[k] = std::pow( - (mu * params_.barcSq) / (u2_k + mu * params_.barcSq), 2); - } - } - return weights; - default: - throw std::runtime_error( - "GncOptimizer::calculateWeights: called with unknown loss type."); - } - } -}; - /* ************************************************************************* */ TEST(GncOptimizer, gncParamsConstructor) { //check params are correctly parsed @@ -566,7 +289,7 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { knownInliers.push_back(2); // nonconvexity with known inliers - GncParams gncParams = GncParams(); + GncParams gncParams; gncParams.setKnownInliers(knownInliers); // gncParams.setVerbosityGNC(GncParams::VerbosityGNC::VALUES); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -609,7 +332,7 @@ TEST(GncOptimizer, optimizeSmallPoseGraph) { // Note: in difficult instances, we set the odometry measurements to be inliers, // but this problem is simple enought to succeed even without that assumption // std::vector knownInliers; - GncParams gncParams = GncParams(); + GncParams gncParams; auto gnc = GncOptimizer>(*graph, *initial, gncParams); Values actual = gnc.optimize(); From db1a3668483e7a94804f9e2d05e254d081cf8ccf Mon Sep 17 00:00:00 2001 From: lcarlone Date: Sat, 5 Dec 2020 14:06:32 -0500 Subject: [PATCH 146/261] added comments --- gtsam/nonlinear/GncOptimizer.h | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index 6601494e8..7c41b2475 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -48,16 +48,18 @@ public: using BaseOptimizer = GaussNewtonOptimizer; // BaseOptimizerParameters::OptimizerType; + /// Constructor GncParams(const BaseOptimizerParameters& baseOptimizerParams) : baseOptimizerParams(baseOptimizerParams) { } - // default constructor + /// Default constructor GncParams() : baseOptimizerParams() { } - BaseOptimizerParameters baseOptimizerParams; + /// GNC parameters + BaseOptimizerParameters baseOptimizerParams; /*optimization parameters used to solve the weighted least squares problem at each GNC iteration*/ /// any other specific GNC parameters: RobustLossType lossType = GM; /* default loss*/ size_t maxIterations = 100; /* maximum number of iterations*/ @@ -66,29 +68,41 @@ public: VerbosityGNC verbosityGNC = SILENT; /* verbosity level */ std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ + /// Set the robust loss function to be used in GNC (chosen among the ones in RobustLossType) void setLossType(const RobustLossType type) { lossType = type; } + /// Set the maximum number of iterations in GNC (changing the max nr of iters might lead to less accurate solutions and is not recommended) void setMaxIterations(const size_t maxIter) { std::cout << "setMaxIterations: changing the max nr of iters might lead to less accurate solutions and is not recommended! " << std::endl; maxIterations = maxIter; } + /** Set the maximum weighted residual error for an inlier. For a factor in the form f(x) = 0.5 * || r(x) ||^2_Omega, + * the inlier threshold is the largest value of f(x) for the corresponding measurement to be considered an inlier. + * */ void setInlierThreshold(const double inth) { barcSq = inth; } + /// Set the graduated non-convexity step: at each GNC iteration, mu is updated as mu <- mu * muStep void setMuStep(const double step) { muStep = step; } + /// Set the verbosity level void setVerbosityGNC(const VerbosityGNC verbosity) { verbosityGNC = verbosity; } + /** (Optional) Provide a vector of measurements that must be considered inliers. The enties in the vector + * corresponds to the slots in the factor graph. For instance, if you have a nonlinear factor graph nfg, + * and you provide knownIn = {0, 2, 15}, GNC will not apply outlier rejection to nfg[0], nfg[2], and nfg[15]. + * This functionality is commonly used in SLAM when one may assume the odometry is outlier free, and + * only apply GNC to prune outliers from the loop closures + * */ void setKnownInliers(const std::vector knownIn) { for (size_t i = 0; i < knownIn.size(); i++) knownInliers.push_back(knownIn[i]); } - /// equals bool equals(const GncParams& other, double tol = 1e-9) const { return baseOptimizerParams.equals(other.baseOptimizerParams) @@ -98,7 +112,6 @@ public: && verbosityGNC == other.verbosityGNC && knownInliers == other.knownInliers; } - /// print function void print(const std::string& str) const { std::cout << str << "\n"; @@ -132,6 +145,7 @@ private: Vector weights_; // this could be a local variable in optimize, but it is useful to make it accessible from outside public: + /// Constructor GncOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, const GncParameters& params = GncParameters()) : state_(initialValues), params_(params) { @@ -156,21 +170,23 @@ public: } } - /// getter functions + /// Access a copy of the internal factor graph NonlinearFactorGraph getFactors() const { return NonlinearFactorGraph(nfg_); } + /// Access a copy of the internal values Values getState() const { return Values(state_); } + /// Access a copy of the parameters GncParameters getParams() const { return GncParameters(params_); } + /// Access a copy of the GNC weights Vector getWeights() const { return weights_; } - - /// implement GNC main loop, including graduating nonconvexity with mu + /// Compute optimal solution using graduated non-convexity Values optimize() { // start by assuming all measurements are inliers weights_ = Vector::Ones(nfg_.size()); @@ -203,7 +219,6 @@ public: } break; } - // otherwise update mu mu = updateMu(mu); } From 5e82b72b60e594bd7d67ea3cbeb6485bfb2a14a2 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Sat, 5 Dec 2020 14:34:35 -0500 Subject: [PATCH 147/261] fixed typo --- examples/ShonanAveragingCLI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ShonanAveragingCLI.cpp b/examples/ShonanAveragingCLI.cpp index 9970f45da..c72a32017 100644 --- a/examples/ShonanAveragingCLI.cpp +++ b/examples/ShonanAveragingCLI.cpp @@ -27,7 +27,7 @@ * * If you prefer using a robust Huber loss, you can add the option "-h true", * for instance - * ./ShonanAveragingCLI -i spere2500.txt -u true + * ./ShonanAveragingCLI -i spere2500.txt -h true */ #include From 553f5690387355a73b0b810c3c31d7474739ea6a Mon Sep 17 00:00:00 2001 From: lcarlone Date: Sat, 5 Dec 2020 14:34:46 -0500 Subject: [PATCH 148/261] added more explanation on throw --- gtsam/sfm/ShonanAveraging.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 58921988b..06ff92160 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -811,7 +811,7 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, .useHuber) { // in this case, there is no optimality verification if (pMin != pMax) { throw std::runtime_error( - "When using robust norm, Shonan only tests a single rank"); + "When using robust norm, Shonan only tests a single rank. Set pMin = pMax"); } const Values SO3Values = roundSolution(Qstar); return std::make_pair(SO3Values, 0); From de5adb495f61f30aaf367ff915a438478cf129c8 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sat, 5 Dec 2020 16:06:27 -0500 Subject: [PATCH 149/261] added flag to enable optimality certification, some formatting --- gtsam/sfm/ShonanAveraging.cpp | 49 +++++++++++++++++++---------------- gtsam/sfm/ShonanAveraging.h | 26 +++++++++++-------- 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 06ff92160..e37bfee55 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -54,7 +54,8 @@ ShonanAveragingParameters::ShonanAveragingParameters( alpha(alpha), beta(beta), gamma(gamma), - useHuber(false) { + useHuber(false), + certifyOptimality(true) { // By default, we will do conjugate gradient lm.linearSolverType = LevenbergMarquardtParams::Iterative; @@ -343,13 +344,15 @@ static double Kappa(const BinaryMeasurement &measurement, } else { const auto &robust = boost::dynamic_pointer_cast( measurement.noiseModel()); + // Check if noise model is robust if (robust) { - if (parameters.getUseHuber()) { - // Cannot verify optimality, setting arbitrary value - sigma = 1; - } else { + // If robust, check if optimality certificate is expected + if (parameters.getCertifyOptimality()) { throw std::invalid_argument( - "Robust cost function is invalid unless useHuber is set."); + "Verification of optimality does not work with robust cost."); + } else { + // Optimality certificate not required, so setting default sigma + sigma = 1; } } else { throw std::invalid_argument( @@ -807,30 +810,30 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, for (size_t p = pMin; p <= pMax; p++) { // Optimize until convergence at this level Qstar = tryOptimizingAt(p, initialSOp); - if (parameters_ - .useHuber) { // in this case, there is no optimality verification + if (parameters_.getUseHuber() || parameters_.getCertifyOptimality()) { + // in this case, there is no optimality verification if (pMin != pMax) { throw std::runtime_error( "When using robust norm, Shonan only tests a single rank. Set pMin = pMax"); } const Values SO3Values = roundSolution(Qstar); return std::make_pair(SO3Values, 0); - } + } else { + // Check certificate of global optimality + Vector minEigenVector; + double minEigenValue = computeMinEigenValue(Qstar, &minEigenVector); + if (minEigenValue > parameters_.optimalityThreshold) { + // If at global optimum, round and return solution + const Values SO3Values = roundSolution(Qstar); + return std::make_pair(SO3Values, minEigenValue); + } - // Check certificate of global optimality - Vector minEigenVector; - double minEigenValue = computeMinEigenValue(Qstar, &minEigenVector); - if (minEigenValue > parameters_.optimalityThreshold) { - // If at global optimum, round and return solution - const Values SO3Values = roundSolution(Qstar); - return std::make_pair(SO3Values, minEigenValue); - } - - // Not at global optimimum yet, so check whether we will go to next level - if (p != pMax) { - // Calculate initial estimate for next level by following minEigenVector - initialSOp = - initializeWithDescent(p + 1, Qstar, minEigenVector, minEigenValue); + // Not at global optimimum yet, so check whether we will go to next level + if (p != pMax) { + // Calculate initial estimate for next level by following minEigenVector + initialSOp = + initializeWithDescent(p + 1, Qstar, minEigenVector, minEigenValue); + } } } throw std::runtime_error("Shonan::run did not converge for given pMax"); diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index 48d873a1a..8a620cdc5 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -47,14 +47,16 @@ struct GTSAM_EXPORT ShonanAveragingParameters { using Anchor = std::pair; // Paremeters themselves: - LevenbergMarquardtParams lm; // LM parameters - double optimalityThreshold; // threshold used in checkOptimality - Anchor anchor; // pose to use as anchor if not Karcher - double alpha; // weight of anchor-based prior (default 0) - double beta; // weight of Karcher-based prior (default 1) - double gamma; // weight of gauge-fixing factors (default 0) - bool useHuber; // if enabled, the Huber loss is used in the optimization - // (default is false) + LevenbergMarquardtParams lm; ///< LM parameters + double optimalityThreshold; ///< threshold used in checkOptimality + Anchor anchor; ///< pose to use as anchor if not Karcher + double alpha; ///< weight of anchor-based prior (default 0) + double beta; ///< weight of Karcher-based prior (default 1) + double gamma; ///< weight of gauge-fixing factors (default 0) + ///< if enabled, the Huber loss is used (default false) + bool useHuber; + ///< if enabled solution optimality is certified (default true) + bool certifyOptimality; ShonanAveragingParameters(const LevenbergMarquardtParams &lm = LevenbergMarquardtParams::CeresDefaults(), @@ -83,6 +85,9 @@ struct GTSAM_EXPORT ShonanAveragingParameters { void setUseHuber(bool value) { useHuber = value; } bool getUseHuber() const { return useHuber; } + void setCertifyOptimality(bool value) { certifyOptimality = value; } + bool getCertifyOptimality() const { return certifyOptimality; } + /// Print the parameters and flags used for rotation averaging. void print() const { std::cout << " ShonanAveragingParameters: " << std::endl; @@ -166,7 +171,7 @@ class GTSAM_EXPORT ShonanAveraging { /** * Update factors to use robust Huber loss. - * + * * @param measurements Vector of BinaryMeasurements. * @param k Huber noise model threshold. */ @@ -174,7 +179,6 @@ class GTSAM_EXPORT ShonanAveraging { double k = 1.345) const { Measurements robustMeasurements; for (auto &measurement : measurements) { - auto model = measurement.noiseModel(); const auto &robust = boost::dynamic_pointer_cast(model); @@ -189,7 +193,7 @@ class GTSAM_EXPORT ShonanAveraging { noiseModel::mEstimator::Huber::Create(k), model); } BinaryMeasurement meas(measurement.key1(), measurement.key2(), - measurement.measured(), robust_model); + measurement.measured(), robust_model); robustMeasurements.push_back(meas); } return robustMeasurements; From 9a841a2c3431b843b9d62564190e9167c9deb214 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sat, 5 Dec 2020 17:21:19 -0500 Subject: [PATCH 150/261] correct flag checking --- gtsam/sfm/ShonanAveraging.cpp | 2 +- gtsam/sfm/tests/testShonanAveraging.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index e37bfee55..b40726312 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -810,7 +810,7 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, for (size_t p = pMin; p <= pMax; p++) { // Optimize until convergence at this level Qstar = tryOptimizingAt(p, initialSOp); - if (parameters_.getUseHuber() || parameters_.getCertifyOptimality()) { + if (parameters_.getUseHuber() || !parameters_.getCertifyOptimality()) { // in this case, there is no optimality verification if (pMin != pMax) { throw std::runtime_error( diff --git a/gtsam/sfm/tests/testShonanAveraging.cpp b/gtsam/sfm/tests/testShonanAveraging.cpp index 002109454..c2ad71dad 100644 --- a/gtsam/sfm/tests/testShonanAveraging.cpp +++ b/gtsam/sfm/tests/testShonanAveraging.cpp @@ -330,6 +330,8 @@ TEST(ShonanAveraging2, noisyToyGraphWithHuber) { ShonanAveraging2::Parameters parameters(lmParams); auto measurements = parseMeasurements(g2oFile); parameters.setUseHuber(true); + parameters.setCertifyOptimality(false); + string parameters_print = " ShonanAveragingParameters: \n alpha: 0\n beta: 1\n gamma: 0\n " "useHuber: 1\n"; From b24f943c360b6be3c594fb9e80578b08d8ba28fe Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sat, 5 Dec 2020 18:08:45 -0500 Subject: [PATCH 151/261] Revert "code formatted" This reverts commit 8be6890b206c761bb1f334f4f7ab6fcfa7ccbff0. --- gtsam/geometry/triangulation.h | 726 ++- gtsam/gtsam.i | 5664 +++++++++++----------- python/gtsam/preamble.h | 10 +- python/gtsam/specializations.h | 18 +- python/gtsam/tests/test_Triangulation.py | 9 +- 5 files changed, 3116 insertions(+), 3311 deletions(-) diff --git a/gtsam/geometry/triangulation.h b/gtsam/geometry/triangulation.h index e22b35e56..1df9efd22 100644 --- a/gtsam/geometry/triangulation.h +++ b/gtsam/geometry/triangulation.h @@ -27,52 +27,49 @@ #include #include -namespace gtsam -{ +namespace gtsam { - /// Exception thrown by triangulateDLT when SVD returns rank < 3 - class GTSAM_EXPORT TriangulationUnderconstrainedException : public std::runtime_error - { - public: - TriangulationUnderconstrainedException() : std::runtime_error("Triangulation Underconstrained Exception.") - { - } - }; +/// Exception thrown by triangulateDLT when SVD returns rank < 3 +class GTSAM_EXPORT TriangulationUnderconstrainedException: public std::runtime_error { +public: + TriangulationUnderconstrainedException() : + std::runtime_error("Triangulation Underconstrained Exception.") { + } +}; - /// Exception thrown by triangulateDLT when landmark is behind one or more of the cameras - class GTSAM_EXPORT TriangulationCheiralityException : public std::runtime_error - { - public: - TriangulationCheiralityException() : std::runtime_error( - "Triangulation Cheirality Exception: The resulting landmark is behind one or more cameras.") - { - } - }; +/// Exception thrown by triangulateDLT when landmark is behind one or more of the cameras +class GTSAM_EXPORT TriangulationCheiralityException: public std::runtime_error { +public: + TriangulationCheiralityException() : + std::runtime_error( + "Triangulation Cheirality Exception: The resulting landmark is behind one or more cameras.") { + } +}; - /** +/** * DLT triangulation: See Hartley and Zisserman, 2nd Ed., page 312 * @param projection_matrices Projection matrices (K*P^-1) * @param measurements 2D measurements * @param rank_tol SVD rank tolerance * @return Triangulated point, in homogeneous coordinates */ - GTSAM_EXPORT Vector4 triangulateHomogeneousDLT( - const std::vector> &projection_matrices, - const Point2Vector &measurements, double rank_tol = 1e-9); +GTSAM_EXPORT Vector4 triangulateHomogeneousDLT( + const std::vector>& projection_matrices, + const Point2Vector& measurements, double rank_tol = 1e-9); - /** +/** * DLT triangulation: See Hartley and Zisserman, 2nd Ed., page 312 * @param projection_matrices Projection matrices (K*P^-1) * @param measurements 2D measurements * @param rank_tol SVD rank tolerance * @return Triangulated Point3 */ - GTSAM_EXPORT Point3 triangulateDLT( - const std::vector> &projection_matrices, - const Point2Vector &measurements, - double rank_tol = 1e-9); +GTSAM_EXPORT Point3 triangulateDLT( + const std::vector>& projection_matrices, + const Point2Vector& measurements, + double rank_tol = 1e-9); - /** +/** * Create a factor graph with projection factors from poses and one calibration * @param poses Camera poses * @param sharedCal shared pointer to single calibration object (monocular only!) @@ -81,29 +78,27 @@ namespace gtsam * @param initialEstimate * @return graph and initial values */ - template - std::pair triangulationGraph( - const std::vector &poses, boost::shared_ptr sharedCal, - const Point2Vector &measurements, Key landmarkKey, - const Point3 &initialEstimate) - { - Values values; - values.insert(landmarkKey, initialEstimate); // Initial landmark value - NonlinearFactorGraph graph; - static SharedNoiseModel unit2(noiseModel::Unit::Create(2)); - static SharedNoiseModel prior_model(noiseModel::Isotropic::Sigma(6, 1e-6)); - for (size_t i = 0; i < measurements.size(); i++) - { - const Pose3 &pose_i = poses[i]; - typedef PinholePose Camera; - Camera camera_i(pose_i, sharedCal); - graph.emplace_shared> // - (camera_i, measurements[i], unit2, landmarkKey); - } - return std::make_pair(graph, values); +template +std::pair triangulationGraph( + const std::vector& poses, boost::shared_ptr sharedCal, + const Point2Vector& measurements, Key landmarkKey, + const Point3& initialEstimate) { + Values values; + values.insert(landmarkKey, initialEstimate); // Initial landmark value + NonlinearFactorGraph graph; + static SharedNoiseModel unit2(noiseModel::Unit::Create(2)); + static SharedNoiseModel prior_model(noiseModel::Isotropic::Sigma(6, 1e-6)); + for (size_t i = 0; i < measurements.size(); i++) { + const Pose3& pose_i = poses[i]; + typedef PinholePose Camera; + Camera camera_i(pose_i, sharedCal); + graph.emplace_shared > // + (camera_i, measurements[i], unit2, landmarkKey); } + return std::make_pair(graph, values); +} - /** +/** * Create a factor graph with projection factors from pinhole cameras * (each camera has a pose and calibration) * @param cameras pinhole cameras (monocular or stereo) @@ -112,37 +107,35 @@ namespace gtsam * @param initialEstimate * @return graph and initial values */ - template - std::pair triangulationGraph( - const CameraSet &cameras, - const typename CAMERA::MeasurementVector &measurements, Key landmarkKey, - const Point3 &initialEstimate) - { - Values values; - values.insert(landmarkKey, initialEstimate); // Initial landmark value - NonlinearFactorGraph graph; - static SharedNoiseModel unit(noiseModel::Unit::Create( - traits::dimension)); - for (size_t i = 0; i < measurements.size(); i++) - { - const CAMERA &camera_i = cameras[i]; - graph.emplace_shared> // - (camera_i, measurements[i], unit, landmarkKey); - } - return std::make_pair(graph, values); +template +std::pair triangulationGraph( + const CameraSet& cameras, + const typename CAMERA::MeasurementVector& measurements, Key landmarkKey, + const Point3& initialEstimate) { + Values values; + values.insert(landmarkKey, initialEstimate); // Initial landmark value + NonlinearFactorGraph graph; + static SharedNoiseModel unit(noiseModel::Unit::Create( + traits::dimension)); + for (size_t i = 0; i < measurements.size(); i++) { + const CAMERA& camera_i = cameras[i]; + graph.emplace_shared > // + (camera_i, measurements[i], unit, landmarkKey); } + return std::make_pair(graph, values); +} - /** +/** * Optimize for triangulation * @param graph nonlinear factors for projection * @param values initial values * @param landmarkKey to refer to landmark * @return refined Point3 */ - GTSAM_EXPORT Point3 optimize(const NonlinearFactorGraph &graph, - const Values &values, Key landmarkKey); +GTSAM_EXPORT Point3 optimize(const NonlinearFactorGraph& graph, + const Values& values, Key landmarkKey); - /** +/** * Given an initial estimate , refine a point using measurements in several cameras * @param poses Camera poses * @param sharedCal shared pointer to single calibration object @@ -150,69 +143,63 @@ namespace gtsam * @param initialEstimate * @return refined Point3 */ - template - Point3 triangulateNonlinear(const std::vector &poses, - boost::shared_ptr sharedCal, - const Point2Vector &measurements, const Point3 &initialEstimate) - { +template +Point3 triangulateNonlinear(const std::vector& poses, + boost::shared_ptr sharedCal, + const Point2Vector& measurements, const Point3& initialEstimate) { - // Create a factor graph and initial values - Values values; - NonlinearFactorGraph graph; - boost::tie(graph, values) = triangulationGraph // - (poses, sharedCal, measurements, Symbol('p', 0), initialEstimate); + // Create a factor graph and initial values + Values values; + NonlinearFactorGraph graph; + boost::tie(graph, values) = triangulationGraph // + (poses, sharedCal, measurements, Symbol('p', 0), initialEstimate); - return optimize(graph, values, Symbol('p', 0)); - } + return optimize(graph, values, Symbol('p', 0)); +} - /** +/** * Given an initial estimate , refine a point using measurements in several cameras * @param cameras pinhole cameras (monocular or stereo) * @param measurements 2D measurements * @param initialEstimate * @return refined Point3 */ - template - Point3 triangulateNonlinear( - const CameraSet &cameras, - const typename CAMERA::MeasurementVector &measurements, const Point3 &initialEstimate) - { +template +Point3 triangulateNonlinear( + const CameraSet& cameras, + const typename CAMERA::MeasurementVector& measurements, const Point3& initialEstimate) { - // Create a factor graph and initial values - Values values; - NonlinearFactorGraph graph; - boost::tie(graph, values) = triangulationGraph // - (cameras, measurements, Symbol('p', 0), initialEstimate); + // Create a factor graph and initial values + Values values; + NonlinearFactorGraph graph; + boost::tie(graph, values) = triangulationGraph // + (cameras, measurements, Symbol('p', 0), initialEstimate); - return optimize(graph, values, Symbol('p', 0)); - } + return optimize(graph, values, Symbol('p', 0)); +} - /** +/** * Create a 3*4 camera projection matrix from calibration and pose. * Functor for partial application on calibration * @param pose The camera pose * @param cal The calibration * @return Returns a Matrix34 */ - template - struct CameraProjectionMatrix - { - CameraProjectionMatrix(const CALIBRATION &calibration) : K_(calibration.K()) - { - } - Matrix34 operator()(const Pose3 &pose) const - { - return K_ * (pose.inverse().matrix()).block<3, 4>(0, 0); - } +template +struct CameraProjectionMatrix { + CameraProjectionMatrix(const CALIBRATION& calibration) : + K_(calibration.K()) { + } + Matrix34 operator()(const Pose3& pose) const { + return K_ * (pose.inverse().matrix()).block<3, 4>(0, 0); + } +private: + const Matrix3 K_; +public: + GTSAM_MAKE_ALIGNED_OPERATOR_NEW +}; - private: - const Matrix3 K_; - - public: - GTSAM_MAKE_ALIGNED_OPERATOR_NEW - }; - - /** +/** * Function to triangulate 3D landmark point from an arbitrary number * of poses (at least 2) using the DLT. The function checks that the * resulting point lies in front of all cameras, but has no other checks @@ -224,45 +211,43 @@ namespace gtsam * @param optimize Flag to turn on nonlinear refinement of triangulation * @return Returns a Point3 */ - template - Point3 triangulatePoint3(const std::vector &poses, - boost::shared_ptr sharedCal, - const Point2Vector &measurements, double rank_tol = 1e-9, - bool optimize = false) - { +template +Point3 triangulatePoint3(const std::vector& poses, + boost::shared_ptr sharedCal, + const Point2Vector& measurements, double rank_tol = 1e-9, + bool optimize = false) { - assert(poses.size() == measurements.size()); - if (poses.size() < 2) - throw(TriangulationUnderconstrainedException()); + assert(poses.size() == measurements.size()); + if (poses.size() < 2) + throw(TriangulationUnderconstrainedException()); - // construct projection matrices from poses & calibration - std::vector> projection_matrices; - CameraProjectionMatrix createP(*sharedCal); // partially apply - for (const Pose3 &pose : poses) - projection_matrices.push_back(createP(pose)); + // construct projection matrices from poses & calibration + std::vector> projection_matrices; + CameraProjectionMatrix createP(*sharedCal); // partially apply + for(const Pose3& pose: poses) + projection_matrices.push_back(createP(pose)); - // Triangulate linearly - Point3 point = triangulateDLT(projection_matrices, measurements, rank_tol); + // Triangulate linearly + Point3 point = triangulateDLT(projection_matrices, measurements, rank_tol); - // Then refine using non-linear optimization - if (optimize) - point = triangulateNonlinear // - (poses, sharedCal, measurements, point); + // Then refine using non-linear optimization + if (optimize) + point = triangulateNonlinear // + (poses, sharedCal, measurements, point); #ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION - // verify that the triangulated point lies in front of all cameras - for (const Pose3 &pose : poses) - { - const Point3 &p_local = pose.transformTo(point); - if (p_local.z() <= 0) - throw(TriangulationCheiralityException()); - } + // verify that the triangulated point lies in front of all cameras + for(const Pose3& pose: poses) { + const Point3& p_local = pose.transformTo(point); + if (p_local.z() <= 0) + throw(TriangulationCheiralityException()); + } #endif - return point; - } + return point; +} - /** +/** * Function to triangulate 3D landmark point from an arbitrary number * of poses (at least 2) using the DLT. This function is similar to the one * above, except that each camera has its own calibration. The function @@ -274,76 +259,72 @@ namespace gtsam * @param optimize Flag to turn on nonlinear refinement of triangulation * @return Returns a Point3 */ - template - Point3 triangulatePoint3( - const CameraSet &cameras, - const typename CAMERA::MeasurementVector &measurements, double rank_tol = 1e-9, - bool optimize = false) - { +template +Point3 triangulatePoint3( + const CameraSet& cameras, + const typename CAMERA::MeasurementVector& measurements, double rank_tol = 1e-9, + bool optimize = false) { - size_t m = cameras.size(); - assert(measurements.size() == m); + size_t m = cameras.size(); + assert(measurements.size() == m); - if (m < 2) - throw(TriangulationUnderconstrainedException()); + if (m < 2) + throw(TriangulationUnderconstrainedException()); - // construct projection matrices from poses & calibration - std::vector> projection_matrices; - for (const CAMERA &camera : cameras) - projection_matrices.push_back( - CameraProjectionMatrix(camera.calibration())( - camera.pose())); - Point3 point = triangulateDLT(projection_matrices, measurements, rank_tol); + // construct projection matrices from poses & calibration + std::vector> projection_matrices; + for(const CAMERA& camera: cameras) + projection_matrices.push_back( + CameraProjectionMatrix(camera.calibration())( + camera.pose())); + Point3 point = triangulateDLT(projection_matrices, measurements, rank_tol); - // The n refine using non-linear optimization - if (optimize) - point = triangulateNonlinear(cameras, measurements, point); + // The n refine using non-linear optimization + if (optimize) + point = triangulateNonlinear(cameras, measurements, point); #ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION - // verify that the triangulated point lies in front of all cameras - for (const CAMERA &camera : cameras) - { - const Point3 &p_local = camera.pose().transformTo(point); - if (p_local.z() <= 0) - throw(TriangulationCheiralityException()); - } + // verify that the triangulated point lies in front of all cameras + for(const CAMERA& camera: cameras) { + const Point3& p_local = camera.pose().transformTo(point); + if (p_local.z() <= 0) + throw(TriangulationCheiralityException()); + } #endif - return point; - } + return point; +} - /// Pinhole-specific version - template - Point3 triangulatePoint3( - const CameraSet> &cameras, - const Point2Vector &measurements, double rank_tol = 1e-9, - bool optimize = false) - { - return triangulatePoint3> // - (cameras, measurements, rank_tol, optimize); - } +/// Pinhole-specific version +template +Point3 triangulatePoint3( + const CameraSet >& cameras, + const Point2Vector& measurements, double rank_tol = 1e-9, + bool optimize = false) { + return triangulatePoint3 > // + (cameras, measurements, rank_tol, optimize); +} - struct GTSAM_EXPORT TriangulationParameters - { +struct GTSAM_EXPORT TriangulationParameters { - double rankTolerance; ///< threshold to decide whether triangulation is result.degenerate - ///< (the rank is the number of singular values of the triangulation matrix which are larger than rankTolerance) - bool enableEPI; ///< if set to true, will refine triangulation using LM + double rankTolerance; ///< threshold to decide whether triangulation is result.degenerate + ///< (the rank is the number of singular values of the triangulation matrix which are larger than rankTolerance) + bool enableEPI; ///< if set to true, will refine triangulation using LM - /** + /** * if the landmark is triangulated at distance larger than this, * result is flagged as degenerate. */ - double landmarkDistanceThreshold; // + double landmarkDistanceThreshold; // - /** + /** * If this is nonnegative the we will check if the average reprojection error * is smaller than this threshold after triangulation, otherwise result is * flagged as degenerate. */ - double dynamicOutlierRejectionThreshold; + double dynamicOutlierRejectionThreshold; - /** + /** * Constructor * @param rankTol tolerance used to check if point triangulation is degenerate * @param enableEPI if true refine triangulation with embedded LM iterations @@ -351,194 +332,173 @@ namespace gtsam * @param dynamicOutlierRejectionThreshold or if average error larger than this * */ - TriangulationParameters(const double _rankTolerance = 1.0, - const bool _enableEPI = false, double _landmarkDistanceThreshold = -1, - double _dynamicOutlierRejectionThreshold = -1) : rankTolerance(_rankTolerance), enableEPI(_enableEPI), // - landmarkDistanceThreshold(_landmarkDistanceThreshold), // - dynamicOutlierRejectionThreshold(_dynamicOutlierRejectionThreshold) - { - } - - // stream to output - friend std::ostream &operator<<(std::ostream &os, - const TriangulationParameters &p) - { - os << "rankTolerance = " << p.rankTolerance << std::endl; - os << "enableEPI = " << p.enableEPI << std::endl; - os << "landmarkDistanceThreshold = " << p.landmarkDistanceThreshold - << std::endl; - os << "dynamicOutlierRejectionThreshold = " - << p.dynamicOutlierRejectionThreshold << std::endl; - return os; - } - - private: - /// Serialization function - friend class boost::serialization::access; - template - void serialize(ARCHIVE &ar, const unsigned int version) - { - ar &BOOST_SERIALIZATION_NVP(rankTolerance); - ar &BOOST_SERIALIZATION_NVP(enableEPI); - ar &BOOST_SERIALIZATION_NVP(landmarkDistanceThreshold); - ar &BOOST_SERIALIZATION_NVP(dynamicOutlierRejectionThreshold); - } - }; - - /** - * TriangulationResult is an optional point, along with the reasons why it is invalid. - */ - class TriangulationResult : public boost::optional - { - enum Status - { - VALID, - DEGENERATE, - BEHIND_CAMERA, - OUTLIER, - FAR_POINT - }; - Status status_; - TriangulationResult(Status s) : status_(s) - { - } - - public: - /** - * Default constructor, only for serialization - */ - TriangulationResult() {} - - /** - * Constructor - */ - TriangulationResult(const Point3 &p) : status_(VALID) - { - reset(p); - } - static TriangulationResult Degenerate() - { - return TriangulationResult(DEGENERATE); - } - static TriangulationResult Outlier() - { - return TriangulationResult(OUTLIER); - } - static TriangulationResult FarPoint() - { - return TriangulationResult(FAR_POINT); - } - static TriangulationResult BehindCamera() - { - return TriangulationResult(BEHIND_CAMERA); - } - bool valid() const - { - return status_ == VALID; - } - bool degenerate() const - { - return status_ == DEGENERATE; - } - bool outlier() const - { - return status_ == OUTLIER; - } - bool farPoint() const - { - return status_ == FAR_POINT; - } - bool behindCamera() const - { - return status_ == BEHIND_CAMERA; - } - // stream to output - friend std::ostream &operator<<(std::ostream &os, - const TriangulationResult &result) - { - if (result) - os << "point = " << *result << std::endl; - else - os << "no point, status = " << result.status_ << std::endl; - return os; - } - - private: - /// Serialization function - friend class boost::serialization::access; - template - void serialize(ARCHIVE &ar, const unsigned int version) - { - ar &BOOST_SERIALIZATION_NVP(status_); - } - }; - - /// triangulateSafe: extensive checking of the outcome - template - TriangulationResult triangulateSafe(const CameraSet &cameras, - const typename CAMERA::MeasurementVector &measured, - const TriangulationParameters ¶ms) - { - - size_t m = cameras.size(); - - // if we have a single pose the corresponding factor is uninformative - if (m < 2) - return TriangulationResult::Degenerate(); - else - // We triangulate the 3D position of the landmark - try - { - Point3 point = triangulatePoint3(cameras, measured, - params.rankTolerance, params.enableEPI); - - // Check landmark distance and re-projection errors to avoid outliers - size_t i = 0; - double maxReprojError = 0.0; - for (const CAMERA &camera : cameras) - { - const Pose3 &pose = camera.pose(); - if (params.landmarkDistanceThreshold > 0 && distance3(pose.translation(), point) > params.landmarkDistanceThreshold) - return TriangulationResult::FarPoint(); -#ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION - // verify that the triangulated point lies in front of all cameras - // Only needed if this was not yet handled by exception - const Point3 &p_local = pose.transformTo(point); - if (p_local.z() <= 0) - return TriangulationResult::BehindCamera(); -#endif - // Check reprojection error - if (params.dynamicOutlierRejectionThreshold > 0) - { - const Point2 &zi = measured.at(i); - Point2 reprojectionError(camera.project(point) - zi); - maxReprojError = std::max(maxReprojError, reprojectionError.norm()); - } - i += 1; - } - // Flag as degenerate if average reprojection error is too large - if (params.dynamicOutlierRejectionThreshold > 0 && maxReprojError > params.dynamicOutlierRejectionThreshold) - return TriangulationResult::Outlier(); - - // all good! - return TriangulationResult(point); - } - catch (TriangulationUnderconstrainedException &) - { - // This exception is thrown if - // 1) There is a single pose for triangulation - this should not happen because we checked the number of poses before - // 2) The rank of the matrix used for triangulation is < 3: rotation-only, parallel cameras (or motion towards the landmark) - return TriangulationResult::Degenerate(); - } - catch (TriangulationCheiralityException &) - { - // point is behind one of the cameras: can be the case of close-to-parallel cameras or may depend on outliers - return TriangulationResult::BehindCamera(); - } + TriangulationParameters(const double _rankTolerance = 1.0, + const bool _enableEPI = false, double _landmarkDistanceThreshold = -1, + double _dynamicOutlierRejectionThreshold = -1) : + rankTolerance(_rankTolerance), enableEPI(_enableEPI), // + landmarkDistanceThreshold(_landmarkDistanceThreshold), // + dynamicOutlierRejectionThreshold(_dynamicOutlierRejectionThreshold) { } - // Vector of Cameras - used by the Python/MATLAB wrapper - using CameraSetCal3Bundler = CameraSet>; - using CameraSetCal3_S2 = CameraSet>; + // stream to output + friend std::ostream &operator<<(std::ostream &os, + const TriangulationParameters& p) { + os << "rankTolerance = " << p.rankTolerance << std::endl; + os << "enableEPI = " << p.enableEPI << std::endl; + os << "landmarkDistanceThreshold = " << p.landmarkDistanceThreshold + << std::endl; + os << "dynamicOutlierRejectionThreshold = " + << p.dynamicOutlierRejectionThreshold << std::endl; + return os; + } + +private: + + /// Serialization function + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(rankTolerance); + ar & BOOST_SERIALIZATION_NVP(enableEPI); + ar & BOOST_SERIALIZATION_NVP(landmarkDistanceThreshold); + ar & BOOST_SERIALIZATION_NVP(dynamicOutlierRejectionThreshold); + } +}; + +/** + * TriangulationResult is an optional point, along with the reasons why it is invalid. + */ +class TriangulationResult: public boost::optional { + enum Status { + VALID, DEGENERATE, BEHIND_CAMERA, OUTLIER, FAR_POINT + }; + Status status_; + TriangulationResult(Status s) : + status_(s) { + } +public: + + /** + * Default constructor, only for serialization + */ + TriangulationResult() {} + + /** + * Constructor + */ + TriangulationResult(const Point3& p) : + status_(VALID) { + reset(p); + } + static TriangulationResult Degenerate() { + return TriangulationResult(DEGENERATE); + } + static TriangulationResult Outlier() { + return TriangulationResult(OUTLIER); + } + static TriangulationResult FarPoint() { + return TriangulationResult(FAR_POINT); + } + static TriangulationResult BehindCamera() { + return TriangulationResult(BEHIND_CAMERA); + } + bool valid() const { + return status_ == VALID; + } + bool degenerate() const { + return status_ == DEGENERATE; + } + bool outlier() const { + return status_ == OUTLIER; + } + bool farPoint() const { + return status_ == FAR_POINT; + } + bool behindCamera() const { + return status_ == BEHIND_CAMERA; + } + // stream to output + friend std::ostream &operator<<(std::ostream &os, + const TriangulationResult& result) { + if (result) + os << "point = " << *result << std::endl; + else + os << "no point, status = " << result.status_ << std::endl; + return os; + } + +private: + + /// Serialization function + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int version) { + ar & BOOST_SERIALIZATION_NVP(status_); + } +}; + +/// triangulateSafe: extensive checking of the outcome +template +TriangulationResult triangulateSafe(const CameraSet& cameras, + const typename CAMERA::MeasurementVector& measured, + const TriangulationParameters& params) { + + size_t m = cameras.size(); + + // if we have a single pose the corresponding factor is uninformative + if (m < 2) + return TriangulationResult::Degenerate(); + else + // We triangulate the 3D position of the landmark + try { + Point3 point = triangulatePoint3(cameras, measured, + params.rankTolerance, params.enableEPI); + + // Check landmark distance and re-projection errors to avoid outliers + size_t i = 0; + double maxReprojError = 0.0; + for(const CAMERA& camera: cameras) { + const Pose3& pose = camera.pose(); + if (params.landmarkDistanceThreshold > 0 + && distance3(pose.translation(), point) + > params.landmarkDistanceThreshold) + return TriangulationResult::FarPoint(); +#ifdef GTSAM_THROW_CHEIRALITY_EXCEPTION + // verify that the triangulated point lies in front of all cameras + // Only needed if this was not yet handled by exception + const Point3& p_local = pose.transformTo(point); + if (p_local.z() <= 0) + return TriangulationResult::BehindCamera(); +#endif + // Check reprojection error + if (params.dynamicOutlierRejectionThreshold > 0) { + const Point2& zi = measured.at(i); + Point2 reprojectionError(camera.project(point) - zi); + maxReprojError = std::max(maxReprojError, reprojectionError.norm()); + } + i += 1; + } + // Flag as degenerate if average reprojection error is too large + if (params.dynamicOutlierRejectionThreshold > 0 + && maxReprojError > params.dynamicOutlierRejectionThreshold) + return TriangulationResult::Outlier(); + + // all good! + return TriangulationResult(point); + } catch (TriangulationUnderconstrainedException&) { + // This exception is thrown if + // 1) There is a single pose for triangulation - this should not happen because we checked the number of poses before + // 2) The rank of the matrix used for triangulation is < 3: rotation-only, parallel cameras (or motion towards the landmark) + return TriangulationResult::Degenerate(); + } catch (TriangulationCheiralityException&) { + // point is behind one of the cameras: can be the case of close-to-parallel cameras or may depend on outliers + return TriangulationResult::BehindCamera(); + } +} + +// Vector of Cameras - used by the Python/MATLAB wrapper +using CameraSetCal3Bundler = CameraSet>; +using CameraSetCal3_S2 = CameraSet>; + +} // \namespace gtsam -} // namespace gtsam diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index b33e7ad6e..64e57a1d5 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -118,735 +118,708 @@ * - TODO: Add generalized serialization support via boost.serialization with hooks to matlab save/load */ -namespace gtsam -{ +namespace gtsam { // Actually a FastList #include - class KeyList - { - KeyList(); - KeyList(const gtsam::KeyList &other); +class KeyList { + KeyList(); + KeyList(const gtsam::KeyList& other); - // Note: no print function + // Note: no print function - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - size_t front() const; - size_t back() const; - void push_back(size_t key); - void push_front(size_t key); - void pop_back(); - void pop_front(); - void sort(); - void remove(size_t key); + // structure specific methods + size_t front() const; + size_t back() const; + void push_back(size_t key); + void push_front(size_t key); + void pop_back(); + void pop_front(); + void sort(); + void remove(size_t key); - void serialize() const; - }; + void serialize() const; +}; - // Actually a FastSet - class KeySet - { - KeySet(); - KeySet(const gtsam::KeySet &set); - KeySet(const gtsam::KeyVector &vector); - KeySet(const gtsam::KeyList &list); +// Actually a FastSet +class KeySet { + KeySet(); + KeySet(const gtsam::KeySet& set); + KeySet(const gtsam::KeyVector& vector); + KeySet(const gtsam::KeyList& list); - // Testable - void print(string s) const; - bool equals(const gtsam::KeySet &other) const; + // Testable + void print(string s) const; + bool equals(const gtsam::KeySet& other) const; - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - void insert(size_t key); - void merge(const gtsam::KeySet &other); - bool erase(size_t key); // returns true if value was removed - bool count(size_t key) const; // returns true if value exists + // structure specific methods + void insert(size_t key); + void merge(const gtsam::KeySet& other); + bool erase(size_t key); // returns true if value was removed + bool count(size_t key) const; // returns true if value exists - void serialize() const; - }; + void serialize() const; +}; - // Actually a vector - class KeyVector - { - KeyVector(); - KeyVector(const gtsam::KeyVector &other); +// Actually a vector +class KeyVector { + KeyVector(); + KeyVector(const gtsam::KeyVector& other); - // Note: no print function + // Note: no print function - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - size_t at(size_t i) const; - size_t front() const; - size_t back() const; - void push_back(size_t key) const; + // structure specific methods + size_t at(size_t i) const; + size_t front() const; + size_t back() const; + void push_back(size_t key) const; - void serialize() const; - }; + void serialize() const; +}; - // Actually a FastMap - class KeyGroupMap - { - KeyGroupMap(); +// Actually a FastMap +class KeyGroupMap { + KeyGroupMap(); - // Note: no print function + // Note: no print function - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - size_t at(size_t key) const; - int erase(size_t key); - bool insert2(size_t key, int val); - }; + // structure specific methods + size_t at(size_t key) const; + int erase(size_t key); + bool insert2(size_t key, int val); +}; - // Actually a FastSet - class FactorIndexSet - { - FactorIndexSet(); - FactorIndexSet(const gtsam::FactorIndexSet &set); +// Actually a FastSet +class FactorIndexSet { + FactorIndexSet(); + FactorIndexSet(const gtsam::FactorIndexSet& set); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - void insert(size_t factorIndex); - bool erase(size_t factorIndex); // returns true if value was removed - bool count(size_t factorIndex) const; // returns true if value exists - }; + // structure specific methods + void insert(size_t factorIndex); + bool erase(size_t factorIndex); // returns true if value was removed + bool count(size_t factorIndex) const; // returns true if value exists +}; - // Actually a vector - class FactorIndices - { - FactorIndices(); - FactorIndices(const gtsam::FactorIndices &other); +// Actually a vector +class FactorIndices { + FactorIndices(); + FactorIndices(const gtsam::FactorIndices& other); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - size_t at(size_t i) const; - size_t front() const; - size_t back() const; - void push_back(size_t factorIndex) const; - }; + // structure specific methods + size_t at(size_t i) const; + size_t front() const; + size_t back() const; + void push_back(size_t factorIndex) const; +}; - //************************************************************************* - // base - //************************************************************************* +//************************************************************************* +// base +//************************************************************************* - /** gtsam namespace functions */ +/** gtsam namespace functions */ #include - bool isDebugVersion(); +bool isDebugVersion(); #include - class IndexPair - { - IndexPair(); - IndexPair(size_t i, size_t j); - size_t i() const; - size_t j() const; - }; +class IndexPair { + IndexPair(); + IndexPair(size_t i, size_t j); + size_t i() const; + size_t j() const; +}; - // template - // class DSFMap { - // DSFMap(); - // KEY find(const KEY& key) const; - // void merge(const KEY& x, const KEY& y); - // std::map sets(); - // }; +// template +// class DSFMap { +// DSFMap(); +// KEY find(const KEY& key) const; +// void merge(const KEY& x, const KEY& y); +// std::map sets(); +// }; - class IndexPairSet - { - IndexPairSet(); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); +class IndexPairSet { + IndexPairSet(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - void insert(gtsam::IndexPair key); - bool erase(gtsam::IndexPair key); // returns true if value was removed - bool count(gtsam::IndexPair key) const; // returns true if value exists - }; + // structure specific methods + void insert(gtsam::IndexPair key); + bool erase(gtsam::IndexPair key); // returns true if value was removed + bool count(gtsam::IndexPair key) const; // returns true if value exists +}; - class IndexPairVector - { - IndexPairVector(); - IndexPairVector(const gtsam::IndexPairVector &other); +class IndexPairVector { + IndexPairVector(); + IndexPairVector(const gtsam::IndexPairVector& other); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - gtsam::IndexPair at(size_t i) const; - void push_back(gtsam::IndexPair key) const; - }; + // structure specific methods + gtsam::IndexPair at(size_t i) const; + void push_back(gtsam::IndexPair key) const; +}; - gtsam::IndexPairVector IndexPairSetAsArray(gtsam::IndexPairSet &set); +gtsam::IndexPairVector IndexPairSetAsArray(gtsam::IndexPairSet& set); - class IndexPairSetMap - { - IndexPairSetMap(); - // common STL methods - size_t size() const; - bool empty() const; - void clear(); +class IndexPairSetMap { + IndexPairSetMap(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - gtsam::IndexPairSet at(gtsam::IndexPair &key); - }; + // structure specific methods + gtsam::IndexPairSet at(gtsam::IndexPair& key); +}; - class DSFMapIndexPair - { - DSFMapIndexPair(); - gtsam::IndexPair find(const gtsam::IndexPair &key) const; - void merge(const gtsam::IndexPair &x, const gtsam::IndexPair &y); - gtsam::IndexPairSetMap sets(); - }; +class DSFMapIndexPair { + DSFMapIndexPair(); + gtsam::IndexPair find(const gtsam::IndexPair& key) const; + void merge(const gtsam::IndexPair& x, const gtsam::IndexPair& y); + gtsam::IndexPairSetMap sets(); +}; #include - bool linear_independent(Matrix A, Matrix B, double tol); +bool linear_independent(Matrix A, Matrix B, double tol); #include - virtual class Value - { - // No constructors because this is an abstract class +virtual class Value { + // No constructors because this is an abstract class - // Testable - void print(string s) const; + // Testable + void print(string s) const; - // Manifold - size_t dim() const; - }; + // Manifold + size_t dim() const; +}; #include - template - virtual class GenericValue : gtsam::Value - { - void serializable() const; - }; +template +virtual class GenericValue : gtsam::Value { + void serializable() const; +}; - //************************************************************************* - // geometry - //************************************************************************* +//************************************************************************* +// geometry +//************************************************************************* #include - class Point2 - { - // Standard Constructors - Point2(); - Point2(double x, double y); - Point2(Vector v); +class Point2 { + // Standard Constructors + Point2(); + Point2(double x, double y); + Point2(Vector v); - // Testable - void print(string s) const; - bool equals(const gtsam::Point2 &point, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Point2& point, double tol) const; - // Group - static gtsam::Point2 identity(); + // Group + static gtsam::Point2 identity(); - // Standard Interface - double x() const; - double y() const; - Vector vector() const; - double distance(const gtsam::Point2 &p2) const; - double norm() const; + // Standard Interface + double x() const; + double y() const; + Vector vector() const; + double distance(const gtsam::Point2& p2) const; + double norm() const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; // std::vector #include - class Point2Vector - { - // Constructors - Point2Vector(); - Point2Vector(const gtsam::Point2Vector &v); +class Point2Vector +{ + // Constructors + Point2Vector(); + Point2Vector(const gtsam::Point2Vector& v); - //Capacity - size_t size() const; - size_t max_size() const; - void resize(size_t sz); - size_t capacity() const; - bool empty() const; - void reserve(size_t n); + //Capacity + size_t size() const; + size_t max_size() const; + void resize(size_t sz); + size_t capacity() const; + bool empty() const; + void reserve(size_t n); - //Element access - gtsam::Point2 at(size_t n) const; - gtsam::Point2 front() const; - gtsam::Point2 back() const; + //Element access + gtsam::Point2 at(size_t n) const; + gtsam::Point2 front() const; + gtsam::Point2 back() const; - //Modifiers - void assign(size_t n, const gtsam::Point2 &u); - void push_back(const gtsam::Point2 &x); - void pop_back(); - }; + //Modifiers + void assign(size_t n, const gtsam::Point2& u); + void push_back(const gtsam::Point2& x); + void pop_back(); +}; #include - class StereoPoint2 - { - // Standard Constructors - StereoPoint2(); - StereoPoint2(double uL, double uR, double v); +class StereoPoint2 { + // Standard Constructors + StereoPoint2(); + StereoPoint2(double uL, double uR, double v); - // Testable - void print(string s) const; - bool equals(const gtsam::StereoPoint2 &point, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::StereoPoint2& point, double tol) const; - // Group - static gtsam::StereoPoint2 identity(); - gtsam::StereoPoint2 inverse() const; - gtsam::StereoPoint2 compose(const gtsam::StereoPoint2 &p2) const; - gtsam::StereoPoint2 between(const gtsam::StereoPoint2 &p2) const; + // Group + static gtsam::StereoPoint2 identity(); + gtsam::StereoPoint2 inverse() const; + gtsam::StereoPoint2 compose(const gtsam::StereoPoint2& p2) const; + gtsam::StereoPoint2 between(const gtsam::StereoPoint2& p2) const; - // Manifold - gtsam::StereoPoint2 retract(Vector v) const; - Vector localCoordinates(const gtsam::StereoPoint2 &p) const; + // Manifold + gtsam::StereoPoint2 retract(Vector v) const; + Vector localCoordinates(const gtsam::StereoPoint2& p) const; - // Lie Group - static gtsam::StereoPoint2 Expmap(Vector v); - static Vector Logmap(const gtsam::StereoPoint2 &p); + // Lie Group + static gtsam::StereoPoint2 Expmap(Vector v); + static Vector Logmap(const gtsam::StereoPoint2& p); - // Standard Interface - Vector vector() const; - double uL() const; - double uR() const; - double v() const; + // Standard Interface + Vector vector() const; + double uL() const; + double uR() const; + double v() const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - class Point3 - { - // Standard Constructors - Point3(); - Point3(double x, double y, double z); - Point3(Vector v); +class Point3 { + // Standard Constructors + Point3(); + Point3(double x, double y, double z); + Point3(Vector v); - // Testable - void print(string s) const; - bool equals(const gtsam::Point3 &p, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Point3& p, double tol) const; - // Group - static gtsam::Point3 identity(); + // Group + static gtsam::Point3 identity(); - // Standard Interface - Vector vector() const; - double x() const; - double y() const; - double z() const; + // Standard Interface + Vector vector() const; + double x() const; + double y() const; + double z() const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - class Rot2 - { - // Standard Constructors and Named Constructors - Rot2(); - Rot2(double theta); - static gtsam::Rot2 fromAngle(double theta); - static gtsam::Rot2 fromDegrees(double theta); - static gtsam::Rot2 fromCosSin(double c, double s); +class Rot2 { + // Standard Constructors and Named Constructors + Rot2(); + Rot2(double theta); + static gtsam::Rot2 fromAngle(double theta); + static gtsam::Rot2 fromDegrees(double theta); + static gtsam::Rot2 fromCosSin(double c, double s); - // Testable - void print(string s) const; - bool equals(const gtsam::Rot2 &rot, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Rot2& rot, double tol) const; - // Group - static gtsam::Rot2 identity(); - gtsam::Rot2 inverse(); - gtsam::Rot2 compose(const gtsam::Rot2 &p2) const; - gtsam::Rot2 between(const gtsam::Rot2 &p2) const; + // Group + static gtsam::Rot2 identity(); + gtsam::Rot2 inverse(); + gtsam::Rot2 compose(const gtsam::Rot2& p2) const; + gtsam::Rot2 between(const gtsam::Rot2& p2) const; - // Manifold - gtsam::Rot2 retract(Vector v) const; - Vector localCoordinates(const gtsam::Rot2 &p) const; + // Manifold + gtsam::Rot2 retract(Vector v) const; + Vector localCoordinates(const gtsam::Rot2& p) const; - // Lie Group - static gtsam::Rot2 Expmap(Vector v); - static Vector Logmap(const gtsam::Rot2 &p); - Vector logmap(const gtsam::Rot2 &p); + // Lie Group + static gtsam::Rot2 Expmap(Vector v); + static Vector Logmap(const gtsam::Rot2& p); + Vector logmap(const gtsam::Rot2& p); - // Group Action on Point2 - gtsam::Point2 rotate(const gtsam::Point2 &point) const; - gtsam::Point2 unrotate(const gtsam::Point2 &point) const; + // Group Action on Point2 + gtsam::Point2 rotate(const gtsam::Point2& point) const; + gtsam::Point2 unrotate(const gtsam::Point2& point) const; - // Standard Interface - static gtsam::Rot2 relativeBearing(const gtsam::Point2 &d); // Ignoring derivative - static gtsam::Rot2 atan2(double y, double x); - double theta() const; - double degrees() const; - double c() const; - double s() const; - Matrix matrix() const; + // Standard Interface + static gtsam::Rot2 relativeBearing(const gtsam::Point2& d); // Ignoring derivative + static gtsam::Rot2 atan2(double y, double x); + double theta() const; + double degrees() const; + double c() const; + double s() const; + Matrix matrix() const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - class SO3 - { - // Standard Constructors - SO3(); - SO3(Matrix R); - static gtsam::SO3 FromMatrix(Matrix R); - static gtsam::SO3 AxisAngle(const Vector axis, double theta); - static gtsam::SO3 ClosestTo(const Matrix M); +class SO3 { + // Standard Constructors + SO3(); + SO3(Matrix R); + static gtsam::SO3 FromMatrix(Matrix R); + static gtsam::SO3 AxisAngle(const Vector axis, double theta); + static gtsam::SO3 ClosestTo(const Matrix M); - // Testable - void print(string s) const; - bool equals(const gtsam::SO3 &other, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::SO3& other, double tol) const; - // Group - static gtsam::SO3 identity(); - gtsam::SO3 inverse() const; - gtsam::SO3 between(const gtsam::SO3 &R) const; - gtsam::SO3 compose(const gtsam::SO3 &R) const; + // Group + static gtsam::SO3 identity(); + gtsam::SO3 inverse() const; + gtsam::SO3 between(const gtsam::SO3& R) const; + gtsam::SO3 compose(const gtsam::SO3& R) const; - // Manifold - gtsam::SO3 retract(Vector v) const; - Vector localCoordinates(const gtsam::SO3 &R) const; - static gtsam::SO3 Expmap(Vector v); + // Manifold + gtsam::SO3 retract(Vector v) const; + Vector localCoordinates(const gtsam::SO3& R) const; + static gtsam::SO3 Expmap(Vector v); - // Other methods - Vector vec() const; - Matrix matrix() const; - }; + // Other methods + Vector vec() const; + Matrix matrix() const; +}; #include - class SO4 - { - // Standard Constructors - SO4(); - SO4(Matrix R); - static gtsam::SO4 FromMatrix(Matrix R); +class SO4 { + // Standard Constructors + SO4(); + SO4(Matrix R); + static gtsam::SO4 FromMatrix(Matrix R); - // Testable - void print(string s) const; - bool equals(const gtsam::SO4 &other, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::SO4& other, double tol) const; - // Group - static gtsam::SO4 identity(); - gtsam::SO4 inverse() const; - gtsam::SO4 between(const gtsam::SO4 &Q) const; - gtsam::SO4 compose(const gtsam::SO4 &Q) const; + // Group + static gtsam::SO4 identity(); + gtsam::SO4 inverse() const; + gtsam::SO4 between(const gtsam::SO4& Q) const; + gtsam::SO4 compose(const gtsam::SO4& Q) const; - // Manifold - gtsam::SO4 retract(Vector v) const; - Vector localCoordinates(const gtsam::SO4 &Q) const; - static gtsam::SO4 Expmap(Vector v); + // Manifold + gtsam::SO4 retract(Vector v) const; + Vector localCoordinates(const gtsam::SO4& Q) const; + static gtsam::SO4 Expmap(Vector v); - // Other methods - Vector vec() const; - Matrix matrix() const; - }; + // Other methods + Vector vec() const; + Matrix matrix() const; +}; #include - class SOn - { - // Standard Constructors - SOn(size_t n); - static gtsam::SOn FromMatrix(Matrix R); - static gtsam::SOn Lift(size_t n, Matrix R); +class SOn { + // Standard Constructors + SOn(size_t n); + static gtsam::SOn FromMatrix(Matrix R); + static gtsam::SOn Lift(size_t n, Matrix R); - // Testable - void print(string s) const; - bool equals(const gtsam::SOn &other, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::SOn& other, double tol) const; - // Group - static gtsam::SOn identity(); - gtsam::SOn inverse() const; - gtsam::SOn between(const gtsam::SOn &Q) const; - gtsam::SOn compose(const gtsam::SOn &Q) const; + // Group + static gtsam::SOn identity(); + gtsam::SOn inverse() const; + gtsam::SOn between(const gtsam::SOn& Q) const; + gtsam::SOn compose(const gtsam::SOn& Q) const; - // Manifold - gtsam::SOn retract(Vector v) const; - Vector localCoordinates(const gtsam::SOn &Q) const; - static gtsam::SOn Expmap(Vector v); + // Manifold + gtsam::SOn retract(Vector v) const; + Vector localCoordinates(const gtsam::SOn& Q) const; + static gtsam::SOn Expmap(Vector v); - // Other methods - Vector vec() const; - Matrix matrix() const; + // Other methods + Vector vec() const; + Matrix matrix() const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - class Quaternion - { - double w() const; - double x() const; - double y() const; - double z() const; - Vector coeffs() const; - }; +class Quaternion { + double w() const; + double x() const; + double y() const; + double z() const; + Vector coeffs() const; +}; #include - class Rot3 - { - // Standard Constructors and Named Constructors - Rot3(); - Rot3(Matrix R); - Rot3(const gtsam::Point3 &col1, const gtsam::Point3 &col2, const gtsam::Point3 &col3); - Rot3(double R11, double R12, double R13, - double R21, double R22, double R23, - double R31, double R32, double R33); - Rot3(double w, double x, double y, double z); +class Rot3 { + // Standard Constructors and Named Constructors + Rot3(); + Rot3(Matrix R); + Rot3(const gtsam::Point3& col1, const gtsam::Point3& col2, const gtsam::Point3& col3); + Rot3(double R11, double R12, double R13, + double R21, double R22, double R23, + double R31, double R32, double R33); + Rot3(double w, double x, double y, double z); - static gtsam::Rot3 Rx(double t); - static gtsam::Rot3 Ry(double t); - static gtsam::Rot3 Rz(double t); - static gtsam::Rot3 RzRyRx(double x, double y, double z); - static gtsam::Rot3 RzRyRx(Vector xyz); - static gtsam::Rot3 Yaw(double t); // positive yaw is to right (as in aircraft heading) - static gtsam::Rot3 Pitch(double t); // positive pitch is up (increasing aircraft altitude) - static gtsam::Rot3 Roll(double t); // positive roll is to right (increasing yaw in aircraft) - static gtsam::Rot3 Ypr(double y, double p, double r); - static gtsam::Rot3 Quaternion(double w, double x, double y, double z); - static gtsam::Rot3 AxisAngle(const gtsam::Point3 &axis, double angle); - static gtsam::Rot3 Rodrigues(Vector v); - static gtsam::Rot3 Rodrigues(double wx, double wy, double wz); - static gtsam::Rot3 ClosestTo(const Matrix M); + static gtsam::Rot3 Rx(double t); + static gtsam::Rot3 Ry(double t); + static gtsam::Rot3 Rz(double t); + static gtsam::Rot3 RzRyRx(double x, double y, double z); + static gtsam::Rot3 RzRyRx(Vector xyz); + static gtsam::Rot3 Yaw(double t); // positive yaw is to right (as in aircraft heading) + static gtsam::Rot3 Pitch(double t); // positive pitch is up (increasing aircraft altitude) + static gtsam::Rot3 Roll(double t); // positive roll is to right (increasing yaw in aircraft) + static gtsam::Rot3 Ypr(double y, double p, double r); + static gtsam::Rot3 Quaternion(double w, double x, double y, double z); + static gtsam::Rot3 AxisAngle(const gtsam::Point3& axis, double angle); + static gtsam::Rot3 Rodrigues(Vector v); + static gtsam::Rot3 Rodrigues(double wx, double wy, double wz); + static gtsam::Rot3 ClosestTo(const Matrix M); - // Testable - void print(string s) const; - bool equals(const gtsam::Rot3 &rot, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Rot3& rot, double tol) const; - // Group - static gtsam::Rot3 identity(); + // Group + static gtsam::Rot3 identity(); gtsam::Rot3 inverse() const; - gtsam::Rot3 compose(const gtsam::Rot3 &p2) const; - gtsam::Rot3 between(const gtsam::Rot3 &p2) const; + gtsam::Rot3 compose(const gtsam::Rot3& p2) const; + gtsam::Rot3 between(const gtsam::Rot3& p2) const; - // Manifold - //gtsam::Rot3 retractCayley(Vector v) const; // TODO, does not exist in both Matrix and Quaternion options - gtsam::Rot3 retract(Vector v) const; - Vector localCoordinates(const gtsam::Rot3 &p) const; + // Manifold + //gtsam::Rot3 retractCayley(Vector v) const; // TODO, does not exist in both Matrix and Quaternion options + gtsam::Rot3 retract(Vector v) const; + Vector localCoordinates(const gtsam::Rot3& p) const; - // Group Action on Point3 - gtsam::Point3 rotate(const gtsam::Point3 &p) const; - gtsam::Point3 unrotate(const gtsam::Point3 &p) const; + // Group Action on Point3 + gtsam::Point3 rotate(const gtsam::Point3& p) const; + gtsam::Point3 unrotate(const gtsam::Point3& p) const; - // Standard Interface - static gtsam::Rot3 Expmap(Vector v); - static Vector Logmap(const gtsam::Rot3 &p); - Vector logmap(const gtsam::Rot3 &p); - Matrix matrix() const; - Matrix transpose() const; - gtsam::Point3 column(size_t index) const; - Vector xyz() const; - Vector ypr() const; - Vector rpy() const; - double roll() const; - double pitch() const; - double yaw() const; - pair axisAngle() const; - gtsam::Quaternion toQuaternion() const; - Vector quaternion() const; - gtsam::Rot3 slerp(double t, const gtsam::Rot3 &other) const; + // Standard Interface + static gtsam::Rot3 Expmap(Vector v); + static Vector Logmap(const gtsam::Rot3& p); + Vector logmap(const gtsam::Rot3& p); + Matrix matrix() const; + Matrix transpose() const; + gtsam::Point3 column(size_t index) const; + Vector xyz() const; + Vector ypr() const; + Vector rpy() const; + double roll() const; + double pitch() const; + double yaw() const; + pair axisAngle() const; + gtsam::Quaternion toQuaternion() const; + Vector quaternion() const; + gtsam::Rot3 slerp(double t, const gtsam::Rot3& other) const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - class Pose2 - { - // Standard Constructor - Pose2(); - Pose2(const gtsam::Pose2 &other); - Pose2(double x, double y, double theta); - Pose2(double theta, const gtsam::Point2 &t); - Pose2(const gtsam::Rot2 &r, const gtsam::Point2 &t); - Pose2(Vector v); +class Pose2 { + // Standard Constructor + Pose2(); + Pose2(const gtsam::Pose2& other); + Pose2(double x, double y, double theta); + Pose2(double theta, const gtsam::Point2& t); + Pose2(const gtsam::Rot2& r, const gtsam::Point2& t); + Pose2(Vector v); - // Testable - void print(string s) const; - bool equals(const gtsam::Pose2 &pose, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Pose2& pose, double tol) const; - // Group - static gtsam::Pose2 identity(); - gtsam::Pose2 inverse() const; - gtsam::Pose2 compose(const gtsam::Pose2 &p2) const; - gtsam::Pose2 between(const gtsam::Pose2 &p2) const; + // Group + static gtsam::Pose2 identity(); + gtsam::Pose2 inverse() const; + gtsam::Pose2 compose(const gtsam::Pose2& p2) const; + gtsam::Pose2 between(const gtsam::Pose2& p2) const; - // Manifold - gtsam::Pose2 retract(Vector v) const; - Vector localCoordinates(const gtsam::Pose2 &p) const; + // Manifold + gtsam::Pose2 retract(Vector v) const; + Vector localCoordinates(const gtsam::Pose2& p) const; - // Lie Group - static gtsam::Pose2 Expmap(Vector v); - static Vector Logmap(const gtsam::Pose2 &p); - Vector logmap(const gtsam::Pose2 &p); - static Matrix ExpmapDerivative(Vector v); - static Matrix LogmapDerivative(const gtsam::Pose2 &v); - Matrix AdjointMap() const; - Vector Adjoint(Vector xi) const; - static Matrix adjointMap_(Vector v); - static Vector adjoint_(Vector xi, Vector y); - static Vector adjointTranspose(Vector xi, Vector y); - static Matrix wedge(double vx, double vy, double w); + // Lie Group + static gtsam::Pose2 Expmap(Vector v); + static Vector Logmap(const gtsam::Pose2& p); + Vector logmap(const gtsam::Pose2& p); + static Matrix ExpmapDerivative(Vector v); + static Matrix LogmapDerivative(const gtsam::Pose2& v); + Matrix AdjointMap() const; + Vector Adjoint(Vector xi) const; + static Matrix adjointMap_(Vector v); + static Vector adjoint_(Vector xi, Vector y); + static Vector adjointTranspose(Vector xi, Vector y); + static Matrix wedge(double vx, double vy, double w); - // Group Actions on Point2 - gtsam::Point2 transformFrom(const gtsam::Point2 &p) const; - gtsam::Point2 transformTo(const gtsam::Point2 &p) const; + // Group Actions on Point2 + gtsam::Point2 transformFrom(const gtsam::Point2& p) const; + gtsam::Point2 transformTo(const gtsam::Point2& p) const; - // Standard Interface - double x() const; - double y() const; - double theta() const; - gtsam::Rot2 bearing(const gtsam::Point2 &point) const; - double range(const gtsam::Point2 &point) const; - gtsam::Point2 translation() const; - gtsam::Rot2 rotation() const; - Matrix matrix() const; + // Standard Interface + double x() const; + double y() const; + double theta() const; + gtsam::Rot2 bearing(const gtsam::Point2& point) const; + double range(const gtsam::Point2& point) const; + gtsam::Point2 translation() const; + gtsam::Rot2 rotation() const; + Matrix matrix() const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - class Pose3 - { - // Standard Constructors - Pose3(); - Pose3(const gtsam::Pose3 &other); - Pose3(const gtsam::Rot3 &r, const gtsam::Point3 &t); - Pose3(const gtsam::Pose2 &pose2); - Pose3(Matrix mat); +class Pose3 { + // Standard Constructors + Pose3(); + Pose3(const gtsam::Pose3& other); + Pose3(const gtsam::Rot3& r, const gtsam::Point3& t); + Pose3(const gtsam::Pose2& pose2); + Pose3(Matrix mat); - // Testable - void print(string s) const; - bool equals(const gtsam::Pose3 &pose, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Pose3& pose, double tol) const; - // Group - static gtsam::Pose3 identity(); - gtsam::Pose3 inverse() const; - gtsam::Pose3 compose(const gtsam::Pose3 &pose) const; - gtsam::Pose3 between(const gtsam::Pose3 &pose) const; + // Group + static gtsam::Pose3 identity(); + gtsam::Pose3 inverse() const; + gtsam::Pose3 compose(const gtsam::Pose3& pose) const; + gtsam::Pose3 between(const gtsam::Pose3& pose) const; - // Manifold - gtsam::Pose3 retract(Vector v) const; - Vector localCoordinates(const gtsam::Pose3 &pose) const; + // Manifold + gtsam::Pose3 retract(Vector v) const; + Vector localCoordinates(const gtsam::Pose3& pose) const; - // Lie Group - static gtsam::Pose3 Expmap(Vector v); - static Vector Logmap(const gtsam::Pose3 &pose); - Vector logmap(const gtsam::Pose3 &pose); - Matrix AdjointMap() const; - Vector Adjoint(Vector xi) const; - static Matrix adjointMap_(Vector xi); - static Vector adjoint_(Vector xi, Vector y); - static Vector adjointTranspose(Vector xi, Vector y); - static Matrix ExpmapDerivative(Vector xi); - static Matrix LogmapDerivative(const gtsam::Pose3 &xi); - static Matrix wedge(double wx, double wy, double wz, double vx, double vy, double vz); + // Lie Group + static gtsam::Pose3 Expmap(Vector v); + static Vector Logmap(const gtsam::Pose3& pose); + Vector logmap(const gtsam::Pose3& pose); + Matrix AdjointMap() const; + Vector Adjoint(Vector xi) const; + static Matrix adjointMap_(Vector xi); + static Vector adjoint_(Vector xi, Vector y); + static Vector adjointTranspose(Vector xi, Vector y); + static Matrix ExpmapDerivative(Vector xi); + static Matrix LogmapDerivative(const gtsam::Pose3& xi); + static Matrix wedge(double wx, double wy, double wz, double vx, double vy, double vz); - // Group Action on Point3 - gtsam::Point3 transformFrom(const gtsam::Point3 &point) const; - gtsam::Point3 transformTo(const gtsam::Point3 &point) const; + // Group Action on Point3 + gtsam::Point3 transformFrom(const gtsam::Point3& point) const; + gtsam::Point3 transformTo(const gtsam::Point3& point) const; - // Standard Interface - gtsam::Rot3 rotation() const; - gtsam::Point3 translation() const; - double x() const; - double y() const; - double z() const; - Matrix matrix() const; - gtsam::Pose3 transformPoseFrom(const gtsam::Pose3 &pose) const; - gtsam::Pose3 transformPoseTo(const gtsam::Pose3 &pose) const; - double range(const gtsam::Point3 &point); - double range(const gtsam::Pose3 &pose); + // Standard Interface + gtsam::Rot3 rotation() const; + gtsam::Point3 translation() const; + double x() const; + double y() const; + double z() const; + Matrix matrix() const; + gtsam::Pose3 transformPoseFrom(const gtsam::Pose3& pose) const; + gtsam::Pose3 transformPoseTo(const gtsam::Pose3& pose) const; + double range(const gtsam::Point3& point); + double range(const gtsam::Pose3& pose); - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; // std::vector #include - class Pose3Vector - { - Pose3Vector(); - size_t size() const; - bool empty() const; - gtsam::Pose3 at(size_t n) const; - void push_back(const gtsam::Pose3 &pose); - }; +class Pose3Vector +{ + Pose3Vector(); + size_t size() const; + bool empty() const; + gtsam::Pose3 at(size_t n) const; + void push_back(const gtsam::Pose3& pose); +}; #include - class Unit3 - { - // Standard Constructors - Unit3(); - Unit3(const gtsam::Point3 &pose); +class Unit3 { + // Standard Constructors + Unit3(); + Unit3(const gtsam::Point3& pose); - // Testable - void print(string s) const; - bool equals(const gtsam::Unit3 &pose, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Unit3& pose, double tol) const; - // Other functionality - Matrix basis() const; - Matrix skew() const; - gtsam::Point3 point3() const; + // Other functionality + Matrix basis() const; + Matrix skew() const; + gtsam::Point3 point3() const; - // Manifold - static size_t Dim(); - size_t dim() const; - gtsam::Unit3 retract(Vector v) const; - Vector localCoordinates(const gtsam::Unit3 &s) const; - }; + // Manifold + static size_t Dim(); + size_t dim() const; + gtsam::Unit3 retract(Vector v) const; + Vector localCoordinates(const gtsam::Unit3& s) const; +}; #include - class EssentialMatrix - { - // Standard Constructors - EssentialMatrix(const gtsam::Rot3 &aRb, const gtsam::Unit3 &aTb); +class EssentialMatrix { + // Standard Constructors + EssentialMatrix(const gtsam::Rot3& aRb, const gtsam::Unit3& aTb); - // Testable - void print(string s) const; - bool equals(const gtsam::EssentialMatrix &pose, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::EssentialMatrix& pose, double tol) const; - // Manifold - static size_t Dim(); - size_t dim() const; - gtsam::EssentialMatrix retract(Vector v) const; - Vector localCoordinates(const gtsam::EssentialMatrix &s) const; + // Manifold + static size_t Dim(); + size_t dim() const; + gtsam::EssentialMatrix retract(Vector v) const; + Vector localCoordinates(const gtsam::EssentialMatrix& s) const; - // Other methods: - gtsam::Rot3 rotation() const; - gtsam::Unit3 direction() const; - Matrix matrix() const; - double error(Vector vA, Vector vB); - }; + // Other methods: + gtsam::Rot3 rotation() const; + gtsam::Unit3 direction() const; + Matrix matrix() const; + double error(Vector vA, Vector vB); +}; #include class Cal3_S2 { @@ -886,402 +859,389 @@ class Cal3_S2 { }; #include - virtual class Cal3DS2_Base - { - // Standard Constructors - Cal3DS2_Base(); +virtual class Cal3DS2_Base { + // Standard Constructors + Cal3DS2_Base(); - // Testable - void print(string s) const; + // Testable + void print(string s) const; - // Standard Interface - double fx() const; - double fy() const; - double skew() const; - double px() const; - double py() const; - double k1() const; - double k2() const; - Matrix K() const; - Vector k() const; - Vector vector() const; + // Standard Interface + double fx() const; + double fy() const; + double skew() const; + double px() const; + double py() const; + double k1() const; + double k2() const; + Matrix K() const; + Vector k() const; + Vector vector() const; - // Action on Point2 - gtsam::Point2 uncalibrate(const gtsam::Point2 &p) const; - gtsam::Point2 calibrate(const gtsam::Point2 &p) const; + // Action on Point2 + gtsam::Point2 uncalibrate(const gtsam::Point2& p) const; + gtsam::Point2 calibrate(const gtsam::Point2& p) const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - virtual class Cal3DS2 : gtsam::Cal3DS2_Base - { - // Standard Constructors - Cal3DS2(); - Cal3DS2(double fx, double fy, double s, double u0, double v0, double k1, double k2); - Cal3DS2(double fx, double fy, double s, double u0, double v0, double k1, double k2, double p1, double p2); - Cal3DS2(Vector v); +virtual class Cal3DS2 : gtsam::Cal3DS2_Base { + // Standard Constructors + Cal3DS2(); + Cal3DS2(double fx, double fy, double s, double u0, double v0, double k1, double k2); + Cal3DS2(double fx, double fy, double s, double u0, double v0, double k1, double k2, double p1, double p2); + Cal3DS2(Vector v); - // Testable - bool equals(const gtsam::Cal3DS2 &rhs, double tol) const; + // Testable + bool equals(const gtsam::Cal3DS2& rhs, double tol) const; - // Manifold - size_t dim() const; - static size_t Dim(); - gtsam::Cal3DS2 retract(Vector v) const; - Vector localCoordinates(const gtsam::Cal3DS2 &c) const; + // Manifold + size_t dim() const; + static size_t Dim(); + gtsam::Cal3DS2 retract(Vector v) const; + Vector localCoordinates(const gtsam::Cal3DS2& c) const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - virtual class Cal3Unified : gtsam::Cal3DS2_Base - { - // Standard Constructors - Cal3Unified(); - Cal3Unified(double fx, double fy, double s, double u0, double v0, double k1, double k2); - Cal3Unified(double fx, double fy, double s, double u0, double v0, double k1, double k2, double p1, double p2, double xi); - Cal3Unified(Vector v); +virtual class Cal3Unified : gtsam::Cal3DS2_Base { + // Standard Constructors + Cal3Unified(); + Cal3Unified(double fx, double fy, double s, double u0, double v0, double k1, double k2); + Cal3Unified(double fx, double fy, double s, double u0, double v0, double k1, double k2, double p1, double p2, double xi); + Cal3Unified(Vector v); - // Testable - bool equals(const gtsam::Cal3Unified &rhs, double tol) const; + // Testable + bool equals(const gtsam::Cal3Unified& rhs, double tol) const; - // Standard Interface - double xi() const; - gtsam::Point2 spaceToNPlane(const gtsam::Point2 &p) const; - gtsam::Point2 nPlaneToSpace(const gtsam::Point2 &p) const; + // Standard Interface + double xi() const; + gtsam::Point2 spaceToNPlane(const gtsam::Point2& p) const; + gtsam::Point2 nPlaneToSpace(const gtsam::Point2& p) const; - // Manifold - size_t dim() const; - static size_t Dim(); - gtsam::Cal3Unified retract(Vector v) const; - Vector localCoordinates(const gtsam::Cal3Unified &c) const; + // Manifold + size_t dim() const; + static size_t Dim(); + gtsam::Cal3Unified retract(Vector v) const; + Vector localCoordinates(const gtsam::Cal3Unified& c) const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - class Cal3_S2Stereo - { - // Standard Constructors - Cal3_S2Stereo(); - Cal3_S2Stereo(double fx, double fy, double s, double u0, double v0, double b); - Cal3_S2Stereo(Vector v); +class Cal3_S2Stereo { + // Standard Constructors + Cal3_S2Stereo(); + Cal3_S2Stereo(double fx, double fy, double s, double u0, double v0, double b); + Cal3_S2Stereo(Vector v); - // Testable - void print(string s) const; - bool equals(const gtsam::Cal3_S2Stereo &K, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Cal3_S2Stereo& K, double tol) const; - // Standard Interface - double fx() const; - double fy() const; - double skew() const; - double px() const; - double py() const; - gtsam::Point2 principalPoint() const; - double baseline() const; - }; + // Standard Interface + double fx() const; + double fy() const; + double skew() const; + double px() const; + double py() const; + gtsam::Point2 principalPoint() const; + double baseline() const; +}; #include - class Cal3Bundler - { - // Standard Constructors - Cal3Bundler(); - Cal3Bundler(double fx, double k1, double k2, double u0, double v0); - Cal3Bundler(double fx, double k1, double k2, double u0, double v0, double tol); +class Cal3Bundler { + // Standard Constructors + Cal3Bundler(); + Cal3Bundler(double fx, double k1, double k2, double u0, double v0); + Cal3Bundler(double fx, double k1, double k2, double u0, double v0, double tol); - // Testable - void print(string s) const; - bool equals(const gtsam::Cal3Bundler &rhs, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::Cal3Bundler& rhs, double tol) const; - // Manifold - static size_t Dim(); - size_t dim() const; - gtsam::Cal3Bundler retract(Vector v) const; - Vector localCoordinates(const gtsam::Cal3Bundler &c) const; + // Manifold + static size_t Dim(); + size_t dim() const; + gtsam::Cal3Bundler retract(Vector v) const; + Vector localCoordinates(const gtsam::Cal3Bundler& c) const; - // Action on Point2 - gtsam::Point2 calibrate(const gtsam::Point2 &p) const; - gtsam::Point2 uncalibrate(const gtsam::Point2 &p) const; + // Action on Point2 + gtsam::Point2 calibrate(const gtsam::Point2& p) const; + gtsam::Point2 uncalibrate(const gtsam::Point2& p) const; - // Standard Interface - double fx() const; - double fy() const; - double k1() const; - double k2() const; - double px() const; - double py() const; - Vector vector() const; - Vector k() const; - Matrix K() const; + // Standard Interface + double fx() const; + double fy() const; + double k1() const; + double k2() const; + double px() const; + double py() const; + Vector vector() const; + Vector k() const; + Matrix K() const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - class CalibratedCamera - { - // Standard Constructors and Named Constructors - CalibratedCamera(); - CalibratedCamera(const gtsam::Pose3 &pose); - CalibratedCamera(Vector v); - static gtsam::CalibratedCamera Level(const gtsam::Pose2 &pose2, double height); +class CalibratedCamera { + // Standard Constructors and Named Constructors + CalibratedCamera(); + CalibratedCamera(const gtsam::Pose3& pose); + CalibratedCamera(Vector v); + static gtsam::CalibratedCamera Level(const gtsam::Pose2& pose2, double height); - // Testable - void print(string s) const; - bool equals(const gtsam::CalibratedCamera &camera, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::CalibratedCamera& camera, double tol) const; - // Manifold - static size_t Dim(); - size_t dim() const; - gtsam::CalibratedCamera retract(Vector d) const; - Vector localCoordinates(const gtsam::CalibratedCamera &T2) const; + // Manifold + static size_t Dim(); + size_t dim() const; + gtsam::CalibratedCamera retract(Vector d) const; + Vector localCoordinates(const gtsam::CalibratedCamera& T2) const; - // Action on Point3 - gtsam::Point2 project(const gtsam::Point3 &point) const; - static gtsam::Point2 Project(const gtsam::Point3 &cameraPoint); + // Action on Point3 + gtsam::Point2 project(const gtsam::Point3& point) const; + static gtsam::Point2 Project(const gtsam::Point3& cameraPoint); - // Standard Interface - gtsam::Pose3 pose() const; - double range(const gtsam::Point3 &p) const; // TODO: Other overloaded range methods + // Standard Interface + gtsam::Pose3 pose() const; + double range(const gtsam::Point3& p) const; // TODO: Other overloaded range methods - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - template - class PinholeCamera - { - // Standard Constructors and Named Constructors - PinholeCamera(); - PinholeCamera(const gtsam::Pose3 &pose); - PinholeCamera(const gtsam::Pose3 &pose, const CALIBRATION &K); - static This Level(const CALIBRATION &K, const gtsam::Pose2 &pose, double height); - static This Level(const gtsam::Pose2 &pose, double height); - static This Lookat(const gtsam::Point3 &eye, const gtsam::Point3 &target, - const gtsam::Point3 &upVector, const CALIBRATION &K); +template +class PinholeCamera { + // Standard Constructors and Named Constructors + PinholeCamera(); + PinholeCamera(const gtsam::Pose3& pose); + PinholeCamera(const gtsam::Pose3& pose, const CALIBRATION& K); + static This Level(const CALIBRATION& K, const gtsam::Pose2& pose, double height); + static This Level(const gtsam::Pose2& pose, double height); + static This Lookat(const gtsam::Point3& eye, const gtsam::Point3& target, + const gtsam::Point3& upVector, const CALIBRATION& K); - // Testable - void print(string s) const; - bool equals(const This &camera, double tol) const; + // Testable + void print(string s) const; + bool equals(const This& camera, double tol) const; - // Standard Interface - gtsam::Pose3 pose() const; - CALIBRATION calibration() const; + // Standard Interface + gtsam::Pose3 pose() const; + CALIBRATION calibration() const; - // Manifold - This retract(Vector d) const; - Vector localCoordinates(const This &T2) const; - size_t dim() const; - static size_t Dim(); + // Manifold + This retract(Vector d) const; + Vector localCoordinates(const This& T2) const; + size_t dim() const; + static size_t Dim(); - // Transformations and measurement functions - static gtsam::Point2 Project(const gtsam::Point3 &cameraPoint); - pair projectSafe(const gtsam::Point3 &pw) const; - gtsam::Point2 project(const gtsam::Point3 &point); - gtsam::Point3 backproject(const gtsam::Point2 &p, double depth) const; - double range(const gtsam::Point3 &point); - double range(const gtsam::Pose3 &pose); + // Transformations and measurement functions + static gtsam::Point2 Project(const gtsam::Point3& cameraPoint); + pair projectSafe(const gtsam::Point3& pw) const; + gtsam::Point2 project(const gtsam::Point3& point); + gtsam::Point3 backproject(const gtsam::Point2& p, double depth) const; + double range(const gtsam::Point3& point); + double range(const gtsam::Pose3& pose); - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; // Forward declaration of PinholeCameraCalX is defined here. #include - // Some typedefs for common camera types - // PinholeCameraCal3_S2 is the same as SimpleCamera above - typedef gtsam::PinholeCamera PinholeCameraCal3_S2; - typedef gtsam::PinholeCamera PinholeCameraCal3DS2; - typedef gtsam::PinholeCamera PinholeCameraCal3Unified; - typedef gtsam::PinholeCamera PinholeCameraCal3Bundler; +// Some typedefs for common camera types +// PinholeCameraCal3_S2 is the same as SimpleCamera above +typedef gtsam::PinholeCamera PinholeCameraCal3_S2; +typedef gtsam::PinholeCamera PinholeCameraCal3DS2; +typedef gtsam::PinholeCamera PinholeCameraCal3Unified; +typedef gtsam::PinholeCamera PinholeCameraCal3Bundler; - template - class CameraSet - { - CameraSet(); - // structure specific methods - T at(size_t i) const; - void push_back(const T &cam); - }; +template +class CameraSet { + CameraSet(); + + // structure specific methods + T at(size_t i) const; + void push_back(const T& cam); +}; #include - class StereoCamera - { - // Standard Constructors and Named Constructors - StereoCamera(); - StereoCamera(const gtsam::Pose3 &pose, const gtsam::Cal3_S2Stereo *K); +class StereoCamera { + // Standard Constructors and Named Constructors + StereoCamera(); + StereoCamera(const gtsam::Pose3& pose, const gtsam::Cal3_S2Stereo* K); - // Testable - void print(string s) const; - bool equals(const gtsam::StereoCamera &camera, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::StereoCamera& camera, double tol) const; - // Standard Interface - gtsam::Pose3 pose() const; - double baseline() const; - gtsam::Cal3_S2Stereo calibration() const; + // Standard Interface + gtsam::Pose3 pose() const; + double baseline() const; + gtsam::Cal3_S2Stereo calibration() const; - // Manifold - gtsam::StereoCamera retract(Vector d) const; - Vector localCoordinates(const gtsam::StereoCamera &T2) const; - size_t dim() const; - static size_t Dim(); + // Manifold + gtsam::StereoCamera retract(Vector d) const; + Vector localCoordinates(const gtsam::StereoCamera& T2) const; + size_t dim() const; + static size_t Dim(); - // Transformations and measurement functions - gtsam::StereoPoint2 project(const gtsam::Point3 &point); - gtsam::Point3 backproject(const gtsam::StereoPoint2 &p) const; + // Transformations and measurement functions + gtsam::StereoPoint2 project(const gtsam::Point3& point); + gtsam::Point3 backproject(const gtsam::StereoPoint2& p) const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - // Templates appear not yet supported for free functions - issue raised at borglab/wrap#14 to add support - gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector &poses, - gtsam::Cal3_S2 *sharedCal, const gtsam::Point2Vector &measurements, - double rank_tol, bool optimize); - gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector &poses, - gtsam::Cal3DS2 *sharedCal, const gtsam::Point2Vector &measurements, - double rank_tol, bool optimize); - gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector &poses, - gtsam::Cal3Bundler *sharedCal, const gtsam::Point2Vector &measurements, - double rank_tol, bool optimize); - gtsam::Point3 triangulatePoint3(const gtsam::CameraSetCal3_S2 &cameras, - const gtsam::Point2Vector &measurements, double rank_tol, - bool optimize); - gtsam::Point3 triangulatePoint3(const gtsam::CameraSetCal3Bundler &cameras, - const gtsam::Point2Vector &measurements, double rank_tol, - bool optimize); - - //************************************************************************* - // Symbolic - //************************************************************************* +// Templates appear not yet supported for free functions - issue raised at borglab/wrap#14 to add support +gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, + gtsam::Cal3_S2* sharedCal, const gtsam::Point2Vector& measurements, + double rank_tol, bool optimize); +gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, + gtsam::Cal3DS2* sharedCal, const gtsam::Point2Vector& measurements, + double rank_tol, bool optimize); +gtsam::Point3 triangulatePoint3(const gtsam::Pose3Vector& poses, + gtsam::Cal3Bundler* sharedCal, const gtsam::Point2Vector& measurements, + double rank_tol, bool optimize); +gtsam::Point3 triangulatePoint3(const gtsam::CameraSetCal3_S2& cameras, + const gtsam::Point2Vector& measurements, double rank_tol, + bool optimize); +gtsam::Point3 triangulatePoint3(const gtsam::CameraSetCal3Bundler& cameras, + const gtsam::Point2Vector& measurements, double rank_tol, + bool optimize); + +//************************************************************************* +// Symbolic +//************************************************************************* #include - virtual class SymbolicFactor - { - // Standard Constructors and Named Constructors - SymbolicFactor(const gtsam::SymbolicFactor &f); - SymbolicFactor(); - SymbolicFactor(size_t j); - SymbolicFactor(size_t j1, size_t j2); - SymbolicFactor(size_t j1, size_t j2, size_t j3); - SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4); - SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4, size_t j5); - SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4, size_t j5, size_t j6); - static gtsam::SymbolicFactor FromKeys(const gtsam::KeyVector &js); +virtual class SymbolicFactor { + // Standard Constructors and Named Constructors + SymbolicFactor(const gtsam::SymbolicFactor& f); + SymbolicFactor(); + SymbolicFactor(size_t j); + SymbolicFactor(size_t j1, size_t j2); + SymbolicFactor(size_t j1, size_t j2, size_t j3); + SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4); + SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4, size_t j5); + SymbolicFactor(size_t j1, size_t j2, size_t j3, size_t j4, size_t j5, size_t j6); + static gtsam::SymbolicFactor FromKeys(const gtsam::KeyVector& js); - // From Factor - size_t size() const; - void print(string s) const; - bool equals(const gtsam::SymbolicFactor &other, double tol) const; - gtsam::KeyVector keys(); - }; + // From Factor + size_t size() const; + void print(string s) const; + bool equals(const gtsam::SymbolicFactor& other, double tol) const; + gtsam::KeyVector keys(); +}; #include - virtual class SymbolicFactorGraph - { - SymbolicFactorGraph(); - SymbolicFactorGraph(const gtsam::SymbolicBayesNet &bayesNet); - SymbolicFactorGraph(const gtsam::SymbolicBayesTree &bayesTree); +virtual class SymbolicFactorGraph { + SymbolicFactorGraph(); + SymbolicFactorGraph(const gtsam::SymbolicBayesNet& bayesNet); + SymbolicFactorGraph(const gtsam::SymbolicBayesTree& bayesTree); - // From FactorGraph - void push_back(gtsam::SymbolicFactor *factor); - void print(string s) const; - bool equals(const gtsam::SymbolicFactorGraph &rhs, double tol) const; - size_t size() const; - bool exists(size_t idx) const; + // From FactorGraph + void push_back(gtsam::SymbolicFactor* factor); + void print(string s) const; + bool equals(const gtsam::SymbolicFactorGraph& rhs, double tol) const; + size_t size() const; + bool exists(size_t idx) const; - // Standard interface - gtsam::KeySet keys() const; - void push_back(const gtsam::SymbolicFactorGraph &graph); - void push_back(const gtsam::SymbolicBayesNet &bayesNet); - void push_back(const gtsam::SymbolicBayesTree &bayesTree); + // Standard interface + gtsam::KeySet keys() const; + void push_back(const gtsam::SymbolicFactorGraph& graph); + void push_back(const gtsam::SymbolicBayesNet& bayesNet); + void push_back(const gtsam::SymbolicBayesTree& bayesTree); - //Advanced Interface - void push_factor(size_t key); - void push_factor(size_t key1, size_t key2); - void push_factor(size_t key1, size_t key2, size_t key3); - void push_factor(size_t key1, size_t key2, size_t key3, size_t key4); + //Advanced Interface + void push_factor(size_t key); + void push_factor(size_t key1, size_t key2); + void push_factor(size_t key1, size_t key2, size_t key3); + void push_factor(size_t key1, size_t key2, size_t key3, size_t key4); - gtsam::SymbolicBayesNet *eliminateSequential(); - gtsam::SymbolicBayesNet *eliminateSequential(const gtsam::Ordering &ordering); - gtsam::SymbolicBayesTree *eliminateMultifrontal(); - gtsam::SymbolicBayesTree *eliminateMultifrontal(const gtsam::Ordering &ordering); - pair eliminatePartialSequential( - const gtsam::Ordering &ordering); - pair eliminatePartialSequential( - const gtsam::KeyVector &keys); - pair eliminatePartialMultifrontal( - const gtsam::Ordering &ordering); - pair eliminatePartialMultifrontal( - const gtsam::KeyVector &keys); - gtsam::SymbolicBayesNet *marginalMultifrontalBayesNet(const gtsam::Ordering &ordering); - gtsam::SymbolicBayesNet *marginalMultifrontalBayesNet(const gtsam::KeyVector &key_vector); - gtsam::SymbolicBayesNet *marginalMultifrontalBayesNet(const gtsam::Ordering &ordering, - const gtsam::Ordering &marginalizedVariableOrdering); - gtsam::SymbolicBayesNet *marginalMultifrontalBayesNet(const gtsam::KeyVector &key_vector, - const gtsam::Ordering &marginalizedVariableOrdering); - gtsam::SymbolicFactorGraph *marginal(const gtsam::KeyVector &key_vector); - }; + gtsam::SymbolicBayesNet* eliminateSequential(); + gtsam::SymbolicBayesNet* eliminateSequential(const gtsam::Ordering& ordering); + gtsam::SymbolicBayesTree* eliminateMultifrontal(); + gtsam::SymbolicBayesTree* eliminateMultifrontal(const gtsam::Ordering& ordering); + pair eliminatePartialSequential( + const gtsam::Ordering& ordering); + pair eliminatePartialSequential( + const gtsam::KeyVector& keys); + pair eliminatePartialMultifrontal( + const gtsam::Ordering& ordering); + pair eliminatePartialMultifrontal( + const gtsam::KeyVector& keys); + gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(const gtsam::Ordering& ordering); + gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(const gtsam::KeyVector& key_vector); + gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(const gtsam::Ordering& ordering, + const gtsam::Ordering& marginalizedVariableOrdering); + gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet(const gtsam::KeyVector& key_vector, + const gtsam::Ordering& marginalizedVariableOrdering); + gtsam::SymbolicFactorGraph* marginal(const gtsam::KeyVector& key_vector); +}; #include - virtual class SymbolicConditional : gtsam::SymbolicFactor - { - // Standard Constructors and Named Constructors - SymbolicConditional(); - SymbolicConditional(const gtsam::SymbolicConditional &other); - SymbolicConditional(size_t key); - SymbolicConditional(size_t key, size_t parent); - SymbolicConditional(size_t key, size_t parent1, size_t parent2); - SymbolicConditional(size_t key, size_t parent1, size_t parent2, size_t parent3); - static gtsam::SymbolicConditional FromKeys(const gtsam::KeyVector &keys, size_t nrFrontals); +virtual class SymbolicConditional : gtsam::SymbolicFactor { + // Standard Constructors and Named Constructors + SymbolicConditional(); + SymbolicConditional(const gtsam::SymbolicConditional& other); + SymbolicConditional(size_t key); + SymbolicConditional(size_t key, size_t parent); + SymbolicConditional(size_t key, size_t parent1, size_t parent2); + SymbolicConditional(size_t key, size_t parent1, size_t parent2, size_t parent3); + static gtsam::SymbolicConditional FromKeys(const gtsam::KeyVector& keys, size_t nrFrontals); - // Testable - void print(string s) const; - bool equals(const gtsam::SymbolicConditional &other, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::SymbolicConditional& other, double tol) const; - // Standard interface - size_t nrFrontals() const; - size_t nrParents() const; - }; + // Standard interface + size_t nrFrontals() const; + size_t nrParents() const; +}; #include - class SymbolicBayesNet - { - SymbolicBayesNet(); - SymbolicBayesNet(const gtsam::SymbolicBayesNet &other); - // Testable - void print(string s) const; - bool equals(const gtsam::SymbolicBayesNet &other, double tol) const; +class SymbolicBayesNet { + SymbolicBayesNet(); + SymbolicBayesNet(const gtsam::SymbolicBayesNet& other); + // Testable + void print(string s) const; + bool equals(const gtsam::SymbolicBayesNet& other, double tol) const; - // Standard interface - size_t size() const; - void saveGraph(string s) const; - gtsam::SymbolicConditional *at(size_t idx) const; - gtsam::SymbolicConditional *front() const; - gtsam::SymbolicConditional *back() const; - void push_back(gtsam::SymbolicConditional *conditional); - void push_back(const gtsam::SymbolicBayesNet &bayesNet); - }; + // Standard interface + size_t size() const; + void saveGraph(string s) const; + gtsam::SymbolicConditional* at(size_t idx) const; + gtsam::SymbolicConditional* front() const; + gtsam::SymbolicConditional* back() const; + void push_back(gtsam::SymbolicConditional* conditional); + void push_back(const gtsam::SymbolicBayesNet& bayesNet); +}; #include - class SymbolicBayesTree - { +class SymbolicBayesTree { //Constructors SymbolicBayesTree(); - SymbolicBayesTree(const gtsam::SymbolicBayesTree &other); + SymbolicBayesTree(const gtsam::SymbolicBayesTree& other); // Testable void print(string s); - bool equals(const gtsam::SymbolicBayesTree &other, double tol) const; + bool equals(const gtsam::SymbolicBayesTree& other, double tol) const; //Standard Interface //size_t findParentClique(const gtsam::IndexVector& parents) const; @@ -1291,1019 +1251,969 @@ class Cal3_S2 { void deleteCachedShortcuts(); size_t numCachedSeparatorMarginals() const; - gtsam::SymbolicConditional *marginalFactor(size_t key) const; - gtsam::SymbolicFactorGraph *joint(size_t key1, size_t key2) const; - gtsam::SymbolicBayesNet *jointBayesNet(size_t key1, size_t key2) const; - }; + gtsam::SymbolicConditional* marginalFactor(size_t key) const; + gtsam::SymbolicFactorGraph* joint(size_t key1, size_t key2) const; + gtsam::SymbolicBayesNet* jointBayesNet(size_t key1, size_t key2) const; +}; - // class SymbolicBayesTreeClique { - // BayesTreeClique(); - // BayesTreeClique(CONDITIONAL* conditional); - // // BayesTreeClique(const pair& result) : Base(result) {} - // - // bool equals(const This& other, double tol) const; - // void print(string s) const; - // void printTree() const; // Default indent of "" - // void printTree(string indent) const; - // size_t numCachedSeparatorMarginals() const; - // - // CONDITIONAL* conditional() const; - // bool isRoot() const; - // size_t treeSize() const; - // // const std::list& children() const { return children_; } - // // derived_ptr parent() const { return parent_.lock(); } - // - // // TODO: need wrapped versions graphs, BayesNet - // // BayesNet shortcut(derived_ptr root, Eliminate function) const; - // // FactorGraph marginal(derived_ptr root, Eliminate function) const; - // // FactorGraph joint(derived_ptr C2, derived_ptr root, Eliminate function) const; - // - // void deleteCachedShortcuts(); - // }; +// class SymbolicBayesTreeClique { +// BayesTreeClique(); +// BayesTreeClique(CONDITIONAL* conditional); +// // BayesTreeClique(const pair& result) : Base(result) {} +// +// bool equals(const This& other, double tol) const; +// void print(string s) const; +// void printTree() const; // Default indent of "" +// void printTree(string indent) const; +// size_t numCachedSeparatorMarginals() const; +// +// CONDITIONAL* conditional() const; +// bool isRoot() const; +// size_t treeSize() const; +// // const std::list& children() const { return children_; } +// // derived_ptr parent() const { return parent_.lock(); } +// +// // TODO: need wrapped versions graphs, BayesNet +// // BayesNet shortcut(derived_ptr root, Eliminate function) const; +// // FactorGraph marginal(derived_ptr root, Eliminate function) const; +// // FactorGraph joint(derived_ptr C2, derived_ptr root, Eliminate function) const; +// +// void deleteCachedShortcuts(); +// }; #include - class VariableIndex - { - // Standard Constructors and Named Constructors - VariableIndex(); - // TODO: Templetize constructor when wrap supports it - //template - //VariableIndex(const T& factorGraph, size_t nVariables); - //VariableIndex(const T& factorGraph); - VariableIndex(const gtsam::SymbolicFactorGraph &sfg); - VariableIndex(const gtsam::GaussianFactorGraph &gfg); - VariableIndex(const gtsam::NonlinearFactorGraph &fg); - VariableIndex(const gtsam::VariableIndex &other); +class VariableIndex { + // Standard Constructors and Named Constructors + VariableIndex(); + // TODO: Templetize constructor when wrap supports it + //template + //VariableIndex(const T& factorGraph, size_t nVariables); + //VariableIndex(const T& factorGraph); + VariableIndex(const gtsam::SymbolicFactorGraph& sfg); + VariableIndex(const gtsam::GaussianFactorGraph& gfg); + VariableIndex(const gtsam::NonlinearFactorGraph& fg); + VariableIndex(const gtsam::VariableIndex& other); - // Testable - bool equals(const gtsam::VariableIndex &other, double tol) const; - void print(string s) const; + // Testable + bool equals(const gtsam::VariableIndex& other, double tol) const; + void print(string s) const; - // Standard interface - size_t size() const; - size_t nFactors() const; - size_t nEntries() const; - }; + // Standard interface + size_t size() const; + size_t nFactors() const; + size_t nEntries() const; +}; - //************************************************************************* - // linear - //************************************************************************* +//************************************************************************* +// linear +//************************************************************************* - namespace noiseModel - { +namespace noiseModel { #include - virtual class Base - { - void print(string s) const; - // Methods below are available for all noise models. However, can't add them - // because wrap (incorrectly) thinks robust classes derive from this Base as well. - // bool isConstrained() const; - // bool isUnit() const; - // size_t dim() const; - // Vector sigmas() const; - }; - - virtual class Gaussian : gtsam::noiseModel::Base - { - static gtsam::noiseModel::Gaussian *Information(Matrix R); - static gtsam::noiseModel::Gaussian *SqrtInformation(Matrix R); - static gtsam::noiseModel::Gaussian *Covariance(Matrix R); - - bool equals(gtsam::noiseModel::Base &expected, double tol); - - // access to noise model - Matrix R() const; - Matrix information() const; - Matrix covariance() const; - - // Whitening operations - Vector whiten(Vector v) const; - Vector unwhiten(Vector v) const; - Matrix Whiten(Matrix H) const; - - // enabling serialization functionality - void serializable() const; - }; - - virtual class Diagonal : gtsam::noiseModel::Gaussian - { - static gtsam::noiseModel::Diagonal *Sigmas(Vector sigmas); - static gtsam::noiseModel::Diagonal *Variances(Vector variances); - static gtsam::noiseModel::Diagonal *Precisions(Vector precisions); - Matrix R() const; - - // access to noise model - Vector sigmas() const; - Vector invsigmas() const; - Vector precisions() const; - - // enabling serialization functionality - void serializable() const; - }; - - virtual class Constrained : gtsam::noiseModel::Diagonal - { - static gtsam::noiseModel::Constrained *MixedSigmas(Vector mu, Vector sigmas); - static gtsam::noiseModel::Constrained *MixedSigmas(double m, Vector sigmas); - static gtsam::noiseModel::Constrained *MixedVariances(Vector mu, Vector variances); - static gtsam::noiseModel::Constrained *MixedVariances(Vector variances); - static gtsam::noiseModel::Constrained *MixedPrecisions(Vector mu, Vector precisions); - static gtsam::noiseModel::Constrained *MixedPrecisions(Vector precisions); - - static gtsam::noiseModel::Constrained *All(size_t dim); - static gtsam::noiseModel::Constrained *All(size_t dim, double mu); - - gtsam::noiseModel::Constrained *unit() const; - - // enabling serialization functionality - void serializable() const; - }; - - virtual class Isotropic : gtsam::noiseModel::Diagonal - { - static gtsam::noiseModel::Isotropic *Sigma(size_t dim, double sigma); - static gtsam::noiseModel::Isotropic *Variance(size_t dim, double varianace); - static gtsam::noiseModel::Isotropic *Precision(size_t dim, double precision); - - // access to noise model - double sigma() const; - - // enabling serialization functionality - void serializable() const; - }; - - virtual class Unit : gtsam::noiseModel::Isotropic - { - static gtsam::noiseModel::Unit *Create(size_t dim); - - // enabling serialization functionality - void serializable() const; - }; - - namespace mEstimator - { - virtual class Base - { - void print(string s) const; - }; - - virtual class Null : gtsam::noiseModel::mEstimator::Base - { - Null(); - static gtsam::noiseModel::mEstimator::Null *Create(); - - // enabling serialization functionality - void serializable() const; - - double weight(double error) const; - double loss(double error) const; - }; - - virtual class Fair : gtsam::noiseModel::mEstimator::Base - { - Fair(double c); - static gtsam::noiseModel::mEstimator::Fair *Create(double c); - - // enabling serialization functionality - void serializable() const; - - double weight(double error) const; - double loss(double error) const; - }; - - virtual class Huber : gtsam::noiseModel::mEstimator::Base - { - Huber(double k); - static gtsam::noiseModel::mEstimator::Huber *Create(double k); - - // enabling serialization functionality - void serializable() const; - - double weight(double error) const; - double loss(double error) const; - }; - - virtual class Cauchy : gtsam::noiseModel::mEstimator::Base - { - Cauchy(double k); - static gtsam::noiseModel::mEstimator::Cauchy *Create(double k); - - // enabling serialization functionality - void serializable() const; - - double weight(double error) const; - double loss(double error) const; - }; - - virtual class Tukey : gtsam::noiseModel::mEstimator::Base - { - Tukey(double k); - static gtsam::noiseModel::mEstimator::Tukey *Create(double k); - - // enabling serialization functionality - void serializable() const; - - double weight(double error) const; - double loss(double error) const; - }; - - virtual class Welsch : gtsam::noiseModel::mEstimator::Base - { - Welsch(double k); - static gtsam::noiseModel::mEstimator::Welsch *Create(double k); - - // enabling serialization functionality - void serializable() const; - - double weight(double error) const; - double loss(double error) const; - }; - - virtual class GemanMcClure : gtsam::noiseModel::mEstimator::Base - { - GemanMcClure(double c); - static gtsam::noiseModel::mEstimator::GemanMcClure *Create(double c); - - // enabling serialization functionality - void serializable() const; - - double weight(double error) const; - double loss(double error) const; - }; - - virtual class DCS : gtsam::noiseModel::mEstimator::Base - { - DCS(double c); - static gtsam::noiseModel::mEstimator::DCS *Create(double c); - - // enabling serialization functionality - void serializable() const; - - double weight(double error) const; - double loss(double error) const; - }; - - virtual class L2WithDeadZone : gtsam::noiseModel::mEstimator::Base - { - L2WithDeadZone(double k); - static gtsam::noiseModel::mEstimator::L2WithDeadZone *Create(double k); - - // enabling serialization functionality - void serializable() const; - - double weight(double error) const; - double loss(double error) const; - }; - - } // namespace mEstimator - - virtual class Robust : gtsam::noiseModel::Base - { - Robust(const gtsam::noiseModel::mEstimator::Base *robust, const gtsam::noiseModel::Base *noise); - static gtsam::noiseModel::Robust *Create(const gtsam::noiseModel::mEstimator::Base *robust, const gtsam::noiseModel::Base *noise); - - // enabling serialization functionality - void serializable() const; - }; - - } // namespace noiseModel - -#include - class Sampler - { - // Constructors - Sampler(gtsam::noiseModel::Diagonal *model, int seed); - Sampler(Vector sigmas, int seed); - - // Standard Interface - size_t dim() const; - Vector sigmas() const; - gtsam::noiseModel::Diagonal *model() const; - Vector sample(); - }; - -#include - class VectorValues - { - //Constructors - VectorValues(); - VectorValues(const gtsam::VectorValues &other); - - //Named Constructors - static gtsam::VectorValues Zero(const gtsam::VectorValues &model); - - //Standard Interface - size_t size() const; - size_t dim(size_t j) const; - bool exists(size_t j) const; - void print(string s) const; - bool equals(const gtsam::VectorValues &expected, double tol) const; - void insert(size_t j, Vector value); - Vector vector() const; - Vector at(size_t j) const; - void update(const gtsam::VectorValues &values); - - //Advanced Interface - void setZero(); - - gtsam::VectorValues add(const gtsam::VectorValues &c) const; - void addInPlace(const gtsam::VectorValues &c); - gtsam::VectorValues subtract(const gtsam::VectorValues &c) const; - gtsam::VectorValues scale(double a) const; - void scaleInPlace(double a); - - bool hasSameStructure(const gtsam::VectorValues &other) const; - double dot(const gtsam::VectorValues &V) const; - double norm() const; - double squaredNorm() const; - - // enabling serialization functionality - void serialize() const; - }; - -#include - virtual class GaussianFactor - { - gtsam::KeyVector keys() const; - void print(string s) const; - bool equals(const gtsam::GaussianFactor &lf, double tol) const; - double error(const gtsam::VectorValues &c) const; - gtsam::GaussianFactor *clone() const; - gtsam::GaussianFactor *negate() const; - Matrix augmentedInformation() const; - Matrix information() const; - Matrix augmentedJacobian() const; - pair jacobian() const; - size_t size() const; - bool empty() const; - }; - -#include - virtual class JacobianFactor : gtsam::GaussianFactor - { - //Constructors - JacobianFactor(); - JacobianFactor(const gtsam::GaussianFactor &factor); - JacobianFactor(Vector b_in); - JacobianFactor(size_t i1, Matrix A1, Vector b, - const gtsam::noiseModel::Diagonal *model); - JacobianFactor(size_t i1, Matrix A1, size_t i2, Matrix A2, Vector b, - const gtsam::noiseModel::Diagonal *model); - JacobianFactor(size_t i1, Matrix A1, size_t i2, Matrix A2, size_t i3, Matrix A3, - Vector b, const gtsam::noiseModel::Diagonal *model); - JacobianFactor(const gtsam::GaussianFactorGraph &graph); - - //Testable - void print(string s) const; - void printKeys(string s) const; - bool equals(const gtsam::GaussianFactor &lf, double tol) const; - size_t size() const; - Vector unweighted_error(const gtsam::VectorValues &c) const; - Vector error_vector(const gtsam::VectorValues &c) const; - double error(const gtsam::VectorValues &c) const; - - //Standard Interface - Matrix getA() const; - Vector getb() const; - size_t rows() const; - size_t cols() const; - bool isConstrained() const; - pair jacobianUnweighted() const; - Matrix augmentedJacobianUnweighted() const; - - void transposeMultiplyAdd(double alpha, Vector e, gtsam::VectorValues &x) const; - gtsam::JacobianFactor whiten() const; - - pair eliminate(const gtsam::Ordering &keys) const; - - void setModel(bool anyConstrained, Vector sigmas); - - gtsam::noiseModel::Diagonal *get_model() const; - - // enabling serialization functionality - void serialize() const; - }; - -#include - virtual class HessianFactor : gtsam::GaussianFactor - { - //Constructors - HessianFactor(); - HessianFactor(const gtsam::GaussianFactor &factor); - HessianFactor(size_t j, Matrix G, Vector g, double f); - HessianFactor(size_t j, Vector mu, Matrix Sigma); - HessianFactor(size_t j1, size_t j2, Matrix G11, Matrix G12, Vector g1, Matrix G22, - Vector g2, double f); - HessianFactor(size_t j1, size_t j2, size_t j3, Matrix G11, Matrix G12, Matrix G13, - Vector g1, Matrix G22, Matrix G23, Vector g2, Matrix G33, Vector g3, - double f); - HessianFactor(const gtsam::GaussianFactorGraph &factors); - - //Testable - size_t size() const; - void print(string s) const; - void printKeys(string s) const; - bool equals(const gtsam::GaussianFactor &lf, double tol) const; - double error(const gtsam::VectorValues &c) const; - - //Standard Interface - size_t rows() const; - Matrix information() const; - double constantTerm() const; - Vector linearTerm() const; - - // enabling serialization functionality - void serialize() const; - }; - -#include - class GaussianFactorGraph - { - GaussianFactorGraph(); - GaussianFactorGraph(const gtsam::GaussianBayesNet &bayesNet); - GaussianFactorGraph(const gtsam::GaussianBayesTree &bayesTree); - - // From FactorGraph - void print(string s) const; - bool equals(const gtsam::GaussianFactorGraph &lfgraph, double tol) const; - size_t size() const; - gtsam::GaussianFactor *at(size_t idx) const; - gtsam::KeySet keys() const; - gtsam::KeyVector keyVector() const; - bool exists(size_t idx) const; - - // Building the graph - void push_back(const gtsam::GaussianFactor *factor); - void push_back(const gtsam::GaussianConditional *conditional); - void push_back(const gtsam::GaussianFactorGraph &graph); - void push_back(const gtsam::GaussianBayesNet &bayesNet); - void push_back(const gtsam::GaussianBayesTree &bayesTree); - void add(const gtsam::GaussianFactor &factor); - void add(Vector b); - void add(size_t key1, Matrix A1, Vector b, const gtsam::noiseModel::Diagonal *model); - void add(size_t key1, Matrix A1, size_t key2, Matrix A2, Vector b, - const gtsam::noiseModel::Diagonal *model); - void add(size_t key1, Matrix A1, size_t key2, Matrix A2, size_t key3, Matrix A3, - Vector b, const gtsam::noiseModel::Diagonal *model); - - // error and probability - double error(const gtsam::VectorValues &c) const; - double probPrime(const gtsam::VectorValues &c) const; - - gtsam::GaussianFactorGraph clone() const; - gtsam::GaussianFactorGraph negate() const; - - // Optimizing and linear algebra - gtsam::VectorValues optimize() const; - gtsam::VectorValues optimize(const gtsam::Ordering &ordering) const; - gtsam::VectorValues optimizeGradientSearch() const; - gtsam::VectorValues gradient(const gtsam::VectorValues &x0) const; - gtsam::VectorValues gradientAtZero() const; - - // Elimination and marginals - gtsam::GaussianBayesNet *eliminateSequential(); - gtsam::GaussianBayesNet *eliminateSequential(const gtsam::Ordering &ordering); - gtsam::GaussianBayesTree *eliminateMultifrontal(); - gtsam::GaussianBayesTree *eliminateMultifrontal(const gtsam::Ordering &ordering); - pair eliminatePartialSequential( - const gtsam::Ordering &ordering); - pair eliminatePartialSequential( - const gtsam::KeyVector &keys); - pair eliminatePartialMultifrontal( - const gtsam::Ordering &ordering); - pair eliminatePartialMultifrontal( - const gtsam::KeyVector &keys); - gtsam::GaussianBayesNet *marginalMultifrontalBayesNet(const gtsam::Ordering &ordering); - gtsam::GaussianBayesNet *marginalMultifrontalBayesNet(const gtsam::KeyVector &key_vector); - gtsam::GaussianBayesNet *marginalMultifrontalBayesNet(const gtsam::Ordering &ordering, - const gtsam::Ordering &marginalizedVariableOrdering); - gtsam::GaussianBayesNet *marginalMultifrontalBayesNet(const gtsam::KeyVector &key_vector, - const gtsam::Ordering &marginalizedVariableOrdering); - gtsam::GaussianFactorGraph *marginal(const gtsam::KeyVector &key_vector); - - // Conversion to matrices - Matrix sparseJacobian_() const; - Matrix augmentedJacobian() const; - Matrix augmentedJacobian(const gtsam::Ordering &ordering) const; - pair jacobian() const; - pair jacobian(const gtsam::Ordering &ordering) const; - Matrix augmentedHessian() const; - Matrix augmentedHessian(const gtsam::Ordering &ordering) const; - pair hessian() const; - pair hessian(const gtsam::Ordering &ordering) const; - - // enabling serialization functionality - void serialize() const; - }; - -#include - virtual class GaussianConditional : gtsam::GaussianFactor - { - //Constructors - GaussianConditional(size_t key, Vector d, Matrix R, const gtsam::noiseModel::Diagonal *sigmas); - GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S, - const gtsam::noiseModel::Diagonal *sigmas); - GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S, - size_t name2, Matrix T, const gtsam::noiseModel::Diagonal *sigmas); - - //Constructors with no noise model - GaussianConditional(size_t key, Vector d, Matrix R); - GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S); - GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S, - size_t name2, Matrix T); - - //Standard Interface - void print(string s) const; - bool equals(const gtsam::GaussianConditional &cg, double tol) const; - - //Advanced Interface - gtsam::VectorValues solve(const gtsam::VectorValues &parents) const; - gtsam::VectorValues solveOtherRHS(const gtsam::VectorValues &parents, const gtsam::VectorValues &rhs) const; - void solveTransposeInPlace(gtsam::VectorValues &gy) const; - void scaleFrontalsBySigma(gtsam::VectorValues &gy) const; - Matrix R() const; - Matrix S() const; - Vector d() const; - - // enabling serialization functionality - void serialize() const; - }; - -#include - virtual class GaussianDensity : gtsam::GaussianConditional - { - //Constructors - GaussianDensity(size_t key, Vector d, Matrix R, const gtsam::noiseModel::Diagonal *sigmas); - - //Standard Interface - void print(string s) const; - bool equals(const gtsam::GaussianDensity &cg, double tol) const; - Vector mean() const; - Matrix covariance() const; - }; - -#include - virtual class GaussianBayesNet - { - //Constructors - GaussianBayesNet(); - GaussianBayesNet(const gtsam::GaussianConditional *conditional); - - // Testable - void print(string s) const; - bool equals(const gtsam::GaussianBayesNet &other, double tol) const; - size_t size() const; - - // FactorGraph derived interface - // size_t size() const; - gtsam::GaussianConditional *at(size_t idx) const; - gtsam::KeySet keys() const; - bool exists(size_t idx) const; - - gtsam::GaussianConditional *front() const; - gtsam::GaussianConditional *back() const; - void push_back(gtsam::GaussianConditional *conditional); - void push_back(const gtsam::GaussianBayesNet &bayesNet); - - gtsam::VectorValues optimize() const; - gtsam::VectorValues optimize(gtsam::VectorValues &solutionForMissing) const; - gtsam::VectorValues optimizeGradientSearch() const; - gtsam::VectorValues gradient(const gtsam::VectorValues &x0) const; - gtsam::VectorValues gradientAtZero() const; - double error(const gtsam::VectorValues &x) const; - double determinant() const; - double logDeterminant() const; - gtsam::VectorValues backSubstitute(const gtsam::VectorValues &gx) const; - gtsam::VectorValues backSubstituteTranspose(const gtsam::VectorValues &gx) const; - }; - -#include - virtual class GaussianBayesTree - { - // Standard Constructors and Named Constructors - GaussianBayesTree(); - GaussianBayesTree(const gtsam::GaussianBayesTree &other); - bool equals(const gtsam::GaussianBayesTree &other, double tol) const; - void print(string s); - size_t size() const; - bool empty() const; - size_t numCachedSeparatorMarginals() const; - void saveGraph(string s) const; - - gtsam::VectorValues optimize() const; - gtsam::VectorValues optimizeGradientSearch() const; - gtsam::VectorValues gradient(const gtsam::VectorValues &x0) const; - gtsam::VectorValues gradientAtZero() const; - double error(const gtsam::VectorValues &x) const; - double determinant() const; - double logDeterminant() const; - Matrix marginalCovariance(size_t key) const; - gtsam::GaussianConditional *marginalFactor(size_t key) const; - gtsam::GaussianFactorGraph *joint(size_t key1, size_t key2) const; - gtsam::GaussianBayesNet *jointBayesNet(size_t key1, size_t key2) const; - }; - -#include - class Errors - { - //Constructors - Errors(); - Errors(const gtsam::VectorValues &V); - - //Testable - void print(string s); - bool equals(const gtsam::Errors &expected, double tol) const; - }; - -#include - class GaussianISAM - { - //Constructor - GaussianISAM(); - - //Standard Interface - void update(const gtsam::GaussianFactorGraph &newFactors); - void saveGraph(string s) const; - void clear(); - }; - -#include - virtual class IterativeOptimizationParameters - { - string getVerbosity() const; - void setVerbosity(string s); - void print() const; - }; - - //virtual class IterativeSolver { - // IterativeSolver(); - // gtsam::VectorValues optimize (); - //}; - -#include - virtual class ConjugateGradientParameters : gtsam::IterativeOptimizationParameters - { - ConjugateGradientParameters(); - int getMinIterations() const; - int getMaxIterations() const; - int getReset() const; - double getEpsilon_rel() const; - double getEpsilon_abs() const; - - void setMinIterations(int value); - void setMaxIterations(int value); - void setReset(int value); - void setEpsilon_rel(double value); - void setEpsilon_abs(double value); - void print() const; - }; - -#include - virtual class PreconditionerParameters - { - PreconditionerParameters(); - }; - - virtual class DummyPreconditionerParameters : gtsam::PreconditionerParameters - { - DummyPreconditionerParameters(); - }; - -#include - virtual class PCGSolverParameters : gtsam::ConjugateGradientParameters - { - PCGSolverParameters(); - void print(string s); - void setPreconditionerParams(gtsam::PreconditionerParameters *preconditioner); - }; - -#include - virtual class SubgraphSolverParameters : gtsam::ConjugateGradientParameters - { - SubgraphSolverParameters(); - void print() const; - }; - - virtual class SubgraphSolver - { - SubgraphSolver(const gtsam::GaussianFactorGraph &A, const gtsam::SubgraphSolverParameters ¶meters, const gtsam::Ordering &ordering); - SubgraphSolver(const gtsam::GaussianFactorGraph &Ab1, const gtsam::GaussianFactorGraph *Ab2, const gtsam::SubgraphSolverParameters ¶meters, const gtsam::Ordering &ordering); - gtsam::VectorValues optimize() const; - }; - -#include - class KalmanFilter - { - KalmanFilter(size_t n); - // gtsam::GaussianDensity* init(Vector x0, const gtsam::SharedDiagonal& P0); - gtsam::GaussianDensity *init(Vector x0, Matrix P0); - void print(string s) const; - static size_t step(gtsam::GaussianDensity *p); - gtsam::GaussianDensity *predict(gtsam::GaussianDensity *p, Matrix F, - Matrix B, Vector u, const gtsam::noiseModel::Diagonal *modelQ); - gtsam::GaussianDensity *predictQ(gtsam::GaussianDensity *p, Matrix F, - Matrix B, Vector u, Matrix Q); - gtsam::GaussianDensity *predict2(gtsam::GaussianDensity *p, Matrix A0, - Matrix A1, Vector b, const gtsam::noiseModel::Diagonal *model); - gtsam::GaussianDensity *update(gtsam::GaussianDensity *p, Matrix H, - Vector z, const gtsam::noiseModel::Diagonal *model); - gtsam::GaussianDensity *updateQ(gtsam::GaussianDensity *p, Matrix H, - Vector z, Matrix Q); - }; - - //************************************************************************* - // nonlinear - //************************************************************************* - -#include - size_t symbol(char chr, size_t index); - char symbolChr(size_t key); - size_t symbolIndex(size_t key); - - namespace symbol_shorthand - { - size_t A(size_t j); - size_t B(size_t j); - size_t C(size_t j); - size_t D(size_t j); - size_t E(size_t j); - size_t F(size_t j); - size_t G(size_t j); - size_t H(size_t j); - size_t I(size_t j); - size_t J(size_t j); - size_t K(size_t j); - size_t L(size_t j); - size_t M(size_t j); - size_t N(size_t j); - size_t O(size_t j); - size_t P(size_t j); - size_t Q(size_t j); - size_t R(size_t j); - size_t S(size_t j); - size_t T(size_t j); - size_t U(size_t j); - size_t V(size_t j); - size_t W(size_t j); - size_t X(size_t j); - size_t Y(size_t j); - size_t Z(size_t j); - } // namespace symbol_shorthand - - // Default keyformatter - void PrintKeyList(const gtsam::KeyList &keys); - void PrintKeyList(const gtsam::KeyList &keys, string s); - void PrintKeyVector(const gtsam::KeyVector &keys); - void PrintKeyVector(const gtsam::KeyVector &keys, string s); - void PrintKeySet(const gtsam::KeySet &keys); - void PrintKeySet(const gtsam::KeySet &keys, string s); - -#include - class LabeledSymbol - { - LabeledSymbol(size_t full_key); - LabeledSymbol(const gtsam::LabeledSymbol &key); - LabeledSymbol(unsigned char valType, unsigned char label, size_t j); - - size_t key() const; - unsigned char label() const; - unsigned char chr() const; - size_t index() const; - - gtsam::LabeledSymbol upper() const; - gtsam::LabeledSymbol lower() const; - gtsam::LabeledSymbol newChr(unsigned char c) const; - gtsam::LabeledSymbol newLabel(unsigned char label) const; - - void print(string s) const; - }; - - size_t mrsymbol(unsigned char c, unsigned char label, size_t j); - unsigned char mrsymbolChr(size_t key); - unsigned char mrsymbolLabel(size_t key); - size_t mrsymbolIndex(size_t key); - -#include - class Ordering - { - // Standard Constructors and Named Constructors - Ordering(); - Ordering(const gtsam::Ordering &other); - - // Testable - void print(string s) const; - bool equals(const gtsam::Ordering &ord, double tol) const; - - // Standard interface - size_t size() const; - size_t at(size_t key) const; - void push_back(size_t key); - - // enabling serialization functionality - void serialize() const; - }; - -#include - class NonlinearFactorGraph - { - NonlinearFactorGraph(); - NonlinearFactorGraph(const gtsam::NonlinearFactorGraph &graph); - - // FactorGraph - void print(string s) const; - bool equals(const gtsam::NonlinearFactorGraph &fg, double tol) const; - size_t size() const; - bool empty() const; - void remove(size_t i); - void replace(size_t i, gtsam::NonlinearFactor *factors); - void resize(size_t size); - size_t nrFactors() const; - gtsam::NonlinearFactor *at(size_t idx) const; - void push_back(const gtsam::NonlinearFactorGraph &factors); - void push_back(gtsam::NonlinearFactor *factor); - void add(gtsam::NonlinearFactor *factor); - bool exists(size_t idx) const; - gtsam::KeySet keys() const; - gtsam::KeyVector keyVector() const; - - template , gtsam::imuBias::ConstantBias}> - void addPrior(size_t key, const T &prior, const gtsam::noiseModel::Base *noiseModel); - - // NonlinearFactorGraph - void printErrors(const gtsam::Values &values) const; - double error(const gtsam::Values &values) const; - double probPrime(const gtsam::Values &values) const; - gtsam::Ordering orderingCOLAMD() const; - // Ordering* orderingCOLAMDConstrained(const gtsam::Values& c, const std::map& constraints) const; - gtsam::GaussianFactorGraph *linearize(const gtsam::Values &values) const; - gtsam::NonlinearFactorGraph clone() const; - - // enabling serialization functionality - void serialize() const; - }; - -#include - virtual class NonlinearFactor - { - // Factor base class - size_t size() const; - gtsam::KeyVector keys() const; - void print(string s) const; - void printKeys(string s) const; - // NonlinearFactor - bool equals(const gtsam::NonlinearFactor &other, double tol) const; - double error(const gtsam::Values &c) const; - size_t dim() const; - bool active(const gtsam::Values &c) const; - gtsam::GaussianFactor *linearize(const gtsam::Values &c) const; - gtsam::NonlinearFactor *clone() const; - // gtsam::NonlinearFactor* rekey(const gtsam::KeyVector& newKeys) const; //TODO: Conversion from KeyVector to std::vector does not happen - }; - -#include - virtual class NoiseModelFactor : gtsam::NonlinearFactor - { - bool equals(const gtsam::NoiseModelFactor &other, double tol) const; - gtsam::noiseModel::Base *noiseModel() const; - Vector unwhitenedError(const gtsam::Values &x) const; - Vector whitenedError(const gtsam::Values &x) const; - }; - -#include - class Values - { - Values(); - Values(const gtsam::Values &other); - - size_t size() const; - bool empty() const; - void clear(); - size_t dim() const; - - void print(string s) const; - bool equals(const gtsam::Values &other, double tol) const; - - void insert(const gtsam::Values &values); - void update(const gtsam::Values &values); - void erase(size_t j); - void swap(gtsam::Values &values); - - bool exists(size_t j) const; - gtsam::KeyVector keys() const; - - gtsam::VectorValues zeroVectors() const; - - gtsam::Values retract(const gtsam::VectorValues &delta) const; - gtsam::VectorValues localCoordinates(const gtsam::Values &cp) const; - - // enabling serialization functionality - void serialize() const; - - // New in 4.0, we have to specialize every insert/update/at to generate wrappers - // Instead of the old: - // void insert(size_t j, const gtsam::Value& value); - // void update(size_t j, const gtsam::Value& val); - // gtsam::Value at(size_t j) const; - - // The order is important: Vector has to precede Point2/Point3 so `atVector` - // can work for those fixed-size vectors. - void insert(size_t j, Vector vector); - void insert(size_t j, Matrix matrix); - void insert(size_t j, const gtsam::Point2 &point2); - void insert(size_t j, const gtsam::Point3 &point3); - void insert(size_t j, const gtsam::Rot2 &rot2); - void insert(size_t j, const gtsam::Pose2 &pose2); - void insert(size_t j, const gtsam::SO3 &R); - void insert(size_t j, const gtsam::SO4 &Q); - void insert(size_t j, const gtsam::SOn &P); - void insert(size_t j, const gtsam::Rot3 &rot3); - void insert(size_t j, const gtsam::Pose3 &pose3); - void insert(size_t j, const gtsam::Unit3 &unit3); - void insert(size_t j, const gtsam::Cal3_S2 &cal3_s2); - void insert(size_t j, const gtsam::Cal3DS2 &cal3ds2); - void insert(size_t j, const gtsam::Cal3Bundler &cal3bundler); - void insert(size_t j, const gtsam::EssentialMatrix &essential_matrix); - void insert(size_t j, const gtsam::PinholeCameraCal3_S2 &simple_camera); - void insert(size_t j, const gtsam::PinholeCamera &camera); - void insert(size_t j, const gtsam::imuBias::ConstantBias &constant_bias); - void insert(size_t j, const gtsam::NavState &nav_state); - - void update(size_t j, const gtsam::Point2 &point2); - void update(size_t j, const gtsam::Point3 &point3); - void update(size_t j, const gtsam::Rot2 &rot2); - void update(size_t j, const gtsam::Pose2 &pose2); - void update(size_t j, const gtsam::SO3 &R); - void update(size_t j, const gtsam::SO4 &Q); - void update(size_t j, const gtsam::SOn &P); - void update(size_t j, const gtsam::Rot3 &rot3); - void update(size_t j, const gtsam::Pose3 &pose3); - void update(size_t j, const gtsam::Unit3 &unit3); - void update(size_t j, const gtsam::Cal3_S2 &cal3_s2); - void update(size_t j, const gtsam::Cal3DS2 &cal3ds2); - void update(size_t j, const gtsam::Cal3Bundler &cal3bundler); - void update(size_t j, const gtsam::EssentialMatrix &essential_matrix); - void update(size_t j, const gtsam::PinholeCameraCal3_S2 &simple_camera); - void update(size_t j, const gtsam::PinholeCamera &camera); - void update(size_t j, const gtsam::imuBias::ConstantBias &constant_bias); - void update(size_t j, const gtsam::NavState &nav_state); - void update(size_t j, Vector vector); - void update(size_t j, Matrix matrix); - - template , gtsam::imuBias::ConstantBias, gtsam::NavState, Vector, Matrix}> - T at(size_t j); - - /// version for double - void insertDouble(size_t j, double c); - double atDouble(size_t j) const; - }; - -#include - class Marginals - { - Marginals(const gtsam::NonlinearFactorGraph &graph, - const gtsam::Values &solution); - Marginals(const gtsam::GaussianFactorGraph &gfgraph, - const gtsam::Values &solution); - Marginals(const gtsam::GaussianFactorGraph &gfgraph, - const gtsam::VectorValues &solutionvec); - - void print(string s) const; - Matrix marginalCovariance(size_t variable) const; - Matrix marginalInformation(size_t variable) const; - gtsam::JointMarginal jointMarginalCovariance(const gtsam::KeyVector &variables) const; - gtsam::JointMarginal jointMarginalInformation(const gtsam::KeyVector &variables) const; - }; - - class JointMarginal - { - Matrix at(size_t iVariable, size_t jVariable) const; - Matrix fullMatrix() const; - void print(string s) const; - void print() const; - }; - -#include - virtual class LinearContainerFactor : gtsam::NonlinearFactor - { - - LinearContainerFactor(gtsam::GaussianFactor *factor, const gtsam::Values &linearizationPoint); - LinearContainerFactor(gtsam::GaussianFactor *factor); - - gtsam::GaussianFactor *factor() const; - // const boost::optional& linearizationPoint() const; - - bool isJacobian() const; - gtsam::JacobianFactor *toJacobian() const; - gtsam::HessianFactor *toHessian() const; - - static gtsam::NonlinearFactorGraph ConvertLinearGraph(const gtsam::GaussianFactorGraph &linear_graph, - const gtsam::Values &linearizationPoint); - - static gtsam::NonlinearFactorGraph ConvertLinearGraph(const gtsam::GaussianFactorGraph &linear_graph); +virtual class Base { + void print(string s) const; + // Methods below are available for all noise models. However, can't add them + // because wrap (incorrectly) thinks robust classes derive from this Base as well. + // bool isConstrained() const; + // bool isUnit() const; + // size_t dim() const; + // Vector sigmas() const; +}; + +virtual class Gaussian : gtsam::noiseModel::Base { + static gtsam::noiseModel::Gaussian* Information(Matrix R); + static gtsam::noiseModel::Gaussian* SqrtInformation(Matrix R); + static gtsam::noiseModel::Gaussian* Covariance(Matrix R); + + bool equals(gtsam::noiseModel::Base& expected, double tol); + + // access to noise model + Matrix R() const; + Matrix information() const; + Matrix covariance() const; + + // Whitening operations + Vector whiten(Vector v) const; + Vector unwhiten(Vector v) const; + Matrix Whiten(Matrix H) const; + + // enabling serialization functionality + void serializable() const; +}; + +virtual class Diagonal : gtsam::noiseModel::Gaussian { + static gtsam::noiseModel::Diagonal* Sigmas(Vector sigmas); + static gtsam::noiseModel::Diagonal* Variances(Vector variances); + static gtsam::noiseModel::Diagonal* Precisions(Vector precisions); + Matrix R() const; + + // access to noise model + Vector sigmas() const; + Vector invsigmas() const; + Vector precisions() const; + + // enabling serialization functionality + void serializable() const; +}; + +virtual class Constrained : gtsam::noiseModel::Diagonal { + static gtsam::noiseModel::Constrained* MixedSigmas(Vector mu, Vector sigmas); + static gtsam::noiseModel::Constrained* MixedSigmas(double m, Vector sigmas); + static gtsam::noiseModel::Constrained* MixedVariances(Vector mu, Vector variances); + static gtsam::noiseModel::Constrained* MixedVariances(Vector variances); + static gtsam::noiseModel::Constrained* MixedPrecisions(Vector mu, Vector precisions); + static gtsam::noiseModel::Constrained* MixedPrecisions(Vector precisions); + + static gtsam::noiseModel::Constrained* All(size_t dim); + static gtsam::noiseModel::Constrained* All(size_t dim, double mu); + + gtsam::noiseModel::Constrained* unit() const; // enabling serialization functionality void serializable() const; - }; // \class LinearContainerFactor +}; + +virtual class Isotropic : gtsam::noiseModel::Diagonal { + static gtsam::noiseModel::Isotropic* Sigma(size_t dim, double sigma); + static gtsam::noiseModel::Isotropic* Variance(size_t dim, double varianace); + static gtsam::noiseModel::Isotropic* Precision(size_t dim, double precision); + + // access to noise model + double sigma() const; + + // enabling serialization functionality + void serializable() const; +}; + +virtual class Unit : gtsam::noiseModel::Isotropic { + static gtsam::noiseModel::Unit* Create(size_t dim); + + // enabling serialization functionality + void serializable() const; +}; + +namespace mEstimator { +virtual class Base { + void print(string s) const; +}; + +virtual class Null: gtsam::noiseModel::mEstimator::Base { + Null(); + static gtsam::noiseModel::mEstimator::Null* Create(); + + // enabling serialization functionality + void serializable() const; + + double weight(double error) const; + double loss(double error) const; +}; + +virtual class Fair: gtsam::noiseModel::mEstimator::Base { + Fair(double c); + static gtsam::noiseModel::mEstimator::Fair* Create(double c); + + // enabling serialization functionality + void serializable() const; + + double weight(double error) const; + double loss(double error) const; +}; + +virtual class Huber: gtsam::noiseModel::mEstimator::Base { + Huber(double k); + static gtsam::noiseModel::mEstimator::Huber* Create(double k); + + // enabling serialization functionality + void serializable() const; + + double weight(double error) const; + double loss(double error) const; +}; + +virtual class Cauchy: gtsam::noiseModel::mEstimator::Base { + Cauchy(double k); + static gtsam::noiseModel::mEstimator::Cauchy* Create(double k); + + // enabling serialization functionality + void serializable() const; + + double weight(double error) const; + double loss(double error) const; +}; + +virtual class Tukey: gtsam::noiseModel::mEstimator::Base { + Tukey(double k); + static gtsam::noiseModel::mEstimator::Tukey* Create(double k); + + // enabling serialization functionality + void serializable() const; + + double weight(double error) const; + double loss(double error) const; +}; + +virtual class Welsch: gtsam::noiseModel::mEstimator::Base { + Welsch(double k); + static gtsam::noiseModel::mEstimator::Welsch* Create(double k); + + // enabling serialization functionality + void serializable() const; + + double weight(double error) const; + double loss(double error) const; +}; + +virtual class GemanMcClure: gtsam::noiseModel::mEstimator::Base { + GemanMcClure(double c); + static gtsam::noiseModel::mEstimator::GemanMcClure* Create(double c); + + // enabling serialization functionality + void serializable() const; + + double weight(double error) const; + double loss(double error) const; +}; + +virtual class DCS: gtsam::noiseModel::mEstimator::Base { + DCS(double c); + static gtsam::noiseModel::mEstimator::DCS* Create(double c); + + // enabling serialization functionality + void serializable() const; + + double weight(double error) const; + double loss(double error) const; +}; + +virtual class L2WithDeadZone: gtsam::noiseModel::mEstimator::Base { + L2WithDeadZone(double k); + static gtsam::noiseModel::mEstimator::L2WithDeadZone* Create(double k); + + // enabling serialization functionality + void serializable() const; + + double weight(double error) const; + double loss(double error) const; +}; + +}///\namespace mEstimator + +virtual class Robust : gtsam::noiseModel::Base { + Robust(const gtsam::noiseModel::mEstimator::Base* robust, const gtsam::noiseModel::Base* noise); + static gtsam::noiseModel::Robust* Create(const gtsam::noiseModel::mEstimator::Base* robust, const gtsam::noiseModel::Base* noise); + + // enabling serialization functionality + void serializable() const; +}; + +}///\namespace noiseModel + +#include +class Sampler { + // Constructors + Sampler(gtsam::noiseModel::Diagonal* model, int seed); + Sampler(Vector sigmas, int seed); + + // Standard Interface + size_t dim() const; + Vector sigmas() const; + gtsam::noiseModel::Diagonal* model() const; + Vector sample(); +}; + +#include +class VectorValues { + //Constructors + VectorValues(); + VectorValues(const gtsam::VectorValues& other); + + //Named Constructors + static gtsam::VectorValues Zero(const gtsam::VectorValues& model); + + //Standard Interface + size_t size() const; + size_t dim(size_t j) const; + bool exists(size_t j) const; + void print(string s) const; + bool equals(const gtsam::VectorValues& expected, double tol) const; + void insert(size_t j, Vector value); + Vector vector() const; + Vector at(size_t j) const; + void update(const gtsam::VectorValues& values); + + //Advanced Interface + void setZero(); + + gtsam::VectorValues add(const gtsam::VectorValues& c) const; + void addInPlace(const gtsam::VectorValues& c); + gtsam::VectorValues subtract(const gtsam::VectorValues& c) const; + gtsam::VectorValues scale(double a) const; + void scaleInPlace(double a); + + bool hasSameStructure(const gtsam::VectorValues& other) const; + double dot(const gtsam::VectorValues& V) const; + double norm() const; + double squaredNorm() const; + + // enabling serialization functionality + void serialize() const; +}; + +#include +virtual class GaussianFactor { + gtsam::KeyVector keys() const; + void print(string s) const; + bool equals(const gtsam::GaussianFactor& lf, double tol) const; + double error(const gtsam::VectorValues& c) const; + gtsam::GaussianFactor* clone() const; + gtsam::GaussianFactor* negate() const; + Matrix augmentedInformation() const; + Matrix information() const; + Matrix augmentedJacobian() const; + pair jacobian() const; + size_t size() const; + bool empty() const; +}; + +#include +virtual class JacobianFactor : gtsam::GaussianFactor { + //Constructors + JacobianFactor(); + JacobianFactor(const gtsam::GaussianFactor& factor); + JacobianFactor(Vector b_in); + JacobianFactor(size_t i1, Matrix A1, Vector b, + const gtsam::noiseModel::Diagonal* model); + JacobianFactor(size_t i1, Matrix A1, size_t i2, Matrix A2, Vector b, + const gtsam::noiseModel::Diagonal* model); + JacobianFactor(size_t i1, Matrix A1, size_t i2, Matrix A2, size_t i3, Matrix A3, + Vector b, const gtsam::noiseModel::Diagonal* model); + JacobianFactor(const gtsam::GaussianFactorGraph& graph); + + //Testable + void print(string s) const; + void printKeys(string s) const; + bool equals(const gtsam::GaussianFactor& lf, double tol) const; + size_t size() const; + Vector unweighted_error(const gtsam::VectorValues& c) const; + Vector error_vector(const gtsam::VectorValues& c) const; + double error(const gtsam::VectorValues& c) const; + + //Standard Interface + Matrix getA() const; + Vector getb() const; + size_t rows() const; + size_t cols() const; + bool isConstrained() const; + pair jacobianUnweighted() const; + Matrix augmentedJacobianUnweighted() const; + + void transposeMultiplyAdd(double alpha, Vector e, gtsam::VectorValues& x) const; + gtsam::JacobianFactor whiten() const; + + pair eliminate(const gtsam::Ordering& keys) const; + + void setModel(bool anyConstrained, Vector sigmas); + + gtsam::noiseModel::Diagonal* get_model() const; + + // enabling serialization functionality + void serialize() const; +}; + +#include +virtual class HessianFactor : gtsam::GaussianFactor { + //Constructors + HessianFactor(); + HessianFactor(const gtsam::GaussianFactor& factor); + HessianFactor(size_t j, Matrix G, Vector g, double f); + HessianFactor(size_t j, Vector mu, Matrix Sigma); + HessianFactor(size_t j1, size_t j2, Matrix G11, Matrix G12, Vector g1, Matrix G22, + Vector g2, double f); + HessianFactor(size_t j1, size_t j2, size_t j3, Matrix G11, Matrix G12, Matrix G13, + Vector g1, Matrix G22, Matrix G23, Vector g2, Matrix G33, Vector g3, + double f); + HessianFactor(const gtsam::GaussianFactorGraph& factors); + + //Testable + size_t size() const; + void print(string s) const; + void printKeys(string s) const; + bool equals(const gtsam::GaussianFactor& lf, double tol) const; + double error(const gtsam::VectorValues& c) const; + + //Standard Interface + size_t rows() const; + Matrix information() const; + double constantTerm() const; + Vector linearTerm() const; + + // enabling serialization functionality + void serialize() const; +}; + +#include +class GaussianFactorGraph { + GaussianFactorGraph(); + GaussianFactorGraph(const gtsam::GaussianBayesNet& bayesNet); + GaussianFactorGraph(const gtsam::GaussianBayesTree& bayesTree); + + // From FactorGraph + void print(string s) const; + bool equals(const gtsam::GaussianFactorGraph& lfgraph, double tol) const; + size_t size() const; + gtsam::GaussianFactor* at(size_t idx) const; + gtsam::KeySet keys() const; + gtsam::KeyVector keyVector() const; + bool exists(size_t idx) const; + + // Building the graph + void push_back(const gtsam::GaussianFactor* factor); + void push_back(const gtsam::GaussianConditional* conditional); + void push_back(const gtsam::GaussianFactorGraph& graph); + void push_back(const gtsam::GaussianBayesNet& bayesNet); + void push_back(const gtsam::GaussianBayesTree& bayesTree); + void add(const gtsam::GaussianFactor& factor); + void add(Vector b); + void add(size_t key1, Matrix A1, Vector b, const gtsam::noiseModel::Diagonal* model); + void add(size_t key1, Matrix A1, size_t key2, Matrix A2, Vector b, + const gtsam::noiseModel::Diagonal* model); + void add(size_t key1, Matrix A1, size_t key2, Matrix A2, size_t key3, Matrix A3, + Vector b, const gtsam::noiseModel::Diagonal* model); + + // error and probability + double error(const gtsam::VectorValues& c) const; + double probPrime(const gtsam::VectorValues& c) const; + + gtsam::GaussianFactorGraph clone() const; + gtsam::GaussianFactorGraph negate() const; + + // Optimizing and linear algebra + gtsam::VectorValues optimize() const; + gtsam::VectorValues optimize(const gtsam::Ordering& ordering) const; + gtsam::VectorValues optimizeGradientSearch() const; + gtsam::VectorValues gradient(const gtsam::VectorValues& x0) const; + gtsam::VectorValues gradientAtZero() const; + + // Elimination and marginals + gtsam::GaussianBayesNet* eliminateSequential(); + gtsam::GaussianBayesNet* eliminateSequential(const gtsam::Ordering& ordering); + gtsam::GaussianBayesTree* eliminateMultifrontal(); + gtsam::GaussianBayesTree* eliminateMultifrontal(const gtsam::Ordering& ordering); + pair eliminatePartialSequential( + const gtsam::Ordering& ordering); + pair eliminatePartialSequential( + const gtsam::KeyVector& keys); + pair eliminatePartialMultifrontal( + const gtsam::Ordering& ordering); + pair eliminatePartialMultifrontal( + const gtsam::KeyVector& keys); + gtsam::GaussianBayesNet* marginalMultifrontalBayesNet(const gtsam::Ordering& ordering); + gtsam::GaussianBayesNet* marginalMultifrontalBayesNet(const gtsam::KeyVector& key_vector); + gtsam::GaussianBayesNet* marginalMultifrontalBayesNet(const gtsam::Ordering& ordering, + const gtsam::Ordering& marginalizedVariableOrdering); + gtsam::GaussianBayesNet* marginalMultifrontalBayesNet(const gtsam::KeyVector& key_vector, + const gtsam::Ordering& marginalizedVariableOrdering); + gtsam::GaussianFactorGraph* marginal(const gtsam::KeyVector& key_vector); + + // Conversion to matrices + Matrix sparseJacobian_() const; + Matrix augmentedJacobian() const; + Matrix augmentedJacobian(const gtsam::Ordering& ordering) const; + pair jacobian() const; + pair jacobian(const gtsam::Ordering& ordering) const; + Matrix augmentedHessian() const; + Matrix augmentedHessian(const gtsam::Ordering& ordering) const; + pair hessian() const; + pair hessian(const gtsam::Ordering& ordering) const; + + // enabling serialization functionality + void serialize() const; +}; + +#include +virtual class GaussianConditional : gtsam::GaussianFactor { + //Constructors + GaussianConditional(size_t key, Vector d, Matrix R, const gtsam::noiseModel::Diagonal* sigmas); + GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S, + const gtsam::noiseModel::Diagonal* sigmas); + GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S, + size_t name2, Matrix T, const gtsam::noiseModel::Diagonal* sigmas); + + //Constructors with no noise model + GaussianConditional(size_t key, Vector d, Matrix R); + GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S); + GaussianConditional(size_t key, Vector d, Matrix R, size_t name1, Matrix S, + size_t name2, Matrix T); + + //Standard Interface + void print(string s) const; + bool equals(const gtsam::GaussianConditional &cg, double tol) const; + + //Advanced Interface + gtsam::VectorValues solve(const gtsam::VectorValues& parents) const; + gtsam::VectorValues solveOtherRHS(const gtsam::VectorValues& parents, const gtsam::VectorValues& rhs) const; + void solveTransposeInPlace(gtsam::VectorValues& gy) const; + void scaleFrontalsBySigma(gtsam::VectorValues& gy) const; + Matrix R() const; + Matrix S() const; + Vector d() const; + + // enabling serialization functionality + void serialize() const; +}; + +#include +virtual class GaussianDensity : gtsam::GaussianConditional { + //Constructors + GaussianDensity(size_t key, Vector d, Matrix R, const gtsam::noiseModel::Diagonal* sigmas); + + //Standard Interface + void print(string s) const; + bool equals(const gtsam::GaussianDensity &cg, double tol) const; + Vector mean() const; + Matrix covariance() const; +}; + +#include +virtual class GaussianBayesNet { + //Constructors + GaussianBayesNet(); + GaussianBayesNet(const gtsam::GaussianConditional* conditional); + + // Testable + void print(string s) const; + bool equals(const gtsam::GaussianBayesNet& other, double tol) const; + size_t size() const; + + // FactorGraph derived interface + // size_t size() const; + gtsam::GaussianConditional* at(size_t idx) const; + gtsam::KeySet keys() const; + bool exists(size_t idx) const; + + gtsam::GaussianConditional* front() const; + gtsam::GaussianConditional* back() const; + void push_back(gtsam::GaussianConditional* conditional); + void push_back(const gtsam::GaussianBayesNet& bayesNet); + + gtsam::VectorValues optimize() const; + gtsam::VectorValues optimize(gtsam::VectorValues& solutionForMissing) const; + gtsam::VectorValues optimizeGradientSearch() const; + gtsam::VectorValues gradient(const gtsam::VectorValues& x0) const; + gtsam::VectorValues gradientAtZero() const; + double error(const gtsam::VectorValues& x) const; + double determinant() const; + double logDeterminant() const; + gtsam::VectorValues backSubstitute(const gtsam::VectorValues& gx) const; + gtsam::VectorValues backSubstituteTranspose(const gtsam::VectorValues& gx) const; +}; + +#include +virtual class GaussianBayesTree { + // Standard Constructors and Named Constructors + GaussianBayesTree(); + GaussianBayesTree(const gtsam::GaussianBayesTree& other); + bool equals(const gtsam::GaussianBayesTree& other, double tol) const; + void print(string s); + size_t size() const; + bool empty() const; + size_t numCachedSeparatorMarginals() const; + void saveGraph(string s) const; + + gtsam::VectorValues optimize() const; + gtsam::VectorValues optimizeGradientSearch() const; + gtsam::VectorValues gradient(const gtsam::VectorValues& x0) const; + gtsam::VectorValues gradientAtZero() const; + double error(const gtsam::VectorValues& x) const; + double determinant() const; + double logDeterminant() const; + Matrix marginalCovariance(size_t key) const; + gtsam::GaussianConditional* marginalFactor(size_t key) const; + gtsam::GaussianFactorGraph* joint(size_t key1, size_t key2) const; + gtsam::GaussianBayesNet* jointBayesNet(size_t key1, size_t key2) const; +}; + +#include +class Errors { + //Constructors + Errors(); + Errors(const gtsam::VectorValues& V); + + //Testable + void print(string s); + bool equals(const gtsam::Errors& expected, double tol) const; +}; + +#include +class GaussianISAM { + //Constructor + GaussianISAM(); + + //Standard Interface + void update(const gtsam::GaussianFactorGraph& newFactors); + void saveGraph(string s) const; + void clear(); +}; + +#include +virtual class IterativeOptimizationParameters { + string getVerbosity() const; + void setVerbosity(string s) ; + void print() const; +}; + +//virtual class IterativeSolver { +// IterativeSolver(); +// gtsam::VectorValues optimize (); +//}; + +#include +virtual class ConjugateGradientParameters : gtsam::IterativeOptimizationParameters { + ConjugateGradientParameters(); + int getMinIterations() const ; + int getMaxIterations() const ; + int getReset() const; + double getEpsilon_rel() const; + double getEpsilon_abs() const; + + void setMinIterations(int value); + void setMaxIterations(int value); + void setReset(int value); + void setEpsilon_rel(double value); + void setEpsilon_abs(double value); + void print() const; +}; + +#include +virtual class PreconditionerParameters { + PreconditionerParameters(); +}; + +virtual class DummyPreconditionerParameters : gtsam::PreconditionerParameters { + DummyPreconditionerParameters(); +}; + +#include +virtual class PCGSolverParameters : gtsam::ConjugateGradientParameters { + PCGSolverParameters(); + void print(string s); + void setPreconditionerParams(gtsam::PreconditionerParameters* preconditioner); +}; + +#include +virtual class SubgraphSolverParameters : gtsam::ConjugateGradientParameters { + SubgraphSolverParameters(); + void print() const; +}; + +virtual class SubgraphSolver { + SubgraphSolver(const gtsam::GaussianFactorGraph &A, const gtsam::SubgraphSolverParameters ¶meters, const gtsam::Ordering& ordering); + SubgraphSolver(const gtsam::GaussianFactorGraph &Ab1, const gtsam::GaussianFactorGraph* Ab2, const gtsam::SubgraphSolverParameters ¶meters, const gtsam::Ordering& ordering); + gtsam::VectorValues optimize() const; +}; + +#include +class KalmanFilter { + KalmanFilter(size_t n); + // gtsam::GaussianDensity* init(Vector x0, const gtsam::SharedDiagonal& P0); + gtsam::GaussianDensity* init(Vector x0, Matrix P0); + void print(string s) const; + static size_t step(gtsam::GaussianDensity* p); + gtsam::GaussianDensity* predict(gtsam::GaussianDensity* p, Matrix F, + Matrix B, Vector u, const gtsam::noiseModel::Diagonal* modelQ); + gtsam::GaussianDensity* predictQ(gtsam::GaussianDensity* p, Matrix F, + Matrix B, Vector u, Matrix Q); + gtsam::GaussianDensity* predict2(gtsam::GaussianDensity* p, Matrix A0, + Matrix A1, Vector b, const gtsam::noiseModel::Diagonal* model); + gtsam::GaussianDensity* update(gtsam::GaussianDensity* p, Matrix H, + Vector z, const gtsam::noiseModel::Diagonal* model); + gtsam::GaussianDensity* updateQ(gtsam::GaussianDensity* p, Matrix H, + Vector z, Matrix Q); +}; + +//************************************************************************* +// nonlinear +//************************************************************************* + +#include +size_t symbol(char chr, size_t index); +char symbolChr(size_t key); +size_t symbolIndex(size_t key); + +namespace symbol_shorthand { + size_t A(size_t j); + size_t B(size_t j); + size_t C(size_t j); + size_t D(size_t j); + size_t E(size_t j); + size_t F(size_t j); + size_t G(size_t j); + size_t H(size_t j); + size_t I(size_t j); + size_t J(size_t j); + size_t K(size_t j); + size_t L(size_t j); + size_t M(size_t j); + size_t N(size_t j); + size_t O(size_t j); + size_t P(size_t j); + size_t Q(size_t j); + size_t R(size_t j); + size_t S(size_t j); + size_t T(size_t j); + size_t U(size_t j); + size_t V(size_t j); + size_t W(size_t j); + size_t X(size_t j); + size_t Y(size_t j); + size_t Z(size_t j); +}///\namespace symbol + +// Default keyformatter +void PrintKeyList (const gtsam::KeyList& keys); +void PrintKeyList (const gtsam::KeyList& keys, string s); +void PrintKeyVector(const gtsam::KeyVector& keys); +void PrintKeyVector(const gtsam::KeyVector& keys, string s); +void PrintKeySet (const gtsam::KeySet& keys); +void PrintKeySet (const gtsam::KeySet& keys, string s); + +#include +class LabeledSymbol { + LabeledSymbol(size_t full_key); + LabeledSymbol(const gtsam::LabeledSymbol& key); + LabeledSymbol(unsigned char valType, unsigned char label, size_t j); + + size_t key() const; + unsigned char label() const; + unsigned char chr() const; + size_t index() const; + + gtsam::LabeledSymbol upper() const; + gtsam::LabeledSymbol lower() const; + gtsam::LabeledSymbol newChr(unsigned char c) const; + gtsam::LabeledSymbol newLabel(unsigned char label) const; + + void print(string s) const; +}; + +size_t mrsymbol(unsigned char c, unsigned char label, size_t j); +unsigned char mrsymbolChr(size_t key); +unsigned char mrsymbolLabel(size_t key); +size_t mrsymbolIndex(size_t key); + +#include +class Ordering { + // Standard Constructors and Named Constructors + Ordering(); + Ordering(const gtsam::Ordering& other); + + // Testable + void print(string s) const; + bool equals(const gtsam::Ordering& ord, double tol) const; + + // Standard interface + size_t size() const; + size_t at(size_t key) const; + void push_back(size_t key); + + // enabling serialization functionality + void serialize() const; +}; + +#include +class NonlinearFactorGraph { + NonlinearFactorGraph(); + NonlinearFactorGraph(const gtsam::NonlinearFactorGraph& graph); + + // FactorGraph + void print(string s) const; + bool equals(const gtsam::NonlinearFactorGraph& fg, double tol) const; + size_t size() const; + bool empty() const; + void remove(size_t i); + void replace(size_t i, gtsam::NonlinearFactor* factors); + void resize(size_t size); + size_t nrFactors() const; + gtsam::NonlinearFactor* at(size_t idx) const; + void push_back(const gtsam::NonlinearFactorGraph& factors); + void push_back(gtsam::NonlinearFactor* factor); + void add(gtsam::NonlinearFactor* factor); + bool exists(size_t idx) const; + gtsam::KeySet keys() const; + gtsam::KeyVector keyVector() const; + + template, gtsam::imuBias::ConstantBias}> + void addPrior(size_t key, const T& prior, const gtsam::noiseModel::Base* noiseModel); + + // NonlinearFactorGraph + void printErrors(const gtsam::Values& values) const; + double error(const gtsam::Values& values) const; + double probPrime(const gtsam::Values& values) const; + gtsam::Ordering orderingCOLAMD() const; + // Ordering* orderingCOLAMDConstrained(const gtsam::Values& c, const std::map& constraints) const; + gtsam::GaussianFactorGraph* linearize(const gtsam::Values& values) const; + gtsam::NonlinearFactorGraph clone() const; + + // enabling serialization functionality + void serialize() const; +}; + +#include +virtual class NonlinearFactor { + // Factor base class + size_t size() const; + gtsam::KeyVector keys() const; + void print(string s) const; + void printKeys(string s) const; + // NonlinearFactor + bool equals(const gtsam::NonlinearFactor& other, double tol) const; + double error(const gtsam::Values& c) const; + size_t dim() const; + bool active(const gtsam::Values& c) const; + gtsam::GaussianFactor* linearize(const gtsam::Values& c) const; + gtsam::NonlinearFactor* clone() const; + // gtsam::NonlinearFactor* rekey(const gtsam::KeyVector& newKeys) const; //TODO: Conversion from KeyVector to std::vector does not happen +}; + +#include +virtual class NoiseModelFactor: gtsam::NonlinearFactor { + bool equals(const gtsam::NoiseModelFactor& other, double tol) const; + gtsam::noiseModel::Base* noiseModel() const; + Vector unwhitenedError(const gtsam::Values& x) const; + Vector whitenedError(const gtsam::Values& x) const; +}; + +#include +class Values { + Values(); + Values(const gtsam::Values& other); + + size_t size() const; + bool empty() const; + void clear(); + size_t dim() const; + + void print(string s) const; + bool equals(const gtsam::Values& other, double tol) const; + + void insert(const gtsam::Values& values); + void update(const gtsam::Values& values); + void erase(size_t j); + void swap(gtsam::Values& values); + + bool exists(size_t j) const; + gtsam::KeyVector keys() const; + + gtsam::VectorValues zeroVectors() const; + + gtsam::Values retract(const gtsam::VectorValues& delta) const; + gtsam::VectorValues localCoordinates(const gtsam::Values& cp) const; + + // enabling serialization functionality + void serialize() const; + + // New in 4.0, we have to specialize every insert/update/at to generate wrappers + // Instead of the old: + // void insert(size_t j, const gtsam::Value& value); + // void update(size_t j, const gtsam::Value& val); + // gtsam::Value at(size_t j) const; + + // The order is important: Vector has to precede Point2/Point3 so `atVector` + // can work for those fixed-size vectors. + void insert(size_t j, Vector vector); + void insert(size_t j, Matrix matrix); + void insert(size_t j, const gtsam::Point2& point2); + void insert(size_t j, const gtsam::Point3& point3); + void insert(size_t j, const gtsam::Rot2& rot2); + void insert(size_t j, const gtsam::Pose2& pose2); + void insert(size_t j, const gtsam::SO3& R); + void insert(size_t j, const gtsam::SO4& Q); + void insert(size_t j, const gtsam::SOn& P); + void insert(size_t j, const gtsam::Rot3& rot3); + void insert(size_t j, const gtsam::Pose3& pose3); + void insert(size_t j, const gtsam::Unit3& unit3); + void insert(size_t j, const gtsam::Cal3_S2& cal3_s2); + void insert(size_t j, const gtsam::Cal3DS2& cal3ds2); + void insert(size_t j, const gtsam::Cal3Bundler& cal3bundler); + void insert(size_t j, const gtsam::EssentialMatrix& essential_matrix); + void insert(size_t j, const gtsam::PinholeCameraCal3_S2& simple_camera); + void insert(size_t j, const gtsam::PinholeCamera& camera); + void insert(size_t j, const gtsam::imuBias::ConstantBias& constant_bias); + void insert(size_t j, const gtsam::NavState& nav_state); + + void update(size_t j, const gtsam::Point2& point2); + void update(size_t j, const gtsam::Point3& point3); + void update(size_t j, const gtsam::Rot2& rot2); + void update(size_t j, const gtsam::Pose2& pose2); + void update(size_t j, const gtsam::SO3& R); + void update(size_t j, const gtsam::SO4& Q); + void update(size_t j, const gtsam::SOn& P); + void update(size_t j, const gtsam::Rot3& rot3); + void update(size_t j, const gtsam::Pose3& pose3); + void update(size_t j, const gtsam::Unit3& unit3); + void update(size_t j, const gtsam::Cal3_S2& cal3_s2); + void update(size_t j, const gtsam::Cal3DS2& cal3ds2); + void update(size_t j, const gtsam::Cal3Bundler& cal3bundler); + void update(size_t j, const gtsam::EssentialMatrix& essential_matrix); + void update(size_t j, const gtsam::PinholeCameraCal3_S2& simple_camera); + void update(size_t j, const gtsam::PinholeCamera& camera); + void update(size_t j, const gtsam::imuBias::ConstantBias& constant_bias); + void update(size_t j, const gtsam::NavState& nav_state); + void update(size_t j, Vector vector); + void update(size_t j, Matrix matrix); + + template, gtsam::imuBias::ConstantBias, gtsam::NavState, Vector, Matrix}> + T at(size_t j); + + /// version for double + void insertDouble(size_t j, double c); + double atDouble(size_t j) const; +}; + +#include +class Marginals { + Marginals(const gtsam::NonlinearFactorGraph& graph, + const gtsam::Values& solution); + Marginals(const gtsam::GaussianFactorGraph& gfgraph, + const gtsam::Values& solution); + Marginals(const gtsam::GaussianFactorGraph& gfgraph, + const gtsam::VectorValues& solutionvec); + + void print(string s) const; + Matrix marginalCovariance(size_t variable) const; + Matrix marginalInformation(size_t variable) const; + gtsam::JointMarginal jointMarginalCovariance(const gtsam::KeyVector& variables) const; + gtsam::JointMarginal jointMarginalInformation(const gtsam::KeyVector& variables) const; +}; + +class JointMarginal { + Matrix at(size_t iVariable, size_t jVariable) const; + Matrix fullMatrix() const; + void print(string s) const; + void print() const; +}; + +#include +virtual class LinearContainerFactor : gtsam::NonlinearFactor { + + LinearContainerFactor(gtsam::GaussianFactor* factor, const gtsam::Values& linearizationPoint); + LinearContainerFactor(gtsam::GaussianFactor* factor); + + gtsam::GaussianFactor* factor() const; +// const boost::optional& linearizationPoint() const; + + bool isJacobian() const; + gtsam::JacobianFactor* toJacobian() const; + gtsam::HessianFactor* toHessian() const; + + static gtsam::NonlinearFactorGraph ConvertLinearGraph(const gtsam::GaussianFactorGraph& linear_graph, + const gtsam::Values& linearizationPoint); + + static gtsam::NonlinearFactorGraph ConvertLinearGraph(const gtsam::GaussianFactorGraph& linear_graph); + + // enabling serialization functionality + void serializable() const; +}; // \class LinearContainerFactor // Summarization functionality //#include @@ -2321,210 +2231,196 @@ class Cal3_S2 { // Nonlinear optimizers //************************************************************************* #include - virtual class NonlinearOptimizerParams - { - NonlinearOptimizerParams(); - void print(string s) const; +virtual class NonlinearOptimizerParams { + NonlinearOptimizerParams(); + void print(string s) const; - int getMaxIterations() const; - double getRelativeErrorTol() const; - double getAbsoluteErrorTol() const; - double getErrorTol() const; - string getVerbosity() const; + int getMaxIterations() const; + double getRelativeErrorTol() const; + double getAbsoluteErrorTol() const; + double getErrorTol() const; + string getVerbosity() const; - void setMaxIterations(int value); - void setRelativeErrorTol(double value); - void setAbsoluteErrorTol(double value); - void setErrorTol(double value); - void setVerbosity(string s); + void setMaxIterations(int value); + void setRelativeErrorTol(double value); + void setAbsoluteErrorTol(double value); + void setErrorTol(double value); + void setVerbosity(string s); - string getLinearSolverType() const; - void setLinearSolverType(string solver); + string getLinearSolverType() const; + void setLinearSolverType(string solver); - void setIterativeParams(gtsam::IterativeOptimizationParameters *params); - void setOrdering(const gtsam::Ordering &ordering); - string getOrderingType() const; - void setOrderingType(string ordering); + void setIterativeParams(gtsam::IterativeOptimizationParameters* params); + void setOrdering(const gtsam::Ordering& ordering); + string getOrderingType() const; + void setOrderingType(string ordering); - bool isMultifrontal() const; - bool isSequential() const; - bool isCholmod() const; - bool isIterative() const; - }; + bool isMultifrontal() const; + bool isSequential() const; + bool isCholmod() const; + bool isIterative() const; +}; - bool checkConvergence(double relativeErrorTreshold, - double absoluteErrorTreshold, double errorThreshold, - double currentError, double newError); - bool checkConvergence(const gtsam::NonlinearOptimizerParams ¶ms, - double currentError, double newError); +bool checkConvergence(double relativeErrorTreshold, + double absoluteErrorTreshold, double errorThreshold, + double currentError, double newError); +bool checkConvergence(const gtsam::NonlinearOptimizerParams& params, + double currentError, double newError); #include - virtual class GaussNewtonParams : gtsam::NonlinearOptimizerParams - { - GaussNewtonParams(); - }; +virtual class GaussNewtonParams : gtsam::NonlinearOptimizerParams { + GaussNewtonParams(); +}; #include - virtual class LevenbergMarquardtParams : gtsam::NonlinearOptimizerParams - { - LevenbergMarquardtParams(); +virtual class LevenbergMarquardtParams : gtsam::NonlinearOptimizerParams { + LevenbergMarquardtParams(); - bool getDiagonalDamping() const; - double getlambdaFactor() const; - double getlambdaInitial() const; - double getlambdaLowerBound() const; - double getlambdaUpperBound() const; - bool getUseFixedLambdaFactor(); - string getLogFile() const; - string getVerbosityLM() const; + bool getDiagonalDamping() const; + double getlambdaFactor() const; + double getlambdaInitial() const; + double getlambdaLowerBound() const; + double getlambdaUpperBound() const; + bool getUseFixedLambdaFactor(); + string getLogFile() const; + string getVerbosityLM() const; - void setDiagonalDamping(bool flag); - void setlambdaFactor(double value); - void setlambdaInitial(double value); - void setlambdaLowerBound(double value); - void setlambdaUpperBound(double value); - void setUseFixedLambdaFactor(bool flag); - void setLogFile(string s); - void setVerbosityLM(string s); + void setDiagonalDamping(bool flag); + void setlambdaFactor(double value); + void setlambdaInitial(double value); + void setlambdaLowerBound(double value); + void setlambdaUpperBound(double value); + void setUseFixedLambdaFactor(bool flag); + void setLogFile(string s); + void setVerbosityLM(string s); - static gtsam::LevenbergMarquardtParams LegacyDefaults(); - static gtsam::LevenbergMarquardtParams CeresDefaults(); + static gtsam::LevenbergMarquardtParams LegacyDefaults(); + static gtsam::LevenbergMarquardtParams CeresDefaults(); - static gtsam::LevenbergMarquardtParams EnsureHasOrdering( - gtsam::LevenbergMarquardtParams params, - const gtsam::NonlinearFactorGraph &graph); - static gtsam::LevenbergMarquardtParams ReplaceOrdering( - gtsam::LevenbergMarquardtParams params, const gtsam::Ordering &ordering); - }; + static gtsam::LevenbergMarquardtParams EnsureHasOrdering( + gtsam::LevenbergMarquardtParams params, + const gtsam::NonlinearFactorGraph& graph); + static gtsam::LevenbergMarquardtParams ReplaceOrdering( + gtsam::LevenbergMarquardtParams params, const gtsam::Ordering& ordering); +}; #include - virtual class DoglegParams : gtsam::NonlinearOptimizerParams - { - DoglegParams(); +virtual class DoglegParams : gtsam::NonlinearOptimizerParams { + DoglegParams(); - double getDeltaInitial() const; - string getVerbosityDL() const; + double getDeltaInitial() const; + string getVerbosityDL() const; - void setDeltaInitial(double deltaInitial) const; - void setVerbosityDL(string verbosityDL) const; - }; + void setDeltaInitial(double deltaInitial) const; + void setVerbosityDL(string verbosityDL) const; +}; #include - virtual class NonlinearOptimizer - { - gtsam::Values optimize(); - gtsam::Values optimizeSafely(); - double error() const; - int iterations() const; - gtsam::Values values() const; - gtsam::NonlinearFactorGraph graph() const; - gtsam::GaussianFactorGraph *iterate() const; - }; +virtual class NonlinearOptimizer { + gtsam::Values optimize(); + gtsam::Values optimizeSafely(); + double error() const; + int iterations() const; + gtsam::Values values() const; + gtsam::NonlinearFactorGraph graph() const; + gtsam::GaussianFactorGraph* iterate() const; +}; #include - virtual class GaussNewtonOptimizer : gtsam::NonlinearOptimizer - { - GaussNewtonOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues); - GaussNewtonOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues, const gtsam::GaussNewtonParams ¶ms); - }; +virtual class GaussNewtonOptimizer : gtsam::NonlinearOptimizer { + GaussNewtonOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues); + GaussNewtonOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues, const gtsam::GaussNewtonParams& params); +}; #include - virtual class DoglegOptimizer : gtsam::NonlinearOptimizer - { - DoglegOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues); - DoglegOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues, const gtsam::DoglegParams ¶ms); - double getDelta() const; - }; +virtual class DoglegOptimizer : gtsam::NonlinearOptimizer { + DoglegOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues); + DoglegOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues, const gtsam::DoglegParams& params); + double getDelta() const; +}; #include - virtual class LevenbergMarquardtOptimizer : gtsam::NonlinearOptimizer - { - LevenbergMarquardtOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues); - LevenbergMarquardtOptimizer(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &initialValues, const gtsam::LevenbergMarquardtParams ¶ms); - double lambda() const; - void print(string str) const; - }; +virtual class LevenbergMarquardtOptimizer : gtsam::NonlinearOptimizer { + LevenbergMarquardtOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues); + LevenbergMarquardtOptimizer(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& initialValues, const gtsam::LevenbergMarquardtParams& params); + double lambda() const; + void print(string str) const; +}; #include - class ISAM2GaussNewtonParams - { - ISAM2GaussNewtonParams(); +class ISAM2GaussNewtonParams { + ISAM2GaussNewtonParams(); - void print(string str) const; + void print(string str) const; - /** Getters and Setters for all properties */ - double getWildfireThreshold() const; - void setWildfireThreshold(double wildfireThreshold); - }; + /** Getters and Setters for all properties */ + double getWildfireThreshold() const; + void setWildfireThreshold(double wildfireThreshold); +}; - class ISAM2DoglegParams - { - ISAM2DoglegParams(); +class ISAM2DoglegParams { + ISAM2DoglegParams(); - void print(string str) const; + void print(string str) const; - /** Getters and Setters for all properties */ - double getWildfireThreshold() const; - void setWildfireThreshold(double wildfireThreshold); - double getInitialDelta() const; - void setInitialDelta(double initialDelta); - string getAdaptationMode() const; - void setAdaptationMode(string adaptationMode); - bool isVerbose() const; - void setVerbose(bool verbose); - }; + /** Getters and Setters for all properties */ + double getWildfireThreshold() const; + void setWildfireThreshold(double wildfireThreshold); + double getInitialDelta() const; + void setInitialDelta(double initialDelta); + string getAdaptationMode() const; + void setAdaptationMode(string adaptationMode); + bool isVerbose() const; + void setVerbose(bool verbose); +}; - class ISAM2ThresholdMapValue - { - ISAM2ThresholdMapValue(char c, Vector thresholds); - ISAM2ThresholdMapValue(const gtsam::ISAM2ThresholdMapValue &other); - }; +class ISAM2ThresholdMapValue { + ISAM2ThresholdMapValue(char c, Vector thresholds); + ISAM2ThresholdMapValue(const gtsam::ISAM2ThresholdMapValue& other); +}; - class ISAM2ThresholdMap - { - ISAM2ThresholdMap(); - ISAM2ThresholdMap(const gtsam::ISAM2ThresholdMap &other); +class ISAM2ThresholdMap { + ISAM2ThresholdMap(); + ISAM2ThresholdMap(const gtsam::ISAM2ThresholdMap& other); - // Note: no print function + // Note: no print function - // common STL methods - size_t size() const; - bool empty() const; - void clear(); + // common STL methods + size_t size() const; + bool empty() const; + void clear(); - // structure specific methods - void insert(const gtsam::ISAM2ThresholdMapValue &value) const; - }; + // structure specific methods + void insert(const gtsam::ISAM2ThresholdMapValue& value) const; +}; - class ISAM2Params - { - ISAM2Params(); +class ISAM2Params { + ISAM2Params(); - void print(string str) const; + void print(string str) const; - /** Getters and Setters for all properties */ - void setOptimizationParams(const gtsam::ISAM2GaussNewtonParams &gauss_newton__params); - void setOptimizationParams(const gtsam::ISAM2DoglegParams &dogleg_params); - void setRelinearizeThreshold(double threshold); - void setRelinearizeThreshold(const gtsam::ISAM2ThresholdMap &threshold_map); - int getRelinearizeSkip() const; - void setRelinearizeSkip(int relinearizeSkip); - bool isEnableRelinearization() const; - void setEnableRelinearization(bool enableRelinearization); - bool isEvaluateNonlinearError() const; - void setEvaluateNonlinearError(bool evaluateNonlinearError); - string getFactorization() const; - void setFactorization(string factorization); - bool isCacheLinearizedFactors() const; - void setCacheLinearizedFactors(bool cacheLinearizedFactors); - bool isEnableDetailedResults() const; - void setEnableDetailedResults(bool enableDetailedResults); - bool isEnablePartialRelinearizationCheck() const; - void setEnablePartialRelinearizationCheck(bool enablePartialRelinearizationCheck); - }; + /** Getters and Setters for all properties */ + void setOptimizationParams(const gtsam::ISAM2GaussNewtonParams& gauss_newton__params); + void setOptimizationParams(const gtsam::ISAM2DoglegParams& dogleg_params); + void setRelinearizeThreshold(double threshold); + void setRelinearizeThreshold(const gtsam::ISAM2ThresholdMap& threshold_map); + int getRelinearizeSkip() const; + void setRelinearizeSkip(int relinearizeSkip); + bool isEnableRelinearization() const; + void setEnableRelinearization(bool enableRelinearization); + bool isEvaluateNonlinearError() const; + void setEvaluateNonlinearError(bool evaluateNonlinearError); + string getFactorization() const; + void setFactorization(string factorization); + bool isCacheLinearizedFactors() const; + void setCacheLinearizedFactors(bool cacheLinearizedFactors); + bool isEnableDetailedResults() const; + void setEnableDetailedResults(bool enableDetailedResults); + bool isEnablePartialRelinearizationCheck() const; + void setEnablePartialRelinearizationCheck(bool enablePartialRelinearizationCheck); +}; - class ISAM2Clique - { +class ISAM2Clique { //Constructors ISAM2Clique(); @@ -2532,77 +2428,74 @@ class Cal3_S2 { //Standard Interface Vector gradientContribution() const; void print(string s); - }; +}; - class ISAM2Result - { - ISAM2Result(); +class ISAM2Result { + ISAM2Result(); - void print(string str) const; + void print(string str) const; - /** Getters and Setters for all properties */ - size_t getVariablesRelinearized() const; - size_t getVariablesReeliminated() const; - size_t getCliques() const; - double getErrorBefore() const; - double getErrorAfter() const; - }; + /** Getters and Setters for all properties */ + size_t getVariablesRelinearized() const; + size_t getVariablesReeliminated() const; + size_t getCliques() const; + double getErrorBefore() const; + double getErrorAfter() const; +}; - class ISAM2 - { - ISAM2(); - ISAM2(const gtsam::ISAM2Params ¶ms); - ISAM2(const gtsam::ISAM2 &other); +class ISAM2 { + ISAM2(); + ISAM2(const gtsam::ISAM2Params& params); + ISAM2(const gtsam::ISAM2& other); - bool equals(const gtsam::ISAM2 &other, double tol) const; - void print(string s) const; - void printStats() const; - void saveGraph(string s) const; + bool equals(const gtsam::ISAM2& other, double tol) const; + void print(string s) const; + void printStats() const; + void saveGraph(string s) const; - gtsam::ISAM2Result update(); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta, const gtsam::FactorIndices &removeFactorIndices); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta, const gtsam::FactorIndices &removeFactorIndices, const gtsam::KeyGroupMap &constrainedKeys); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta, const gtsam::FactorIndices &removeFactorIndices, gtsam::KeyGroupMap &constrainedKeys, const gtsam::KeyList &noRelinKeys); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta, const gtsam::FactorIndices &removeFactorIndices, gtsam::KeyGroupMap &constrainedKeys, const gtsam::KeyList &noRelinKeys, const gtsam::KeyList &extraReelimKeys); - gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &newTheta, const gtsam::FactorIndices &removeFactorIndices, gtsam::KeyGroupMap &constrainedKeys, const gtsam::KeyList &noRelinKeys, const gtsam::KeyList &extraReelimKeys, bool force_relinearize); + gtsam::ISAM2Result update(); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta, const gtsam::FactorIndices& removeFactorIndices); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta, const gtsam::FactorIndices& removeFactorIndices, const gtsam::KeyGroupMap& constrainedKeys); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta, const gtsam::FactorIndices& removeFactorIndices, gtsam::KeyGroupMap& constrainedKeys, const gtsam::KeyList& noRelinKeys); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta, const gtsam::FactorIndices& removeFactorIndices, gtsam::KeyGroupMap& constrainedKeys, const gtsam::KeyList& noRelinKeys, const gtsam::KeyList& extraReelimKeys); + gtsam::ISAM2Result update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& newTheta, const gtsam::FactorIndices& removeFactorIndices, gtsam::KeyGroupMap& constrainedKeys, const gtsam::KeyList& noRelinKeys, const gtsam::KeyList& extraReelimKeys, bool force_relinearize); - gtsam::Values getLinearizationPoint() const; - gtsam::Values calculateEstimate() const; - template , - Vector, Matrix}> - VALUE calculateEstimate(size_t key) const; - gtsam::Values calculateBestEstimate() const; - Matrix marginalCovariance(size_t key) const; - gtsam::VectorValues getDelta() const; - gtsam::NonlinearFactorGraph getFactorsUnsafe() const; - gtsam::VariableIndex getVariableIndex() const; - gtsam::ISAM2Params params() const; - }; + gtsam::Values getLinearizationPoint() const; + gtsam::Values calculateEstimate() const; + template , + Vector, Matrix}> + VALUE calculateEstimate(size_t key) const; + gtsam::Values calculateBestEstimate() const; + Matrix marginalCovariance(size_t key) const; + gtsam::VectorValues getDelta() const; + gtsam::NonlinearFactorGraph getFactorsUnsafe() const; + gtsam::VariableIndex getVariableIndex() const; + gtsam::ISAM2Params params() const; +}; #include - class NonlinearISAM - { - NonlinearISAM(); - NonlinearISAM(int reorderInterval); - void print(string s) const; - void printStats() const; - void saveGraph(string s) const; - gtsam::Values estimate() const; - Matrix marginalCovariance(size_t key) const; - int reorderInterval() const; - int reorderCounter() const; - void update(const gtsam::NonlinearFactorGraph &newFactors, const gtsam::Values &initialValues); - void reorder_relinearize(); +class NonlinearISAM { + NonlinearISAM(); + NonlinearISAM(int reorderInterval); + void print(string s) const; + void printStats() const; + void saveGraph(string s) const; + gtsam::Values estimate() const; + Matrix marginalCovariance(size_t key) const; + int reorderInterval() const; + int reorderCounter() const; + void update(const gtsam::NonlinearFactorGraph& newFactors, const gtsam::Values& initialValues); + void reorder_relinearize(); - // These might be expensive as instead of a reference the wrapper will make a copy - gtsam::GaussianISAM bayesTree() const; - gtsam::Values getLinearizationPoint() const; - gtsam::NonlinearFactorGraph getFactorsUnsafe() const; - }; + // These might be expensive as instead of a reference the wrapper will make a copy + gtsam::GaussianISAM bayesTree() const; + gtsam::Values getLinearizationPoint() const; + gtsam::NonlinearFactorGraph getFactorsUnsafe() const; +}; //************************************************************************* // Nonlinear factor types @@ -2611,966 +2504,917 @@ class Cal3_S2 { #include #include - template }> - virtual class PriorFactor : gtsam::NoiseModelFactor - { - PriorFactor(size_t key, const T &prior, const gtsam::noiseModel::Base *noiseModel); - T prior() const; +template}> +virtual class PriorFactor : gtsam::NoiseModelFactor { + PriorFactor(size_t key, const T& prior, const gtsam::noiseModel::Base* noiseModel); + T prior() const; + + // enabling serialization functionality + void serialize() const; +}; - // enabling serialization functionality - void serialize() const; - }; #include - template - virtual class BetweenFactor : gtsam::NoiseModelFactor - { - BetweenFactor(size_t key1, size_t key2, const T &relativePose, const gtsam::noiseModel::Base *noiseModel); - T measured() const; +template +virtual class BetweenFactor : gtsam::NoiseModelFactor { + BetweenFactor(size_t key1, size_t key2, const T& relativePose, const gtsam::noiseModel::Base* noiseModel); + T measured() const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - template - virtual class NonlinearEquality : gtsam::NoiseModelFactor - { - // Constructor - forces exact evaluation - NonlinearEquality(size_t j, const T &feasible); - // Constructor - allows inexact evaluation - NonlinearEquality(size_t j, const T &feasible, double error_gain); +template +virtual class NonlinearEquality : gtsam::NoiseModelFactor { + // Constructor - forces exact evaluation + NonlinearEquality(size_t j, const T& feasible); + // Constructor - allows inexact evaluation + NonlinearEquality(size_t j, const T& feasible, double error_gain); - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - template - virtual class RangeFactor : gtsam::NoiseModelFactor - { - RangeFactor(size_t key1, size_t key2, double measured, const gtsam::noiseModel::Base *noiseModel); +template +virtual class RangeFactor : gtsam::NoiseModelFactor { + RangeFactor(size_t key1, size_t key2, double measured, const gtsam::noiseModel::Base* noiseModel); - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; + +typedef gtsam::RangeFactor RangeFactor2D; +typedef gtsam::RangeFactor RangeFactor3D; +typedef gtsam::RangeFactor RangeFactorPose2; +typedef gtsam::RangeFactor RangeFactorPose3; +typedef gtsam::RangeFactor RangeFactorCalibratedCameraPoint; +typedef gtsam::RangeFactor RangeFactorSimpleCameraPoint; +typedef gtsam::RangeFactor RangeFactorCalibratedCamera; +typedef gtsam::RangeFactor RangeFactorSimpleCamera; - typedef gtsam::RangeFactor RangeFactor2D; - typedef gtsam::RangeFactor RangeFactor3D; - typedef gtsam::RangeFactor RangeFactorPose2; - typedef gtsam::RangeFactor RangeFactorPose3; - typedef gtsam::RangeFactor RangeFactorCalibratedCameraPoint; - typedef gtsam::RangeFactor RangeFactorSimpleCameraPoint; - typedef gtsam::RangeFactor RangeFactorCalibratedCamera; - typedef gtsam::RangeFactor RangeFactorSimpleCamera; #include - template - virtual class RangeFactorWithTransform : gtsam::NoiseModelFactor - { - RangeFactorWithTransform(size_t key1, size_t key2, double measured, const gtsam::noiseModel::Base *noiseModel, const POSE &body_T_sensor); +template +virtual class RangeFactorWithTransform : gtsam::NoiseModelFactor { + RangeFactorWithTransform(size_t key1, size_t key2, double measured, const gtsam::noiseModel::Base* noiseModel, const POSE& body_T_sensor); - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; - typedef gtsam::RangeFactorWithTransform RangeFactorWithTransform2D; - typedef gtsam::RangeFactorWithTransform RangeFactorWithTransform3D; - typedef gtsam::RangeFactorWithTransform RangeFactorWithTransformPose2; - typedef gtsam::RangeFactorWithTransform RangeFactorWithTransformPose3; +typedef gtsam::RangeFactorWithTransform RangeFactorWithTransform2D; +typedef gtsam::RangeFactorWithTransform RangeFactorWithTransform3D; +typedef gtsam::RangeFactorWithTransform RangeFactorWithTransformPose2; +typedef gtsam::RangeFactorWithTransform RangeFactorWithTransformPose3; #include - template - virtual class BearingFactor : gtsam::NoiseModelFactor - { - BearingFactor(size_t key1, size_t key2, const BEARING &measured, const gtsam::noiseModel::Base *noiseModel); +template +virtual class BearingFactor : gtsam::NoiseModelFactor { + BearingFactor(size_t key1, size_t key2, const BEARING& measured, const gtsam::noiseModel::Base* noiseModel); - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; - typedef gtsam::BearingFactor BearingFactor2D; - typedef gtsam::BearingFactor BearingFactorPose2; +typedef gtsam::BearingFactor BearingFactor2D; +typedef gtsam::BearingFactor BearingFactorPose2; #include - template - class BearingRange - { - BearingRange(const BEARING &b, const RANGE &r); - BEARING bearing() const; - RANGE range() const; - static This Measure(const POSE &pose, const POINT &point); - static BEARING MeasureBearing(const POSE &pose, const POINT &point); - static RANGE MeasureRange(const POSE &pose, const POINT &point); - void print(string s) const; - }; +template +class BearingRange { + BearingRange(const BEARING& b, const RANGE& r); + BEARING bearing() const; + RANGE range() const; + static This Measure(const POSE& pose, const POINT& point); + static BEARING MeasureBearing(const POSE& pose, const POINT& point); + static RANGE MeasureRange(const POSE& pose, const POINT& point); + void print(string s) const; +}; - typedef gtsam::BearingRange BearingRange2D; +typedef gtsam::BearingRange BearingRange2D; #include - template - virtual class BearingRangeFactor : gtsam::NoiseModelFactor - { - BearingRangeFactor(size_t poseKey, size_t pointKey, - const BEARING &measuredBearing, const RANGE &measuredRange, - const gtsam::noiseModel::Base *noiseModel); +template +virtual class BearingRangeFactor : gtsam::NoiseModelFactor { + BearingRangeFactor(size_t poseKey, size_t pointKey, + const BEARING& measuredBearing, const RANGE& measuredRange, + const gtsam::noiseModel::Base* noiseModel); - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; + +typedef gtsam::BearingRangeFactor BearingRangeFactor2D; +typedef gtsam::BearingRangeFactor BearingRangeFactorPose2; - typedef gtsam::BearingRangeFactor BearingRangeFactor2D; - typedef gtsam::BearingRangeFactor BearingRangeFactorPose2; #include - template - virtual class GenericProjectionFactor : gtsam::NoiseModelFactor - { - GenericProjectionFactor(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *noiseModel, - size_t poseKey, size_t pointKey, const CALIBRATION *k); - GenericProjectionFactor(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *noiseModel, - size_t poseKey, size_t pointKey, const CALIBRATION *k, const POSE &body_P_sensor); +template +virtual class GenericProjectionFactor : gtsam::NoiseModelFactor { + GenericProjectionFactor(const gtsam::Point2& measured, const gtsam::noiseModel::Base* noiseModel, + size_t poseKey, size_t pointKey, const CALIBRATION* k); + GenericProjectionFactor(const gtsam::Point2& measured, const gtsam::noiseModel::Base* noiseModel, + size_t poseKey, size_t pointKey, const CALIBRATION* k, const POSE& body_P_sensor); - GenericProjectionFactor(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *noiseModel, - size_t poseKey, size_t pointKey, const CALIBRATION *k, bool throwCheirality, bool verboseCheirality); - GenericProjectionFactor(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *noiseModel, - size_t poseKey, size_t pointKey, const CALIBRATION *k, bool throwCheirality, bool verboseCheirality, - const POSE &body_P_sensor); + GenericProjectionFactor(const gtsam::Point2& measured, const gtsam::noiseModel::Base* noiseModel, + size_t poseKey, size_t pointKey, const CALIBRATION* k, bool throwCheirality, bool verboseCheirality); + GenericProjectionFactor(const gtsam::Point2& measured, const gtsam::noiseModel::Base* noiseModel, + size_t poseKey, size_t pointKey, const CALIBRATION* k, bool throwCheirality, bool verboseCheirality, + const POSE& body_P_sensor); - gtsam::Point2 measured() const; - CALIBRATION *calibration() const; - bool verboseCheirality() const; - bool throwCheirality() const; + gtsam::Point2 measured() const; + CALIBRATION* calibration() const; + bool verboseCheirality() const; + bool throwCheirality() const; + + // enabling serialization functionality + void serialize() const; +}; +typedef gtsam::GenericProjectionFactor GenericProjectionFactorCal3_S2; +typedef gtsam::GenericProjectionFactor GenericProjectionFactorCal3DS2; - // enabling serialization functionality - void serialize() const; - }; - typedef gtsam::GenericProjectionFactor GenericProjectionFactorCal3_S2; - typedef gtsam::GenericProjectionFactor GenericProjectionFactorCal3DS2; #include - template - virtual class GeneralSFMFactor : gtsam::NoiseModelFactor - { - GeneralSFMFactor(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *model, size_t cameraKey, size_t landmarkKey); - gtsam::Point2 measured() const; - }; - typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3_S2; - typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; - typedef gtsam::GeneralSFMFactor, gtsam::Point3> GeneralSFMFactorCal3Bundler; +template +virtual class GeneralSFMFactor : gtsam::NoiseModelFactor { + GeneralSFMFactor(const gtsam::Point2& measured, const gtsam::noiseModel::Base* model, size_t cameraKey, size_t landmarkKey); + gtsam::Point2 measured() const; +}; +typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3_S2; +typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; +typedef gtsam::GeneralSFMFactor, gtsam::Point3> GeneralSFMFactorCal3Bundler; - template - virtual class GeneralSFMFactor2 : gtsam::NoiseModelFactor - { - GeneralSFMFactor2(const gtsam::Point2 &measured, const gtsam::noiseModel::Base *model, size_t poseKey, size_t landmarkKey, size_t calibKey); - gtsam::Point2 measured() const; +template +virtual class GeneralSFMFactor2 : gtsam::NoiseModelFactor { + GeneralSFMFactor2(const gtsam::Point2& measured, const gtsam::noiseModel::Base* model, size_t poseKey, size_t landmarkKey, size_t calibKey); + gtsam::Point2 measured() const; - // enabling serialization functionality - void serialize() const; - }; + // enabling serialization functionality + void serialize() const; +}; #include - class SmartProjectionParams - { - SmartProjectionParams(); - // TODO(frank): make these work: - // void setLinearizationMode(LinearizationMode linMode); - // void setDegeneracyMode(DegeneracyMode degMode); - void setRankTolerance(double rankTol); - void setEnableEPI(bool enableEPI); - void setLandmarkDistanceThreshold(bool landmarkDistanceThreshold); - void setDynamicOutlierRejectionThreshold(bool dynOutRejectionThreshold); - }; +class SmartProjectionParams { + SmartProjectionParams(); + // TODO(frank): make these work: + // void setLinearizationMode(LinearizationMode linMode); + // void setDegeneracyMode(DegeneracyMode degMode); + void setRankTolerance(double rankTol); + void setEnableEPI(bool enableEPI); + void setLandmarkDistanceThreshold(bool landmarkDistanceThreshold); + void setDynamicOutlierRejectionThreshold(bool dynOutRejectionThreshold); +}; #include - template - virtual class SmartProjectionPoseFactor : gtsam::NonlinearFactor - { +template +virtual class SmartProjectionPoseFactor: gtsam::NonlinearFactor { - SmartProjectionPoseFactor(const gtsam::noiseModel::Base *noise, - const CALIBRATION *K); - SmartProjectionPoseFactor(const gtsam::noiseModel::Base *noise, - const CALIBRATION *K, - const gtsam::Pose3 &body_P_sensor); - SmartProjectionPoseFactor(const gtsam::noiseModel::Base *noise, - const CALIBRATION *K, - const gtsam::SmartProjectionParams ¶ms); - SmartProjectionPoseFactor(const gtsam::noiseModel::Base *noise, - const CALIBRATION *K, - const gtsam::Pose3 &body_P_sensor, - const gtsam::SmartProjectionParams ¶ms); + SmartProjectionPoseFactor(const gtsam::noiseModel::Base* noise, + const CALIBRATION* K); + SmartProjectionPoseFactor(const gtsam::noiseModel::Base* noise, + const CALIBRATION* K, + const gtsam::Pose3& body_P_sensor); + SmartProjectionPoseFactor(const gtsam::noiseModel::Base* noise, + const CALIBRATION* K, + const gtsam::SmartProjectionParams& params); + SmartProjectionPoseFactor(const gtsam::noiseModel::Base* noise, + const CALIBRATION* K, + const gtsam::Pose3& body_P_sensor, + const gtsam::SmartProjectionParams& params); - void add(const gtsam::Point2 &measured_i, size_t poseKey_i); + void add(const gtsam::Point2& measured_i, size_t poseKey_i); - // enabling serialization functionality - //void serialize() const; - }; + // enabling serialization functionality + //void serialize() const; +}; + +typedef gtsam::SmartProjectionPoseFactor SmartProjectionPose3Factor; - typedef gtsam::SmartProjectionPoseFactor SmartProjectionPose3Factor; #include - template - virtual class GenericStereoFactor : gtsam::NoiseModelFactor - { - GenericStereoFactor(const gtsam::StereoPoint2 &measured, const gtsam::noiseModel::Base *noiseModel, - size_t poseKey, size_t landmarkKey, const gtsam::Cal3_S2Stereo *K); - gtsam::StereoPoint2 measured() const; - gtsam::Cal3_S2Stereo *calibration() const; +template +virtual class GenericStereoFactor : gtsam::NoiseModelFactor { + GenericStereoFactor(const gtsam::StereoPoint2& measured, const gtsam::noiseModel::Base* noiseModel, + size_t poseKey, size_t landmarkKey, const gtsam::Cal3_S2Stereo* K); + gtsam::StereoPoint2 measured() const; + gtsam::Cal3_S2Stereo* calibration() const; - // enabling serialization functionality - void serialize() const; - }; - typedef gtsam::GenericStereoFactor GenericStereoFactor3D; + // enabling serialization functionality + void serialize() const; +}; +typedef gtsam::GenericStereoFactor GenericStereoFactor3D; #include - template - virtual class PoseTranslationPrior : gtsam::NoiseModelFactor - { - PoseTranslationPrior(size_t key, const POSE &pose_z, const gtsam::noiseModel::Base *noiseModel); - }; +template +virtual class PoseTranslationPrior : gtsam::NoiseModelFactor { + PoseTranslationPrior(size_t key, const POSE& pose_z, const gtsam::noiseModel::Base* noiseModel); +}; - typedef gtsam::PoseTranslationPrior PoseTranslationPrior2D; - typedef gtsam::PoseTranslationPrior PoseTranslationPrior3D; +typedef gtsam::PoseTranslationPrior PoseTranslationPrior2D; +typedef gtsam::PoseTranslationPrior PoseTranslationPrior3D; #include - template - virtual class PoseRotationPrior : gtsam::NoiseModelFactor - { - PoseRotationPrior(size_t key, const POSE &pose_z, const gtsam::noiseModel::Base *noiseModel); - }; +template +virtual class PoseRotationPrior : gtsam::NoiseModelFactor { + PoseRotationPrior(size_t key, const POSE& pose_z, const gtsam::noiseModel::Base* noiseModel); +}; - typedef gtsam::PoseRotationPrior PoseRotationPrior2D; - typedef gtsam::PoseRotationPrior PoseRotationPrior3D; +typedef gtsam::PoseRotationPrior PoseRotationPrior2D; +typedef gtsam::PoseRotationPrior PoseRotationPrior3D; #include - virtual class EssentialMatrixFactor : gtsam::NoiseModelFactor - { - EssentialMatrixFactor(size_t key, const gtsam::Point2 &pA, const gtsam::Point2 &pB, - const gtsam::noiseModel::Base *noiseModel); - }; +virtual class EssentialMatrixFactor : gtsam::NoiseModelFactor { + EssentialMatrixFactor(size_t key, const gtsam::Point2& pA, const gtsam::Point2& pB, + const gtsam::noiseModel::Base* noiseModel); +}; #include - class SfmTrack - { - SfmTrack(); - SfmTrack(const gtsam::Point3 &pt); - const Point3 &point3() const; +class SfmTrack { + SfmTrack(); + SfmTrack(const gtsam::Point3& pt); + const Point3& point3() const; - double r; - double g; - double b; - // TODO Need to close wrap#10 to allow this to work. - // std::vector> measurements; + double r; + double g; + double b; + // TODO Need to close wrap#10 to allow this to work. + // std::vector> measurements; - size_t number_measurements() const; - pair measurement(size_t idx) const; - pair siftIndex(size_t idx) const; - void add_measurement(size_t idx, const gtsam::Point2 &m); - }; + size_t number_measurements() const; + pair measurement(size_t idx) const; + pair siftIndex(size_t idx) const; + void add_measurement(size_t idx, const gtsam::Point2& m); +}; - class SfmData - { - SfmData(); - size_t number_cameras() const; - size_t number_tracks() const; - gtsam::PinholeCamera camera(size_t idx) const; - gtsam::SfmTrack track(size_t idx) const; - void add_track(const gtsam::SfmTrack &t); - void add_camera(const gtsam::SfmCamera &cam); - }; +class SfmData { + SfmData(); + size_t number_cameras() const; + size_t number_tracks() const; + gtsam::PinholeCamera camera(size_t idx) const; + gtsam::SfmTrack track(size_t idx) const; + void add_track(const gtsam::SfmTrack& t) ; + void add_camera(const gtsam::SfmCamera& cam); +}; - gtsam::SfmData readBal(string filename); - bool writeBAL(string filename, gtsam::SfmData &data); - gtsam::Values initialCamerasEstimate(const gtsam::SfmData &db); - gtsam::Values initialCamerasAndPointsEstimate(const gtsam::SfmData &db); +gtsam::SfmData readBal(string filename); +bool writeBAL(string filename, gtsam::SfmData& data); +gtsam::Values initialCamerasEstimate(const gtsam::SfmData& db); +gtsam::Values initialCamerasAndPointsEstimate(const gtsam::SfmData& db); - pair load2D(string filename, - gtsam::noiseModel::Diagonal *model, int maxIndex, bool addNoise, bool smart); - pair load2D(string filename, - gtsam::noiseModel::Diagonal *model, int maxIndex, bool addNoise); - pair load2D(string filename, - gtsam::noiseModel::Diagonal *model, int maxIndex); - pair load2D(string filename, - gtsam::noiseModel::Diagonal *model); - pair load2D(string filename); - pair load2D_robust(string filename, - gtsam::noiseModel::Base *model, int maxIndex); - void save2D(const gtsam::NonlinearFactorGraph &graph, - const gtsam::Values &config, gtsam::noiseModel::Diagonal *model, - string filename); +pair load2D(string filename, + gtsam::noiseModel::Diagonal* model, int maxIndex, bool addNoise, bool smart); +pair load2D(string filename, + gtsam::noiseModel::Diagonal* model, int maxIndex, bool addNoise); +pair load2D(string filename, + gtsam::noiseModel::Diagonal* model, int maxIndex); +pair load2D(string filename, + gtsam::noiseModel::Diagonal* model); +pair load2D(string filename); +pair load2D_robust(string filename, + gtsam::noiseModel::Base* model, int maxIndex); +void save2D(const gtsam::NonlinearFactorGraph& graph, + const gtsam::Values& config, gtsam::noiseModel::Diagonal* model, + string filename); - // std::vector::shared_ptr> - // Ignored by pybind -> will be List[BetweenFactorPose2] - class BetweenFactorPose2s - { - BetweenFactorPose2s(); - size_t size() const; - gtsam::BetweenFactor *at(size_t i) const; - void push_back(const gtsam::BetweenFactor *factor); - }; - gtsam::BetweenFactorPose2s parse2DFactors(string filename); +// std::vector::shared_ptr> +// Ignored by pybind -> will be List[BetweenFactorPose2] +class BetweenFactorPose2s +{ + BetweenFactorPose2s(); + size_t size() const; + gtsam::BetweenFactor* at(size_t i) const; + void push_back(const gtsam::BetweenFactor* factor); +}; +gtsam::BetweenFactorPose2s parse2DFactors(string filename); - // std::vector::shared_ptr> - // Ignored by pybind -> will be List[BetweenFactorPose3] - class BetweenFactorPose3s - { - BetweenFactorPose3s(); - size_t size() const; - gtsam::BetweenFactor *at(size_t i) const; - void push_back(const gtsam::BetweenFactor *factor); - }; - gtsam::BetweenFactorPose3s parse3DFactors(string filename); +// std::vector::shared_ptr> +// Ignored by pybind -> will be List[BetweenFactorPose3] +class BetweenFactorPose3s +{ + BetweenFactorPose3s(); + size_t size() const; + gtsam::BetweenFactor* at(size_t i) const; + void push_back(const gtsam::BetweenFactor* factor); +}; +gtsam::BetweenFactorPose3s parse3DFactors(string filename); - pair load3D(string filename); +pair load3D(string filename); - pair readG2o(string filename); - pair readG2o(string filename, bool is3D); - void writeG2o(const gtsam::NonlinearFactorGraph &graph, - const gtsam::Values &estimate, string filename); +pair readG2o(string filename); +pair readG2o(string filename, bool is3D); +void writeG2o(const gtsam::NonlinearFactorGraph& graph, + const gtsam::Values& estimate, string filename); #include - class InitializePose3 - { - static gtsam::Values computeOrientationsChordal( - const gtsam::NonlinearFactorGraph &pose3Graph); - static gtsam::Values computeOrientationsGradient( - const gtsam::NonlinearFactorGraph &pose3Graph, - const gtsam::Values &givenGuess, size_t maxIter, const bool setRefFrame); - static gtsam::Values computeOrientationsGradient( - const gtsam::NonlinearFactorGraph &pose3Graph, - const gtsam::Values &givenGuess); - static gtsam::NonlinearFactorGraph buildPose3graph( - const gtsam::NonlinearFactorGraph &graph); - static gtsam::Values initializeOrientations( - const gtsam::NonlinearFactorGraph &graph); - static gtsam::Values initialize(const gtsam::NonlinearFactorGraph &graph, - const gtsam::Values &givenGuess, - bool useGradient); - static gtsam::Values initialize(const gtsam::NonlinearFactorGraph &graph); - }; +class InitializePose3 { + static gtsam::Values computeOrientationsChordal( + const gtsam::NonlinearFactorGraph& pose3Graph); + static gtsam::Values computeOrientationsGradient( + const gtsam::NonlinearFactorGraph& pose3Graph, + const gtsam::Values& givenGuess, size_t maxIter, const bool setRefFrame); + static gtsam::Values computeOrientationsGradient( + const gtsam::NonlinearFactorGraph& pose3Graph, + const gtsam::Values& givenGuess); + static gtsam::NonlinearFactorGraph buildPose3graph( + const gtsam::NonlinearFactorGraph& graph); + static gtsam::Values initializeOrientations( + const gtsam::NonlinearFactorGraph& graph); + static gtsam::Values initialize(const gtsam::NonlinearFactorGraph& graph, + const gtsam::Values& givenGuess, + bool useGradient); + static gtsam::Values initialize(const gtsam::NonlinearFactorGraph& graph); +}; #include - template - virtual class KarcherMeanFactor : gtsam::NonlinearFactor - { - KarcherMeanFactor(const gtsam::KeyVector &keys); - }; +template +virtual class KarcherMeanFactor : gtsam::NonlinearFactor { + KarcherMeanFactor(const gtsam::KeyVector& keys); +}; #include - gtsam::noiseModel::Isotropic *ConvertNoiseModel( - gtsam::noiseModel::Base *model, size_t d); +gtsam::noiseModel::Isotropic* ConvertNoiseModel( + gtsam::noiseModel::Base* model, size_t d); - template - virtual class FrobeniusFactor : gtsam::NoiseModelFactor - { - FrobeniusFactor(size_t key1, size_t key2); - FrobeniusFactor(size_t key1, size_t key2, gtsam::noiseModel::Base *model); +template +virtual class FrobeniusFactor : gtsam::NoiseModelFactor { + FrobeniusFactor(size_t key1, size_t key2); + FrobeniusFactor(size_t key1, size_t key2, gtsam::noiseModel::Base* model); - Vector evaluateError(const T &R1, const T &R2); - }; + Vector evaluateError(const T& R1, const T& R2); +}; - template - virtual class FrobeniusBetweenFactor : gtsam::NoiseModelFactor - { - FrobeniusBetweenFactor(size_t key1, size_t key2, const T &R12); - FrobeniusBetweenFactor(size_t key1, size_t key2, const T &R12, gtsam::noiseModel::Base *model); +template +virtual class FrobeniusBetweenFactor : gtsam::NoiseModelFactor { + FrobeniusBetweenFactor(size_t key1, size_t key2, const T& R12); + FrobeniusBetweenFactor(size_t key1, size_t key2, const T& R12, gtsam::noiseModel::Base* model); - Vector evaluateError(const T &R1, const T &R2); - }; + Vector evaluateError(const T& R1, const T& R2); +}; #include - virtual class ShonanFactor3 : gtsam::NoiseModelFactor - { - ShonanFactor3(size_t key1, size_t key2, const gtsam::Rot3 &R12, - size_t p); - ShonanFactor3(size_t key1, size_t key2, const gtsam::Rot3 &R12, - size_t p, gtsam::noiseModel::Base *model); - Vector evaluateError(const gtsam::SOn &Q1, const gtsam::SOn &Q2); - }; +virtual class ShonanFactor3 : gtsam::NoiseModelFactor { + ShonanFactor3(size_t key1, size_t key2, const gtsam::Rot3 &R12, + size_t p); + ShonanFactor3(size_t key1, size_t key2, const gtsam::Rot3 &R12, + size_t p, gtsam::noiseModel::Base *model); + Vector evaluateError(const gtsam::SOn &Q1, const gtsam::SOn &Q2); +}; #include - template - class BinaryMeasurement - { - BinaryMeasurement(size_t key1, size_t key2, const T &measured, - const gtsam::noiseModel::Base *model); - size_t key1() const; - size_t key2() const; - T measured() const; - gtsam::noiseModel::Base *noiseModel() const; - }; +template +class BinaryMeasurement { + BinaryMeasurement(size_t key1, size_t key2, const T& measured, + const gtsam::noiseModel::Base* model); + size_t key1() const; + size_t key2() const; + T measured() const; + gtsam::noiseModel::Base* noiseModel() const; +}; - typedef gtsam::BinaryMeasurement BinaryMeasurementUnit3; - typedef gtsam::BinaryMeasurement BinaryMeasurementRot3; +typedef gtsam::BinaryMeasurement BinaryMeasurementUnit3; +typedef gtsam::BinaryMeasurement BinaryMeasurementRot3; - class BinaryMeasurementsUnit3 - { - BinaryMeasurementsUnit3(); - size_t size() const; - gtsam::BinaryMeasurement at(size_t idx) const; - void push_back(const gtsam::BinaryMeasurement &measurement); - }; +class BinaryMeasurementsUnit3 { + BinaryMeasurementsUnit3(); + size_t size() const; + gtsam::BinaryMeasurement at(size_t idx) const; + void push_back(const gtsam::BinaryMeasurement& measurement); +}; #include - // TODO(frank): copy/pasta below until we have integer template paremeters in wrap! +// TODO(frank): copy/pasta below until we have integer template paremeters in wrap! - class ShonanAveragingParameters2 - { - ShonanAveragingParameters2(const gtsam::LevenbergMarquardtParams &lm); - ShonanAveragingParameters2(const gtsam::LevenbergMarquardtParams &lm, string method); - gtsam::LevenbergMarquardtParams getLMParams() const; - void setOptimalityThreshold(double value); - double getOptimalityThreshold() const; - void setAnchor(size_t index, const gtsam::Rot2 &value); - pair getAnchor(); - void setAnchorWeight(double value); - double getAnchorWeight() const; - void setKarcherWeight(double value); - double getKarcherWeight(); - void setGaugesWeight(double value); - double getGaugesWeight(); - }; +class ShonanAveragingParameters2 { + ShonanAveragingParameters2(const gtsam::LevenbergMarquardtParams& lm); + ShonanAveragingParameters2(const gtsam::LevenbergMarquardtParams& lm, string method); + gtsam::LevenbergMarquardtParams getLMParams() const; + void setOptimalityThreshold(double value); + double getOptimalityThreshold() const; + void setAnchor(size_t index, const gtsam::Rot2& value); + pair getAnchor(); + void setAnchorWeight(double value); + double getAnchorWeight() const; + void setKarcherWeight(double value); + double getKarcherWeight(); + void setGaugesWeight(double value); + double getGaugesWeight(); +}; - class ShonanAveragingParameters3 - { - ShonanAveragingParameters3(const gtsam::LevenbergMarquardtParams &lm); - ShonanAveragingParameters3(const gtsam::LevenbergMarquardtParams &lm, string method); - gtsam::LevenbergMarquardtParams getLMParams() const; - void setOptimalityThreshold(double value); - double getOptimalityThreshold() const; - void setAnchor(size_t index, const gtsam::Rot3 &value); - pair getAnchor(); - void setAnchorWeight(double value); - double getAnchorWeight() const; - void setKarcherWeight(double value); - double getKarcherWeight(); - void setGaugesWeight(double value); - double getGaugesWeight(); - }; +class ShonanAveragingParameters3 { + ShonanAveragingParameters3(const gtsam::LevenbergMarquardtParams& lm); + ShonanAveragingParameters3(const gtsam::LevenbergMarquardtParams& lm, string method); + gtsam::LevenbergMarquardtParams getLMParams() const; + void setOptimalityThreshold(double value); + double getOptimalityThreshold() const; + void setAnchor(size_t index, const gtsam::Rot3& value); + pair getAnchor(); + void setAnchorWeight(double value); + double getAnchorWeight() const; + void setKarcherWeight(double value); + double getKarcherWeight(); + void setGaugesWeight(double value); + double getGaugesWeight(); +}; - class ShonanAveraging2 - { - ShonanAveraging2(string g2oFile); - ShonanAveraging2(string g2oFile, - const gtsam::ShonanAveragingParameters2 ¶meters); +class ShonanAveraging2 { + ShonanAveraging2(string g2oFile); + ShonanAveraging2(string g2oFile, + const gtsam::ShonanAveragingParameters2 ¶meters); - // Query properties - size_t nrUnknowns() const; - size_t nrMeasurements() const; - gtsam::Rot2 measured(size_t i); - gtsam::KeyVector keys(size_t i); + // Query properties + size_t nrUnknowns() const; + size_t nrMeasurements() const; + gtsam::Rot2 measured(size_t i); + gtsam::KeyVector keys(size_t i); - // Matrix API (advanced use, debugging) - Matrix denseD() const; - Matrix denseQ() const; - Matrix denseL() const; - // Matrix computeLambda_(Matrix S) const; - Matrix computeLambda_(const gtsam::Values &values) const; - Matrix computeA_(const gtsam::Values &values) const; - double computeMinEigenValue(const gtsam::Values &values) const; - gtsam::Values initializeWithDescent(size_t p, const gtsam::Values &values, - const Vector &minEigenVector, double minEigenValue) const; + // Matrix API (advanced use, debugging) + Matrix denseD() const; + Matrix denseQ() const; + Matrix denseL() const; + // Matrix computeLambda_(Matrix S) const; + Matrix computeLambda_(const gtsam::Values& values) const; + Matrix computeA_(const gtsam::Values& values) const; + double computeMinEigenValue(const gtsam::Values& values) const; + gtsam::Values initializeWithDescent(size_t p, const gtsam::Values& values, + const Vector& minEigenVector, double minEigenValue) const; - // Advanced API - gtsam::NonlinearFactorGraph buildGraphAt(size_t p) const; - gtsam::Values initializeRandomlyAt(size_t p) const; - double costAt(size_t p, const gtsam::Values &values) const; - pair computeMinEigenVector(const gtsam::Values &values) const; - bool checkOptimality(const gtsam::Values &values) const; - gtsam::LevenbergMarquardtOptimizer *createOptimizerAt(size_t p, const gtsam::Values &initial); - // gtsam::Values tryOptimizingAt(size_t p) const; - gtsam::Values tryOptimizingAt(size_t p, const gtsam::Values &initial) const; - gtsam::Values projectFrom(size_t p, const gtsam::Values &values) const; - gtsam::Values roundSolution(const gtsam::Values &values) const; + // Advanced API + gtsam::NonlinearFactorGraph buildGraphAt(size_t p) const; + gtsam::Values initializeRandomlyAt(size_t p) const; + double costAt(size_t p, const gtsam::Values& values) const; + pair computeMinEigenVector(const gtsam::Values& values) const; + bool checkOptimality(const gtsam::Values& values) const; + gtsam::LevenbergMarquardtOptimizer* createOptimizerAt(size_t p, const gtsam::Values& initial); + // gtsam::Values tryOptimizingAt(size_t p) const; + gtsam::Values tryOptimizingAt(size_t p, const gtsam::Values& initial) const; + gtsam::Values projectFrom(size_t p, const gtsam::Values& values) const; + gtsam::Values roundSolution(const gtsam::Values& values) const; - // Basic API - double cost(const gtsam::Values &values) const; - gtsam::Values initializeRandomly() const; - pair run(const gtsam::Values &initial, size_t min_p, size_t max_p) const; - }; + // Basic API + double cost(const gtsam::Values& values) const; + gtsam::Values initializeRandomly() const; + pair run(const gtsam::Values& initial, size_t min_p, size_t max_p) const; +}; - class ShonanAveraging3 - { - ShonanAveraging3(string g2oFile); - ShonanAveraging3(string g2oFile, - const gtsam::ShonanAveragingParameters3 ¶meters); +class ShonanAveraging3 { + ShonanAveraging3(string g2oFile); + ShonanAveraging3(string g2oFile, + const gtsam::ShonanAveragingParameters3 ¶meters); + + // TODO(frank): deprecate once we land pybind wrapper + ShonanAveraging3(const gtsam::BetweenFactorPose3s &factors); + ShonanAveraging3(const gtsam::BetweenFactorPose3s &factors, + const gtsam::ShonanAveragingParameters3 ¶meters); - // TODO(frank): deprecate once we land pybind wrapper - ShonanAveraging3(const gtsam::BetweenFactorPose3s &factors); - ShonanAveraging3(const gtsam::BetweenFactorPose3s &factors, - const gtsam::ShonanAveragingParameters3 ¶meters); + // Query properties + size_t nrUnknowns() const; + size_t nrMeasurements() const; + gtsam::Rot3 measured(size_t i); + gtsam::KeyVector keys(size_t i); - // Query properties - size_t nrUnknowns() const; - size_t nrMeasurements() const; - gtsam::Rot3 measured(size_t i); - gtsam::KeyVector keys(size_t i); + // Matrix API (advanced use, debugging) + Matrix denseD() const; + Matrix denseQ() const; + Matrix denseL() const; + // Matrix computeLambda_(Matrix S) const; + Matrix computeLambda_(const gtsam::Values& values) const; + Matrix computeA_(const gtsam::Values& values) const; + double computeMinEigenValue(const gtsam::Values& values) const; + gtsam::Values initializeWithDescent(size_t p, const gtsam::Values& values, + const Vector& minEigenVector, double minEigenValue) const; - // Matrix API (advanced use, debugging) - Matrix denseD() const; - Matrix denseQ() const; - Matrix denseL() const; - // Matrix computeLambda_(Matrix S) const; - Matrix computeLambda_(const gtsam::Values &values) const; - Matrix computeA_(const gtsam::Values &values) const; - double computeMinEigenValue(const gtsam::Values &values) const; - gtsam::Values initializeWithDescent(size_t p, const gtsam::Values &values, - const Vector &minEigenVector, double minEigenValue) const; + // Advanced API + gtsam::NonlinearFactorGraph buildGraphAt(size_t p) const; + gtsam::Values initializeRandomlyAt(size_t p) const; + double costAt(size_t p, const gtsam::Values& values) const; + pair computeMinEigenVector(const gtsam::Values& values) const; + bool checkOptimality(const gtsam::Values& values) const; + gtsam::LevenbergMarquardtOptimizer* createOptimizerAt(size_t p, const gtsam::Values& initial); + // gtsam::Values tryOptimizingAt(size_t p) const; + gtsam::Values tryOptimizingAt(size_t p, const gtsam::Values& initial) const; + gtsam::Values projectFrom(size_t p, const gtsam::Values& values) const; + gtsam::Values roundSolution(const gtsam::Values& values) const; - // Advanced API - gtsam::NonlinearFactorGraph buildGraphAt(size_t p) const; - gtsam::Values initializeRandomlyAt(size_t p) const; - double costAt(size_t p, const gtsam::Values &values) const; - pair computeMinEigenVector(const gtsam::Values &values) const; - bool checkOptimality(const gtsam::Values &values) const; - gtsam::LevenbergMarquardtOptimizer *createOptimizerAt(size_t p, const gtsam::Values &initial); - // gtsam::Values tryOptimizingAt(size_t p) const; - gtsam::Values tryOptimizingAt(size_t p, const gtsam::Values &initial) const; - gtsam::Values projectFrom(size_t p, const gtsam::Values &values) const; - gtsam::Values roundSolution(const gtsam::Values &values) const; - - // Basic API - double cost(const gtsam::Values &values) const; - gtsam::Values initializeRandomly() const; - pair run(const gtsam::Values &initial, size_t min_p, size_t max_p) const; - }; + // Basic API + double cost(const gtsam::Values& values) const; + gtsam::Values initializeRandomly() const; + pair run(const gtsam::Values& initial, size_t min_p, size_t max_p) const; +}; #include - class KeyPairDoubleMap - { - KeyPairDoubleMap(); - KeyPairDoubleMap(const gtsam::KeyPairDoubleMap &other); +class KeyPairDoubleMap { + KeyPairDoubleMap(); + KeyPairDoubleMap(const gtsam::KeyPairDoubleMap& other); - size_t size() const; - bool empty() const; - void clear(); - size_t at(const pair &keypair) const; - }; + size_t size() const; + bool empty() const; + void clear(); + size_t at(const pair& keypair) const; +}; - class MFAS - { - MFAS(const gtsam::BinaryMeasurementsUnit3 &relativeTranslations, - const gtsam::Unit3 &projectionDirection); +class MFAS { + MFAS(const gtsam::BinaryMeasurementsUnit3& relativeTranslations, + const gtsam::Unit3& projectionDirection); - gtsam::KeyPairDoubleMap computeOutlierWeights() const; - gtsam::KeyVector computeOrdering() const; - }; + gtsam::KeyPairDoubleMap computeOutlierWeights() const; + gtsam::KeyVector computeOrdering() const; +}; #include - class TranslationRecovery - { - TranslationRecovery(const gtsam::BinaryMeasurementsUnit3 &relativeTranslations, - const gtsam::LevenbergMarquardtParams &lmParams); - TranslationRecovery( - const gtsam::BinaryMeasurementsUnit3 &relativeTranslations); // default LevenbergMarquardtParams - gtsam::Values run(const double scale) const; - gtsam::Values run() const; // default scale = 1.0 - }; +class TranslationRecovery { + TranslationRecovery(const gtsam::BinaryMeasurementsUnit3 &relativeTranslations, + const gtsam::LevenbergMarquardtParams &lmParams); + TranslationRecovery( + const gtsam::BinaryMeasurementsUnit3 & relativeTranslations); // default LevenbergMarquardtParams + gtsam::Values run(const double scale) const; + gtsam::Values run() const; // default scale = 1.0 +}; - //************************************************************************* - // Navigation - //************************************************************************* - namespace imuBias - { +//************************************************************************* +// Navigation +//************************************************************************* +namespace imuBias { #include - class ConstantBias - { - // Constructors - ConstantBias(); - ConstantBias(Vector biasAcc, Vector biasGyro); +class ConstantBias { + // Constructors + ConstantBias(); + ConstantBias(Vector biasAcc, Vector biasGyro); - // Testable - void print(string s) const; - bool equals(const gtsam::imuBias::ConstantBias &expected, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::imuBias::ConstantBias& expected, double tol) const; - // Group - static gtsam::imuBias::ConstantBias identity(); - gtsam::imuBias::ConstantBias inverse() const; - gtsam::imuBias::ConstantBias compose(const gtsam::imuBias::ConstantBias &b) const; - gtsam::imuBias::ConstantBias between(const gtsam::imuBias::ConstantBias &b) const; + // Group + static gtsam::imuBias::ConstantBias identity(); + gtsam::imuBias::ConstantBias inverse() const; + gtsam::imuBias::ConstantBias compose(const gtsam::imuBias::ConstantBias& b) const; + gtsam::imuBias::ConstantBias between(const gtsam::imuBias::ConstantBias& b) const; - // Manifold - gtsam::imuBias::ConstantBias retract(Vector v) const; - Vector localCoordinates(const gtsam::imuBias::ConstantBias &b) const; + // Manifold + gtsam::imuBias::ConstantBias retract(Vector v) const; + Vector localCoordinates(const gtsam::imuBias::ConstantBias& b) const; - // Lie Group - static gtsam::imuBias::ConstantBias Expmap(Vector v); - static Vector Logmap(const gtsam::imuBias::ConstantBias &b); + // Lie Group + static gtsam::imuBias::ConstantBias Expmap(Vector v); + static Vector Logmap(const gtsam::imuBias::ConstantBias& b); - // Standard Interface - Vector vector() const; - Vector accelerometer() const; - Vector gyroscope() const; - Vector correctAccelerometer(Vector measurement) const; - Vector correctGyroscope(Vector measurement) const; - }; + // Standard Interface + Vector vector() const; + Vector accelerometer() const; + Vector gyroscope() const; + Vector correctAccelerometer(Vector measurement) const; + Vector correctGyroscope(Vector measurement) const; +}; - } // namespace imuBias +}///\namespace imuBias #include - class NavState - { - // Constructors - NavState(); - NavState(const gtsam::Rot3 &R, const gtsam::Point3 &t, Vector v); - NavState(const gtsam::Pose3 &pose, Vector v); +class NavState { + // Constructors + NavState(); + NavState(const gtsam::Rot3& R, const gtsam::Point3& t, Vector v); + NavState(const gtsam::Pose3& pose, Vector v); - // Testable - void print(string s) const; - bool equals(const gtsam::NavState &expected, double tol) const; + // Testable + void print(string s) const; + bool equals(const gtsam::NavState& expected, double tol) const; - // Access - gtsam::Rot3 attitude() const; - gtsam::Point3 position() const; - Vector velocity() const; - gtsam::Pose3 pose() const; - }; + // Access + gtsam::Rot3 attitude() const; + gtsam::Point3 position() const; + Vector velocity() const; + gtsam::Pose3 pose() const; +}; #include - virtual class PreintegratedRotationParams - { - PreintegratedRotationParams(); +virtual class PreintegratedRotationParams { + PreintegratedRotationParams(); - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegratedRotationParams &expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegratedRotationParams& expected, double tol); - void setGyroscopeCovariance(Matrix cov); - void setOmegaCoriolis(Vector omega); - void setBodyPSensor(const gtsam::Pose3 &pose); + void setGyroscopeCovariance(Matrix cov); + void setOmegaCoriolis(Vector omega); + void setBodyPSensor(const gtsam::Pose3& pose); - Matrix getGyroscopeCovariance() const; + Matrix getGyroscopeCovariance() const; - // TODO(frank): allow optional - // boost::optional getOmegaCoriolis() const; - // boost::optional getBodyPSensor() const; - }; + // TODO(frank): allow optional + // boost::optional getOmegaCoriolis() const; + // boost::optional getBodyPSensor() const; +}; #include - virtual class PreintegrationParams : gtsam::PreintegratedRotationParams - { - PreintegrationParams(Vector n_gravity); +virtual class PreintegrationParams : gtsam::PreintegratedRotationParams { + PreintegrationParams(Vector n_gravity); - static gtsam::PreintegrationParams *MakeSharedD(double g); - static gtsam::PreintegrationParams *MakeSharedU(double g); - static gtsam::PreintegrationParams *MakeSharedD(); // default g = 9.81 - static gtsam::PreintegrationParams *MakeSharedU(); // default g = 9.81 + static gtsam::PreintegrationParams* MakeSharedD(double g); + static gtsam::PreintegrationParams* MakeSharedU(double g); + static gtsam::PreintegrationParams* MakeSharedD(); // default g = 9.81 + static gtsam::PreintegrationParams* MakeSharedU(); // default g = 9.81 - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegrationParams &expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegrationParams& expected, double tol); - void setAccelerometerCovariance(Matrix cov); - void setIntegrationCovariance(Matrix cov); - void setUse2ndOrderCoriolis(bool flag); + void setAccelerometerCovariance(Matrix cov); + void setIntegrationCovariance(Matrix cov); + void setUse2ndOrderCoriolis(bool flag); - Matrix getAccelerometerCovariance() const; - Matrix getIntegrationCovariance() const; - bool getUse2ndOrderCoriolis() const; - }; + Matrix getAccelerometerCovariance() const; + Matrix getIntegrationCovariance() const; + bool getUse2ndOrderCoriolis() const; +}; #include - class PreintegratedImuMeasurements - { - // Constructors - PreintegratedImuMeasurements(const gtsam::PreintegrationParams *params); - PreintegratedImuMeasurements(const gtsam::PreintegrationParams *params, - const gtsam::imuBias::ConstantBias &bias); +class PreintegratedImuMeasurements { + // Constructors + PreintegratedImuMeasurements(const gtsam::PreintegrationParams* params); + PreintegratedImuMeasurements(const gtsam::PreintegrationParams* params, + const gtsam::imuBias::ConstantBias& bias); - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegratedImuMeasurements &expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegratedImuMeasurements& expected, double tol); - // Standard Interface - void integrateMeasurement(Vector measuredAcc, Vector measuredOmega, - double deltaT); - void resetIntegration(); - void resetIntegrationAndSetBias(const gtsam::imuBias::ConstantBias &biasHat); + // Standard Interface + void integrateMeasurement(Vector measuredAcc, Vector measuredOmega, + double deltaT); + void resetIntegration(); + void resetIntegrationAndSetBias(const gtsam::imuBias::ConstantBias& biasHat); - Matrix preintMeasCov() const; - Vector preintegrated() const; - double deltaTij() const; - gtsam::Rot3 deltaRij() const; - Vector deltaPij() const; - Vector deltaVij() const; - gtsam::imuBias::ConstantBias biasHat() const; - Vector biasHatVector() const; - gtsam::NavState predict(const gtsam::NavState &state_i, - const gtsam::imuBias::ConstantBias &bias) const; - }; + Matrix preintMeasCov() const; + Vector preintegrated() const; + double deltaTij() const; + gtsam::Rot3 deltaRij() const; + Vector deltaPij() const; + Vector deltaVij() const; + gtsam::imuBias::ConstantBias biasHat() const; + Vector biasHatVector() const; + gtsam::NavState predict(const gtsam::NavState& state_i, + const gtsam::imuBias::ConstantBias& bias) const; +}; - virtual class ImuFactor : gtsam::NonlinearFactor - { - ImuFactor(size_t pose_i, size_t vel_i, size_t pose_j, size_t vel_j, - size_t bias, - const gtsam::PreintegratedImuMeasurements &preintegratedMeasurements); +virtual class ImuFactor: gtsam::NonlinearFactor { + ImuFactor(size_t pose_i, size_t vel_i, size_t pose_j, size_t vel_j, + size_t bias, + const gtsam::PreintegratedImuMeasurements& preintegratedMeasurements); - // Standard Interface - gtsam::PreintegratedImuMeasurements preintegratedMeasurements() const; - Vector evaluateError(const gtsam::Pose3 &pose_i, Vector vel_i, - const gtsam::Pose3 &pose_j, Vector vel_j, - const gtsam::imuBias::ConstantBias &bias); - }; + // Standard Interface + gtsam::PreintegratedImuMeasurements preintegratedMeasurements() const; + Vector evaluateError(const gtsam::Pose3& pose_i, Vector vel_i, + const gtsam::Pose3& pose_j, Vector vel_j, + const gtsam::imuBias::ConstantBias& bias); +}; #include - virtual class PreintegrationCombinedParams : gtsam::PreintegrationParams - { - PreintegrationCombinedParams(Vector n_gravity); +virtual class PreintegrationCombinedParams : gtsam::PreintegrationParams { + PreintegrationCombinedParams(Vector n_gravity); - static gtsam::PreintegrationCombinedParams *MakeSharedD(double g); - static gtsam::PreintegrationCombinedParams *MakeSharedU(double g); - static gtsam::PreintegrationCombinedParams *MakeSharedD(); // default g = 9.81 - static gtsam::PreintegrationCombinedParams *MakeSharedU(); // default g = 9.81 + static gtsam::PreintegrationCombinedParams* MakeSharedD(double g); + static gtsam::PreintegrationCombinedParams* MakeSharedU(double g); + static gtsam::PreintegrationCombinedParams* MakeSharedD(); // default g = 9.81 + static gtsam::PreintegrationCombinedParams* MakeSharedU(); // default g = 9.81 - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegrationCombinedParams &expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegrationCombinedParams& expected, double tol); - void setBiasAccCovariance(Matrix cov); - void setBiasOmegaCovariance(Matrix cov); - void setBiasAccOmegaInt(Matrix cov); + void setBiasAccCovariance(Matrix cov); + void setBiasOmegaCovariance(Matrix cov); + void setBiasAccOmegaInt(Matrix cov); + + Matrix getBiasAccCovariance() const ; + Matrix getBiasOmegaCovariance() const ; + Matrix getBiasAccOmegaInt() const; + +}; - Matrix getBiasAccCovariance() const; - Matrix getBiasOmegaCovariance() const; - Matrix getBiasAccOmegaInt() const; - }; +class PreintegratedCombinedMeasurements { +// Constructors + PreintegratedCombinedMeasurements(const gtsam::PreintegrationCombinedParams* params); + PreintegratedCombinedMeasurements(const gtsam::PreintegrationCombinedParams* params, + const gtsam::imuBias::ConstantBias& bias); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegratedCombinedMeasurements& expected, + double tol); - class PreintegratedCombinedMeasurements - { - // Constructors - PreintegratedCombinedMeasurements(const gtsam::PreintegrationCombinedParams *params); - PreintegratedCombinedMeasurements(const gtsam::PreintegrationCombinedParams *params, - const gtsam::imuBias::ConstantBias &bias); - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegratedCombinedMeasurements &expected, - double tol); + // Standard Interface + void integrateMeasurement(Vector measuredAcc, Vector measuredOmega, + double deltaT); + void resetIntegration(); + void resetIntegrationAndSetBias(const gtsam::imuBias::ConstantBias& biasHat); - // Standard Interface - void integrateMeasurement(Vector measuredAcc, Vector measuredOmega, - double deltaT); - void resetIntegration(); - void resetIntegrationAndSetBias(const gtsam::imuBias::ConstantBias &biasHat); + Matrix preintMeasCov() const; + double deltaTij() const; + gtsam::Rot3 deltaRij() const; + Vector deltaPij() const; + Vector deltaVij() const; + gtsam::imuBias::ConstantBias biasHat() const; + Vector biasHatVector() const; + gtsam::NavState predict(const gtsam::NavState& state_i, + const gtsam::imuBias::ConstantBias& bias) const; +}; - Matrix preintMeasCov() const; - double deltaTij() const; - gtsam::Rot3 deltaRij() const; - Vector deltaPij() const; - Vector deltaVij() const; - gtsam::imuBias::ConstantBias biasHat() const; - Vector biasHatVector() const; - gtsam::NavState predict(const gtsam::NavState &state_i, - const gtsam::imuBias::ConstantBias &bias) const; - }; +virtual class CombinedImuFactor: gtsam::NonlinearFactor { + CombinedImuFactor(size_t pose_i, size_t vel_i, size_t pose_j, size_t vel_j, + size_t bias_i, size_t bias_j, + const gtsam::PreintegratedCombinedMeasurements& CombinedPreintegratedMeasurements); - virtual class CombinedImuFactor : gtsam::NonlinearFactor - { - CombinedImuFactor(size_t pose_i, size_t vel_i, size_t pose_j, size_t vel_j, - size_t bias_i, size_t bias_j, - const gtsam::PreintegratedCombinedMeasurements &CombinedPreintegratedMeasurements); - - // Standard Interface - gtsam::PreintegratedCombinedMeasurements preintegratedMeasurements() const; - Vector evaluateError(const gtsam::Pose3 &pose_i, Vector vel_i, - const gtsam::Pose3 &pose_j, Vector vel_j, - const gtsam::imuBias::ConstantBias &bias_i, - const gtsam::imuBias::ConstantBias &bias_j); - }; + // Standard Interface + gtsam::PreintegratedCombinedMeasurements preintegratedMeasurements() const; + Vector evaluateError(const gtsam::Pose3& pose_i, Vector vel_i, + const gtsam::Pose3& pose_j, Vector vel_j, + const gtsam::imuBias::ConstantBias& bias_i, + const gtsam::imuBias::ConstantBias& bias_j); +}; #include - class PreintegratedAhrsMeasurements - { - // Standard Constructor - PreintegratedAhrsMeasurements(Vector bias, Matrix measuredOmegaCovariance); - PreintegratedAhrsMeasurements(const gtsam::PreintegratedAhrsMeasurements &rhs); +class PreintegratedAhrsMeasurements { + // Standard Constructor + PreintegratedAhrsMeasurements(Vector bias, Matrix measuredOmegaCovariance); + PreintegratedAhrsMeasurements(const gtsam::PreintegratedAhrsMeasurements& rhs); - // Testable - void print(string s) const; - bool equals(const gtsam::PreintegratedAhrsMeasurements &expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::PreintegratedAhrsMeasurements& expected, double tol); - // get Data - gtsam::Rot3 deltaRij() const; - double deltaTij() const; - Vector biasHat() const; + // get Data + gtsam::Rot3 deltaRij() const; + double deltaTij() const; + Vector biasHat() const; - // Standard Interface - void integrateMeasurement(Vector measuredOmega, double deltaT); - void resetIntegration(); - }; + // Standard Interface + void integrateMeasurement(Vector measuredOmega, double deltaT); + void resetIntegration() ; +}; - virtual class AHRSFactor : gtsam::NonlinearFactor - { - AHRSFactor(size_t rot_i, size_t rot_j, size_t bias, - const gtsam::PreintegratedAhrsMeasurements &preintegratedMeasurements, Vector omegaCoriolis); - AHRSFactor(size_t rot_i, size_t rot_j, size_t bias, - const gtsam::PreintegratedAhrsMeasurements &preintegratedMeasurements, Vector omegaCoriolis, - const gtsam::Pose3 &body_P_sensor); +virtual class AHRSFactor : gtsam::NonlinearFactor { + AHRSFactor(size_t rot_i, size_t rot_j,size_t bias, + const gtsam::PreintegratedAhrsMeasurements& preintegratedMeasurements, Vector omegaCoriolis); + AHRSFactor(size_t rot_i, size_t rot_j, size_t bias, + const gtsam::PreintegratedAhrsMeasurements& preintegratedMeasurements, Vector omegaCoriolis, + const gtsam::Pose3& body_P_sensor); - // Standard Interface - gtsam::PreintegratedAhrsMeasurements preintegratedMeasurements() const; - Vector evaluateError(const gtsam::Rot3 &rot_i, const gtsam::Rot3 &rot_j, - Vector bias) const; - gtsam::Rot3 predict(const gtsam::Rot3 &rot_i, Vector bias, - const gtsam::PreintegratedAhrsMeasurements &preintegratedMeasurements, - Vector omegaCoriolis) const; - }; + // Standard Interface + gtsam::PreintegratedAhrsMeasurements preintegratedMeasurements() const; + Vector evaluateError(const gtsam::Rot3& rot_i, const gtsam::Rot3& rot_j, + Vector bias) const; + gtsam::Rot3 predict(const gtsam::Rot3& rot_i, Vector bias, + const gtsam::PreintegratedAhrsMeasurements& preintegratedMeasurements, + Vector omegaCoriolis) const; +}; #include - //virtual class AttitudeFactor : gtsam::NonlinearFactor { - // AttitudeFactor(const Unit3& nZ, const Unit3& bRef); - // AttitudeFactor(); - //}; - virtual class Rot3AttitudeFactor : gtsam::NonlinearFactor - { - Rot3AttitudeFactor(size_t key, const gtsam::Unit3 &nZ, const gtsam::noiseModel::Diagonal *model, - const gtsam::Unit3 &bRef); - Rot3AttitudeFactor(size_t key, const gtsam::Unit3 &nZ, const gtsam::noiseModel::Diagonal *model); - Rot3AttitudeFactor(); - void print(string s) const; - bool equals(const gtsam::NonlinearFactor &expected, double tol) const; - gtsam::Unit3 nZ() const; - gtsam::Unit3 bRef() const; - }; +//virtual class AttitudeFactor : gtsam::NonlinearFactor { +// AttitudeFactor(const Unit3& nZ, const Unit3& bRef); +// AttitudeFactor(); +//}; +virtual class Rot3AttitudeFactor : gtsam::NonlinearFactor{ + Rot3AttitudeFactor(size_t key, const gtsam::Unit3& nZ, const gtsam::noiseModel::Diagonal* model, + const gtsam::Unit3& bRef); + Rot3AttitudeFactor(size_t key, const gtsam::Unit3& nZ, const gtsam::noiseModel::Diagonal* model); + Rot3AttitudeFactor(); + void print(string s) const; + bool equals(const gtsam::NonlinearFactor& expected, double tol) const; + gtsam::Unit3 nZ() const; + gtsam::Unit3 bRef() const; +}; - virtual class Pose3AttitudeFactor : gtsam::NonlinearFactor - { - Pose3AttitudeFactor(size_t key, const gtsam::Unit3 &nZ, - const gtsam::noiseModel::Diagonal *model, - const gtsam::Unit3 &bRef); - Pose3AttitudeFactor(size_t key, const gtsam::Unit3 &nZ, - const gtsam::noiseModel::Diagonal *model); - Pose3AttitudeFactor(); - void print(string s) const; - bool equals(const gtsam::NonlinearFactor &expected, double tol) const; - gtsam::Unit3 nZ() const; - gtsam::Unit3 bRef() const; - }; +virtual class Pose3AttitudeFactor : gtsam::NonlinearFactor { + Pose3AttitudeFactor(size_t key, const gtsam::Unit3& nZ, + const gtsam::noiseModel::Diagonal* model, + const gtsam::Unit3& bRef); + Pose3AttitudeFactor(size_t key, const gtsam::Unit3& nZ, + const gtsam::noiseModel::Diagonal* model); + Pose3AttitudeFactor(); + void print(string s) const; + bool equals(const gtsam::NonlinearFactor& expected, double tol) const; + gtsam::Unit3 nZ() const; + gtsam::Unit3 bRef() const; +}; #include - virtual class GPSFactor : gtsam::NonlinearFactor - { - GPSFactor(size_t key, const gtsam::Point3 &gpsIn, - const gtsam::noiseModel::Base *model); +virtual class GPSFactor : gtsam::NonlinearFactor{ + GPSFactor(size_t key, const gtsam::Point3& gpsIn, + const gtsam::noiseModel::Base* model); - // Testable - void print(string s) const; - bool equals(const gtsam::GPSFactor &expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::GPSFactor& expected, double tol); - // Standard Interface - gtsam::Point3 measurementIn() const; - }; + // Standard Interface + gtsam::Point3 measurementIn() const; +}; - virtual class GPSFactor2 : gtsam::NonlinearFactor - { - GPSFactor2(size_t key, const gtsam::Point3 &gpsIn, - const gtsam::noiseModel::Base *model); +virtual class GPSFactor2 : gtsam::NonlinearFactor { + GPSFactor2(size_t key, const gtsam::Point3& gpsIn, + const gtsam::noiseModel::Base* model); - // Testable - void print(string s) const; - bool equals(const gtsam::GPSFactor2 &expected, double tol); + // Testable + void print(string s) const; + bool equals(const gtsam::GPSFactor2& expected, double tol); - // Standard Interface - gtsam::Point3 measurementIn() const; - }; + // Standard Interface + gtsam::Point3 measurementIn() const; +}; #include - virtual class Scenario - { - gtsam::Pose3 pose(double t) const; - Vector omega_b(double t) const; - Vector velocity_n(double t) const; - Vector acceleration_n(double t) const; - gtsam::Rot3 rotation(double t) const; - gtsam::NavState navState(double t) const; - Vector velocity_b(double t) const; - Vector acceleration_b(double t) const; - }; +virtual class Scenario { + gtsam::Pose3 pose(double t) const; + Vector omega_b(double t) const; + Vector velocity_n(double t) const; + Vector acceleration_n(double t) const; + gtsam::Rot3 rotation(double t) const; + gtsam::NavState navState(double t) const; + Vector velocity_b(double t) const; + Vector acceleration_b(double t) const; +}; - virtual class ConstantTwistScenario : gtsam::Scenario - { - ConstantTwistScenario(Vector w, Vector v); - ConstantTwistScenario(Vector w, Vector v, - const gtsam::Pose3 &nTb0); - }; +virtual class ConstantTwistScenario : gtsam::Scenario { + ConstantTwistScenario(Vector w, Vector v); + ConstantTwistScenario(Vector w, Vector v, + const gtsam::Pose3& nTb0); +}; - virtual class AcceleratingScenario : gtsam::Scenario - { - AcceleratingScenario(const gtsam::Rot3 &nRb, const gtsam::Point3 &p0, - Vector v0, Vector a_n, - Vector omega_b); - }; +virtual class AcceleratingScenario : gtsam::Scenario { + AcceleratingScenario(const gtsam::Rot3& nRb, const gtsam::Point3& p0, + Vector v0, Vector a_n, + Vector omega_b); +}; #include - class ScenarioRunner - { - ScenarioRunner(const gtsam::Scenario &scenario, - const gtsam::PreintegrationParams *p, - double imuSampleTime, - const gtsam::imuBias::ConstantBias &bias); - Vector gravity_n() const; - Vector actualAngularVelocity(double t) const; - Vector actualSpecificForce(double t) const; - Vector measuredAngularVelocity(double t) const; - Vector measuredSpecificForce(double t) const; - double imuSampleTime() const; - gtsam::PreintegratedImuMeasurements integrate( - double T, const gtsam::imuBias::ConstantBias &estimatedBias, - bool corrupted) const; - gtsam::NavState predict( - const gtsam::PreintegratedImuMeasurements &pim, - const gtsam::imuBias::ConstantBias &estimatedBias) const; - Matrix estimateCovariance( - double T, size_t N, - const gtsam::imuBias::ConstantBias &estimatedBias) const; - Matrix estimateNoiseCovariance(size_t N) const; - }; +class ScenarioRunner { + ScenarioRunner(const gtsam::Scenario& scenario, + const gtsam::PreintegrationParams* p, + double imuSampleTime, + const gtsam::imuBias::ConstantBias& bias); + Vector gravity_n() const; + Vector actualAngularVelocity(double t) const; + Vector actualSpecificForce(double t) const; + Vector measuredAngularVelocity(double t) const; + Vector measuredSpecificForce(double t) const; + double imuSampleTime() const; + gtsam::PreintegratedImuMeasurements integrate( + double T, const gtsam::imuBias::ConstantBias& estimatedBias, + bool corrupted) const; + gtsam::NavState predict( + const gtsam::PreintegratedImuMeasurements& pim, + const gtsam::imuBias::ConstantBias& estimatedBias) const; + Matrix estimateCovariance( + double T, size_t N, + const gtsam::imuBias::ConstantBias& estimatedBias) const; + Matrix estimateNoiseCovariance(size_t N) const; +}; - //************************************************************************* - // Utilities - //************************************************************************* +//************************************************************************* +// Utilities +//************************************************************************* - namespace utilities - { +namespace utilities { + + #include + gtsam::KeyList createKeyList(Vector I); + gtsam::KeyList createKeyList(string s, Vector I); + gtsam::KeyVector createKeyVector(Vector I); + gtsam::KeyVector createKeyVector(string s, Vector I); + gtsam::KeySet createKeySet(Vector I); + gtsam::KeySet createKeySet(string s, Vector I); + Matrix extractPoint2(const gtsam::Values& values); + Matrix extractPoint3(const gtsam::Values& values); + gtsam::Values allPose2s(gtsam::Values& values); + Matrix extractPose2(const gtsam::Values& values); + gtsam::Values allPose3s(gtsam::Values& values); + Matrix extractPose3(const gtsam::Values& values); + void perturbPoint2(gtsam::Values& values, double sigma, int seed); + void perturbPose2 (gtsam::Values& values, double sigmaT, double sigmaR, int seed); + void perturbPoint3(gtsam::Values& values, double sigma, int seed); + void insertBackprojections(gtsam::Values& values, const gtsam::PinholeCameraCal3_S2& c, Vector J, Matrix Z, double depth); + void insertProjectionFactors(gtsam::NonlinearFactorGraph& graph, size_t i, Vector J, Matrix Z, const gtsam::noiseModel::Base* model, const gtsam::Cal3_S2* K); + void insertProjectionFactors(gtsam::NonlinearFactorGraph& graph, size_t i, Vector J, Matrix Z, const gtsam::noiseModel::Base* model, const gtsam::Cal3_S2* K, const gtsam::Pose3& body_P_sensor); + Matrix reprojectionErrors(const gtsam::NonlinearFactorGraph& graph, const gtsam::Values& values); + gtsam::Values localToWorld(const gtsam::Values& local, const gtsam::Pose2& base); + gtsam::Values localToWorld(const gtsam::Values& local, const gtsam::Pose2& base, const gtsam::KeyVector& keys); + +} //\namespace utilities #include - gtsam::KeyList createKeyList(Vector I); - gtsam::KeyList createKeyList(string s, Vector I); - gtsam::KeyVector createKeyVector(Vector I); - gtsam::KeyVector createKeyVector(string s, Vector I); - gtsam::KeySet createKeySet(Vector I); - gtsam::KeySet createKeySet(string s, Vector I); - Matrix extractPoint2(const gtsam::Values &values); - Matrix extractPoint3(const gtsam::Values &values); - gtsam::Values allPose2s(gtsam::Values &values); - Matrix extractPose2(const gtsam::Values &values); - gtsam::Values allPose3s(gtsam::Values &values); - Matrix extractPose3(const gtsam::Values &values); - void perturbPoint2(gtsam::Values &values, double sigma, int seed); - void perturbPose2(gtsam::Values &values, double sigmaT, double sigmaR, int seed); - void perturbPoint3(gtsam::Values &values, double sigma, int seed); - void insertBackprojections(gtsam::Values &values, const gtsam::PinholeCameraCal3_S2 &c, Vector J, Matrix Z, double depth); - void insertProjectionFactors(gtsam::NonlinearFactorGraph &graph, size_t i, Vector J, Matrix Z, const gtsam::noiseModel::Base *model, const gtsam::Cal3_S2 *K); - void insertProjectionFactors(gtsam::NonlinearFactorGraph &graph, size_t i, Vector J, Matrix Z, const gtsam::noiseModel::Base *model, const gtsam::Cal3_S2 *K, const gtsam::Pose3 &body_P_sensor); - Matrix reprojectionErrors(const gtsam::NonlinearFactorGraph &graph, const gtsam::Values &values); - gtsam::Values localToWorld(const gtsam::Values &local, const gtsam::Pose2 &base); - gtsam::Values localToWorld(const gtsam::Values &local, const gtsam::Pose2 &base, const gtsam::KeyVector &keys); +class RedirectCout { + RedirectCout(); + string str(); +}; - } // namespace utilities - -#include - class RedirectCout - { - RedirectCout(); - string str(); - }; - -} // namespace gtsam +} diff --git a/python/gtsam/preamble.h b/python/gtsam/preamble.h index fa98cd171..c8a577431 100644 --- a/python/gtsam/preamble.h +++ b/python/gtsam/preamble.h @@ -5,10 +5,10 @@ PYBIND11_MAKE_OPAQUE(std::vector>); #else PYBIND11_MAKE_OPAQUE(std::vector); #endif -PYBIND11_MAKE_OPAQUE(std::vector>); +PYBIND11_MAKE_OPAQUE(std::vector >); PYBIND11_MAKE_OPAQUE(std::vector); -PYBIND11_MAKE_OPAQUE(std::vector>>); -PYBIND11_MAKE_OPAQUE(std::vector>>); +PYBIND11_MAKE_OPAQUE(std::vector > >); +PYBIND11_MAKE_OPAQUE(std::vector > >); PYBIND11_MAKE_OPAQUE(std::vector); -PYBIND11_MAKE_OPAQUE(gtsam::CameraSet>); -PYBIND11_MAKE_OPAQUE(gtsam::CameraSet>); \ No newline at end of file +PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); +PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); \ No newline at end of file diff --git a/python/gtsam/specializations.h b/python/gtsam/specializations.h index 63694f6f4..431697aac 100644 --- a/python/gtsam/specializations.h +++ b/python/gtsam/specializations.h @@ -1,17 +1,17 @@ // Please refer to: https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html // These are required to save one copy operation on Python calls #ifdef GTSAM_ALLOCATOR_TBB -py::bind_vector>>(m_, "KeyVector"); +py::bind_vector > >(m_, "KeyVector"); #else -py::bind_vector>(m_, "KeyVector"); +py::bind_vector >(m_, "KeyVector"); #endif -py::bind_vector>>(m_, "Point2Vector"); -py::bind_vector>(m_, "Pose3Vector"); -py::bind_vector>>>(m_, "BetweenFactorPose3s"); -py::bind_vector>>>(m_, "BetweenFactorPose2s"); -py::bind_vector>>(m_, "BinaryMeasurementsUnit3"); +py::bind_vector > >(m_, "Point2Vector"); +py::bind_vector >(m_, "Pose3Vector"); +py::bind_vector > > >(m_, "BetweenFactorPose3s"); +py::bind_vector > > >(m_, "BetweenFactorPose2s"); +py::bind_vector > >(m_, "BinaryMeasurementsUnit3"); py::bind_map(m_, "IndexPairSetMap"); py::bind_vector(m_, "IndexPairVector"); py::bind_map(m_, "KeyPairDoubleMap"); -py::bind_vector>>(m_, "CameraSetCal3_S2"); -py::bind_vector>>(m_, "CameraSetCal3Bundler"); +py::bind_vector > >(m_, "CameraSetCal3_S2"); +py::bind_vector > >(m_, "CameraSetCal3Bundler"); diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index 901aad0b9..574452afa 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -14,10 +14,11 @@ import numpy as np import gtsam as g from gtsam.utils.test_case import GtsamTestCase -from gtsam import Cal3_S2, Cal3Bundler, CameraSetCal3_S2,\ - CameraSetCal3Bundler, PinholeCameraCal3_S2, PinholeCameraCal3Bundler, \ - Point3, Pose3, Point2Vector, Pose3Vector, Rot3, triangulatePoint3 - +from gtsam import Cal3_S2, Cal3Bundler, Rot3, Pose3, \ + PinholeCameraCal3_S2, PinholeCameraCal3Bundler, Point3, \ + Point2Vector, Pose3Vector, triangulatePoint3, \ + CameraSetCal3_S2, CameraSetCal3Bundler +from numpy.core.records import array class TestVisualISAMExample(GtsamTestCase): """ Tests for triangulation with shared and individual calibrations """ From a7248163e8d51d97885fdc0949c2d703d922ede8 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sat, 5 Dec 2020 18:09:56 -0500 Subject: [PATCH 152/261] format python triangulation tests --- python/gtsam/tests/test_Triangulation.py | 45 ++++++++++++++---------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index 574452afa..b54c05ce1 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -10,16 +10,16 @@ Author: Frank Dellaert & Fan Jiang (Python) """ import unittest -import numpy as np - import gtsam as g +import numpy as np +from gtsam import (Cal3_S2, Cal3Bundler, CameraSetCal3_S2, + CameraSetCal3Bundler, PinholeCameraCal3_S2, + PinholeCameraCal3Bundler, Point2Vector, Point3, Pose3, + Pose3Vector, Rot3, triangulatePoint3) from gtsam.utils.test_case import GtsamTestCase -from gtsam import Cal3_S2, Cal3Bundler, Rot3, Pose3, \ - PinholeCameraCal3_S2, PinholeCameraCal3Bundler, Point3, \ - Point2Vector, Pose3Vector, triangulatePoint3, \ - CameraSetCal3_S2, CameraSetCal3Bundler from numpy.core.records import array + class TestVisualISAMExample(GtsamTestCase): """ Tests for triangulation with shared and individual calibrations """ @@ -38,7 +38,7 @@ class TestVisualISAMExample(GtsamTestCase): # landmark ~5 meters infront of camera self.landmark = Point3(5, 0.5, 1.2) - + def generate_measurements(self, calibration, camera_model, camera_set, *cal_params): """ Generate vector of measurements for given calibration and camera model Args: @@ -53,26 +53,27 @@ class TestVisualISAMExample(GtsamTestCase): cameras = camera_set() else: cameras = [] - measurements = Point2Vector() + measurements = Point2Vector() for k, pose in zip(cal_params, self.poses): K = calibration(*k) camera = camera_model(pose, K) cameras.append(camera) z = camera.project(self.landmark) - measurements.append(z) + measurements.append(z) return measurements, cameras - def test_TriangulationExample(self): """ Tests triangulation with shared Cal3_S2 calibration""" # Some common constants - sharedCal = (1500, 1200, 0, 640, 480) + sharedCal = (1500, 1200, 0, 640, 480) - measurements, _ = self.generate_measurements(Cal3_S2, PinholeCameraCal3_S2, None, sharedCal, sharedCal) + measurements, _ = self.generate_measurements( + Cal3_S2, PinholeCameraCal3_S2, None, sharedCal, sharedCal) - triangulated_landmark = triangulatePoint3(self.poses, Cal3_S2(sharedCal), measurements, rank_tol=1e-9, optimize=True) + triangulated_landmark = triangulatePoint3(self.poses, Cal3_S2( + sharedCal), measurements, rank_tol=1e-9, optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) # Add some noise and try again: result should be ~ (4.995, 0.499167, 1.19814) @@ -80,7 +81,8 @@ class TestVisualISAMExample(GtsamTestCase): measurements_noisy.append(measurements[0] - np.array([0.1, 0.5])) measurements_noisy.append(measurements[1] - np.array([-0.2, 0.3])) - triangulated_landmark = triangulatePoint3(self.poses, Cal3_S2(sharedCal), measurements_noisy, rank_tol=1e-9, optimize=True) + triangulated_landmark = triangulatePoint3(self.poses, Cal3_S2( + sharedCal), measurements_noisy, rank_tol=1e-9, optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-2) def test_distinct_Ks(self): @@ -89,9 +91,11 @@ class TestVisualISAMExample(GtsamTestCase): K1 = (1500, 1200, 0, 640, 480) K2 = (1600, 1300, 0, 650, 440) - measurements, cameras = self.generate_measurements(Cal3_S2, PinholeCameraCal3_S2, CameraSetCal3_S2, K1, K2) + measurements, cameras = self.generate_measurements( + Cal3_S2, PinholeCameraCal3_S2, CameraSetCal3_S2, K1, K2) - triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol=1e-9, optimize=True) + triangulated_landmark = triangulatePoint3( + cameras, measurements, rank_tol=1e-9, optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) def test_distinct_Ks_Bundler(self): @@ -100,10 +104,13 @@ class TestVisualISAMExample(GtsamTestCase): K1 = (1500, 0, 0, 640, 480) K2 = (1600, 0, 0, 650, 440) - measurements, cameras = self.generate_measurements(Cal3Bundler, PinholeCameraCal3Bundler, CameraSetCal3Bundler, K1, K2) + measurements, cameras = self.generate_measurements( + Cal3Bundler, PinholeCameraCal3Bundler, CameraSetCal3Bundler, K1, K2) + + triangulated_landmark = triangulatePoint3( + cameras, measurements, rank_tol=1e-9, optimize=True) + self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) - triangulated_landmark = triangulatePoint3(cameras, measurements, rank_tol=1e-9, optimize=True) - self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) if __name__ == "__main__": unittest.main() From d05f360c1146d0af3a90df30629df2f89eddefe0 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sat, 5 Dec 2020 18:15:53 -0500 Subject: [PATCH 153/261] more formatting --- python/gtsam/preamble.h | 2 +- python/gtsam/tests/test_Triangulation.py | 46 ++++++++++++++++-------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/python/gtsam/preamble.h b/python/gtsam/preamble.h index c8a577431..b56766c72 100644 --- a/python/gtsam/preamble.h +++ b/python/gtsam/preamble.h @@ -11,4 +11,4 @@ PYBIND11_MAKE_OPAQUE(std::vector > >); PYBIND11_MAKE_OPAQUE(std::vector); PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); -PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); \ No newline at end of file +PYBIND11_MAKE_OPAQUE(gtsam::CameraSet >); diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index b54c05ce1..6fdc4d148 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -39,12 +39,14 @@ class TestVisualISAMExample(GtsamTestCase): # landmark ~5 meters infront of camera self.landmark = Point3(5, 0.5, 1.2) - def generate_measurements(self, calibration, camera_model, camera_set, *cal_params): - """ Generate vector of measurements for given calibration and camera model + def generate_measurements(self, calibration, camera_model, cal_params, camera_set=None): + """ + Generate vector of measurements for given calibration and camera model. + Args: calibration: Camera calibration e.g. Cal3_S2 camera_model: Camera model e.g. PinholeCameraCal3_S2 - cal_params: (list of) camera parameters e.g. K1, K2 + cal_params: Iterable of camera parameters for `calibration` e.g. [K1, K2] camera_set: Cameraset object (for individual calibrations) Returns: list of measurements and list/CameraSet object for cameras @@ -69,11 +71,15 @@ class TestVisualISAMExample(GtsamTestCase): # Some common constants sharedCal = (1500, 1200, 0, 640, 480) - measurements, _ = self.generate_measurements( - Cal3_S2, PinholeCameraCal3_S2, None, sharedCal, sharedCal) + measurements, _ = self.generate_measurements(Cal3_S2, + PinholeCameraCal3_S2, + (sharedCal, sharedCal)) - triangulated_landmark = triangulatePoint3(self.poses, Cal3_S2( - sharedCal), measurements, rank_tol=1e-9, optimize=True) + triangulated_landmark = triangulatePoint3(self.poses, + Cal3_S2(sharedCal), + measurements, + rank_tol=1e-9, + optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) # Add some noise and try again: result should be ~ (4.995, 0.499167, 1.19814) @@ -81,8 +87,12 @@ class TestVisualISAMExample(GtsamTestCase): measurements_noisy.append(measurements[0] - np.array([0.1, 0.5])) measurements_noisy.append(measurements[1] - np.array([-0.2, 0.3])) - triangulated_landmark = triangulatePoint3(self.poses, Cal3_S2( - sharedCal), measurements_noisy, rank_tol=1e-9, optimize=True) + triangulated_landmark = triangulatePoint3(self.poses, + Cal3_S2(sharedCal), + measurements_noisy, + rank_tol=1e-9, + optimize=True) + self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-2) def test_distinct_Ks(self): @@ -91,8 +101,10 @@ class TestVisualISAMExample(GtsamTestCase): K1 = (1500, 1200, 0, 640, 480) K2 = (1600, 1300, 0, 650, 440) - measurements, cameras = self.generate_measurements( - Cal3_S2, PinholeCameraCal3_S2, CameraSetCal3_S2, K1, K2) + measurements, cameras = self.generate_measurements(Cal3_S2, + PinholeCameraCal3_S2, + (K1, K2), + camera_set=CameraSetCal3_S2) triangulated_landmark = triangulatePoint3( cameras, measurements, rank_tol=1e-9, optimize=True) @@ -104,11 +116,15 @@ class TestVisualISAMExample(GtsamTestCase): K1 = (1500, 0, 0, 640, 480) K2 = (1600, 0, 0, 650, 440) - measurements, cameras = self.generate_measurements( - Cal3Bundler, PinholeCameraCal3Bundler, CameraSetCal3Bundler, K1, K2) + measurements, cameras = self.generate_measurements(Cal3Bundler, + PinholeCameraCal3Bundler, + (K1, K2), + camera_set=CameraSetCal3Bundler) - triangulated_landmark = triangulatePoint3( - cameras, measurements, rank_tol=1e-9, optimize=True) + triangulated_landmark = triangulatePoint3(cameras, + measurements, + rank_tol=1e-9, + optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) From 3da28858317bf46cea8b3cb21abb17e2674c7fce Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sat, 5 Dec 2020 18:18:30 -0500 Subject: [PATCH 154/261] remove unused imports --- python/gtsam/tests/test_Triangulation.py | 40 +++++++++++++----------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/python/gtsam/tests/test_Triangulation.py b/python/gtsam/tests/test_Triangulation.py index 6fdc4d148..399cf019d 100644 --- a/python/gtsam/tests/test_Triangulation.py +++ b/python/gtsam/tests/test_Triangulation.py @@ -10,14 +10,14 @@ Author: Frank Dellaert & Fan Jiang (Python) """ import unittest -import gtsam as g import numpy as np + +import gtsam from gtsam import (Cal3_S2, Cal3Bundler, CameraSetCal3_S2, CameraSetCal3Bundler, PinholeCameraCal3_S2, PinholeCameraCal3Bundler, Point2Vector, Point3, Pose3, - Pose3Vector, Rot3, triangulatePoint3) + Pose3Vector, Rot3) from gtsam.utils.test_case import GtsamTestCase -from numpy.core.records import array class TestVisualISAMExample(GtsamTestCase): @@ -75,11 +75,11 @@ class TestVisualISAMExample(GtsamTestCase): PinholeCameraCal3_S2, (sharedCal, sharedCal)) - triangulated_landmark = triangulatePoint3(self.poses, - Cal3_S2(sharedCal), - measurements, - rank_tol=1e-9, - optimize=True) + triangulated_landmark = gtsam.triangulatePoint3(self.poses, + Cal3_S2(sharedCal), + measurements, + rank_tol=1e-9, + optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) # Add some noise and try again: result should be ~ (4.995, 0.499167, 1.19814) @@ -87,11 +87,11 @@ class TestVisualISAMExample(GtsamTestCase): measurements_noisy.append(measurements[0] - np.array([0.1, 0.5])) measurements_noisy.append(measurements[1] - np.array([-0.2, 0.3])) - triangulated_landmark = triangulatePoint3(self.poses, - Cal3_S2(sharedCal), - measurements_noisy, - rank_tol=1e-9, - optimize=True) + triangulated_landmark = gtsam.triangulatePoint3(self.poses, + Cal3_S2(sharedCal), + measurements_noisy, + rank_tol=1e-9, + optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-2) @@ -106,8 +106,10 @@ class TestVisualISAMExample(GtsamTestCase): (K1, K2), camera_set=CameraSetCal3_S2) - triangulated_landmark = triangulatePoint3( - cameras, measurements, rank_tol=1e-9, optimize=True) + triangulated_landmark = gtsam.triangulatePoint3(cameras, + measurements, + rank_tol=1e-9, + optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) def test_distinct_Ks_Bundler(self): @@ -121,10 +123,10 @@ class TestVisualISAMExample(GtsamTestCase): (K1, K2), camera_set=CameraSetCal3Bundler) - triangulated_landmark = triangulatePoint3(cameras, - measurements, - rank_tol=1e-9, - optimize=True) + triangulated_landmark = gtsam.triangulatePoint3(cameras, + measurements, + rank_tol=1e-9, + optimize=True) self.gtsamAssertEquals(self.landmark, triangulated_landmark, 1e-9) From af069ab4b28bc31fe8e0c06e060c5d687bc954ce Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Sun, 6 Dec 2020 13:50:44 -0500 Subject: [PATCH 155/261] fix comment --- gtsam/nonlinear/GncOptimizer.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index 7c41b2475..d540dffbb 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -10,8 +10,8 @@ * -------------------------------------------------------------------------- */ /** - * @file testGncOptimizer.cpp - * @brief Unit tests for GncOptimizer class + * @file GncOptimizer.cpp + * @brief The GncOptimizer class * @author Jingnan Shi * @author Luca Carlone * @author Frank Dellaert From 47775a7a4f7134c382e7b47c0d340e9c65a4fc7e Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Mon, 7 Dec 2020 00:53:21 -0500 Subject: [PATCH 156/261] TLS wip --- gtsam/nonlinear/GncOptimizer.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index d540dffbb..be7d046c6 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -119,6 +119,9 @@ public: case GM: std::cout << "lossType: Geman McClure" << "\n"; break; + case TLS: + std::cout << "lossType: Truncated Least-squares" << "\n"; + break; default: throw std::runtime_error("GncParams::print: unknown loss type."); } @@ -193,6 +196,18 @@ public: GaussNewtonOptimizer baseOptimizer(nfg_, state_); Values result = baseOptimizer.optimize(); double mu = initializeMu(); + + // handle the degenerate case for TLS cost that corresponds to small + // maximum residual error at initialization + if (mu <= 0 && params_.lossType == GncParameters::TLS) { + if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { + std::cout << "GNC Optimizer stopped because maximum residual at " + "initialization is small." << std::endl; + result.print("result\n"); + } + return result; + } + for (size_t iter = 0; iter < params_.maxIterations; iter++) { // display info @@ -238,6 +253,11 @@ public: switch (params_.lossType) { case GncParameters::GM: return 2 * rmax_sq / params_.barcSq; // initial mu + case GncParameters::TLS: + // initialize mu to the value specified in Remark 5 in GNC paper + // degenerate case: residual is close to zero so mu approximately equals + // to -1 + return params_.barcSq / (2 * rmax_sq - params_.barcSq); default: throw std::runtime_error( "GncOptimizer::initializeMu: called with unknown loss type."); @@ -249,6 +269,9 @@ public: switch (params_.lossType) { case GncParameters::GM: return std::max(1.0, mu / params_.muStep); // reduce mu, but saturate at 1 + case GncParameters::TLS: + // increases mu at each iteration + return mu * params_.muStep; default: throw std::runtime_error( "GncOptimizer::updateMu: called with unknown loss type."); @@ -260,6 +283,7 @@ public: switch (params_.lossType) { case GncParameters::GM: return std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function + // TODO: Add TLS default: throw std::runtime_error( "GncOptimizer::checkMuConvergence: called with unknown loss type."); @@ -317,6 +341,7 @@ public: } } return weights; + // TODO: Add TLS default: throw std::runtime_error( "GncOptimizer::calculateWeights: called with unknown loss type."); From 9903fb91d0ceaa65885a2c42282e0563bb104d63 Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Mon, 7 Dec 2020 13:24:49 -0500 Subject: [PATCH 157/261] tls done except unit tests --- gtsam/nonlinear/GncOptimizer.h | 31 +++++++++++++++++++++++++++---- tests/testGncOptimizer.cpp | 4 +++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index be7d046c6..b6e6933ec 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -65,6 +65,7 @@ public: size_t maxIterations = 100; /* maximum number of iterations*/ double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ + double relativeMuTol = 1e-5; ///< The maximum relative mu decrease to stop iterating VerbosityGNC verbosityGNC = SILENT; /* verbosity level */ std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ @@ -89,6 +90,10 @@ public: void setMuStep(const double step) { muStep = step; } + /// Set the maximum relative difference in mu values to stop iterating + void setRelativeMuTol(double value) { + relativeMuTol = value; + } /// Set the verbosity level void setVerbosityGNC(const VerbosityGNC verbosity) { verbosityGNC = verbosity; @@ -196,6 +201,7 @@ public: GaussNewtonOptimizer baseOptimizer(nfg_, state_); Values result = baseOptimizer.optimize(); double mu = initializeMu(); + double mu_prev = mu; // handle the degenerate case for TLS cost that corresponds to small // maximum residual error at initialization @@ -225,7 +231,7 @@ public: result = baseOptimizer_iter.optimize(); // stopping condition - if (checkMuConvergence(mu)) { + if (checkMuConvergence(mu, mu_prev)) { // display info if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { std::cout << "final iterations: " << iter << std::endl; @@ -235,6 +241,7 @@ public: break; } // otherwise update mu + mu_prev = mu; mu = updateMu(mu); } return result; @@ -279,11 +286,12 @@ public: } /// check if we have reached the value of mu for which the surrogate loss matches the original loss - bool checkMuConvergence(const double mu) const { + bool checkMuConvergence(const double mu, const double mu_prev) const { switch (params_.lossType) { case GncParameters::GM: return std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function - // TODO: Add TLS + case GncParameters::TLS: + return std::fabs(mu - mu_prev) < params_.relativeMuTol; default: throw std::runtime_error( "GncOptimizer::checkMuConvergence: called with unknown loss type."); @@ -341,7 +349,22 @@ public: } } return weights; - // TODO: Add TLS + case GncParameters::TLS: // use eq (14) in GNC paper + double upperbound = (mu + 1) / mu * params_.barcSq; + double lowerbound = mu / (mu +1 ) * params_.barcSq; + for (size_t k : unknownWeights) { + if (nfg_[k]) { + double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual + if (u2_k >= upperbound ) { + weights[k] = 0; + } else if (u2_k <= lowerbound) { + weights[k] = 1; + } else { + weights[k] = std::sqrt(params_.barcSq * mu * (mu + 1) / u2_k ) - mu; + } + } + } + return weights; default: throw std::runtime_error( "GncOptimizer::calculateWeights: called with unknown loss type."); diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 5006aa941..3f784b96e 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -162,7 +162,9 @@ TEST(GncOptimizer, checkMuConvergence) { gncParams); double mu = 1.0; - CHECK(gnc.checkMuConvergence(mu)); + CHECK(gnc.checkMuConvergence(mu, 0)); + + // TODO: test relative mu convergence } /* ************************************************************************* */ From d85d9c6194623a462c5b0288967503be2a95053f Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Mon, 7 Dec 2020 13:45:12 -0500 Subject: [PATCH 158/261] minor fix --- gtsam/nonlinear/GncOptimizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index b6e6933ec..40ed8c49a 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -10,7 +10,7 @@ * -------------------------------------------------------------------------- */ /** - * @file GncOptimizer.cpp + * @file GncOptimizer.h * @brief The GncOptimizer class * @author Jingnan Shi * @author Luca Carlone From 58e49fc0fc64a207154221d7ddd30d9dc19ebaf6 Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Mon, 7 Dec 2020 15:08:50 -0500 Subject: [PATCH 159/261] fix scoping --- gtsam/nonlinear/GncOptimizer.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index 40ed8c49a..f5412c6ce 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -340,7 +340,7 @@ public: // update weights of known inlier/outlier measurements switch (params_.lossType) { - case GncParameters::GM: // use eq (12) in GNC paper + case GncParameters::GM: { // use eq (12) in GNC paper for (size_t k : unknownWeights) { if (nfg_[k]) { double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual @@ -349,22 +349,25 @@ public: } } return weights; - case GncParameters::TLS: // use eq (14) in GNC paper + } + case GncParameters::TLS: { // use eq (14) in GNC paper double upperbound = (mu + 1) / mu * params_.barcSq; - double lowerbound = mu / (mu +1 ) * params_.barcSq; + double lowerbound = mu / (mu + 1) * params_.barcSq; for (size_t k : unknownWeights) { if (nfg_[k]) { - double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual - if (u2_k >= upperbound ) { + double u2_k = nfg_[k]->error( + currentEstimate); // squared (and whitened) residual + if (u2_k >= upperbound) { weights[k] = 0; } else if (u2_k <= lowerbound) { weights[k] = 1; } else { - weights[k] = std::sqrt(params_.barcSq * mu * (mu + 1) / u2_k ) - mu; + weights[k] = std::sqrt(params_.barcSq * mu * (mu + 1) / u2_k) - mu; } } } return weights; + } default: throw std::runtime_error( "GncOptimizer::calculateWeights: called with unknown loss type."); From d0a81f8441ba91eab1bbfdf7af1fa0d69db99c54 Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Mon, 7 Dec 2020 16:04:36 -0500 Subject: [PATCH 160/261] mu initialization test & minor formatting fixes --- tests/testGncOptimizer.cpp | 135 +++++++++++++++++++++++-------------- 1 file changed, 84 insertions(+), 51 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 3f784b96e..ca40231c9 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -16,29 +16,32 @@ * @author Luca Carlone * @author Frank Dellaert * - * Implementation of the paper: Yang, Antonante, Tzoumas, Carlone, "Graduated Non-Convexity for Robust Spatial Perception: - * From Non-Minimal Solvers to Global Outlier Rejection", ICRA/RAL, 2020. (arxiv version: https://arxiv.org/pdf/1909.08605.pdf) + * Implementation of the paper: Yang, Antonante, Tzoumas, Carlone, "Graduated + * Non-Convexity for Robust Spatial Perception: From Non-Minimal Solvers to + * Global Outlier Rejection", ICRA/RAL, 2020. (arxiv version: + * https://arxiv.org/pdf/1909.08605.pdf) * * See also: - * Antonante, Tzoumas, Yang, Carlone, "Outlier-Robust Estimation: Hardness, Minimally-Tuned Algorithms, and Applications", - * arxiv: https://arxiv.org/pdf/2007.15109.pdf, 2020. + * Antonante, Tzoumas, Yang, Carlone, "Outlier-Robust Estimation: Hardness, + * Minimally-Tuned Algorithms, and Applications", arxiv: + * https://arxiv.org/pdf/2007.15109.pdf, 2020. */ -#include -#include -#include #include +#include +#include +#include using namespace std; using namespace gtsam; -using symbol_shorthand::X; using symbol_shorthand::L; +using symbol_shorthand::X; static double tol = 1e-7; /* ************************************************************************* */ TEST(GncOptimizer, gncParamsConstructor) { - //check params are correctly parsed + // check params are correctly parsed LevenbergMarquardtParams lmParams; GncParams gncParams1(lmParams); CHECK(lmParams.equals(gncParams1.baseOptimizerParams)); @@ -69,7 +72,8 @@ TEST(GncOptimizer, gncParamsConstructor) { /* ************************************************************************* */ TEST(GncOptimizer, gncConstructor) { // has to have Gaussian noise models ! - auto fg = example::createReallyNonlinearFactorGraph(); // just a unary factor on a 2D point + auto fg = example::createReallyNonlinearFactorGraph(); // just a unary factor + // on a 2D point Point2 p0(3, 3); Values initial; @@ -77,8 +81,8 @@ TEST(GncOptimizer, gncConstructor) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); - auto gnc = GncOptimizer>(fg, initial, - gncParams); + auto gnc = + GncOptimizer>(fg, initial, gncParams); CHECK(gnc.getFactors().equals(fg)); CHECK(gnc.getState().equals(initial)); @@ -97,10 +101,11 @@ TEST(GncOptimizer, gncConstructorWithRobustGraphAsInput) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); - auto gnc = GncOptimizer>(fg_robust, - initial, gncParams); + auto gnc = GncOptimizer>( + fg_robust, initial, gncParams); - // make sure that when parsing the graph is transformed into one without robust loss + // make sure that when parsing the graph is transformed into one without + // robust loss CHECK(fg.equals(gnc.getFactors())); } @@ -112,13 +117,25 @@ TEST(GncOptimizer, initializeMu) { Values initial; initial.insert(X(1), p0); + // testing GM mu initialization LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); gncParams.setLossType( GncParams::RobustLossType::GM); - auto gnc = GncOptimizer>(fg, initial, - gncParams); - EXPECT_DOUBLES_EQUAL(gnc.initializeMu(), 2 * 198.999, 1e-3); // according to rmk 5 in the gnc paper: m0 = 2 rmax^2 / barcSq (barcSq=1 in this example) + auto gnc_gm = + GncOptimizer>(fg, initial, gncParams); + // according to rmk 5 in the gnc paper: m0 = 2 rmax^2 / barcSq + // (barcSq=1 in this example) + EXPECT_DOUBLES_EQUAL(gnc_gm.initializeMu(), 2 * 198.999, 1e-3); + + // testing TLS mu initialization + gncParams.setLossType( + GncParams::RobustLossType::TLS); + auto gnc_tls = + GncOptimizer>(fg, initial, gncParams); + // according to rmk 5 in the gnc paper: m0 = barcSq / (2 * rmax^2 - barcSq) + // (barcSq=1 in this example) + EXPECT_DOUBLES_EQUAL(gnc_gm.initializeMu(), 1 / (2 * 198.999 - 1), 1e-3); } /* ************************************************************************* */ @@ -134,8 +151,8 @@ TEST(GncOptimizer, updateMu) { GncParams gncParams(lmParams); gncParams.setLossType( GncParams::RobustLossType::GM); - auto gnc = GncOptimizer>(fg, initial, - gncParams); + auto gnc = + GncOptimizer>(fg, initial, gncParams); double mu = 5.0; EXPECT_DOUBLES_EQUAL(gnc.updateMu(mu), mu / 1.4, tol); @@ -158,8 +175,8 @@ TEST(GncOptimizer, checkMuConvergence) { GncParams gncParams(lmParams); gncParams.setLossType( GncParams::RobustLossType::GM); - auto gnc = GncOptimizer>(fg, initial, - gncParams); + auto gnc = + GncOptimizer>(fg, initial, gncParams); double mu = 1.0; CHECK(gnc.checkMuConvergence(mu, 0)); @@ -175,11 +192,12 @@ TEST(GncOptimizer, calculateWeights) { Values initial; initial.insert(X(1), p0); - // we have 4 factors, 3 with zero errors (inliers), 1 with error 50 = 0.5 * 1/sigma^2 || [1;0] - [0;0] ||^2 (outlier) + // we have 4 factors, 3 with zero errors (inliers), 1 with error 50 = 0.5 * + // 1/sigma^2 || [1;0] - [0;0] ||^2 (outlier) Vector weights_expected = Vector::Zero(4); - weights_expected[0] = 1.0; // zero error - weights_expected[1] = 1.0; // zero error - weights_expected[2] = 1.0; // zero error + weights_expected[0] = 1.0; // zero error + weights_expected[1] = 1.0; // zero error + weights_expected[2] = 1.0; // zero error weights_expected[3] = std::pow(1.0 / (50.0 + 1.0), 2); // outlier, error = 50 GaussNewtonParams gnParams; @@ -191,10 +209,11 @@ TEST(GncOptimizer, calculateWeights) { mu = 2.0; double barcSq = 5.0; - weights_expected[3] = std::pow(mu * barcSq / (50.0 + mu * barcSq), 2); // outlier, error = 50 + weights_expected[3] = + std::pow(mu * barcSq / (50.0 + mu * barcSq), 2); // outlier, error = 50 gncParams.setInlierThreshold(barcSq); - auto gnc2 = GncOptimizer>(fg, initial, - gncParams); + auto gnc2 = + GncOptimizer>(fg, initial, gncParams); weights_actual = gnc2.calculateWeights(initial, mu); CHECK(assert_equal(weights_expected, weights_actual, tol)); } @@ -203,16 +222,17 @@ TEST(GncOptimizer, calculateWeights) { TEST(GncOptimizer, makeWeightedGraph) { // create original factor double sigma1 = 0.1; - NonlinearFactorGraph nfg = example::nonlinearFactorGraphWithGivenSigma( - sigma1); + NonlinearFactorGraph nfg = + example::nonlinearFactorGraphWithGivenSigma(sigma1); // create expected double sigma2 = 10; - NonlinearFactorGraph expected = example::nonlinearFactorGraphWithGivenSigma( - sigma2); + NonlinearFactorGraph expected = + example::nonlinearFactorGraphWithGivenSigma(sigma2); // create weights - Vector weights = Vector::Ones(1); // original info:1/0.1^2 = 100. New info: 1/10^2 = 0.01. Ratio is 10-4 + Vector weights = Vector::Ones( + 1); // original info:1/0.1^2 = 100. New info: 1/10^2 = 0.01. Ratio is 10-4 weights[0] = 1e-4; // create actual @@ -223,7 +243,7 @@ TEST(GncOptimizer, makeWeightedGraph) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); auto gnc = GncOptimizer>(nfg, initial, - gncParams); + gncParams); NonlinearFactorGraph actual = gnc.makeWeightedGraph(weights); // check it's all good @@ -240,8 +260,8 @@ TEST(GncOptimizer, optimizeSimple) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); - auto gnc = GncOptimizer>(fg, initial, - gncParams); + auto gnc = + GncOptimizer>(fg, initial, gncParams); Values actual = gnc.optimize(); DOUBLES_EQUAL(0, fg.error(actual), tol); @@ -259,17 +279,23 @@ TEST(GncOptimizer, optimize) { GaussNewtonParams gnParams; GaussNewtonOptimizer gn(fg, initial, gnParams); Values gn_results = gn.optimize(); - // converges to incorrect point due to lack of robustness to an outlier, ideal solution is Point2(0,0) + // converges to incorrect point due to lack of robustness to an outlier, ideal + // solution is Point2(0,0) CHECK(assert_equal(Point2(0.25, 0.0), gn_results.at(X(1)), 1e-3)); // try with robust loss function and standard GN - auto fg_robust = example::sharedRobustFactorGraphWithOutliers(); // same as fg, but with factors wrapped in Geman McClure losses + auto fg_robust = + example::sharedRobustFactorGraphWithOutliers(); // same as fg, but with + // factors wrapped in + // Geman McClure losses GaussNewtonOptimizer gn2(fg_robust, initial, gnParams); Values gn2_results = gn2.optimize(); // converges to incorrect point, this time due to the nonconvexity of the loss - CHECK(assert_equal(Point2(0.999706, 0.0), gn2_results.at(X(1)), 1e-3)); + CHECK( + assert_equal(Point2(0.999706, 0.0), gn2_results.at(X(1)), 1e-3)); - // .. but graduated nonconvexity ensures both robustness and convergence in the face of nonconvexity + // .. but graduated nonconvexity ensures both robustness and convergence in + // the face of nonconvexity GncParams gncParams(gnParams); // gncParams.setVerbosityGNC(GncParams::VerbosityGNC::SUMMARY); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -315,31 +341,38 @@ TEST(GncOptimizer, optimizeSmallPoseGraph) { boost::tie(graph, initial) = load2D(filename); // Add a Gaussian prior on first poses Pose2 priorMean(0.0, 0.0, 0.0); // prior at origin - SharedDiagonal priorNoise = noiseModel::Diagonal::Sigmas(Vector3(0.01, 0.01, 0.01)); - graph -> addPrior(0, priorMean, priorNoise); + SharedDiagonal priorNoise = + noiseModel::Diagonal::Sigmas(Vector3(0.01, 0.01, 0.01)); + graph->addPrior(0, priorMean, priorNoise); /// get expected values by optimizing outlier-free graph Values expected = LevenbergMarquardtOptimizer(*graph, *initial).optimize(); // add a few outliers - SharedDiagonal betweenNoise = noiseModel::Diagonal::Sigmas(Vector3(0.1, 0.1, 0.01)); - graph->push_back( BetweenFactor(90 , 50 , Pose2(), betweenNoise) ); // some arbitrary and incorrect between factor + SharedDiagonal betweenNoise = + noiseModel::Diagonal::Sigmas(Vector3(0.1, 0.1, 0.01)); + graph->push_back(BetweenFactor( + 90, 50, Pose2(), + betweenNoise)); // some arbitrary and incorrect between factor /// get expected values by optimizing outlier-free graph - Values expectedWithOutliers = LevenbergMarquardtOptimizer(*graph, *initial).optimize(); + Values expectedWithOutliers = + LevenbergMarquardtOptimizer(*graph, *initial).optimize(); // as expected, the following test fails due to the presence of an outlier! // CHECK(assert_equal(expected, expectedWithOutliers, 1e-3)); // GNC - // Note: in difficult instances, we set the odometry measurements to be inliers, - // but this problem is simple enought to succeed even without that assumption - // std::vector knownInliers; + // Note: in difficult instances, we set the odometry measurements to be + // inliers, but this problem is simple enought to succeed even without that + // assumption std::vector knownInliers; GncParams gncParams; - auto gnc = GncOptimizer>(*graph, *initial, gncParams); + auto gnc = + GncOptimizer>(*graph, *initial, gncParams); Values actual = gnc.optimize(); // compare - CHECK(assert_equal(expected, actual, 1e-3)); // yay! we are robust to outliers! + CHECK( + assert_equal(expected, actual, 1e-3)); // yay! we are robust to outliers! } /* ************************************************************************* */ From 9caa0d14cf99fc48b46bbf61da9224d5e7056e1f Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Mon, 7 Dec 2020 16:16:21 -0500 Subject: [PATCH 161/261] mu update test Separated GM & TLS case make sure the mu set size is explicitly stated (does not depend on default values) --- tests/testGncOptimizer.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index ca40231c9..a1c6fe526 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -139,7 +139,7 @@ TEST(GncOptimizer, initializeMu) { } /* ************************************************************************* */ -TEST(GncOptimizer, updateMu) { +TEST(GncOptimizer, updateMuGM) { // has to have Gaussian noise models ! auto fg = example::createReallyNonlinearFactorGraph(); @@ -151,6 +151,7 @@ TEST(GncOptimizer, updateMu) { GncParams gncParams(lmParams); gncParams.setLossType( GncParams::RobustLossType::GM); + gncParams.setMuStep(1.4); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -162,6 +163,27 @@ TEST(GncOptimizer, updateMu) { EXPECT_DOUBLES_EQUAL(gnc.updateMu(mu), 1.0, tol); } +/* ************************************************************************* */ +TEST(GncOptimizer, updateMuTLS) { + // has to have Gaussian noise models ! + auto fg = example::createReallyNonlinearFactorGraph(); + + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setMuStep(1.4); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + auto gnc = + GncOptimizer>(fg, initial, gncParams); + + double mu = 5.0; + EXPECT_DOUBLES_EQUAL(gnc.updateMu(mu), mu * 1.4, tol); +} + /* ************************************************************************* */ TEST(GncOptimizer, checkMuConvergence) { // has to have Gaussian noise models ! From 428d17a4bc30d1193be3b37cfd71cae8fd4ec4da Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Mon, 7 Dec 2020 16:35:46 -0500 Subject: [PATCH 162/261] correctly check relative difference between mu valus at consecutive iterations --- gtsam/nonlinear/GncOptimizer.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index f5412c6ce..811487779 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -203,9 +203,11 @@ public: double mu = initializeMu(); double mu_prev = mu; - // handle the degenerate case for TLS cost that corresponds to small - // maximum residual error at initialization - if (mu <= 0 && params_.lossType == GncParameters::TLS) { + // handle the degenerate case that corresponds to small + // maximum residual errors at initialization + // For GM: if residual error is small, mu -> 0 + // For TLS: if residual error is small, mu -> -1 + if (mu <= 0) { if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { std::cout << "GNC Optimizer stopped because maximum residual at " "initialization is small." << std::endl; @@ -230,6 +232,10 @@ public: GaussNewtonOptimizer baseOptimizer_iter(graph_iter, state_); result = baseOptimizer_iter.optimize(); + // update mu + mu_prev = mu; + mu = updateMu(mu); + // stopping condition if (checkMuConvergence(mu, mu_prev)) { // display info @@ -240,9 +246,6 @@ public: } break; } - // otherwise update mu - mu_prev = mu; - mu = updateMu(mu); } return result; } From 594f63d1f694c9b13373f580ec5de66fe7b62d91 Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Mon, 7 Dec 2020 17:28:35 -0500 Subject: [PATCH 163/261] test fix --- tests/testGncOptimizer.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index a1c6fe526..5734dfc43 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -135,7 +135,7 @@ TEST(GncOptimizer, initializeMu) { GncOptimizer>(fg, initial, gncParams); // according to rmk 5 in the gnc paper: m0 = barcSq / (2 * rmax^2 - barcSq) // (barcSq=1 in this example) - EXPECT_DOUBLES_EQUAL(gnc_gm.initializeMu(), 1 / (2 * 198.999 - 1), 1e-3); + EXPECT_DOUBLES_EQUAL(gnc_tls.initializeMu(), 1 / (2 * 198.999 - 1), 1e-3); } /* ************************************************************************* */ @@ -185,7 +185,7 @@ TEST(GncOptimizer, updateMuTLS) { } /* ************************************************************************* */ -TEST(GncOptimizer, checkMuConvergence) { +TEST(GncOptimizer, checkMuConvergenceGM) { // has to have Gaussian noise models ! auto fg = example::createReallyNonlinearFactorGraph(); @@ -202,8 +202,26 @@ TEST(GncOptimizer, checkMuConvergence) { double mu = 1.0; CHECK(gnc.checkMuConvergence(mu, 0)); +} - // TODO: test relative mu convergence +/* ************************************************************************* */ +TEST(GncOptimizer, checkMuConvergenceTLS) { + // has to have Gaussian noise models ! + auto fg = example::createReallyNonlinearFactorGraph(); + + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + auto gnc = + GncOptimizer>(fg, initial, gncParams); + + double mu = 1.0; + CHECK(gnc.checkMuConvergence(mu, mu)); } /* ************************************************************************* */ From 398c01375ef41ea79aa1486b099a03e5843bcf2c Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Mon, 7 Dec 2020 20:20:51 -0500 Subject: [PATCH 164/261] more unit tests --- tests/testGncOptimizer.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 5734dfc43..b3bef11e0 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -225,7 +225,7 @@ TEST(GncOptimizer, checkMuConvergenceTLS) { } /* ************************************************************************* */ -TEST(GncOptimizer, calculateWeights) { +TEST(GncOptimizer, calculateWeightsGM) { auto fg = example::sharedNonRobustFactorGraphWithOutliers(); Point2 p0(0, 0); @@ -242,6 +242,8 @@ TEST(GncOptimizer, calculateWeights) { GaussNewtonParams gnParams; GncParams gncParams(gnParams); + gncParams.setLossType( + GncParams::RobustLossType::GM); auto gnc = GncOptimizer>(fg, initial, gncParams); double mu = 1.0; Vector weights_actual = gnc.calculateWeights(initial, mu); @@ -258,6 +260,31 @@ TEST(GncOptimizer, calculateWeights) { CHECK(assert_equal(weights_expected, weights_actual, tol)); } +/* ************************************************************************* */ +TEST(GncOptimizer, calculateWeightsTLS) { + auto fg = example::sharedNonRobustFactorGraphWithOutliers(); + + Point2 p0(0, 0); + Values initial; + initial.insert(X(1), p0); + + // we have 4 factors, 3 with zero errors (inliers), 1 with error + Vector weights_expected = Vector::Zero(4); + weights_expected[0] = 1.0; // zero error + weights_expected[1] = 1.0; // zero error + weights_expected[2] = 1.0; // zero error + weights_expected[3] = 0; // outliers + + GaussNewtonParams gnParams; + GncParams gncParams(gnParams); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + auto gnc = GncOptimizer>(fg, initial, gncParams); + double mu = 1.0; + Vector weights_actual = gnc.calculateWeights(initial, mu); + CHECK(assert_equal(weights_expected, weights_actual, tol)); +} + /* ************************************************************************* */ TEST(GncOptimizer, makeWeightedGraph) { // create original factor From 24f915daf34982dbf25466984b82afd499429dab Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 8 Dec 2020 09:42:18 -0500 Subject: [PATCH 165/261] better documentation --- gtsam/nonlinear/NonlinearFactorGraph.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gtsam/nonlinear/NonlinearFactorGraph.h b/gtsam/nonlinear/NonlinearFactorGraph.h index f6b17edbc..989f493d3 100644 --- a/gtsam/nonlinear/NonlinearFactorGraph.h +++ b/gtsam/nonlinear/NonlinearFactorGraph.h @@ -111,12 +111,17 @@ namespace gtsam { /** Test equality */ bool equals(const NonlinearFactorGraph& other, double tol = 1e-9) const; - /** Write the graph in GraphViz format for visualization */ + /// Write the graph in GraphViz format for visualization void saveGraph(std::ostream& stm, const Values& values = Values(), const GraphvizFormatting& graphvizFormatting = GraphvizFormatting(), const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; - - /** Write the graph in GraphViz format to file for visualization */ + + /** + * Write the graph in GraphViz format to file for visualization. + * + * This is a wrapper friendly version since wrapped languages don't have + * access to C++ streams. + */ void saveGraph(const std::string& file, const Values& values = Values(), const GraphvizFormatting& graphvizFormatting = GraphvizFormatting(), const KeyFormatter& keyFormatter = DefaultKeyFormatter) const; From 720ac412081602732933004af2263b13974199c5 Mon Sep 17 00:00:00 2001 From: Russell Buchanan Date: Tue, 8 Dec 2020 15:22:01 +0000 Subject: [PATCH 166/261] Adds unit test for imu preintegration of a single step --- tests/ImuMeasurement.h | 23 +++++ tests/Measurement.h | 23 +++++ tests/testImuPreintegration.cpp | 155 ++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 tests/ImuMeasurement.h create mode 100644 tests/Measurement.h create mode 100644 tests/testImuPreintegration.cpp diff --git a/tests/ImuMeasurement.h b/tests/ImuMeasurement.h new file mode 100644 index 000000000..5ac3d54be --- /dev/null +++ b/tests/ImuMeasurement.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +namespace drs { + +/// +/// \brief Contains data from the IMU mesaurements. +/// +class ImuMeasurement : public Measurement { + public: + enum Name { BODY = 0, RF_FOOT = 1, RH_FOOT = 2 }; + + Name name; ///< Unique string identifier + Eigen::Vector3d I_a_WI; ///< Raw acceleration from the IMU (m/s/s) + Eigen::Vector3d I_w_WI; ///< Raw angular velocity from the IMU (rad/s) + + virtual ~ImuMeasurement() override {} + ImuMeasurement(); + friend std::ostream& operator<<(std::ostream& stream, const ImuMeasurement& meas); +}; + +} // namespace drs diff --git a/tests/Measurement.h b/tests/Measurement.h new file mode 100644 index 000000000..e26c5d918 --- /dev/null +++ b/tests/Measurement.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +namespace drs { + +/// +/// \brief This is the base class for all measurement types. +/// +class Measurement { +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + uint64_t dt; ///< Time since the last message of this type (nanoseconds). + uint64_t time; ///< ROS time message recieved (nanoseconds). + std::string type; ///< The type of message (to enable dynamic/static casting). + + virtual ~Measurement() {} + Measurement(); + Measurement(std::string _type); +}; + +} // namespace drs diff --git a/tests/testImuPreintegration.cpp b/tests/testImuPreintegration.cpp new file mode 100644 index 000000000..6e3b6396d --- /dev/null +++ b/tests/testImuPreintegration.cpp @@ -0,0 +1,155 @@ +/** + * @file testImuPreintegration.cpp + * @brief Unit tests for IMU Preintegration + * @author Russell Buchanan + **/ + +#include + +#include +#include + +#include +#include +#include +#include + +namespace drs { + +Measurement::Measurement() : dt(0), time(0), type("UNDEFINED") {} + +Measurement::Measurement(std::string _type) : dt(0), time(0), type(_type) {} + +ImuMeasurement::ImuMeasurement() : I_a_WI{0, 0, 0}, I_w_WI{0, 0, 0} { type = "ImuMeasurement"; } + +std::ostream& operator<<(std::ostream& stream, const ImuMeasurement& meas) { + stream << "IMU Measurement at time = " << meas.time << " : \n" + << "dt : " << meas.dt << "\n" + << "I_a_WI: " << meas.I_a_WI.transpose() << "\n" + << "I_w_WI: " << meas.I_w_WI.transpose() << "\n"; + return stream; +} + +} // namespace drs + +using namespace gtsam; + +/* ************************************************************************* */ +/// \brief Uses the GTSAM library to perform IMU preintegration on an acceleration input. +/// +TEST(GtsamLibraryTests, LoadedSimulationData) { + Eigen::Vector3d finalPos; + + std::vector imuMeasurements; + + double accNoiseSigma = 0.001249; + double accBiasRwSigma = 0.000106; + double gyrNoiseSigma = 0.000208; + double gyrBiasRwSigma = 0.000004; + double integrationCovariance = 1e-8; + double biasAccOmegaInt = 1e-5; + + double gravity = 9.81; + double rate = 400.0; // Hz + + /// @todo Update directory to correct location + std::string inFileString = "/home/russell/imu_data.csv"; + std::ofstream outputFile; + outputFile.open("/home/russell/gtsam_output.csv", std::ofstream::out); + std::ifstream inputFile(inFileString); + std::string line; + while (std::getline(inputFile, line)) { + std::stringstream ss(line); + std::string str; + std::vector results; + while (getline(ss, str, ',')) { + results.push_back(std::atof(str.c_str())); + } + drs::ImuMeasurement measurement; + measurement.dt = static_cast(1e9 * (1 / rate)); + measurement.time = results[2]; + measurement.I_a_WI = {results[29], results[30], results[31]}; + measurement.I_w_WI = {results[17], results[18], results[19]}; + imuMeasurements.push_back(measurement); + + // std::cout << "IMU measurement " << measurement << std::endl; + } + + // Assume a Z-up navigation (assuming we are performing optimization in the IMU frame). + boost::shared_ptr imuPreintegratedParams = + gtsam::PreintegratedCombinedMeasurements::Params::MakeSharedU(gravity); + imuPreintegratedParams->accelerometerCovariance = I_3x3 * pow(accNoiseSigma, 2); + imuPreintegratedParams->biasAccCovariance = I_3x3 * pow(accBiasRwSigma, 2); + imuPreintegratedParams->gyroscopeCovariance = I_3x3 * pow(gyrNoiseSigma, 2); + imuPreintegratedParams->biasOmegaCovariance = I_3x3 * pow(gyrBiasRwSigma, 2); + imuPreintegratedParams->integrationCovariance = I_3x3 * integrationCovariance; + imuPreintegratedParams->biasAccOmegaInt = I_6x6 * biasAccOmegaInt; + + // Initial state + gtsam::Pose3 priorPose; + gtsam::Vector3 priorVelocity; + gtsam::imuBias::ConstantBias priorImuBias; + gtsam::PreintegratedCombinedMeasurements imuPreintegrated; + Eigen::Vector3d position; + Eigen::Vector3d velocity; + gtsam::NavState propState; + + gtsam::NavState initialNavState(priorPose, priorVelocity); + + // Bias estimated by my Algorithm + priorImuBias = + gtsam::imuBias::ConstantBias(Eigen::Vector3d(-0.0314648, 0.0219921, 6.95945e-05), + Eigen::Vector3d(4.88581e-08, -1.04971e-09, -0.000122868)); + + // zero bias + // priorImuBias = gtsam::imuBias::ConstantBias(Eigen::Vector3d(0,0,0), + // Eigen::Vector3d(0,0,0)); + + imuPreintegrated = gtsam::PreintegratedCombinedMeasurements(imuPreintegratedParams, priorImuBias); + + // Put header row in output csv + outputFile << "X Position," + << "Y Position," + << "Z Position," + << "X Velocity," + << "Y Velocity," + << "Z Velocity," + << "\n"; + + for (int n = 1; n < imuMeasurements.size(); n++) { //start at 1 to skip header + // integrate + imuPreintegrated.integrateMeasurement(imuMeasurements[n].I_a_WI, imuMeasurements[n].I_w_WI, + 1 / rate); + // predict + propState = imuPreintegrated.predict(initialNavState, priorImuBias); + position = propState.pose().translation(); + velocity = propState.velocity(); + // std::cout << "IMU Position " << position.transpose() << std::endl; + // std::cout << "IMU Velocity " << velocity.transpose() << std::endl; + + // Write to csv + outputFile << std::to_string(position.x()) << "," << std::to_string(position.y()) << "," + << std::to_string(position.z()) << "," << std::to_string(velocity.x()) << "," + << std::to_string(velocity.y()) << "," << std::to_string(velocity.z()) << "," + << "\n"; + } + + outputFile.close(); + + gtsam::Vector3 rotation = propState.pose().rotation().rpy(); + + // Dont have ground truth for x and y position yet + // DOUBLES_EQUAL(0.1, position[0], 1e-2); + // DOUBLES_EQUAL(0.1, position[1], 1e-2); + DOUBLES_EQUAL(0.0, position[2], 1e-2); + + DOUBLES_EQUAL(0.0, rotation[0], 1e-2); + DOUBLES_EQUAL(0.0, rotation[1], 1e-2); + DOUBLES_EQUAL(0.0, rotation[2], 1e-2); +} +/* ************************************************************************* */ +int main() { + TestResult tr; + return TestRegistry::runAllTests(tr); +} +/* ************************************************************************* */ From 0c079c66d0b3eaf3da8ab82ec04bf6b4215dbcf6 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Tue, 8 Dec 2020 19:26:10 -0500 Subject: [PATCH 167/261] fixed small typos --- gtsam/sfm/ShonanAveraging.cpp | 4 ++-- gtsam/sfm/ShonanAveraging.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index b40726312..5957047a3 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -349,7 +349,7 @@ static double Kappa(const BinaryMeasurement &measurement, // If robust, check if optimality certificate is expected if (parameters.getCertifyOptimality()) { throw std::invalid_argument( - "Verification of optimality does not work with robust cost."); + "Certification of optimality does not work with robust cost."); } else { // Optimality certificate not required, so setting default sigma sigma = 1; @@ -811,7 +811,7 @@ std::pair ShonanAveraging::run(const Values &initialEstimate, // Optimize until convergence at this level Qstar = tryOptimizingAt(p, initialSOp); if (parameters_.getUseHuber() || !parameters_.getCertifyOptimality()) { - // in this case, there is no optimality verification + // in this case, there is no optimality certification if (pMin != pMax) { throw std::runtime_error( "When using robust norm, Shonan only tests a single rank. Set pMin = pMax"); diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index 8a620cdc5..2cb62ca55 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -46,7 +46,7 @@ struct GTSAM_EXPORT ShonanAveragingParameters { using Rot = typename std::conditional::type; using Anchor = std::pair; - // Paremeters themselves: + // Parameters themselves: LevenbergMarquardtParams lm; ///< LM parameters double optimalityThreshold; ///< threshold used in checkOptimality Anchor anchor; ///< pose to use as anchor if not Karcher From 43b0225557fc057e5cdca3e1b657512c1387906c Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 10 Dec 2020 10:07:49 -0500 Subject: [PATCH 168/261] explicitly initialize Point3 --- gtsam/slam/tests/testInitializePose3.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/gtsam/slam/tests/testInitializePose3.cpp b/gtsam/slam/tests/testInitializePose3.cpp index 01ec9edb1..dfe3d24ae 100644 --- a/gtsam/slam/tests/testInitializePose3.cpp +++ b/gtsam/slam/tests/testInitializePose3.cpp @@ -75,8 +75,14 @@ NonlinearFactorGraph graph2() { g.add(BetweenFactor(x0, x1, pose0.between(pose1), noiseModel::Isotropic::Precision(6, 1.0))); g.add(BetweenFactor(x1, x2, pose1.between(pose2), noiseModel::Isotropic::Precision(6, 1.0))); g.add(BetweenFactor(x2, x3, pose2.between(pose3), noiseModel::Isotropic::Precision(6, 1.0))); - g.add(BetweenFactor(x2, x0, Pose3(Rot3::Ypr(0.1,0,0.1), Point3()), noiseModel::Isotropic::Precision(6, 0.0))); // random pose, but zero information - g.add(BetweenFactor(x0, x3, Pose3(Rot3::Ypr(0.5,-0.2,0.2), Point3(10,20,30)), noiseModel::Isotropic::Precision(6, 0.0))); // random pose, but zero informatoin + // random pose, but zero information + g.add(BetweenFactor(x2, x0, + Pose3(Rot3::Ypr(0.1, 0, 0.1), Point3(0, 0, 0)), + noiseModel::Isotropic::Precision(6, 0.0))); + // random pose, but zero informatoin + g.add(BetweenFactor( + x0, x3, Pose3(Rot3::Ypr(0.5, -0.2, 0.2), Point3(10, 20, 30)), + noiseModel::Isotropic::Precision(6, 0.0))); g.addPrior(x0, pose0, model); return g; } From 592c572f8c757e96aacf685939f42f2e5cdf1a0c Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 10 Dec 2020 11:10:36 -0500 Subject: [PATCH 169/261] formatting --- gtsam/slam/tests/testInitializePose3.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gtsam/slam/tests/testInitializePose3.cpp b/gtsam/slam/tests/testInitializePose3.cpp index dfe3d24ae..995a109fa 100644 --- a/gtsam/slam/tests/testInitializePose3.cpp +++ b/gtsam/slam/tests/testInitializePose3.cpp @@ -76,13 +76,14 @@ NonlinearFactorGraph graph2() { g.add(BetweenFactor(x1, x2, pose1.between(pose2), noiseModel::Isotropic::Precision(6, 1.0))); g.add(BetweenFactor(x2, x3, pose2.between(pose3), noiseModel::Isotropic::Precision(6, 1.0))); // random pose, but zero information - g.add(BetweenFactor(x2, x0, - Pose3(Rot3::Ypr(0.1, 0, 0.1), Point3(0, 0, 0)), - noiseModel::Isotropic::Precision(6, 0.0))); - // random pose, but zero informatoin + auto noise_zero_info = noiseModel::Isotropic::Precision(6, 0.0); + g.add(BetweenFactor( + x2, x0, Pose3(Rot3::Ypr(0.1, 0.0, 0.1), Point3(0.0, 0.0, 0.0)), + noise_zero_info)); + // random pose, but zero information g.add(BetweenFactor( x0, x3, Pose3(Rot3::Ypr(0.5, -0.2, 0.2), Point3(10, 20, 30)), - noiseModel::Isotropic::Precision(6, 0.0))); + noise_zero_info)); g.addPrior(x0, pose0, model); return g; } From afb6ebb933308f755f6f4c9384925ed9c6bfc128 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Fri, 11 Dec 2020 01:01:27 -0500 Subject: [PATCH 170/261] Added the example graph in powerMethodExample.h --- gtsam/linear/tests/powerMethodExample.h | 67 +++++++++++++++++++ .../tests/testAcceleratedPowerMethod.cpp | 24 +------ gtsam/linear/tests/testPowerMethod.cpp | 24 +------ 3 files changed, 73 insertions(+), 42 deletions(-) create mode 100644 gtsam/linear/tests/powerMethodExample.h diff --git a/gtsam/linear/tests/powerMethodExample.h b/gtsam/linear/tests/powerMethodExample.h new file mode 100644 index 000000000..f80299386 --- /dev/null +++ b/gtsam/linear/tests/powerMethodExample.h @@ -0,0 +1,67 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010-2019, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * powerMethodExample.h + * + * @file powerMethodExample.h + * @date Nov 2020 + * @author Jing Wu + * @brief Create sparse and dense factor graph for + * PowerMethod/AcceleratedPowerMethod + */ + +#include + +#include + + +namespace gtsam { +namespace linear { +namespace test { +namespace example { + +/* ************************************************************************* */ +inline GaussianFactorGraph createSparseGraph() { + using symbol_shorthand::X; + // Let's make a scalar synchronization graph with 4 nodes + GaussianFactorGraph fg; + auto model = noiseModel::Unit::Create(1); + for (size_t j = 0; j < 3; j++) { + fg.add(X(j), -I_1x1, X(j + 1), I_1x1, Vector1::Zero(), model); + } + fg.add(X(3), -I_1x1, X(0), I_1x1, Vector1::Zero(), model); // extra row + + return fg; +} + +/* ************************************************************************* */ +inline GaussianFactorGraph createDenseGraph() { + using symbol_shorthand::X; + // Let's make a scalar synchronization graph with 10 nodes + GaussianFactorGraph fg; + auto model = noiseModel::Unit::Create(1); + // Iterate over nodes + for (size_t j = 0; j < 10; j++) { + // Each node has an edge with all the others + for (size_t i = 1; i < 10; i++) + fg.add(X(j), -I_1x1, X((j + i) % 10), I_1x1, Vector1::Zero(), model); + } + + return fg; +} + +/* ************************************************************************* */ + +} // namespace example +} // namespace test +} // namespace linear +} // namespace gtsam diff --git a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp index c7c8e8a55..7c4a90936 100644 --- a/gtsam/linear/tests/testAcceleratedPowerMethod.cpp +++ b/gtsam/linear/tests/testAcceleratedPowerMethod.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -33,7 +34,6 @@ using namespace std; using namespace gtsam; -using symbol_shorthand::X; /* ************************************************************************* */ TEST(AcceleratedPowerMethod, acceleratedPowerIteration) { @@ -65,12 +65,7 @@ TEST(AcceleratedPowerMethod, acceleratedPowerIteration) { /* ************************************************************************* */ TEST(AcceleratedPowerMethod, useFactorGraphSparse) { // Let's make a scalar synchronization graph with 4 nodes - GaussianFactorGraph fg; - auto model = noiseModel::Unit::Create(1); - for (size_t j = 0; j < 3; j++) { - fg.add(X(j), -I_1x1, X(j + 1), I_1x1, Vector1::Zero(), model); - } - fg.add(X(3), -I_1x1, X(0), I_1x1, Vector1::Zero(), model); // extra row + GaussianFactorGraph fg = gtsam::linear::test::example::createSparseGraph(); // Get eigenvalues and eigenvectors with Eigen auto L = fg.hessian(); @@ -105,20 +100,7 @@ TEST(AcceleratedPowerMethod, useFactorGraphSparse) { /* ************************************************************************* */ TEST(AcceleratedPowerMethod, useFactorGraphDense) { // Let's make a scalar synchronization graph with 10 nodes - GaussianFactorGraph fg; - auto model = noiseModel::Unit::Create(1); - // Each node has an edge with all the others - for (size_t j = 0; j < 10; j++) { - fg.add(X(j), -I_1x1, X((j + 1)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 2)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 3)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 4)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 5)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 6)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 7)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 8)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 9)%10 ), I_1x1, Vector1::Zero(), model); - } + GaussianFactorGraph fg = gtsam::linear::test::example::createDenseGraph(); // Get eigenvalues and eigenvectors with Eigen auto L = fg.hessian(); diff --git a/gtsam/linear/tests/testPowerMethod.cpp b/gtsam/linear/tests/testPowerMethod.cpp index 7adfd0aa5..54d4c720d 100644 --- a/gtsam/linear/tests/testPowerMethod.cpp +++ b/gtsam/linear/tests/testPowerMethod.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -33,7 +34,6 @@ using namespace std; using namespace gtsam; -using symbol_shorthand::X; /* ************************************************************************* */ TEST(PowerMethod, powerIteration) { @@ -63,12 +63,7 @@ TEST(PowerMethod, powerIteration) { /* ************************************************************************* */ TEST(PowerMethod, useFactorGraphSparse) { // Let's make a scalar synchronization graph with 4 nodes - GaussianFactorGraph fg; - auto model = noiseModel::Unit::Create(1); - for (size_t j = 0; j < 3; j++) { - fg.add(X(j), -I_1x1, X(j + 1), I_1x1, Vector1::Zero(), model); - } - fg.add(X(3), -I_1x1, X(0), I_1x1, Vector1::Zero(), model); // extra row + GaussianFactorGraph fg = gtsam::linear::test::example::createSparseGraph(); // Get eigenvalues and eigenvectors with Eigen auto L = fg.hessian(); @@ -96,20 +91,7 @@ TEST(PowerMethod, useFactorGraphSparse) { /* ************************************************************************* */ TEST(PowerMethod, useFactorGraphDense) { // Let's make a scalar synchronization graph with 10 nodes - GaussianFactorGraph fg; - auto model = noiseModel::Unit::Create(1); - // Each node has an edge with all the others - for (size_t j = 0; j < 10; j++) { - fg.add(X(j), -I_1x1, X((j + 1)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 2)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 3)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 4)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 5)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 6)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 7)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 8)%10 ), I_1x1, Vector1::Zero(), model); - fg.add(X(j), -I_1x1, X((j + 9)%10 ), I_1x1, Vector1::Zero(), model); - } + GaussianFactorGraph fg = gtsam::linear::test::example::createDenseGraph(); // Get eigenvalues and eigenvectors with Eigen auto L = fg.hessian(); From 55ad1f16a630f23a1f15ddeeb70f995b36ffa3ec Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Fri, 11 Dec 2020 01:01:40 -0500 Subject: [PATCH 171/261] Refined reference documentation --- gtsam/linear/AcceleratedPowerMethod.h | 10 ++++++---- gtsam/linear/PowerMethod.h | 12 +++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/gtsam/linear/AcceleratedPowerMethod.h b/gtsam/linear/AcceleratedPowerMethod.h index 0699f237e..4cb25daf7 100644 --- a/gtsam/linear/AcceleratedPowerMethod.h +++ b/gtsam/linear/AcceleratedPowerMethod.h @@ -29,19 +29,21 @@ using Sparse = Eigen::SparseMatrix; * \brief Compute maximum Eigenpair with accelerated power method * * References : - * 1) Rosen, D. and Carlone, L., 2017, September. Computational + * 1) G. Golub and C. V. Loan, Matrix Computations, 3rd ed. Baltimore, Johns + * Hopkins University Press, 1996, pp.405-411 + * 2) Rosen, D. and Carlone, L., 2017, September. Computational * enhancements for certifiably correct SLAM. In Proceedings of the * International Conference on Intelligent Robots and Systems. - * 2) Yulun Tian and Kasra Khosoussi and David M. Rosen and Jonathan P. How, + * 3) Yulun Tian and Kasra Khosoussi and David M. Rosen and Jonathan P. How, * 2020, Aug, Distributed Certifiably Correct Pose-Graph Optimization, Arxiv - * 3) C. de Sa, B. He, I. Mitliagkas, C. Ré, and P. Xu, “Accelerated + * 4) C. de Sa, B. He, I. Mitliagkas, C. Ré, and P. Xu, “Accelerated * stochastic power iteration,” in Proc. Mach. Learn. Res., no. 84, 2018, pp. * 58–67 * * It performs the following iteration: \f$ x_{k+1} = A * x_k - \beta * * x_{k-1} \f$ where A is the aim matrix we want to get eigenpair of, x is the * Ritz vector - * + * * Template argument Operator just needs multiplication operator * */ diff --git a/gtsam/linear/PowerMethod.h b/gtsam/linear/PowerMethod.h index a209c5779..8834777cc 100644 --- a/gtsam/linear/PowerMethod.h +++ b/gtsam/linear/PowerMethod.h @@ -35,19 +35,21 @@ using Sparse = Eigen::SparseMatrix; * \brief Compute maximum Eigenpair with power method * * References : - * 1) Rosen, D. and Carlone, L., 2017, September. Computational + * 1) G. Golub and C. V. Loan, Matrix Computations, 3rd ed. Baltimore, Johns + * Hopkins University Press, 1996, pp.405-411 + * 2) Rosen, D. and Carlone, L., 2017, September. Computational * enhancements for certifiably correct SLAM. In Proceedings of the * International Conference on Intelligent Robots and Systems. - * 2) Yulun Tian and Kasra Khosoussi and David M. Rosen and Jonathan P. How, + * 3) Yulun Tian and Kasra Khosoussi and David M. Rosen and Jonathan P. How, * 2020, Aug, Distributed Certifiably Correct Pose-Graph Optimization, Arxiv - * 3) C. de Sa, B. He, I. Mitliagkas, C. Ré, and P. Xu, “Accelerated + * 4) C. de Sa, B. He, I. Mitliagkas, C. Ré, and P. Xu, “Accelerated * stochastic power iteration,” in Proc. Mach. Learn. Res., no. 84, 2018, pp. * 58–67 * - * It performs the following iteration: \f$ x_{k+1} = A * x_k \f$ + * It performs the following iteration: \f$ x_{k+1} = A * x_k \f$ * where A is the aim matrix we want to get eigenpair of, x is the * Ritz vector - * + * * Template argument Operator just needs multiplication operator * */ From 525dbb6058a0c4ba5cb7fcf7d9811dc6af43d110 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Fri, 11 Dec 2020 01:21:14 -0500 Subject: [PATCH 172/261] Make purturb static --- gtsam/sfm/ShonanAveraging.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index fab57c828..dfab2bf52 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -485,7 +485,7 @@ Sparse ShonanAveraging::computeA(const Matrix &S) const { // ref : Part III. C, Rosen, D. and Carlone, L., 2017, September. Computational // enhancements for certifiably correct SLAM. In Proceedings of the // International Conference on Intelligent Robots and Systems. -Vector perturb(const Vector &initialVector) { +static Vector perturb(const Vector &initialVector) { // generate a 0.03*||x_0||_2 as stated in David's paper int n = initialVector.rows(); Vector disturb = Vector::Random(n); From 8b9f917f4327c0d36e73b06c80fb444bdf0d3739 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 14 Dec 2020 14:32:04 -0500 Subject: [PATCH 173/261] refactored code for ImuMeasurements --- tests/ImuMeasurement.h | 26 +++++++++++++++++++------- tests/Measurement.h | 24 +++++++++++++----------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/tests/ImuMeasurement.h b/tests/ImuMeasurement.h index 5ac3d54be..d49759545 100644 --- a/tests/ImuMeasurement.h +++ b/tests/ImuMeasurement.h @@ -2,11 +2,11 @@ #include -namespace drs { +namespace gtsam { -/// -/// \brief Contains data from the IMU mesaurements. -/// +/** + *\brief Contains data from the IMU mesaurements. + */ class ImuMeasurement : public Measurement { public: enum Name { BODY = 0, RF_FOOT = 1, RH_FOOT = 2 }; @@ -15,9 +15,21 @@ class ImuMeasurement : public Measurement { Eigen::Vector3d I_a_WI; ///< Raw acceleration from the IMU (m/s/s) Eigen::Vector3d I_w_WI; ///< Raw angular velocity from the IMU (rad/s) + ImuMeasurement() + : Measurement("ImuMeasurement"), I_a_WI{0, 0, 0}, I_w_WI{0, 0, 0} {} + virtual ~ImuMeasurement() override {} - ImuMeasurement(); - friend std::ostream& operator<<(std::ostream& stream, const ImuMeasurement& meas); + + friend std::ostream& operator<<(std::ostream& stream, + const ImuMeasurement& meas); }; -} // namespace drs +std::ostream& operator<<(std::ostream& stream, const ImuMeasurement& meas) { + stream << "IMU Measurement at time = " << meas.time << " : \n" + << "dt : " << meas.dt << "\n" + << "I_a_WI: " << meas.I_a_WI.transpose() << "\n" + << "I_w_WI: " << meas.I_w_WI.transpose() << "\n"; + return stream; +} + +} // namespace gtsam diff --git a/tests/Measurement.h b/tests/Measurement.h index e26c5d918..be38ac4f3 100644 --- a/tests/Measurement.h +++ b/tests/Measurement.h @@ -3,21 +3,23 @@ #include #include -namespace drs { +namespace gtsam { -/// -/// \brief This is the base class for all measurement types. -/// +/** + * \brief This is the base class for all measurement types. + */ class Measurement { -public: + public: EIGEN_MAKE_ALIGNED_OPERATOR_NEW - uint64_t dt; ///< Time since the last message of this type (nanoseconds). - uint64_t time; ///< ROS time message recieved (nanoseconds). - std::string type; ///< The type of message (to enable dynamic/static casting). + size_t dt; ///< Time since the last message of this type (nanoseconds). + size_t time; ///< ROS time message recieved (nanoseconds). + ///< The type of message (to enable dynamic/static casting). + std::string type; + + Measurement() : dt(0), time(0), type("UNDEFINED") {} + Measurement(std::string _type) : dt(0), time(0), type(_type) {} virtual ~Measurement() {} - Measurement(); - Measurement(std::string _type); }; -} // namespace drs +} // namespace gtsam From 7f975d194adff9043c81d1cba6d0b0fe03db0c42 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 14 Dec 2020 14:32:24 -0500 Subject: [PATCH 174/261] refactored code for testing ImuPreintegration with impact --- tests/testImuPreintegration.cpp | 133 ++++++++++++++++---------------- 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/tests/testImuPreintegration.cpp b/tests/testImuPreintegration.cpp index 6e3b6396d..43b3461ee 100644 --- a/tests/testImuPreintegration.cpp +++ b/tests/testImuPreintegration.cpp @@ -1,46 +1,42 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + /** * @file testImuPreintegration.cpp * @brief Unit tests for IMU Preintegration * @author Russell Buchanan **/ +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include - -namespace drs { - -Measurement::Measurement() : dt(0), time(0), type("UNDEFINED") {} - -Measurement::Measurement(std::string _type) : dt(0), time(0), type(_type) {} - -ImuMeasurement::ImuMeasurement() : I_a_WI{0, 0, 0}, I_w_WI{0, 0, 0} { type = "ImuMeasurement"; } - -std::ostream& operator<<(std::ostream& stream, const ImuMeasurement& meas) { - stream << "IMU Measurement at time = " << meas.time << " : \n" - << "dt : " << meas.dt << "\n" - << "I_a_WI: " << meas.I_a_WI.transpose() << "\n" - << "I_w_WI: " << meas.I_w_WI.transpose() << "\n"; - return stream; -} - -} // namespace drs - +using namespace std; using namespace gtsam; /* ************************************************************************* */ -/// \brief Uses the GTSAM library to perform IMU preintegration on an acceleration input. -/// -TEST(GtsamLibraryTests, LoadedSimulationData) { +/** + * \brief Uses the GTSAM library to perform IMU preintegration on an + * acceleration input. + */ +TEST(TestImuPreintegration, LoadedSimulationData) { Eigen::Vector3d finalPos; - std::vector imuMeasurements; + vector imuMeasurements; double accNoiseSigma = 0.001249; double accBiasRwSigma = 0.000106; @@ -52,33 +48,36 @@ TEST(GtsamLibraryTests, LoadedSimulationData) { double gravity = 9.81; double rate = 400.0; // Hz - /// @todo Update directory to correct location - std::string inFileString = "/home/russell/imu_data.csv"; - std::ofstream outputFile; - outputFile.open("/home/russell/gtsam_output.csv", std::ofstream::out); - std::ifstream inputFile(inFileString); - std::string line; - while (std::getline(inputFile, line)) { - std::stringstream ss(line); - std::string str; - std::vector results; + string inFileString = findExampleDataFile("quadraped_imu_data.csv"); + ofstream outputFile; + outputFile.open("imu_preint_output.csv", ios::out); + ifstream inputFile(inFileString); + string line; + while (getline(inputFile, line)) { + stringstream ss(line); + string str; + vector results; while (getline(ss, str, ',')) { - results.push_back(std::atof(str.c_str())); + results.push_back(atof(str.c_str())); } - drs::ImuMeasurement measurement; - measurement.dt = static_cast(1e9 * (1 / rate)); + ImuMeasurement measurement; + measurement.dt = static_cast(1e9 * (1 / rate)); measurement.time = results[2]; measurement.I_a_WI = {results[29], results[30], results[31]}; measurement.I_w_WI = {results[17], results[18], results[19]}; imuMeasurements.push_back(measurement); - // std::cout << "IMU measurement " << measurement << std::endl; + // cout << "IMU measurement " << measurement << endl; } - // Assume a Z-up navigation (assuming we are performing optimization in the IMU frame). - boost::shared_ptr imuPreintegratedParams = - gtsam::PreintegratedCombinedMeasurements::Params::MakeSharedU(gravity); - imuPreintegratedParams->accelerometerCovariance = I_3x3 * pow(accNoiseSigma, 2); + // Assume a Z-up navigation (assuming we are performing optimization in the + // IMU frame). + boost::shared_ptr + imuPreintegratedParams = + PreintegratedCombinedMeasurements::Params::MakeSharedU( + gravity); + imuPreintegratedParams->accelerometerCovariance = + I_3x3 * pow(accNoiseSigma, 2); imuPreintegratedParams->biasAccCovariance = I_3x3 * pow(accBiasRwSigma, 2); imuPreintegratedParams->gyroscopeCovariance = I_3x3 * pow(gyrNoiseSigma, 2); imuPreintegratedParams->biasOmegaCovariance = I_3x3 * pow(gyrBiasRwSigma, 2); @@ -86,26 +85,27 @@ TEST(GtsamLibraryTests, LoadedSimulationData) { imuPreintegratedParams->biasAccOmegaInt = I_6x6 * biasAccOmegaInt; // Initial state - gtsam::Pose3 priorPose; - gtsam::Vector3 priorVelocity; - gtsam::imuBias::ConstantBias priorImuBias; - gtsam::PreintegratedCombinedMeasurements imuPreintegrated; + Pose3 priorPose; + Vector3 priorVelocity; + imuBias::ConstantBias priorImuBias; + PreintegratedCombinedMeasurements imuPreintegrated; Eigen::Vector3d position; Eigen::Vector3d velocity; - gtsam::NavState propState; + NavState propState; - gtsam::NavState initialNavState(priorPose, priorVelocity); + NavState initialNavState(priorPose, priorVelocity); // Bias estimated by my Algorithm - priorImuBias = - gtsam::imuBias::ConstantBias(Eigen::Vector3d(-0.0314648, 0.0219921, 6.95945e-05), - Eigen::Vector3d(4.88581e-08, -1.04971e-09, -0.000122868)); + priorImuBias = imuBias::ConstantBias( + Eigen::Vector3d(-0.0314648, 0.0219921, 6.95945e-05), + Eigen::Vector3d(4.88581e-08, -1.04971e-09, -0.000122868)); // zero bias - // priorImuBias = gtsam::imuBias::ConstantBias(Eigen::Vector3d(0,0,0), + // priorImuBias = imuBias::ConstantBias(Eigen::Vector3d(0,0,0), // Eigen::Vector3d(0,0,0)); - imuPreintegrated = gtsam::PreintegratedCombinedMeasurements(imuPreintegratedParams, priorImuBias); + imuPreintegrated = PreintegratedCombinedMeasurements( + imuPreintegratedParams, priorImuBias); // Put header row in output csv outputFile << "X Position," @@ -116,27 +116,29 @@ TEST(GtsamLibraryTests, LoadedSimulationData) { << "Z Velocity," << "\n"; - for (int n = 1; n < imuMeasurements.size(); n++) { //start at 1 to skip header + // start at 1 to skip header + for (size_t n = 1; n < imuMeasurements.size(); n++) { // integrate - imuPreintegrated.integrateMeasurement(imuMeasurements[n].I_a_WI, imuMeasurements[n].I_w_WI, - 1 / rate); + imuPreintegrated.integrateMeasurement(imuMeasurements[n].I_a_WI, + imuMeasurements[n].I_w_WI, 1 / rate); // predict propState = imuPreintegrated.predict(initialNavState, priorImuBias); position = propState.pose().translation(); velocity = propState.velocity(); - // std::cout << "IMU Position " << position.transpose() << std::endl; - // std::cout << "IMU Velocity " << velocity.transpose() << std::endl; + // cout << "IMU Position " << position.transpose() << endl; + // cout << "IMU Velocity " << velocity.transpose() << endl; // Write to csv - outputFile << std::to_string(position.x()) << "," << std::to_string(position.y()) << "," - << std::to_string(position.z()) << "," << std::to_string(velocity.x()) << "," - << std::to_string(velocity.y()) << "," << std::to_string(velocity.z()) << "," + outputFile << to_string(position.x()) << "," << to_string(position.y()) + << "," << to_string(position.z()) << "," + << to_string(velocity.x()) << "," << to_string(velocity.y()) + << "," << to_string(velocity.z()) << "," << "\n"; } outputFile.close(); - gtsam::Vector3 rotation = propState.pose().rotation().rpy(); + Vector3 rotation = propState.pose().rotation().rpy(); // Dont have ground truth for x and y position yet // DOUBLES_EQUAL(0.1, position[0], 1e-2); @@ -147,6 +149,7 @@ TEST(GtsamLibraryTests, LoadedSimulationData) { DOUBLES_EQUAL(0.0, rotation[1], 1e-2); DOUBLES_EQUAL(0.0, rotation[2], 1e-2); } + /* ************************************************************************* */ int main() { TestResult tr; From e54ef580f7356203ce22f65e8eeef20529eba24f Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 14 Dec 2020 14:32:36 -0500 Subject: [PATCH 175/261] add simulation data --- examples/Data/quadraped_imu_data.csv | 2636 ++++++++++++++++++++++++++ 1 file changed, 2636 insertions(+) create mode 100644 examples/Data/quadraped_imu_data.csv diff --git a/examples/Data/quadraped_imu_data.csv b/examples/Data/quadraped_imu_data.csv new file mode 100644 index 000000000..d324066d8 --- /dev/null +++ b/examples/Data/quadraped_imu_data.csv @@ -0,0 +1,2636 @@ +%time,field.header.seq,field.header.stamp,field.header.frame_id,field.orientation.x,field.orientation.y,field.orientation.z,field.orientation.w,field.orientation_covariance0,field.orientation_covariance1,field.orientation_covariance2,field.orientation_covariance3,field.orientation_covariance4,field.orientation_covariance5,field.orientation_covariance6,field.orientation_covariance7,field.orientation_covariance8,field.angular_velocity.x,field.angular_velocity.y,field.angular_velocity.z,field.angular_velocity_covariance0,field.angular_velocity_covariance1,field.angular_velocity_covariance2,field.angular_velocity_covariance3,field.angular_velocity_covariance4,field.angular_velocity_covariance5,field.angular_velocity_covariance6,field.angular_velocity_covariance7,field.angular_velocity_covariance8,field.linear_acceleration.x,field.linear_acceleration.y,field.linear_acceleration.z,field.linear_acceleration_covariance0,field.linear_acceleration_covariance1,field.linear_acceleration_covariance2,field.linear_acceleration_covariance3,field.linear_acceleration_covariance4,field.linear_acceleration_covariance5,field.linear_acceleration_covariance6,field.linear_acceleration_covariance7,field.linear_acceleration_covariance8 +117735250000,11048,117735250000,RH_EXTIMU,2.2932715788e-06,1.53196171221e-05,-0.703285780478,0.71090724482,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.19800998937e-07,-8.13380203893e-09,-7.22038459104e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245457587107,-0.000181612558247,9.8100077031,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117737750000,11049,117737750000,RH_EXTIMU,2.29313402886e-06,1.53196621872e-05,-0.70328584464,0.710907181346,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0268029415e-07,-5.10996651005e-08,-7.22029453453e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246233372419,-0.00017714749759,9.81001157075,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117737750000,11050,117740250000,RH_EXTIMU,2.29307998339e-06,1.53197209386e-05,-0.703285908801,0.710907117872,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.28894961166e-08,3.66612768662e-09,-7.22022488535e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244992819707,-0.000178649476366,9.80999936342,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117742750000,11051,117742750000,RH_EXTIMU,2.29322015822e-06,1.531966497e-05,-0.703285972962,0.710907054399,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12113343221e-07,4.76958204019e-08,-7.22016100777e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244525990158,-0.000181660653484,9.80999679571,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117745250000,11052,117745250000,RH_EXTIMU,2.293183196e-06,1.53196615055e-05,-0.703286037122,0.710906990927,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.81693540833e-08,-2.21061727875e-08,-7.22009336014e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246087327017,-0.000178542674556,9.80998704598,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117747750000,11053,117747750000,RH_EXTIMU,2.29329139507e-06,1.53195613238e-05,-0.703286101282,0.710906927455,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.18803441961e-07,4.56022684731e-09,-7.22002706405e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244808220716,-0.000181947765531,9.81000178509,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117750250000,11054,117750250000,RH_EXTIMU,2.29320463572e-06,1.53195684906e-05,-0.703286165441,0.710906863984,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.24717115333e-08,-4.40772440141e-08,-7.21995169286e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246213828915,-0.000178047842864,9.80999242585,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117750250000,11055,117752750000,RH_EXTIMU,2.2932913045e-06,1.53195007692e-05,-0.703286229599,0.710906800514,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.82954801468e-08,1.09076674284e-08,-7.21985776802e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024522225298,-0.000180891416039,9.81003509629,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117755250000,11056,117755250000,RH_EXTIMU,2.29309344794e-06,1.53196727566e-05,-0.703286293756,0.710906737044,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.08388404483e-07,-1.28460937909e-08,-7.21977440579e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245213461921,-0.000175906863484,9.81000608935,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117757750000,11057,117757750000,RH_EXTIMU,2.29316299034e-06,1.53196814379e-05,-0.703286357913,0.710906673575,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.55688884737e-08,4.47240318075e-08,-7.21971848869e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244776732528,-0.000180521462445,9.80998867347,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117762750000,11058,117760250000,RH_EXTIMU,2.29329336854e-06,1.53195824688e-05,-0.703286422069,0.710906610106,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.30734970339e-07,1.77285196194e-08,-7.21965870892e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244880811467,-0.00018178797353,9.80998622901,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117762750000,11059,117762750000,RH_EXTIMU,2.29346102476e-06,1.53194455635e-05,-0.703286486225,0.710906546638,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.73279948265e-07,1.71269066204e-08,-7.21959389915e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245332844923,-0.000182313647277,9.80999880236,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117765250000,11060,117765250000,RH_EXTIMU,2.29328861395e-06,1.53194931639e-05,-0.70328655038,0.710906483171,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.23933033463e-07,-6.92717073101e-08,-7.21950602553e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246438505825,-0.000176454593377,9.81000353275,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117767750000,11061,117767750000,RH_EXTIMU,2.2932347149e-06,1.53195711494e-05,-0.703286614534,0.710906419704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.36279925846e-08,1.46872759233e-08,-7.21944124447e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244868756476,-0.000178376840913,9.80999213137,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117770250000,11062,117770250000,RH_EXTIMU,2.29324288354e-06,1.53194222205e-05,-0.703286678688,0.710906356238,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.93401640611e-08,-7.94435817158e-08,-7.21937101628e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246818966152,-0.000181203011244,9.80999464601,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117772750000,11063,117772750000,RH_EXTIMU,2.29334011956e-06,1.53193373544e-05,-0.703286742841,0.710906292773,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03951387808e-07,7.10245973005e-09,-7.21930125849e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244546602605,-0.000181295434791,9.81000279832,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117775250000,11064,117775250000,RH_EXTIMU,2.29339758781e-06,1.53193252454e-05,-0.703286806993,0.710906229308,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.03991495598e-08,2.61067521579e-08,-7.21921821507e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024530078765,-0.000179816386255,9.81001520402,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117777750000,11065,117777750000,RH_EXTIMU,2.29321328605e-06,1.53194107569e-05,-0.703286871145,0.710906165844,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.52025648402e-07,-5.44010003828e-08,-7.21914868296e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246114543589,-0.000176779202578,9.80998767173,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117780250000,11066,117780250000,RH_EXTIMU,2.29346682906e-06,1.53193439089e-05,-0.703286935296,0.71090610238,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.82709551224e-07,1.05292710498e-07,-7.21908096192e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243455110003,-0.000182903971445,9.81001128283,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117782750000,11067,117782750000,RH_EXTIMU,2.29346689621e-06,1.53194037111e-05,-0.703286999447,0.710906038917,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.2705656399e-08,3.47088488136e-08,-7.21901204274e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244904453409,-0.000178694839104,9.80999319876,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117785250000,11068,117785250000,RH_EXTIMU,2.29354782256e-06,1.53193775937e-05,-0.703287063597,0.710905975455,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.16218465478e-08,3.1338040657e-08,-7.21894458253e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244950317669,-0.000180523918674,9.80999732479,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117787750000,11069,117787750000,RH_EXTIMU,2.29347003814e-06,1.53193682817e-05,-0.703287127746,0.710905911993,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.80961105574e-08,-4.83997246667e-08,-7.21887250549e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246498335555,-0.000178285597786,9.80999058003,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117790250000,11070,117790250000,RH_EXTIMU,2.29348046574e-06,1.53192806352e-05,-0.703287191895,0.710905848532,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.6145567215e-08,-4.3319799211e-08,-7.21880606691e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245644492047,-0.000180658336284,9.80999408856,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117792750000,11071,117792750000,RH_EXTIMU,2.29357044321e-06,1.53191846988e-05,-0.703287256043,0.710905785072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.06051697715e-07,-3.27738287266e-09,-7.21873195951e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245212177494,-0.000181344617064,9.81000696248,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117795250000,11072,117795250000,RH_EXTIMU,2.29356910901e-06,1.53191888447e-05,-0.70328732019,0.710905721612,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.18879634395e-09,2.2672175202e-09,-7.21864858755e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245192142085,-0.000179227576991,9.8100126012,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117797750000,11073,117797750000,RH_EXTIMU,2.293528312e-06,1.53192850058e-05,-0.703287384336,0.710905658153,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.64028065804e-08,3.2395600678e-08,-7.21857442193e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244845794011,-0.00017800513415,9.81000374321,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117800250000,11074,117800250000,RH_EXTIMU,2.2934606798e-06,1.531933274e-05,-0.703287448482,0.710905594694,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.44181789099e-08,-1.02443096786e-08,-7.21850481782e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245794011011,-0.000178191663677,9.80999156635,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117802750000,11075,117802750000,RH_EXTIMU,2.29352055818e-06,1.531923889e-05,-0.703287512628,0.710905531236,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.77596523245e-08,-1.90253739978e-08,-7.21843798182e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245466932176,-0.000181250623895,9.8099973546,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117805250000,11076,117805250000,RH_EXTIMU,2.29352719295e-06,1.53191733903e-05,-0.703287576772,0.710905467779,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.15280027586e-08,-3.28583567766e-08,-7.21836499285e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245872566982,-0.000179979310376,9.80999779452,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117807750000,11077,117807750000,RH_EXTIMU,2.29361719919e-06,1.53191164788e-05,-0.703287640916,0.710905404322,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.41113856269e-08,1.89332654046e-08,-7.218295102e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244600681146,-0.000181032282798,9.81000410965,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117810250000,11078,117810250000,RH_EXTIMU,2.29370588681e-06,1.53191312664e-05,-0.70328770506,0.710905340866,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.30214152016e-08,5.89683425628e-08,-7.2182156293e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244495852793,-0.000180157932095,9.81001515412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117812750000,11079,117812750000,RH_EXTIMU,2.293627173e-06,1.53192368722e-05,-0.703287769202,0.710905277411,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.03280942112e-07,1.64337949599e-08,-7.21815268012e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245120458682,-0.000177534796119,9.80998176238,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117815250000,11080,117815250000,RH_EXTIMU,2.29371554886e-06,1.53191212973e-05,-0.703287833345,0.710905213956,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.16189917151e-07,-1.53473252791e-08,-7.21807632984e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245919893263,-0.000181354425988,9.81000829963,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117817750000,11081,117817750000,RH_EXTIMU,2.29356483423e-06,1.53191175175e-05,-0.703287897486,0.710905150502,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.26858616952e-08,-8.62863758714e-08,-7.21800781003e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024653876675,-0.000177867782103,9.80998484886,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117820250000,11082,117820250000,RH_EXTIMU,2.29366496674e-06,1.53190255687e-05,-0.703287961627,0.710905087048,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.09583408647e-07,4.70408199622e-09,-7.21794474583e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245039319774,-0.000181355682441,9.80999444568,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117822750000,11083,117822750000,RH_EXTIMU,2.29378833295e-06,1.5318962477e-05,-0.703288025767,0.710905023595,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.06561128218e-07,3.41877406042e-08,-7.21785992039e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024468876112,-0.000181171616384,9.81002275371,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117825250000,11084,117825250000,RH_EXTIMU,2.29360382653e-06,1.53191384861e-05,-0.703288089907,0.710904960143,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.03058814858e-07,-3.04841443468e-09,-7.21777533142e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245584579378,-0.000175469957056,9.8100033381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117827750000,11085,117827750000,RH_EXTIMU,2.29369030993e-06,1.53190989107e-05,-0.703288154045,0.710904896691,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.23539533095e-08,2.68106682297e-08,-7.21771742482e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244759855336,-0.000181412439511,9.80999313688,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117830250000,11086,117830250000,RH_EXTIMU,2.29370369771e-06,1.53189843271e-05,-0.703288218184,0.71090483324,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.29846682943e-08,-5.69741562039e-08,-7.2176460484e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246457784194,-0.000180494376204,9.80999361466,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117834000000,11087,117832750000,RH_EXTIMU,2.29374880968e-06,1.53189861815e-05,-0.703288282321,0.710904769789,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.55153657902e-08,2.70959136944e-08,-7.21758906825e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024444089491,-0.000179724970632,9.80998414998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117835250000,11088,117835250000,RH_EXTIMU,2.29384431474e-06,1.53188992091e-05,-0.703288346459,0.710904706339,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04151767937e-07,4.93070927492e-09,-7.21752027048e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002456763195,-0.000181035924299,9.80999620849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117837750000,11089,117837750000,RH_EXTIMU,2.29392503979e-06,1.53188568556e-05,-0.703288410595,0.71090464289,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.06420829626e-08,2.19908083707e-08,-7.21743933102e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244774548526,-0.000180472599878,9.81001374013,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117840250000,11090,117840250000,RH_EXTIMU,2.29383411463e-06,1.53189095618e-05,-0.703288474731,0.710904579442,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.0462997141e-08,-2.05221520842e-08,-7.21736130557e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245817253437,-0.000177933731246,9.81000238445,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117842750000,11091,117842750000,RH_EXTIMU,2.29379940787e-06,1.53189257598e-05,-0.703288538866,0.710904515994,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.79496434611e-08,-9.65502627624e-09,-7.21729035466e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245269647221,-0.000179062655707,9.80999963835,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117845250000,11092,117845250000,RH_EXTIMU,2.29391580474e-06,1.5318897069e-05,-0.703288603,0.710904452546,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.32423725969e-08,4.98312058449e-08,-7.21720619108e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244577714384,-0.000180931907794,9.81002265529,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117847750000,11093,117847750000,RH_EXTIMU,2.29378125018e-06,1.53189690913e-05,-0.703288667134,0.7109043891,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.16143928999e-07,-3.40839139757e-08,-7.21712456183e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245952644073,-0.000177430983727,9.8100057464,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117850250000,11094,117850250000,RH_EXTIMU,2.29376947572e-06,1.53189997021e-05,-0.703288731267,0.710904325654,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.30165903617e-08,1.14442430487e-08,-7.21705877692e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244928200716,-0.00017919965894,9.80999257573,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117852750000,11095,117852750000,RH_EXTIMU,2.29391222813e-06,1.53189241669e-05,-0.703288795399,0.710904262209,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.24587473043e-07,3.80181438574e-08,-7.21700115213e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244793051607,-0.000181736454851,9.80999089093,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117855250000,11096,117855250000,RH_EXTIMU,2.29408158877e-06,1.53188375657e-05,-0.703288859531,0.710904198764,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.45946262954e-07,4.66952492771e-08,-7.21692462596e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244319275825,-0.000182160434341,9.81001263084,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117857750000,11097,117857750000,RH_EXTIMU,2.29385849259e-06,1.53189249544e-05,-0.703288923662,0.71090413532,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.75145237034e-07,-7.51610452355e-08,-7.2168400897e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024749135331,-0.000175272691117,9.80999484185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117860250000,11098,117860250000,RH_EXTIMU,2.29387030537e-06,1.53188320026e-05,-0.703288987792,0.710904071876,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.99181116813e-08,-4.55577702514e-08,-7.21678356225e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245247084824,-0.000181255984365,9.80998723431,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117862750000,11099,117862750000,RH_EXTIMU,2.29399719621e-06,1.53187233327e-05,-0.703289051922,0.710904008433,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34209171098e-07,1.02494809842e-08,-7.21671997493e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245240994457,-0.00018153057982,9.80999387768,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117865250000,11100,117865250000,RH_EXTIMU,2.29399746803e-06,1.53186713293e-05,-0.703289116052,0.710903944991,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.03156707213e-08,-2.87628271839e-08,-7.21663940848e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024574933073,-0.00017974890485,9.81000663858,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117867750000,11101,117867750000,RH_EXTIMU,2.29396440763e-06,1.53186907067e-05,-0.70328918018,0.710903881549,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.88022297627e-08,-6.92065188331e-09,-7.21656007441e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024525769481,-0.000178826343134,9.8100085921,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117870250000,11102,117870250000,RH_EXTIMU,2.29394633718e-06,1.53187487937e-05,-0.703289244308,0.710903818108,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.20563221765e-08,2.35281775551e-08,-7.21648537229e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024497837777,-0.000178712729759,9.81000443016,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117872750000,11103,117872750000,RH_EXTIMU,2.29395143597e-06,1.53187564506e-05,-0.703289308435,0.710903754668,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.05902162341e-10,7.88316821443e-09,-7.21641320151e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245254080177,-0.000179525852995,9.81000090119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117875250000,11104,117875250000,RH_EXTIMU,2.2940317782e-06,1.53187306818e-05,-0.703289372562,0.710903691228,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.10931029064e-08,3.12075283234e-08,-7.21634365474e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244781079594,-0.000180580237773,9.81000131487,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117875250000,11105,117877750000,RH_EXTIMU,2.29407251297e-06,1.53187061399e-05,-0.703289436688,0.710903627789,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.78770899998e-08,9.62091861207e-09,-7.21627167673e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024525321109,-0.000180024442593,9.81000030626,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117880250000,11106,117880250000,RH_EXTIMU,2.29394346129e-06,1.53187137403e-05,-0.703289500813,0.710903564351,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.67685911979e-08,-6.7626273803e-08,-7.21620025486e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246825806567,-0.000177526781539,9.80998713842,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117884000000,11107,117882750000,RH_EXTIMU,2.29404581733e-06,1.53186108043e-05,-0.703289564938,0.710903500913,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17029581377e-07,-2.93608688345e-10,-7.21614199097e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244569905607,-0.000182029511277,9.80999251816,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117884000000,11108,117885250000,RH_EXTIMU,2.29414299372e-06,1.53185815823e-05,-0.703289629062,0.710903437475,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.26098806917e-08,3.87150493313e-08,-7.21607138281e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244850404153,-0.000180295769757,9.80999865111,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117884000000,11109,117887750000,RH_EXTIMU,2.29426229492e-06,1.53185869049e-05,-0.703289693185,0.710903374039,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.57568843785e-08,7.08094613516e-08,-7.21600789352e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244120720586,-0.000180585559964,9.80999456027,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117890250000,11110,117890250000,RH_EXTIMU,2.29429101847e-06,1.53185391872e-05,-0.703289757308,0.710903310602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.40854787474e-08,-1.03176479115e-08,-7.21593485472e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024598638619,-0.000179927910379,9.80999922387,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117892750000,11111,117892750000,RH_EXTIMU,2.2941041534e-06,1.53184819463e-05,-0.70328982143,0.710903247167,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.31666244212e-08,-1.37030714333e-07,-7.2158588209e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247453395218,-0.00017797132513,9.8099900986,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117895250000,11112,117895250000,RH_EXTIMU,2.29425346957e-06,1.53183901638e-05,-0.703289885552,0.710903183732,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.37461504593e-07,3.24709042037e-08,-7.21579061012e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244139082073,-0.000182088026236,9.81000856193,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117897750000,11113,117897750000,RH_EXTIMU,2.29416494343e-06,1.53184488473e-05,-0.703289949673,0.710903120298,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.24618317088e-08,-1.57733085925e-08,-7.21570918639e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246119398294,-0.000177390627532,9.8100015463,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117900250000,11114,117900250000,RH_EXTIMU,2.29410472943e-06,1.53184276885e-05,-0.703290013793,0.710903056864,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.14382408851e-08,-4.52521220134e-08,-7.21564083489e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245812946347,-0.000179235755088,9.80999377703,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117902750000,11115,117902750000,RH_EXTIMU,2.29432176047e-06,1.53183109613e-05,-0.703290077913,0.710902993431,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.90007068417e-07,5.63829202735e-08,-7.21556984201e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243933948847,-0.000183371690358,9.81001690066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117905250000,11116,117905250000,RH_EXTIMU,2.29425633309e-06,1.53184307013e-05,-0.703290142032,0.710902929999,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.03677417063e-07,3.19469480106e-08,-7.21547740435e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245241122195,-0.000176858238855,9.81001561565,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117907750000,11117,117907750000,RH_EXTIMU,2.29409991426e-06,1.53185055725e-05,-0.70329020615,0.710902866567,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.30181623199e-07,-4.47657064785e-08,-7.21541414544e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246038366215,-0.000177480854079,9.80998410192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117910250000,11118,117910250000,RH_EXTIMU,2.29422321576e-06,1.53184521757e-05,-0.703290270267,0.710902803136,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.01069203007e-07,3.96651282868e-08,-7.21534736193e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244570304429,-0.000181155932692,9.81000127256,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117912750000,11119,117912750000,RH_EXTIMU,2.29421699811e-06,1.53184450626e-05,-0.703290334384,0.710902739706,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.3681109972e-09,-6.88399752662e-09,-7.21527374875e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245617227321,-0.000179260069057,9.8099970186,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117915250000,11120,117915250000,RH_EXTIMU,2.2943531705e-06,1.53183193664e-05,-0.703290398501,0.710902676276,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.49067136159e-07,5.78841071652e-09,-7.21520554986e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245044336547,-0.000182469486928,9.81000417563,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117917750000,11121,117917750000,RH_EXTIMU,2.2943312631e-06,1.53183068237e-05,-0.703290462616,0.710902612847,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.50014401742e-09,-1.87995163783e-08,-7.21512374153e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245691520598,-0.000178766145237,9.81000834715,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117920250000,11122,117920250000,RH_EXTIMU,2.29433251426e-06,1.53183856406e-05,-0.703290526731,0.710902549419,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.27312668137e-08,4.61884903714e-08,-7.21505018464e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244474272161,-0.000178791389872,9.81000506184,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117922750000,11123,117922750000,RH_EXTIMU,2.29438340581e-06,1.53183650263e-05,-0.703290590846,0.710902485991,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.14435740743e-08,1.75690012982e-08,-7.21497643765e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245179737269,-0.000180409699523,9.81000577403,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117926500000,11124,117925250000,RH_EXTIMU,2.29420480503e-06,1.53184063003e-05,-0.70329065496,0.710902422564,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.23894194024e-07,-7.63535399714e-08,-7.21491804472e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246497012585,-0.000177008695411,9.80996950736,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117927750000,11125,117927750000,RH_EXTIMU,2.2944291238e-06,1.53182289498e-05,-0.703290719073,0.710902359137,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.28260309748e-07,2.60054786683e-08,-7.21485600015e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244791117847,-0.000183519759132,9.81000039953,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117930250000,11126,117930250000,RH_EXTIMU,2.29456070467e-06,1.53182530912e-05,-0.703290783185,0.710902295711,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.21522549129e-08,8.84210301812e-08,-7.2147751644e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243852531168,-0.000180016919264,9.81001333144,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117932750000,11127,117932750000,RH_EXTIMU,2.29431967544e-06,1.53183222486e-05,-0.703290847297,0.710902232285,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.75086705629e-07,-9.56200179694e-08,-7.21469529981e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247275199491,-0.000176145473723,9.80999474039,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117935250000,11128,117935250000,RH_EXTIMU,2.29440937657e-06,1.53181998972e-05,-0.703290911408,0.710902168861,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.20755944298e-07,-1.84555310997e-08,-7.21462475188e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245400806271,-0.000181936345996,9.81000467535,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117937750000,11129,117937750000,RH_EXTIMU,2.29436909093e-06,1.53181554056e-05,-0.703290975519,0.710902105436,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.02317338339e-09,-4.73098011689e-08,-7.21455129095e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245992317878,-0.000179262093885,9.80999842626,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117940250000,11130,117940250000,RH_EXTIMU,2.29437377465e-06,1.5318132894e-05,-0.703291039629,0.710902042013,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.62315722049e-08,-9.50810329743e-09,-7.21448137131e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245353748295,-0.000179655494027,9.80999737692,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117942750000,11131,117942750000,RH_EXTIMU,2.29442410713e-06,1.53180828491e-05,-0.703291103738,0.71090197859,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.7684126442e-08,5.16629073019e-10,-7.21441333636e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245253499565,-0.000180441821452,9.80999696906,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117945250000,11132,117945250000,RH_EXTIMU,2.29449498249e-06,1.53181308138e-05,-0.703291167846,0.710901915168,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.42238122146e-08,6.78149387639e-08,-7.21434120757e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002440680045,-0.000179432803297,9.81000557869,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117950250000,11133,117947750000,RH_EXTIMU,2.29443659611e-06,1.53181433149e-05,-0.703291231954,0.710901851746,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.93370569492e-08,-2.50809626356e-08,-7.21427477903e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024598606336,-0.000178794836883,9.80998606516,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117950250000,11134,117950250000,RH_EXTIMU,2.29451989816e-06,1.53180412625e-05,-0.703291296062,0.710901788325,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.05695690891e-07,-1.05113526324e-08,-7.21420160606e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245512957839,-0.000181131501575,9.81000448162,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117952750000,11135,117952750000,RH_EXTIMU,2.29452616437e-06,1.53180299509e-05,-0.703291360169,0.710901724905,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.08300273081e-08,-2.24807237174e-09,-7.21412979535e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245217353355,-0.000179529803524,9.80999875337,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117955250000,11136,117955250000,RH_EXTIMU,2.29456191799e-06,1.53180276648e-05,-0.703291424275,0.710901661485,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.25220707437e-08,1.9475521828e-08,-7.21405611531e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024499357425,-0.000179714071188,9.81000483327,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117957750000,11137,117957750000,RH_EXTIMU,2.29450678974e-06,1.53180162433e-05,-0.70329148838,0.710901598066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.40245027533e-08,-3.68531515094e-08,-7.2139773708e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246065338548,-0.000178947436708,9.8100037468,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117960250000,11138,117960250000,RH_EXTIMU,2.29454110508e-06,1.53179932928e-05,-0.703291552485,0.710901534647,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.33305641514e-08,6.91399423605e-09,-7.21390818704e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244997922495,-0.000180144171537,9.81000021635,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117962750000,11139,117962750000,RH_EXTIMU,2.2945599764e-06,1.53179904013e-05,-0.703291616589,0.710901471229,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.32613578165e-08,9.63263566091e-09,-7.21384489064e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245037057529,-0.000179652255868,9.80998890925,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117965250000,11140,117965250000,RH_EXTIMU,2.29476396381e-06,1.53178906141e-05,-0.703291680692,0.710901407812,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.73057519201e-07,5.86784837545e-08,-7.21377540944e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244314314458,-0.000182595470489,9.81000894169,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117967750000,11141,117967750000,RH_EXTIMU,2.29458851795e-06,1.53179588095e-05,-0.703291744795,0.710901344395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.37246831623e-07,-5.92680635913e-08,-7.21369385449e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246655155014,-0.000176350795034,9.80999536948,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117970250000,11142,117970250000,RH_EXTIMU,2.29457988502e-06,1.53179808714e-05,-0.703291808897,0.710901280979,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.64205169058e-08,8.34931302744e-09,-7.21362904981e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244928119295,-0.000179123446168,9.80999339681,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117972750000,11143,117972750000,RH_EXTIMU,2.29487254989e-06,1.53179011831e-05,-0.703291872999,0.710901217564,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.12181903804e-07,1.20002088873e-07,-7.21356470307e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024294471992,-0.000183896397151,9.81001080849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117975250000,11144,117975250000,RH_EXTIMU,2.29470655891e-06,1.53179740384e-05,-0.7032919371,0.710901154149,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.34491494367e-07,-5.12982867263e-08,-7.21347489318e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247387977689,-0.000175771425055,9.8100018062,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117977750000,11145,117977750000,RH_EXTIMU,2.29474459421e-06,1.53179363488e-05,-0.7032920012,0.710901090735,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.37388541048e-08,6.24478350098e-10,-7.21340481274e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244292799577,-0.000181157166198,9.8100100892,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117980250000,11146,117980250000,RH_EXTIMU,2.29475249471e-06,1.53179650765e-05,-0.7032920653,0.710901027321,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.07680644751e-08,2.14425323898e-08,-7.21333083103e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245356689708,-0.000178900479343,9.80999906106,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117982750000,11147,117982750000,RH_EXTIMU,2.29475599279e-06,1.53179545147e-05,-0.703292129399,0.710900963908,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.83374506784e-09,-3.37915677452e-09,-7.21326432379e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245451278688,-0.000179489694006,9.80999178746,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117985250000,11148,117985250000,RH_EXTIMU,2.29492038147e-06,1.53178730901e-05,-0.703292193497,0.710900900496,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.40205384598e-07,4.68421482061e-08,-7.21319344338e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024447977043,-0.000181965865006,9.81000892619,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117987750000,11149,117987750000,RH_EXTIMU,2.29472278314e-06,1.53178623356e-05,-0.703292257595,0.710900837085,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.05425544851e-07,-1.16632396966e-07,-7.21311187582e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247493566079,-0.000177246084925,9.8099961299,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117990250000,11150,117990250000,RH_EXTIMU,2.29471291297e-06,1.53178238356e-05,-0.703292321692,0.710900773674,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.69499258989e-08,-2.67896608166e-08,-7.21304292352e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245299268502,-0.00017981566964,9.809998558,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117992750000,11151,117992750000,RH_EXTIMU,2.29487490078e-06,1.53177743856e-05,-0.703292385788,0.710900710263,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.20849877791e-07,6.3676002744e-08,-7.21297231453e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243973748896,-0.000181830880042,9.81001112392,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117995250000,11152,117995250000,RH_EXTIMU,2.29470271854e-06,1.53178921731e-05,-0.703292449884,0.710900646854,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.63292963512e-07,-2.92280333964e-08,-7.21288893694e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246538263906,-0.000175678977443,9.80999563973,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +117997750000,11153,117997750000,RH_EXTIMU,2.29479577892e-06,1.5317776804e-05,-0.703292513979,0.710900583445,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.1873777786e-07,-1.25944895054e-08,-7.21283315069e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245066689004,-0.000182291407342,9.80999207723,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118000250000,11154,118000250000,RH_EXTIMU,2.29470991182e-06,1.53177367941e-05,-0.703292578073,0.710900520036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.54215914612e-08,-7.04068569309e-08,-7.21275955105e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024654861863,-0.000178374003025,9.80999064678,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118002750000,11155,118002750000,RH_EXTIMU,2.2948727564e-06,1.53176947204e-05,-0.703292642167,0.710900456628,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17186961571e-07,6.83530747235e-08,-7.21268891277e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243925612119,-0.000181520462694,9.81000906816,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118005250000,11156,118005250000,RH_EXTIMU,2.29480205256e-06,1.53177109545e-05,-0.70329270626,0.710900393221,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.8442768903e-08,-2.98883780686e-08,-7.21261265037e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246271617064,-0.000178291519161,9.80999716458,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118007750000,11157,118007750000,RH_EXTIMU,2.2948404439e-06,1.53176537834e-05,-0.703292770353,0.710900329814,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.49021542833e-08,-1.02547559566e-08,-7.21254773706e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244924939374,-0.00018060466832,9.80999428621,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118010250000,11158,118010250000,RH_EXTIMU,2.29495114122e-06,1.53176236779e-05,-0.703292834444,0.710900266408,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.07959773286e-08,4.58198222257e-08,-7.212484162e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024481014205,-0.000180667825335,9.80999390266,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118012750000,11159,118012750000,RH_EXTIMU,2.29500992391e-06,1.53175423162e-05,-0.703292898536,0.710900203003,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.01095496325e-08,-1.25395546367e-08,-7.21240971674e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245515656616,-0.00018076863324,9.81000375961,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118015250000,11160,118015250000,RH_EXTIMU,2.29496472284e-06,1.53175735559e-05,-0.703292962626,0.710900139598,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.23815085437e-08,-7.00572964288e-09,-7.21232346707e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245490282352,-0.000178289855974,9.81001472363,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118017750000,11161,118017750000,RH_EXTIMU,2.29481227567e-06,1.53176557041e-05,-0.703293026716,0.710900076194,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.32017392431e-07,-3.83934091443e-08,-7.21225440758e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245823151737,-0.0001772444407,9.80999029849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118020250000,11162,118020250000,RH_EXTIMU,2.29505289223e-06,1.53176334366e-05,-0.703293090806,0.71090001279,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.50273679607e-07,1.23374492494e-07,-7.21219215234e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243080902751,-0.000182263773304,9.8100042213,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118022750000,11163,118022750000,RH_EXTIMU,2.2949684849e-06,1.53176358508e-05,-0.703293154894,0.710899949387,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.84606848508e-08,-4.54582002935e-08,-7.21211664071e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002465428001,-0.000178229191035,9.8099932519,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118025250000,11164,118025250000,RH_EXTIMU,2.2950193336e-06,1.53175568799e-05,-0.703293218982,0.710899885985,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.42521981142e-08,-1.56438481482e-08,-7.21204438871e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245375855196,-0.000180873394636,9.81000468018,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118027750000,11165,118027750000,RH_EXTIMU,2.29506380793e-06,1.53175325644e-05,-0.70329328307,0.710899822584,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.98759173412e-08,1.18533396239e-08,-7.21196443822e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244940439218,-0.000180079158255,9.81001256123,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118030250000,11166,118030250000,RH_EXTIMU,2.29487577296e-06,1.53175929927e-05,-0.703293347156,0.710899759183,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.40036564543e-07,-7.07689400556e-08,-7.21190270456e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246607838819,-0.000176757339901,9.80997395283,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118032750000,11167,118032750000,RH_EXTIMU,2.29498295959e-06,1.53174114095e-05,-0.703293411242,0.710899695782,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.64025882922e-07,-4.23037852573e-08,-7.2118377418e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246030759473,-0.000182246166926,9.8099945412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118035250000,11168,118035250000,RH_EXTIMU,2.29511026078e-06,1.53173478217e-05,-0.703293475328,0.710899632382,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.09077120621e-07,3.61196448822e-08,-7.21176282619e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244474101917,-0.000181055228124,9.81000934319,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118037750000,11169,118037750000,RH_EXTIMU,2.29513783342e-06,1.53173738748e-05,-0.703293539413,0.710899568983,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.92442598814e-09,3.09894571349e-08,-7.21168684544e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244790041385,-0.000179498931566,9.81000673781,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118040250000,11170,118040250000,RH_EXTIMU,2.29519068294e-06,1.53174070777e-05,-0.703293603497,0.710899505585,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22771396327e-08,4.92773309288e-08,-7.21161440503e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244459632514,-0.000179624486301,9.81000397547,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118040250000,11171,118042750000,RH_EXTIMU,2.29515879296e-06,1.53174529688e-05,-0.70329366758,0.710899442187,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.30547139138e-08,8.8159657784e-09,-7.21154273389e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245714026909,-0.000178361505674,9.80999680709,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118040250000,11172,118045250000,RH_EXTIMU,2.29523033615e-06,1.53173704695e-05,-0.703293731663,0.710899378789,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.80066536826e-08,-6.00704295366e-09,-7.21146712631e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245005149329,-0.000181476813612,9.81001147265,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118040250000,11173,118047750000,RH_EXTIMU,2.29509301758e-06,1.53174281956e-05,-0.703293795745,0.710899315393,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.09672826373e-07,-4.37710589092e-08,-7.21139059111e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246205483512,-0.000176997696647,9.80999408067,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118040250000,11174,118050250000,RH_EXTIMU,2.29514866856e-06,1.53173859557e-05,-0.703293859827,0.710899251997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.63171216641e-08,7.94769853547e-09,-7.21132360473e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245079316151,-0.000180565813704,9.80999981617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118052750000,11175,118052750000,RH_EXTIMU,2.29514522694e-06,1.5317357738e-05,-0.703293923908,0.710899188602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.48205826273e-08,-1.732514071e-08,-7.211248038e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245656989698,-0.000179480457234,9.8100012566,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118055250000,11176,118055250000,RH_EXTIMU,2.29514375644e-06,1.53173421959e-05,-0.703293987988,0.710899125207,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.8098541508e-09,-9.0072603374e-09,-7.21117579523e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245380688407,-0.000179527590557,9.81000060117,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118057750000,11177,118057750000,RH_EXTIMU,2.29515942901e-06,1.53173259898e-05,-0.703294052068,0.710899061813,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.89330486572e-08,2.60362656333e-10,-7.21110430045e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245278189195,-0.000179707112884,9.80999998931,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118060250000,11178,118060250000,RH_EXTIMU,2.29517928844e-06,1.5317306654e-05,-0.703294116147,0.710898998419,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.30750502845e-08,8.36146795156e-10,-7.21103282311e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245295186887,-0.000179759119289,9.80999978535,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118062750000,11179,118062750000,RH_EXTIMU,2.29519878806e-06,1.53172868563e-05,-0.703294180225,0.710898935026,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.3130317767e-08,3.70963379457e-10,-7.21096123454e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245302320899,-0.000179750126366,9.80999980036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118066500000,11180,118065250000,RH_EXTIMU,2.29521739346e-06,1.53172678279e-05,-0.703294244303,0.710898871634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.21888984091e-08,3.05379324332e-10,-7.21088962368e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024530217568,-0.000179731853147,9.80999985802,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118067750000,11181,118067750000,RH_EXTIMU,2.29525604965e-06,1.53172569055e-05,-0.70329430838,0.710898808243,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.90313896388e-08,1.61967292548e-08,-7.2108147517e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024504564988,-0.000179837194819,9.81000579726,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118070250000,11182,118070250000,RH_EXTIMU,2.29529013601e-06,1.53172042188e-05,-0.703294372456,0.710898744852,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.99305864697e-08,-1.01266490193e-08,-7.21075113715e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245104237657,-0.000180772333058,9.80999282896,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118072750000,11183,118072750000,RH_EXTIMU,2.29535234281e-06,1.53172057889e-05,-0.703294436532,0.710898681461,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.53963294564e-08,3.65518414923e-08,-7.21067372813e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245094660916,-0.000179359947686,9.81000558277,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118075250000,11184,118075250000,RH_EXTIMU,2.29536758646e-06,1.53172398496e-05,-0.703294500607,0.710898618072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.59281351456e-09,2.86066545124e-08,-7.21060337595e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024475803752,-0.000179323358023,9.80999864387,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118077750000,11185,118077750000,RH_EXTIMU,2.2955383739e-06,1.53171956956e-05,-0.703294564681,0.710898554682,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.228741988e-07,7.16389976973e-08,-7.21053896203e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244124300974,-0.000181758381979,9.81000362467,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118080250000,11186,118080250000,RH_EXTIMU,2.29532883035e-06,1.53172863788e-05,-0.703294628755,0.710898491294,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.6929139515e-07,-6.56643653835e-08,-7.21045772239e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024725621286,-0.000175456709363,9.80998911769,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118080250000,11187,118082750000,RH_EXTIMU,2.29541267421e-06,1.53171439419e-05,-0.703294692829,0.710898427906,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.28725158506e-07,-3.31738639653e-08,-7.2103951642e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245218083916,-0.000182365548537,9.80999936879,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118085250000,11188,118085250000,RH_EXTIMU,2.29543098756e-06,1.53170942121e-05,-0.703294756901,0.710898364519,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.92964313222e-08,-1.73194485263e-08,-7.21032137121e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245520941168,-0.000179799090243,9.80999945376,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118087750000,11189,118087750000,RH_EXTIMU,2.2953762389e-06,1.53170929754e-05,-0.703294820973,0.710898301132,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.95392585995e-08,-3.0847822823e-08,-7.21024930052e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245772414654,-0.000178711439336,9.80999635995,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118090250000,11190,118090250000,RH_EXTIMU,2.29543427136e-06,1.53170214686e-05,-0.703294885044,0.710898237746,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.41379407535e-08,-7.35705764149e-09,-7.21017797137e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024532167667,-0.000180896150825,9.81000221238,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118092750000,11191,118092750000,RH_EXTIMU,2.29534889124e-06,1.53170207812e-05,-0.703294949115,0.710898174361,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.72689847979e-08,-4.77698444232e-08,-7.21010457894e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246329518893,-0.000177968702191,9.80999307379,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118092750000,11192,118095250000,RH_EXTIMU,2.2954739403e-06,1.53169573867e-05,-0.703295013185,0.710898110976,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.07687194587e-07,3.49625441982e-08,-7.2100410719e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244151319976,-0.000181839236718,9.81000084708,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118096500000,11193,118097750000,RH_EXTIMU,2.295516623e-06,1.53169446613e-05,-0.703295077254,0.710898047592,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.23357309636e-08,1.7436637262e-08,-7.20996399136e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245422337511,-0.00017954715839,9.81000387263,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118096500000,11194,118100250000,RH_EXTIMU,2.2954732079e-06,1.53169417133e-05,-0.703295141323,0.710897984208,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.21308543231e-08,-2.54444610262e-08,-7.20988661846e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245748426563,-0.00017893664418,9.8100047751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118102750000,11195,118102750000,RH_EXTIMU,2.29538945314e-06,1.53169694303e-05,-0.703295205391,0.710897920826,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.23260436561e-08,-3.07012329187e-08,-7.20981245457e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245806903094,-0.000178160564857,9.80999722081,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118105250000,11196,118105250000,RH_EXTIMU,2.29544144208e-06,1.53168974305e-05,-0.703295269458,0.710897857443,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.09782405812e-08,-1.10377759489e-08,-7.20974955398e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245374121313,-0.000180913348319,9.80999188097,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118107750000,11197,118107750000,RH_EXTIMU,2.29554492211e-06,1.53168140643e-05,-0.703295333525,0.710897794062,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.06657251708e-07,1.14687461558e-08,-7.20968436491e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244873809324,-0.000181103128422,9.80999512481,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118110250000,11198,118110250000,RH_EXTIMU,2.29565155442e-06,1.5316839988e-05,-0.703295397592,0.71089773068,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.69595358076e-08,7.53974857666e-08,-7.209612231e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244062207555,-0.000180025294643,9.81000768095,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118112750000,11199,118112750000,RH_EXTIMU,2.2956704661e-06,1.53169207425e-05,-0.703295461657,0.7108976673,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.37785693463e-08,5.7225914668e-08,-7.20952683505e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244541465689,-0.000178815452228,9.81001728413,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118115250000,11200,118115250000,RH_EXTIMU,2.29546719499e-06,1.53169523258e-05,-0.703295525722,0.71089760392,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.32472445552e-07,-9.57467658182e-08,-7.20945459646e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247267015004,-0.000177026788555,9.80998573346,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118117750000,11201,118117750000,RH_EXTIMU,2.29563009387e-06,1.53168069563e-05,-0.703295589786,0.710897540541,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.75335116397e-07,9.63755171533e-09,-7.20939011787e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244683309633,-0.000182842922134,9.81000458195,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118120250000,11202,118120250000,RH_EXTIMU,2.29554774263e-06,1.53168300759e-05,-0.70329565385,0.710897477163,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.89411696264e-08,-3.2526336294e-08,-7.20930678808e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246243879713,-0.000177643351221,9.81000289837,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118122750000,11203,118122750000,RH_EXTIMU,2.29545358789e-06,1.53168498868e-05,-0.703295717912,0.710897413785,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.37924711963e-08,-4.10490975785e-08,-7.20924170713e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245775213651,-0.000178230673598,9.80998710083,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118125250000,11204,118125250000,RH_EXTIMU,2.29578371256e-06,1.53166984899e-05,-0.703295781975,0.710897350408,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.73830626066e-07,1.00297022009e-07,-7.20918273719e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243041520616,-0.000185137313605,9.81000914788,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118127750000,11205,118127750000,RH_EXTIMU,2.29560273549e-06,1.53167995745e-05,-0.703295846036,0.710897287031,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.58897390766e-07,-4.36768155547e-08,-7.20909214473e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247079751899,-0.000175108887501,9.80999782559,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118130250000,11206,118130250000,RH_EXTIMU,2.2956382615e-06,1.53167348366e-05,-0.703295910097,0.710897223655,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.75295239329e-08,-1.61704139009e-08,-7.20903602709e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245022524097,-0.000181185683112,9.80999050196,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118130250000,11207,118132750000,RH_EXTIMU,2.29576425607e-06,1.5316679455e-05,-0.703295974158,0.71089716028,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03716398572e-07,4.005160669e-08,-7.20895827219e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024468982538,-0.000180889868269,9.81001176601,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118135250000,11208,118135250000,RH_EXTIMU,2.29569509041e-06,1.53167044353e-05,-0.703296038217,0.710897096905,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.24892302827e-08,-2.40495061725e-08,-7.20888997992e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245732026344,-0.000178490268038,9.80998935256,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118137750000,11209,118137750000,RH_EXTIMU,2.29589011429e-06,1.53166002857e-05,-0.703296102277,0.710897033531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.70413310581e-07,5.1154751572e-08,-7.20882086302e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244076591358,-0.000182753552568,9.81001071824,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118140250000,11210,118140250000,RH_EXTIMU,2.29579942433e-06,1.53167174515e-05,-0.703296166335,0.710896970157,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.16597487329e-07,1.62676417032e-08,-7.20873151097e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245614338167,-0.000176475157353,9.8100126023,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118142750000,11211,118142750000,RH_EXTIMU,2.29571836944e-06,1.53167990202e-05,-0.703296230393,0.710896906785,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.10896026573e-08,1.44397435842e-09,-7.20865177213e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245208168795,-0.000178228435544,9.81001139819,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118146500000,11212,118145250000,RH_EXTIMU,2.29567663966e-06,1.53168200257e-05,-0.703296294449,0.710896843412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.46496257236e-08,-1.08736433083e-08,-7.20857793907e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245512293085,-0.000178915159277,9.8099986001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118147750000,11213,118147750000,RH_EXTIMU,2.29583128639e-06,1.53167170281e-05,-0.703296358506,0.710896780041,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.46801864932e-07,2.90923217905e-08,-7.20851839459e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244693362198,-0.000182285597004,9.8099963476,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118150250000,11214,118150250000,RH_EXTIMU,2.29572244565e-06,1.53167531459e-05,-0.703296422562,0.71089671667,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.13195112951e-08,-4.00381977953e-08,-7.20844355202e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246401124769,-0.000177023092602,9.80998997506,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118152750000,11215,118152750000,RH_EXTIMU,2.29577278202e-06,1.53166454946e-05,-0.703296486617,0.7108966533,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.00970197005e-08,-3.22431510008e-08,-7.20837706736e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245544995389,-0.000181461301604,9.80999748064,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118152750000,11216,118155250000,RH_EXTIMU,2.29578066453e-06,1.53165954393e-05,-0.703296550671,0.71089658993,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.35471638624e-08,-2.33734784591e-08,-7.20830823868e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245568726252,-0.000179661114086,9.80999222166,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118157750000,11217,118157750000,RH_EXTIMU,2.29593741223e-06,1.53165133658e-05,-0.703296614725,0.710896526561,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.36223998231e-07,4.21743014039e-08,-7.20824571434e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244397808301,-0.000181986692327,9.80999859276,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118160250000,11218,118160250000,RH_EXTIMU,2.29597391489e-06,1.53165040218e-05,-0.703296678779,0.710896463192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.6918246874e-08,1.58824597921e-08,-7.20816790886e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245246632602,-0.000179455071648,9.81000469251,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118162750000,11219,118162750000,RH_EXTIMU,2.29588754308e-06,1.53165387407e-05,-0.703296742831,0.710896399824,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.77540676761e-08,-2.81919346859e-08,-7.20809178924e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246040111909,-0.000177935451458,9.80999928258,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118165250000,11220,118165250000,RH_EXTIMU,2.29591306465e-06,1.53164975755e-05,-0.703296806883,0.710896336457,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.85768799141e-08,-8.39316957653e-09,-7.20802116901e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245045231325,-0.000180385875488,9.81000284063,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118167750000,11221,118167750000,RH_EXTIMU,2.29594419494e-06,1.53165268436e-05,-0.703296870934,0.710896273091,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.13824200444e-09,3.48191159607e-08,-7.20794743852e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244771822934,-0.000179231180711,9.81000310777,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118170250000,11222,118170250000,RH_EXTIMU,2.29593229682e-06,1.53165274372e-05,-0.703296934985,0.710896209725,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.19946801878e-09,-5.69791267423e-09,-7.20787586472e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245711174995,-0.000179228291908,9.8099972411,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118172750000,11223,118172750000,RH_EXTIMU,2.29603215107e-06,1.53164637577e-05,-0.703296999035,0.710896146359,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.3518528514e-08,2.0624883608e-08,-7.20779727202e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244843113992,-0.000181073578323,9.81001500486,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118175250000,11224,118175250000,RH_EXTIMU,2.29586261303e-06,1.53165799528e-05,-0.703297063084,0.710896082995,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.60893732956e-07,-2.86475404974e-08,-7.20772376939e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245905086496,-0.00017607085898,9.80998977579,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118177750000,11225,118177750000,RH_EXTIMU,2.29602386253e-06,1.5316507759e-05,-0.703297127133,0.710896019631,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.33225448783e-07,5.03259851455e-08,-7.20767035311e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244157494815,-0.000182429928317,9.80999186052,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118180250000,11226,118180250000,RH_EXTIMU,2.29607348132e-06,1.53164047812e-05,-0.703297191181,0.710895956267,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.70594496101e-08,-2.99890747672e-08,-7.20758769797e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024619012487,-0.000180453208165,9.81000678586,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118182750000,11227,118182750000,RH_EXTIMU,2.29597293064e-06,1.53164228941e-05,-0.703297255229,0.710895892904,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.64747082117e-08,-4.56137385069e-08,-7.20751842521e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024578531632,-0.000178096793879,9.80999257552,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118185250000,11228,118185250000,RH_EXTIMU,2.29606664129e-06,1.53164022819e-05,-0.703297319275,0.710895829542,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.57931757454e-08,4.16613992476e-08,-7.20744756614e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244546296473,-0.000180525933757,9.81000499318,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118187750000,11229,118187750000,RH_EXTIMU,2.29610442674e-06,1.53163438382e-05,-0.703297383321,0.71089576618,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.5272985478e-08,-1.13196302517e-08,-7.20736790574e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245725612831,-0.00018036643885,9.81000861777,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118189000000,11230,118190250000,RH_EXTIMU,2.29596222889e-06,1.53163704426e-05,-0.703297447367,0.71089570282,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.49377477086e-08,-6.42168479541e-08,-7.20729687392e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024621793105,-0.000177567839035,9.80999154602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118192750000,11231,118192750000,RH_EXTIMU,2.29611607596e-06,1.53163535861e-05,-0.703297511412,0.710895639459,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.78806071502e-08,7.76323535434e-08,-7.2072393824e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243723057841,-0.000181276661949,9.80999240216,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118195250000,11232,118195250000,RH_EXTIMU,2.29622992554e-06,1.53163104778e-05,-0.703297575456,0.710895576099,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.9903608662e-08,4.019842956e-08,-7.20716169808e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024501680359,-0.000180653466573,9.81000916177,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118197750000,11233,118197750000,RH_EXTIMU,2.29610608417e-06,1.53163001479e-05,-0.7032976395,0.71089551274,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.37175229113e-08,-7.48939457131e-08,-7.20707325593e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246766467911,-0.000178086072873,9.8100120346,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118200250000,11234,118200250000,RH_EXTIMU,2.29603804663e-06,1.53163556509e-05,-0.703297703542,0.710895449382,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.90210675214e-08,-6.05634813807e-09,-7.20700774632e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244958408266,-0.000178393015492,9.8099932227,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118202750000,11235,118202750000,RH_EXTIMU,2.29603354822e-06,1.53163831996e-05,-0.703297767585,0.710895386024,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.71571700125e-08,1.37951072831e-08,-7.20693922443e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245120589189,-0.000178908215002,9.809995919,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118205250000,11236,118205250000,RH_EXTIMU,2.29613754557e-06,1.53163190366e-05,-0.703297831626,0.710895322667,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.61466155257e-08,2.26810419176e-08,-7.20687736802e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244976304966,-0.000181250084773,9.80998932484,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118207750000,11237,118207750000,RH_EXTIMU,2.29616001043e-06,1.53161602593e-05,-0.703297895667,0.71089525931,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03011446234e-07,-7.70010240907e-08,-7.20681567723e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246730805528,-0.00018097712229,9.80998147845,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118210250000,11238,118210250000,RH_EXTIMU,2.29633084116e-06,1.53160203535e-05,-0.703297959708,0.710895195954,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.7677162124e-07,1.7207891677e-08,-7.20674879722e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244542260518,-0.000182354293094,9.81000287747,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118212750000,11239,118212750000,RH_EXTIMU,2.29631224199e-06,1.53160817511e-05,-0.703298023748,0.710895132599,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.42212455369e-08,2.51118498801e-08,-7.20666676543e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245159701527,-0.000178006723626,9.81000772604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118215250000,11240,118215250000,RH_EXTIMU,2.29626936764e-06,1.53161353165e-05,-0.703298087787,0.710895069244,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.36202259789e-08,6.99937178809e-09,-7.20659146207e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245238276395,-0.000178537729762,9.81000399978,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118217750000,11241,118217750000,RH_EXTIMU,2.29626884338e-06,1.53161391437e-05,-0.703298151825,0.71089500589,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.55048774945e-09,2.54029376065e-09,-7.20651928628e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245285411061,-0.000179436017773,9.81000099005,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118220250000,11242,118220250000,RH_EXTIMU,2.29628628153e-06,1.53161200928e-05,-0.703298215863,0.710894942536,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.15371969176e-08,-3.64590714957e-10,-7.20644793399e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245316149774,-0.000179745505544,9.80999980907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118222750000,11243,118222750000,RH_EXTIMU,2.29630722062e-06,1.53160970507e-05,-0.703298279901,0.710894879183,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.57737819693e-08,-6.64635859697e-10,-7.2063765628e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245312697487,-0.000179772533305,9.80999964999,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118227750000,11244,118225250000,RH_EXTIMU,2.29632704164e-06,1.53160757212e-05,-0.703298343937,0.710894815831,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.41743419953e-08,-3.19747138526e-10,-7.20630501351e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245307228101,-0.000179732807783,9.80999976693,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118227750000,11245,118227750000,RH_EXTIMU,2.29634537205e-06,1.53160562234e-05,-0.703298407973,0.710894752479,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.22960302147e-08,-1.16719883086e-10,-7.20623336261e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245305267905,-0.000179700764115,9.80999987604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118230250000,11246,118230250000,RH_EXTIMU,2.29635491769e-06,1.53160162697e-05,-0.703298472008,0.710894689128,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.88092084478e-08,-1.66929272346e-08,-7.20615715893e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024567137569,-0.000179848493948,9.81000664659,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118232750000,11247,118232750000,RH_EXTIMU,2.29628267165e-06,1.53160373382e-05,-0.703298536043,0.710894625778,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.20403963882e-08,-2.80078913584e-08,-7.20607398773e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245591648637,-0.000178374549012,9.81000898594,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118235250000,11248,118235250000,RH_EXTIMU,2.29629151623e-06,1.53160588797e-05,-0.703298600077,0.710894562429,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.18905974388e-09,1.78858726275e-08,-7.20600368723e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244976819145,-0.000179382238518,9.81000180957,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118237750000,11249,118237750000,RH_EXTIMU,2.29632280872e-06,1.53160443181e-05,-0.70329866411,0.710894499079,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.68904095665e-08,9.98354576452e-09,-7.20593319879e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245202435032,-0.000179874490478,9.8099994029,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118240250000,11250,118240250000,RH_EXTIMU,2.29635170156e-06,1.53160157119e-05,-0.703298728142,0.710894435731,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.34277153432e-08,6.46017618605e-10,-7.20586224175e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245319725342,-0.000179902697073,9.80999920237,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118242750000,11251,118242750000,RH_EXTIMU,2.29643172632e-06,1.53160434777e-05,-0.703298792174,0.710894372383,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.07901627201e-08,6.14744341978e-08,-7.20579635688e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244148594714,-0.0001798508387,9.80999772821,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118245250000,11252,118245250000,RH_EXTIMU,2.2964936268e-06,1.5316040275e-05,-0.703298856206,0.710894309036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.79066523053e-08,3.36647740225e-08,-7.20572578672e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244991148464,-0.000179950812288,9.80999894912,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118247750000,11253,118247750000,RH_EXTIMU,2.29652522951e-06,1.53160160132e-05,-0.703298920236,0.710894245689,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.25245587693e-08,4.64136467497e-09,-7.20564894571e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245358316778,-0.000179823451296,9.810006677,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118250250000,11254,118250250000,RH_EXTIMU,2.29649642392e-06,1.53160317806e-05,-0.703298984266,0.710894182344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.43526327158e-08,-6.58143769324e-09,-7.20557414875e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245389264528,-0.00017891763618,9.81000259427,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118252750000,11255,118252750000,RH_EXTIMU,2.29650142525e-06,1.5316026333e-05,-0.703299048296,0.710894118998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.81030682161e-09,3.74307809152e-10,-7.20550231362e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245286197813,-0.000179530244982,9.81000058692,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118255250000,11256,118255250000,RH_EXTIMU,2.29642432566e-06,1.53160398557e-05,-0.703299112325,0.710894055654,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.05552251638e-08,-3.50301540732e-08,-7.20543316074e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024608642516,-0.000178122507332,9.80998898301,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118257750000,11257,118257750000,RH_EXTIMU,2.29651370932e-06,1.53159462179e-05,-0.703299176353,0.710893992309,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04419034965e-07,-2.30394602462e-09,-7.2053738062e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245019893075,-0.000181514266954,9.80999045207,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118260250000,11258,118260250000,RH_EXTIMU,2.29668075561e-06,1.53158542109e-05,-0.70329924038,0.710893928966,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.47669430944e-07,4.23195103653e-08,-7.2053021181e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244645362311,-0.00018175323915,9.8100045473,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118260250000,11259,118262750000,RH_EXTIMU,2.29655858388e-06,1.53158573536e-05,-0.703299304407,0.710893865623,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.03482631949e-08,-6.62928184554e-08,-7.20522502086e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246860033984,-0.000177606728252,9.8099949743,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118265250000,11260,118265250000,RH_EXTIMU,2.29656804419e-06,1.53157541653e-05,-0.703299368434,0.710893802281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.4338883351e-08,-5.27035067116e-08,-7.20515401611e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245603813851,-0.000180940622289,9.81000266615,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118270250000,11261,118267750000,RH_EXTIMU,2.29654684811e-06,1.53157402492e-05,-0.703299432459,0.710893738939,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.32390111754e-09,-1.91816034525e-08,-7.20507618358e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245606923027,-0.000178972660722,9.81000411652,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118270250000,11262,118270250000,RH_EXTIMU,2.2964228453e-06,1.5315798617e-05,-0.703299496484,0.710893675598,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.02461430951e-07,-3.59157941411e-08,-7.20500666191e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246014903042,-0.000177187518519,9.80998825822,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118272750000,11263,118272750000,RH_EXTIMU,2.29653627508e-06,1.53157082852e-05,-0.703299560508,0.710893612258,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.16234290569e-07,1.31055141993e-08,-7.20495074235e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244748907209,-0.000181876889748,9.80998852841,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118275250000,11264,118275250000,RH_EXTIMU,2.29662763877e-06,1.53156219445e-05,-0.703299624532,0.710893548918,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.01439432307e-07,2.96002562274e-09,-7.20488139651e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245346416571,-0.000180801272317,9.80999578129,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118279000000,11265,118277750000,RH_EXTIMU,2.29665075829e-06,1.53155941454e-05,-0.703299688555,0.710893485579,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.96900730145e-08,-2.14333655874e-09,-7.20480896956e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245332434046,-0.000179645705846,9.80999975981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118280250000,11266,118280250000,RH_EXTIMU,2.29666469036e-06,1.53155846832e-05,-0.703299752578,0.71089342224,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.41479829023e-08,3.11587432716e-09,-7.20472872119e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245303553759,-0.000179473568891,9.81001137997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118282750000,11267,118282750000,RH_EXTIMU,2.29659949771e-06,1.53156288579e-05,-0.7032998166,0.710893358902,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.10296317459e-08,-1.08987992275e-08,-7.20465134386e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245450082528,-0.00017832022622,9.81000469631,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118285250000,11268,118285250000,RH_EXTIMU,2.29659343403e-06,1.5315634369e-05,-0.703299880621,0.710893295565,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.64852441366e-09,3.8103384071e-10,-7.20457939969e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245265630354,-0.000179379674519,9.81000117256,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118287750000,11269,118287750000,RH_EXTIMU,2.2966548071e-06,1.53155897606e-05,-0.703299944641,0.710893232228,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.09030317174e-08,9.81987570421e-09,-7.20450901279e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245087414206,-0.000180611947825,9.8100008703,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118290250000,11270,118290250000,RH_EXTIMU,2.29670426584e-06,1.53155345192e-05,-0.703300008661,0.710893168892,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.01097124331e-08,-2.93074523711e-09,-7.20443879663e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245434307056,-0.000180271339319,9.8099986852,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118292750000,11271,118292750000,RH_EXTIMU,2.29673284905e-06,1.53155052708e-05,-0.70330007268,0.710893105557,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.36127584357e-08,1.06464382156e-10,-7.20436801518e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245274678933,-0.000179840785567,9.80999924936,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118295250000,11272,118295250000,RH_EXTIMU,2.29675358812e-06,1.53154860529e-05,-0.703300136699,0.710893042222,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.35080997034e-08,1.39753741529e-09,-7.20429638314e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245281967878,-0.000179689279532,9.80999981662,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118297750000,11273,118297750000,RH_EXTIMU,2.29685019739e-06,1.53155164254e-05,-0.703300200717,0.710892978888,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.87550491352e-08,7.22878865755e-08,-7.20422418879e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244018769597,-0.000179977300016,9.81000723618,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118300250000,11274,118300250000,RH_EXTIMU,2.29683557822e-06,1.53155466578e-05,-0.703300264734,0.710892915554,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.44233431429e-08,9.62661297642e-09,-7.20414869223e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245468426459,-0.000178894965288,9.81000196081,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118302750000,11275,118302750000,RH_EXTIMU,2.2969030706e-06,1.53155269109e-05,-0.70330032875,0.710892852222,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.03950178433e-08,2.7401933631e-08,-7.20407606341e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244534356412,-0.000180466862729,9.81000743082,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118305250000,11276,118305250000,RH_EXTIMU,2.29675771302e-06,1.53156271678e-05,-0.703300392766,0.710892788889,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.38174782364e-07,-2.41081444611e-08,-7.20399926944e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246402448752,-0.000176235354694,9.80999255601,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118307750000,11277,118307750000,RH_EXTIMU,2.29671834007e-06,1.53155387909e-05,-0.703300456782,0.710892725558,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.8233158564e-08,-7.17556665236e-08,-7.20392473987e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246165774649,-0.000180251247923,9.81000546676,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118310250000,11278,118310250000,RH_EXTIMU,2.29680074132e-06,1.53154708446e-05,-0.703300520796,0.710892662227,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.59927830339e-08,8.37858796919e-09,-7.20384849236e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244670136885,-0.00018129331168,9.81001133211,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118312750000,11279,118312750000,RH_EXTIMU,2.29670493451e-06,1.53155229833e-05,-0.70330058481,0.710892598897,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.29213244669e-08,-2.35944507043e-08,-7.20377561305e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246162193991,-0.000177129835432,9.8099907848,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118315250000,11280,118315250000,RH_EXTIMU,2.29687400923e-06,1.53154517154e-05,-0.703300648823,0.710892535567,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.37154064108e-07,5.52555315258e-08,-7.20372143591e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243864438056,-0.000182450704185,9.80999348435,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118317750000,11281,118317750000,RH_EXTIMU,2.29695463045e-06,1.53153930392e-05,-0.703300712836,0.710892472238,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.97647006491e-08,1.26490990275e-08,-7.20364633977e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245581418056,-0.000180323712323,9.81000038212,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118320250000,11282,118320250000,RH_EXTIMU,2.29685844683e-06,1.53153925919e-05,-0.703300776848,0.710892408909,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.35486417547e-08,-5.3712893316e-08,-7.20357322634e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246200190261,-0.000177967838184,9.80999268903,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118322750000,11283,118322750000,RH_EXTIMU,2.29688282178e-06,1.5315366731e-05,-0.70330084086,0.710892345581,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.93133875491e-08,-3.34783837383e-10,-7.20350880136e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245046852145,-0.000180041502404,9.80999537531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118325250000,11284,118325250000,RH_EXTIMU,2.29707820781e-06,1.53152524499e-05,-0.70330090487,0.710892282254,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.76318629507e-07,4.55971118002e-08,-7.20343114906e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244325254463,-0.00018293660317,9.81001933449,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118327750000,11285,118327750000,RH_EXTIMU,2.29691460341e-06,1.53153393463e-05,-0.70330096888,0.710892218928,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.41034895238e-07,-4.19730587742e-08,-7.20333534887e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246537966141,-0.000176019968235,9.81001524606,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118330250000,11286,118330250000,RH_EXTIMU,2.29683739991e-06,1.53154746992e-05,-0.70330103289,0.710892155602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.19161179442e-07,3.41975437642e-08,-7.20327627675e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244259095182,-0.000177722520258,9.80998922839,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118332750000,11287,118332750000,RH_EXTIMU,2.29691839547e-06,1.53153750925e-05,-0.703301096899,0.710892092277,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0300671805e-07,-1.04180376345e-08,-7.20320908954e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245852586944,-0.000181244554837,9.80999413298,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118335250000,11288,118335250000,RH_EXTIMU,2.29702873492e-06,1.53152377358e-05,-0.703301160907,0.710892028952,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.4093464306e-07,-1.5376883093e-08,-7.20313370899e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245546782509,-0.000181716929093,9.81000708,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118337750000,11289,118337750000,RH_EXTIMU,2.29690727289e-06,1.53152784803e-05,-0.703301224914,0.710891965628,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.11009919477e-08,-4.45093614634e-08,-7.20307385772e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245758746656,-0.000177529960755,9.80997743535,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118340250000,11290,118340250000,RH_EXTIMU,2.29716766168e-06,1.53151235397e-05,-0.703301288921,0.710891902304,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.36163130968e-07,5.90468435273e-08,-7.20301134822e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244181151556,-0.000183858327771,9.810001715,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118342750000,11291,118342750000,RH_EXTIMU,2.29708672293e-06,1.53150976599e-05,-0.703301352928,0.710891838981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.05693499646e-08,-5.95994270243e-08,-7.20292134691e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246748695237,-0.000177925983794,9.81001101134,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118345250000,11292,118345250000,RH_EXTIMU,2.29703764226e-06,1.5315151016e-05,-0.703301416933,0.710891775659,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.70325821453e-08,3.38770914342e-09,-7.20284357387e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244808679495,-0.000178633669777,9.81001128872,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118347750000,11293,118347750000,RH_EXTIMU,2.29682895193e-06,1.53152848294e-05,-0.703301480938,0.710891712338,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.93073384331e-07,-4.06580584685e-08,-7.202772701e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024652741742,-0.000175289840187,9.8099822123,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118351500000,11294,118350250000,RH_EXTIMU,2.29708895821e-06,1.53151616449e-05,-0.703301544942,0.710891649017,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.18078263107e-07,7.68918003316e-08,-7.202715001e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243480907878,-0.000184023261071,9.81000500716,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118352750000,11295,118352750000,RH_EXTIMU,2.29713285907e-06,1.53151303688e-05,-0.703301608946,0.710891585696,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.34648147323e-08,7.57144517685e-09,-7.20263628173e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245409803025,-0.000179872184694,9.810004054,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118355250000,11296,118355250000,RH_EXTIMU,2.29717939994e-06,1.53151409311e-05,-0.703301672949,0.710891522377,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.14261317473e-08,3.28509423978e-08,-7.20255792581e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244777538693,-0.000179584078063,9.81001164072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118357750000,11297,118357750000,RH_EXTIMU,2.29693746797e-06,1.53152342865e-05,-0.703301736951,0.710891459058,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.89215018154e-07,-8.23702788951e-08,-7.20248345738e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247250626271,-0.000175433032443,9.80998583536,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118360250000,11298,118360250000,RH_EXTIMU,2.29711829715e-06,1.53151237222e-05,-0.703301800953,0.710891395739,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.65948516373e-07,3.9520775609e-08,-7.20241915396e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243912895784,-0.000183011917424,9.81000812106,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118362750000,11299,118362750000,RH_EXTIMU,2.29712133108e-06,1.53151531115e-05,-0.703301864954,0.710891332422,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.39096911755e-08,1.90792417062e-08,-7.20234725571e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024504896608,-0.000178850809819,9.80999613464,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118365250000,11300,118365250000,RH_EXTIMU,2.29710779713e-06,1.53150990878e-05,-0.703301928955,0.710891269104,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.35995407472e-08,-3.76805823079e-08,-7.20227404374e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246124683244,-0.000179706751565,9.80999822589,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118367750000,11301,118367750000,RH_EXTIMU,2.29731849491e-06,1.53151104257e-05,-0.703301992954,0.710891205788,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.14347914728e-07,1.25653449018e-07,-7.20221024041e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242837982861,-0.000181440426918,9.81000517731,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118370250000,11302,118370250000,RH_EXTIMU,2.29728884234e-06,1.53151134245e-05,-0.703302056954,0.710891142472,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.76505836123e-08,-1.43201554653e-08,-7.20213826017e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246056821977,-0.000178864583989,9.80999238221,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118372750000,11303,118372750000,RH_EXTIMU,2.297224263e-06,1.53150597585e-05,-0.703302120952,0.710891079157,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.63191995011e-09,-6.61974236528e-08,-7.20206776878e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246628977274,-0.000178897330424,9.80999186816,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118376500000,11304,118375250000,RH_EXTIMU,2.29728479442e-06,1.53149234235e-05,-0.70330218495,0.710891015842,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12033245584e-07,-4.28198745927e-08,-7.20199455261e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245507170473,-0.000181727057179,9.81000752958,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118377750000,11305,118377750000,RH_EXTIMU,2.29716906213e-06,1.53149536227e-05,-0.703302248947,0.710890952528,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.1909356676e-08,-4.7283009795e-08,-7.20191183856e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246138427965,-0.000177260897142,9.81000137083,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118380250000,11306,118380250000,RH_EXTIMU,2.29720447179e-06,1.53149535458e-05,-0.703302312944,0.710890889214,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.10816595926e-08,2.05372990969e-08,-7.20185209504e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244719485611,-0.000179964438403,9.8099920058,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118382750000,11307,118382750000,RH_EXTIMU,2.29727936307e-06,1.53149421752e-05,-0.70330237694,0.710890825901,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.98896313777e-08,3.63284552894e-08,-7.20178695593e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244717017091,-0.000180083606432,9.80999274519,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118385250000,11308,118385250000,RH_EXTIMU,2.29742177536e-06,1.53148570339e-05,-0.703302440935,0.710890762589,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.29796158181e-07,3.23642823329e-08,-7.20171404475e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244891769814,-0.000181832078653,9.81000983832,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118387750000,11309,118387750000,RH_EXTIMU,2.29732912314e-06,1.53149402915e-05,-0.70330250493,0.710890699278,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.86362970567e-08,-4.1222985011e-09,-7.20162487998e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245475468458,-0.000177025948651,9.81001328774,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118390250000,11310,118390250000,RH_EXTIMU,2.29722730817e-06,1.53149716598e-05,-0.703302568924,0.710890635967,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.46521546121e-08,-3.87877774331e-08,-7.20156489778e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245878355765,-0.000178435966681,9.80998143376,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118392750000,11311,118392750000,RH_EXTIMU,2.29731056875e-06,1.53147876828e-05,-0.703302632918,0.710890572656,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.51764927867e-07,-5.71260433994e-08,-7.20150210056e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246315653872,-0.000181958326003,9.80998850658,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118395250000,11312,118395250000,RH_EXTIMU,2.29752457596e-06,1.53146954884e-05,-0.70330269691,0.710890509346,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.74481378703e-07,6.86354299347e-08,-7.20142098753e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243946865669,-0.000182080207042,9.81002351759,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118397750000,11313,118397750000,RH_EXTIMU,2.29733992192e-06,1.53148258664e-05,-0.703302760902,0.710890446037,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.77470817998e-07,-2.90885397075e-08,-7.2013363071e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245933990447,-0.000176016222997,9.81000586635,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118400250000,11314,118400250000,RH_EXTIMU,2.29728272043e-06,1.53148836739e-05,-0.703302824894,0.710890382729,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.41557302096e-08,1.34987552092e-09,-7.20126559359e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245203743075,-0.000178379225345,9.8099987066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118402750000,11315,118402750000,RH_EXTIMU,2.29745264328e-06,1.53148393157e-05,-0.703302888885,0.710890319421,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22495326535e-07,7.10367990141e-08,-7.20120138187e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243821937946,-0.000182053322903,9.81000212815,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118405250000,11316,118405250000,RH_EXTIMU,2.29752265881e-06,1.53148479213e-05,-0.703302952875,0.710890256114,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.58771766004e-08,4.49458244015e-08,-7.20113287623e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244984500734,-0.000179448196615,9.80999343574,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118407750000,11317,118407750000,RH_EXTIMU,2.29757891849e-06,1.53148017047e-05,-0.703303016864,0.710890192807,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.88993363032e-08,6.02814787819e-09,-7.20106960689e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245485514873,-0.000180337880343,9.80999229179,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118410250000,11318,118410250000,RH_EXTIMU,2.29758479213e-06,1.53147031141e-05,-0.703303080853,0.710890129501,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.97120221686e-08,-5.21069378188e-08,-7.20098321415e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246186536703,-0.000180192401036,9.81001429041,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118412750000,11319,118412750000,RH_EXTIMU,2.29734073047e-06,1.53147372445e-05,-0.703303144841,0.710890066196,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.57103683204e-07,-1.17251114174e-07,-7.20090861328e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246996611364,-0.000176467553441,9.80999068156,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118415250000,11320,118415250000,RH_EXTIMU,2.2973594195e-06,1.53146580945e-05,-0.703303208829,0.710890002891,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.60621079505e-08,-3.38402889488e-08,-7.20084858196e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245559894714,-0.000180505593988,9.80998728982,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118417750000,11321,118417750000,RH_EXTIMU,2.29750861102e-06,1.53145558754e-05,-0.703303272816,0.710889939587,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.43260150776e-07,2.64662303072e-08,-7.20078161308e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244635968413,-0.000181785499324,9.81000085064,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118420250000,11322,118420250000,RH_EXTIMU,2.297628206e-06,1.53145735535e-05,-0.703303336802,0.710889876284,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.89689157589e-08,7.80009622038e-08,-7.20070513869e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243901159533,-0.00018025384162,9.81001097055,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118422750000,11323,118422750000,RH_EXTIMU,2.29762118911e-06,1.53146635005e-05,-0.703303400788,0.710889812981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.36983068673e-08,4.78638639271e-08,-7.20062705868e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245044826066,-0.000178071107023,9.81000741844,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118425250000,11324,118425250000,RH_EXTIMU,2.29756083755e-06,1.53146975984e-05,-0.703303464773,0.710889749679,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.26073183641e-08,-1.39065227016e-08,-7.20055405977e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245600898478,-0.00017859062772,9.80999826609,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118427750000,11325,118427750000,RH_EXTIMU,2.29758795189e-06,1.53146180992e-05,-0.703303528758,0.710889686377,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.10501525045e-08,-2.92984730022e-08,-7.20048505704e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245899622751,-0.000180540511941,9.80999618787,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118430250000,11326,118430250000,RH_EXTIMU,2.29763539233e-06,1.53145165306e-05,-0.703303592741,0.710889623076,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.50270359387e-08,-3.04132957007e-08,-7.20041450865e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245496626757,-0.00018069516055,9.8100014385,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118430250000,11327,118432750000,RH_EXTIMU,2.29758272422e-06,1.53146009187e-05,-0.703303656724,0.710889559776,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.65330733794e-08,1.90170712502e-08,-7.20033941606e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245018938019,-0.000177598380344,9.80999854343,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118430250000,11328,118435250000,RH_EXTIMU,2.29763855299e-06,1.53145758371e-05,-0.703303720707,0.710889496476,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.67627320131e-08,1.78053651818e-08,-7.20027866879e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245030435349,-0.000180357583015,9.80998980383,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118437750000,11329,118437750000,RH_EXTIMU,2.29769334261e-06,1.531451353e-05,-0.703303784689,0.710889433177,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.71163865056e-08,-3.94986724905e-09,-7.200212769e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245496342398,-0.000180274620909,9.80999318377,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118440250000,11330,118440250000,RH_EXTIMU,2.2976969468e-06,1.53144579033e-05,-0.70330384867,0.710889369878,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.42479077871e-08,-2.89497435644e-08,-7.20013542803e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245738598237,-0.000179867645482,9.81000455243,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118442750000,11331,118442750000,RH_EXTIMU,2.29762950522e-06,1.53144468892e-05,-0.703303912651,0.710889306581,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.12575900276e-08,-4.3551479874e-08,-7.20005588758e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245960347987,-0.000178578951806,9.81000483426,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118445250000,11332,118445250000,RH_EXTIMU,2.2977420542e-06,1.53144545523e-05,-0.703303976631,0.710889243283,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.05965403993e-08,6.8340851425e-08,-7.19998718181e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024357510954,-0.000180818834255,9.81000646852,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118449000000,11333,118447750000,RH_EXTIMU,2.29786554059e-06,1.53145024339e-05,-0.70330404061,0.710889179987,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.41880335326e-08,9.73674968749e-08,-7.19991879514e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244194728948,-0.000179899402569,9.81000107443,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118454000000,11334,118450250000,RH_EXTIMU,2.29786980768e-06,1.53144846575e-05,-0.703304104588,0.710889116691,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.33287075911e-08,-7.05092116484e-09,-7.19984456252e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245872015512,-0.000179479268711,9.81000081948,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118454000000,11335,118452750000,RH_EXTIMU,2.29781343838e-06,1.5314441893e-05,-0.703304168566,0.710889053395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.09648033192e-09,-5.53786394345e-08,-7.19976773551e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246101297936,-0.000179138957373,9.81000180296,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118455250000,11336,118455250000,RH_EXTIMU,2.29785688127e-06,1.53144281368e-05,-0.703304232544,0.710888990101,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.334644353e-08,1.72774225514e-08,-7.19969687168e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244798120207,-0.000179960850674,9.81000307713,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118457750000,11337,118457750000,RH_EXTIMU,2.29779443624e-06,1.5314425503e-05,-0.70330429652,0.710888926807,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.31311064718e-08,-3.59743350329e-08,-7.19962476285e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246218662097,-0.000178497003377,9.80999327311,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118460250000,11338,118460250000,RH_EXTIMU,2.29782087292e-06,1.53143201396e-05,-0.703304360497,0.710888863513,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.52170022881e-08,-4.43890641636e-08,-7.19955913154e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245726399633,-0.000180852408431,9.80999380741,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118462750000,11339,118462750000,RH_EXTIMU,2.29785978596e-06,1.53142980721e-05,-0.703304424472,0.71088880022,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.54465508996e-08,1.00019643488e-08,-7.19948843592e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244965029843,-0.000179659980738,9.81000001381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118465250000,11340,118465250000,RH_EXTIMU,2.2978701852e-06,1.53143088759e-05,-0.703304488447,0.710888736928,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.35597594879e-10,1.26531259349e-08,-7.19941512129e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245152958118,-0.000179244407712,9.81000118147,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118467750000,11341,118467750000,RH_EXTIMU,2.29793408117e-06,1.53142683218e-05,-0.703304552421,0.710888673636,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.00559708002e-08,1.35449032976e-08,-7.19933239803e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245219433401,-0.000180384078403,9.81001698925,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118470250000,11342,118470250000,RH_EXTIMU,2.29763556345e-06,1.53143581595e-05,-0.703304616394,0.710888610345,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.19416813146e-07,-1.16209591112e-07,-7.19925334796e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247713224344,-0.000174842591132,9.80998968098,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118472750000,11343,118472750000,RH_EXTIMU,2.29762454737e-06,1.53142396302e-05,-0.703304680367,0.710888547055,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.13248934824e-08,-7.2949210782e-08,-7.19919334632e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245710216623,-0.000181168425078,9.80998986224,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118475250000,11344,118475250000,RH_EXTIMU,2.29802899009e-06,1.53142154701e-05,-0.703304744339,0.710888483765,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.44504597908e-07,2.14474816687e-07,-7.19912167398e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000241368876447,-0.000183529629143,9.81002497082,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118477750000,11345,118477750000,RH_EXTIMU,2.29774741947e-06,1.53143274179e-05,-0.703304808311,0.710888420476,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.22218898358e-07,-9.41002585882e-08,-7.19904836256e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247566873087,-0.000175149021475,9.80997780393,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118480250000,11346,118480250000,RH_EXTIMU,2.29798875764e-06,1.53141426883e-05,-0.703304872282,0.710888357188,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.42088669067e-07,3.13874996566e-08,-7.19899174943e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244371924291,-0.000184043828791,9.80999576754,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118482750000,11347,118482750000,RH_EXTIMU,2.29812282047e-06,1.53140913387e-05,-0.703304936252,0.7108882939,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.06034559224e-07,4.68843337375e-08,-7.19891855361e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244587335786,-0.00018073362525,9.81000639375,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118485250000,11348,118485250000,RH_EXTIMU,2.29787920782e-06,1.53142344503e-05,-0.703305000222,0.710888230613,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.18165913975e-07,-5.50203566967e-08,-7.19883584954e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002469140934,-0.000174533797668,9.8099941555,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118487750000,11349,118487750000,RH_EXTIMU,2.29792794306e-06,1.53141367742e-05,-0.703305064191,0.710888167326,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.35731603893e-08,-2.74710803779e-08,-7.19877175464e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245087002873,-0.000181809566033,9.81000072311,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118490250000,11350,118490250000,RH_EXTIMU,2.29794975655e-06,1.53140864369e-05,-0.703305128159,0.71088810404,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.1627569556e-08,-1.56963633274e-08,-7.19869184015e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245575249481,-0.00017968810747,9.8100061752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118492750000,11351,118492750000,RH_EXTIMU,2.29794462272e-06,1.53141153171e-05,-0.703305192127,0.710888040755,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.8268873383e-08,1.41936404711e-08,-7.19861802296e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244993985017,-0.000178918081433,9.81000462457,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118495250000,11352,118495250000,RH_EXTIMU,2.29806010011e-06,1.53141722086e-05,-0.703305256094,0.71088797747,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.45635210838e-08,9.79852204093e-08,-7.19854620124e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243669702038,-0.000180033465509,9.81000889144,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118497750000,11353,118497750000,RH_EXTIMU,2.29791565082e-06,1.53142320003e-05,-0.70330532006,0.710887914186,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.14891254061e-07,-4.66116786436e-08,-7.19847290928e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246804782722,-0.000176860869076,9.80998809959,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118501500000,11354,118500250000,RH_EXTIMU,2.29803393919e-06,1.53140512746e-05,-0.703305384026,0.710887850902,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.69856102448e-07,-3.55685804809e-08,-7.19841216654e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245265473779,-0.000183105341117,9.80999632148,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118501500000,11355,118502750000,RH_EXTIMU,2.29807066846e-06,1.53139832226e-05,-0.703305447991,0.71088778762,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.00773574858e-08,-1.73786360329e-08,-7.19833330821e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245585786318,-0.000179764806985,9.81000624401,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118501500000,11356,118505250000,RH_EXTIMU,2.2980764256e-06,1.53140328485e-05,-0.703305511955,0.710887724337,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.3747561416e-08,3.2119623691e-08,-7.19825267137e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024460366892,-0.000178987919978,9.81001441813,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118507750000,11357,118507750000,RH_EXTIMU,2.29801821787e-06,1.53141036054e-05,-0.703305575919,0.710887661056,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.20143663837e-08,8.14763379734e-09,-7.19817557755e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245402788246,-0.000177961864172,9.81000093957,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118510250000,11358,118510250000,RH_EXTIMU,2.29806198359e-06,1.5314071017e-05,-0.703305639882,0.710887597775,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.41256640023e-08,6.74886023764e-09,-7.1981165931e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245234735356,-0.000180202294002,9.8099891025,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118512750000,11359,118512750000,RH_EXTIMU,2.2980727639e-06,1.53140437409e-05,-0.703305703845,0.710887534495,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.23776104461e-08,-8.78906736868e-09,-7.19805238343e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245507525941,-0.000179424497538,9.80998637124,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118515250000,11360,118515250000,RH_EXTIMU,2.29816347994e-06,1.53139334904e-05,-0.703305767807,0.710887471215,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.14522874878e-07,-1.100197592e-08,-7.19798953579e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245394683863,-0.000181404140991,9.80999146797,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118517750000,11361,118517750000,RH_EXTIMU,2.29822593088e-06,1.53138530551e-05,-0.703305831768,0.710887407936,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.16729348623e-08,-9.94905790035e-09,-7.19791522883e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245333254287,-0.000180505462484,9.81000402535,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118520250000,11362,118520250000,RH_EXTIMU,2.29816571232e-06,1.53139061956e-05,-0.703305895729,0.710887344657,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.32461831353e-08,-3.00249390249e-09,-7.19783401277e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245405912924,-0.000177876117986,9.8100071924,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118522750000,11363,118522750000,RH_EXTIMU,2.29814985812e-06,1.53139085559e-05,-0.703305959688,0.710887281379,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.44455725567e-09,-6.92029316271e-09,-7.19775598482e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245459213313,-0.000179322062323,9.8100087216,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118525250000,11364,118525250000,RH_EXTIMU,2.29812258416e-06,1.53139128136e-05,-0.703306023648,0.710887218102,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.70066176574e-08,-1.22665380873e-08,-7.19768164723e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245438907381,-0.000179091791602,9.81000301934,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118527750000,11365,118527750000,RH_EXTIMU,2.29811655013e-06,1.53139058965e-05,-0.703306087606,0.710887154826,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.36014180073e-09,-6.67120937426e-09,-7.19761253598e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245350928201,-0.000179385675741,9.80999655156,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118531500000,11366,118530250000,RH_EXTIMU,2.29829529112e-06,1.53139115111e-05,-0.703306151564,0.71088709155,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.93926403595e-08,1.0441836231e-07,-7.19754713206e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243420570285,-0.000181106654628,9.81000359945,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118532750000,11367,118532750000,RH_EXTIMU,2.2981906813e-06,1.53138804268e-05,-0.703306215522,0.710887028274,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.11033279378e-08,-7.58785029485e-08,-7.19747644179e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247121936874,-0.000178340919529,9.80998530577,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118535250000,11368,118535250000,RH_EXTIMU,2.29838413565e-06,1.53137457144e-05,-0.703306279479,0.710886964999,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.86714483703e-07,3.28914753744e-08,-7.19741086829e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243967752398,-0.000183016850195,9.81000616483,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118537750000,11369,118537750000,RH_EXTIMU,2.29827437567e-06,1.53138171503e-05,-0.703306343435,0.710886901725,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.01714722814e-07,-2.047206687e-08,-7.19733353805e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246134550589,-0.000176745022673,9.80999517789,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118540250000,11370,118540250000,RH_EXTIMU,2.29828677322e-06,1.53138112713e-05,-0.70330640739,0.710886838452,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12582484408e-08,4.28956619461e-09,-7.19726380402e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245171425881,-0.000179624532321,9.81000000659,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118542750000,11371,118542750000,RH_EXTIMU,2.29838457314e-06,1.5313748428e-05,-0.703306471345,0.710886775179,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.18780329211e-08,1.99446644857e-08,-7.19719431255e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244993010961,-0.000181024778162,9.81000076712,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118545250000,11372,118545250000,RH_EXTIMU,2.29837732454e-06,1.53136807979e-05,-0.703306535299,0.710886711907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.48292719876e-08,-4.18827338679e-08,-7.19711962832e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024587396203,-0.000179956459845,9.81000123768,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118547750000,11373,118547750000,RH_EXTIMU,2.29841794656e-06,1.53137133377e-05,-0.703306599253,0.710886648635,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.69360997786e-09,4.20189984004e-08,-7.19704705929e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244587741659,-0.000179100204225,9.81000435694,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118550250000,11374,118550250000,RH_EXTIMU,2.29835866041e-06,1.53137776795e-05,-0.703306663206,0.710886585364,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.90184053377e-08,3.89227851323e-09,-7.19697500004e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245514746739,-0.000177861104226,9.80999588554,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118552750000,11375,118552750000,RH_EXTIMU,2.29857513226e-06,1.53136933414e-05,-0.703306727158,0.710886522094,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.71461808179e-07,7.44905479253e-08,-7.19690455083e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243506124291,-0.000183207539998,9.8100162791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118555250000,11376,118555250000,RH_EXTIMU,2.29831940106e-06,1.5313826931e-05,-0.70330679111,0.710886458824,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.19700427756e-07,-6.72548425635e-08,-7.19681571715e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247609381465,-0.00017405210554,9.8099952123,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118557750000,11377,118557750000,RH_EXTIMU,2.29829613858e-06,1.53137455835e-05,-0.703306855061,0.710886395555,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.34400057316e-08,-5.86940641144e-08,-7.19676045915e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245541529804,-0.000180718388885,9.80998706557,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118560250000,11378,118560250000,RH_EXTIMU,2.29846561551e-06,1.53136372664e-05,-0.703306919011,0.710886332286,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.58226973031e-07,3.4412045519e-08,-7.1966941827e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244393739344,-0.00018219602755,9.80999901763,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118564000000,11379,118562750000,RH_EXTIMU,2.29868313937e-06,1.53135549669e-05,-0.703306982961,0.710886269018,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.70912999775e-07,7.62418640891e-08,-7.19661773972e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243990170485,-0.000182382239416,9.81001810308,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118565250000,11380,118565250000,RH_EXTIMU,2.29839670596e-06,1.53137392143e-05,-0.70330704691,0.710886205751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.65663470569e-07,-5.5719866535e-08,-7.19652824663e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247173249735,-0.000173367865894,9.80999769245,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118567750000,11381,118567750000,RH_EXTIMU,2.29846871625e-06,1.53136652037e-05,-0.703307110858,0.710886142485,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.34944329949e-08,-9.16751678174e-10,-7.19647884926e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244628845382,-0.000181917511131,9.80998514973,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118570250000,11382,118570250000,RH_EXTIMU,2.29860105202e-06,1.53135510696e-05,-0.703307174806,0.710886079219,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.40377312524e-07,1.02065894621e-08,-7.19641466718e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245229153596,-0.000181370717918,9.80999106945,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118572750000,11383,118572750000,RH_EXTIMU,2.29864472509e-06,1.53134814913e-05,-0.703307238753,0.710886015953,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.488494444e-08,-1.43398661856e-08,-7.19633853461e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245649156764,-0.000180235693037,9.81000595613,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118575250000,11384,118575250000,RH_EXTIMU,2.29843525828e-06,1.53135401087e-05,-0.7033073027,0.710885952688,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.51206708922e-07,-8.3861945454e-08,-7.19625340002e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246767681266,-0.000176046941941,9.8100003918,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118577750000,11385,118577750000,RH_EXTIMU,2.29856973491e-06,1.5313483661e-05,-0.703307366645,0.710885889424,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0913778224e-07,4.42179041696e-08,-7.19618060479e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244208452927,-0.000181812181409,9.81001627228,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118580250000,11386,118580250000,RH_EXTIMU,2.29851722343e-06,1.53135291027e-05,-0.703307430591,0.710885826161,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.45315571127e-08,-3.04489074357e-09,-7.19611151684e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245350620972,-0.00017832854179,9.80999203723,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118582750000,11387,118582750000,RH_EXTIMU,2.29866182111e-06,1.53134639416e-05,-0.703307494535,0.710885762898,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.19796240464e-07,4.49570954562e-08,-7.19604435764e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024444772038,-0.000181618267906,9.81000361412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118585250000,11388,118585250000,RH_EXTIMU,2.29851115606e-06,1.53134837211e-05,-0.703307558479,0.710885699636,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.59136286663e-08,-7.28649296074e-08,-7.19596511235e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247266612801,-0.000176864476755,9.80999194005,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118587750000,11389,118587750000,RH_EXTIMU,2.29854788036e-06,1.53133564971e-05,-0.703307622422,0.710885636374,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.3367177389e-08,-5.10331673398e-08,-7.19590428375e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245315315719,-0.000181426746934,9.80999372524,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118590250000,11390,118590250000,RH_EXTIMU,2.29863457937e-06,1.53133483355e-05,-0.703307686365,0.710885573113,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.47981893739e-08,4.47967441272e-08,-7.1958322153e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244545094786,-0.000180015661254,9.81000287432,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118592750000,11391,118592750000,RH_EXTIMU,2.29866617634e-06,1.53133390967e-05,-0.703307750307,0.710885509853,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.40673431488e-08,1.3181079083e-08,-7.19575319412e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245291140023,-0.000179587595425,9.81000850355,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118595250000,11392,118595250000,RH_EXTIMU,2.29870353046e-06,1.53133189932e-05,-0.703307814248,0.710885446593,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.34544023606e-08,1.02415340809e-08,-7.19567669657e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245148003989,-0.00018001817734,9.8100087413,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118597750000,11393,118597750000,RH_EXTIMU,2.29862435097e-06,1.5313377844e-05,-0.703307878189,0.710885383334,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.72425682484e-08,-1.04237337883e-08,-7.19560530907e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245386984878,-0.000177844656161,9.8099967776,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118600250000,11394,118600250000,RH_EXTIMU,2.29867754397e-06,1.53133896416e-05,-0.703307942129,0.710885320075,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.45130507789e-08,3.72956342867e-08,-7.19553627495e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244593153189,-0.000179790379258,9.81000093551,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118602750000,11395,118602750000,RH_EXTIMU,2.29856603335e-06,1.53134355445e-05,-0.703308006068,0.710885256818,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.83444584957e-08,-3.5978331218e-08,-7.1954647761e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246472692743,-0.000177260420551,9.80998726821,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118605250000,11396,118605250000,RH_EXTIMU,2.2988351552e-06,1.531322149e-05,-0.703308070007,0.71088519356,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.7438840806e-07,3.03432703646e-08,-7.19540274091e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243900261899,-0.000185235937118,9.81001066336,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118607750000,11397,118607750000,RH_EXTIMU,2.29870186239e-06,1.53133351833e-05,-0.703308133945,0.710885130304,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.38874266038e-07,-9.68103211183e-09,-7.19532445856e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245893010737,-0.000175743296254,9.80999083851,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118610250000,11398,118610250000,RH_EXTIMU,2.29870018804e-06,1.53133300585e-05,-0.703308197883,0.710885067048,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.83085153301e-09,-3.19924869938e-09,-7.19526076562e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245559582096,-0.000179339954601,9.80998970981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118612750000,11399,118612750000,RH_EXTIMU,2.29902682373e-06,1.53132095657e-05,-0.70330826182,0.710885003792,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.54454811859e-07,1.15912553232e-07,-7.19518566508e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243199244619,-0.000184024654843,9.81002410934,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118615250000,11400,118615250000,RH_EXTIMU,2.29865563073e-06,1.5313251597e-05,-0.703308325756,0.710884940537,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.33849635509e-07,-1.84289601244e-07,-7.19510458435e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000248766295482,-0.000174788895277,9.80998370048,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118617750000,11401,118617750000,RH_EXTIMU,2.29870670094e-06,1.53131786434e-05,-0.703308389691,0.710884877283,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.09907427553e-08,-1.20975250323e-08,-7.19504418922e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244778633486,-0.000180700269656,9.80999365735,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118620250000,11402,118620250000,RH_EXTIMU,2.29880698735e-06,1.53131495201e-05,-0.703308453626,0.71088481403,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.43193432023e-08,4.05205096016e-08,-7.19498104984e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244691867085,-0.000180492997048,9.80999223842,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118622750000,11403,118622750000,RH_EXTIMU,2.29889776638e-06,1.5313119991e-05,-0.703308517561,0.710884750777,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.91407773684e-08,3.49403693496e-08,-7.19490288186e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244891404741,-0.000180237237009,9.81001075629,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118625250000,11404,118625250000,RH_EXTIMU,2.29875815354e-06,1.53131756586e-05,-0.703308581494,0.710884687524,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.09820605616e-07,-4.623678149e-08,-7.19482110391e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246496141071,-0.000176918394826,9.81000008753,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118627750000,11405,118627750000,RH_EXTIMU,2.29880007896e-06,1.53130899821e-05,-0.703308645427,0.710884624273,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.29484612758e-08,-2.44783955294e-08,-7.19476368919e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245169245203,-0.000181262324935,9.80998992623,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118630250000,11406,118630250000,RH_EXTIMU,2.29902683977e-06,1.53129569881e-05,-0.70330870936,0.710884561022,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0468884077e-07,5.26088113902e-08,-7.19469276307e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244121105502,-0.000183094475655,9.81001123736,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118632750000,11407,118632750000,RH_EXTIMU,2.29895302205e-06,1.5313042344e-05,-0.703308773292,0.710884497771,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.91064248241e-08,7.66649171451e-09,-7.19460297676e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245634577052,-0.000176969021046,9.81001327649,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118635250000,11408,118635250000,RH_EXTIMU,2.29880865281e-06,1.53131146298e-05,-0.703308837223,0.710884434521,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.21875795948e-07,-3.94621495667e-08,-7.19453096114e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245916926444,-0.000177382545382,9.80999603076,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118637750000,11409,118637750000,RH_EXTIMU,2.29901128518e-06,1.53130561542e-05,-0.703308901153,0.710884371272,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.49039223005e-07,8.14122179179e-08,-7.19446807278e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243777686295,-0.000182253175307,9.81000219259,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118640250000,11410,118640250000,RH_EXTIMU,2.29908024294e-06,1.53130328358e-05,-0.703308965083,0.710884308024,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.32362879161e-08,2.61948134098e-08,-7.19439766912e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245095539756,-0.000180029738817,9.80999830041,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118642750000,11411,118642750000,RH_EXTIMU,2.29902770854e-06,1.53130393174e-05,-0.703309029012,0.710884244776,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.26240804563e-08,-2.52149641296e-08,-7.19432574818e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245962408828,-0.000178323756051,9.80999474626,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118645250000,11412,118645250000,RH_EXTIMU,2.2988751021e-06,1.53130371917e-05,-0.703309092941,0.710884181528,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.46928609969e-08,-8.64153127537e-08,-7.19425710457e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246897145429,-0.000177494859289,9.80998406191,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118647750000,11413,118647750000,RH_EXTIMU,2.29916984533e-06,1.53128256046e-05,-0.703309156868,0.710884118282,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.87570980908e-07,4.61625928234e-08,-7.19419418422e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243354739118,-0.000185469464098,9.81001309394,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118650250000,11414,118650250000,RH_EXTIMU,2.29911805827e-06,1.5312946578e-05,-0.703309220796,0.710884055036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.66175692438e-08,4.03177917063e-08,-7.19409891947e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245371516886,-0.000176384824486,9.81001784435,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118652750000,11415,118652750000,RH_EXTIMU,2.29890414181e-06,1.53130978521e-05,-0.703309284722,0.710883991791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.0587036584e-07,-3.36716647937e-08,-7.1940182588e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245907387819,-0.000175836316243,9.81000600444,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118655250000,11416,118655250000,RH_EXTIMU,2.2988749688e-06,1.53130299882e-05,-0.703309348648,0.710883928546,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.24919768595e-08,-5.43515897948e-08,-7.19396195277e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246130296027,-0.000180280441315,9.80997799013,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118661500000,11417,118657750000,RH_EXTIMU,2.29908940474e-06,1.53128760214e-05,-0.703309412573,0.710883865302,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.09479709292e-07,3.37470201725e-08,-7.19389711333e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244578739262,-0.000182704828472,9.81000194886,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118661500000,11418,118660250000,RH_EXTIMU,2.29909912736e-06,1.53128592321e-05,-0.703309476498,0.710883802058,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.58752030459e-08,-3.42060893449e-09,-7.19382755465e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245385063168,-0.000179432862742,9.80999337583,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118661500000,11419,118662750000,RH_EXTIMU,2.29921664753e-06,1.53127986332e-05,-0.703309540422,0.710883738815,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.01829763863e-07,3.23166036539e-08,-7.1937555008e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244568438153,-0.000181004183896,9.81000725224,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118661500000,11420,118665250000,RH_EXTIMU,2.29917730888e-06,1.5312870676e-05,-0.703309604345,0.710883675573,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.20074855847e-08,1.9494616135e-08,-7.19367297615e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245394735887,-0.000177875305666,9.81000915838,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118667750000,11421,118667750000,RH_EXTIMU,2.29896494013e-06,1.53129258864e-05,-0.703309668268,0.710883612331,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.50940178936e-07,-8.74331027454e-08,-7.19359889734e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247012607298,-0.000176267007268,9.80998901342,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118670250000,11422,118670250000,RH_EXTIMU,2.29919255447e-06,1.53128014245e-05,-0.70330973219,0.71088354909,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.00373422498e-07,5.79415168307e-08,-7.19354335452e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243346905336,-0.000183884185458,9.81000023882,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118672750000,11423,118672750000,RH_EXTIMU,2.29923916111e-06,1.53128077381e-05,-0.703309796112,0.71088348585,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.38525605871e-08,3.04708418743e-08,-7.19346630986e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245503786814,-0.000178814828598,9.80999979327,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118675250000,11424,118675250000,RH_EXTIMU,2.29923471127e-06,1.5312764819e-05,-0.703309860032,0.71088342261,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.25170848285e-08,-2.6254982018e-08,-7.19338557054e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245779595116,-0.000179759613687,9.81001191086,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118677750000,11425,118677750000,RH_EXTIMU,2.29912824659e-06,1.53128020715e-05,-0.703309923952,0.710883359371,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.0607905792e-08,-3.80592278756e-08,-7.19330980677e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245839467145,-0.000177771413483,9.80999960246,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118680250000,11426,118680250000,RH_EXTIMU,2.2991662983e-06,1.53128043187e-05,-0.703309987872,0.710883296132,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.12752539542e-08,2.33448061733e-08,-7.1932466732e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244612009756,-0.00017983305996,9.80999394363,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118682750000,11427,118682750000,RH_EXTIMU,2.29924074293e-06,1.53128053902e-05,-0.703310051791,0.710883232894,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.26335981663e-08,4.3152627001e-08,-7.19318332911e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244768445058,-0.000179883081963,9.80999072663,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118685250000,11428,118685250000,RH_EXTIMU,2.29936116261e-06,1.53126897015e-05,-0.703310115709,0.710883169657,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34474821628e-07,2.61806617434e-09,-7.19311254302e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245382922668,-0.000181828990045,9.81000483571,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118687750000,11429,118687750000,RH_EXTIMU,2.29927620918e-06,1.53126954019e-05,-0.703310179627,0.71088310642,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.06215894418e-08,-4.38999205258e-08,-7.19302589596e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245942755598,-0.000177935228854,9.81000853403,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118690250000,11430,118690250000,RH_EXTIMU,2.29927527673e-06,1.53127369054e-05,-0.703310243543,0.710883043184,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.29828522809e-08,2.37357526442e-08,-7.19295858935e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244823305112,-0.000178990446073,9.80999911515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118692750000,11431,118692750000,RH_EXTIMU,2.29935809042e-06,1.53127156701e-05,-0.70331030746,0.710882979949,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.99440021516e-08,3.51753724292e-08,-7.19288877291e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244668184993,-0.000180520321999,9.81000274747,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118695250000,11432,118695250000,RH_EXTIMU,2.29923880519e-06,1.53127584195e-05,-0.703310371375,0.710882916714,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.09918258608e-08,-4.21467275018e-08,-7.19281481463e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024651220972,-0.000177083658028,9.80998912545,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118697750000,11433,118697750000,RH_EXTIMU,2.29924430517e-06,1.5312647216e-05,-0.70331043529,0.71088285348,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.65956169069e-08,-5.94905032546e-08,-7.19275694914e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246046927973,-0.000180670959335,9.80998570554,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118700250000,11434,118700250000,RH_EXTIMU,2.29941291698e-06,1.53124929651e-05,-0.703310499205,0.710882790246,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.83578852151e-07,7.80277574962e-09,-7.19267807576e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244964339537,-0.000182482852085,9.81001395734,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118702750000,11435,118702750000,RH_EXTIMU,2.29927520847e-06,1.53125606677e-05,-0.703310563119,0.710882727013,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.15509171908e-07,-3.83215579709e-08,-7.19260086851e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245928307624,-0.000176750800242,9.80999751772,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118705250000,11436,118705250000,RH_EXTIMU,2.29930126177e-06,1.53125639959e-05,-0.703310627032,0.710882663781,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.38433082481e-08,1.72086588609e-08,-7.19253813684e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244828819816,-0.000179882594748,9.80999317854,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118707750000,11437,118707750000,RH_EXTIMU,2.29947816355e-06,1.53124821305e-05,-0.703310690944,0.710882600549,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.4756580996e-07,5.36332043148e-08,-7.19247017937e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244154345352,-0.000182071640268,9.81000589296,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118710250000,11438,118710250000,RH_EXTIMU,2.29950496901e-06,1.5312544037e-05,-0.703310754856,0.710882537318,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.86879367779e-08,5.09456546395e-08,-7.19238703722e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244796746332,-0.00017860858891,9.81001154405,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118712750000,11439,118712750000,RH_EXTIMU,2.29937609166e-06,1.5312608721e-05,-0.703310818767,0.710882474088,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.08788436929e-07,-3.50694950528e-08,-7.19231379703e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246283696347,-0.000177035094614,9.80999357604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118715250000,11440,118715250000,RH_EXTIMU,2.29940686723e-06,1.53125559376e-05,-0.703310882678,0.710882410858,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.80999657249e-08,-1.20453719122e-08,-7.1922524785e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245188377956,-0.000180508024905,9.80999165939,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118717750000,11441,118717750000,RH_EXTIMU,2.29960567145e-06,1.53124368337e-05,-0.703310946588,0.710882347629,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.80973996498e-07,4.47788423519e-08,-7.19218165476e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244244550599,-0.00018277801232,9.81000926365,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118720250000,11442,118720250000,RH_EXTIMU,2.29931756168e-06,1.53124634359e-05,-0.703311010497,0.7108822844,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.77918184513e-07,-1.4631882809e-07,-7.19210016436e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000248237512031,-0.000175305257228,9.80998766986,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118722750000,11443,118722750000,RH_EXTIMU,2.29932715024e-06,1.53123935206e-05,-0.703311074405,0.710882221172,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.56900276979e-08,-3.37092755427e-08,-7.19203411184e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245405416832,-0.000180250890704,9.80999782818,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118725250000,11444,118725250000,RH_EXTIMU,2.29935396326e-06,1.53123546197e-05,-0.703311138313,0.710882157945,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.80354129119e-08,-6.37985568423e-09,-7.19196300358e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245318851242,-0.000179820535249,9.80999906601,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118727750000,11445,118727750000,RH_EXTIMU,2.29937190375e-06,1.5312335753e-05,-0.703311202221,0.710882094718,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.17173430952e-08,2.15704527894e-11,-7.19189130544e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245273530225,-0.000179567540908,9.80999995815,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118730250000,11446,118730250000,RH_EXTIMU,2.2996595528e-06,1.53123117006e-05,-0.703311266127,0.710882031492,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.78019880135e-07,1.48823640108e-07,-7.19181929692e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242733380887,-0.000182604668716,9.81001829467,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118732750000,11447,118732750000,RH_EXTIMU,2.2994560132e-06,1.53124385681e-05,-0.703311330033,0.710881968267,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.86236820114e-07,-4.17141784133e-08,-7.19173633369e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246421159968,-0.00017560000154,9.81000038941,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118735250000,11448,118735250000,RH_EXTIMU,2.29942763366e-06,1.53124576106e-05,-0.703311393939,0.710881905042,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.59547319617e-08,-4.48117309585e-09,-7.19166445237e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245265728628,-0.000179086444014,9.81000203088,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118735250000,11449,118737750000,RH_EXTIMU,2.29947521351e-06,1.53124050731e-05,-0.703311457843,0.710881841818,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.75182261021e-08,-2.45065893406e-09,-7.19159498669e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245321339584,-0.000180497123023,9.80999809643,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118740250000,11450,118740250000,RH_EXTIMU,2.29950180062e-06,1.531229707e-05,-0.703311521748,0.710881778594,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.67872043862e-08,-4.58057990029e-08,-7.1915412132e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245990127598,-0.000180599893494,9.80997507814,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118742750000,11451,118742750000,RH_EXTIMU,2.29971326111e-06,1.53121798124e-05,-0.703311585651,0.710881715371,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.87132739666e-07,5.29499530056e-08,-7.19146762816e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244372554059,-0.000182121298448,9.81001205634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118745250000,11452,118745250000,RH_EXTIMU,2.29964788107e-06,1.53122578203e-05,-0.703311649554,0.710881652149,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.01739171178e-08,8.23432754862e-09,-7.19137909677e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245300578352,-0.000177564131124,9.81001644789,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118747750000,11453,118747750000,RH_EXTIMU,2.29939275542e-06,1.53123578064e-05,-0.703311713456,0.710881588927,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.00449346593e-07,-8.60267393079e-08,-7.19130782753e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246954480904,-0.000175551181,9.80998347672,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118750250000,11454,118750250000,RH_EXTIMU,2.29968941985e-06,1.53122222402e-05,-0.703311777358,0.710881525706,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.4588996796e-07,9.04777318095e-08,-7.1912592687e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242824946308,-0.000184683966289,9.80999552122,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118752750000,11455,118752750000,RH_EXTIMU,2.29980818288e-06,1.53121534232e-05,-0.703311841259,0.710881462486,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.07160039458e-07,2.83422758423e-08,-7.19118166052e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245798681917,-0.000180405183624,9.810003232,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118755250000,11456,118755250000,RH_EXTIMU,2.29963625422e-06,1.53121433993e-05,-0.703311905159,0.710881399266,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.12376602433e-08,-1.01779390283e-07,-7.19109873327e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246952922638,-0.000177177851219,9.81000224805,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118757750000,11457,118757750000,RH_EXTIMU,2.29959106672e-06,1.53121605226e-05,-0.703311969058,0.710881336047,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.44337662666e-08,-1.50297104877e-08,-7.19102553055e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245162561631,-0.000179009130719,9.81000420392,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118760250000,11458,118760250000,RH_EXTIMU,2.29960637783e-06,1.53121468786e-05,-0.703312032957,0.710881272828,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.72833632615e-08,1.51220625959e-09,-7.19095572808e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245126523239,-0.000179568122214,9.80999656522,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118762750000,11459,118762750000,RH_EXTIMU,2.29976516562e-06,1.53121217784e-05,-0.703312096856,0.71088120961,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.05325083325e-07,7.57241268067e-08,-7.19089549358e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244030790116,-0.000181217029459,9.8099958273,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118765250000,11460,118765250000,RH_EXTIMU,2.29973320171e-06,1.5312078439e-05,-0.703312160754,0.710881146393,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.10589446845e-09,-4.19749844939e-08,-7.19082146816e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246335803296,-0.000179081327233,9.80999507582,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118767750000,11461,118767750000,RH_EXTIMU,2.29979502387e-06,1.53120164841e-05,-0.703312224651,0.710881083176,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.09165127479e-08,2.06980862682e-10,-7.1907475021e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245000189618,-0.000180628463143,9.81000841028,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118770250000,11462,118770250000,RH_EXTIMU,2.29965988404e-06,1.5312080525e-05,-0.703312288547,0.71088101996,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.11988301184e-07,-3.89591773594e-08,-7.19066592332e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246285613657,-0.000176753868115,9.80999991035,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118772750000,11463,118772750000,RH_EXTIMU,2.29988700041e-06,1.53119965286e-05,-0.703312352443,0.710880956744,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.77321723105e-07,8.06746603783e-08,-7.19060204093e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024306912965,-0.000183436432751,9.81001301025,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118775250000,11464,118775250000,RH_EXTIMU,2.29980414392e-06,1.53121438006e-05,-0.703312416338,0.710880893529,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.29084441354e-07,3.77918743906e-08,-7.19052028271e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245626895704,-0.000175878601483,9.8099982329,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118777750000,11465,118777750000,RH_EXTIMU,2.29980502773e-06,1.53121214433e-05,-0.703312480232,0.710880830315,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.39809861284e-08,-1.15606605838e-08,-7.19046204119e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245483655051,-0.000179944482862,9.80998833476,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118780250000,11466,118780250000,RH_EXTIMU,2.29978992524e-06,1.53120316748e-05,-0.703312544126,0.710880767102,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.28183506972e-08,-5.88923616806e-08,-7.19039038904e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246313920361,-0.000179827579352,9.80999367593,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118782750000,11467,118782750000,RH_EXTIMU,2.29977620514e-06,1.53119531685e-05,-0.703312608019,0.710880703889,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.72678326798e-08,-5.17097031922e-08,-7.19031834885e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245860781089,-0.000179823703384,9.80999820447,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118785250000,11468,118785250000,RH_EXTIMU,2.29999233301e-06,1.53118063003e-05,-0.703312671912,0.710880640676,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.06447281333e-07,3.87365068755e-08,-7.19024905055e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243961051983,-0.000183537853331,9.81001106913,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118787750000,11469,118787750000,RH_EXTIMU,2.29987785238e-06,1.53119398457e-05,-0.703312735804,0.710880577464,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.39346057677e-07,1.21920946268e-08,-7.19016672064e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024606167012,-0.00017553330297,9.81000043692,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118790250000,11470,118790250000,RH_EXTIMU,2.29992258527e-06,1.53119173211e-05,-0.703312799695,0.710880514253,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.90122347213e-08,1.30158622527e-08,-7.19009781113e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244529846164,-0.000180842783235,9.81000684181,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118792750000,11471,118792750000,RH_EXTIMU,2.29986655193e-06,1.53119563392e-05,-0.703312863586,0.710880451043,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.29209988284e-08,-8.68068514347e-09,-7.19001783286e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245840249251,-0.000177842315244,9.81000258138,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118792750000,11472,118795250000,RH_EXTIMU,2.29981646535e-06,1.53119523332e-05,-0.703312927476,0.710880387833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.53315803873e-08,-2.98026965171e-08,-7.18994821205e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245626471728,-0.000179006862531,9.80999699332,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118797750000,11473,118797750000,RH_EXTIMU,2.29980743999e-06,1.53119583044e-05,-0.703312991365,0.710880324624,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.59353229066e-09,-1.02554320097e-09,-7.18988352768e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245229789245,-0.000178901757585,9.80998766544,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118800250000,11474,118800250000,RH_EXTIMU,2.29999357505e-06,1.53118763339e-05,-0.703313055254,0.710880261415,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.52875427004e-07,5.87687392172e-08,-7.18983029276e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244205072322,-0.000182196849303,9.8099879293,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118802750000,11475,118802750000,RH_EXTIMU,2.30007570144e-06,1.53117687923e-05,-0.703313119142,0.710880198207,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.08112858049e-07,-1.4294204951e-08,-7.18974333236e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245972920881,-0.000180718311595,9.81001634894,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118805250000,11476,118805250000,RH_EXTIMU,2.29999684956e-06,1.53117715139e-05,-0.703313183029,0.710880135,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.54758133078e-08,-4.21615744867e-08,-7.18965987977e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245685017198,-0.000178585418594,9.81001280379,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118807750000,11477,118807750000,RH_EXTIMU,2.29988150215e-06,1.53118322786e-05,-0.703313246916,0.710880071793,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.88889691476e-08,-2.96864444265e-08,-7.1895893087e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245744620072,-0.000177477439484,9.80999393125,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118809000000,11478,118810250000,RH_EXTIMU,2.29998204924e-06,1.53117865407e-05,-0.703313310802,0.710880008587,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.38148652762e-08,3.12182416832e-08,-7.18952440361e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024460341278,-0.000180960651474,9.80999786709,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118814000000,11479,118812750000,RH_EXTIMU,2.30017502192e-06,1.53117248472e-05,-0.703313374688,0.710879945382,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.45355093965e-07,7.41475326965e-08,-7.18945428641e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243976113905,-0.00018197658349,9.81000920782,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118815250000,11480,118815250000,RH_EXTIMU,2.29991877363e-06,1.53118412364e-05,-0.703313438572,0.710879882177,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.10317016176e-07,-7.73306366727e-08,-7.18937263638e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247629724118,-0.000174321360216,9.80998788161,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118830250000,11481,118817750000,RH_EXTIMU,2.30011159642e-06,1.53116587977e-05,-0.703313502457,0.710879818973,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.13207173264e-07,5.39498405914e-09,-7.18931478131e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244036200779,-0.000184478135499,9.81000601553,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118830250000,11482,118820250000,RH_EXTIMU,2.30004089704e-06,1.53117231843e-05,-0.70331356634,0.710879755769,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.55353787148e-08,-2.50548984592e-09,-7.18922618089e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245809709547,-0.000176775836362,9.8100067797,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118830250000,11483,118822750000,RH_EXTIMU,2.30005839509e-06,1.53117379472e-05,-0.703313630223,0.710879692566,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.54371063024e-09,1.88976288087e-08,-7.18915884627e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244875789003,-0.000179766840811,9.81000079642,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118830250000,11484,118825250000,RH_EXTIMU,2.30002502984e-06,1.53117380257e-05,-0.703313694105,0.710879629364,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.81203230616e-08,-1.80716750254e-08,-7.18908988086e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245789784332,-0.000178646437463,9.80999188476,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118830250000,11485,118827750000,RH_EXTIMU,2.30016743218e-06,1.53117141645e-05,-0.703313757987,0.710879566162,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.53090712141e-08,6.72094901147e-08,-7.18902271894e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024391760367,-0.000181120919778,9.81000456599,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118830250000,11486,118830250000,RH_EXTIMU,2.30022350863e-06,1.53117024704e-05,-0.703313821868,0.710879502961,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.93693934118e-08,2.55575996955e-08,-7.18894687315e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245046865423,-0.000179978797769,9.81000581277,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118834000000,11487,118832750000,RH_EXTIMU,2.30020234249e-06,1.53117017702e-05,-0.703313885748,0.710879439761,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.07445262243e-08,-1.16507115854e-08,-7.18887005329e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245627554606,-0.00017889897065,9.81000375894,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118835250000,11488,118835250000,RH_EXTIMU,2.30019610677e-06,1.53116992574e-05,-0.703313949628,0.710879376561,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.2336310772e-09,-4.28099875494e-09,-7.18879823621e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245301560473,-0.000179286486716,9.81000101322,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118837750000,11489,118837750000,RH_EXTIMU,2.30021411304e-06,1.53116815245e-05,-0.703314013506,0.710879313362,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.11163889521e-08,7.03140540886e-10,-7.18872718724e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245273476203,-0.000179629448036,9.80999980457,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118841500000,11490,118840250000,RH_EXTIMU,2.300236549e-06,1.5311658263e-05,-0.703314077385,0.710879250163,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.67463313428e-08,5.12664690937e-11,-7.18865612351e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245293545296,-0.000179681283697,9.80999956216,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118842750000,11491,118842750000,RH_EXTIMU,2.30025773681e-06,1.53116361712e-05,-0.703314141263,0.710879186965,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.53783116401e-08,1.42545233217e-11,-7.18858487015e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245291439577,-0.000179642364922,9.8099996701,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118845250000,11492,118845250000,RH_EXTIMU,2.30020447164e-06,1.53116235784e-05,-0.70331420514,0.710879123768,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.23079769583e-08,-3.64747110832e-08,-7.1885143779e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024610651426,-0.000178598365432,9.80999199326,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118847750000,11493,118847750000,RH_EXTIMU,2.30028946307e-06,1.53115265536e-05,-0.703314269016,0.710879060571,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03824764255e-07,-6.70119703579e-09,-7.18844861237e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244987646168,-0.000181336565965,9.81000036276,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118850250000,11494,118850250000,RH_EXTIMU,2.30025867283e-06,1.53115745099e-05,-0.703314332892,0.710878997375,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.35944740925e-08,1.06052990824e-08,-7.18837032883e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245230372423,-0.000178028318872,9.81000147562,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118852750000,11495,118852750000,RH_EXTIMU,2.3002615217e-06,1.53115662752e-05,-0.703314396767,0.71087893418,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.15213502396e-09,-2.42361327336e-09,-7.18830468513e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245439840996,-0.000179459134852,9.80999328585,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118855250000,11496,118855250000,RH_EXTIMU,2.30041646332e-06,1.5311449797e-05,-0.703314460642,0.710878870985,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.54551154369e-07,2.15931347526e-08,-7.18823662672e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244657930042,-0.000182372975237,9.81000429453,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118857750000,11497,118857750000,RH_EXTIMU,2.30029488176e-06,1.53114541903e-05,-0.703314524515,0.710878807791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.07170523004e-08,-6.5252997228e-08,-7.18815574957e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246981134787,-0.000177115116465,9.80999764535,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118860250000,11498,118860250000,RH_EXTIMU,2.30024314207e-06,1.53114487936e-05,-0.703314588389,0.710878744597,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.54893260981e-08,-3.15240659467e-08,-7.18809045431e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245181528944,-0.000179057427418,9.80999257246,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118862750000,11499,118862750000,RH_EXTIMU,2.30053907576e-06,1.53113735282e-05,-0.703314652261,0.710878681404,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.11545231549e-07,1.24360482333e-07,-7.18802734633e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242789757375,-0.000183573862222,9.81001050486,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118865250000,11500,118865250000,RH_EXTIMU,2.30027145129e-06,1.53115361271e-05,-0.703314716133,0.710878618212,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.42786674406e-07,-5.74524343785e-08,-7.18794351134e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247638874374,-0.000173358422182,9.80998477415,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118867750000,11501,118867750000,RH_EXTIMU,2.30047348321e-06,1.53114233213e-05,-0.703314780005,0.71087855502,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.79265150019e-07,5.01771894132e-08,-7.1878895187e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243577596328,-0.000183530998595,9.8100008654,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118870250000,11502,118870250000,RH_EXTIMU,2.30044226676e-06,1.53113396064e-05,-0.703314843875,0.710878491829,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.02481130027e-08,-6.45164084124e-08,-7.18780052672e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246793749279,-0.000179311372566,9.81001127604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118872750000,11503,118872750000,RH_EXTIMU,2.30033309036e-06,1.53113791185e-05,-0.703314907745,0.710878428638,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.34218229177e-08,-3.83011955695e-08,-7.18772327038e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245538562124,-0.000177765148034,9.81000462149,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118876500000,11504,118875250000,RH_EXTIMU,2.30032573537e-06,1.53114122141e-05,-0.703314971615,0.710878365448,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.190546859e-08,1.53397284113e-08,-7.18766804287e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024485397912,-0.00017912709849,9.80998052959,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118877750000,11505,118877750000,RH_EXTIMU,2.30036599694e-06,1.53112857635e-05,-0.703315035484,0.710878302259,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.4943125801e-08,-4.8603028159e-08,-7.18759628677e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247046191521,-0.000180191012266,9.80999173277,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118880250000,11506,118880250000,RH_EXTIMU,2.30034838619e-06,1.53110859662e-05,-0.703315099352,0.71087823907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03299728967e-07,-1.22877555479e-07,-7.18753483076e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246471178478,-0.000181485294274,9.80998693351,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118882750000,11507,118882750000,RH_EXTIMU,2.30068610404e-06,1.53109506148e-05,-0.70331516322,0.710878175882,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.69115323219e-07,1.13699447638e-07,-7.18746252769e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242330273785,-0.000184382045358,9.81002561241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118886500000,11508,118885250000,RH_EXTIMU,2.30039251178e-06,1.5311299933e-05,-0.703315227086,0.710878112695,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.62612718678e-07,3.41242592315e-08,-7.1873635405e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246106817098,-0.000171117823792,9.81000602549,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118887750000,11509,118887750000,RH_EXTIMU,2.3004566791e-06,1.53112952352e-05,-0.703315290953,0.710878049508,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.00339312464e-08,3.40886735354e-08,-7.18730855675e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244295361834,-0.000181462375645,9.80999640958,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118890250000,11510,118890250000,RH_EXTIMU,2.3006114968e-06,1.53112419196e-05,-0.703315354818,0.710877986322,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.18941968718e-07,5.74441983007e-08,-7.18723387861e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244550340907,-0.000181055841863,9.81000719167,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118892750000,11511,118892750000,RH_EXTIMU,2.30052409729e-06,1.53112964934e-05,-0.703315418683,0.710877923136,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.9511846586e-08,-1.7482828937e-08,-7.18716807726e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245616105226,-0.000177686380948,9.80998623829,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118897750000,11512,118895250000,RH_EXTIMU,2.30064178817e-06,1.53112056463e-05,-0.703315482548,0.710877859951,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.18944964461e-07,1.52105164745e-08,-7.18710196872e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245100343864,-0.000181445218514,9.80999818632,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118897750000,11513,118897750000,RH_EXTIMU,2.30058218765e-06,1.53111428635e-05,-0.703315546411,0.710877796767,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.32854076759e-09,-6.85827373163e-08,-7.18702627322e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246531402093,-0.000178912528303,9.80999623644,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118900250000,11514,118900250000,RH_EXTIMU,2.3006630814e-06,1.53110554941e-05,-0.703315610274,0.710877733583,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.60615816631e-08,-3.5156899599e-09,-7.18695270604e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245019720211,-0.000181202225593,9.81000980893,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118904000000,11515,118902750000,RH_EXTIMU,2.30063707974e-06,1.53110635425e-05,-0.703315674137,0.7108776704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.84171271653e-08,-9.39638054446e-09,-7.1868658448e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245490068876,-0.000178649289788,9.81001739439,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118905250000,11516,118905250000,RH_EXTIMU,2.30036882652e-06,1.53112102981e-05,-0.703315737998,0.710877607218,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.34230066862e-07,-6.6816763816e-08,-7.18678575105e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024682725291,-0.000174616967951,9.80999271053,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118907750000,11517,118907750000,RH_EXTIMU,2.30053928778e-06,1.5311097427e-05,-0.703315801859,0.710877544036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.61347409942e-07,3.23768138713e-08,-7.18673906769e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243853633475,-0.000183084265794,9.80998663213,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118910250000,11518,118910250000,RH_EXTIMU,2.30073567967e-06,1.5311038328e-05,-0.70331586572,0.710877480855,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.45839151051e-07,7.75470920924e-08,-7.18667551149e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244396607745,-0.000181360603899,9.80999281185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118912750000,11519,118912750000,RH_EXTIMU,2.30079084878e-06,1.53109960301e-05,-0.70331592958,0.710877417675,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.60722920305e-08,7.64251698874e-09,-7.18658646492e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245486867287,-0.000179784748981,9.81002206126,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118915250000,11520,118915250000,RH_EXTIMU,2.3005982083e-06,1.53110578709e-05,-0.703315993439,0.710877354495,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.43451415011e-07,-7.25643923588e-08,-7.18651372669e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246389971429,-0.000176884423418,9.80999076699,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118917750000,11521,118917750000,RH_EXTIMU,2.30061042504e-06,1.53110170519e-05,-0.703316057297,0.710877291315,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.08131112624e-08,-1.56837380223e-08,-7.18645117065e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245473935532,-0.000179641280301,9.80999020031,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118920250000,11522,118920250000,RH_EXTIMU,2.30068846657e-06,1.53109542382e-05,-0.703316121155,0.710877228137,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.06231154009e-08,8.84437518634e-09,-7.18638274829e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244981513148,-0.000180789643594,9.80999940388,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118920250000,11523,118922750000,RH_EXTIMU,2.30067711638e-06,1.5310927011e-05,-0.703316185013,0.710877164959,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.76307720234e-09,-2.1214088736e-08,-7.18630546429e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024574356903,-0.000179104869778,9.81000252561,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118925250000,11524,118925250000,RH_EXTIMU,2.3007684136e-06,1.53109839439e-05,-0.703316248869,0.710877101781,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.07858356853e-08,8.44028357334e-08,-7.18623885814e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024362805567,-0.000179647847934,9.81000264834,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118927750000,11525,118927750000,RH_EXTIMU,2.30076097344e-06,1.53109238339e-05,-0.703316312725,0.710877038604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.04883138745e-08,-3.77146151228e-08,-7.18616545607e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246396250724,-0.0001798125984,9.8099958908,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118930250000,11526,118930250000,RH_EXTIMU,2.30092901305e-06,1.53109004657e-05,-0.703316376581,0.710876975428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0961097901e-07,8.1914807758e-08,-7.18609023964e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243771503967,-0.000181126716108,9.81001808347,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118932750000,11527,118932750000,RH_EXTIMU,2.30086539153e-06,1.53109431674e-05,-0.703316440435,0.710876912253,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.93094686343e-08,-1.08560586289e-08,-7.18600316317e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024552685718,-0.00017824263166,9.81001527755,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118936500000,11528,118935250000,RH_EXTIMU,2.30065873416e-06,1.53109721114e-05,-0.703316504289,0.710876849078,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.32913381504e-07,-9.91596346818e-08,-7.18594428185e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246960776673,-0.000177044022196,9.80997032527,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118937750000,11529,118937750000,RH_EXTIMU,2.30106892271e-06,1.5310733266e-05,-0.703316568143,0.710876785903,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.68560389611e-07,9.56184245366e-08,-7.18588706958e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242973609847,-0.000186343379564,9.81000980701,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118940250000,11530,118940250000,RH_EXTIMU,2.30102271343e-06,1.53108404337e-05,-0.703316631995,0.71087672273,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.56791726614e-08,3.56028991813e-08,-7.18579192232e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245504749304,-0.000176485787939,9.81001631896,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118942750000,11531,118942750000,RH_EXTIMU,2.30069391376e-06,1.53109350062e-05,-0.703316695847,0.710876659557,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.39301933703e-07,-1.30560488269e-07,-7.18572245484e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247753411979,-0.000174990836815,9.80998063804,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118945250000,11532,118945250000,RH_EXTIMU,2.30084148912e-06,1.53107634944e-05,-0.703316759699,0.710876596384,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.81326381729e-07,-1.38489715207e-08,-7.18566153337e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002449880311,-0.000182952321582,9.80999744585,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118947750000,11533,118947750000,RH_EXTIMU,2.30080446535e-06,1.53107080205e-05,-0.70331682355,0.710876533212,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.10554684593e-08,-5.17233813919e-08,-7.18559152472e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246091316105,-0.000179005598914,9.8099905344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118950250000,11534,118950250000,RH_EXTIMU,2.30096948962e-06,1.53106441016e-05,-0.7033168874,0.710876470041,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.3071201103e-07,5.71569818255e-08,-7.18552120454e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243861289684,-0.000181762388276,9.81001066627,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118952750000,11535,118952750000,RH_EXTIMU,2.30083411672e-06,1.53107669142e-05,-0.70331695125,0.710876406871,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.45189288005e-07,-5.66819163469e-09,-7.18544633535e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245817072458,-0.000176091460718,9.80999149536,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118955250000,11536,118955250000,RH_EXTIMU,2.30103355874e-06,1.53107072836e-05,-0.703317015099,0.710876343701,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.47872603142e-07,7.89609977476e-08,-7.18537919275e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243644436176,-0.00018245824975,9.81001034507,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118957750000,11537,118957750000,RH_EXTIMU,2.30102213693e-06,1.53107395477e-05,-0.703317078947,0.710876280531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.37507970582e-08,1.25783242001e-08,-7.18529365259e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245775953304,-0.000178271336307,9.81001215072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118960250000,11538,118960250000,RH_EXTIMU,2.30076659914e-06,1.53108152602e-05,-0.703317142794,0.710876217363,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.87026207247e-07,-1.00065290215e-07,-7.18521548898e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247171548826,-0.000175573453036,9.80999137924,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118962750000,11539,118962750000,RH_EXTIMU,2.30098856441e-06,1.5310651074e-05,-0.703317206641,0.710876154195,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.1951014669e-07,3.21729490355e-08,-7.18516014409e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243846822931,-0.000184268970567,9.81000170364,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118965250000,11540,118965250000,RH_EXTIMU,2.30110087882e-06,1.5310643797e-05,-0.703317270487,0.710876091027,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.88660550504e-08,5.97118479526e-08,-7.18508066437e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024469814116,-0.000179712985118,9.81000796648,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118970250000,11541,118967750000,RH_EXTIMU,2.30093614441e-06,1.53106868244e-05,-0.703317334333,0.710876027861,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.16995830639e-07,-6.75625649637e-08,-7.18501221088e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246549250235,-0.000177070495496,9.8099857224,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118970250000,11542,118970250000,RH_EXTIMU,2.30108397787e-06,1.53105979296e-05,-0.703317398178,0.710875964694,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34988307317e-07,3.32806878292e-08,-7.18494770803e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244370530068,-0.000181845707889,9.81000071415,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118972750000,11543,118972750000,RH_EXTIMU,2.30108908731e-06,1.53105894648e-05,-0.703317462023,0.710875901529,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.56675772645e-09,-1.28292449174e-09,-7.18487161429e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024577931488,-0.000178910109971,9.81000104192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118975250000,11544,118975250000,RH_EXTIMU,2.30109008211e-06,1.53106147083e-05,-0.703317525866,0.710875838364,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.27393422326e-08,1.55718669075e-08,-7.18480569515e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244732147533,-0.000179054167079,9.80999426662,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118977750000,11545,118977750000,RH_EXTIMU,2.30107585695e-06,1.53105677947e-05,-0.70331758971,0.710875775199,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.92045075208e-08,-3.40274746258e-08,-7.18473066267e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246092603535,-0.000179417173072,9.81000024074,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118981500000,11546,118980250000,RH_EXTIMU,2.30110586052e-06,1.53105363489e-05,-0.703317653552,0.710875712036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.56544179604e-08,-3.45502536724e-10,-7.18465774326e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245000243074,-0.000179946788382,9.81000432755,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118982750000,11547,118982750000,RH_EXTIMU,2.30118427563e-06,1.53105470985e-05,-0.703317717394,0.710875648873,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.94446719237e-08,5.08899861593e-08,-7.18458351625e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244388559601,-0.000179935890018,9.81000947982,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118985250000,11548,118985250000,RH_EXTIMU,2.30115078848e-06,1.53106276265e-05,-0.703317781235,0.71087558571,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.34553420808e-08,2.76107466746e-08,-7.18450354105e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245135427178,-0.000177907638502,9.81000748769,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118987750000,11549,118987750000,RH_EXTIMU,2.30112987104e-06,1.53106549218e-05,-0.703317845075,0.710875522549,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.63553567644e-08,4.40967899108e-09,-7.18443059754e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245274085992,-0.000178937441679,9.81000228179,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118990250000,11550,118990250000,RH_EXTIMU,2.30097604188e-06,1.53106478064e-05,-0.703317908915,0.710875459387,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.25810130219e-08,-8.99430167479e-08,-7.18436151225e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247306615269,-0.000177371232849,9.80998238188,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118992750000,11551,118992750000,RH_EXTIMU,2.30118204525e-06,1.53104149267e-05,-0.703317972755,0.710875396227,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.49083196325e-07,-1.58740090783e-08,-7.18430901198e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244502776517,-0.000184448233113,9.809991375,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118995250000,11552,118995250000,RH_EXTIMU,2.30126052714e-06,1.53103464612e-05,-0.703318036593,0.710875333067,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.40532631433e-08,5.87792598343e-09,-7.18423800175e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245491412785,-0.00017991559081,9.80999475859,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +118997750000,11553,118997750000,RH_EXTIMU,2.30135343022e-06,1.53103240157e-05,-0.703318100431,0.710875269907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.63612564712e-08,4.01636328908e-08,-7.18416786074e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244400382392,-0.000180397306375,9.81000323007,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119000250000,11554,119000250000,RH_EXTIMU,2.30134980268e-06,1.53103469206e-05,-0.703318164269,0.710875206749,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.40523510379e-08,1.16410274038e-08,-7.18409152529e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245564217901,-0.000178637325965,9.81000442423,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119000250000,11555,119002750000,RH_EXTIMU,2.30124940702e-06,1.53103737515e-05,-0.703318228106,0.71087514359,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.1293397122e-08,-4.05732823855e-08,-7.1840134793e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245867660918,-0.00017795223176,9.81000049844,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119000250000,11556,119005250000,RH_EXTIMU,2.3013077944e-06,1.53103240987e-05,-0.703318291942,0.710875080433,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.20404489054e-08,5.27041577011e-09,-7.18394972138e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245048028642,-0.000180553844963,9.80999570379,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119007750000,11557,119007750000,RH_EXTIMU,2.30132168938e-06,1.53102774267e-05,-0.703318355777,0.710875017276,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.50604753019e-08,-1.8068287626e-08,-7.18387843515e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245748986802,-0.000179568165411,9.80999761549,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119010250000,11558,119010250000,RH_EXTIMU,2.30125506725e-06,1.53102473337e-05,-0.703318419612,0.71087495412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.0057898386e-08,-5.3943117932e-08,-7.18380798799e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246035453499,-0.00017879401619,9.80999272676,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119012750000,11559,119012750000,RH_EXTIMU,2.30140185257e-06,1.5310234669e-05,-0.703318483446,0.710874890964,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.15007304928e-08,7.60431151317e-08,-7.18373377456e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243998278711,-0.000180748217405,9.81001449218,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119015250000,11560,119015250000,RH_EXTIMU,2.3013284946e-06,1.53102586488e-05,-0.70331854728,0.710874827809,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.43128879729e-08,-2.69818994364e-08,-7.18364903366e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245774168752,-0.000178355796363,9.8100092115,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119017750000,11561,119017750000,RH_EXTIMU,2.30132938036e-06,1.53102534919e-05,-0.703318611113,0.710874764655,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.30341513463e-09,-1.77836752095e-09,-7.18357830377e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245284116921,-0.000179397709391,9.81000167328,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119020250000,11562,119020250000,RH_EXTIMU,2.30128875976e-06,1.53102420392e-05,-0.703318674945,0.710874701501,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.5758937571e-08,-2.87124964812e-08,-7.18350888046e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245947677636,-0.000178767914524,9.80999273389,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119022750000,11563,119022750000,RH_EXTIMU,2.30141467473e-06,1.53101904212e-05,-0.703318738776,0.710874638348,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.01549031161e-07,4.21475193406e-08,-7.18344568401e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243951315066,-0.000181264340152,9.80999962464,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119025250000,11564,119025250000,RH_EXTIMU,2.30146989402e-06,1.5310228288e-05,-0.703318802607,0.710874575196,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.09953253279e-08,5.32602390834e-08,-7.18336769819e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024505203212,-0.000179100831442,9.81000888158,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119027750000,11565,119027750000,RH_EXTIMU,2.30129364933e-06,1.53102460349e-05,-0.703318866437,0.710874512044,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.09317601079e-07,-8.84163331416e-08,-7.18328266923e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246866820923,-0.000177073354342,9.81000288242,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119030250000,11566,119030250000,RH_EXTIMU,2.30140707516e-06,1.53102174524e-05,-0.703318930267,0.710874448893,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.14853869845e-08,4.82207207636e-08,-7.18322091057e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243759044843,-0.000181265266232,9.81000085733,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119032750000,11567,119032750000,RH_EXTIMU,2.30139006155e-06,1.53102265036e-05,-0.703318994096,0.710874385742,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.38702830628e-08,-3.76941663083e-09,-7.18315144085e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246241795843,-0.000178324466939,9.80998969781,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119035250000,11568,119035250000,RH_EXTIMU,2.30138013084e-06,1.5310105327e-05,-0.703319057924,0.710874322592,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.34311111623e-08,-7.3844692749e-08,-7.18308519606e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246137674803,-0.000180577590674,9.80999111002,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119037750000,11569,119037750000,RH_EXTIMU,2.30158517238e-06,1.53099941516e-05,-0.703319121752,0.710874259443,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.80058456018e-07,5.27982719816e-08,-7.18301877193e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024378791623,-0.000182593494716,9.8100063886,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119040250000,11570,119040250000,RH_EXTIMU,2.30142206651e-06,1.53101350693e-05,-0.703319185579,0.710874196294,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.71148261871e-07,-1.0976658944e-08,-7.18294089874e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024639915489,-0.000174943335191,9.80999021748,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119042750000,11571,119042750000,RH_EXTIMU,2.30152601383e-06,1.53100848342e-05,-0.703319249406,0.710874133146,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.82778564789e-08,3.05737591361e-08,-7.18288012157e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244275215848,-0.000181556333509,9.80999861997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119042750000,11572,119045250000,RH_EXTIMU,2.30161396104e-06,1.53100611456e-05,-0.703319313232,0.710874069998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.42420446411e-08,3.6668210284e-08,-7.18279722958e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244864475798,-0.000180059794978,9.81001578784,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119047750000,11573,119047750000,RH_EXTIMU,2.3015268295e-06,1.53101348494e-05,-0.703319377057,0.710874006851,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.01234781982e-08,-6.4538424993e-09,-7.18271756872e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245434091289,-0.000177637342477,9.81000651046,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119050250000,11574,119050250000,RH_EXTIMU,2.30151282557e-06,1.53101518837e-05,-0.703319440881,0.710873943705,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.66504803924e-08,2.46391781766e-09,-7.18264565865e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245230835303,-0.000179114507233,9.81000169653,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119051500000,11575,119052750000,RH_EXTIMU,2.30153351483e-06,1.5310130114e-05,-0.703319504705,0.71087388056,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.49128096575e-08,-8.35918763012e-11,-7.18257506231e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245299005349,-0.000179696279604,9.80999952293,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119055250000,11576,119055250000,RH_EXTIMU,2.30156022014e-06,1.53101005541e-05,-0.703319568528,0.710873817415,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.27172972473e-08,-1.12890400422e-09,-7.18250442236e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245303328509,-0.000179746811987,9.80999922342,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119055250000,11577,119057750000,RH_EXTIMU,2.30158424159e-06,1.53100747516e-05,-0.703319632351,0.71087375427,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.90768634697e-08,-5.0215862755e-10,-7.18243343657e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245291565666,-0.000179660507826,9.80999947868,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119060250000,11578,119060250000,RH_EXTIMU,2.30160489484e-06,1.5310053119e-05,-0.703319696173,0.710873691127,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.48151607024e-08,-2.59135901467e-11,-7.18236216932e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245286467182,-0.000179588200187,9.80999972383,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119062750000,11579,119062750000,RH_EXTIMU,2.30162557279e-06,1.53100246022e-05,-0.703319759994,0.710873627984,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.87025850198e-08,-3.92700542945e-09,-7.18228937851e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245374408368,-0.000179666708607,9.81000161133,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119065250000,11580,119065250000,RH_EXTIMU,2.3015235785e-06,1.53099540168e-05,-0.703319823815,0.710873564841,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.73908004204e-08,-9.6873668359e-08,-7.18222934218e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246888687076,-0.000178936037556,9.80997523838,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119067750000,11581,119067750000,RH_EXTIMU,2.30171690962e-06,1.5309855316e-05,-0.703319887635,0.710873501699,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.66379680201e-07,5.33037224381e-08,-7.18215683832e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244477553177,-0.000181577019523,9.81001043191,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119070250000,11582,119070250000,RH_EXTIMU,2.30158224444e-06,1.5309893693e-05,-0.703319951454,0.710873438558,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.72790265171e-08,-5.32893989128e-08,-7.18208390238e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246056871943,-0.000177368731992,9.80999164087,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119072750000,11583,119072750000,RH_EXTIMU,2.30182011687e-06,1.53098435841e-05,-0.703320015273,0.710873375417,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.64369697663e-07,1.0599933161e-07,-7.18201407314e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243274037043,-0.000182468929968,9.8100154687,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119075250000,11584,119075250000,RH_EXTIMU,2.30167555079e-06,1.53098819504e-05,-0.703320079091,0.710873312277,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.02903649676e-07,-5.88663052159e-08,-7.18193488998e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246621463268,-0.000177168466249,9.80999624028,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119077750000,11585,119077750000,RH_EXTIMU,2.30169254088e-06,1.53098205353e-05,-0.703320142908,0.710873249138,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.51157383162e-08,-2.4711322738e-08,-7.18186229231e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245529913689,-0.000180202932619,9.81000562528,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119080250000,11586,119080250000,RH_EXTIMU,2.30149846039e-06,1.53098670306e-05,-0.703320206725,0.710873185999,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.35636316123e-07,-8.21029372508e-08,-7.18178334164e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246889711361,-0.00017619435273,9.80999333953,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119082750000,11587,119082750000,RH_EXTIMU,2.30160800701e-06,1.53097768835e-05,-0.703320270541,0.710873122861,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.13918719202e-07,1.1026344947e-08,-7.18172596248e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244364686037,-0.000181962176949,9.80999410006,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119085250000,11588,119085250000,RH_EXTIMU,2.30189717744e-06,1.53096820928e-05,-0.703320334357,0.710873059723,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.18683201477e-07,1.09452019376e-07,-7.18165402963e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243288542074,-0.000183234265739,9.81001689635,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119087750000,11589,119087750000,RH_EXTIMU,2.30163674143e-06,1.5309804901e-05,-0.703320398172,0.710872996587,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.1631049643e-07,-7.60393575084e-08,-7.18157362e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247267634183,-0.000174552467986,9.80998733804,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119090250000,11590,119090250000,RH_EXTIMU,2.30191255588e-06,1.53097106418e-05,-0.703320461986,0.71087293345,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.10788571525e-07,1.02239511511e-07,-7.1815110273e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242768750111,-0.000183836861679,9.81001325118,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119094000000,11591,119092750000,RH_EXTIMU,2.30181701541e-06,1.53098231571e-05,-0.703320525799,0.710872870315,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.16743298303e-07,1.08865415534e-08,-7.18142681621e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246338164188,-0.000175973443186,9.81000105704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119095250000,11592,119095250000,RH_EXTIMU,2.30175155741e-06,1.5309787793e-05,-0.703320589612,0.71087280718,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.64301961194e-08,-5.62860946455e-08,-7.18135768174e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245875579918,-0.000179465720088,9.80999728537,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119097750000,11593,119097750000,RH_EXTIMU,2.30178140384e-06,1.53097271512e-05,-0.703320653425,0.710872744045,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.19919351595e-08,-1.70378392e-08,-7.18128805612e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245425129787,-0.000180082213398,9.80999814089,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119100250000,11594,119100250000,RH_EXTIMU,2.30169607733e-06,1.53097084009e-05,-0.703320717236,0.710872680912,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.70772211482e-08,-5.80170657499e-08,-7.18121692216e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246506496314,-0.000178117669431,9.80999085736,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119102750000,11595,119102750000,RH_EXTIMU,2.30182971746e-06,1.53096034771e-05,-0.703320781047,0.710872617778,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.35934762653e-07,1.61792564239e-08,-7.1811534756e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244244277441,-0.000182162467499,9.80999998024,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119105250000,11596,119105250000,RH_EXTIMU,2.30189589439e-06,1.53096354513e-05,-0.703320844858,0.710872554646,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.05419559323e-08,5.6074309502e-08,-7.1810812623e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244661701445,-0.000179019652565,9.81000119407,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119107750000,11597,119107750000,RH_EXTIMU,2.30190535741e-06,1.53096623741e-05,-0.703320908668,0.710872491514,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.86889940599e-09,2.12910784172e-08,-7.18100811078e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245108104108,-0.000179022984532,9.81000159337,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119110250000,11598,119110250000,RH_EXTIMU,2.30191356004e-06,1.53096626869e-05,-0.703320972477,0.710872428383,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.38659307458e-09,5.44886229728e-09,-7.18093752814e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245238778552,-0.000179309713767,9.80999845544,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119112750000,11599,119112750000,RH_EXTIMU,2.30205028752e-06,1.53096003875e-05,-0.703321036285,0.710872365252,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.13707563515e-07,4.2156826076e-08,-7.18086680841e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244378749707,-0.000181541867647,9.81000724945,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119116500000,11600,119115250000,RH_EXTIMU,2.30195155955e-06,1.53096120897e-05,-0.703321100093,0.710872302122,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.18329513297e-08,-4.82392675189e-08,-7.18078874437e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024679812514,-0.000177420891802,9.80999637888,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119119000000,11601,119117750000,RH_EXTIMU,2.30193685786e-06,1.53095309935e-05,-0.7033211639,0.710872238993,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.816625875e-08,-5.37355436919e-08,-7.18072006681e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245653145633,-0.000180229183682,9.81000010914,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119120250000,11602,119120250000,RH_EXTIMU,2.30191235958e-06,1.53095494888e-05,-0.703321227707,0.710872175864,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.34408441265e-08,-2.61027298652e-09,-7.18064529071e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245226303946,-0.000178539870522,9.80999920359,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119122750000,11603,119122750000,RH_EXTIMU,2.30210369478e-06,1.53095207948e-05,-0.703321291513,0.710872112736,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.25854471094e-07,9.19935730968e-08,-7.1805811851e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243674848472,-0.00018166117097,9.81000446708,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119125250000,11604,119125250000,RH_EXTIMU,2.30204516954e-06,1.53095084593e-05,-0.703321355318,0.710872049608,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.5444810204e-08,-3.92891334758e-08,-7.18050781696e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246286236135,-0.000178528233118,9.80999321761,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119127750000,11605,119127750000,RH_EXTIMU,2.30203392843e-06,1.53094838606e-05,-0.703321419123,0.710871986481,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.3455472549e-09,-1.96584633186e-08,-7.18043637208e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245471552701,-0.000179216464956,9.8099999915,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119130250000,11606,119130250000,RH_EXTIMU,2.30217834053e-06,1.53094531864e-05,-0.703321482927,0.710871923355,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.00283602667e-07,6.44657632398e-08,-7.18036206236e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243789316838,-0.000181353323665,9.81001519119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119132750000,11607,119132750000,RH_EXTIMU,2.30209141331e-06,1.53095809086e-05,-0.70332154673,0.710871860229,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.20401416893e-07,2.43807106025e-08,-7.18027915204e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245551368209,-0.000176456052905,9.81000404551,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119135250000,11608,119135250000,RH_EXTIMU,2.3020694065e-06,1.53095512055e-05,-0.703321610532,0.710871797104,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.09513399287e-09,-2.86187364231e-08,-7.18021402113e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245822705612,-0.00017965251997,9.80999442481,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119137750000,11609,119137750000,RH_EXTIMU,2.30201771122e-06,1.53095064949e-05,-0.703321674334,0.71087173398,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.34453261602e-09,-5.38579320066e-08,-7.18014465394e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024608215557,-0.000178897804033,9.80998986928,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119140250000,11610,119140250000,RH_EXTIMU,2.30208922373e-06,1.53093977664e-05,-0.703321738136,0.710871670856,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.02743495956e-07,-2.09409211275e-08,-7.18008184432e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245405745439,-0.000181146850883,9.80999313556,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119142750000,11611,119142750000,RH_EXTIMU,2.30218793612e-06,1.53093190996e-05,-0.703321801937,0.710871607733,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.01297613568e-07,1.14592347502e-08,-7.18001247056e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024493198005,-0.0001808911861,9.80999917459,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119146500000,11612,119145250000,RH_EXTIMU,2.30216608948e-06,1.5309308074e-05,-0.703321865737,0.71087154461,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.32287863837e-09,-1.79067805604e-08,-7.17994023913e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245892897122,-0.000178597924474,9.8099970559,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119149000000,11613,119147750000,RH_EXTIMU,2.30213099894e-06,1.53092960057e-05,-0.703321929536,0.710871481488,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.22678880729e-08,-2.59516374768e-08,-7.17986666915e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245517053946,-0.000179080215574,9.80999997988,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119149000000,11614,119150250000,RH_EXTIMU,2.30215833419e-06,1.53092835707e-05,-0.703321993335,0.710871418367,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.3439733238e-08,8.96423426214e-09,-7.17979615868e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024496456698,-0.000179545363939,9.81000184672,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119152750000,11615,119152750000,RH_EXTIMU,2.30215292161e-06,1.5309345173e-05,-0.703322057134,0.710871355246,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.68414896042e-08,3.26431653047e-08,-7.17972090693e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024483269711,-0.000178425826399,9.8100039471,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119155250000,11616,119155250000,RH_EXTIMU,2.30216564122e-06,1.53093269679e-05,-0.703322120931,0.710871292126,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.83743976479e-08,-2.54078159433e-09,-7.17964657523e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245490626892,-0.000179728320485,9.81000360754,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119157750000,11617,119157750000,RH_EXTIMU,2.30221563812e-06,1.53093109067e-05,-0.703322184728,0.710871229007,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.83677002233e-08,1.96526907078e-08,-7.17957769938e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024461482271,-0.00017986594149,9.80999868072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119160250000,11618,119160250000,RH_EXTIMU,2.30224605109e-06,1.53093037205e-05,-0.703322248524,0.710871165888,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.22367150379e-08,1.36808874807e-08,-7.17951480091e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245751487824,-0.000179316698551,9.80998877103,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119162750000,11619,119162750000,RH_EXTIMU,2.30227728616e-06,1.53091578739e-05,-0.70332231232,0.71087110277,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.00722613579e-07,-6.47123360723e-08,-7.17944397401e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024593899594,-0.000181120257172,9.80999820529,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119169000000,11620,119165250000,RH_EXTIMU,2.30232278487e-06,1.53091510594e-05,-0.703322376115,0.710871039652,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.06067701017e-08,2.23803509728e-08,-7.17936808022e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244720957295,-0.000179493403684,9.81000777946,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119169000000,11621,119167750000,RH_EXTIMU,2.30227539876e-06,1.53092203255e-05,-0.70332243991,0.710870976535,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.50239199347e-08,1.33847848463e-08,-7.17929145833e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245249561589,-0.000177847119323,9.81000235965,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119174000000,11622,119170250000,RH_EXTIMU,2.302333864e-06,1.53091929601e-05,-0.703322503703,0.710870913419,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.95439362246e-08,1.79888070798e-08,-7.17922320837e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244972819822,-0.000180401850965,9.81000178299,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119174000000,11623,119172750000,RH_EXTIMU,2.30222185152e-06,1.5309204642e-05,-0.703322567497,0.710870850303,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.93764925945e-08,-5.57257639892e-08,-7.17914908923e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246531915235,-0.000177409158786,9.80999088391,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119175250000,11624,119175250000,RH_EXTIMU,2.30229315997e-06,1.53091232615e-05,-0.703322631289,0.710870787188,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.72397819675e-08,-5.50301902451e-09,-7.1790905205e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244937106394,-0.000181123083873,9.80999101119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119177750000,11625,119177750000,RH_EXTIMU,2.30248534972e-06,1.53090123026e-05,-0.703322695081,0.710870724073,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.72627124821e-07,4.56906496704e-08,-7.17901897479e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244336207717,-0.00018236159589,9.81000900797,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119180250000,11626,119180250000,RH_EXTIMU,2.30243437867e-06,1.53090653608e-05,-0.703322758872,0.710870660959,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.79431969141e-08,2.15022678033e-09,-7.17893337984e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245636266701,-0.000177551490232,9.81001016554,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119182750000,11627,119182750000,RH_EXTIMU,2.30238076818e-06,1.53091170985e-05,-0.703322822663,0.710870597846,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.87012150399e-08,-8.58801335335e-11,-7.17885915855e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245237929798,-0.000178349085623,9.81000413055,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119185250000,11628,119185250000,RH_EXTIMU,2.30244817563e-06,1.530911216e-05,-0.703322886453,0.710870534734,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.2010594835e-08,3.57742795198e-08,-7.17878161573e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244650129197,-0.000180026377129,9.8100122384,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119187750000,11629,119187750000,RH_EXTIMU,2.30227711491e-06,1.53092151464e-05,-0.703322950242,0.710870471622,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.543302908e-07,-3.70252646447e-08,-7.17871249307e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246408327855,-0.000176001945639,9.80998479576,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119191500000,11630,119190250000,RH_EXTIMU,2.30244747574e-06,1.53090673372e-05,-0.70332301403,0.71087040851,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.80947163308e-07,1.24518337787e-08,-7.1786578835e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244365746065,-0.000183288554385,9.80999243926,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119192750000,11631,119192750000,RH_EXTIMU,2.30256459416e-06,1.53089846519e-05,-0.703323077818,0.710870345399,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.14025872561e-07,1.95302815808e-08,-7.17858819917e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245246258987,-0.000180657862811,9.80999456437,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119195250000,11632,119195250000,RH_EXTIMU,2.30262297749e-06,1.53088855695e-05,-0.703323141606,0.710870282289,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.98493605708e-08,-2.28424569932e-08,-7.17852149273e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245811977246,-0.000180605277712,9.80999526641,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119195250000,11633,119197750000,RH_EXTIMU,2.30262092097e-06,1.53088533341e-05,-0.703323205393,0.71087021918,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.78654922794e-08,-1.88339049975e-08,-7.17844311239e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245328473445,-0.000179255156506,9.81000893383,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119200250000,11634,119200250000,RH_EXTIMU,2.30250466786e-06,1.53089864752e-05,-0.703323269179,0.710870156071,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.40128265109e-07,1.0961455269e-08,-7.17835741662e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245166503387,-0.000176475805306,9.81001187531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119202750000,11635,119202750000,RH_EXTIMU,2.30239372784e-06,1.53090677959e-05,-0.703323332964,0.710870092963,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0794949123e-07,-1.55192171687e-08,-7.1782861542e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245681872695,-0.000177415648867,9.80999390154,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119205250000,11636,119205250000,RH_EXTIMU,2.30252281593e-06,1.53089601352e-05,-0.703323396749,0.710870029855,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34885525685e-07,1.20617504325e-08,-7.17823082509e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244878054315,-0.000182013733534,9.80998893525,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119207750000,11637,119207750000,RH_EXTIMU,2.30262515219e-06,1.53088654717e-05,-0.703323460533,0.710869966748,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12358875134e-07,4.4010336848e-09,-7.17816313411e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245284423447,-0.000180836434259,9.809995072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119210250000,11638,119210250000,RH_EXTIMU,2.30272678711e-06,1.53087964579e-05,-0.703323524317,0.710869903641,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.75279916524e-08,1.85932958902e-08,-7.17808828306e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244862451544,-0.000180922194716,9.81000963734,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119212750000,11639,119212750000,RH_EXTIMU,2.30263548948e-06,1.53088532219e-05,-0.7033235881,0.710869840536,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.296194234e-08,-1.84326064412e-08,-7.17800204666e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245821085511,-0.000177288972324,9.81001038677,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119215250000,11640,119215250000,RH_EXTIMU,2.30257805773e-06,1.53088974058e-05,-0.703323651882,0.71086977743,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.66242755892e-08,-6.53192545089e-09,-7.17792807583e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245290313914,-0.000178412085585,9.81000396786,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119217750000,11641,119217750000,RH_EXTIMU,2.30258694575e-06,1.5308890681e-05,-0.703323715663,0.710869714326,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.73576054742e-09,1.83188781465e-09,-7.17785728013e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245244027738,-0.000179477074136,9.81000027003,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119221500000,11642,119220250000,RH_EXTIMU,2.30260720348e-06,1.53088474048e-05,-0.703323779444,0.710869651222,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.67675584952e-08,-1.25574076657e-08,-7.17778748089e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245571340382,-0.00017978808734,9.80999857744,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119222750000,11643,119222750000,RH_EXTIMU,2.30259597983e-06,1.53088354977e-05,-0.703323843224,0.710869588119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.21417895248e-09,-1.2431279398e-08,-7.17771459836e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245374844807,-0.000179121810338,9.80999844687,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119225250000,11644,119225250000,RH_EXTIMU,2.30266872983e-06,1.53087830897e-05,-0.703323907004,0.710869525016,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.17578098535e-08,1.17845689864e-08,-7.17764965021e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245044363128,-0.000180514756722,9.80999596374,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119227750000,11645,119227750000,RH_EXTIMU,2.30272068719e-06,1.53087409761e-05,-0.703323970783,0.710869461914,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.41408645342e-08,5.93979788665e-09,-7.17757973351e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245231648447,-0.000179975862238,9.80999815722,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119230250000,11646,119230250000,RH_EXTIMU,2.3027435407e-06,1.53087184713e-05,-0.703324034562,0.710869398813,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.65565739113e-08,7.15651672982e-10,-7.177508158e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245286927738,-0.000179528102785,9.8099997197,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119232750000,11647,119232750000,RH_EXTIMU,2.30275743297e-06,1.53087043777e-05,-0.703324098339,0.710869335712,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.6727703664e-08,4.56940753171e-10,-7.17743637001e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245277655663,-0.000179408211762,9.81000019944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119235250000,11648,119235250000,RH_EXTIMU,2.30289498358e-06,1.53087140186e-05,-0.703324162116,0.710869272612,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.36971903906e-08,8.35321547177e-08,-7.17736207107e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243843252669,-0.000180490081974,9.81001258593,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119237750000,11649,119237750000,RH_EXTIMU,2.30287065984e-06,1.53087709633e-05,-0.703324225893,0.710869209512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.49759812454e-08,1.93535254349e-08,-7.1772855744e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245197054535,-0.000178370953051,9.81000384553,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119240250000,11650,119240250000,RH_EXTIMU,2.30287443746e-06,1.53087745857e-05,-0.703324289668,0.710869146414,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.00746440156e-09,4.84081702023e-09,-7.17721405936e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245254015115,-0.000179299866485,9.81000080501,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119244000000,11651,119242750000,RH_EXTIMU,2.30276881556e-06,1.53087236211e-05,-0.703324353444,0.710869083315,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.04936859699e-08,-8.7757194688e-08,-7.17715075816e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246725947372,-0.00017865097518,9.80998043396,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119245250000,11652,119245250000,RH_EXTIMU,2.30294146959e-06,1.53085677793e-05,-0.703324417218,0.710869020217,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.86770674738e-07,9.17421041001e-09,-7.17708467997e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244897405834,-0.000182521804085,9.81000346499,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119247750000,11653,119247750000,RH_EXTIMU,2.30286362041e-06,1.53085814219e-05,-0.703324480992,0.71086895712,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.10513027302e-08,-3.53888775545e-08,-7.17699838527e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024603739059,-0.000177662331515,9.81000860246,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119251500000,11654,119250250000,RH_EXTIMU,2.30280374658e-06,1.53086225559e-05,-0.703324544765,0.710868894024,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.62971441733e-08,-9.6406281513e-09,-7.17692403381e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245289809227,-0.000178333460829,9.81000408578,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119252750000,11655,119252750000,RH_EXTIMU,2.30276403416e-06,1.53086465075e-05,-0.703324608538,0.710868830928,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.51635889689e-08,-8.06818672726e-09,-7.17685519818e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245466697905,-0.000178501691778,9.80999338018,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119255250000,11656,119255250000,RH_EXTIMU,2.30286556476e-06,1.53085786245e-05,-0.70332467231,0.710868767833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.68322364874e-08,1.91776763239e-08,-7.17679471103e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244824681682,-0.000181105098358,9.80999260256,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119260250000,11657,119257750000,RH_EXTIMU,2.30293602309e-06,1.53085228278e-05,-0.703324736081,0.710868704739,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.23610925952e-08,8.56799455262e-09,-7.17672495222e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245233357935,-0.000180200240874,9.80999731626,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119260250000,11658,119260250000,RH_EXTIMU,2.30288205267e-06,1.53084682065e-05,-0.703324799852,0.710868641645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.37725922536e-10,-6.07746353996e-08,-7.17664830853e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246419692279,-0.000178973108901,9.80999982486,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119262750000,11659,119262750000,RH_EXTIMU,2.30287188355e-06,1.53084268782e-05,-0.703324863622,0.710868578551,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.83678710102e-08,-2.85697470103e-08,-7.1765793442e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245433127212,-0.000179601893978,9.80999782821,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119265250000,11660,119265250000,RH_EXTIMU,2.30288627038e-06,1.53084138722e-05,-0.703324927391,0.710868515459,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.63968719739e-08,1.35364285352e-09,-7.17650547669e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245293018319,-0.000179237760425,9.8100021188,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119267750000,11661,119267750000,RH_EXTIMU,2.30285109423e-06,1.53084393236e-05,-0.70332499116,0.710868452367,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.34278108269e-08,-4.6629123178e-09,-7.17643479433e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024538819961,-0.000178413510737,9.80999597643,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119267750000,11662,119270250000,RH_EXTIMU,2.30290481188e-06,1.53084323078e-05,-0.703325054928,0.710868389275,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.5393680332e-08,2.68900723288e-08,-7.17637072442e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244718813583,-0.000179930818651,9.80999469307,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119272750000,11663,119272750000,RH_EXTIMU,2.3031615076e-06,1.53083897595e-05,-0.703325118696,0.710868326184,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.70818896154e-07,1.20890621624e-07,-7.17630423163e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243301722887,-0.00018226107794,9.81000639816,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119276500000,11664,119275250000,RH_EXTIMU,2.30312987499e-06,1.530837984e-05,-0.703325182463,0.710868263094,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.15107985566e-08,-2.27844263708e-08,-7.1762252219e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246306582983,-0.000178642502497,9.81000384091,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119276500000,11665,119277750000,RH_EXTIMU,2.30296498397e-06,1.53083804567e-05,-0.703325246229,0.710868200004,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.32224585659e-08,-9.17717429729e-08,-7.17613498908e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246623718421,-0.000177399911336,9.81001425513,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119276500000,11666,119280250000,RH_EXTIMU,2.30289902997e-06,1.53084656145e-05,-0.703325309994,0.710868136916,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.4525483609e-08,1.19742813139e-08,-7.17605969556e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244686070383,-0.000177911158012,9.810007752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119286500000,11667,119282750000,RH_EXTIMU,2.30290083237e-06,1.53084910786e-05,-0.703325373759,0.710868073827,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.24054840821e-08,1.61505849298e-08,-7.17598787027e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024510020849,-0.000179158911439,9.81000144684,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119286500000,11668,119285250000,RH_EXTIMU,2.30285805284e-06,1.53084990858e-05,-0.703325437523,0.71086801074,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.79366723027e-08,-1.88615511927e-08,-7.1759221575e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245756895611,-0.000178463549432,9.80998630985,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119290250000,11669,119287750000,RH_EXTIMU,2.3030312283e-06,1.53083682822e-05,-0.703325501287,0.710867947653,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.72979034443e-07,2.37068390366e-08,-7.17587010737e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244634566879,-0.000182554880031,9.80998601141,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119290250000,11670,119290250000,RH_EXTIMU,2.3032314446e-06,1.53082624523e-05,-0.70332556505,0.710867884566,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.74305328058e-07,5.31240012947e-08,-7.17579951967e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244519430299,-0.0001818768111,9.8100037224,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119295250000,11671,119292750000,RH_EXTIMU,2.30322843454e-06,1.53082758147e-05,-0.703325628812,0.71086782148,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.33318603105e-09,6.56058164531e-09,-7.17572414977e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245286810595,-0.000178754351684,9.81000212436,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119295250000,11672,119295250000,RH_EXTIMU,2.30318889616e-06,1.53082364811e-05,-0.703325692574,0.710867758395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.43330930894e-10,-4.39603974458e-08,-7.17563864652e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246214514056,-0.000179125234949,9.81001452015,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119297750000,11673,119297750000,RH_EXTIMU,2.30308125688e-06,1.5308266889e-05,-0.703325756335,0.710867695311,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.74260982374e-08,-4.26164663402e-08,-7.17556038766e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245757342594,-0.000177899196889,9.81000561759,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119300250000,11674,119300250000,RH_EXTIMU,2.30312400508e-06,1.530826075e-05,-0.703325820095,0.710867632227,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.86618997121e-08,2.12166151426e-08,-7.17550049808e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244716024411,-0.000179984553147,9.80998941912,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119302750000,11675,119302750000,RH_EXTIMU,2.30324981861e-06,1.53081755153e-05,-0.703325883855,0.710867569143,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.20404696058e-07,2.29729294698e-08,-7.17543634473e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245020220241,-0.000181171335039,9.8099940744,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119305250000,11676,119305250000,RH_EXTIMU,2.30313858771e-06,1.5308132739e-05,-0.703325947614,0.710867506061,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.82907172303e-08,-8.62568469646e-08,-7.17536678286e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246816771677,-0.000178094563723,9.80998628923,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119307750000,11677,119307750000,RH_EXTIMU,2.30320018083e-06,1.53080977058e-05,-0.703326011373,0.710867442978,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.56364944994e-08,1.53879205754e-08,-7.17529597131e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244767662023,-0.000179983511845,9.81000364391,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119310250000,11678,119310250000,RH_EXTIMU,2.30330163811e-06,1.53081583307e-05,-0.703326075131,0.710867379897,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.44839244127e-08,9.22180940548e-08,-7.17521245753e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243783224034,-0.000179481588876,9.81002242446,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119312750000,11679,119312750000,RH_EXTIMU,2.30306102173e-06,1.5308314293e-05,-0.703326138888,0.710867316816,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.23693921196e-07,-4.60355628779e-08,-7.17513108264e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246547392092,-0.000174840181039,9.80999466292,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119315250000,11680,119315250000,RH_EXTIMU,2.30333778733e-06,1.53081451808e-05,-0.703326202644,0.710867253736,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.53444725908e-07,6.02071965479e-08,-7.17507626514e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243639678845,-0.000185172992074,9.81000704015,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119317750000,11681,119317750000,RH_EXTIMU,2.30328342351e-06,1.53081476868e-05,-0.7033262664,0.710867190656,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.14293445666e-08,-2.85082598003e-08,-7.17500614239e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246105411874,-0.000177717700197,9.80998166422,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119320250000,11682,119320250000,RH_EXTIMU,2.30345078531e-06,1.53080456959e-05,-0.703326330156,0.710867127577,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.53460899765e-07,3.68214198502e-08,-7.17494286081e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244569803743,-0.000181926118082,9.81000165316,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119322750000,11683,119322750000,RH_EXTIMU,2.30339220711e-06,1.53080812161e-05,-0.70332639391,0.710867064499,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.24018629033e-08,-1.21045763181e-08,-7.17485840564e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245704976202,-0.000177715076167,9.81000768474,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119326500000,11684,119325250000,RH_EXTIMU,2.30321613141e-06,1.53081302627e-05,-0.703326457664,0.710867001421,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.26832787511e-07,-7.05234296037e-08,-7.1747823467e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246747253616,-0.000176716841127,9.80999644229,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119327750000,11685,119327750000,RH_EXTIMU,2.30318172122e-06,1.53080584803e-05,-0.703326521418,0.710866938344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.17172992857e-08,-5.95284682304e-08,-7.17471466193e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245776695901,-0.000179941279989,9.80999603909,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119330250000,11686,119330250000,RH_EXTIMU,2.30325888673e-06,1.53079560093e-05,-0.70332658517,0.710866875268,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.02436996473e-07,-1.4201602257e-08,-7.17464737246e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245399495862,-0.000180975319616,9.80999597765,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119332750000,11687,119332750000,RH_EXTIMU,2.3033569668e-06,1.53079356534e-05,-0.703326648922,0.710866812192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.81279332261e-08,4.42645627933e-08,-7.17456915276e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244519363044,-0.000180043259283,9.81001245171,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119335250000,11688,119335250000,RH_EXTIMU,2.30317632148e-06,1.53080311878e-05,-0.703326712674,0.710866749117,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.55588376617e-07,-4.66573795968e-08,-7.1745003158e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246437695484,-0.000175983770273,9.80998365445,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119337750000,11689,119337750000,RH_EXTIMU,2.30329512696e-06,1.53079110163e-05,-0.703326776425,0.710866686042,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.36076673551e-07,-8.38479856376e-10,-7.1744481023e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244793378711,-0.000182202317089,9.80998544875,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119340250000,11690,119340250000,RH_EXTIMU,2.30343461947e-06,1.53077727161e-05,-0.703326840175,0.710866622968,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.58041592029e-07,4.91587060364e-10,-7.17437828354e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245337687347,-0.000181693170379,9.80999880051,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119342750000,11691,119342750000,RH_EXTIMU,2.30347106461e-06,1.53077152206e-05,-0.703326903925,0.710866559894,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.3973538453e-08,-1.15361018233e-08,-7.17429865711e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245412099683,-0.000179866657683,9.81001034341,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119345250000,11692,119345250000,RH_EXTIMU,2.30342752664e-06,1.53077684889e-05,-0.703326967674,0.710866496822,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.38348808311e-08,6.45112922272e-09,-7.17421906165e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245216089067,-0.000178031597148,9.81000749297,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119347750000,11693,119347750000,RH_EXTIMU,2.30349171412e-06,1.53077764144e-05,-0.703327031422,0.710866433749,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.29404979295e-08,4.12779368475e-08,-7.17414521704e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244404774841,-0.000180140686106,9.81001151317,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119350250000,11694,119350250000,RH_EXTIMU,2.30339931723e-06,1.53078821034e-05,-0.703327095169,0.710866370678,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.11115716798e-07,8.77132503058e-09,-7.17406343323e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245478098887,-0.000176741258242,9.81000568719,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119352750000,11695,119352750000,RH_EXTIMU,2.30344236867e-06,1.53078919565e-05,-0.703327158916,0.710866307607,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.98359893438e-08,3.04816946534e-08,-7.17399686513e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244710974955,-0.000180003843765,9.80999972567,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119355250000,11696,119355250000,RH_EXTIMU,2.30337269043e-06,1.53078857699e-05,-0.703327222663,0.710866244537,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.52477232708e-08,-4.20686002118e-08,-7.17392909193e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246356749665,-0.000178072036597,9.80998652735,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119357750000,11697,119357750000,RH_EXTIMU,2.30357713877e-06,1.53077516648e-05,-0.703327286408,0.710866181467,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.92621049231e-07,3.94255061825e-08,-7.17386593225e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243878459031,-0.000183286080066,9.8100059482,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119360250000,11698,119360250000,RH_EXTIMU,2.30343361309e-06,1.53077994107e-05,-0.703327350153,0.710866118398,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.07589968511e-07,-5.29487836576e-08,-7.17378110355e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247093304603,-0.000176170453991,9.80999654072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119362750000,11699,119362750000,RH_EXTIMU,2.30350914153e-06,1.53076716459e-05,-0.703327413898,0.71086605533,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.15737683382e-07,-2.9507046165e-08,-7.17371959614e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024494425067,-0.00018197715633,9.80999896044,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119362750000,11700,119365250000,RH_EXTIMU,2.3035541118e-06,1.53076751945e-05,-0.703327477641,0.710865992262,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.44744689365e-08,2.79759741293e-08,-7.17364439473e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244976564889,-0.000179109497171,9.81000312052,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119367750000,11701,119367750000,RH_EXTIMU,2.30357287156e-06,1.53077227524e-05,-0.703327541385,0.710865929195,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.51936825539e-08,3.82561216365e-08,-7.17357338893e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244537646711,-0.000178864894566,9.81000131946,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119370250000,11702,119370250000,RH_EXTIMU,2.30355833338e-06,1.53077778778e-05,-0.703327605127,0.710865866128,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.83878847309e-08,2.38241717513e-08,-7.17350706669e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245306276799,-0.000178277290351,9.80999035984,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119372750000,11703,119372750000,RH_EXTIMU,2.30381493145e-06,1.53076778491e-05,-0.703327668869,0.710865803062,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.03104637437e-07,8.81472582826e-08,-7.17344016148e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243665902288,-0.000183093667122,9.81000974922,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119376500000,11704,119375250000,RH_EXTIMU,2.30367499678e-06,1.53077150238e-05,-0.70332773261,0.710865739997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.95997922575e-08,-5.6940136786e-08,-7.17336301516e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246827322359,-0.000176734752273,9.8099921705,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119377750000,11705,119377750000,RH_EXTIMU,2.30367329466e-06,1.53076307385e-05,-0.703327796351,0.710865676932,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.7352973366e-08,-4.82353187287e-08,-7.1732988388e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245582814214,-0.000180395724414,9.80999357295,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119380250000,11706,119380250000,RH_EXTIMU,2.30385132448e-06,1.53076242395e-05,-0.703327860091,0.710865613868,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.05797737161e-07,9.71295665086e-08,-7.17321358917e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243568049357,-0.000180745072349,9.81002869088,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119382750000,11707,119382750000,RH_EXTIMU,2.30366652543e-06,1.53077216675e-05,-0.70332792383,0.710865550805,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.59016097738e-07,-4.79180791107e-08,-7.17314024481e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246257192343,-0.000176541755251,9.80999140602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119385250000,11708,119385250000,RH_EXTIMU,2.30366158201e-06,1.53077052446e-05,-0.703327987569,0.710865487742,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.32606137504e-09,-1.14662672703e-08,-7.17307382798e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245513525653,-0.000179190039533,9.80999236161,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119387750000,11709,119387750000,RH_EXTIMU,2.30386003564e-06,1.53075740927e-05,-0.703328051307,0.71086542468,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.87550053317e-07,3.77321287011e-08,-7.17300842433e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244245320753,-0.000182971781137,9.8100061033,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119391500000,11710,119390250000,RH_EXTIMU,2.30382986991e-06,1.53076169244e-05,-0.703328115044,0.710865361619,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.03580347927e-08,8.03970110221e-09,-7.17292322514e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245550667125,-0.000177736723274,9.81000954214,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119392750000,11711,119392750000,RH_EXTIMU,2.3037373709e-06,1.53076476678e-05,-0.703328178781,0.710865298558,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.90049115435e-08,-3.39073809334e-08,-7.17285047406e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245840797249,-0.000178102704036,9.8099987969,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119395250000,11712,119395250000,RH_EXTIMU,2.30387312238e-06,1.53076513105e-05,-0.703328242517,0.710865235497,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.60479812004e-08,7.91085903431e-08,-7.17278386851e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243766554879,-0.000180637755288,9.81000445185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119397750000,11713,119397750000,RH_EXTIMU,2.30391110158e-06,1.53076660662e-05,-0.703328306252,0.710865172438,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.41927162521e-08,3.04157034026e-08,-7.17271154101e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245042485995,-0.000179323655897,9.81000039264,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119400250000,11714,119400250000,RH_EXTIMU,2.30368220482e-06,1.53076135514e-05,-0.703328369987,0.710865109379,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.97269210654e-08,-1.58001673666e-07,-7.17263995814e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000248137771084,-0.000177204667965,9.80998215579,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119402750000,11715,119402750000,RH_EXTIMU,2.30370487858e-06,1.53074736233e-05,-0.703328433721,0.71086504632,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.25233635169e-08,-6.61635091283e-08,-7.17257311792e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245992246548,-0.00018071705414,9.80999605618,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119405250000,11716,119405250000,RH_EXTIMU,2.30377185302e-06,1.53074049403e-05,-0.703328497454,0.710864983263,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.76299197545e-08,-7.20734018354e-10,-7.17250162342e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024485708162,-0.000180531534543,9.81000160579,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119407750000,11717,119407750000,RH_EXTIMU,2.3038557369e-06,1.53074199357e-05,-0.703328561187,0.710864920205,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.01634254858e-08,5.63808283172e-08,-7.17242729114e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244487645246,-0.000179569033751,9.81000897331,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119410250000,11718,119410250000,RH_EXTIMU,2.30374510891e-06,1.53074170074e-05,-0.70332862492,0.710864857149,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.03689445002e-08,-6.3256816616e-08,-7.1723634666e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246496763824,-0.00017819117618,9.80998021786,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119412750000,11719,119412750000,RH_EXTIMU,2.30393125135e-06,1.53073327586e-05,-0.703328688651,0.710864794093,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.54158065837e-07,5.74785276312e-08,-7.17229215938e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244159502142,-0.000181678719292,9.81001162561,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119415250000,11720,119415250000,RH_EXTIMU,2.30391412718e-06,1.53073917086e-05,-0.703328752382,0.710864731038,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.20107048954e-08,2.45439619037e-08,-7.17220979664e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245013102685,-0.000178232060066,9.8100108198,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119417750000,11721,119417750000,RH_EXTIMU,2.30382635715e-06,1.53074790101e-05,-0.703328816112,0.710864667983,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.81387712081e-08,9.17396741329e-10,-7.17214135165e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245390436102,-0.000177350651513,9.80999079298,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119420250000,11722,119420250000,RH_EXTIMU,2.30398107352e-06,1.53073884712e-05,-0.703328879842,0.710864604929,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.39825434912e-07,3.62191878894e-08,-7.17208767424e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244529510517,-0.000182060634915,9.80998799331,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119422750000,11723,119422750000,RH_EXTIMU,2.30402529755e-06,1.53073001026e-05,-0.703328943571,0.710864541875,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.57682435011e-08,-2.47165822483e-08,-7.17200856424e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246317001312,-0.000179752279358,9.81000244109,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119425250000,11724,119425250000,RH_EXTIMU,2.30396903054e-06,1.53072197686e-05,-0.7033290073,0.710864478822,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.40990151476e-08,-7.6689965526e-08,-7.17193917365e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246049309444,-0.000179649328111,9.80999569515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119427750000,11725,119427750000,RH_EXTIMU,2.30395251002e-06,1.5307186608e-05,-0.703329071027,0.71086441577,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0159813157e-08,-2.74990109669e-08,-7.17186351676e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245734784332,-0.000179006788568,9.8100037373,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119430250000,11726,119430250000,RH_EXTIMU,2.30394567493e-06,1.53071961696e-05,-0.703329134755,0.710864352718,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.37040248691e-09,2.24638559566e-09,-7.17178755586e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244793098346,-0.000179186221584,9.81000790961,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119434000000,11727,119432750000,RH_EXTIMU,2.30391622323e-06,1.53072817528e-05,-0.703329198481,0.710864289667,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.40069057333e-08,3.27537410343e-08,-7.17171138654e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244963667679,-0.00017783781551,9.81000361907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119435250000,11728,119435250000,RH_EXTIMU,2.30398335355e-06,1.53072485581e-05,-0.703329262207,0.710864226617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.77504732773e-08,1.95488654115e-08,-7.1716417534e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244957918176,-0.000180589261813,9.81000352925,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119437750000,11729,119437750000,RH_EXTIMU,2.30402418364e-06,1.53072315358e-05,-0.703329325932,0.710864163568,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.36941289331e-08,1.39477948943e-08,-7.17156717666e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245010658267,-0.000179554254395,9.81000460914,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119440250000,11730,119440250000,RH_EXTIMU,2.30395626302e-06,1.53072858116e-05,-0.703329389656,0.710864100518,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.82682893498e-08,-6.69567289315e-09,-7.17149412419e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245776433985,-0.000177654223242,9.80999631206,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119442750000,11731,119442750000,RH_EXTIMU,2.30403008879e-06,1.53072004218e-05,-0.70332945338,0.71086403747,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.09263292536e-08,-6.36671037091e-09,-7.17142729041e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245007717621,-0.000181194299046,9.81000096707,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119445250000,11732,119445250000,RH_EXTIMU,2.30404515784e-06,1.53072028613e-05,-0.703329517103,0.710863974422,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.09359974542e-09,1.05207112161e-08,-7.17135133649e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024523709078,-0.00017892816689,9.81000335191,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119447750000,11733,119447750000,RH_EXTIMU,2.30399458724e-06,1.53072068948e-05,-0.703329580826,0.710863911375,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.01320393934e-08,-2.55057950188e-08,-7.17128010004e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245879474664,-0.000178532304735,9.80999469607,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119450250000,11734,119450250000,RH_EXTIMU,2.30409551557e-06,1.53071143733e-05,-0.703329644548,0.710863848328,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.10352054825e-07,4.82716537843e-09,-7.17121649366e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244812404468,-0.000181341577317,9.80999796157,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119452750000,11735,119452750000,RH_EXTIMU,2.30416093507e-06,1.53070907681e-05,-0.703329708269,0.710863785283,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.13818395734e-08,2.40396504033e-08,-7.17113793574e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245076382035,-0.000179867984276,9.81001077323,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119455250000,11736,119455250000,RH_EXTIMU,2.30393520252e-06,1.53071885279e-05,-0.70332977199,0.710863722237,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.8248149717e-07,-7.07617955036e-08,-7.17105847424e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246724358233,-0.000175250676392,9.80999091634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119457750000,11737,119457750000,RH_EXTIMU,2.30409439592e-06,1.530709526e-05,-0.70332983571,0.710863659192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.43906841822e-07,3.71863276106e-08,-7.17101231463e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244134044486,-0.000182482936665,9.80998474924,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119460250000,11738,119460250000,RH_EXTIMU,2.30434250501e-06,1.53070284766e-05,-0.703329899429,0.710863596148,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.79570494249e-07,1.02277466866e-07,-7.1709351113e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243777902524,-0.000181848809065,9.810015981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119462750000,11739,119462750000,RH_EXTIMU,2.30426000176e-06,1.53071194879e-05,-0.703329963148,0.710863533105,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.72311569891e-08,5.99026920142e-09,-7.17085257842e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245427318845,-0.000177246355406,9.8100073359,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119464000000,11740,119465250000,RH_EXTIMU,2.30423208089e-06,1.53071526837e-05,-0.703330026866,0.710863470062,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.36599093497e-08,3.82259448525e-09,-7.17077979134e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245223019395,-0.000178746990654,9.81000266511,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119464000000,11741,119467750000,RH_EXTIMU,2.30399875263e-06,1.53070841349e-05,-0.703330090584,0.71086340702,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.32251974561e-08,-1.69613960569e-07,-7.1707122298e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000248253063262,-0.000177455105705,9.809977069,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119470250000,11742,119470250000,RH_EXTIMU,2.30423291184e-06,1.53068708779e-05,-0.703330154301,0.710863343978,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.54052636391e-07,1.11302838527e-08,-7.17064778398e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244264594297,-0.000184034399557,9.8100089419,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119472750000,11743,119472750000,RH_EXTIMU,2.30407314901e-06,1.5306980969e-05,-0.703330218017,0.710863280937,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.51903493159e-07,-2.66305252473e-08,-7.17056491311e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246293862532,-0.000175185768829,9.80999427207,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119475250000,11744,119475250000,RH_EXTIMU,2.30419091796e-06,1.53069226362e-05,-0.703330281732,0.710863217897,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.00692319715e-07,3.37455733721e-08,-7.17051448084e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244303171653,-0.000181690618206,9.8099876062,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119477750000,11745,119477750000,RH_EXTIMU,2.30431044514e-06,1.53068305681e-05,-0.703330345448,0.710863154857,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.20673858413e-07,1.55498904009e-08,-7.1704469184e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245205890516,-0.000180939506822,9.80999457708,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119480250000,11746,119480250000,RH_EXTIMU,2.30434204957e-06,1.53067950212e-05,-0.703330409162,0.710863091818,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.88705006463e-08,-1.77797503785e-09,-7.17037502377e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245334447543,-0.000179552185094,9.80999925998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119482750000,11747,119482750000,RH_EXTIMU,2.30436463212e-06,1.53067798695e-05,-0.703330472876,0.710863028779,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.22642417366e-08,4.74421582527e-09,-7.17030086253e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245167209446,-0.000179483733421,9.81000480945,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119485250000,11748,119485250000,RH_EXTIMU,2.30440092354e-06,1.53068283946e-05,-0.703330536589,0.710862965741,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.76837981514e-09,4.86701406385e-08,-7.17022529714e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244215449478,-0.000179044739824,9.81000809292,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119487750000,11749,119487750000,RH_EXTIMU,2.30435021957e-06,1.53068714757e-05,-0.703330600301,0.710862902704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.2178629666e-08,-3.37507977332e-09,-7.17015072512e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246133703293,-0.000178027882598,9.80999917295,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119490250000,11750,119490250000,RH_EXTIMU,2.30433851399e-06,1.53067875721e-05,-0.703330664013,0.710862839667,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.1449106008e-08,-5.36470063672e-08,-7.17008014871e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245582669731,-0.000180143530797,9.80999837892,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119492750000,11751,119492750000,RH_EXTIMU,2.30449912229e-06,1.53067543782e-05,-0.703330727724,0.710862776631,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.10909768742e-07,7.21460238305e-08,-7.17001238403e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243982298512,-0.000181214800787,9.81000731222,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119495250000,11752,119495250000,RH_EXTIMU,2.30445434194e-06,1.53067888215e-05,-0.703330791435,0.710862713595,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.39498028092e-08,-4.95431415869e-09,-7.16992892092e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245748094025,-0.000177953272507,9.8100076032,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119497750000,11753,119497750000,RH_EXTIMU,2.3044021738e-06,1.53068136972e-05,-0.703330855145,0.710862650561,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.2767839374e-08,-1.45521534591e-08,-7.16985899771e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245425576367,-0.000178535565834,9.80999767252,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119500250000,11754,119500250000,RH_EXTIMU,2.30447146154e-06,1.5306797559e-05,-0.703330918854,0.710862587526,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.93800288232e-08,3.04625434683e-08,-7.16978703682e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244750290456,-0.000180014878986,9.81000534189,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119502750000,11755,119502750000,RH_EXTIMU,2.30442340286e-06,1.53068269659e-05,-0.703330982562,0.710862524493,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.29803926699e-08,-9.66307787801e-09,-7.16971580436e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245602893295,-0.000178176403054,9.80999383889,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119505250000,11756,119505250000,RH_EXTIMU,2.30457820098e-06,1.53067053159e-05,-0.70333104627,0.71086246146,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.57376670095e-07,1.85727184212e-08,-7.16964930286e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244765927323,-0.000182430599812,9.81000651301,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119507750000,11757,119507750000,RH_EXTIMU,2.30447044739e-06,1.53067302107e-05,-0.703331109977,0.710862398428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.43894878339e-08,-4.5817342519e-08,-7.16955892574e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246290949994,-0.000177157602976,9.81001132405,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119510250000,11758,119510250000,RH_EXTIMU,2.30440417769e-06,1.53068093902e-05,-0.703331173684,0.710862335396,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.13421174153e-08,8.39534776287e-09,-7.16950021959e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244905074154,-0.000177865208687,9.80998559653,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119512750000,11759,119512750000,RH_EXTIMU,2.30453063447e-06,1.53066999135e-05,-0.70333123739,0.710862272365,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34409701336e-07,9.54890806792e-09,-7.16943452416e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245239191973,-0.000181762436215,9.80999749513,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119515250000,11760,119515250000,RH_EXTIMU,2.30458016295e-06,1.53066086908e-05,-0.703331301095,0.710862209335,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.03904494422e-08,-2.33550929818e-08,-7.16935730084e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245462196727,-0.000180320096638,9.81000553394,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119517750000,11761,119517750000,RH_EXTIMU,2.30450387064e-06,1.53066416211e-05,-0.7033313648,0.710862146305,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.10190645203e-08,-2.35455489203e-08,-7.16928214664e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246043188774,-0.000177630429853,9.8099991645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119520250000,11762,119520250000,RH_EXTIMU,2.30437141923e-06,1.53066067555e-05,-0.703331428504,0.710862083276,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.48098736272e-08,-9.3699078439e-08,-7.16921935783e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246486660923,-0.000178349386516,9.80998163816,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119521500000,11763,119522750000,RH_EXTIMU,2.30463563054e-06,1.53065863277e-05,-0.703331492208,0.710862020247,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.62644531396e-07,1.37699768533e-07,-7.16916220514e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242564351525,-0.000181932808194,9.80999913102,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119525250000,11764,119525250000,RH_EXTIMU,2.30455710714e-06,1.53065822302e-05,-0.70333155591,0.710861957219,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.14536614374e-08,-4.5858242544e-08,-7.16908493394e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024712964604,-0.000177783799506,9.80999287286,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119527750000,11765,119527750000,RH_EXTIMU,2.30454524106e-06,1.53064622445e-05,-0.703331619613,0.710861894191,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.16599195265e-08,-7.42569038345e-08,-7.16901397317e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245630569342,-0.000180587981616,9.80999984992,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119530250000,11766,119530250000,RH_EXTIMU,2.30473434493e-06,1.53064127143e-05,-0.703331683314,0.710861831165,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.36306538066e-07,7.88892280545e-08,-7.1689381748e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024378080386,-0.000181703081815,9.8100217243,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119532750000,11767,119532750000,RH_EXTIMU,2.30449977033e-06,1.53065954503e-05,-0.703331747015,0.710861768139,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.35323048352e-07,-2.74126996745e-08,-7.16884061801e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246302416748,-0.000174181323118,9.81001178203,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119539000000,11768,119535250000,RH_EXTIMU,2.30449890696e-06,1.53066171738e-05,-0.703331810715,0.710861705113,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.18178691062e-08,1.25225020431e-08,-7.16877992274e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244830274889,-0.000179662930878,9.80999658414,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119539000000,11769,119537750000,RH_EXTIMU,2.30459713811e-06,1.53065786816e-05,-0.703331874415,0.710861642089,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.84174984426e-08,3.40354436919e-08,-7.16871701676e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244638815485,-0.000180586436721,9.80998990693,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119540250000,11770,119540250000,RH_EXTIMU,2.30478356526e-06,1.53064178983e-05,-0.703331938114,0.710861579064,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.97382525815e-07,1.41147231989e-08,-7.16865817257e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245395840962,-0.000182618391622,9.80999312295,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119542750000,11771,119542750000,RH_EXTIMU,2.30472880453e-06,1.53063355796e-05,-0.703332001812,0.710861516041,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.60722688422e-08,-7.69714716644e-08,-7.1685761012e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246543550419,-0.000178855193813,9.81000264114,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119545250000,11772,119545250000,RH_EXTIMU,2.30480680295e-06,1.53063950987e-05,-0.70333206551,0.710861453018,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17636728299e-08,7.83891963288e-08,-7.16850266764e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024357270155,-0.000179319384644,9.8100124907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119547750000,11773,119547750000,RH_EXTIMU,2.30460411849e-06,1.53064277858e-05,-0.703332129206,0.710861389995,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.32760201203e-07,-9.48005042546e-08,-7.16841514216e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247361361854,-0.000176670621946,9.81000556517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119550250000,11774,119550250000,RH_EXTIMU,2.30449991768e-06,1.53064816315e-05,-0.703332192903,0.710861326974,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.86588047635e-08,-2.73545156322e-08,-7.16835939887e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245239057058,-0.000177742037095,9.80997870723,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119552750000,11775,119552750000,RH_EXTIMU,2.30485390063e-06,1.53063414126e-05,-0.703332256599,0.710861263953,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.81098726151e-07,1.20087441256e-07,-7.16829660589e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243256361082,-0.000184276143923,9.81000796566,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119555250000,11776,119555250000,RH_EXTIMU,2.30472817956e-06,1.53063281822e-05,-0.703332320294,0.710861200932,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.31556868162e-08,-7.76087391987e-08,-7.16822181822e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246927243835,-0.00017755029837,9.80998892082,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119557750000,11777,119557750000,RH_EXTIMU,2.30476308722e-06,1.53062606019e-05,-0.703332383988,0.710861137912,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.87728367708e-08,-1.81365510303e-08,-7.168154469e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245347704089,-0.000180136120788,9.80999752652,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119560250000,11778,119560250000,RH_EXTIMU,2.3047857986e-06,1.53062299891e-05,-0.703332447682,0.710861074893,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.10365938338e-08,-3.97598542065e-09,-7.16808299035e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245297250652,-0.000179519260197,9.80999950218,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119562750000,11779,119562750000,RH_EXTIMU,2.3047609668e-06,1.5306233047e-05,-0.703332511375,0.710861011874,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.49460005091e-08,-1.15788212278e-08,-7.16800965185e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002455235415,-0.00017863878774,9.8100005003,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119566500000,11780,119565250000,RH_EXTIMU,2.30474409945e-06,1.53062508343e-05,-0.703332575068,0.710860948856,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.87044671097e-08,1.27896689658e-09,-7.16793662998e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245117235559,-0.000178855224014,9.81000030714,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119569000000,11781,119567750000,RH_EXTIMU,2.30480753262e-06,1.53062191555e-05,-0.70333263876,0.710860885839,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.47944014249e-08,1.83305423554e-08,-7.16787031335e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244993913421,-0.000180153949694,9.80999731986,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119570250000,11782,119570250000,RH_EXTIMU,2.30485253748e-06,1.53061860797e-05,-0.703332702451,0.710860822822,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.51004910553e-08,7.1670655964e-09,-7.16780015088e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245219862408,-0.000179794266971,9.80999861735,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119572750000,11783,119572750000,RH_EXTIMU,2.30493525194e-06,1.53061503961e-05,-0.703332766142,0.710860759806,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.80128020945e-08,2.69019707075e-08,-7.16771784908e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244928260756,-0.000180209112643,9.81001775033,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119575250000,11784,119575250000,RH_EXTIMU,2.30484063088e-06,1.53062154261e-05,-0.703332829832,0.71086069679,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.95040424097e-08,-1.56040552847e-08,-7.16763816025e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245533194062,-0.000177567710515,9.81000648715,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119577750000,11785,119577750000,RH_EXTIMU,2.30482855385e-06,1.53062286698e-05,-0.703332893521,0.710860633775,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.34237935317e-08,1.39038445552e-09,-7.16756683956e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245205989067,-0.000179081570625,9.81000149069,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119582750000,11786,119580250000,RH_EXTIMU,2.30484835664e-06,1.53062253771e-05,-0.70333295721,0.710860570761,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.40103785047e-08,9.92401113627e-09,-7.1675106814e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244987209722,-0.000179478071987,9.8099806972,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119582750000,11787,119582750000,RH_EXTIMU,2.30500864449e-06,1.53061116934e-05,-0.703333020898,0.710860507747,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.56015905261e-07,2.61921323579e-08,-7.16744885947e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244963394819,-0.000181685036913,9.80999203694,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119587750000,11788,119585250000,RH_EXTIMU,2.30506345264e-06,1.53060555745e-05,-0.703333084586,0.710860444734,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.36410072627e-08,-4.21295513037e-10,-7.167377819e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024535101003,-0.000179894909849,9.80999796439,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119587750000,11789,119587750000,RH_EXTIMU,2.30517346279e-06,1.53060622594e-05,-0.703333148273,0.710860381722,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.96961494742e-08,6.63547875593e-08,-7.16730069313e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244139937694,-0.000180035464161,9.81001414423,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119590250000,11790,119590250000,RH_EXTIMU,2.30508806517e-06,1.53061199549e-05,-0.703333211959,0.71086031871,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.01319010145e-08,-1.45855166521e-08,-7.16722191768e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245859289302,-0.00017765552688,9.81000329437,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119592750000,11791,119592750000,RH_EXTIMU,2.30509956413e-06,1.53060678034e-05,-0.703333275644,0.710860255699,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.67792626695e-08,-2.25337598105e-08,-7.16714840247e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245408878422,-0.00018010190418,9.81000648572,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119595250000,11792,119595250000,RH_EXTIMU,2.30509872933e-06,1.53061112627e-05,-0.703333339329,0.710860192688,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.40318420256e-08,2.489920011e-08,-7.16707013684e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244703593082,-0.00017852900614,9.81000957237,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119597750000,11793,119597750000,RH_EXTIMU,2.30493307174e-06,1.53062148727e-05,-0.703333403013,0.710860129678,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.51609424334e-07,-3.36340893959e-08,-7.16699636258e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246484850591,-0.000176045192916,9.80999008239,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119600250000,11794,119600250000,RH_EXTIMU,2.30503916412e-06,1.53060558791e-05,-0.703333466697,0.710860066669,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.50689913126e-07,-3.00690394389e-08,-7.16693807727e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245135406434,-0.000182529931676,9.80999416539,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119602750000,11795,119602750000,RH_EXTIMU,2.30506572117e-06,1.53060058864e-05,-0.70333353038,0.71086000366,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.41278856426e-08,-1.28333771547e-08,-7.16686218023e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024568206826,-0.000179354087564,9.81000072443,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119605250000,11796,119605250000,RH_EXTIMU,2.3050411606e-06,1.53059623889e-05,-0.703333594062,0.710859940652,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.14032299394e-08,-3.79018005185e-08,-7.16678894848e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245826015075,-0.000179275991822,9.81000008501,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119607750000,11797,119607750000,RH_EXTIMU,2.30497618289e-06,1.53059755057e-05,-0.703333657744,0.710859877645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.34364461908e-08,-2.84473946899e-08,-7.16672152938e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245668158128,-0.000178022606696,9.80998903586,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119610250000,11798,119610250000,RH_EXTIMU,2.3052848331e-06,1.5305846144e-05,-0.703333721425,0.710859814638,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.49209130556e-07,1.00754914803e-07,-7.1666609728e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243028255606,-0.000184410566292,9.81001037513,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119612750000,11799,119612750000,RH_EXTIMU,2.30518891959e-06,1.53059195645e-05,-0.703333785105,0.710859751632,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.49602044463e-08,-1.15599568704e-08,-7.16656745648e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246335508739,-0.000176324621797,9.81001123603,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119615250000,11800,119615250000,RH_EXTIMU,2.30514324311e-06,1.53059972194e-05,-0.703333848785,0.710859688626,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.87735885597e-08,1.91148027426e-08,-7.16649519957e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244667035801,-0.00017828134462,9.81000655943,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119621500000,11801,119617750000,RH_EXTIMU,2.30523371993e-06,1.53060235454e-05,-0.703333912464,0.710859625621,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.75362344866e-08,6.65336358682e-08,-7.16642988138e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244187923072,-0.000180029947392,9.80999816062,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119621500000,11802,119620250000,RH_EXTIMU,2.30513555755e-06,1.53060238387e-05,-0.703333976142,0.710859562617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.50928591927e-08,-5.44119005855e-08,-7.16635859096e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246521184326,-0.000177724612522,9.80998789719,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119622750000,11803,119622750000,RH_EXTIMU,2.3050921188e-06,1.53059495767e-05,-0.70333403982,0.710859499613,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.79776291468e-08,-6.60194037489e-08,-7.16630127883e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246530770412,-0.000179219779416,9.80997876934,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119625250000,11804,119625250000,RH_EXTIMU,2.30528915437e-06,1.53057338263e-05,-0.703334103498,0.71085943661,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.34343241224e-07,-1.11750610041e-08,-7.16623335043e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244656352119,-0.000183831975127,9.81000884661,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119627750000,11805,119627750000,RH_EXTIMU,2.30530483795e-06,1.53057592602e-05,-0.703334167174,0.710859373608,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.49587536059e-09,2.39425734622e-08,-7.16613880573e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244929195509,-0.000178490200366,9.81002412189,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119630250000,11806,119630250000,RH_EXTIMU,2.30518597582e-06,1.5305895904e-05,-0.70333423085,0.710859310606,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.43584535916e-07,1.14817745316e-08,-7.16606241064e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024543030643,-0.000176396060281,9.81000097742,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119632750000,11807,119632750000,RH_EXTIMU,2.30529145787e-06,1.53059103922e-05,-0.703334294525,0.710859247605,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.27301862055e-08,6.82445370754e-08,-7.16601448136e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024385879061,-0.000180592078911,9.80998227887,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119635250000,11808,119635250000,RH_EXTIMU,2.30532361534e-06,1.53057830091e-05,-0.7033343582,0.710859184604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.08577373739e-08,-5.36932041487e-08,-7.1659466361e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247060270106,-0.000180176379728,9.80998609826,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119635250000,11809,119637750000,RH_EXTIMU,2.30539564203e-06,1.53055784625e-05,-0.703334421874,0.710859121604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.56948234631e-07,-7.51419942413e-08,-7.16587370139e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245635315866,-0.00018214667119,9.81000572166,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119640250000,11810,119640250000,RH_EXTIMU,2.3053033438e-06,1.53056690204e-05,-0.703334485547,0.710859058605,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0254697875e-07,2.19855754725e-10,-7.16579099934e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245325780914,-0.000176541421746,9.81000804125,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119642750000,11811,119642750000,RH_EXTIMU,2.30522600924e-06,1.53057504493e-05,-0.70333454922,0.710858995606,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.89007766264e-08,3.44791241182e-09,-7.16571790497e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245295137222,-0.000177682748192,9.8099994252,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119645250000,11812,119645250000,RH_EXTIMU,2.30531936999e-06,1.53056835898e-05,-0.703334612892,0.710858932608,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.1608556837e-08,1.51628978143e-08,-7.16565408461e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244906768229,-0.000181126646262,9.80999686629,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119647750000,11813,119647750000,RH_EXTIMU,2.30538331317e-06,1.53056207854e-05,-0.703334676564,0.71085886961,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.25974649279e-08,9.16679262086e-10,-7.16558394732e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245374529046,-0.000180137635586,9.80999813634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119650250000,11814,119650250000,RH_EXTIMU,2.30541655549e-06,1.53056458037e-05,-0.703334740235,0.710858806613,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.7233245427e-09,3.35858703984e-08,-7.16550782092e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244671958343,-0.000178971736767,9.81000837919,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119652750000,11815,119652750000,RH_EXTIMU,2.30533990048e-06,1.5305653605e-05,-0.703334803905,0.710858743617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.70864682472e-08,-3.80408691559e-08,-7.16544141462e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246006735287,-0.000178408701378,9.80998699047,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119655250000,11816,119655250000,RH_EXTIMU,2.30545202821e-06,1.5305580401e-05,-0.703334867574,0.710858680621,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.05850889799e-07,2.21144524572e-08,-7.16536660494e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244802220921,-0.00018093199673,9.81001327476,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119657750000,11817,119657750000,RH_EXTIMU,2.30530852252e-06,1.53056540451e-05,-0.703334931243,0.710858617626,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.22151163097e-07,-3.82117437698e-08,-7.16527710944e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246074335778,-0.000176601386425,9.81001174737,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119660250000,11818,119660250000,RH_EXTIMU,2.3054130959e-06,1.53056597126e-05,-0.703334994911,0.710858554632,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.71763245713e-08,6.2717069165e-08,-7.1652008248e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244080090573,-0.000180595934108,9.81001783741,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119662750000,11819,119662750000,RH_EXTIMU,2.30546739767e-06,1.53057518226e-05,-0.703335058579,0.710858491639,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.00508810697e-08,8.35895078796e-08,-7.16514475701e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243769422778,-0.000178976533856,9.80998549124,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119665250000,11820,119665250000,RH_EXTIMU,2.30552500418e-06,1.53056593678e-05,-0.703335122246,0.710858428645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.56771469411e-08,-1.95105499501e-08,-7.16507474999e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246125644288,-0.000180411249917,9.8099954231,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119667750000,11821,119667750000,RH_EXTIMU,2.30552089541e-06,1.53056033691e-05,-0.703335185912,0.710858365653,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.00678609035e-08,-3.35037355167e-08,-7.16500178986e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245710995101,-0.000179429932881,9.8099997238,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119670250000,11822,119670250000,RH_EXTIMU,2.30557366147e-06,1.53055538334e-05,-0.703335249578,0.710858302661,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.87752495126e-08,2.17336436955e-09,-7.16493371483e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244834800211,-0.00018039250199,9.81000096569,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119672750000,11823,119672750000,RH_EXTIMU,2.30550902465e-06,1.53056057365e-05,-0.703335313242,0.71085823967,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.50665976436e-08,-6.19860781158e-09,-7.16485678199e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245931391946,-0.000177261324227,9.80999698257,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119675250000,11824,119675250000,RH_EXTIMU,2.30554476113e-06,1.53055235935e-05,-0.703335376907,0.710858176679,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.74378338107e-08,-2.59519834602e-08,-7.16479414241e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245448618658,-0.000180686488006,9.8099931091,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119677750000,11825,119677750000,RH_EXTIMU,2.30560485182e-06,1.53054511167e-05,-0.703335440571,0.710858113689,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.58488879173e-08,-6.75161240286e-09,-7.16472526096e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245334041324,-0.000180232396332,9.80999700293,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119680250000,11826,119680250000,RH_EXTIMU,2.30562941321e-06,1.53054230496e-05,-0.703335504234,0.7108580507,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.06558576411e-08,-1.48758531488e-09,-7.16465384784e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245277210112,-0.00017947060872,9.80999956811,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119682750000,11827,119682750000,RH_EXTIMU,2.30564120485e-06,1.53054119914e-05,-0.703335567896,0.710857987711,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.38235851551e-08,9.99919053304e-10,-7.16458194911e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245255963532,-0.000179262514926,9.8100004006,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119685250000,11828,119685250000,RH_EXTIMU,2.30565218697e-06,1.53054015344e-05,-0.703335631558,0.710857924723,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.30248363666e-08,8.86408726968e-10,-7.16451021717e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245264323708,-0.000179285404939,9.81000037857,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119687750000,11829,119687750000,RH_EXTIMU,2.30566551261e-06,1.53053879377e-05,-0.703335695219,0.710857861735,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.61242632747e-08,4.19426177395e-10,-7.16443870947e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245270548044,-0.00017934491202,9.81000018599,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119690250000,11830,119690250000,RH_EXTIMU,2.30554732993e-06,1.53054001289e-05,-0.70333575888,0.710857798748,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.31728539327e-08,-5.89108645092e-08,-7.16436652744e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246587657024,-0.00017735129766,9.80999126708,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119692750000,11831,119692750000,RH_EXTIMU,2.30571095184e-06,1.53053309859e-05,-0.70333582254,0.710857735762,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.32849773719e-07,5.33980443458e-08,-7.16430610073e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243812991835,-0.000181926719098,9.8099984656,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119695250000,11832,119695250000,RH_EXTIMU,2.30578586049e-06,1.53052984857e-05,-0.703335886199,0.710857672776,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.17820015622e-08,2.43201314724e-08,-7.16423565442e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245079342467,-0.000179926746493,9.80999797487,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119697750000,11833,119697750000,RH_EXTIMU,2.30580924775e-06,1.53052817053e-05,-0.703335949858,0.710857609791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.36374805429e-08,4.27024946027e-09,-7.16416389912e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245266925808,-0.000179377997684,9.80999992116,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119700250000,11834,119700250000,RH_EXTIMU,2.305770327e-06,1.53052865997e-05,-0.703336013516,0.710857546806,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.39919669982e-08,-1.84623586873e-08,-7.16409374476e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245575142512,-0.000178554278138,9.80999539548,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119702750000,11835,119702750000,RH_EXTIMU,2.30576733049e-06,1.530527222e-05,-0.703336077174,0.710857483822,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.2825292849e-09,-9.20979173751e-09,-7.16401497385e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245468964276,-0.000179075568584,9.81000902231,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119705250000,11836,119705250000,RH_EXTIMU,2.30565991023e-06,1.53052676437e-05,-0.70333614083,0.710857420839,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.76178845633e-08,-6.2390722241e-08,-7.16393692137e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246321968181,-0.00017811503038,9.81000170613,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119707750000,11837,119707750000,RH_EXTIMU,2.30570894102e-06,1.53052655596e-05,-0.703336204487,0.710857357857,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.99514126782e-08,2.7056620338e-08,-7.16386818292e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244539454595,-0.000179739913371,9.81000294312,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119710250000,11838,119710250000,RH_EXTIMU,2.30573724054e-06,1.53052672725e-05,-0.703336268142,0.710857294875,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.60253252553e-08,1.75511160086e-08,-7.16379677013e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245094150753,-0.000179353086717,9.81000017791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119712750000,11839,119712750000,RH_EXTIMU,2.305748791e-06,1.53052456129e-05,-0.703336331797,0.710857231893,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.96513528472e-08,-5.16468894765e-09,-7.16373193261e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245370449767,-0.000179454058018,9.80999047817,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119712750000,11840,119715250000,RH_EXTIMU,2.30580151279e-06,1.5305180366e-05,-0.703336395451,0.710857168912,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.75901093373e-08,-6.78632649868e-09,-7.16366567289e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245478817108,-0.000180080386987,9.80999327753,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119717750000,11841,119717750000,RH_EXTIMU,2.30584629167e-06,1.53051171335e-05,-0.703336459105,0.710857105932,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.19396112348e-08,-1.01099646437e-08,-7.1635972574e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245349924127,-0.000180085088307,9.80999660554,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119722750000,11842,119720250000,RH_EXTIMU,2.30602388886e-06,1.53050881507e-05,-0.703336522758,0.710857042953,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.18200276639e-07,8.41000427316e-08,-7.16351442373e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243883457728,-0.00018105535455,9.8100249087,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119722750000,11843,119722750000,RH_EXTIMU,2.30577063486e-06,1.53052001233e-05,-0.70333658641,0.710856979974,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.06129898752e-07,-7.81673327016e-08,-7.16343152551e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246796891037,-0.000175348064401,9.80999962839,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119725250000,11844,119725250000,RH_EXTIMU,2.30584355863e-06,1.53051413361e-05,-0.703336650062,0.710856916996,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.54439859003e-08,8.25422191974e-09,-7.163366392e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244446246671,-0.00018122789599,9.81000266299,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119727750000,11845,119727750000,RH_EXTIMU,2.3058790397e-06,1.53051708906e-05,-0.703336713713,0.710856854018,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.44367440327e-09,3.74250312506e-08,-7.16329186523e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245237789785,-0.000178497713637,9.81000061417,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119730250000,11846,119730250000,RH_EXTIMU,2.3057868153e-06,1.53051517566e-05,-0.703336777363,0.710856791041,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.07850456928e-08,-6.21193908479e-08,-7.16322214001e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246627310859,-0.000178259216923,9.80999180347,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119732750000,11847,119732750000,RH_EXTIMU,2.3057615124e-06,1.5305043418e-05,-0.703336841013,0.710856728065,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.74649330135e-08,-7.51940754652e-08,-7.16315252968e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246095444978,-0.000180083173032,9.80999563579,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119735250000,11848,119735250000,RH_EXTIMU,2.3059680305e-06,1.53050119453e-05,-0.703336904662,0.710856665089,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.360480289e-07,9.89570532357e-08,-7.16309534154e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243204229029,-0.000181548841625,9.80999464794,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119737750000,11849,119737750000,RH_EXTIMU,2.30609087805e-06,1.53049889831e-05,-0.70333696831,0.710856602114,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.36772278392e-08,5.67179490811e-08,-7.16302777887e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244703387457,-0.000180308775165,9.80999652167,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119737750000,11850,119740250000,RH_EXTIMU,2.30612583463e-06,1.53049698168e-05,-0.703337031958,0.710856539139,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.15590589147e-08,9.42306193418e-09,-7.1629558351e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245277579507,-0.000179457788789,9.80999954323,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119742750000,11851,119742750000,RH_EXTIMU,2.30612492569e-06,1.53049274423e-05,-0.703337095605,0.710856476165,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.42214289265e-08,-2.3955567406e-08,-7.16287103221e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245838818949,-0.000179372282322,9.81001540499,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119745250000,11852,119745250000,RH_EXTIMU,2.30599040173e-06,1.53049978975e-05,-0.703337159252,0.710856413192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.15249324389e-07,-3.49721081677e-08,-7.16279204806e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245690821079,-0.00017698625442,9.81000537836,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119747750000,11853,119747750000,RH_EXTIMU,2.3059704079e-06,1.53050456358e-05,-0.703337222898,0.710856350219,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.73356062919e-08,1.65517234974e-08,-7.1627210022e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024486931238,-0.00017868771849,9.81000206507,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119750250000,11854,119750250000,RH_EXTIMU,2.30608724018e-06,1.53050307407e-05,-0.703337286543,0.710856287247,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.57172179326e-08,5.79210136322e-08,-7.1626456209e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244392159494,-0.000180543110114,9.8100118408,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119754000000,11855,119752750000,RH_EXTIMU,2.3059724588e-06,1.53050662629e-05,-0.703337350187,0.710856224276,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.43663096169e-08,-4.37294417271e-08,-7.16257212015e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246381058948,-0.0001773485962,9.8099919402,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119755250000,11856,119755250000,RH_EXTIMU,2.30605379664e-06,1.53049355051e-05,-0.703337413831,0.710856161305,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.20724520497e-07,-2.79400409668e-08,-7.16251423633e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245359618509,-0.000181629288321,9.80998955955,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119757750000,11857,119757750000,RH_EXTIMU,2.30612284593e-06,1.53048300504e-05,-0.703337477475,0.710856098335,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.94989279151e-08,-2.04649811465e-08,-7.16244410417e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024565113337,-0.000180508098987,9.80999797362,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119760250000,11858,119760250000,RH_EXTIMU,2.30608209202e-06,1.53048086984e-05,-0.703337541117,0.710856035365,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.02665940635e-08,-3.4419992365e-08,-7.16236670504e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024575379725,-0.000178630988665,9.81000277206,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119762750000,11859,119762750000,RH_EXTIMU,2.30606296449e-06,1.53048131352e-05,-0.703337604759,0.710855972397,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.24786059245e-08,-7.58576659739e-09,-7.16229395115e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245286580624,-0.000178874437894,9.81000178678,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119765250000,11860,119765250000,RH_EXTIMU,2.30607081121e-06,1.53048062859e-05,-0.703337668401,0.710855909428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.2115728539e-09,1.17360405878e-09,-7.16222248818e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245238023805,-0.000179262175962,9.8100004904,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119767750000,11861,119767750000,RH_EXTIMU,2.306087884e-06,1.53047895301e-05,-0.703337732041,0.710855846461,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.00323720143e-08,7.31165829709e-10,-7.16215137345e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245263832104,-0.000179413485741,9.80999992558,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119770250000,11862,119770250000,RH_EXTIMU,2.30614980188e-06,1.53048262647e-05,-0.703337795682,0.710855783494,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.5437648892e-08,5.63832951953e-08,-7.16209453867e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244136154574,-0.000179376035423,9.80998541654,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119772750000,11863,119772750000,RH_EXTIMU,2.30627688434e-06,1.53047418856e-05,-0.703337859321,0.710855720527,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.20642835141e-07,2.41739399398e-08,-7.16202755803e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245292846858,-0.000181059684405,9.80999701964,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119775250000,11864,119775250000,RH_EXTIMU,2.30619866916e-06,1.53046947264e-05,-0.70333792296,0.710855657561,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.70493216539e-08,-7.01745478863e-08,-7.16194481564e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246497195515,-0.000178386648837,9.81000512967,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119777750000,11865,119777750000,RH_EXTIMU,2.30613873331e-06,1.53047053863e-05,-0.703337986598,0.710855594596,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.91872448475e-08,-2.70085013583e-08,-7.16187026088e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245465524241,-0.000178423438426,9.81000335416,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119780250000,11866,119780250000,RH_EXTIMU,2.30613582365e-06,1.5304705351e-05,-0.703338050236,0.710855531631,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.39526192825e-10,-1.00369986395e-09,-7.16179867302e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245223502376,-0.000179138607961,9.81000097916,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119780250000,11867,119782750000,RH_EXTIMU,2.30626638562e-06,1.53046580377e-05,-0.703338113873,0.710855468667,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0176566549e-07,4.7210547054e-08,-7.16172709355e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024422468419,-0.000181243816923,9.81000924184,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119780250000,11868,119785250000,RH_EXTIMU,2.30625942018e-06,1.53047107276e-05,-0.703338177509,0.710855405704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.27128491783e-08,2.66981356126e-08,-7.16164942328e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245191813223,-0.000178054465539,9.81000402403,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119787750000,11869,119787750000,RH_EXTIMU,2.30618933941e-06,1.53047058146e-05,-0.703338241145,0.710855342741,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.61941131513e-08,-4.15728484364e-08,-7.16158175578e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246052141015,-0.000178591759367,9.80999189462,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119790250000,11870,119790250000,RH_EXTIMU,2.30624063789e-06,1.53046307176e-05,-0.70333830478,0.710855279779,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.23228015042e-08,-1.31888429262e-08,-7.16151430746e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245381828826,-0.000180325078427,9.80999680867,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119792750000,11871,119792750000,RH_EXTIMU,2.30617881325e-06,1.53045764778e-05,-0.703338368414,0.710855216818,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.74429057674e-09,-6.4978725211e-08,-7.1614552954e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246272000585,-0.00017887889771,9.80997653868,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119795250000,11872,119795250000,RH_EXTIMU,2.30631885884e-06,1.53044406514e-05,-0.703338432048,0.710855153857,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.56962529242e-07,2.21067694633e-09,-7.1613938327e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245110126994,-0.000181626508781,9.80999201387,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119797750000,11873,119797750000,RH_EXTIMU,2.30649699009e-06,1.53043584485e-05,-0.703338495681,0.710855090896,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.48448835679e-07,5.41352229262e-08,-7.16131905152e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244058006212,-0.000181747212526,9.81001476737,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119800250000,11874,119800250000,RH_EXTIMU,2.30643365451e-06,1.53044779265e-05,-0.703338559314,0.710855027937,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.02349449925e-07,3.29615753479e-08,-7.16122680366e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245161271075,-0.000176768789633,9.81002010181,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119802750000,11875,119802750000,RH_EXTIMU,2.30631878587e-06,1.5304580403e-05,-0.703338622945,0.710854964978,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.22089253036e-07,-5.70305457985e-09,-7.16114630417e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245487754692,-0.000177140593935,9.81000945313,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119805250000,11876,119805250000,RH_EXTIMU,2.30629933052e-06,1.530459709e-05,-0.703338686576,0.71085490202,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.95579849472e-08,-8.03908001022e-10,-7.16107516289e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245252226827,-0.000179025783788,9.81000166173,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119807750000,11877,119807750000,RH_EXTIMU,2.30632755406e-06,1.53045667888e-05,-0.703338750207,0.710854839062,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.39950900905e-08,-6.97784625994e-10,-7.16100557617e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245282408741,-0.000179737494735,9.80999894883,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119810250000,11878,119810250000,RH_EXTIMU,2.30633510839e-06,1.53045676353e-05,-0.703338813837,0.710854776105,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.71494939608e-09,5.38541105044e-09,-7.16094545414e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245059497332,-0.000179102618644,9.80998525279,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119812750000,11879,119812750000,RH_EXTIMU,2.30650358911e-06,1.53044590865e-05,-0.703338877466,0.710854713148,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.57784725861e-07,3.3722713473e-08,-7.16087816074e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244859661371,-0.000181783184669,9.81000022072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119815250000,11880,119815250000,RH_EXTIMU,2.30651882691e-06,1.53043938394e-05,-0.703338941095,0.710854650192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.62733735684e-08,-2.78777131444e-08,-7.1608012015e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245893912448,-0.000179710462672,9.8100052709,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119817750000,11881,119817750000,RH_EXTIMU,2.30646594096e-06,1.53043964278e-05,-0.703339004723,0.710854587237,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.06365899436e-08,-2.76320442153e-08,-7.16071778037e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245448835075,-0.000178420758529,9.81001328162,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119821500000,11882,119820250000,RH_EXTIMU,2.30636920297e-06,1.53045206932e-05,-0.70333906835,0.710854524283,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.24038733372e-07,1.68894372128e-08,-7.160640223e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245051889899,-0.000176767347512,9.81000361791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119822750000,11883,119822750000,RH_EXTIMU,2.30640082647e-06,1.53045228725e-05,-0.703339131976,0.710854461329,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.76527436067e-08,1.9686327391e-08,-7.16057727808e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244981621099,-0.00017968126241,9.8099942663,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119825250000,11884,119825250000,RH_EXTIMU,2.30645753863e-06,1.53044780982e-05,-0.703339195602,0.710854398376,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.83396223583e-08,7.10130688345e-09,-7.16050881216e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245186982868,-0.000180073751764,9.80999687512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119827750000,11885,119827750000,RH_EXTIMU,2.30648919959e-06,1.53044403711e-05,-0.703339259228,0.710854335423,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.01281793718e-08,-2.98669148012e-09,-7.16043784887e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024534250181,-0.00017964377074,9.80999897957,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119830250000,11886,119830250000,RH_EXTIMU,2.30650744779e-06,1.53044189714e-05,-0.703339322852,0.710854272471,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.33136449943e-08,-1.24860204078e-09,-7.16036654987e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245279299474,-0.000179395071418,9.80999986136,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119832750000,11887,119832750000,RH_EXTIMU,2.3064361981e-06,1.53043670312e-05,-0.703339386476,0.710854209519,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0398150715e-08,-6.89743082522e-08,-7.16028986736e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246534914168,-0.000178768430921,9.81000030057,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119835250000,11888,119835250000,RH_EXTIMU,2.30637370085e-06,1.53043359119e-05,-0.7033394501,0.710854146568,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.71360273824e-08,-5.22091525153e-08,-7.16023285646e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245783563893,-0.00017883835013,9.80997814325,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119837750000,11889,119837750000,RH_EXTIMU,2.30664828729e-06,1.53041986458e-05,-0.703339513723,0.710854083618,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.34283554072e-07,7.7094392793e-08,-7.16017251916e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243593245015,-0.000183354502,9.81000096693,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119840250000,11890,119840250000,RH_EXTIMU,2.30666171838e-06,1.53042039421e-05,-0.703339577345,0.710854020668,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.55306055091e-09,1.12225413219e-08,-7.16009491407e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245650618821,-0.000178498349157,9.8100006363,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119842750000,11891,119842750000,RH_EXTIMU,2.30672159647e-06,1.53041841827e-05,-0.703339640967,0.710853957719,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.6064815061e-08,2.31081797232e-08,-7.16002072901e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244721887388,-0.000180108405349,9.81000999252,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119845250000,11892,119845250000,RH_EXTIMU,2.30660849827e-06,1.53042503341e-05,-0.703339704588,0.710853894771,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.00643474299e-07,-2.53646737691e-08,-7.159939477e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024608480013,-0.000176849204546,9.81000244113,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119847750000,11893,119847750000,RH_EXTIMU,2.30660230516e-06,1.53042206488e-05,-0.703339768208,0.710853831823,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.4076260699e-08,-1.97129296362e-08,-7.15987269355e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245352985713,-0.000179693830572,9.80999747074,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119850250000,11894,119850250000,RH_EXTIMU,2.30670910903e-06,1.53041925749e-05,-0.703339831828,0.710853768876,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.74290390804e-08,4.47836501715e-08,-7.15980420661e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244217920729,-0.00018048240675,9.81000337613,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119852750000,11895,119852750000,RH_EXTIMU,2.30676334054e-06,1.53042538233e-05,-0.703339895447,0.710853705929,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.72717019332e-09,6.59987631274e-08,-7.1597248035e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244544309831,-0.000178746020359,9.81001184404,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119855250000,11896,119855250000,RH_EXTIMU,2.30660906829e-06,1.53043334294e-05,-0.703339959065,0.710853642984,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.31629042162e-07,-4.08807668563e-08,-7.15965017289e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246356467277,-0.000176525691811,9.80999271154,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119857750000,11897,119857750000,RH_EXTIMU,2.30666050438e-06,1.53042067238e-05,-0.703340022683,0.710853580038,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.01439575828e-07,-4.24603913449e-08,-7.15958775956e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245738093398,-0.000181378239912,9.80999571867,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119860250000,11898,119860250000,RH_EXTIMU,2.30670660004e-06,1.53041948482e-05,-0.7033400863,0.710853517094,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.37909260918e-08,1.98365345539e-08,-7.15951537414e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244659011451,-0.000179324891069,9.81000058413,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119862750000,11899,119862750000,RH_EXTIMU,2.30681741133e-06,1.53041598637e-05,-0.703340149916,0.710853454149,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.3596329897e-08,4.31085676759e-08,-7.1594458218e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244554424227,-0.00018081396415,9.81000243692,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119865250000,11900,119865250000,RH_EXTIMU,2.30684846913e-06,1.53040863033e-05,-0.703340213532,0.710853391206,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.9947438582e-08,-2.37039220472e-08,-7.15937426004e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024602733694,-0.000179818827859,9.80999860761,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119867750000,11901,119867750000,RH_EXTIMU,2.30676768906e-06,1.53040760867e-05,-0.703340277147,0.710853328263,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.92946321188e-08,-5.06094577527e-08,-7.15929482085e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245973487634,-0.000178155777815,9.8100057033,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119870250000,11902,119870250000,RH_EXTIMU,2.30665178031e-06,1.53040798491e-05,-0.703340340762,0.710853265321,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.7137258797e-08,-6.24258323171e-08,-7.15922282469e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246180088825,-0.00017794369476,9.80999441655,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119872750000,11903,119872750000,RH_EXTIMU,2.30668844205e-06,1.53040319722e-05,-0.703340404376,0.71085320238,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.86828359309e-08,-5.94494846376e-09,-7.159157097e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245155318453,-0.000179942661407,9.80999455344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119875250000,11904,119875250000,RH_EXTIMU,2.306761444e-06,1.53039564248e-05,-0.703340467989,0.710853139439,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.49183704856e-08,-1.23312323802e-09,-7.15909087424e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245423415653,-0.000180511024892,9.80999672395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119877750000,11905,119877750000,RH_EXTIMU,2.30675446215e-06,1.53039517837e-05,-0.703340531601,0.710853076498,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.64046326726e-10,-5.91462511191e-09,-7.15902042742e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245088152405,-0.000178740210416,9.80999357058,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119880250000,11906,119880250000,RH_EXTIMU,2.30696372849e-06,1.53039146335e-05,-0.703340595214,0.710853013558,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.40804444742e-07,9.72749308862e-08,-7.15896114742e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243620128695,-0.000181854456128,9.81000080469,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119882750000,11907,119882750000,RH_EXTIMU,2.3069261766e-06,1.53039159249e-05,-0.703340658825,0.710852950619,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.11867946469e-08,-1.97418237607e-08,-7.1588646127e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024618999581,-0.000178085385704,9.81002227857,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119885250000,11908,119885250000,RH_EXTIMU,2.30684351019e-06,1.53040354376e-05,-0.703340722435,0.710852887681,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.13362493249e-07,2.21038135708e-08,-7.15879298067e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244546119544,-0.000177386501241,9.81000263313,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119887750000,11909,119887750000,RH_EXTIMU,2.30687578886e-06,1.53040826938e-05,-0.703340786046,0.710852824743,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.33851288841e-09,4.56892524387e-08,-7.15873514785e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244546103759,-0.000179131419869,9.80998582188,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119890250000,11910,119890250000,RH_EXTIMU,2.30694080407e-06,1.53039926302e-05,-0.703340849655,0.710852761806,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.85442439697e-08,-1.39821054057e-08,-7.15867354809e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245740977463,-0.000180495144525,9.80998540404,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119892750000,11911,119892750000,RH_EXTIMU,2.30709390358e-06,1.53038357725e-05,-0.703340913264,0.710852698869,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.76219438091e-07,-2.40412595239e-09,-7.15860289739e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245231889951,-0.000182205200626,9.81000532096,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119895250000,11912,119895250000,RH_EXTIMU,2.30700036378e-06,1.53038277149e-05,-0.703340976872,0.710852635933,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.77656791449e-08,-5.6561405239e-08,-7.15851682811e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024636854508,-0.000177563339649,9.81000909452,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119897750000,11913,119897750000,RH_EXTIMU,2.30682058807e-06,1.53039049106e-05,-0.70334104048,0.710852572998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.4477627552e-07,-5.66019275091e-08,-7.158440842e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246177608895,-0.000176374996513,9.80999747371,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119900250000,11914,119900250000,RH_EXTIMU,2.30687811591e-06,1.53038520306e-05,-0.703341104086,0.710852510063,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.33641105417e-08,2.95055079992e-09,-7.15838028468e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244758328043,-0.000180689639962,9.80999280689,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119902750000,11915,119902750000,RH_EXTIMU,2.30696758962e-06,1.53038033354e-05,-0.703341167693,0.710852447129,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.91764409456e-08,2.33054632898e-08,-7.15831065784e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024501161701,-0.000180200791232,9.8100001384,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119905250000,11916,119905250000,RH_EXTIMU,2.30686126131e-06,1.53037657463e-05,-0.703341231298,0.710852384195,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.84217618786e-08,-8.05511755338e-08,-7.15823439301e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246770582798,-0.000178170055758,9.809996045,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119907750000,11917,119907750000,RH_EXTIMU,2.3068549426e-06,1.53037169842e-05,-0.703341294903,0.710852321262,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.47386463514e-08,-3.06323890791e-08,-7.15816401774e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245508834883,-0.00017948844175,9.80999960567,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119910250000,11918,119910250000,RH_EXTIMU,2.30702539224e-06,1.53037034551e-05,-0.703341358508,0.71085225833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0543892103e-07,8.88667586914e-08,-7.15809135155e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243634159679,-0.000180977718061,9.81001189986,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119912750000,11919,119912750000,RH_EXTIMU,2.30699829613e-06,1.530371625e-05,-0.703341422111,0.710852195399,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.17135756899e-08,-7.31693660976e-09,-7.15801681669e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024584684975,-0.000178574093639,9.81000084871,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119915250000,11920,119915250000,RH_EXTIMU,2.30707810559e-06,1.53037143861e-05,-0.703341485714,0.710852132468,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.73297905917e-08,4.44997508535e-08,-7.15794643188e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243853979034,-0.000180190387774,9.81000553949,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119919000000,11921,119917750000,RH_EXTIMU,2.30715906392e-06,1.53037755212e-05,-0.703341549317,0.710852069537,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.25352946045e-08,8.0972529561e-08,-7.15787562542e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244612097351,-0.000179047592442,9.81000354634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119920250000,11922,119920250000,RH_EXTIMU,2.30701796119e-06,1.5303776565e-05,-0.703341612918,0.710852006607,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.99350269321e-08,-7.81480772736e-08,-7.15779729844e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246898039207,-0.00017740511952,9.80999521825,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119922750000,11923,119922750000,RH_EXTIMU,2.30713825272e-06,1.53037234386e-05,-0.703341676519,0.710851943678,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.91951754417e-08,3.81259104575e-08,-7.15772463338e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244204549729,-0.000181107811169,9.81001450411,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119925250000,11924,119925250000,RH_EXTIMU,2.30708492391e-06,1.53037480011e-05,-0.70334174012,0.71085188075,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.32529774941e-08,-1.53854125775e-08,-7.15764599806e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024563926348,-0.000178232514631,9.81000408944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119927750000,11925,119927750000,RH_EXTIMU,2.3069394393e-06,1.530380732e-05,-0.70334180372,0.710851817822,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.15216772373e-07,-4.74737197795e-08,-7.1575807384e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246428113595,-0.000176609192606,9.80998153911,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119930250000,11926,119930250000,RH_EXTIMU,2.30705833598e-06,1.53036112965e-05,-0.703341867319,0.710851754895,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.78806335951e-07,-4.39218726183e-08,-7.1575290375e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245432280288,-0.000182815030043,9.80998286751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119932750000,11927,119932750000,RH_EXTIMU,2.30719699462e-06,1.53034765453e-05,-0.703341930917,0.710851691968,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.55568289995e-07,2.04205868619e-09,-7.15745649569e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245192275883,-0.000181279086378,9.81000258397,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119935250000,11928,119935250000,RH_EXTIMU,2.30722805031e-06,1.53035082749e-05,-0.703341994515,0.710851629042,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.02175256464e-10,3.61712224256e-08,-7.15738246497e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244376101643,-0.000178896448154,9.8100050015,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119937750000,11929,119937750000,RH_EXTIMU,2.30729152211e-06,1.53034964977e-05,-0.703342058113,0.710851566117,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.3616698182e-08,2.96694375038e-08,-7.15729892358e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024525640182,-0.000179817754808,9.81001775552,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119937750000,11930,119940250000,RH_EXTIMU,2.30714784007e-06,1.53035981316e-05,-0.703342121709,0.710851503192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.38001284567e-07,-2.23957904691e-08,-7.15722379692e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245546063007,-0.000176432212736,9.80999792704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119942750000,11931,119942750000,RH_EXTIMU,2.30738303422e-06,1.53036089222e-05,-0.703342185305,0.710851440268,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.28573634067e-07,1.39126978791e-07,-7.15715383185e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242866817292,-0.000181825702535,9.81001815352,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119945250000,11932,119945250000,RH_EXTIMU,2.30713993989e-06,1.53036911651e-05,-0.7033422489,0.710851377344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.83624314428e-07,-8.93598676843e-08,-7.1570825337e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247128101825,-0.000175614930966,9.80998087918,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119947750000,11933,119947750000,RH_EXTIMU,2.30728317157e-06,1.53036068799e-05,-0.703342312495,0.710851314421,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.29772962107e-07,3.33142818566e-08,-7.15702050549e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244471329149,-0.000181462310678,9.80999841445,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119950250000,11934,119950250000,RH_EXTIMU,2.30719694949e-06,1.53035688985e-05,-0.703342376089,0.710851251499,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.67670485585e-08,-6.94612016231e-08,-7.15694644998e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246965935063,-0.000178039954872,9.8099911753,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119952750000,11935,119952750000,RH_EXTIMU,2.30716544849e-06,1.5303435802e-05,-0.703342439683,0.710851188577,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.78706460191e-08,-9.27613120388e-08,-7.15687811007e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246295180275,-0.000180269095566,9.80999438582,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119955250000,11936,119955250000,RH_EXTIMU,2.3073191914e-06,1.53034312691e-05,-0.703342503275,0.710851125656,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.08758685536e-08,8.45823355638e-08,-7.15680758795e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243470814856,-0.000180477715295,9.81000983651,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119957750000,11937,119957750000,RH_EXTIMU,2.30742153492e-06,1.53034775228e-05,-0.703342566867,0.710851062736,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.3069766941e-08,8.4542535775e-08,-7.15672978442e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244158884803,-0.000179669234824,9.81001250656,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119957750000,11938,119960250000,RH_EXTIMU,2.30725336208e-06,1.53035072199e-05,-0.703342630459,0.710850999816,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.11451786298e-07,-7.70853876943e-08,-7.15665686266e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246805354943,-0.000177053944203,9.80999054087,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119962750000,11939,119962750000,RH_EXTIMU,2.30729898328e-06,1.53034331323e-05,-0.70334269405,0.710850936897,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.85257388385e-08,-1.5809392367e-08,-7.15659097283e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245316190741,-0.000180340630668,9.80999675523,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119965250000,11940,119965250000,RH_EXTIMU,2.30733405126e-06,1.53033880896e-05,-0.70334275764,0.710850873978,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.61815022195e-08,-5.23014589249e-09,-7.15652049694e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245316649155,-0.000179708832926,9.80999863913,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119967750000,11941,119967750000,RH_EXTIMU,2.3073532395e-06,1.53033664779e-05,-0.70334282123,0.71085081106,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.39669639084e-08,-8.40508726887e-10,-7.15644918222e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245266658196,-0.000179367682236,9.80999985428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119970250000,11942,119970250000,RH_EXTIMU,2.30736758235e-06,1.53033519665e-05,-0.703342884819,0.710850748143,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.7216349408e-08,4.70875743063e-10,-7.15637768304e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002452592944,-0.000179291905625,9.81000017036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119972750000,11943,119972750000,RH_EXTIMU,2.30738195502e-06,1.53033372405e-05,-0.703342948407,0.710850685226,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.73540274039e-08,3.65637670853e-10,-7.15630628799e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245263880331,-0.000179309161604,9.81000013281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119975250000,11944,119975250000,RH_EXTIMU,2.30736383241e-06,1.53033053821e-05,-0.703343011995,0.71085062231,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.51455990094e-09,-2.76615071517e-08,-7.15623709717e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245744863261,-0.000179161825523,9.80999454585,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119977750000,11945,119977750000,RH_EXTIMU,2.30742997059e-06,1.5303272741e-05,-0.703343075582,0.710850559395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.68723981379e-08,1.93048008432e-08,-7.15616238479e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244907804612,-0.000179938751768,9.81000688268,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119980250000,11946,119980250000,RH_EXTIMU,2.3073339408e-06,1.53032627124e-05,-0.703343139168,0.71085049648,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.80728416392e-08,-5.90837029188e-08,-7.15609132469e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246541080054,-0.000177951458825,9.80999107706,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119982750000,11947,119982750000,RH_EXTIMU,2.30736825767e-06,1.53031560608e-05,-0.703343202754,0.710850433566,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.04200861487e-08,-4.06886122865e-08,-7.15602813436e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245520254527,-0.00018071494517,9.80999277574,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119987750000,11948,119985250000,RH_EXTIMU,2.30758287673e-06,1.53030672117e-05,-0.703343266339,0.710850370652,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.72937330379e-07,7.08868132801e-08,-7.15595774573e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243558612744,-0.00018232638198,9.81001222011,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119987750000,11949,119987750000,RH_EXTIMU,2.30747838467e-06,1.53031904289e-05,-0.703343329924,0.710850307739,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.27859181646e-07,1.19289890797e-08,-7.15587239879e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245929546611,-0.000175903991903,9.8100053744,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119990250000,11950,119990250000,RH_EXTIMU,2.30742741447e-06,1.53031876446e-05,-0.703343393507,0.710850244827,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.65245663785e-08,-2.96101474939e-08,-7.15580298728e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245534175168,-0.00017906399086,9.80999922021,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119992750000,11951,119992750000,RH_EXTIMU,2.30745946257e-06,1.53032074028e-05,-0.70334345709,0.710850181915,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.00226028002e-09,2.9921553724e-08,-7.15572899182e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024494560478,-0.000178868195066,9.81000447573,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119996500000,11952,119995250000,RH_EXTIMU,2.30745386523e-06,1.53032216589e-05,-0.703343520673,0.710850119004,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.03100894619e-08,5.61048567091e-09,-7.15566623875e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244829476953,-0.00017911227693,9.80998797165,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +119997750000,11953,119997750000,RH_EXTIMU,2.30755764087e-06,1.53031381612e-05,-0.703343584255,0.710850056093,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0689172627e-07,1.15612838481e-08,-7.15560249795e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245262313353,-0.000180892786086,9.80999514392,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120000250000,11954,120000250000,RH_EXTIMU,2.30765133876e-06,1.53030620076e-05,-0.703343647836,0.710849993183,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.70283476146e-08,1.00672361041e-08,-7.1555199042e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245208892909,-0.000180546163435,9.81001593821,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120002750000,11955,120002750000,RH_EXTIMU,2.30747497659e-06,1.53031183441e-05,-0.703343711417,0.710849930274,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.31098240307e-07,-6.65443566743e-08,-7.15544227837e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246569968405,-0.0001764570572,9.80999630194,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120005250000,11956,120005250000,RH_EXTIMU,2.30768812877e-06,1.53030059836e-05,-0.703343774997,0.710849867366,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.85332333037e-07,5.66910107195e-08,-7.15537649412e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243381402369,-0.000183277543247,9.81001619864,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120007750000,11957,120007750000,RH_EXTIMU,2.30746132737e-06,1.53032203776e-05,-0.703343838576,0.710849804458,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.48717049087e-07,-5.04115651958e-09,-7.155286311e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246369293226,-0.000173327565452,9.80999851809,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120010250000,11958,120010250000,RH_EXTIMU,2.30758973106e-06,1.53031334141e-05,-0.703343902155,0.71084974155,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.228472651e-07,2.34479585089e-08,-7.15523638028e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244297760449,-0.00018238324189,9.8099912037,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120015250000,11959,120012750000,RH_EXTIMU,2.30757097831e-06,1.53030860492e-05,-0.703343965733,0.710849678644,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.68812362657e-08,-3.68344026258e-08,-7.15516944211e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024648586167,-0.000178525270933,9.80998036123,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120015250000,11960,120015250000,RH_EXTIMU,2.30771720558e-06,1.53028804791e-05,-0.703344029311,0.710849615737,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.99720122537e-07,-3.3972304241e-08,-7.15511672033e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245341928937,-0.000182872620273,9.80998572145,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120015250000,11961,120017750000,RH_EXTIMU,2.30790834251e-06,1.53027734111e-05,-0.703344092888,0.710849552831,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.69834678604e-07,4.73133386105e-08,-7.15504040443e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244151386804,-0.000181863199306,9.81001468449,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120020250000,11962,120020250000,RH_EXTIMU,2.30780868258e-06,1.5302913253e-05,-0.703344156464,0.710849489927,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.34465689637e-07,2.41017621434e-08,-7.15494704982e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245235070176,-0.000176010891412,9.81001934131,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120022750000,11963,120022750000,RH_EXTIMU,2.30753136179e-06,1.53030300197e-05,-0.703344220039,0.710849427022,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.22513972103e-07,-8.89859925653e-08,-7.15487535271e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246963055123,-0.000175211315608,9.80998551902,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120024000000,11964,120025250000,RH_EXTIMU,2.30767740267e-06,1.53029056549e-05,-0.703344283614,0.710849364119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.53921908426e-07,1.21026201126e-08,-7.15482356354e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244682527683,-0.000182267008437,9.80998779578,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120027750000,11965,120027750000,RH_EXTIMU,2.30790729419e-06,1.53028341719e-05,-0.703344347189,0.710849301215,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.718507384e-07,8.93561079064e-08,-7.15474721315e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243856323128,-0.000181690867377,9.81001520521,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120030250000,11966,120030250000,RH_EXTIMU,2.30781680273e-06,1.53028939285e-05,-0.703344410762,0.710849238313,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.41897880492e-08,-1.62822827697e-08,-7.1546649089e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245873886442,-0.000177380807477,9.81000653182,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120032750000,11967,120032750000,RH_EXTIMU,2.30785601896e-06,1.53028812456e-05,-0.703344474335,0.710849175411,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.03322497156e-08,1.55061843024e-08,-7.15458784385e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244599683186,-0.000180011904829,9.81001599526,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120037750000,11968,120035250000,RH_EXTIMU,2.30774844954e-06,1.53030128385e-05,-0.703344537907,0.71084911251,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.34322225698e-07,1.49601756475e-08,-7.15450412448e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245382169687,-0.00017630426096,9.81000649455,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120037750000,11969,120037750000,RH_EXTIMU,2.3077377048e-06,1.53029969969e-05,-0.703344601479,0.71084904961,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.6977810055e-09,-1.440191981e-08,-7.15444203972e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245577550954,-0.000179440931018,9.80999092659,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120037750000,11970,120040250000,RH_EXTIMU,2.30788756602e-06,1.53029197663e-05,-0.70334466505,0.71084898671,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.29573150328e-07,4.10564881432e-08,-7.15437968681e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024414406775,-0.000181493324166,9.80999767502,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120037750000,11971,120042750000,RH_EXTIMU,2.30786862151e-06,1.53029041658e-05,-0.70334472862,0.71084892381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.10096538462e-09,-1.88786115789e-08,-7.15431211038e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024598027132,-0.000178654488132,9.80998744959,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120037750000,11972,120045250000,RH_EXTIMU,2.30789781568e-06,1.53027836796e-05,-0.70334479219,0.710848860912,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.52911636495e-08,-5.14384933807e-08,-7.15423828072e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246186019404,-0.000180385722151,9.81000229955,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120037750000,11973,120047750000,RH_EXTIMU,2.30789231602e-06,1.53027735342e-05,-0.703344855759,0.710848798014,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.47536108261e-09,-8.21132452831e-09,-7.15416353486e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245045442076,-0.000178980754808,9.8100057252,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120037750000,11974,120050250000,RH_EXTIMU,2.3079013452e-06,1.53028566247e-05,-0.703344919328,0.710848735116,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.07239715124e-08,5.29849601533e-08,-7.15409010775e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244339077614,-0.000178272498844,9.81000333009,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120054000000,11975,120052750000,RH_EXTIMU,2.30784367284e-06,1.53028619382e-05,-0.703344982895,0.71084867222,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.48924767851e-08,-2.87765570675e-08,-7.1540216687e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246440346061,-0.00017824148534,9.80999082027,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120055250000,11976,120055250000,RH_EXTIMU,2.30788828135e-06,1.53027172538e-05,-0.703345046463,0.710848609323,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.07672672471e-07,-5.65261780633e-08,-7.15395282812e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024558913974,-0.000181322531642,9.80999956691,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120057750000,11977,120057750000,RH_EXTIMU,2.30793520539e-06,1.53027040956e-05,-0.703345110029,0.710848546428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.4982837682e-08,1.95728529745e-08,-7.15388063056e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244884777602,-0.000179305635417,9.8100012459,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120060250000,11978,120060250000,RH_EXTIMU,2.30803671049e-06,1.53026851589e-05,-0.703345173595,0.710848483533,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.92733417537e-08,4.69981968335e-08,-7.15381153919e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244429003153,-0.000180415822122,9.81000394925,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120062750000,11979,120062750000,RH_EXTIMU,2.30791921229e-06,1.53027418672e-05,-0.703345237161,0.710848420638,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.78328185846e-08,-3.32120563392e-08,-7.15373811749e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246400963416,-0.000176615126335,9.80999010955,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120065250000,11980,120065250000,RH_EXTIMU,2.30807770418e-06,1.53026091939e-05,-0.703345300725,0.710848357745,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.65677373692e-07,1.43837195767e-08,-7.15367702548e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244420073787,-0.0001828262922,9.81000136975,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120067750000,11981,120067750000,RH_EXTIMU,2.30814291527e-06,1.53026037965e-05,-0.703345364289,0.710848294851,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.10154205809e-08,3.42759344485e-08,-7.1535969962e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244743149233,-0.000179170405867,9.81000996637,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120070250000,11982,120070250000,RH_EXTIMU,2.30794951527e-06,1.53026634189e-05,-0.703345427853,0.710848231959,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.42636251693e-07,-7.42630690189e-08,-7.15352347073e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246853996989,-0.000176373450482,9.80998969367,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120072750000,11983,120072750000,RH_EXTIMU,2.30806313694e-06,1.53025638849e-05,-0.703345491415,0.710848169067,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.21513875516e-07,7.98196146507e-09,-7.15344989455e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244972055606,-0.000181324302723,9.81001132977,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120077750000,11984,120075250000,RH_EXTIMU,2.30802660785e-06,1.53026333344e-05,-0.703345554978,0.710848106176,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.89566363372e-08,1.9592932071e-08,-7.15339045108e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024468701662,-0.000177938996518,9.8099832786,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120077750000,11985,120077750000,RH_EXTIMU,2.30800414948e-06,1.53025694852e-05,-0.703345618539,0.710848043285,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.40490663891e-08,-4.82938752772e-08,-7.15332647284e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246349479735,-0.00017922496066,9.80998443928,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120080250000,11986,120080250000,RH_EXTIMU,2.30809251533e-06,1.53024467059e-05,-0.7033456821,0.710847980395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.20231017632e-07,-1.944801408e-08,-7.15325580645e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245490623345,-0.000180982157755,9.81000093485,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120082750000,11987,120082750000,RH_EXTIMU,2.30821325451e-06,1.53023941347e-05,-0.70334574566,0.710847917506,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.91365940653e-08,3.86935034924e-08,-7.15316837505e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244629571925,-0.000180602981348,9.81002720244,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120085250000,11988,120085250000,RH_EXTIMU,2.3080989064e-06,1.53025796612e-05,-0.70334580922,0.710847854617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.68524486278e-07,4.1816394446e-08,-7.15308799979e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244448619791,-0.000176064755615,9.81000964838,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120087750000,11989,120087750000,RH_EXTIMU,2.30804943734e-06,1.53026219945e-05,-0.703345872779,0.710847791729,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.10577407191e-08,-3.10851227271e-09,-7.15302551479e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245569988324,-0.000178446016596,9.80998614996,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120090250000,11990,120090250000,RH_EXTIMU,2.30817102052e-06,1.53025129653e-05,-0.703345936337,0.710847728841,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.31384110949e-07,7.06199200605e-09,-7.15296506067e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245064972632,-0.000181430346631,9.80999166942,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120092750000,11991,120092750000,RH_EXTIMU,2.30829936517e-06,1.53024068432e-05,-0.703345999895,0.710847665954,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.3359342309e-07,1.25197424541e-08,-7.15289053807e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245015102748,-0.000181324109913,9.81001008957,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120095250000,11992,120095250000,RH_EXTIMU,2.30820569799e-06,1.53024775753e-05,-0.703346063452,0.710847603068,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.21715627998e-08,-1.18281020922e-08,-7.15280306413e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024553076482,-0.000176959808969,9.81001078477,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120097750000,11993,120097750000,RH_EXTIMU,2.30817912225e-06,1.53025215983e-05,-0.703346127008,0.710847540182,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.89896297465e-08,1.07338919201e-08,-7.15273722284e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024516744125,-0.000178493887821,9.80999555603,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120100250000,11994,120100250000,RH_EXTIMU,2.30827175114e-06,1.53024614821e-05,-0.703346190564,0.710847477297,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.73961843158e-08,1.85858524681e-08,-7.15268274528e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244821319276,-0.00018084443192,9.80998281534,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120102750000,11995,120102750000,RH_EXTIMU,2.30833675637e-06,1.53023225144e-05,-0.703346254119,0.710847414413,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.16055164061e-07,-4.1798488518e-08,-7.15261207085e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246198017846,-0.000180683070822,9.80999591178,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120105250000,11996,120105250000,RH_EXTIMU,2.30835826365e-06,1.53022585027e-05,-0.703346317674,0.710847351529,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.91427593943e-08,-2.36479199358e-08,-7.15253005187e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245555720606,-0.000179621434451,9.81001344569,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120107750000,11997,120107750000,RH_EXTIMU,2.30835556504e-06,1.53023478376e-05,-0.703346381227,0.710847288646,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.09071823871e-08,4.99367568671e-08,-7.15245322308e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244213501609,-0.00017815376014,9.81001091422,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120111500000,11998,120110250000,RH_EXTIMU,2.30828462907e-06,1.53023926246e-05,-0.70334644478,0.710847225763,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.46462242869e-08,-1.37922151724e-08,-7.15237131828e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245789190641,-0.000177959551929,9.81000979245,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120112750000,11999,120112750000,RH_EXTIMU,2.30827874846e-06,1.53024032191e-05,-0.703346508333,0.710847162881,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.4113173696e-09,3.36839111261e-09,-7.15231166327e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244982202956,-0.000179215278344,9.8099866476,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120115250000,12000,120115250000,RH_EXTIMU,2.30830317151e-06,1.53023242698e-05,-0.703346571885,0.7108471,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.92058962255e-08,-3.05019446656e-08,-7.15225111907e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246187598178,-0.000179617467772,9.80998149299,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120117750000,12001,120117750000,RH_EXTIMU,2.30846553107e-06,1.5302160166e-05,-0.703346635436,0.710847037119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.85561860742e-07,-1.31373518886e-09,-7.15218797631e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244680879427,-0.000182569253637,9.8100004368,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120121500000,12002,120120250000,RH_EXTIMU,2.30833535908e-06,1.53021745481e-05,-0.703346698987,0.710846974239,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.12242678353e-08,-6.44136686885e-08,-7.152093976e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246743945769,-0.00017678524921,9.81001384421,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120122750000,12003,120122750000,RH_EXTIMU,2.30836956101e-06,1.53022651577e-05,-0.703346762537,0.71084691136,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.06400306976e-08,7.14247091961e-08,-7.15203086582e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243566256288,-0.000178919530906,9.80999909695,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120125250000,12004,120125250000,RH_EXTIMU,2.30846875388e-06,1.53022553649e-05,-0.703346826086,0.710846848481,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.28130296101e-08,5.08970321544e-08,-7.15196809807e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244711561517,-0.00018019126279,9.80999244186,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120127750000,12005,120127750000,RH_EXTIMU,2.30852269448e-06,1.5302188124e-05,-0.703346889635,0.710846785602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.94038243689e-08,-7.23485217166e-09,-7.15189698332e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245653743031,-0.000180041585541,9.80999924179,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120130250000,12006,120130250000,RH_EXTIMU,2.30851931638e-06,1.53022335788e-05,-0.703346953183,0.710846722725,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.6603374822e-08,2.46007066307e-08,-7.15182869951e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244606592583,-0.000178358047692,9.80999580363,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120132750000,12007,120132750000,RH_EXTIMU,2.30856270033e-06,1.53022108106e-05,-0.703347016731,0.710846659848,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.83766368119e-08,1.21158280596e-08,-7.1517474122e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245357381787,-0.000179598949498,9.81001356551,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120136500000,12008,120135250000,RH_EXTIMU,2.3083664643e-06,1.53022166907e-05,-0.703347080277,0.710846596971,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.1400952849e-07,-1.06421385103e-07,-7.15167847915e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246994734568,-0.000177064170735,9.80998408763,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120137750000,12009,120137750000,RH_EXTIMU,2.30850963484e-06,1.53020865921e-05,-0.703347143824,0.710846534095,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.55515475054e-07,7.22707126023e-09,-7.15161435963e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024474891588,-0.000181949309839,9.81000170689,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120140250000,12010,120140250000,RH_EXTIMU,2.30848565923e-06,1.5302106406e-05,-0.703347207369,0.71084647122,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.38892258396e-08,-1.5704656695e-09,-7.15153379078e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245460233118,-0.000178093076664,9.81000597695,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120142750000,12011,120142750000,RH_EXTIMU,2.30850389507e-06,1.53021167415e-05,-0.703347270914,0.710846408346,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.44879389594e-09,1.67907759612e-08,-7.1514600239e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244859402815,-0.000179377324825,9.81000673054,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120145250000,12012,120145250000,RH_EXTIMU,2.30846279002e-06,1.53020918467e-05,-0.703347334458,0.710846345472,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.47374458159e-09,-3.66336787165e-08,-7.15138349165e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246253038069,-0.000178749483009,9.81000209577,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120147750000,12013,120147750000,RH_EXTIMU,2.30842869349e-06,1.53020504495e-05,-0.703347398002,0.710846282599,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.79733727713e-09,-4.20746546689e-08,-7.15131401947e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245576607295,-0.000179131500074,9.80999585733,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120150250000,12014,120150250000,RH_EXTIMU,2.30857948696e-06,1.53020314936e-05,-0.703347461545,0.710846219726,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.73128576184e-08,7.47206641306e-08,-7.1512531099e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243738341455,-0.000180858020452,9.80999847424,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120152750000,12015,120152750000,RH_EXTIMU,2.30861950429e-06,1.53021130342e-05,-0.703347525087,0.710846156854,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.22301918264e-08,6.95394331479e-08,-7.1511721915e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244513531412,-0.000178191449879,9.81001168095,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120155250000,12016,120155250000,RH_EXTIMU,2.30853366449e-06,1.53021497507e-05,-0.703347588629,0.710846093983,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.85807026733e-08,-2.67680458745e-08,-7.15109441297e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246077674287,-0.000177978498553,9.81000123052,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120157750000,12017,120157750000,RH_EXTIMU,2.30854546324e-06,1.530207933e-05,-0.70334765217,0.710846031112,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.7227774775e-08,-3.27553797529e-08,-7.15103206826e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245696784925,-0.000179928529589,9.80999110803,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120160250000,12018,120160250000,RH_EXTIMU,2.308583815e-06,1.53019924384e-05,-0.70334771571,0.710845968242,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.15957573746e-08,-2.71813118367e-08,-7.15096385931e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245512950132,-0.000180206029088,9.80999578929,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120162750000,12019,120162750000,RH_EXTIMU,2.30858990197e-06,1.53019214696e-05,-0.70334777925,0.710845905372,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.42880574338e-08,-3.62810312448e-08,-7.15089035063e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024595938844,-0.000179626554843,9.81000050655,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120170250000,12020,120165250000,RH_EXTIMU,2.30853955387e-06,1.53018741962e-05,-0.703347842789,0.710845842503,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.13820166535e-09,-5.45607518355e-08,-7.15081597085e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245949213427,-0.000178871420453,9.8099978295,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120170250000,12021,120167750000,RH_EXTIMU,2.30869212503e-06,1.53018203428e-05,-0.703347906328,0.710845779635,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17959759872e-07,5.58755223179e-08,-7.15075228168e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243919914101,-0.00018135156473,9.81000451584,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120170250000,12022,120170250000,RH_EXTIMU,2.30853338629e-06,1.5301928696e-05,-0.703347969865,0.710845716767,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.50345111479e-07,-2.70486608006e-08,-7.15067286173e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246498242717,-0.000175453339248,9.80999249152,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120172750000,12023,120172750000,RH_EXTIMU,2.30864813694e-06,1.53018038557e-05,-0.703348033403,0.7108456539,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.36394849801e-07,-5.7738069417e-09,-7.15061411652e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244735758555,-0.000182344869503,9.8099965585,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120175250000,12024,120175250000,RH_EXTIMU,2.30883357578e-06,1.53018280001e-05,-0.703348096939,0.710845591034,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.27630562822e-08,1.18725027973e-07,-7.15054105545e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243317726644,-0.000180120997925,9.81001021887,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120177750000,12025,120177750000,RH_EXTIMU,2.30872689385e-06,1.53018602752e-05,-0.703348160475,0.710845528168,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.79341167698e-08,-4.10213185051e-08,-7.15046158585e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246446975848,-0.000177549688308,9.81000022254,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120180250000,12026,120180250000,RH_EXTIMU,2.30861899963e-06,1.53018408776e-05,-0.703348224011,0.710845465303,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.95484056894e-08,-7.10885096646e-08,-7.150399409e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246218840142,-0.000178207016007,9.80998329417,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120182750000,12027,120182750000,RH_EXTIMU,2.30880649744e-06,1.53017287558e-05,-0.703348287545,0.710845402438,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.70607954233e-07,4.23922163025e-08,-7.15032457152e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244494172599,-0.000181927998468,9.81001450949,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120185250000,12028,120185250000,RH_EXTIMU,2.30863147516e-06,1.53017768055e-05,-0.703348351079,0.710845339574,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.25673722627e-07,-7.05043661211e-08,-7.15025383935e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246447335351,-0.000176602842998,9.80998644817,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120187750000,12029,120187750000,RH_EXTIMU,2.30885767723e-06,1.53016361258e-05,-0.703348414613,0.710845276711,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.08687072933e-07,4.79300573964e-08,-7.15018544218e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244067863903,-0.00018328713567,9.81001417065,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120190250000,12030,120190250000,RH_EXTIMU,2.30875033913e-06,1.5301705891e-05,-0.703348478145,0.710845213848,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.94021419282e-08,-2.0070920428e-08,-7.1500922546e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246068613399,-0.000176431847581,9.81001508008,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120192750000,12031,120192750000,RH_EXTIMU,2.30869128101e-06,1.53018401586e-05,-0.703348541677,0.710845150986,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.08240680801e-07,4.37762283153e-08,-7.150020546e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244287108813,-0.000177391618918,9.81000546611,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120195250000,12032,120195250000,RH_EXTIMU,2.30871925566e-06,1.53018026801e-05,-0.703348605209,0.710845088125,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.78906785617e-08,-4.9201895391e-09,-7.1499573822e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245485449353,-0.000180182485354,9.80999092408,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120197750000,12033,120197750000,RH_EXTIMU,2.30875080098e-06,1.53017156138e-05,-0.70334866874,0.710845025264,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.78232905749e-08,-3.11105096451e-08,-7.14988572891e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245929737639,-0.000179751585054,9.80999690536,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120200250000,12034,120200250000,RH_EXTIMU,2.30878853961e-06,1.53016863821e-05,-0.70334873227,0.710844962404,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.88028629445e-08,5.26356716482e-09,-7.149816519e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244918506221,-0.000179665164866,9.81000068747,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120202750000,12035,120202750000,RH_EXTIMU,2.30885997944e-06,1.5301695514e-05,-0.703348795799,0.710844899544,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.63815759001e-08,4.60429342496e-08,-7.14974499928e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244449629447,-0.000179672453665,9.81000317055,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120205250000,12036,120205250000,RH_EXTIMU,2.30891314649e-06,1.53017041455e-05,-0.703348859328,0.710844836685,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.62718694283e-08,3.5476619821e-08,-7.14967689102e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244874882803,-0.000179336110806,9.8099968739,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120205250000,12037,120207750000,RH_EXTIMU,2.3087755265e-06,1.5301705491e-05,-0.703348922856,0.710844773827,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.81244659162e-08,-7.60186118544e-08,-7.14961150202e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247234290771,-0.000177019985856,9.80997902678,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120210250000,12038,120210250000,RH_EXTIMU,2.30898449711e-06,1.53014627788e-05,-0.703348986384,0.710844710969,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.5629938082e-07,-1.97890215573e-08,-7.14955130524e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244475450644,-0.000184520722036,9.81000256862,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120212750000,12039,120212750000,RH_EXTIMU,2.30900059293e-06,1.53014635293e-05,-0.703349049911,0.710844648112,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.62474595334e-09,1.01356891829e-08,-7.14946330242e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245441349285,-0.000178262668621,9.81001497934,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120215250000,12040,120215250000,RH_EXTIMU,2.30888659302e-06,1.53015699363e-05,-0.703349113437,0.710844585256,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.2380819971e-07,-2.98226371355e-09,-7.14938034392e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245289086324,-0.000176806175688,9.81001195915,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120217750000,12041,120217750000,RH_EXTIMU,2.30897316244e-06,1.530167167e-05,-0.703349176963,0.7108445224,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.11979818939e-09,1.07216403353e-07,-7.14931705698e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243324280296,-0.00017928011923,9.81000011232,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120220250000,12042,120220250000,RH_EXTIMU,2.3088368777e-06,1.53016743101e-05,-0.703349240488,0.710844459545,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.80935989013e-08,-7.45311561303e-08,-7.14925765144e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246908419041,-0.000177504293266,9.80997154432,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120222750000,12043,120222750000,RH_EXTIMU,2.30913759408e-06,1.53014478456e-05,-0.703349304013,0.71084439669,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.99330653034e-07,4.10742110868e-08,-7.14919677142e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244131074442,-0.000184711262636,9.81000288457,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120225250000,12044,120225250000,RH_EXTIMU,2.3090325367e-06,1.53014559899e-05,-0.703349367537,0.710844333836,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.34324540976e-08,-5.38301206313e-08,-7.14911776876e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246882633503,-0.000176528450276,9.80999249526,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120229000000,12045,120227750000,RH_EXTIMU,2.30902776181e-06,1.53013916269e-05,-0.70334943106,0.710844270982,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.43940941015e-08,-3.86363539876e-08,-7.14904804956e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245482553185,-0.000180014831428,9.81000256096,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120230250000,12046,120230250000,RH_EXTIMU,2.3090823963e-06,1.5301408644e-05,-0.703349494582,0.710844208129,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.23878122226e-08,4.10709649293e-08,-7.1489676552e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244441435921,-0.000179254998321,9.81001564994,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120232750000,12047,120232750000,RH_EXTIMU,2.30898489238e-06,1.53014803047e-05,-0.703349558104,0.710844145277,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.48764350942e-08,-1.34597285903e-08,-7.14889186866e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245724479155,-0.000177353143346,9.80999841674,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120235250000,12048,120235250000,RH_EXTIMU,2.3090274825e-06,1.5301411476e-05,-0.703349621626,0.710844082426,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.38421508019e-08,-1.45245660935e-08,-7.14883118416e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245329801543,-0.000180329995046,9.80999106159,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120237750000,12049,120237750000,RH_EXTIMU,2.3091103579e-06,1.53013540129e-05,-0.703349685146,0.710844019575,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.03561699235e-08,1.46065020468e-08,-7.14876482202e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244973996039,-0.000180311920108,9.80999592496,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120240250000,12050,120240250000,RH_EXTIMU,2.30918759786e-06,1.53013034174e-05,-0.703349748666,0.710843956724,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.32871611866e-08,1.53409765061e-08,-7.14869294878e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244984505059,-0.000180242307026,9.8100030543,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120242750000,12051,120242750000,RH_EXTIMU,2.30913589882e-06,1.53013242877e-05,-0.703349812186,0.710843893875,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.02496133377e-08,-1.65695661699e-08,-7.14861656805e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245759028186,-0.000177891908162,9.81000117105,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120245250000,12052,120245250000,RH_EXTIMU,2.3091191865e-06,1.53013316077e-05,-0.703349875705,0.710843831025,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.27290417624e-08,-4.58900288046e-09,-7.14854813195e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245173117445,-0.000178929300752,9.80999592336,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120249000000,12053,120247750000,RH_EXTIMU,2.30921656861e-06,1.53012547113e-05,-0.703349939223,0.710843768177,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.95404645024e-08,1.17178832244e-08,-7.14848522508e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245058919678,-0.000180845585469,9.80999390926,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120250250000,12054,120250250000,RH_EXTIMU,2.30927437687e-06,1.53011979087e-05,-0.70335000274,0.710843705329,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.5729418383e-08,8.77321170674e-10,-7.14841565234e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245286882472,-0.000179926080413,9.80999761031,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120252750000,12055,120252750000,RH_EXTIMU,2.30926647297e-06,1.53011783635e-05,-0.703350066257,0.710843642482,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.39653971001e-09,-1.49102483742e-08,-7.14834007261e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245587282165,-0.000178891348334,9.81000523397,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120255250000,12056,120255250000,RH_EXTIMU,2.30914613584e-06,1.53012405775e-05,-0.703350129773,0.710843579635,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.02545640703e-07,-3.1679845393e-08,-7.14825628753e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245733931437,-0.000177034032946,9.81000853041,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120257750000,12057,120257750000,RH_EXTIMU,2.30909653419e-06,1.53012716124e-05,-0.703350193289,0.710843516789,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.4776362288e-08,-9.60911050609e-09,-7.14818272868e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245315157658,-0.000178419117211,9.81000333482,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120260250000,12058,120260250000,RH_EXTIMU,2.30930689967e-06,1.53012912953e-05,-0.703350256804,0.710843453944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.09447949382e-07,1.30213608543e-07,-7.14810434193e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243024637009,-0.000181095482547,9.81002476232,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120262750000,12059,120262750000,RH_EXTIMU,2.30923574097e-06,1.53014001334e-05,-0.703350320318,0.710843391099,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.00813619893e-07,2.25058323867e-08,-7.14802400098e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245224536267,-0.000177276186237,9.81000712521,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120266500000,12060,120265250000,RH_EXTIMU,2.30923342594e-06,1.5301413664e-05,-0.703350383831,0.710843328255,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.03635737428e-09,7.04386592391e-09,-7.14795343809e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245200872699,-0.000179100521766,9.81000108519,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120267750000,12061,120267750000,RH_EXTIMU,2.30926479212e-06,1.53013810798e-05,-0.703350447344,0.710843265412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.70652407124e-08,-2.28769144859e-10,-7.14788398956e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245286745065,-0.000179688261754,9.80999881067,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120270250000,12062,120270250000,RH_EXTIMU,2.30914190634e-06,1.5301379814e-05,-0.703350510856,0.710843202569,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.82762226877e-08,-6.92133148272e-08,-7.14781614845e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024679379179,-0.00017724089986,9.80998318534,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120272750000,12063,120272750000,RH_EXTIMU,2.30922329867e-06,1.53012229496e-05,-0.703350574368,0.710843139727,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.35443806918e-07,-4.27549908188e-08,-7.14776690456e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245361582283,-0.000181860194379,9.80997795172,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120276500000,12064,120275250000,RH_EXTIMU,2.30936834705e-06,1.53010766523e-05,-0.703350637879,0.710843076885,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.65697448602e-07,-9.27706249168e-10,-7.1477023548e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245246774711,-0.000181442702896,9.8099921624,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120279000000,12065,120277750000,RH_EXTIMU,2.30956050782e-06,1.53010112823e-05,-0.70335070139,0.710843014044,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.46952915787e-07,7.16027188626e-08,-7.14762321648e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244087515846,-0.000181323178598,9.81001849304,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120280250000,12066,120280250000,RH_EXTIMU,2.3094982955e-06,1.53010726338e-05,-0.703350764899,0.710842951204,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.90063491613e-08,5.35253462279e-10,-7.14754427134e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245000189965,-0.00017808950572,9.81000835619,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120285250000,12067,120282750000,RH_EXTIMU,2.30934303288e-06,1.53011759399e-05,-0.703350828408,0.710842888364,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.45528718521e-07,-2.79638521757e-08,-7.14746594655e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246513084204,-0.000175634431745,9.80999689716,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120285250000,12068,120285250000,RH_EXTIMU,2.30938869919e-06,1.53011044216e-05,-0.703350891917,0.710842825525,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.71047088093e-08,-1.43231727769e-08,-7.14740216496e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244942456203,-0.000181024150499,9.80999838628,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120287750000,12069,120287750000,RH_EXTIMU,2.30942529437e-06,1.53010506809e-05,-0.703350955425,0.710842762686,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.19430811587e-08,-9.31768873248e-09,-7.14732414276e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245563267924,-0.000179515025821,9.81000698489,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120290250000,12070,120290250000,RH_EXTIMU,2.3093833558e-06,1.530105828e-05,-0.703351018932,0.710842699849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.7231752756e-08,-1.86247760207e-08,-7.14725075807e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245539494745,-0.00017852774029,9.80999967553,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120292750000,12071,120292750000,RH_EXTIMU,2.30934941496e-06,1.53010349057e-05,-0.703351082439,0.710842637011,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.25555686334e-09,-3.17383572143e-08,-7.14718944013e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024583595928,-0.000178680116929,9.80998328894,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120295250000,12072,120295250000,RH_EXTIMU,2.30951334526e-06,1.53009158534e-05,-0.703351145945,0.710842574174,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.61104847574e-07,2.51903096755e-08,-7.14713624881e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024454388025,-0.000182079506817,9.80998664394,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120297750000,12073,120297750000,RH_EXTIMU,2.30970404379e-06,1.53008453092e-05,-0.70335120945,0.710842511338,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.4903259986e-07,6.78376292949e-08,-7.14705125355e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244347272521,-0.000181128796968,9.81002319257,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120300250000,12074,120300250000,RH_EXTIMU,2.30955795513e-06,1.5300962691e-05,-0.703351272955,0.710842448503,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.48231871602e-07,-1.47975431538e-08,-7.14696595253e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245605415694,-0.000176292831596,9.81001024189,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120302750000,12075,120302750000,RH_EXTIMU,2.3095306308e-06,1.53010478138e-05,-0.703351336459,0.710842385668,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.25421913996e-08,3.36840627171e-08,-7.1468933218e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244596736458,-0.000178150502196,9.8100058785,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120305250000,12076,120305250000,RH_EXTIMU,2.30954312223e-06,1.53010669418e-05,-0.703351399962,0.710842322834,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.76599073328e-09,1.85580985962e-08,-7.14682201658e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245087231307,-0.000179088805111,9.81000094856,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120307750000,12077,120307750000,RH_EXTIMU,2.30956911382e-06,1.53010418964e-05,-0.703351463464,0.710842260001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.9766738035e-08,1.0341165951e-09,-7.14675174259e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245298026889,-0.000179531370142,9.80999929513,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120310250000,12078,120310250000,RH_EXTIMU,2.30964402599e-06,1.53009594987e-05,-0.703351526966,0.710842197168,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.98576602475e-08,-4.05398143325e-09,-7.1466795564e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245391664635,-0.000180616632148,9.81000335902,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120312750000,12079,120312750000,RH_EXTIMU,2.30964812478e-06,1.5300928803e-05,-0.703351590468,0.710842134336,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.04961320933e-08,-1.44977068217e-08,-7.14660777092e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024543666889,-0.000179238720058,9.81000012623,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120315250000,12080,120315250000,RH_EXTIMU,2.30953238154e-06,1.53009638909e-05,-0.703351653969,0.710842071504,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.46700097653e-08,-4.45212566008e-08,-7.14653780724e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246213645945,-0.000176979102337,9.80998953878,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120317750000,12081,120317750000,RH_EXTIMU,2.30957275364e-06,1.53009147396e-05,-0.703351717469,0.710842008673,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.15084434279e-08,-4.58263481619e-09,-7.14647561885e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244945856018,-0.000180261147122,9.80999305757,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120320250000,12082,120320250000,RH_EXTIMU,2.30962844541e-06,1.53008573595e-05,-0.703351780968,0.710841945843,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.48504890756e-08,-6.42028751803e-10,-7.14640544677e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245316054369,-0.000179923935523,9.80999768987,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120322750000,12083,120322750000,RH_EXTIMU,2.30964685084e-06,1.53008329859e-05,-0.703351844467,0.710841883013,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.50746129929e-08,-2.85247486242e-09,-7.14633385206e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245298696028,-0.000179277248099,9.80999987827,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120325250000,12084,120325250000,RH_EXTIMU,2.3096567601e-06,1.53008222293e-05,-0.703351907966,0.710841820183,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.2581066803e-08,1.10468992355e-10,-7.14626210234e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245253131603,-0.000179138312286,9.8100004583,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120327750000,12085,120327750000,RH_EXTIMU,2.30979847632e-06,1.53007346461e-05,-0.703351971463,0.710841757355,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.30765007419e-07,3.0586629183e-08,-7.1461869246e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244582664506,-0.000181779359549,9.81001490531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120330250000,12086,120330250000,RH_EXTIMU,2.30962619879e-06,1.5300810444e-05,-0.70335203496,0.710841694527,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.39726409849e-07,-5.31814175937e-08,-7.14610270687e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246585282232,-0.000175631065633,9.80999947817,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120332750000,12087,120332750000,RH_EXTIMU,2.30963305477e-06,1.53008131593e-05,-0.703352098456,0.7108416317,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.26430643355e-09,6.05355715716e-09,-7.14604811124e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244868906134,-0.000179477908054,9.80998530351,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120335250000,12088,120335250000,RH_EXTIMU,2.30973089258e-06,1.53006919549e-05,-0.703352161952,0.710841568873,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.24730572706e-07,-1.32224530549e-08,-7.14598697207e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245603545521,-0.000181131931721,9.80998882395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120341500000,12089,120337750000,RH_EXTIMU,2.30974882362e-06,1.53006018699e-05,-0.703352225447,0.710841506047,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.17793910847e-08,-4.04877535578e-08,-7.14591459946e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245804634782,-0.000179761335628,9.80999749249,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120341500000,12090,120340250000,RH_EXTIMU,2.30980289376e-06,1.53005791367e-05,-0.703352288942,0.710841443221,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.44331127172e-08,1.81481864571e-08,-7.14584415211e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244666518633,-0.000179732874,9.81000167019,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120342750000,12091,120342750000,RH_EXTIMU,2.30987448512e-06,1.53006512841e-05,-0.703352352436,0.710841380396,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.00933433589e-09,8.19631341166e-08,-7.14576748594e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244043350864,-0.000178743295921,9.81001243719,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120345250000,12092,120345250000,RH_EXTIMU,2.30970548088e-06,1.53006497551e-05,-0.703352415929,0.710841317572,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.43545671989e-08,-9.53134339112e-08,-7.14569703782e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247181393075,-0.000177470114604,9.80998529256,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120347750000,12093,120347750000,RH_EXTIMU,2.30981376023e-06,1.53004903665e-05,-0.703352479422,0.710841254748,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.52153894587e-07,-2.90614803853e-08,-7.14562847637e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245531576735,-0.000181692548868,9.81000297241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120347750000,12094,120350250000,RH_EXTIMU,2.30975629433e-06,1.5300498845e-05,-0.703352542913,0.710841191925,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.65567530197e-08,-2.68618809844e-08,-7.14555456465e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245575187009,-0.00017789136494,9.80999886496,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120352750000,12095,120352750000,RH_EXTIMU,2.30986087077e-06,1.53005049698e-05,-0.703352606405,0.710841129103,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.69167452588e-08,6.29779199553e-08,-7.14548156025e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024387170116,-0.000180435905827,9.81001347233,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120355250000,12096,120355250000,RH_EXTIMU,2.30979469426e-06,1.530059443e-05,-0.703352669895,0.710841066281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.70772064447e-08,1.42888936163e-08,-7.14539963671e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245450742008,-0.000177085124803,9.81000544642,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120357750000,12097,120357750000,RH_EXTIMU,2.30977328354e-06,1.53005750138e-05,-0.703352733385,0.71084100346,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.57306493663e-10,-2.24372611287e-08,-7.14533270176e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245659598883,-0.000179246823673,9.80999512786,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120360250000,12098,120360250000,RH_EXTIMU,2.30988232534e-06,1.53005313346e-05,-0.703352796875,0.710840940639,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.74797945783e-08,3.71683857664e-08,-7.14526480852e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244537951953,-0.000180485230844,9.81000193335,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120362750000,12099,120362750000,RH_EXTIMU,2.30983465485e-06,1.53004625666e-05,-0.703352860363,0.71084087782,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.24788550617e-08,-6.52782245282e-08,-7.14519876155e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246365704199,-0.000179220797383,9.80998732849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120365250000,12100,120365250000,RH_EXTIMU,2.31002021888e-06,1.53004132598e-05,-0.703352923851,0.710840815,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34162472782e-07,7.70257632287e-08,-7.14512676942e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243520620028,-0.000181371739571,9.81001319404,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120367750000,12101,120367750000,RH_EXTIMU,2.30982740606e-06,1.53005648457e-05,-0.703352987339,0.710840752182,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.94048881131e-07,-2.16380304438e-08,-7.14504711685e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024665995816,-0.000174536832551,9.80999053845,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120370250000,12102,120370250000,RH_EXTIMU,2.31002401645e-06,1.53004148989e-05,-0.703353050826,0.710840689363,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.97072536279e-07,2.60101939397e-08,-7.14499555265e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243953593734,-0.000183664744192,9.80999554073,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120372750000,12103,120372750000,RH_EXTIMU,2.31006942108e-06,1.53004053321e-05,-0.703353114312,0.710840626546,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.20966386716e-08,2.07595763617e-08,-7.14491858456e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245446646327,-0.000178642351749,9.81000146066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120375250000,12104,120375250000,RH_EXTIMU,2.30998625941e-06,1.53003910641e-05,-0.703353177798,0.710840563729,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.83702258301e-08,-5.42558690973e-08,-7.14484421903e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246165170524,-0.000178350410311,9.80999773326,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120377750000,12105,120377750000,RH_EXTIMU,2.30999661599e-06,1.53003448291e-05,-0.703353241282,0.710840500913,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.27982663086e-08,-1.98135060868e-08,-7.14477467687e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245412708438,-0.000179559278958,9.80999911802,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120380250000,12106,120380250000,RH_EXTIMU,2.31001637205e-06,1.53003188501e-05,-0.703353304767,0.710840438097,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.67458218939e-08,-3.005606242e-09,-7.14470391227e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245256894923,-0.000179365859592,9.80999963766,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120386500000,12107,120382750000,RH_EXTIMU,2.31004410404e-06,1.53003369771e-05,-0.70335336825,0.710840375282,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.46378097084e-09,2.65642144947e-08,-7.14463118984e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244775129767,-0.000178972259122,9.8100038304,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120386500000,12108,120385250000,RH_EXTIMU,2.31015294757e-06,1.53003445042e-05,-0.703353431733,0.710840312468,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.8554080511e-08,6.61763472883e-08,-7.1445480357e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244303940002,-0.000180045541241,9.81002229104,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120387750000,12109,120387750000,RH_EXTIMU,2.30992704337e-06,1.53003946684e-05,-0.703353495216,0.710840249654,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.55798847812e-07,-9.79338762874e-08,-7.14447467995e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247051448908,-0.000176308589675,9.80998840833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120390250000,12110,120390250000,RH_EXTIMU,2.3100712883e-06,1.53002942326e-05,-0.703353558697,0.710840186841,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.39434677976e-07,2.4700655588e-08,-7.14441606299e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244447767474,-0.00018178105318,9.80999561615,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120392750000,12111,120392750000,RH_EXTIMU,2.31006803779e-06,1.53002713771e-05,-0.703353622178,0.710840124029,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.19050010396e-08,-1.41747527027e-08,-7.14434034599e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245788243833,-0.00017854667933,9.81000037078,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120395250000,12112,120395250000,RH_EXTIMU,2.31010984959e-06,1.53002962385e-05,-0.703353685659,0.710840061217,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.06812458825e-08,3.83162610037e-08,-7.14426618597e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244211337049,-0.0001794462731,9.8100084547,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120397750000,12113,120397750000,RH_EXTIMU,2.31005152292e-06,1.53003019049e-05,-0.703353749139,0.710839998406,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.54640534342e-08,-2.89455875777e-08,-7.14419246317e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246165563426,-0.000178170727265,9.80999672562,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120400250000,12114,120400250000,RH_EXTIMU,2.3101641981e-06,1.53002274698e-05,-0.703353812618,0.710839935595,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.06851654362e-07,2.17227635597e-08,-7.14413034639e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244724263272,-0.000181057385332,9.80999545238,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120402750000,12115,120402750000,RH_EXTIMU,2.31024450683e-06,1.53001680084e-05,-0.703353876096,0.710839872785,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.00203363585e-08,1.20257921017e-08,-7.14406267503e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245132849647,-0.000180178629732,9.80999668215,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120405250000,12116,120405250000,RH_EXTIMU,2.31022980304e-06,1.53001506077e-05,-0.703353939574,0.710839809976,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.32249817347e-09,-1.75173710602e-08,-7.14398834662e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245696777188,-0.000178683469814,9.81000221281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120407750000,12117,120407750000,RH_EXTIMU,2.31016583995e-06,1.53001920248e-05,-0.703354003051,0.710839747167,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.87856579205e-08,-1.17867498521e-08,-7.14390893761e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245260093311,-0.00017793385493,9.81000651563,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120410250000,12118,120410250000,RH_EXTIMU,2.31014058388e-06,1.53002011911e-05,-0.703354066528,0.710839684359,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.86271132577e-08,-8.34706358839e-09,-7.14383643057e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245511646138,-0.000178692122875,9.81000112994,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120412750000,12119,120412750000,RH_EXTIMU,2.31005116306e-06,1.5300207106e-05,-0.703354130004,0.710839621551,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.32862538893e-08,-4.63005279976e-08,-7.14376845068e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246114825273,-0.000177777219511,9.80998807288,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120415250000,12120,120415250000,RH_EXTIMU,2.3103243877e-06,1.53000780919e-05,-0.703354193479,0.710839558744,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.2886221598e-07,8.10237442033e-08,-7.14371064626e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243112933529,-0.000183798814824,9.81000468681,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120417750000,12121,120417750000,RH_EXTIMU,2.31040058884e-06,1.53001309139e-05,-0.703354256954,0.710839495938,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.4504349397e-08,7.35669564951e-08,-7.14362575248e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244668105623,-0.00017853236507,9.81001421658,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120420250000,12122,120420250000,RH_EXTIMU,2.31014986786e-06,1.53001691251e-05,-0.703354320428,0.710839433133,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.63185659707e-07,-1.18695519527e-07,-7.14354739978e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247578144447,-0.000175983801038,9.8099930627,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120422750000,12123,120422750000,RH_EXTIMU,2.31016752596e-06,1.53000968257e-05,-0.703354383901,0.710839370328,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.16163104506e-08,-3.05272364093e-08,-7.14348184695e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024539249814,-0.000180070599517,9.80999751447,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120425250000,12124,120425250000,RH_EXTIMU,2.31026000047e-06,1.53000735651e-05,-0.703354447374,0.710839307523,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.65689488467e-08,3.94576739864e-08,-7.14341592171e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244475909904,-0.000179981728558,9.80999619263,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120427750000,12125,120427750000,RH_EXTIMU,2.31015805213e-06,1.53000806181e-05,-0.703354510846,0.710839244719,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.10507088679e-08,-5.27024304993e-08,-7.14335392063e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246755246735,-0.000177307836653,9.80997596677,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120427750000,12126,120430250000,RH_EXTIMU,2.31046357669e-06,1.52998312093e-05,-0.703354574318,0.710839181916,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.14974254326e-07,3.07334586251e-08,-7.1432985495e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243627764207,-0.000185572819382,9.81000264722,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120431500000,12127,120432750000,RH_EXTIMU,2.31047777129e-06,1.52998716015e-05,-0.703354637789,0.710839119113,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.37629938613e-08,3.16083111527e-08,-7.14321077253e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245372323447,-0.000177564935678,9.81001040737,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120435250000,12128,120435250000,RH_EXTIMU,2.31038676012e-06,1.52999529307e-05,-0.703354701259,0.710839056311,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.66251089517e-08,-4.30954676814e-09,-7.14312524449e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245399223384,-0.000177263635532,9.81001801366,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120437750000,12129,120437750000,RH_EXTIMU,2.31030513415e-06,1.53000453449e-05,-0.703354764728,0.71083899351,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.7525354794e-08,7.27504938931e-09,-7.14305015353e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244994671738,-0.000177566877656,9.81000295671,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120440250000,12130,120440250000,RH_EXTIMU,2.31028451172e-06,1.53000263934e-05,-0.703354828197,0.710838930709,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.70745703878e-10,-2.17297027437e-08,-7.14298853652e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246006188458,-0.000178920460859,9.80998587308,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120442750000,12131,120442750000,RH_EXTIMU,2.31033605266e-06,1.5299914268e-05,-0.703354891666,0.710838867909,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.32939124273e-08,-3.41098398573e-08,-7.14292907792e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245460303791,-0.000180648945177,9.80998600236,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120445250000,12132,120445250000,RH_EXTIMU,2.31046951077e-06,1.5299820942e-05,-0.703354955134,0.71083880511,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.29299687446e-07,2.26743201031e-08,-7.14286709651e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244799157552,-0.000181143625861,9.80999191758,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120447750000,12133,120447750000,RH_EXTIMU,2.31050829776e-06,1.52997188956e-05,-0.703355018601,0.710838742311,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.03698462808e-08,-3.55547032122e-08,-7.14279772473e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246096194341,-0.000180017373584,9.80999369761,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120450250000,12134,120450250000,RH_EXTIMU,2.31059932157e-06,1.52996361227e-05,-0.703355082067,0.710838679512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.92305061542e-08,4.79839467248e-09,-7.14272314294e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244686099998,-0.000180800947325,9.81001262958,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120452750000,12135,120452750000,RH_EXTIMU,2.31057145556e-06,1.52997669216e-05,-0.703355145533,0.710838616715,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.85521811761e-08,5.93530977017e-08,-7.14263217744e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244319299489,-0.000177137358432,9.81002362112,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120455250000,12136,120455250000,RH_EXTIMU,2.31036719045e-06,1.52999703218e-05,-0.703355208998,0.710838553918,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.29716827376e-07,1.38237284973e-09,-7.14255357735e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245770507487,-0.000174625317941,9.8099978903,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120457750000,12137,120457750000,RH_EXTIMU,2.31045535912e-06,1.5299910895e-05,-0.703355272463,0.710838491121,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.44703694858e-08,1.64681240512e-08,-7.1425007264e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244793058917,-0.000181259929454,9.80998721969,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120460250000,12138,120460250000,RH_EXTIMU,2.31057829586e-06,1.52997844396e-05,-0.703355335927,0.710838428325,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.41957819062e-07,-2.08558478995e-09,-7.14242708819e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245401362664,-0.000181172093333,9.81000467858,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120462750000,12139,120462750000,RH_EXTIMU,2.31055868704e-06,1.52997427476e-05,-0.70335539939,0.71083836553,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.32013257923e-08,-3.40913020612e-08,-7.142344535e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245867600121,-0.000179009480426,9.81001125318,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120465250000,12140,120465250000,RH_EXTIMU,2.31046978894e-06,1.52998139274e-05,-0.703355462852,0.710838302736,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.97126447141e-08,-8.89243371014e-09,-7.14227245702e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245154936283,-0.000177379265033,9.8099996632,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120467750000,12141,120467750000,RH_EXTIMU,2.31044689705e-06,1.52998273352e-05,-0.703355526314,0.710838239942,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.96694948917e-08,-4.60498488406e-09,-7.14220561656e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245509069651,-0.000178569721464,9.80999103441,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120470250000,12142,120470250000,RH_EXTIMU,2.31055285125e-06,1.5299716166e-05,-0.703355589776,0.710838177149,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.23699041831e-07,-2.94859968172e-09,-7.14214613888e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245146679296,-0.000181352223638,9.80999060884,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120472750000,12143,120472750000,RH_EXTIMU,2.31070362524e-06,1.52996172311e-05,-0.703355653236,0.710838114356,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.42302718218e-07,2.92280499812e-08,-7.14207594864e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244611476403,-0.000181403086502,9.81000495573,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120475250000,12144,120475250000,RH_EXTIMU,2.31067746164e-06,1.52996595484e-05,-0.703355716696,0.710838051564,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.77969958952e-08,9.99403632934e-09,-7.14199518655e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245351257422,-0.000177812860257,9.81000716205,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120477750000,12145,120477750000,RH_EXTIMU,2.31059454308e-06,1.52996881622e-05,-0.703355780156,0.710837988773,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.23610860549e-08,-2.97339265942e-08,-7.14192628393e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245714712455,-0.000178014614711,9.80999370728,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120480250000,12146,120480250000,RH_EXTIMU,2.31076164043e-06,1.52996718746e-05,-0.703355843614,0.710837925982,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.05080899714e-07,8.54120580097e-08,-7.14184742089e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243818073079,-0.000180759204794,9.81002138414,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120482750000,12147,120482750000,RH_EXTIMU,2.31056657574e-06,1.52997011786e-05,-0.703355907072,0.710837863192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.26523649676e-07,-9.24443530877e-08,-7.14176453546e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247134019926,-0.000176725396489,9.81000063069,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120485250000,12148,120485250000,RH_EXTIMU,2.31054871886e-06,1.52996857784e-05,-0.70335597053,0.710837800402,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.96409525964e-10,-1.81542453165e-08,-7.14171292764e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024505894722,-0.000179230274363,9.80997799422,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120487750000,12149,120487750000,RH_EXTIMU,2.31076882687e-06,1.5299541933e-05,-0.703356033987,0.710837737613,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.07001243958e-07,4.27020639281e-08,-7.14165109807e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244568422054,-0.000182543475288,9.80999762512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120490250000,12150,120490250000,RH_EXTIMU,2.31080671545e-06,1.52995416103e-05,-0.703356097443,0.710837674825,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.26204064461e-08,2.17870546971e-08,-7.14157279312e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244944655724,-0.000178894874045,9.81000531949,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120492750000,12151,120492750000,RH_EXTIMU,2.31075285169e-06,1.52995485392e-05,-0.703356160899,0.710837612037,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.36367077571e-08,-2.57169204974e-08,-7.14150069461e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024590354649,-0.000178285992415,9.80999746878,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120495250000,12152,120495250000,RH_EXTIMU,2.3107969069e-06,1.52994877906e-05,-0.703356224354,0.71083754925,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.01279167332e-08,-9.10550137433e-09,-7.14142542852e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245306350368,-0.000180159824867,9.81001100718,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120497750000,12153,120497750000,RH_EXTIMU,2.31059875513e-06,1.52995889685e-05,-0.703356287808,0.710837486464,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.68721548818e-07,-5.33089978635e-08,-7.14133930602e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246278968076,-0.000175427113609,9.81000266047,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120500250000,12154,120500250000,RH_EXTIMU,2.31064302937e-06,1.52995745172e-05,-0.703356351261,0.710837423678,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.42016801904e-08,1.7345601045e-08,-7.14128127362e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244633569091,-0.000180106767204,9.80999278648,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120502750000,12155,120502750000,RH_EXTIMU,2.31079161839e-06,1.52995110874e-05,-0.703356414714,0.710837360893,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.21081784247e-07,4.81894152076e-08,-7.14121459931e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244409698496,-0.000181150630268,9.81000047698,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120505250000,12156,120505250000,RH_EXTIMU,2.31082757468e-06,1.52994779764e-05,-0.703356478167,0.710837298108,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.99710553334e-08,2.05396823067e-09,-7.14113672834e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245558209026,-0.000179336267043,9.81000578871,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120507750000,12157,120507750000,RH_EXTIMU,2.31072407489e-06,1.52994886737e-05,-0.703356541618,0.710837235324,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.39837337743e-08,-5.15034171747e-08,-7.14106118374e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246095125777,-0.000177721801766,9.81000005406,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120510250000,12158,120510250000,RH_EXTIMU,2.31081392701e-06,1.52995351053e-05,-0.703356605069,0.710837172541,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.58624908952e-08,7.76138518703e-08,-7.1409952119e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243663769198,-0.000179519818537,9.81000244087,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120512750000,12159,120512750000,RH_EXTIMU,2.31081760055e-06,1.52995361873e-05,-0.70335666852,0.710837109758,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.37287525713e-09,3.33348967202e-09,-7.14092478198e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245708411819,-0.000178898485661,9.80999392888,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120515250000,12160,120515250000,RH_EXTIMU,2.31091703806e-06,1.52993929343e-05,-0.70335673197,0.710837046976,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.38046127322e-07,-2.48604830173e-08,-7.14085918343e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245424244347,-0.000181660971626,9.80999869041,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120517750000,12161,120517750000,RH_EXTIMU,2.31090596869e-06,1.52993965797e-05,-0.703356795419,0.710836984194,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.45337718766e-09,-3.50442922363e-09,-7.14078530219e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245303391556,-0.00017824336823,9.80999904158,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120520250000,12162,120520250000,RH_EXTIMU,2.3109581281e-06,1.52994015419e-05,-0.703356858867,0.710836921414,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.77619439886e-08,3.28223128776e-08,-7.14071674952e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244687936485,-0.000179643146722,9.81000178388,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120522750000,12163,120522750000,RH_EXTIMU,2.31095306992e-06,1.52994052883e-05,-0.703356922315,0.710836858633,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.09182525177e-09,-6.46042698644e-11,-7.14064441958e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245336825016,-0.000178669860272,9.80999725582,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120525250000,12164,120525250000,RH_EXTIMU,2.3110444715e-06,1.52993776723e-05,-0.703356985763,0.710836795854,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.84090590589e-08,3.63770426772e-08,-7.1405819633e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244622051574,-0.000180274984158,9.80999533977,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120527750000,12165,120527750000,RH_EXTIMU,2.31110228729e-06,1.52993396096e-05,-0.703357049209,0.710836733074,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.51879754015e-08,1.15381577026e-08,-7.14051194514e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245204742924,-0.000179747850308,9.80999812843,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120530250000,12166,120530250000,RH_EXTIMU,2.311048874e-06,1.52992847521e-05,-0.703357112655,0.710836670296,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.38567839491e-09,-6.05996437028e-08,-7.14042771865e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246463486415,-0.000178731535176,9.81001082061,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120532750000,12167,120532750000,RH_EXTIMU,2.31103959253e-06,1.52992807939e-05,-0.703357176101,0.710836607518,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.1582572222e-09,-6.822394402e-09,-7.14035200711e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245088250849,-0.000179090419476,9.81000818791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120535250000,12168,120535250000,RH_EXTIMU,2.31095306341e-06,1.52992962921e-05,-0.703357239545,0.710836544741,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.70344834661e-08,-3.92242971447e-08,-7.14027653211e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245932079175,-0.000177902973619,9.81000152159,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120537750000,12169,120537750000,RH_EXTIMU,2.31088953945e-06,1.52993270103e-05,-0.703357302989,0.710836481965,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.2516259096e-08,-1.76244525139e-08,-7.14021782204e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245297220085,-0.000178099495794,9.80998175577,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120540250000,12170,120540250000,RH_EXTIMU,2.31111772233e-06,1.52992228141e-05,-0.703357366433,0.710836419189,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.89282899167e-07,6.97931330514e-08,-7.14015832394e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243966299151,-0.000182408936718,9.80999732448,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120542750000,12171,120542750000,RH_EXTIMU,2.31114319857e-06,1.52992198512e-05,-0.703357429876,0.710836356413,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.70472995804e-08,1.33012407315e-08,-7.14008000402e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245473499625,-0.000178723990096,9.81000250922,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120546500000,12172,120545250000,RH_EXTIMU,2.3112080358e-06,1.52991265539e-05,-0.703357493318,0.710836293639,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.02605594397e-08,-1.5921260713e-08,-7.14000790643e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245470530919,-0.000180869570094,9.81000564634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120547750000,12173,120547750000,RH_EXTIMU,2.31103455968e-06,1.52991367139e-05,-0.70335755676,0.710836230865,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.03474867722e-07,-9.1183868356e-08,-7.13993161698e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247078769938,-0.000176283800525,9.80999095757,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120550250000,12174,120550250000,RH_EXTIMU,2.31109955784e-06,1.5299073231e-05,-0.703357620201,0.710836168091,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.35759058589e-08,1.12382400355e-09,-7.13987131706e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244575642322,-0.000180836317091,9.80999684553,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120552750000,12175,120552750000,RH_EXTIMU,2.31114513719e-06,1.52990600925e-05,-0.703357683641,0.710836105318,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.42049207343e-08,1.88264165454e-08,-7.13979309279e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024500389887,-0.000179238990164,9.81000864156,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120555250000,12176,120555250000,RH_EXTIMU,2.31104666694e-06,1.52991460881e-05,-0.70335774708,0.710836042546,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.03492957701e-07,-5.85386734262e-09,-7.13971185086e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245555614016,-0.000176897688847,9.81000580926,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120557750000,12177,120557750000,RH_EXTIMU,2.31103818199e-06,1.52991373425e-05,-0.703357810519,0.710835979775,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.88401700386e-10,-9.09671480727e-09,-7.13964293374e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245314853372,-0.000179262641006,9.8099995718,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120560250000,12178,120560250000,RH_EXTIMU,2.31099386131e-06,1.52991051981e-05,-0.703357873958,0.710835917004,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.22406886849e-09,-4.25671775983e-08,-7.13957826258e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245932665363,-0.000178782611797,9.80998718312,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120562750000,12179,120562750000,RH_EXTIMU,2.31124195916e-06,1.52990128901e-05,-0.703357937396,0.710835854233,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.93918410688e-07,8.77595736294e-08,-7.13951073928e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024366413441,-0.000182386172041,9.81000940913,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120565250000,12180,120565250000,RH_EXTIMU,2.31127296522e-06,1.52990403426e-05,-0.703358000833,0.710835791463,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.07750607579e-09,3.3709031583e-08,-7.1394352799e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244836394819,-0.000178840084814,9.81000485524,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120567750000,12181,120567750000,RH_EXTIMU,2.31117400419e-06,1.52990798456e-05,-0.703358064269,0.710835728694,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.76113723488e-08,-3.25689524955e-08,-7.13936143444e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024626851053,-0.000177257362494,9.80999481981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120570250000,12182,120570250000,RH_EXTIMU,2.31126330364e-06,1.52989710219e-05,-0.703358127705,0.710835665926,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12907860223e-07,-1.09860642225e-08,-7.1392955304e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244871250911,-0.000181503266615,9.81000153456,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120572750000,12183,120572750000,RH_EXTIMU,2.31112299589e-06,1.5298953071e-05,-0.70335819114,0.710835603158,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.87954042534e-08,-8.85064642103e-08,-7.13922722821e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246935485595,-0.000177222822329,9.80998192642,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120575250000,12184,120575250000,RH_EXTIMU,2.31137505205e-06,1.52987933989e-05,-0.703358254575,0.710835540391,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.34074170321e-07,5.16790614437e-08,-7.13916034698e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243805796057,-0.000183590910962,9.81001326808,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120577750000,12185,120577750000,RH_EXTIMU,2.31121355273e-06,1.52988743145e-05,-0.703358318009,0.710835477624,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.3647723128e-07,-4.42084750312e-08,-7.13908545737e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246437794267,-0.000175695573087,9.80998704618,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120580250000,12186,120580250000,RH_EXTIMU,2.31137986218e-06,1.52988071633e-05,-0.703358381442,0.710835414858,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.33252412336e-07,5.60442772517e-08,-7.13902043391e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244020216752,-0.000181669067744,9.81000773376,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120582750000,12187,120582750000,RH_EXTIMU,2.31120230699e-06,1.52988641363e-05,-0.703358444875,0.710835352092,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.32135563157e-07,-6.68582940206e-08,-7.13893215383e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247210220738,-0.000175804432539,9.81000301665,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120585250000,12188,120585250000,RH_EXTIMU,2.31114850536e-06,1.52988391792e-05,-0.703358508306,0.710835289328,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.56597982772e-08,-4.38149286391e-08,-7.13886538574e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245091241275,-0.000179148415769,9.80999682481,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120587750000,12189,120587750000,RH_EXTIMU,2.31138191814e-06,1.52988137322e-05,-0.703358571738,0.710835226563,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.47945505193e-07,1.17518286641e-07,-7.13880411592e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243223412108,-0.000181860324808,9.81000441236,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120590250000,12190,120590250000,RH_EXTIMU,2.31132865226e-06,1.52988276217e-05,-0.703358635169,0.7108351638,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.72136877863e-08,-2.14225917826e-08,-7.13872437254e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246184528085,-0.000177761131611,9.80999944262,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120592750000,12191,120592750000,RH_EXTIMU,2.31119369595e-06,1.52988056656e-05,-0.703358698599,0.710835101037,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.34985497084e-08,-8.77730177847e-08,-7.13865385021e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246650815529,-0.000177770506725,9.80999223451,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120595250000,12192,120595250000,RH_EXTIMU,2.31141056766e-06,1.52986945704e-05,-0.703358762028,0.710835038275,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.86732176029e-07,5.95054824308e-08,-7.13858372416e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243575625635,-0.000182835625906,9.81001620906,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120597750000,12193,120597750000,RH_EXTIMU,2.31121165075e-06,1.52988761816e-05,-0.703358825457,0.710834975513,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.14415603356e-07,-8.00062280198e-09,-7.13850160669e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246245385825,-0.000173827468353,9.80999235851,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120600250000,12194,120600250000,RH_EXTIMU,2.3113320621e-06,1.52988141537e-05,-0.703358888885,0.710834912752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04268763914e-07,3.31314493654e-08,-7.13844411184e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024436470343,-0.000181686087,9.80999901148,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120604000000,12195,120602750000,RH_EXTIMU,2.31143630661e-06,1.5298762187e-05,-0.703358952313,0.710834849991,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.94137996212e-08,2.97561406839e-08,-7.13836397708e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244928332415,-0.000180283876659,9.81001255905,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120605250000,12196,120605250000,RH_EXTIMU,2.3112439585e-06,1.52987743169e-05,-0.703359015739,0.710834787232,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.15315181372e-07,-1.00683113236e-07,-7.13829761403e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246951146197,-0.000176866433561,9.80998047639,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120607750000,12197,120607750000,RH_EXTIMU,2.31137230143e-06,1.52986516004e-05,-0.703359079166,0.710834724472,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.42927821629e-07,3.08282793694e-09,-7.13823739842e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244895157166,-0.000181486025891,9.80999345541,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120610250000,12198,120610250000,RH_EXTIMU,2.31152805264e-06,1.52985858082e-05,-0.703359142591,0.710834661714,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.26483463222e-07,5.08761120197e-08,-7.13816764085e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244251539434,-0.000181118376463,9.81000448842,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120612750000,12199,120612750000,RH_EXTIMU,2.31154070355e-06,1.52985850655e-05,-0.703359206016,0.710834598956,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.50433699753e-09,7.34699621022e-09,-7.13808972853e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245599961782,-0.00017873256887,9.81000524751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120615250000,12200,120615250000,RH_EXTIMU,2.31148546706e-06,1.52985649389e-05,-0.703359269441,0.710834536198,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.9193920944e-08,-4.18754291619e-08,-7.13801409667e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245893314523,-0.000178593057366,9.81000260017,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120617750000,12201,120617750000,RH_EXTIMU,2.31139637348e-06,1.52985576785e-05,-0.703359332864,0.710834473442,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.56869887841e-08,-5.36098414498e-08,-7.13793707443e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246076051418,-0.000178036899306,9.81000350655,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120620250000,12202,120620250000,RH_EXTIMU,2.31148871406e-06,1.5298552273e-05,-0.703359396288,0.710834410686,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.64449327291e-08,4.95357773006e-08,-7.13787172655e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243829093169,-0.000180464759116,9.81000344793,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120622750000,12203,120622750000,RH_EXTIMU,2.32095044593e-06,1.52957838826e-05,-0.703359459709,0.710834347931,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.9392106594e-06,3.75035543669e-06,-7.13762595473e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000162353756128,-0.000331859688882,9.81114604133,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120625250000,12204,120625250000,RH_EXTIMU,2.30488439116e-06,1.5308691198e-05,-0.703359523119,0.710834285187,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.63981362868e-05,-1.69954876388e-06,-7.13651096121e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000326532260771,0.00017792721312,9.80986363309,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120627750000,12205,120627750000,RH_EXTIMU,2.30629793169e-06,1.53047289352e-05,-0.703359586539,0.710834222435,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.03424304305e-06,-1.45717641833e-06,-7.13744697764e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000239659131606,-0.000298492174784,9.80933652849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120630250000,12206,120630250000,RH_EXTIMU,2.31195154243e-06,1.52984749426e-05,-0.70335964996,0.71083415968,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.734960827e-06,-3.74573189891e-07,-7.13770415622e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000251871266757,-0.000284581657094,9.80961943545,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120632750000,12207,120632750000,RH_EXTIMU,2.31359682675e-06,1.52963058664e-05,-0.703359713382,0.710834096926,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.15702425159e-06,-3.07050752186e-07,-7.13768610603e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000248180730861,-0.000203667976743,9.80989213605,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120635250000,12208,120635250000,RH_EXTIMU,2.31240527396e-06,1.52971875832e-05,-0.703359776802,0.710834034172,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.17283612651e-06,-1.68418140035e-07,-7.13755825282e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247209001545,-0.000150230034873,9.8099852132,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120637750000,12209,120637750000,RH_EXTIMU,2.31191337793e-06,1.52980219366e-05,-0.703359840221,0.71083397142,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.48313401934e-07,1.98336103587e-07,-7.1374514138e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000241714571541,-0.000167295708036,9.8100379632,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120640250000,12210,120640250000,RH_EXTIMU,2.31175442437e-06,1.52982319738e-05,-0.70335990364,0.710833908668,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.07684889813e-07,3.06507428999e-08,-7.13736269952e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245496661599,-0.000176576433232,9.81001706316,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120642750000,12211,120642750000,RH_EXTIMU,2.31186111485e-06,1.52982334154e-05,-0.703359967057,0.710833845917,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.07524176794e-08,6.15039076052e-08,-7.13728911106e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024426636096,-0.000180403235349,9.81001464171,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120645250000,12212,120645250000,RH_EXTIMU,2.31170943117e-06,1.52982495479e-05,-0.703360030475,0.710833783167,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.44429107122e-08,-7.55258474233e-08,-7.13721379383e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246733811628,-0.000177237227734,9.809994854,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120647750000,12213,120647750000,RH_EXTIMU,2.31166149951e-06,1.52981978371e-05,-0.703360093891,0.710833720417,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.73205223253e-09,-5.57260935951e-08,-7.13714549212e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245958753846,-0.000179001944011,9.80999486375,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120650250000,12214,120650250000,RH_EXTIMU,2.31175594745e-06,1.52981490187e-05,-0.703360157307,0.710833657668,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.20711350139e-08,2.60339889726e-08,-7.13707597245e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024449145876,-0.000180470170609,9.81000500034,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120652750000,12215,120652750000,RH_EXTIMU,2.31189436015e-06,1.52981620288e-05,-0.703360220722,0.710833594919,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.22822586606e-08,8.59322525107e-08,-7.13699733468e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243729311272,-0.00018035369252,9.81001794057,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120655250000,12216,120655250000,RH_EXTIMU,2.31187977264e-06,1.52982715596e-05,-0.703360284137,0.710833532172,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.90349685995e-08,5.47289841511e-08,-7.13691305002e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244804477452,-0.000177409028362,9.81001608204,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120657750000,12217,120657750000,RH_EXTIMU,2.31170339943e-06,1.52983952638e-05,-0.703360347551,0.710833469425,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.69012344284e-07,-2.82459989449e-08,-7.13683576116e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246199599377,-0.000175823489461,9.80999744695,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120660250000,12218,120660250000,RH_EXTIMU,2.31165280217e-06,1.52983382802e-05,-0.703360410964,0.710833406678,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.1831608545e-09,-6.0224507717e-08,-7.13678061113e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246093104503,-0.00017921955157,9.80997794194,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120662750000,12219,120662750000,RH_EXTIMU,2.31184332949e-06,1.52981368046e-05,-0.703360474377,0.710833343932,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.22606643223e-07,-6.71431399079e-09,-7.13672432813e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024504314572,-0.000183121503154,9.80999192041,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120665250000,12220,120665250000,RH_EXTIMU,2.31185503557e-06,1.5298090431e-05,-0.703360537789,0.710833281186,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.364287703e-08,-1.91336342277e-08,-7.13664514009e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245462461804,-0.000178881011258,9.81000182495,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120667750000,12221,120667750000,RH_EXTIMU,2.31190795493e-06,1.52980893347e-05,-0.7033606012,0.710833218442,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.16024663277e-08,2.98042950193e-08,-7.13656414984e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244863488142,-0.000179376214388,9.81001848696,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120670250000,12222,120670250000,RH_EXTIMU,2.31192524744e-06,1.52981632342e-05,-0.703360664611,0.710833155698,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.08566618273e-08,5.24051109879e-08,-7.13648719013e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244065542254,-0.000178779261572,9.81001168909,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120672750000,12223,120672750000,RH_EXTIMU,2.31199297351e-06,1.52982015332e-05,-0.703360728021,0.710833092954,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.78552504989e-08,6.05386323854e-08,-7.13641572278e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244713125786,-0.000179305242656,9.8100047955,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120675250000,12224,120675250000,RH_EXTIMU,2.31196330291e-06,1.5298195493e-05,-0.70336079143,0.710833030211,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.25818492244e-08,-1.94795464635e-08,-7.1363413097e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245743358166,-0.000178560606031,9.81000135473,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120677750000,12225,120677750000,RH_EXTIMU,2.31193062696e-06,1.52982071719e-05,-0.703360854839,0.710832967469,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.42612149012e-08,-1.10944003811e-08,-7.13626736244e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024542065216,-0.000178507363328,9.81000349649,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120680250000,12226,120680250000,RH_EXTIMU,2.31190904246e-06,1.52981971507e-05,-0.703360918247,0.710832904728,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.74351241314e-09,-1.71934778805e-08,-7.13619249095e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245415381932,-0.000178900094788,9.81000266032,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120682750000,12227,120682750000,RH_EXTIMU,2.3119286785e-06,1.5298176879e-05,-0.703360981654,0.710832841987,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.34650834076e-08,1.71721479919e-10,-7.13612406999e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245279600773,-0.000179308071414,9.80999835111,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120685250000,12228,120685250000,RH_EXTIMU,2.3119117122e-06,1.5298151228e-05,-0.703361045061,0.710832779247,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.67743441121e-09,-2.34830558e-08,-7.13605242412e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245727877038,-0.000178870340818,9.8099988179,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120687750000,12229,120687750000,RH_EXTIMU,2.31191915335e-06,1.52980926479e-05,-0.703361108467,0.710832716507,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.80859385325e-08,-2.84748994225e-08,-7.13597754757e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245586049966,-0.000179775138497,9.81000407854,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120690250000,12230,120690250000,RH_EXTIMU,2.31186679111e-06,1.52980644527e-05,-0.703361171872,0.710832653768,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.30194850472e-08,-4.48467487781e-08,-7.13590686951e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246007756047,-0.00017836403568,9.80999354498,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120692750000,12231,120692750000,RH_EXTIMU,2.31203231807e-06,1.52979824726e-05,-0.703361235277,0.71083259103,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.4115084805e-07,4.71714704459e-08,-7.13584404615e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244030005304,-0.000181837966735,9.81000420212,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120695250000,12232,120695250000,RH_EXTIMU,2.31201184531e-06,1.52980143992e-05,-0.703361298681,0.710832528292,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.87148786995e-08,7.28628602949e-09,-7.13575876399e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245554874998,-0.000177941155998,9.81001072209,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120697750000,12233,120697750000,RH_EXTIMU,2.31195775718e-06,1.52980390903e-05,-0.703361362085,0.710832465555,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.37595010237e-08,-1.57432820672e-08,-7.13567986367e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245420131237,-0.000178255877214,9.81001119462,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120700250000,12234,120700250000,RH_EXTIMU,2.31193590908e-06,1.5298153676e-05,-0.703361425488,0.710832402818,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.60084353455e-08,5.3517864875e-08,-7.13562160694e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244142603755,-0.000177730418335,9.80998468596,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120702750000,12235,120702750000,RH_EXTIMU,2.31205377956e-06,1.52980579223e-05,-0.70336148889,0.710832340082,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.21800476028e-07,1.25231041002e-08,-7.13555638765e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245435812926,-0.000181018023286,9.8099947636,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120705250000,12236,120705250000,RH_EXTIMU,2.31216249601e-06,1.52979398281e-05,-0.703361552292,0.710832277347,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.29165652463e-07,-5.33207446669e-09,-7.13548244048e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024524127951,-0.000181293371835,9.81000722235,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120707750000,12237,120707750000,RH_EXTIMU,2.31203596945e-06,1.52979423515e-05,-0.703361615693,0.710832214613,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.2479243181e-08,-6.91096852393e-08,-7.13539883826e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246720852622,-0.000176941681275,9.8100056247,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120710250000,12238,120710250000,RH_EXTIMU,2.31182640147e-06,1.52980235433e-05,-0.703361679093,0.710832151879,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.6396793928e-07,-7.11001720153e-08,-7.13532520183e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246224649002,-0.00017589972687,9.80999303239,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120712750000,12239,120712750000,RH_EXTIMU,2.31208121305e-06,1.52978983667e-05,-0.703361742492,0.710832089145,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.16230052736e-07,7.2846656422e-08,-7.13526710142e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243250840502,-0.000183850194853,9.81000541139,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120715250000,12240,120715250000,RH_EXTIMU,2.312108101e-06,1.52979279705e-05,-0.703361805891,0.710832026412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.75544328021e-10,3.26146884068e-08,-7.13518773005e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245344947806,-0.000177978674966,9.81000229074,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120717750000,12241,120717750000,RH_EXTIMU,2.31218289844e-06,1.52979232117e-05,-0.70336186929,0.71083196368,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.61044068504e-08,4.003201538e-08,-7.13511946284e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244532507639,-0.000180112341848,9.81000532805,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120720250000,12242,120720250000,RH_EXTIMU,2.31214829049e-06,1.52979275376e-05,-0.703361932688,0.710831900949,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.12226035229e-08,-1.63630427627e-08,-7.13503959327e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245767771462,-0.000178276478535,9.81000517535,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120724000000,12243,120722750000,RH_EXTIMU,2.31203650298e-06,1.52979242053e-05,-0.703361996085,0.710831838218,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.08027317784e-08,-6.41461826313e-08,-7.13498117172e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246159384291,-0.000177959884819,9.80997756822,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120725250000,12244,120725250000,RH_EXTIMU,2.3122486006e-06,1.52978050347e-05,-0.703362059481,0.710831775488,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.88560552689e-07,5.22273698572e-08,-7.13491670605e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244429396208,-0.0001821469877,9.81000289804,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120727750000,12245,120727750000,RH_EXTIMU,2.31216596806e-06,1.52977707229e-05,-0.703362122877,0.710831712758,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.67914848676e-08,-6.53579763476e-08,-7.13483686643e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246436498355,-0.000177966079875,9.81000041829,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120730250000,12246,120730250000,RH_EXTIMU,2.31213603587e-06,1.52977876318e-05,-0.703362186272,0.710831650029,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.56440173045e-08,-6.57657738012e-09,-7.13476546021e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245084486902,-0.000178533445198,9.81000156428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120732750000,12247,120732750000,RH_EXTIMU,2.31214488773e-06,1.52977835931e-05,-0.703362249667,0.7108315873,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.19818876772e-09,3.33457398785e-09,-7.13469390074e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245209071656,-0.000179077375225,9.81000058202,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120735250000,12248,120735250000,RH_EXTIMU,2.31216104971e-06,1.52977660898e-05,-0.703362313061,0.710831524573,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.99315051153e-08,-2.08887262424e-10,-7.13462294267e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245263145223,-0.000179240834823,9.80999997275,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120737750000,12249,120737750000,RH_EXTIMU,2.31217951257e-06,1.5297745785e-05,-0.703362376454,0.710831461845,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.28163559125e-08,-5.07375436386e-10,-7.13455208603e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245258269533,-0.00017926882585,9.80999985747,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120740250000,12250,120740250000,RH_EXTIMU,2.31219765999e-06,1.52977258037e-05,-0.703362439847,0.710831399119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.24549238894e-08,-5.00900199302e-10,-7.13448113205e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245258563527,-0.000179255353595,9.80999990562,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120742750000,12251,120742750000,RH_EXTIMU,2.31228599106e-06,1.52976700664e-05,-0.703362503239,0.710831336393,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.24854584127e-08,1.86575260338e-08,-7.13440744407e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244829366808,-0.000180586306803,9.81000928278,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120745250000,12252,120745250000,RH_EXTIMU,2.31229179193e-06,1.52977418904e-05,-0.70336256663,0.710831273668,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.62240580506e-08,4.47582561121e-08,-7.13432506302e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244636902203,-0.000177913186715,9.81001411089,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120747750000,12253,120747750000,RH_EXTIMU,2.31218540596e-06,1.52978298869e-05,-0.703362630021,0.710831210943,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.09120912065e-07,-9.1714302206e-09,-7.13425064603e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245680774198,-0.000176998120953,9.8099992721,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120750250000,12254,120750250000,RH_EXTIMU,2.31224191886e-06,1.52977726009e-05,-0.703362693411,0.710831148219,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.52629706521e-08,-1.26911271981e-10,-7.13418698256e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245015069502,-0.000180514539801,9.80999518162,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120752750000,12255,120752750000,RH_EXTIMU,2.31235568509e-06,1.52976765212e-05,-0.7033627568,0.710831085496,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.19649763465e-07,1.00283501448e-08,-7.13411145616e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245236149962,-0.000180821612754,9.81000936861,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120755250000,12256,120755250000,RH_EXTIMU,2.31232773985e-06,1.52976847878e-05,-0.703362820189,0.710831022773,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.96512164514e-08,-1.03732497619e-08,-7.13403362195e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245330130417,-0.000178528682251,9.81000769558,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120757750000,12257,120757750000,RH_EXTIMU,2.31213791945e-06,1.52977684884e-05,-0.703362883577,0.710830960051,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.54149945588e-07,-5.8562133088e-08,-7.13395977197e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024658263337,-0.00017566283757,9.80998953422,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120760250000,12258,120760250000,RH_EXTIMU,2.31228680904e-06,1.52976726635e-05,-0.703362946964,0.71083089733,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.39479763799e-07,2.99368512565e-08,-7.13390665723e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243975381355,-0.000182179303059,9.80999140649,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120762750000,12259,120762750000,RH_EXTIMU,2.31233771321e-06,1.52975996215e-05,-0.703363010351,0.710830834609,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.0939204175e-08,-1.22428043084e-08,-7.13383122401e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245924196084,-0.000179602656274,9.81000048281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120765250000,12260,120765250000,RH_EXTIMU,2.3122743162e-06,1.52975886764e-05,-0.703363073737,0.710830771888,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.90011690462e-08,-4.12466778572e-08,-7.13375876925e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245918326893,-0.000178189678264,9.80999562558,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120767750000,12261,120767750000,RH_EXTIMU,2.31248166805e-06,1.52974698712e-05,-0.703363137123,0.710830709169,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.85655910682e-07,4.97649466121e-08,-7.13369339196e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002438779032,-0.000182810083855,9.81000986176,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120770250000,12262,120770250000,RH_EXTIMU,2.31236112209e-06,1.52975634834e-05,-0.703363200508,0.71083064645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.2033315602e-07,-1.394584942e-08,-7.13360627418e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246181271482,-0.000175786946752,9.81000599887,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120772750000,12263,120772750000,RH_EXTIMU,2.31237771223e-06,1.52975980533e-05,-0.703363263892,0.710830583731,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.12622806327e-09,2.96441019818e-08,-7.13353800988e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244215127122,-0.000179391996432,9.81000436607,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120775250000,12264,120775250000,RH_EXTIMU,2.31240305963e-06,1.52976069566e-05,-0.703363327276,0.710830521014,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0296108385e-08,1.99759931366e-08,-7.13346640551e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245434731485,-0.000178908751073,9.80999984946,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120777750000,12265,120777750000,RH_EXTIMU,2.31238768206e-06,1.52975548119e-05,-0.703363390658,0.710830458297,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.14883674093e-08,-3.76553686726e-08,-7.1333925936e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245803453103,-0.000179324484964,9.81000132066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120780250000,12266,120780250000,RH_EXTIMU,2.31238780684e-06,1.52975266672e-05,-0.703363454041,0.71083039558,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.67993812824e-08,-1.52843694962e-08,-7.13332130512e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245378825695,-0.000179161650126,9.81000035768,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120782750000,12267,120782750000,RH_EXTIMU,2.3124022989e-06,1.52975058208e-05,-0.703363517422,0.710830332864,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.08628821691e-08,-3.04978800537e-09,-7.13325038962e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245264001462,-0.000179238003584,9.81000007727,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120785250000,12268,120785250000,RH_EXTIMU,2.31252827924e-06,1.52974599216e-05,-0.703363580803,0.710830270149,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.83592817111e-08,4.54369724934e-08,-7.13318383521e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244335584894,-0.000180896587556,9.81000304084,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120787750000,12269,120787750000,RH_EXTIMU,2.31245013741e-06,1.52975146986e-05,-0.703363644184,0.710830207434,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.4367340853e-08,-1.21696952268e-08,-7.13310855574e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245807230962,-0.000176913237952,9.80999336217,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120790250000,12270,120790250000,RH_EXTIMU,2.31263841138e-06,1.5297434607e-05,-0.703363707564,0.71083014472,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.53023133373e-07,6.10450707353e-08,-7.13305057575e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243878366021,-0.000182277847345,9.81000121669,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120792750000,12271,120792750000,RH_EXTIMU,2.31258185015e-06,1.52974457207e-05,-0.703363770943,0.710830082007,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.75262203502e-08,-2.48563420905e-08,-7.13297048182e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246080830441,-0.000177626966979,9.80999964734,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120795250000,12272,120795250000,RH_EXTIMU,2.31264979268e-06,1.52974106205e-05,-0.703363834321,0.710830019294,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.92786655402e-08,1.89206685771e-08,-7.1328989152e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244669664084,-0.000180265743211,9.81000789137,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120797750000,12273,120797750000,RH_EXTIMU,2.31254910531e-06,1.52974747231e-05,-0.703363897699,0.710829956582,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.24355865401e-08,-1.9552850113e-08,-7.1328233584e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245943915368,-0.000176671733405,9.80999579935,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120800250000,12274,120800250000,RH_EXTIMU,2.31265055955e-06,1.52974300855e-05,-0.703363961076,0.71082989387,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.37021543459e-08,3.23538500974e-08,-7.132760626e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244334579643,-0.000180970152459,9.81000064604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120802750000,12275,120802750000,RH_EXTIMU,2.31254414339e-06,1.52973877307e-05,-0.703364024453,0.710829831159,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.57907034028e-08,-8.33149225167e-08,-7.13268584683e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246987674165,-0.000177866599327,9.8099910106,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120805250000,12276,120805250000,RH_EXTIMU,2.31278008062e-06,1.52973041635e-05,-0.703364087829,0.710829768449,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.82083090064e-07,8.58883796686e-08,-7.1326077226e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243562976017,-0.000182196036339,9.81002562315,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120807750000,12277,120807750000,RH_EXTIMU,2.31261289864e-06,1.52974150201e-05,-0.703364151204,0.71082970574,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.56556804477e-07,-3.03815052573e-08,-7.13252794287e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245913048122,-0.000176008158404,9.81000111728,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120810250000,12278,120810250000,RH_EXTIMU,2.3125188314e-06,1.52974036586e-05,-0.703364214578,0.710829643031,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.62079972748e-08,-5.87415402837e-08,-7.13246506416e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246180000505,-0.0001783114597,9.80998532354,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120815250000,12279,120812750000,RH_EXTIMU,2.31261079281e-06,1.52972890294e-05,-0.703364277953,0.710829580322,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17687567579e-07,-1.27894034867e-08,-7.13240090901e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245339413371,-0.000180908376718,9.80999433813,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120815250000,12280,120815250000,RH_EXTIMU,2.31273902921e-06,1.5297185962e-05,-0.703364341326,0.710829517614,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.31810070001e-07,1.41970169202e-08,-7.13232991585e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245007144223,-0.000181102646414,9.81000339225,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120815250000,12281,120817750000,RH_EXTIMU,2.31289017385e-06,1.52972133342e-05,-0.703364404699,0.710829454907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.14398884406e-08,1.0126353579e-07,-7.13225723632e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243001849808,-0.000180386510168,9.81001634135,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120820250000,12282,120820250000,RH_EXTIMU,2.31259745746e-06,1.52973454515e-05,-0.703364468071,0.710829392201,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.39906822736e-07,-8.89286554877e-08,-7.13217331333e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247644783416,-0.00017400060808,9.8099914476,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120822750000,12283,120822750000,RH_EXTIMU,2.31256886575e-06,1.5297298287e-05,-0.703364531442,0.710829329495,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.11715046772e-08,-4.22588544071e-08,-7.13211093021e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245721392847,-0.000179299798963,9.80998999487,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120825250000,12284,120825250000,RH_EXTIMU,2.31275223527e-06,1.52971342728e-05,-0.703364594813,0.710829266789,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.97456500755e-07,1.05617491359e-08,-7.13205512161e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244863413693,-0.0001826159917,9.80998959671,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120827750000,12285,120827750000,RH_EXTIMU,2.31292530505e-06,1.52970531361e-05,-0.703364658183,0.710829204085,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.44964917611e-07,5.18955683847e-08,-7.13197755658e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244454408891,-0.000181004354201,9.81001409592,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120830250000,12286,120830250000,RH_EXTIMU,2.31284596742e-06,1.529715459e-05,-0.703364721553,0.710829141381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.01312157091e-07,1.37005772662e-08,-7.13189556294e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245029379468,-0.000176889212081,9.81001088855,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120832750000,12287,120832750000,RH_EXTIMU,2.31263617936e-06,1.5297334731e-05,-0.703364784922,0.710829078677,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.19771101917e-07,-1.49563577526e-08,-7.13182236686e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245853648925,-0.000174697418655,9.80998806814,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120835250000,12288,120835250000,RH_EXTIMU,2.31285339504e-06,1.52971575077e-05,-0.70336484829,0.710829015974,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.24136174643e-07,2.20952230424e-08,-7.13177589865e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244540698083,-0.000183910356825,9.80998655037,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120837750000,12289,120837750000,RH_EXTIMU,2.31301227522e-06,1.52969675308e-05,-0.703364911658,0.710828953272,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.9813926165e-07,-1.79822004543e-08,-7.13169928009e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245642512935,-0.000181970738809,9.81000774832,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120840250000,12290,120840250000,RH_EXTIMU,2.31279590646e-06,1.52970545315e-05,-0.703364975025,0.71082889057,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.7110406814e-07,-7.16247783874e-08,-7.13161489005e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024666618026,-0.00017489991627,9.80999864184,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120842750000,12291,120842750000,RH_EXTIMU,2.31280513189e-06,1.52970305913e-05,-0.703365038391,0.710828827869,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.96086394041e-08,-7.77281861899e-09,-7.13155645541e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245019183636,-0.000179828556364,9.80999176029,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120845250000,12292,120845250000,RH_EXTIMU,2.312856632e-06,1.52969410788e-05,-0.703365101757,0.710828765169,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.05456288517e-08,-2.12736739396e-08,-7.13148695788e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245593056073,-0.000180200154906,9.80999620183,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120847750000,12293,120847750000,RH_EXTIMU,2.31291799031e-06,1.52969820003e-05,-0.703365165122,0.710828702469,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.27574268626e-08,5.84464394219e-08,-7.13141028449e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244116191353,-0.000178802284912,9.81001229121,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120850250000,12294,120850250000,RH_EXTIMU,2.31279964057e-06,1.52969501587e-05,-0.703365228487,0.71082863977,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.84926239916e-08,-8.40515864673e-08,-7.13133627423e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246997775236,-0.000178230112742,9.8099921655,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120852750000,12295,120852750000,RH_EXTIMU,2.31314372346e-06,1.52969117696e-05,-0.70336529185,0.710828577071,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.18159822536e-07,1.72432361624e-07,-7.13126265392e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000241794852635,-0.000182966250425,9.81003080401,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120855250000,12296,120855250000,RH_EXTIMU,2.31285459181e-06,1.5297105744e-05,-0.703365355213,0.710828514373,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.72674871272e-07,-5.17361084702e-08,-7.13117381371e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247315104674,-0.000173256732804,9.80999857445,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120857750000,12297,120857750000,RH_EXTIMU,2.3129799266e-06,1.52970506381e-05,-0.703365418576,0.710828451676,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03172316759e-07,3.98382680658e-08,-7.13111571929e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243809597217,-0.000181786222362,9.80999999262,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120860250000,12298,120860250000,RH_EXTIMU,2.313066313e-06,1.52969742126e-05,-0.703365481938,0.710828388979,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.30201892747e-08,5.79864678455e-09,-7.1310412532e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245414761575,-0.000180328401347,9.81000382488,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120862750000,12299,120862750000,RH_EXTIMU,2.31293360532e-06,1.52969956105e-05,-0.703365545299,0.710828326283,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.66149440893e-08,-6.18554105555e-08,-7.13097632233e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246165240235,-0.000177164736893,9.80998344006,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120865250000,12300,120865250000,RH_EXTIMU,2.31312651097e-06,1.52968509923e-05,-0.70336560866,0.710828263588,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.91965180692e-07,2.69575951033e-08,-7.13090908509e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244608098713,-0.000182642489373,9.81000690525,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120867750000,12301,120867750000,RH_EXTIMU,2.31295671578e-06,1.52968845189e-05,-0.70336567202,0.710828200893,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.14529945407e-07,-7.58271910713e-08,-7.13082542825e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024696834589,-0.000175830312701,9.80999703604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120870250000,12302,120870250000,RH_EXTIMU,2.31306254232e-06,1.52968465098e-05,-0.703365735379,0.710828138199,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.2458381952e-08,3.85834534343e-08,-7.1307601218e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244115122761,-0.000180926005938,9.81000685401,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120872750000,12303,120872750000,RH_EXTIMU,2.31301703932e-06,1.52968659352e-05,-0.703365798738,0.710828075506,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.59150343371e-08,-1.39077205036e-08,-7.13068902499e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245595595799,-0.00017809661247,9.80999409151,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120875250000,12304,120875250000,RH_EXTIMU,2.31310245093e-06,1.52968499863e-05,-0.703365862096,0.710828012813,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.84360750247e-08,3.96408877575e-08,-7.13062372127e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244379481304,-0.000179960271299,9.80999740147,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120877750000,12305,120877750000,RH_EXTIMU,2.3131688459e-06,1.52968858919e-05,-0.703365925453,0.71082795012,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.84438628719e-08,5.84280776736e-08,-7.13056481083e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244414600505,-0.00017906493586,9.8099870616,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120880250000,12306,120880250000,RH_EXTIMU,2.31337618363e-06,1.52967490919e-05,-0.70336598881,0.710827887428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.95772873177e-07,3.95243765957e-08,-7.13048875737e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244797661177,-0.000182646790566,9.81001797926,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120882750000,12307,120882750000,RH_EXTIMU,2.31303749196e-06,1.52968764196e-05,-0.703366052166,0.710827824737,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.63356271123e-07,-1.17522940112e-07,-7.13039403377e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247859986097,-0.000172928624013,9.80999969623,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120885250000,12308,120885250000,RH_EXTIMU,2.31303256543e-06,1.52968311601e-05,-0.703366115522,0.710827762047,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.3557013374e-08,-2.78595820452e-08,-7.13033881635e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244894230676,-0.000180305306312,9.80999155669,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120887750000,12309,120887750000,RH_EXTIMU,2.31327644853e-06,1.52966981227e-05,-0.703366178877,0.710827699357,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.14437607589e-07,6.22278838084e-08,-7.13027212198e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243881448133,-0.000183001912212,9.81000576905,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120890250000,12310,120890250000,RH_EXTIMU,2.31333074766e-06,1.52967039226e-05,-0.703366242231,0.710827636668,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.85056050979e-08,3.4501819811e-08,-7.13019529518e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245163067536,-0.000178751680956,9.81000502213,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120892750000,12311,120892750000,RH_EXTIMU,2.31310739524e-06,1.52967353425e-05,-0.703366305584,0.710827573979,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.43800549621e-07,-1.07161606614e-07,-7.13012273825e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247165759245,-0.000176180182668,9.80998813923,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120895250000,12312,120895250000,RH_EXTIMU,2.3132195635e-06,1.52966928391e-05,-0.703366368937,0.710827511291,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.85935237288e-08,3.95960847481e-08,-7.13004848506e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244286523354,-0.000180413663262,9.81001351139,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120897750000,12313,120897750000,RH_EXTIMU,2.31318537077e-06,1.52967570647e-05,-0.70336643229,0.710827448604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.46921800663e-08,1.79325733971e-08,-7.12997471229e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245072018693,-0.000178021000016,9.81000056054,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120897750000,12314,120900250000,RH_EXTIMU,2.31329972716e-06,1.52966347828e-05,-0.703366495641,0.710827385917,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34728607569e-07,-4.53964894996e-09,-7.12990565413e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245333543156,-0.000181701395971,9.81000564075,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120902750000,12315,120902750000,RH_EXTIMU,2.31316487274e-06,1.52967038345e-05,-0.703366558992,0.710827323231,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.14650263501e-07,-3.59646926248e-08,-7.12983050385e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245846306142,-0.000175974332268,9.809990138,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120905250000,12316,120905250000,RH_EXTIMU,2.31337201886e-06,1.52966502077e-05,-0.703366622343,0.710827260546,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.48862799256e-07,8.67140551046e-08,-7.12977947424e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243628739299,-0.000182229387319,9.80999596586,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120907750000,12317,120907750000,RH_EXTIMU,2.31332392341e-06,1.5296630647e-05,-0.703366685693,0.710827197861,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.54521146525e-08,-3.75365611769e-08,-7.12969288848e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246279111057,-0.000177982359159,9.81000620314,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120910250000,12318,120910250000,RH_EXTIMU,2.31329707209e-06,1.52966683931e-05,-0.703366749042,0.710827135177,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.56176084185e-08,7.00558673872e-09,-7.12961387666e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244945476495,-0.000178285227382,9.81001279036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120912750000,12319,120912750000,RH_EXTIMU,2.31321062913e-06,1.52966926289e-05,-0.70336681239,0.710827072493,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.19029021156e-08,-3.42090745109e-08,-7.12954428848e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245836405569,-0.000177990272473,9.8099934474,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120915250000,12320,120915250000,RH_EXTIMU,2.31327665525e-06,1.52966218567e-05,-0.703366875738,0.71082700981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.82608131928e-08,-2.44315056694e-09,-7.12947887316e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245209017871,-0.000180306824276,9.80999644632,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120917750000,12321,120917750000,RH_EXTIMU,2.31331555675e-06,1.52965747312e-05,-0.703366939085,0.710826947128,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.95302232462e-08,-4.25902777968e-09,-7.12940866215e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245318547528,-0.000179588114414,9.80999863136,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120920250000,12322,120920250000,RH_EXTIMU,2.31333252284e-06,1.52965513485e-05,-0.703367002432,0.710826884446,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.3696443082e-08,-3.10031601248e-09,-7.12933734183e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245288787182,-0.000179187658445,9.81000005323,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120922750000,12323,120922750000,RH_EXTIMU,2.31334296444e-06,1.52965361829e-05,-0.703367065778,0.710826821765,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.53624900131e-08,-2.0988394752e-09,-7.1292657912e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245278587449,-0.000179090327661,9.81000044828,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120925250000,12324,120925250000,RH_EXTIMU,2.31335313672e-06,1.52965211504e-05,-0.703367129123,0.710826759084,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.51344369513e-08,-2.17471620912e-09,-7.12919436854e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245282262661,-0.000179104246554,9.81000042407,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120927750000,12325,120927750000,RH_EXTIMU,2.31336444686e-06,1.52965046414e-05,-0.703367192467,0.710826696404,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.66122910685e-08,-2.37406405233e-09,-7.12912303203e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245284649804,-0.000179131960674,9.81000032996,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120930250000,12326,120930250000,RH_EXTIMU,2.31347735273e-06,1.5296496744e-05,-0.703367255812,0.710826633725,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.95402027309e-08,5.96902411793e-08,-7.12906131273e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244124132925,-0.000180205704806,9.80999486751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120932750000,12327,120932750000,RH_EXTIMU,2.3135748071e-06,1.52964845464e-05,-0.703367319155,0.710826571046,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.31732054119e-08,4.85504432417e-08,-7.12899913966e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244600562746,-0.000179844221728,9.80999106949,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120935250000,12328,120935250000,RH_EXTIMU,2.31357917602e-06,1.52964038851e-05,-0.703367382498,0.710826508368,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.87631678127e-08,-4.2760804732e-08,-7.12891884048e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246315116666,-0.000179440115174,9.81000646545,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120937750000,12329,120937750000,RH_EXTIMU,2.31349874354e-06,1.52964054636e-05,-0.70336744584,0.710826445691,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.57358774309e-08,-4.37115080078e-08,-7.1288419606e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024575662637,-0.000178000326329,9.81000416166,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120940250000,12330,120940250000,RH_EXTIMU,2.31348498509e-06,1.52964034379e-05,-0.703367509181,0.710826383014,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.79296539293e-09,-8.24394319571e-09,-7.1287712798e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245377220786,-0.000178824033653,9.80999860552,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120942750000,12331,120942750000,RH_EXTIMU,2.3135748462e-06,1.52963110481e-05,-0.703367572522,0.710826320338,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03978846844e-07,-1.32446241068e-09,-7.12870470277e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245054011104,-0.000180968476497,9.81000137134,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120945250000,12332,120945250000,RH_EXTIMU,2.31357657028e-06,1.52963114757e-05,-0.703367635863,0.710826257662,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.63088600957e-09,1.86304021075e-09,-7.12862875854e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245317854281,-0.000178581288946,9.8100024952,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120947750000,12333,120947750000,RH_EXTIMU,2.31366564963e-06,1.52963160258e-05,-0.703367699202,0.710826194987,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.89867406217e-08,5.33616054491e-08,-7.1285569947e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024405067597,-0.000179968882614,9.81000985172,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120950250000,12334,120950250000,RH_EXTIMU,2.31349698774e-06,1.52963528674e-05,-0.703367762541,0.710826132313,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.15750865675e-07,-7.33049981773e-08,-7.12848634832e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246950546112,-0.000176574265483,9.80998416503,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120952750000,12335,120952750000,RH_EXTIMU,2.31357229663e-06,1.52962420683e-05,-0.703367825879,0.710826069639,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.06062259269e-07,-1.99814813562e-08,-7.1284215161e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245373311538,-0.00018077288797,9.8099984788,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120955250000,12336,120955250000,RH_EXTIMU,2.31363924579e-06,1.52962253805e-05,-0.703367889217,0.710826006966,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.83525833726e-08,2.88318934415e-08,-7.12835273221e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244649708743,-0.000179572792084,9.80999757661,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120957750000,12337,120957750000,RH_EXTIMU,2.31361583931e-06,1.52962183613e-05,-0.703367952554,0.710825944293,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.4696157373e-09,-1.65125569537e-08,-7.12828634165e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245613710718,-0.00017854520264,9.80999065909,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120960250000,12338,120960250000,RH_EXTIMU,2.31375979302e-06,1.52961583225e-05,-0.703368015891,0.710825881621,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.16535357307e-07,4.75099224739e-08,-7.12821371015e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024445933641,-0.000180885377578,9.81000936369,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120962750000,12339,120962750000,RH_EXTIMU,2.31373033432e-06,1.52962365992e-05,-0.703368079227,0.71082581895,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.9906806669e-08,2.85862901064e-08,-7.12814555855e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244745088816,-0.000177673854269,9.80999449726,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120965250000,12340,120965250000,RH_EXTIMU,2.31386739586e-06,1.52961933168e-05,-0.703368142562,0.710825756279,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03187296541e-07,5.31604554886e-08,-7.12806375612e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244666170224,-0.000180721369257,9.81002029498,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120967750000,12341,120967750000,RH_EXTIMU,2.31360078014e-06,1.52962682525e-05,-0.703368205896,0.710825693609,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.92888741902e-07,-1.06760575893e-07,-7.1279811866e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247499037696,-0.000175034538973,9.80999663884,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120970250000,12342,120970250000,RH_EXTIMU,2.31356305988e-06,1.52961798734e-05,-0.70336826923,0.71082563094,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.9171438381e-08,-7.08330331025e-08,-7.12791760312e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245740565488,-0.000180003379755,9.80999421228,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120972750000,12343,120972750000,RH_EXTIMU,2.31361617785e-06,1.52961004024e-05,-0.703368332563,0.710825568271,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.58149455223e-08,-1.46531289092e-08,-7.1278493781e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245334791921,-0.000180067480487,9.80999704142,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120975250000,12344,120975250000,RH_EXTIMU,2.31367361822e-06,1.52960865053e-05,-0.703368395896,0.710825505603,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.13748805347e-08,2.50683013081e-08,-7.12777631729e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244914866992,-0.000179312870805,9.81000361796,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120977750000,12345,120977750000,RH_EXTIMU,2.31375744716e-06,1.52960302259e-05,-0.703368459228,0.710825442935,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.02293103088e-08,1.58158479329e-08,-7.12770521597e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244767853747,-0.000180708182453,9.81000673841,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120980250000,12346,120980250000,RH_EXTIMU,2.31352802706e-06,1.52961191377e-05,-0.703368522559,0.710825380268,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.79601349463e-07,-7.78832606213e-08,-7.12762921792e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247165839321,-0.000174615510909,9.80998486994,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120982750000,12347,120982750000,RH_EXTIMU,2.31377236909e-06,1.52960390322e-05,-0.70336858589,0.710825317602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.84913517064e-07,9.2586811912e-08,-7.1275741426e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242952979327,-0.000183017342253,9.81000342933,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120985250000,12348,120985250000,RH_EXTIMU,2.31387705965e-06,1.52960280779e-05,-0.70336864922,0.710825254936,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.65882565287e-08,5.33291526783e-08,-7.12749515553e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244722082724,-0.000179734081114,9.81000920237,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120987750000,12349,120987750000,RH_EXTIMU,2.31372683597e-06,1.52960801569e-05,-0.703368712549,0.710825192271,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.13839891054e-07,-5.42652288491e-08,-7.12742106957e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246562880682,-0.000176496003197,9.80999153767,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120990250000,12350,120990250000,RH_EXTIMU,2.31385458692e-06,1.5295988443e-05,-0.703368775878,0.710825129607,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.25144803312e-07,2.03803284188e-08,-7.12735787014e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244438763035,-0.000181535877483,9.81000179359,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120992750000,12351,120992750000,RH_EXTIMU,2.3138657113e-06,1.52959558024e-05,-0.703368839206,0.710825066943,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.55836241848e-08,-1.16521877365e-08,-7.12728322208e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024555222836,-0.000179085303092,9.81000097375,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120995250000,12352,120995250000,RH_EXTIMU,2.31382274592e-06,1.52959758177e-05,-0.703368902534,0.71082500428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.48043293207e-08,-1.21448978336e-08,-7.12721834147e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245317659144,-0.000178173590844,9.80998987053,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120997750000,12353,120997750000,RH_EXTIMU,2.31388250866e-06,1.52959393119e-05,-0.703368965861,0.710824941617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.54172287189e-08,1.35183832337e-08,-7.12714096622e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245135461878,-0.000179670548383,9.81001031065,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120997750000,12354,121000250000,RH_EXTIMU,2.31378095636e-06,1.52959882371e-05,-0.703369029187,0.710824878955,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.43878057012e-08,-2.86716252008e-08,-7.12706440152e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245774919202,-0.000177239833249,9.80999987351,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +120997750000,12355,121002750000,RH_EXTIMU,2.31377198206e-06,1.52958960227e-05,-0.703369092512,0.710824816294,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.76761797482e-08,-5.68388832534e-08,-7.12699676407e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246141960084,-0.000179994513023,9.809995406,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121005250000,12356,121005250000,RH_EXTIMU,2.31387242581e-06,1.52958157294e-05,-0.703369155837,0.710824753633,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03189870708e-07,1.1509190109e-08,-7.12692934401e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244613790572,-0.000180732119701,9.81000098555,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121011500000,12357,121007750000,RH_EXTIMU,2.3139706997e-06,1.52958502983e-05,-0.703369219162,0.710824690973,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.73235075117e-08,7.56057455397e-08,-7.1268571883e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024417087976,-0.000179221167685,9.81000652025,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121011500000,12358,121010250000,RH_EXTIMU,2.31385516427e-06,1.52959072467e-05,-0.703369282485,0.710824628313,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.68540487689e-08,-3.19775095096e-08,-7.12678238413e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246308876941,-0.000176832930269,9.80999473423,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121012750000,12359,121012750000,RH_EXTIMU,2.31392526424e-06,1.52958342183e-05,-0.703369345808,0.710824565654,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.18466220369e-08,-1.43384521636e-09,-7.12671884781e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244677421761,-0.000180833464563,9.80999689122,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121015250000,12360,121015250000,RH_EXTIMU,2.31403203788e-06,1.52957745546e-05,-0.703369409131,0.710824502996,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.51812127412e-08,2.6802205518e-08,-7.12664837036e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245074649388,-0.000180333070389,9.81000336517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121017750000,12361,121017750000,RH_EXTIMU,2.31399416448e-06,1.52957390866e-05,-0.703369472453,0.710824440338,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.88547433434e-10,-4.0830912168e-08,-7.126588424e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245866986389,-0.000178798814372,9.80997845538,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121020250000,12362,121020250000,RH_EXTIMU,2.31423890639e-06,1.52955820561e-05,-0.703369535774,0.710824377681,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.28426015048e-07,4.90677881085e-08,-7.1265255924e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244191245927,-0.000182951423737,9.81000471542,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121022750000,12363,121022750000,RH_EXTIMU,2.31410960525e-06,1.52956683674e-05,-0.703369599095,0.710824315024,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.21204528215e-07,-2.30259457101e-08,-7.12643556296e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246012425084,-0.000175881674221,9.81000970576,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121025250000,12364,121025250000,RH_EXTIMU,2.31408755976e-06,1.52957197637e-05,-0.703369662415,0.710824252369,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.05660005211e-08,1.74715110412e-08,-7.12636204173e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244712842107,-0.00017859757062,9.81000714471,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121027750000,12365,121027750000,RH_EXTIMU,2.31412755968e-06,1.52957340984e-05,-0.703369725734,0.710824189713,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.55710496621e-08,3.13088203343e-08,-7.12629396748e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244833380238,-0.000179125766807,9.80999834683,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121030250000,12366,121030250000,RH_EXTIMU,2.31413349863e-06,1.52957334967e-05,-0.703369789053,0.710824127059,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.60661166503e-09,3.64912019207e-09,-7.12622753049e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245459799261,-0.000178773008203,9.80999324456,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121032750000,12367,121032750000,RH_EXTIMU,2.31422663994e-06,1.5295646538e-05,-0.703369852371,0.710824064405,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.02787739432e-07,3.6098248315e-09,-7.12615676988e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244931550887,-0.000180977301705,9.81000530745,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121036500000,12368,121035250000,RH_EXTIMU,2.31404871056e-06,1.52957033392e-05,-0.703369915688,0.710824001751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.32252178182e-07,-6.71701966967e-08,-7.12607791298e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246847850236,-0.000175626380379,9.80999273831,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121037750000,12369,121037750000,RH_EXTIMU,2.31408278494e-06,1.52956341802e-05,-0.703369979005,0.710823939098,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.91829240985e-08,-1.95049087017e-08,-7.12601951883e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245023452891,-0.000180496061351,9.80999137729,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121040250000,12370,121040250000,RH_EXTIMU,2.31425278656e-06,1.52955146274e-05,-0.703370042321,0.710823876446,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.64835599053e-07,2.83238761978e-08,-7.1259476376e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244615628299,-0.000181883609131,9.81000913623,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121042750000,12371,121042750000,RH_EXTIMU,2.31417723923e-06,1.52955654084e-05,-0.703370105636,0.710823813795,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.06441761322e-08,-1.29837249068e-08,-7.12586136249e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245752129126,-0.000177006710812,9.81001086875,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121045250000,12372,121045250000,RH_EXTIMU,2.31411694204e-06,1.52956192768e-05,-0.703370168951,0.710823751144,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.37093534637e-08,-2.64682425615e-09,-7.12578750484e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245206335012,-0.000177950119846,9.81000448155,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121047750000,12373,121047750000,RH_EXTIMU,2.3141210882e-06,1.52956160313e-05,-0.703370232265,0.710823688494,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.07470845316e-09,1.13686091094e-09,-7.12571677986e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245234436129,-0.000179079254853,9.81000062096,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121051500000,12374,121050250000,RH_EXTIMU,2.31414385276e-06,1.52955885658e-05,-0.703370295579,0.710823625844,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.92907584431e-08,-2.15961005854e-09,-7.12564664918e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245284880056,-0.00017936976809,9.80999944188,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121052750000,12375,121052750000,RH_EXTIMU,2.31416724304e-06,1.52955603776e-05,-0.703370358892,0.710823563195,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.00531512998e-08,-2.21841965419e-09,-7.12557623799e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245275609075,-0.000179328783748,9.80999949562,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121055250000,12376,121055250000,RH_EXTIMU,2.31420097586e-06,1.52955616779e-05,-0.703370422204,0.710823500547,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.93415328076e-08,2.03701004603e-08,-7.12550041781e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024490719287,-0.000179073636675,9.81000806196,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121057750000,12377,121057750000,RH_EXTIMU,2.31424899263e-06,1.52955481309e-05,-0.703370485515,0.710823437899,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.58186699557e-08,1.99646464791e-08,-7.12543705059e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024489497335,-0.000179725870857,9.80999186781,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121060250000,12378,121060250000,RH_EXTIMU,2.31432612308e-06,1.52955264484e-05,-0.703370548826,0.710823375252,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.69522786143e-08,3.1720424082e-08,-7.12537192132e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244747725601,-0.00017963134497,9.80999569729,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121062750000,12379,121062750000,RH_EXTIMU,2.31432708768e-06,1.52954696481e-05,-0.703370612137,0.710823312605,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.34005169236e-08,-3.11078390393e-08,-7.12530549589e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245929104418,-0.000179357511866,9.80998894866,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121065250000,12380,121065250000,RH_EXTIMU,2.31442306617e-06,1.52954176044e-05,-0.703370675447,0.710823249959,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.47544805693e-08,2.50609999464e-08,-7.12523436554e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244813906883,-0.000179928883629,9.81000277296,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121067750000,12381,121067750000,RH_EXTIMU,2.31437604954e-06,1.52954355764e-05,-0.703370738756,0.710823187314,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.59585250095e-08,-1.55868432929e-08,-7.12516751951e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245673909803,-0.000178121596603,9.80999245422,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121070250000,12382,121070250000,RH_EXTIMU,2.31438491757e-06,1.52953853173e-05,-0.703370802064,0.710823124669,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.42141732185e-08,-2.29409413796e-08,-7.12509617466e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245325743546,-0.000179588183389,9.8099993256,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121072750000,12383,121072750000,RH_EXTIMU,2.31440270465e-06,1.52953069768e-05,-0.703370865372,0.710823062025,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.50873256852e-08,-3.38909244752e-08,-7.12501568397e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245979603234,-0.000179677447601,9.81001037748,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121075250000,12384,121075250000,RH_EXTIMU,2.31433929254e-06,1.52953220971e-05,-0.703370928679,0.710822999382,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.36773365565e-08,-2.64342043297e-08,-7.12493458063e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245799015927,-0.000177805376642,9.81001022831,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121077750000,12385,121077750000,RH_EXTIMU,2.31424695843e-06,1.52953335923e-05,-0.703370991986,0.710822936739,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.80842534466e-08,-4.4769967318e-08,-7.12486143917e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245620607321,-0.000178213731917,9.81000101303,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121080250000,12386,121080250000,RH_EXTIMU,2.31437435207e-06,1.52953492593e-05,-0.703371055291,0.710822874097,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.45182838515e-08,8.12424788554e-08,-7.12479808121e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243637843981,-0.000180142223327,9.81000017222,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121082750000,12387,121082750000,RH_EXTIMU,2.3144144562e-06,1.52953686459e-05,-0.703371118597,0.710822811455,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.27873586599e-08,3.42401138301e-08,-7.1247308537e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024501632487,-0.000178843312171,9.80999279143,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121085250000,12388,121085250000,RH_EXTIMU,2.31453728801e-06,1.52952669607e-05,-0.703371181901,0.710822748814,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.27957838209e-07,1.19422608061e-08,-7.12466449407e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245113840415,-0.000181384985653,9.8100010477,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121087750000,12389,121087750000,RH_EXTIMU,2.31448518156e-06,1.52952820941e-05,-0.703371245205,0.710822686173,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.72556635723e-08,-2.0065165663e-08,-7.12459094846e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245547149782,-0.000177711692847,9.80999611245,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121090250000,12390,121090250000,RH_EXTIMU,2.31451931072e-06,1.52952751793e-05,-0.703371308509,0.710822623534,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.41893501177e-08,1.59214681875e-08,-7.12452224981e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244963172806,-0.000179290585915,9.80999955472,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121092750000,12391,121092750000,RH_EXTIMU,2.31453944738e-06,1.529525742e-05,-0.703371371812,0.710822560894,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.23345492982e-08,1.88112568569e-09,-7.12445088084e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245274687237,-0.000179172162845,9.80999996344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121095250000,12392,121095250000,RH_EXTIMU,2.31462255198e-06,1.52952148826e-05,-0.703371435114,0.710822498256,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.20842993381e-08,2.3222761116e-08,-7.12437295647e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244923424383,-0.000180107949815,9.81001285541,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121097750000,12393,121097750000,RH_EXTIMU,2.31447260804e-06,1.52952834768e-05,-0.703371498415,0.710822435618,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.22974034843e-07,-4.47171444189e-08,-7.12430796164e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245911540452,-0.00017661972156,9.80998350141,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121100250000,12394,121100250000,RH_EXTIMU,2.31460429775e-06,1.52951782868e-05,-0.703371561716,0.710822372981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34967119492e-07,1.49334868064e-08,-7.1242479912e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244952528045,-0.000181316223412,9.80999242216,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121102750000,12395,121102750000,RH_EXTIMU,2.31466424523e-06,1.5295096933e-05,-0.703371625016,0.710822310344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.07576870456e-08,-1.18809721112e-08,-7.12416276633e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245628312549,-0.000179868908415,9.81001741138,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121106500000,12396,121105250000,RH_EXTIMU,2.31453489432e-06,1.52951668847e-05,-0.703371688316,0.710822247708,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.12027510692e-07,-3.23576297299e-08,-7.12408151619e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245644896739,-0.000176851852198,9.81000797835,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121107750000,12397,121107750000,RH_EXTIMU,2.31450679726e-06,1.52951922724e-05,-0.703371751614,0.710822185073,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.93727029409e-08,-7.24007821306e-10,-7.12400987786e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245171133116,-0.000178562021614,9.81000242821,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121110250000,12398,121110250000,RH_EXTIMU,2.31452446016e-06,1.52951738008e-05,-0.703371814913,0.710822122438,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.13285226476e-08,8.41002763903e-11,-7.12393978521e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245250448212,-0.000179288835054,9.80999974479,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121112750000,12399,121112750000,RH_EXTIMU,2.31447635754e-06,1.52951434103e-05,-0.70337187821,0.710822059804,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.3627714234e-09,-4.36998242845e-08,-7.12387088133e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246208407615,-0.000178457798065,9.80999054722,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121115250000,12400,121115250000,RH_EXTIMU,2.31465500581e-06,1.52950903576e-05,-0.703371941507,0.71082199717,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.32332832083e-07,7.10052838779e-08,-7.12381001942e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024357873968,-0.000181351575926,9.81000083224,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121117750000,12401,121117750000,RH_EXTIMU,2.31470244405e-06,1.52951004792e-05,-0.703372004804,0.710821934537,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.21712081316e-08,3.30982591557e-08,-7.12373705432e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244977384894,-0.00017899515309,9.81000032885,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121120250000,12402,121120250000,RH_EXTIMU,2.31468974567e-06,1.52950910193e-05,-0.703372068099,0.710821871905,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0075093818e-09,-1.18756072704e-08,-7.12366388789e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245624190446,-0.000178727099085,9.81000064079,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121122750000,12403,121122750000,RH_EXTIMU,2.31461560628e-06,1.52950766467e-05,-0.703372131394,0.710821809273,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.31820422105e-08,-4.9241981527e-08,-7.12359296323e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246093713804,-0.000178098212649,9.80999246344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121125250000,12404,121125250000,RH_EXTIMU,2.31470922436e-06,1.52949741637e-05,-0.703372194689,0.710821746642,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.11794023992e-07,-4.94988848517e-09,-7.12353422823e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245025018417,-0.000181045373211,9.80999135901,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121127750000,12405,121127750000,RH_EXTIMU,2.31482015378e-06,1.52948965255e-05,-0.703372257983,0.710821684011,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0765810169e-07,1.89193576109e-08,-7.12346480259e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244873744628,-0.000180565459366,9.81000088664,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121130250000,12406,121130250000,RH_EXTIMU,2.31483578944e-06,1.5294915354e-05,-0.703372321276,0.710821621381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.12996840882e-10,2.01542455877e-08,-7.12338943251e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244957347248,-0.000178531365851,9.81000384885,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121132750000,12407,121132750000,RH_EXTIMU,2.31477542304e-06,1.52949208791e-05,-0.703372384569,0.710821558752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.65462809137e-08,-3.01770916727e-08,-7.12331314359e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024595306368,-0.000178141224491,9.81000257125,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121135250000,12408,121135250000,RH_EXTIMU,2.31477566944e-06,1.52948610956e-05,-0.703372447861,0.710821496124,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.46705774145e-08,-3.32085498311e-08,-7.12323766058e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245746206717,-0.000179566244155,9.81000583812,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121137750000,12409,121137750000,RH_EXTIMU,2.31478498292e-06,1.52949417824e-05,-0.703372511152,0.710821433496,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.9215749435e-08,5.17729405838e-08,-7.1231664711e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244244821421,-0.000177926308236,9.81000464163,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121140250000,12410,121140250000,RH_EXTIMU,2.3147934476e-06,1.52949882941e-05,-0.703372574442,0.710821370868,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.04681634319e-08,3.18613883967e-08,-7.1230950086e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244706278502,-0.000178713543991,9.81000090471,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121142750000,12411,121142750000,RH_EXTIMU,2.31486598066e-06,1.52950135281e-05,-0.703372637732,0.710821308241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.79377301245e-08,5.58127875651e-08,-7.12302997139e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244396633496,-0.000179345508798,9.80999678423,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121145250000,12412,121145250000,RH_EXTIMU,2.31484135137e-06,1.52948835784e-05,-0.703372701022,0.710821245615,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.00072417594e-08,-8.71066061224e-08,-7.12295184384e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247142265069,-0.000179835054557,9.81000089359,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121147750000,12413,121147750000,RH_EXTIMU,2.31473706445e-06,1.52948419523e-05,-0.70337276431,0.71082118299,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.49902091657e-08,-8.17039387905e-08,-7.12288116172e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246329076112,-0.000177883465616,9.8099936261,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121150250000,12414,121150250000,RH_EXTIMU,2.31486272624e-06,1.52947899566e-05,-0.703372827599,0.710821120365,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.01606688168e-07,4.17910295256e-08,-7.12282723488e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244076494116,-0.000180961626851,9.80998792487,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121152750000,12415,121152750000,RH_EXTIMU,2.31499565233e-06,1.52947054482e-05,-0.703372890886,0.71082105774,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.24032435481e-07,2.73900372342e-08,-7.122759474e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245029431652,-0.000180753419411,9.80999827357,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121155250000,12416,121155250000,RH_EXTIMU,2.31501035877e-06,1.52947284048e-05,-0.703372954173,0.710820995117,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.66441978961e-09,2.19788077934e-08,-7.12268236177e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244721015474,-0.000178465661327,9.81000620703,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121157750000,12417,121157750000,RH_EXTIMU,2.31489264136e-06,1.52948068601e-05,-0.703373017459,0.710820932493,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.10197117015e-07,-2.09762487932e-08,-7.12260987475e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246272683045,-0.000176560420676,9.80999210913,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121160250000,12418,121160250000,RH_EXTIMU,2.31494062983e-06,1.52946321733e-05,-0.703373080745,0.710820869871,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.26475257697e-07,-7.16847243493e-08,-7.12254603353e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245970685535,-0.000181619559626,9.80999600318,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121165250000,12419,121162750000,RH_EXTIMU,2.31508490109e-06,1.52945636696e-05,-0.70337314403,0.710820807249,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.21478087076e-07,4.28751129685e-08,-7.12246832481e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243983146169,-0.000180962413277,9.81001678928,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121165250000,12420,121165250000,RH_EXTIMU,2.31490550782e-06,1.52947632189e-05,-0.703373207314,0.710820744628,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.13408970028e-07,1.31797162422e-08,-7.12238528201e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245736417496,-0.000174090356785,9.81000155578,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121171500000,12421,121167750000,RH_EXTIMU,2.31493876462e-06,1.52947659932e-05,-0.703373270598,0.710820682007,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.82409061094e-08,2.09401863751e-08,-7.12232343363e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244634593181,-0.000180077049576,9.80999614805,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121171500000,12422,121170250000,RH_EXTIMU,2.31509550886e-06,1.52946510773e-05,-0.703373333881,0.710820619387,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.54686932109e-07,2.35011124283e-08,-7.12225536372e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244811822219,-0.00018162559515,9.81000292526,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121172750000,12423,121172750000,RH_EXTIMU,2.31503430368e-06,1.52946676829e-05,-0.703373397163,0.710820556768,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.32583821509e-08,-2.43482033954e-08,-7.12217645954e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246075015694,-0.000177482012913,9.81000157512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121175250000,12424,121175250000,RH_EXTIMU,2.31502823403e-06,1.52946503859e-05,-0.703373460445,0.710820494149,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.17169739639e-09,-1.26024256907e-08,-7.12210808889e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245056411966,-0.000179209262181,9.80999882859,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121177750000,12425,121177750000,RH_EXTIMU,2.3151159216e-06,1.52946403334e-05,-0.703373523726,0.710820431531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.64108976117e-08,4.42742440794e-08,-7.12203549049e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244608154012,-0.000179743758997,9.81000728253,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121180250000,12426,121180250000,RH_EXTIMU,2.315117345e-06,1.52946390848e-05,-0.703373587007,0.710820368913,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.40226207917e-09,7.39893771671e-10,-7.12195887598e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245337989375,-0.000178963872427,9.81000669337,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121182750000,12427,121182750000,RH_EXTIMU,2.31511028298e-06,1.52946523375e-05,-0.703373650286,0.710820306296,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.05828999159e-08,4.21139711732e-09,-7.12188446657e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245075525666,-0.000178608956393,9.81000428922,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121185250000,12428,121185250000,RH_EXTIMU,2.31514569111e-06,1.52946750981e-05,-0.703373713566,0.71082024368,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.21794865773e-09,3.35160145999e-08,-7.12181536737e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024476502262,-0.000179022910218,9.81000072568,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121187750000,12429,121187750000,RH_EXTIMU,2.31502562886e-06,1.52946016086e-05,-0.703373776844,0.710820181065,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.60314682551e-08,-1.08700195564e-07,-7.12174906108e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247264307425,-0.000178350677725,9.80998181036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121190250000,12430,121190250000,RH_EXTIMU,2.31516653076e-06,1.52944995137e-05,-0.703373840122,0.71082011845,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.3846366311e-07,2.18773949183e-08,-7.12168509639e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244415146407,-0.00018115346611,9.81000066858,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121192750000,12431,121192750000,RH_EXTIMU,2.31519292794e-06,1.52945077505e-05,-0.703373903399,0.710820055835,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12663056527e-08,2.01864857047e-08,-7.12161025045e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245087270318,-0.000178745988822,9.81000382381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121195250000,12432,121195250000,RH_EXTIMU,2.31514559208e-06,1.52945348516e-05,-0.703373966676,0.710819993221,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.12774314484e-08,-1.05756799375e-08,-7.12153314518e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245478524683,-0.000178020137992,9.81000432102,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121199000000,12433,121197750000,RH_EXTIMU,2.31516178601e-06,1.52945426436e-05,-0.703374029952,0.710819930608,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.71442584903e-09,1.41921789723e-08,-7.12146764223e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244900411405,-0.000179085335732,9.80999525906,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121200250000,12434,121200250000,RH_EXTIMU,2.31515912464e-06,1.52944587681e-05,-0.703374093227,0.710819867996,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.65734792725e-08,-4.85449633403e-08,-7.12139298856e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246274611977,-0.00017953103962,9.81000098281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121202750000,12435,121202750000,RH_EXTIMU,2.3153490126e-06,1.52944562485e-05,-0.703374156502,0.710819805384,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.10288830093e-07,1.06065942777e-07,-7.12131465906e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243186597854,-0.000180786242591,9.81002395907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121205250000,12436,121205250000,RH_EXTIMU,2.31527951163e-06,1.52945741923e-05,-0.703374219776,0.710819742773,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.04998890931e-07,2.86101974038e-08,-7.12123487076e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245052993629,-0.000177010112822,9.81000741089,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121212750000,12437,121207750000,RH_EXTIMU,2.31509524782e-06,1.52946297878e-05,-0.703374283049,0.710819680162,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.35176070201e-07,-7.14215482003e-08,-7.12116392739e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246973983494,-0.000176146507437,9.80998745982,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121212750000,12438,121210250000,RH_EXTIMU,2.3152410241e-06,1.52945408766e-05,-0.703374346322,0.710819617552,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.338169647e-07,3.21172354654e-08,-7.12111051765e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243947069882,-0.000181809097357,9.80999091147,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121212750000,12439,121212750000,RH_EXTIMU,2.31529081952e-06,1.52944533245e-05,-0.703374409594,0.710819554943,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.84721242078e-08,-2.11182841173e-08,-7.12103870924e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245873711557,-0.000179817930932,9.80999599369,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121215250000,12440,121215250000,RH_EXTIMU,2.31530215451e-06,1.52943230995e-05,-0.703374472866,0.710819492334,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.06133515119e-08,-6.702609801e-08,-7.12097350956e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246040479328,-0.000180483020361,9.80999125743,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121217750000,12441,121217750000,RH_EXTIMU,2.31534481145e-06,1.52942715982e-05,-0.703374536137,0.710819429725,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.41269837225e-08,-4.63461489958e-09,-7.12089893441e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245410516641,-0.00017917454844,9.81000310801,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121220250000,12442,121220250000,RH_EXTIMU,2.31522329988e-06,1.52942703613e-05,-0.703374599407,0.710819367118,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.75121159024e-08,-6.84290464285e-08,-7.12082893523e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024636151487,-0.000177526430055,9.8099910885,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121222750000,12443,121222750000,RH_EXTIMU,2.31531670946e-06,1.52942475793e-05,-0.703374662677,0.710819304511,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.68274118792e-08,4.02552433964e-08,-7.12076666809e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002443015929,-0.000180024475378,9.8099957119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121225250000,12444,121225250000,RH_EXTIMU,2.31541294694e-06,1.5294216998e-05,-0.703374725946,0.710819241904,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.28241381119e-08,3.74114080179e-08,-7.12069505648e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244706284809,-0.000180047682359,9.81000426443,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121227750000,12445,121227750000,RH_EXTIMU,2.31528223183e-06,1.52942761197e-05,-0.703374789214,0.710819179298,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.06709526879e-07,-3.92846975524e-08,-7.12061751561e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246352880352,-0.000176363819819,9.80999531849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121230250000,12446,121230250000,RH_EXTIMU,2.31552501871e-06,1.52941884294e-05,-0.703374852482,0.710819116693,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.88295436465e-07,8.73993974373e-08,-7.12055745049e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242761121191,-0.00018317274579,9.81000828141,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121232750000,12447,121232750000,RH_EXTIMU,2.31550429988e-06,1.52942389657e-05,-0.703374915749,0.710819054089,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.93286193084e-08,1.77280875334e-08,-7.1204829665e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245837321414,-0.000177364259374,9.80999420528,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121235250000,12448,121235250000,RH_EXTIMU,2.31542903627e-06,1.52942168093e-05,-0.703374979016,0.710818991485,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.94415317773e-08,-5.43014388146e-08,-7.12041549585e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246176924392,-0.000178243251939,9.80999131714,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121239000000,12449,121237750000,RH_EXTIMU,2.31550224289e-06,1.52941332987e-05,-0.703375042282,0.710818928881,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.95107785034e-08,-5.64657796886e-09,-7.12035403101e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245161829746,-0.000180445706798,9.80999040502,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121244000000,12450,121240250000,RH_EXTIMU,2.31563663964e-06,1.52940283757e-05,-0.703375105547,0.710818866278,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.36355571708e-07,1.66088696918e-08,-7.12028354667e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244911116955,-0.000181178005858,9.8100061115,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121244000000,12451,121242750000,RH_EXTIMU,2.31555781562e-06,1.5294024785e-05,-0.703375168812,0.710818803676,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.19131362381e-08,-4.57474327426e-08,-7.12019092255e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246298296486,-0.000177598601565,9.81001755963,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121245250000,12452,121245250000,RH_EXTIMU,2.31546612874e-06,1.52941019786e-05,-0.703375232076,0.710818741075,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.46850510103e-08,-7.04693962898e-09,-7.1201124573e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244929399056,-0.000177396974882,9.8100124492,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121247750000,12453,121247750000,RH_EXTIMU,2.31537001932e-06,1.52942264088e-05,-0.703375295339,0.710818678474,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.23779972374e-07,1.73257945515e-08,-7.12003845096e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245218924333,-0.000176575322531,9.80999890163,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121250250000,12454,121250250000,RH_EXTIMU,2.3155167299e-06,1.52941515825e-05,-0.703375358602,0.710818615874,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.26422431299e-07,4.06525348201e-08,-7.11997978484e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244256567661,-0.000181712710289,9.80999548903,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121252750000,12455,121252750000,RH_EXTIMU,2.31562350845e-06,1.52940680323e-05,-0.703375421864,0.710818553274,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.08623865697e-07,1.32218219055e-08,-7.11990734152e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245404942962,-0.000180370543768,9.81000199504,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121255250000,12456,121255250000,RH_EXTIMU,2.31548258577e-06,1.52940806347e-05,-0.703375485125,0.710818490675,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.63377397976e-08,-7.14821240848e-08,-7.11983658342e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246399667758,-0.000177007967619,9.80999009877,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121257750000,12457,121257750000,RH_EXTIMU,2.31552211161e-06,1.5294043233e-05,-0.703375548386,0.710818428077,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.44124682081e-08,1.62128619551e-09,-7.11976689011e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245055202425,-0.000179583028788,9.81000143065,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121257750000,12458,121260250000,RH_EXTIMU,2.3156702684e-06,1.52940189773e-05,-0.703375611646,0.710818365479,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.87887007797e-08,7.02234999832e-08,-7.1196873679e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244103495554,-0.000180566490015,9.81001944687,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121262750000,12459,121262750000,RH_EXTIMU,2.3154057723e-06,1.52941313908e-05,-0.703375674905,0.710818302882,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.12772127464e-07,-8.42589167184e-08,-7.11961114931e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247283490945,-0.000174481070964,9.80998678873,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121266500000,12460,121265250000,RH_EXTIMU,2.31548357889e-06,1.52939808061e-05,-0.703375738164,0.710818240286,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.29869117491e-07,-4.12001741774e-08,-7.11955957454e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245159299183,-0.000181940426822,9.8099852315,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121267750000,12461,121267750000,RH_EXTIMU,2.31560550047e-06,1.52938666218e-05,-0.703375801423,0.71081817769,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34472804934e-07,4.32257726937e-09,-7.11949376499e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245143029089,-0.000180782386701,9.80999399763,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121272750000,12462,121270250000,RH_EXTIMU,2.31564022014e-06,1.52938317509e-05,-0.70337586468,0.710818115094,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.02552874926e-08,3.55971494079e-10,-7.11942240143e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245245998728,-0.000179228573885,9.80999926543,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121272750000,12463,121272750000,RH_EXTIMU,2.31564579976e-06,1.52938271646e-05,-0.703375927937,0.710818052499,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.64348564955e-09,1.18031179095e-09,-7.11935021513e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245224644376,-0.000178820803295,9.81000091022,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121275250000,12464,121275250000,RH_EXTIMU,2.315651289e-06,1.52938725122e-05,-0.703375991194,0.710817989905,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.15057306988e-08,2.9524554366e-08,-7.11927051089e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245148422704,-0.000177962345709,9.81001071641,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121277750000,12465,121277750000,RH_EXTIMU,2.31555327808e-06,1.52938983624e-05,-0.703376054449,0.710817927312,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.93904129234e-08,-3.98022917204e-08,-7.11919760459e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245579788939,-0.000178060906476,9.81000000984,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121280250000,12466,121280250000,RH_EXTIMU,2.3155710312e-06,1.52938679369e-05,-0.703376117704,0.710817864719,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.81057773973e-08,-6.66330001399e-09,-7.11912784745e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245275552859,-0.000179371488794,9.80999938412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121282750000,12467,121282750000,RH_EXTIMU,2.31559482973e-06,1.52938375288e-05,-0.703376180959,0.710817802127,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.15336670329e-08,-3.25158708278e-09,-7.11905759705e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245275070498,-0.000179311896139,9.80999934944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121285250000,12468,121285250000,RH_EXTIMU,2.31570972678e-06,1.52938152679e-05,-0.703376244212,0.710817739535,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.87527694604e-08,5.2642578449e-08,-7.11898865565e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244053972643,-0.000180373621087,9.81000468508,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121287750000,12469,121287750000,RH_EXTIMU,2.31577306287e-06,1.52938581817e-05,-0.703376307466,0.710817676944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.27585550714e-08,6.0691014977e-08,-7.11891669038e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244610207754,-0.000178780516857,9.81000283051,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121290250000,12470,121290250000,RH_EXTIMU,2.31578736394e-06,1.52938691316e-05,-0.703376370718,0.710817614354,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.86071158889e-09,1.49225377367e-08,-7.11884512e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245161813966,-0.000178876228405,9.81000087646,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121292750000,12471,121292750000,RH_EXTIMU,2.31580334264e-06,1.52938535105e-05,-0.70337643397,0.710817551764,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.87662022106e-08,7.5684732885e-10,-7.11877431763e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245269161799,-0.00017913417739,9.81000001271,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121295250000,12472,121295250000,RH_EXTIMU,2.31578082423e-06,1.52938128174e-05,-0.703376497221,0.710817489175,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.09827146424e-08,-3.51628429159e-08,-7.11869193534e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002461932605,-0.000178697360357,9.81001094976,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121297750000,12473,121297750000,RH_EXTIMU,2.31567039262e-06,1.52938098894e-05,-0.703376560472,0.710817426587,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.02599936502e-08,-6.31563933825e-08,-7.11861697944e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024588430935,-0.000178009177405,9.81000191885,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121300250000,12474,121300250000,RH_EXTIMU,2.31579044544e-06,1.52937630213e-05,-0.703376623721,0.710817363999,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.55310755835e-08,4.15507158368e-08,-7.11854990732e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244099829926,-0.000180941926999,9.81000361977,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121302750000,12475,121302750000,RH_EXTIMU,2.31564046077e-06,1.52938245321e-05,-0.703376686971,0.710817301412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.19011789041e-07,-4.87696121175e-08,-7.11848537263e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246947890165,-0.000175569849615,9.80997525334,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121305250000,12476,121305250000,RH_EXTIMU,2.31577239666e-06,1.52936748888e-05,-0.70337675022,0.710817238825,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.60120163063e-07,-1.0206181055e-08,-7.118438356e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244679545744,-0.00018238996274,9.80998106962,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121307750000,12477,121307750000,RH_EXTIMU,2.31589524171e-06,1.52935484871e-05,-0.703376813468,0.710817176239,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.41872480596e-07,-2.10512967165e-09,-7.11837049627e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245354868462,-0.000180779434034,9.80999381868,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121310250000,12478,121310250000,RH_EXTIMU,2.31591462556e-06,1.52935184943e-05,-0.703376876715,0.710817113654,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.87894775661e-08,-5.49966766598e-09,-7.11829805819e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245308820636,-0.00017898482511,9.81000001441,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121312750000,12479,121312750000,RH_EXTIMU,2.31608460041e-06,1.52935186691e-05,-0.703376939962,0.710817051069,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.74482320917e-08,9.63930402397e-08,-7.1182186026e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243619209934,-0.000180535128701,9.81002199075,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121315250000,12480,121315250000,RH_EXTIMU,2.31600409917e-06,1.52936209718e-05,-0.703377003209,0.710816988484,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.02453422558e-07,1.35251324205e-08,-7.11813862416e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245241206418,-0.000177015523223,9.810007277,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121317750000,12481,121317750000,RH_EXTIMU,2.31598941854e-06,1.5293645572e-05,-0.703377066454,0.710816925901,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.13009891548e-08,6.37667905739e-09,-7.11806726361e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245173564099,-0.000178653644764,9.81000191715,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121319000000,12482,121320250000,RH_EXTIMU,2.31582828712e-06,1.52936496347e-05,-0.703377129699,0.710816863318,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.30243057729e-08,-8.77101114083e-08,-7.11799821909e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247213818295,-0.000176691059909,9.80998318858,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121322750000,12483,121322750000,RH_EXTIMU,2.31589464553e-06,1.52934613509e-05,-0.703377192943,0.710816800735,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.44572294009e-07,-6.90797371596e-08,-7.11794292433e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002456950406,-0.0001818680922,9.80998571925,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121325250000,12484,121325250000,RH_EXTIMU,2.31598312302e-06,1.52933430669e-05,-0.703377256187,0.710816738154,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17761367391e-07,-1.68276610903e-08,-7.11787543405e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245368002997,-0.000180456526954,9.80999498849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121327750000,12485,121327750000,RH_EXTIMU,2.31600603189e-06,1.52933141372e-05,-0.70337731943,0.710816675572,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.01956901988e-08,-2.91160979632e-09,-7.11780377941e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245237991466,-0.000179066510535,9.80999980047,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121330250000,12486,121330250000,RH_EXTIMU,2.31616825395e-06,1.5293292081e-05,-0.703377382673,0.710816612992,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.05548901214e-07,7.93887732853e-08,-7.11772818819e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024347525445,-0.000181027752052,9.8100202985,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121332750000,12487,121332750000,RH_EXTIMU,2.31605304308e-06,1.52934901644e-05,-0.703377445915,0.710816550412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.76087293421e-07,4.84599091683e-08,-7.11763462279e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024509315607,-0.000175075966374,9.81001904078,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121335250000,12488,121335250000,RH_EXTIMU,2.31596077769e-06,1.52935961939e-05,-0.703377509156,0.710816487833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.11240293679e-07,9.02452758898e-09,-7.11755922492e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245172845389,-0.000177322059576,9.81000671076,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121337750000,12489,121337750000,RH_EXTIMU,2.31596843637e-06,1.52935904956e-05,-0.703377572396,0.710816425254,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.45123855582e-09,1.71768842754e-09,-7.11748970976e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245242214439,-0.000179202614918,9.81000012699,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121340250000,12490,121340250000,RH_EXTIMU,2.3159674168e-06,1.52935405814e-05,-0.703377635636,0.710816362676,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.83967398177e-08,-2.83091346481e-08,-7.11742226785e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245859170241,-0.000179242841649,9.80999203248,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121342750000,12491,121342750000,RH_EXTIMU,2.3160563517e-06,1.52934066633e-05,-0.703377698875,0.710816300099,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.26818740363e-07,-2.54606035758e-08,-7.11736112392e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245444496953,-0.000181125634295,9.80999160116,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121345250000,12492,121345250000,RH_EXTIMU,2.31621920358e-06,1.5293352988e-05,-0.703377762113,0.710816237522,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.23699062027e-07,6.17629310376e-08,-7.11729233763e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244094307428,-0.0001807388079,9.81000442627,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121347750000,12493,121347750000,RH_EXTIMU,2.31622784423e-06,1.52933768422e-05,-0.703377825351,0.710816174946,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.61961942637e-09,1.90752826156e-08,-7.11721825144e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245111026369,-0.000178491152926,9.81000191277,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121347750000,12494,121350250000,RH_EXTIMU,2.31621223084e-06,1.52934072615e-05,-0.703377888589,0.71081611237,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.51059919525e-08,9.16077073879e-09,-7.11714271079e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245145039704,-0.000178283057332,9.81000566853,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121347750000,12495,121352750000,RH_EXTIMU,2.31623971148e-06,1.52934171541e-05,-0.703377951825,0.710816049796,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.09500454405e-08,2.17372319366e-08,-7.11706831372e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024491108759,-0.000179112990697,9.81000653695,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121347750000,12496,121355250000,RH_EXTIMU,2.31614881069e-06,1.52934205408e-05,-0.703378015061,0.710815987221,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.27070938907e-08,-4.85758122704e-08,-7.11699303593e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246085655826,-0.000177863390003,9.80999986284,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121357750000,12497,121357750000,RH_EXTIMU,2.31607307487e-06,1.52934277671e-05,-0.703378078296,0.710815924648,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.62440259103e-08,-3.78590754511e-08,-7.11692507121e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245940075456,-0.000177717207754,9.80999015356,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121360250000,12498,121360250000,RH_EXTIMU,2.31633205772e-06,1.52932794686e-05,-0.703378141531,0.710815862075,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.31608844426e-07,6.20483381907e-08,-7.11686647656e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243574147983,-0.000183727209341,9.81000344339,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121362750000,12499,121362750000,RH_EXTIMU,2.31615635188e-06,1.52933084777e-05,-0.703378204765,0.710815799502,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.15349538815e-07,-8.17255973447e-08,-7.11678507402e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247741483625,-0.000175311653649,9.809990245,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121365250000,12500,121365250000,RH_EXTIMU,2.31616931554e-06,1.52932163567e-05,-0.703378267999,0.71081573693,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.00981680685e-08,-4.44418334051e-08,-7.11672401069e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244973900601,-0.000180604908795,9.8099956924,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121367750000,12501,121367750000,RH_EXTIMU,2.31628513565e-06,1.52932026599e-05,-0.703378331232,0.710815674359,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.44581857476e-08,5.80319329635e-08,-7.11665221912e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244197234019,-0.000179896765286,9.81000596245,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121370250000,12502,121370250000,RH_EXTIMU,2.31622635591e-06,1.52932578482e-05,-0.703378394464,0.710815611789,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.35902759675e-08,-1.04421395024e-09,-7.11657437015e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245744342963,-0.000177352134032,9.81000099562,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121372750000,12503,121372750000,RH_EXTIMU,2.31625340975e-06,1.52932030922e-05,-0.703378457695,0.710815549219,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.70851241418e-08,-1.52655005041e-08,-7.11651015619e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245294719151,-0.00017991727076,9.80999488484,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121375250000,12504,121375250000,RH_EXTIMU,2.3163394164e-06,1.52931490742e-05,-0.703378520926,0.710815486649,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.01935282908e-08,1.8327046721e-08,-7.11644136244e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244829531238,-0.000180123192207,9.81000148271,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121377750000,12505,121377750000,RH_EXTIMU,2.31638663311e-06,1.52932074817e-05,-0.703378584157,0.71081542408,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.12665713619e-09,6.04308850314e-08,-7.11636778868e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244295802242,-0.000178475401049,9.81000478596,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121380250000,12506,121380250000,RH_EXTIMU,2.31646599743e-06,1.52932065931e-05,-0.703378647386,0.710815361512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.65202688166e-08,4.4801539714e-08,-7.11628457512e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244795231329,-0.000179685956804,9.81001977608,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121382750000,12507,121382750000,RH_EXTIMU,2.31621301797e-06,1.52932924699e-05,-0.703378710615,0.710815298945,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.91290966041e-07,-9.28699100488e-08,-7.11620686796e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024724078037,-0.000175049840532,9.80999176061,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121385250000,12508,121385250000,RH_EXTIMU,2.3162650969e-06,1.52931585641e-05,-0.703378773843,0.710815236378,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.05853481939e-07,-4.61925273945e-08,-7.11615094666e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245318235173,-0.000181411488804,9.80998892685,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121387750000,12509,121387750000,RH_EXTIMU,2.31643714501e-06,1.52930325613e-05,-0.703378837071,0.710815173812,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.69627222028e-07,2.58084932568e-08,-7.11608394487e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244561379804,-0.000181662783481,9.8100018493,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121390250000,12510,121390250000,RH_EXTIMU,2.31641611414e-06,1.52930287221e-05,-0.703378900298,0.710815111246,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.90945049597e-09,-1.33689959071e-08,-7.11600147324e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245799695021,-0.000178138135462,9.8100086286,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121392750000,12511,121392750000,RH_EXTIMU,2.316191038e-06,1.52931047183e-05,-0.703378963525,0.710815048681,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.69863838418e-07,-8.27873693322e-08,-7.11593066377e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246887847731,-0.000175340295611,9.80998436447,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121395250000,12512,121395250000,RH_EXTIMU,2.31631441626e-06,1.52929437258e-05,-0.70337902675,0.710814986117,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.61639785623e-07,-2.14751183143e-08,-7.11588161312e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244966044151,-0.000182373897771,9.80998340416,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121397750000,12513,121397750000,RH_EXTIMU,2.31652504007e-06,1.52928303067e-05,-0.703379089976,0.710814923553,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.8448235794e-07,5.46710080763e-08,-7.11581472013e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244003249729,-0.000181766767491,9.81000266782,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121400250000,12514,121400250000,RH_EXTIMU,2.3165056287e-06,1.52929431757e-05,-0.7033791532,0.71081486099,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.36606133213e-08,5.3908582473e-08,-7.11573725122e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244818992078,-0.000176816097551,9.81000165273,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121402750000,12515,121402750000,RH_EXTIMU,2.31668032892e-06,1.52929041041e-05,-0.703379216425,0.710814798427,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22218811083e-07,7.67344592939e-08,-7.11566649515e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243696227435,-0.000181700632049,9.81001699356,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121405250000,12516,121405250000,RH_EXTIMU,2.31655617887e-06,1.52930429257e-05,-0.703379279648,0.710814735865,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.47824103834e-07,9.72975059281e-09,-7.11557172019e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245692718746,-0.000175485586938,9.81001770796,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121409000000,12517,121407750000,RH_EXTIMU,2.31640647798e-06,1.52930797921e-05,-0.70337934287,0.710814673304,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.04983116269e-07,-6.26248088374e-08,-7.11551995767e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246126994519,-0.000177564610858,9.80997045938,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121410250000,12518,121410250000,RH_EXTIMU,2.31687508205e-06,1.52928230983e-05,-0.703379406093,0.710814610743,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.1180445783e-07,1.18363984597e-07,-7.1154632845e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242640083254,-0.000186704189689,9.81001224175,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121412750000,12519,121412750000,RH_EXTIMU,2.31668530298e-06,1.52929615454e-05,-0.703379469314,0.710814548183,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.84933459433e-07,-2.74129603638e-08,-7.11536476584e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246972052318,-0.000173800804543,9.81000901573,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121415250000,12520,121415250000,RH_EXTIMU,2.31652321208e-06,1.52930078482e-05,-0.703379532534,0.710814485624,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.1733860415e-07,-6.42307578872e-08,-7.11528580288e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245887531905,-0.000177295024457,9.81001124221,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121417750000,12521,121417750000,RH_EXTIMU,2.31638219255e-06,1.52930806735e-05,-0.703379595754,0.710814423065,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.20280619831e-07,-3.72917889389e-08,-7.11521815086e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245779741645,-0.000176578036928,9.80998629734,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121420250000,12522,121420250000,RH_EXTIMU,2.31660995489e-06,1.52929382451e-05,-0.703379658974,0.710814360506,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.10551786163e-07,4.7818782068e-08,-7.11517454337e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244118578496,-0.000183124462365,9.80998187387,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121422750000,12523,121422750000,RH_EXTIMU,2.31679723132e-06,1.52928291462e-05,-0.703379722193,0.710814297949,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.68774752446e-07,4.39900902866e-08,-7.11510298818e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244744643577,-0.00018119663528,9.81000271664,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121425250000,12524,121425250000,RH_EXTIMU,2.3166034873e-06,1.52928318226e-05,-0.703379785411,0.710814235392,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.10789463649e-07,-1.06850384051e-07,-7.11502591524e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247361379447,-0.00017624157332,9.80999003227,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121427750000,12525,121427750000,RH_EXTIMU,2.31663040838e-06,1.52927493615e-05,-0.703379848629,0.710814172835,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.25992085297e-08,-3.10948229526e-08,-7.11496475466e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245246260338,-0.000180217994695,9.80999227426,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121430250000,12526,121430250000,RH_EXTIMU,2.31692627831e-06,1.52926166283e-05,-0.703379911846,0.710814110279,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.43825699617e-07,9.16563727748e-08,-7.11489339792e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243111177496,-0.000183586685042,9.81002121811,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121432750000,12527,121432750000,RH_EXTIMU,2.31683186372e-06,1.5292779313e-05,-0.703379975062,0.710814047724,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.44342986123e-07,4.00315580437e-08,-7.11479029172e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245404068722,-0.000175368040617,9.81003101054,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121435250000,12528,121435250000,RH_EXTIMU,2.31642281289e-06,1.52930212279e-05,-0.703380038278,0.71081398517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.67844400807e-07,-9.1961189801e-08,-7.11470619833e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247196699884,-0.000172006654328,9.80999387614,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121437750000,12529,121437750000,RH_EXTIMU,2.31647522102e-06,1.52928509287e-05,-0.703380101493,0.710813922616,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.26519333535e-07,-6.67024249232e-08,-7.11466790715e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245702176529,-0.00018231803458,9.80997007704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121440250000,12530,121440250000,RH_EXTIMU,2.31679742571e-06,1.52926608426e-05,-0.703380164707,0.710813860063,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.91073581442e-07,7.38613755346e-08,-7.11460535379e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243841805674,-0.000183416192135,9.8100009785,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121442750000,12531,121442750000,RH_EXTIMU,2.31689838247e-06,1.52926218994e-05,-0.703380227921,0.71081379751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.02119893856e-08,3.5311791707e-08,-7.11452671208e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244747309718,-0.000180071301107,9.81001201285,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121445250000,12532,121445250000,RH_EXTIMU,2.3167523405e-06,1.5292651816e-05,-0.703380291134,0.710813734958,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.89918365671e-08,-6.45182047129e-08,-7.11445149212e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246562125348,-0.000176708752588,9.80999275607,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121447750000,12533,121447750000,RH_EXTIMU,2.31677927291e-06,1.52926316978e-05,-0.703380354347,0.710813672406,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.75250244979e-08,4.36285182131e-09,-7.11438728857e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244908084937,-0.000179226051786,9.80999585467,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121450250000,12534,121450250000,RH_EXTIMU,2.31687623825e-06,1.52926268337e-05,-0.703380417559,0.710813609855,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.87657454016e-08,5.24449421786e-08,-7.11431634574e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244309974508,-0.000179936966874,9.81000630531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121452750000,12535,121452750000,RH_EXTIMU,2.31683081152e-06,1.52926716937e-05,-0.70338048077,0.710813547305,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.01855727104e-08,5.95918245096e-10,-7.11423516254e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245525039411,-0.000177597545123,9.81000707204,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121455250000,12536,121455250000,RH_EXTIMU,2.31679832467e-06,1.52926957989e-05,-0.70338054398,0.710813484756,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.11485038145e-08,-3.92498352997e-09,-7.11416259241e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245267324638,-0.000178373271411,9.81000264412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121457750000,12537,121457750000,RH_EXTIMU,2.31673012778e-06,1.52926793261e-05,-0.70338060719,0.710813422207,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.8621682079e-08,-4.70938504131e-08,-7.11408311526e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246121155672,-0.000178213023114,9.81000701603,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121460250000,12538,121460250000,RH_EXTIMU,2.31677476025e-06,1.52926525708e-05,-0.7033806704,0.710813359659,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.13248426623e-08,1.0548550271e-08,-7.11402306003e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244664695692,-0.000179880300004,9.80999056844,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121462750000,12539,121462750000,RH_EXTIMU,2.31681518314e-06,1.52925967217e-05,-0.703380733608,0.710813297111,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.53022714873e-08,-8.36441415651e-09,-7.11395730277e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245855104973,-0.000179312792895,9.80999024055,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121465250000,12540,121465250000,RH_EXTIMU,2.31683736388e-06,1.52924630551e-05,-0.703380796816,0.710813234564,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.87171621902e-08,-6.28803816073e-08,-7.11388761469e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246083239226,-0.000180408860138,9.80999776491,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121465250000,12541,121467750000,RH_EXTIMU,2.31687046987e-06,1.52924245094e-05,-0.703380860024,0.710813172017,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.1404766281e-08,-2.64207693195e-09,-7.11381291458e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244866716736,-0.000179351971383,9.81000588241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121470250000,12542,121470250000,RH_EXTIMU,2.31674236253e-06,1.52925023576e-05,-0.70338092323,0.710813109471,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.15764666783e-07,-2.71701447545e-08,-7.11374201367e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024625534751,-0.000176150311558,9.80998893284,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121472750000,12543,121472750000,RH_EXTIMU,2.31689030517e-06,1.52923746765e-05,-0.703380986437,0.710813046926,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.56863618625e-07,1.12901292324e-08,-7.1136862505e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244313270006,-0.000182316952928,9.80999268571,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121475250000,12544,121475250000,RH_EXTIMU,2.31712401259e-06,1.52922929046e-05,-0.703381049642,0.710812984381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.7980044973e-07,8.56566663153e-08,-7.11361241038e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243888070004,-0.000181778387392,9.8100159202,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121477750000,12545,121477750000,RH_EXTIMU,2.31684317927e-06,1.52924254723e-05,-0.703381112847,0.710812921837,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.33403272891e-07,-8.19936270249e-08,-7.11352430087e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247121246669,-0.000173940724653,9.80999841577,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121480250000,12546,121480250000,RH_EXTIMU,2.31683045732e-06,1.52924170518e-05,-0.703381176051,0.710812859294,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.60694543547e-09,-1.12989934783e-08,-7.11345753583e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245157915057,-0.000179115213883,9.81000027079,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121482750000,12547,121482750000,RH_EXTIMU,2.31685910172e-06,1.52923843733e-05,-0.703381239255,0.710812796751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.5566134085e-08,-1.816280707e-09,-7.11338779552e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245252945819,-0.000179394539576,9.80999899701,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121482750000,12548,121485250000,RH_EXTIMU,2.31688432892e-06,1.52923558214e-05,-0.703381302458,0.710812734209,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.13009022511e-08,-1.39259099805e-09,-7.11331754663e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245251563789,-0.000179256921676,9.80999936348,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121487750000,12549,121487750000,RH_EXTIMU,2.31690462413e-06,1.52923341958e-05,-0.70338136566,0.710812671667,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.45988266176e-08,-2.29189394469e-10,-7.11324691689e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245235620918,-0.000179142050714,9.80999975175,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121490250000,12550,121490250000,RH_EXTIMU,2.3169222884e-06,1.52923158122e-05,-0.703381428862,0.710812609126,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.12784996711e-08,1.33858724608e-10,-7.11317612958e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245233744973,-0.000179094506823,9.80999992517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121492750000,12551,121492750000,RH_EXTIMU,2.3169972491e-06,1.52923042455e-05,-0.703381492063,0.710812546586,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.00241210319e-08,3.62513797129e-08,-7.11310988729e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244570671538,-0.000179683701904,9.80999782598,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121497750000,12552,121495250000,RH_EXTIMU,2.31709911732e-06,1.52922759273e-05,-0.703381555264,0.710812484046,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.47512974725e-08,4.18665593392e-08,-7.11304791995e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244597243875,-0.000180086147031,9.80999222413,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121497750000,12553,121497750000,RH_EXTIMU,2.31710630053e-06,1.52922272487e-05,-0.703381618463,0.710812421507,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.23655302941e-08,-2.29911128337e-08,-7.11296183961e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245952515872,-0.000178936288437,9.81001643388,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121500250000,12554,121500250000,RH_EXTIMU,2.31706316043e-06,1.5292287577e-05,-0.703381681662,0.710812358969,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.75895541985e-08,1.06784315757e-08,-7.11287660314e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244891820858,-0.000177875375119,9.81001917689,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121502750000,12555,121502750000,RH_EXTIMU,2.31697327913e-06,1.52923906062e-05,-0.703381744861,0.710812296431,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.08197043397e-07,8.65883103869e-09,-7.11281634069e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244931608408,-0.000177176353357,9.80998514424,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121505250000,12556,121505250000,RH_EXTIMU,2.31708028079e-06,1.52923550771e-05,-0.703381808059,0.710812233894,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.17280071335e-08,4.06546964223e-08,-7.11274993152e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244923601163,-0.000179950218145,9.80999638779,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121507750000,12557,121507750000,RH_EXTIMU,2.31715209136e-06,1.52922341149e-05,-0.703381871256,0.710812171357,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.09790237987e-07,-2.77290300593e-08,-7.11268614771e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245665804616,-0.000180982557382,9.80999298541,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121510250000,12558,121510250000,RH_EXTIMU,2.31727696203e-06,1.52921135446e-05,-0.703381934453,0.710812108821,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.39742281372e-07,2.35107517404e-09,-7.11261309376e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244848516226,-0.000181162429911,9.81000888036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121512750000,12559,121512750000,RH_EXTIMU,2.31707447482e-06,1.5292152841e-05,-0.703381997649,0.710812046286,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.36367529827e-07,-9.09469209309e-08,-7.112539939e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247020940638,-0.000175891596653,9.80998527071,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121515250000,12560,121515250000,RH_EXTIMU,2.31731153767e-06,1.52920519184e-05,-0.703382060844,0.710811983751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.92484461671e-07,7.66548716098e-08,-7.11247644257e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243213947663,-0.000182699478431,9.81001129344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121517750000,12561,121517750000,RH_EXTIMU,2.31730420426e-06,1.52921680091e-05,-0.703382124039,0.710811921217,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.86060120525e-08,6.25362559051e-08,-7.11238795783e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244915353628,-0.000176869336259,9.81001771063,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121520250000,12562,121520250000,RH_EXTIMU,2.31699482564e-06,1.52923224653e-05,-0.703382187233,0.710811858683,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.61952409066e-07,-8.56097715319e-08,-7.1123066069e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247178428377,-0.000173766161769,9.80999337428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121522750000,12563,121522750000,RH_EXTIMU,2.31738623429e-06,1.52922505273e-05,-0.703382250426,0.71081179615,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.63943309933e-07,1.79988234201e-07,-7.11225174424e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000241433577947,-0.000184553231519,9.81001424956,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121525250000,12564,121525250000,RH_EXTIMU,2.31715833053e-06,1.52922352414e-05,-0.703382313619,0.710811733618,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.20106896358e-07,-1.36287203198e-07,-7.11217312568e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000248283861113,-0.000176153873823,9.80998446142,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121527750000,12565,121527750000,RH_EXTIMU,2.31717143892e-06,1.52920729523e-05,-0.703382376811,0.710811671086,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.96641310168e-08,-8.42615951979e-08,-7.1121225867e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246129988213,-0.000180736477256,9.80997464646,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121530250000,12566,121530250000,RH_EXTIMU,2.31742478985e-06,1.52918907581e-05,-0.703382440003,0.710811608555,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.47478536047e-07,3.96053307644e-08,-7.11206141094e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244168096023,-0.000182949214602,9.81000071844,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121532750000,12567,121532750000,RH_EXTIMU,2.31735913452e-06,1.52919485445e-05,-0.703382503194,0.710811546025,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.89626120713e-08,-3.43665083216e-09,-7.11197473016e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024578765164,-0.00017671830211,9.81000952875,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121535250000,12568,121535250000,RH_EXTIMU,2.31725870111e-06,1.52920104591e-05,-0.703382566384,0.710811483495,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.1062121901e-08,-2.06589969357e-08,-7.11189714968e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245354970971,-0.000177355949759,9.8100058171,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121537750000,12569,121537750000,RH_EXTIMU,2.31732976923e-06,1.52919980835e-05,-0.703382629573,0.710811420966,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.82656187559e-08,3.36008945602e-08,-7.11182876349e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244605987261,-0.000180008967421,9.81000332159,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121540250000,12570,121540250000,RH_EXTIMU,2.31724399456e-06,1.52919774862e-05,-0.703382692762,0.710811358437,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.6296528507e-08,-5.93307485846e-08,-7.11175991936e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024641156782,-0.00017786488109,9.80998911506,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121542750000,12571,121542750000,RH_EXTIMU,2.31733103661e-06,1.52919090309e-05,-0.703382755951,0.710811295909,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.89055165871e-08,1.0699871905e-08,-7.11169527938e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244795738299,-0.000180372728294,9.8099969081,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121545250000,12572,121545250000,RH_EXTIMU,2.31746926095e-06,1.52918730992e-05,-0.703382819139,0.710811233382,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.97090310835e-08,5.79949812311e-08,-7.11162700963e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244184697572,-0.000180494319004,9.81000426452,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121547750000,12573,121547750000,RH_EXTIMU,2.31747779983e-06,1.52919267228e-05,-0.703382882326,0.710811170855,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.4429766239e-08,3.5945636504e-08,-7.11155007304e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244974203885,-0.000178001682999,9.81000523767,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121550250000,12574,121550250000,RH_EXTIMU,2.31747770126e-06,1.52919150212e-05,-0.703382945512,0.710811108329,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.41744661708e-09,-6.06181616521e-09,-7.11147205777e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245638241292,-0.000179041958343,9.81001002468,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121552750000,12575,121552750000,RH_EXTIMU,2.31733735113e-06,1.52919166746e-05,-0.703383008698,0.710811045803,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.98514569283e-08,-7.73879015287e-08,-7.11139143265e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246353781845,-0.000177203271403,9.81000272127,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121555250000,12576,121555250000,RH_EXTIMU,2.31738205003e-06,1.52919320652e-05,-0.703383071883,0.710810983278,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.7646480454e-08,3.45519664842e-08,-7.11133686019e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244282975088,-0.00017940896081,9.8099867749,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121557750000,12577,121557750000,RH_EXTIMU,2.31761517545e-06,1.52918427932e-05,-0.703383135068,0.710810920754,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.83689314123e-07,8.10645096586e-08,-7.11127278565e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243848133721,-0.000182112128958,9.81000262568,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121560250000,12578,121560250000,RH_EXTIMU,2.31758625231e-06,1.52918583012e-05,-0.703383198252,0.71081085823,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.42846473112e-08,-6.80892539938e-09,-7.111190158e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246045949969,-0.000177720433675,9.81000688734,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121562750000,12579,121562750000,RH_EXTIMU,2.31746085669e-06,1.52918780512e-05,-0.703383261435,0.710810795707,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.15306362554e-08,-5.86824029385e-08,-7.11111407233e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024595675459,-0.000177321895407,9.80999950226,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121565250000,12580,121565250000,RH_EXTIMU,2.31750189596e-06,1.52918554059e-05,-0.703383324617,0.710810733185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.69684056828e-08,1.08636157684e-08,-7.11104747055e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244914816945,-0.000179607343134,9.81000071661,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121567750000,12581,121567750000,RH_EXTIMU,2.31740056963e-06,1.5291854943e-05,-0.703383387799,0.710810670663,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.64697301975e-08,-5.66325273261e-08,-7.11097449054e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246533103752,-0.0001773483307,9.80999272042,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121570250000,12582,121570250000,RH_EXTIMU,2.31744912562e-06,1.52917651877e-05,-0.703383450981,0.710810608142,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.90060760906e-08,-2.30687496227e-08,-7.11090372107e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245220773124,-0.000180442596472,9.81000432271,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121572750000,12583,121572750000,RH_EXTIMU,2.31760507913e-06,1.52918353269e-05,-0.703383514161,0.710810545621,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.01037342203e-08,1.28288362988e-07,-7.11083787694e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242787498989,-0.000179593711106,9.8100052606,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121575250000,12584,121575250000,RH_EXTIMU,2.31775776452e-06,1.52918543495e-05,-0.703383577342,0.710810483101,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.70089905478e-08,9.73819805135e-08,-7.11076617787e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243906084274,-0.000180428843228,9.81000758459,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121577750000,12585,121577750000,RH_EXTIMU,2.3176721185e-06,1.52918609287e-05,-0.703383640521,0.710810420582,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.15157882976e-08,-4.38046882402e-08,-7.11068814478e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246760096027,-0.000177293242569,9.80999848,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121580250000,12586,121580250000,RH_EXTIMU,2.31757808449e-06,1.52918272243e-05,-0.7033837037,0.710810358064,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.36177974453e-08,-7.14318281401e-08,-7.11062171418e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246048798928,-0.000178258963976,9.80998988568,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121582750000,12587,121582750000,RH_EXTIMU,2.31766122403e-06,1.52916677759e-05,-0.703383766878,0.710810295545,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.37888696815e-07,-4.32392029043e-08,-7.11055588347e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245820903015,-0.000181374329153,9.80999684717,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121587750000,12588,121585250000,RH_EXTIMU,2.31764739176e-06,1.52916634367e-05,-0.703383830056,0.710810233028,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.53519976863e-09,-9.60335024826e-09,-7.11048318065e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245145998551,-0.000178274349202,9.81000072665,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121587750000,12589,121587750000,RH_EXTIMU,2.31775564654e-06,1.52916800017e-05,-0.703383893232,0.710810170511,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.31263934762e-08,7.09830642159e-08,-7.1104109589e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243764234402,-0.000179977660781,9.81001056308,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121590250000,12590,121590250000,RH_EXTIMU,2.31776325715e-06,1.52917676954e-05,-0.703383956409,0.710810107995,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.41293566549e-08,5.47970738252e-08,-7.11033310525e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244796584574,-0.00017769162354,9.81000736852,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121592750000,12591,121592750000,RH_EXTIMU,2.31762138236e-06,1.52917504405e-05,-0.703384019584,0.710810045479,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.00785666991e-08,-8.89983338965e-08,-7.11024986495e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247054803574,-0.000177552530541,9.81000671667,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121595250000,12592,121595250000,RH_EXTIMU,2.31754605066e-06,1.52917284656e-05,-0.703384082759,0.710809982965,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.95830204509e-08,-5.42380511632e-08,-7.11017628591e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245790823442,-0.00017838691694,9.8100026263,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121597750000,12593,121597750000,RH_EXTIMU,2.31755282681e-06,1.52917058092e-05,-0.703384145933,0.71080992045,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.74908848901e-08,-8.42287722859e-09,-7.11010672703e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245220985065,-0.000179137983202,9.80999989489,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121600250000,12594,121600250000,RH_EXTIMU,2.31754392467e-06,1.52917386503e-05,-0.703384209107,0.710809857937,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.26533892071e-08,1.43133533205e-08,-7.11004326657e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244908595419,-0.000178086834648,9.80998712509,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121602750000,12595,121602750000,RH_EXTIMU,2.31777320602e-06,1.52916330064e-05,-0.70338427228,0.710809795424,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.90715661071e-07,6.95917663304e-08,-7.10998803543e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244112093561,-0.000182559230562,9.80999604279,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121605250000,12596,121605250000,RH_EXTIMU,2.31771712264e-06,1.52916167159e-05,-0.703384335452,0.710809732911,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.18361762865e-08,-4.01745085799e-08,-7.10990800859e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246223810014,-0.000177607811612,9.80999647042,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121607750000,12597,121607750000,RH_EXTIMU,2.31766381361e-06,1.52915652996e-05,-0.703384398624,0.710809670399,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.93004364903e-10,-5.85875642236e-08,-7.10984848062e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246355430608,-0.000178667640258,9.80998245161,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121611500000,12598,121610250000,RH_EXTIMU,2.31774469793e-06,1.52913803465e-05,-0.703384461795,0.710809607888,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.50957881833e-07,-5.90113605697e-08,-7.10978891677e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245761677011,-0.000181573952623,9.80998795566,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121612750000,12599,121612750000,RH_EXTIMU,2.31787101793e-06,1.52913376184e-05,-0.703384524966,0.710809545377,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.67636437087e-08,4.74315869022e-08,-7.10971237867e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244299883979,-0.000179918450166,9.81001161436,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121615250000,12600,121615250000,RH_EXTIMU,2.3179515003e-06,1.52913893267e-05,-0.703384588136,0.710809482867,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.75581801316e-08,7.53393545302e-08,-7.1096326351e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243748008006,-0.000179468306627,9.81002078792,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121617750000,12601,121617750000,RH_EXTIMU,2.31761113905e-06,1.5291612481e-05,-0.703384651305,0.710809420358,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.1822761256e-07,-6.39801432935e-08,-7.10954679325e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247364027996,-0.000172041242083,9.80999065322,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121620250000,12602,121620250000,RH_EXTIMU,2.31771127687e-06,1.52914793755e-05,-0.703384714474,0.710809357849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.32731296695e-07,-1.86942465954e-08,-7.10950313127e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244757569268,-0.000182374028815,9.80998171645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121622750000,12603,121622750000,RH_EXTIMU,2.31786584193e-06,1.52913259422e-05,-0.703384777642,0.71080929534,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.75119775355e-07,3.73077159256e-10,-7.10943881258e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245282499848,-0.000181401139272,9.80999162932,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121625250000,12604,121625250000,RH_EXTIMU,2.3180376838e-06,1.5291238927e-05,-0.70338484081,0.710809232833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.47570208828e-07,4.78633285058e-08,-7.10936023122e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244481089105,-0.000181076831116,9.81001624519,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121627750000,12605,121627750000,RH_EXTIMU,2.3178836031e-06,1.52913456307e-05,-0.703384903976,0.710809170326,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.46771956925e-07,-2.53781559253e-08,-7.10926465422e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245917701598,-0.00017569391902,9.81002203381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121630250000,12606,121630250000,RH_EXTIMU,2.31780381119e-06,1.5291438853e-05,-0.703384967142,0.710809107819,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.69417764925e-08,8.75860715543e-09,-7.10919294772e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244695787559,-0.000177713161219,9.81000597666,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121632750000,12607,121632750000,RH_EXTIMU,2.31779809195e-06,1.52914276489e-05,-0.703385030308,0.710809045314,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.94105505172e-09,-8.94196014874e-09,-7.10913140301e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245533183759,-0.000179048891124,9.80998626095,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121635250000,12608,121635250000,RH_EXTIMU,2.31792606354e-06,1.52913347746e-05,-0.703385093473,0.710808982809,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.25920373333e-07,1.98454705354e-08,-7.10907595211e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244808231412,-0.000180897634217,9.80998514656,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121637750000,12609,121637750000,RH_EXTIMU,2.31804681888e-06,1.52912150178e-05,-0.703385156637,0.710808920304,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.36943935259e-07,4.98103420198e-10,-7.10900441548e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245427556737,-0.000180911183836,9.81000429652,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121640250000,12610,121640250000,RH_EXTIMU,2.31793521569e-06,1.52912304968e-05,-0.7033852198,0.7108088578,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.12844041398e-08,-5.33504690042e-08,-7.10891678154e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246091433481,-0.000177102240669,9.81001009796,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121642750000,12611,121642750000,RH_EXTIMU,2.31782433203e-06,1.52913131751e-05,-0.703385282963,0.710808795297,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.08688842753e-07,-1.4732895389e-08,-7.10885058658e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002453577045,-0.000176648477689,9.8099902522,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121645250000,12612,121645250000,RH_EXTIMU,2.31807955603e-06,1.5291260443e-05,-0.703385346126,0.710808732794,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.75693688516e-07,1.14278199557e-07,-7.1087823746e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243244988557,-0.000182313002249,9.8100160006,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121647750000,12613,121647750000,RH_EXTIMU,2.31788169503e-06,1.52913482486e-05,-0.703385409287,0.710808670292,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.61033452967e-07,-6.07601512225e-08,-7.10870386613e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246886566407,-0.000175267692616,9.80999016553,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121650250000,12614,121650250000,RH_EXTIMU,2.31792790065e-06,1.5291194156e-05,-0.703385472448,0.710808607791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.13872468231e-07,-6.09765734795e-08,-7.10865638952e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245706363324,-0.000181505496075,9.80997588653,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121652750000,12615,121652750000,RH_EXTIMU,2.31814684355e-06,1.52909963312e-05,-0.703385535609,0.71080854529,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.36707390429e-07,1.13560091861e-08,-7.10859410973e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244847936407,-0.000182642004492,9.80999627761,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121655250000,12616,121655250000,RH_EXTIMU,2.31815357193e-06,1.52909676142e-05,-0.703385598769,0.710808482789,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.08739285542e-08,-1.18963135402e-08,-7.10850996098e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245640331666,-0.000178464084646,9.81001099177,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121657750000,12617,121657750000,RH_EXTIMU,2.31807033149e-06,1.52910238717e-05,-0.703385661928,0.71080842029,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.81024713608e-08,-1.42020392449e-08,-7.1084330683e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245361599548,-0.00017739709036,9.81000567575,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121660250000,12618,121660250000,RH_EXTIMU,2.31824621709e-06,1.5291057199e-05,-0.703385725087,0.710808357791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.21517344785e-08,1.18571194974e-07,-7.10836303686e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242707066777,-0.000180744973077,9.81001658021,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121662750000,12619,121662750000,RH_EXTIMU,2.31818474674e-06,1.52912204235e-05,-0.703385788244,0.710808295292,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.25914282772e-07,5.8874633517e-08,-7.10827782304e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245230589002,-0.000175986018371,9.81001043834,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121665250000,12620,121665250000,RH_EXTIMU,2.31804454376e-06,1.52912717488e-05,-0.703385851402,0.710808232795,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.07718593748e-07,-4.90601074588e-08,-7.10820602763e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246129874846,-0.000177011529267,9.8099942445,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121667750000,12621,121667750000,RH_EXTIMU,2.31808332406e-06,1.52911907417e-05,-0.703385914558,0.710808170298,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.85241471223e-08,-2.3594958312e-08,-7.10814870103e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245506294347,-0.000180214068416,9.80998539674,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121670250000,12622,121670250000,RH_EXTIMU,2.31814337959e-06,1.5291049045e-05,-0.703385977714,0.710808107801,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.14772818291e-07,-4.61341651227e-08,-7.10808551726e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245966131796,-0.000180508556494,9.80999018144,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121672750000,12623,121672750000,RH_EXTIMU,2.31802631456e-06,1.52910031352e-05,-0.70338604087,0.710808045305,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.98462636033e-08,-9.13326259074e-08,-7.10801314341e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024685404872,-0.000177493345939,9.80998731386,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121675250000,12624,121675250000,RH_EXTIMU,2.3181395692e-06,1.52908786067e-05,-0.703386104024,0.71080798281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.35363546124e-07,-6.43588926174e-09,-7.10793885539e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244845242083,-0.000181282389164,9.81001516888,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121677750000,12625,121677750000,RH_EXTIMU,2.3182163373e-06,1.52909519861e-05,-0.703386167178,0.710807920315,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.2511190688e-09,8.55723666161e-08,-7.10785483096e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243715469974,-0.000178748053651,9.81002246438,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121680250000,12626,121680250000,RH_EXTIMU,2.31811984613e-06,1.52910566001e-05,-0.703386230332,0.710807857821,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.12848156175e-07,5.83929633292e-09,-7.10779483882e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245233756545,-0.0001770666726,9.80998115633,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121685250000,12627,121682750000,RH_EXTIMU,2.31845140279e-06,1.52909668806e-05,-0.703386293485,0.710807795328,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.39912889244e-07,1.36198584649e-07,-7.10772409866e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243098242912,-0.000183013549761,9.81001925276,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121685250000,12628,121685250000,RH_EXTIMU,2.31823559421e-06,1.52910787316e-05,-0.703386356637,0.710807732835,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.8476986155e-07,-5.71864786967e-08,-7.1076428031e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024686605219,-0.000174799057644,9.80999452923,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121687750000,12629,121687750000,RH_EXTIMU,2.32618954284e-06,1.5292562392e-05,-0.703386419781,0.71080767035,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.68900169643e-06,5.32008425948e-06,-7.10677950122e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000156141198923,-0.000242468062611,9.81178683408,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121690250000,12630,121690250000,RH_EXTIMU,2.3075513571e-06,1.53052951272e-05,-0.703386482919,0.710807607871,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.7762470079e-05,-3.24680980269e-06,-7.10607845063e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00033355421828,0.0001561322201,9.80946508972,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121692750000,12631,121692750000,RH_EXTIMU,2.31269695785e-06,1.52976061496e-05,-0.703386546068,0.710807545381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.2535726426e-06,-1.47618166313e-06,-7.10726871291e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000237555667925,-0.000371298284081,9.80910856937,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121695250000,12632,121695250000,RH_EXTIMU,2.31962735042e-06,1.52897828873e-05,-0.70338660922,0.710807482889,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.34405072098e-06,-5.48223268592e-07,-7.10756951847e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000255163332264,-0.000303304365965,9.80953978171,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121697750000,12633,121697750000,RH_EXTIMU,2.31971753433e-06,1.52886412321e-05,-0.703386672371,0.710807420398,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.94591085311e-07,-5.97803099423e-07,-7.10751527405e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000251555263183,-0.000171709257439,9.80984474309,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121700250000,12634,121700250000,RH_EXTIMU,2.31922260646e-06,1.52894396836e-05,-0.703386735521,0.710807357907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.29846493386e-07,1.76182798177e-07,-7.10741003384e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000241336198945,-0.000161538207385,9.81000108649,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121702750000,12635,121702750000,RH_EXTIMU,2.31898275637e-06,1.52898971992e-05,-0.703386798669,0.710807295417,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.92949737821e-07,1.25845651249e-07,-7.10728794322e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244418510078,-0.000172226606021,9.81005076506,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121705250000,12636,121705250000,RH_EXTIMU,2.31859122173e-06,1.52902704824e-05,-0.703386861818,0.710807232928,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.31806145196e-07,-7.4071219628e-09,-7.10719048809e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245367387979,-0.000171819329491,9.81002245307,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121707750000,12637,121707750000,RH_EXTIMU,2.31850427023e-06,1.52903770124e-05,-0.703386924965,0.71080717044,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.08501707336e-07,1.22966416102e-08,-7.1071165266e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245248432342,-0.000177696512362,9.81000913808,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121710250000,12638,121710250000,RH_EXTIMU,2.31861543342e-06,1.52904287219e-05,-0.703386988112,0.710807107953,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.50033711052e-08,9.26042157451e-08,-7.10704540267e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024342746761,-0.000179575857891,9.8100095921,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121710250000,12639,121712750000,RH_EXTIMU,2.31856218834e-06,1.5290474877e-05,-0.703387051258,0.710807045466,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.53611492236e-08,-3.06840282794e-09,-7.1069529682e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245794687033,-0.000177580365053,9.81002374185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121715250000,12640,121715250000,RH_EXTIMU,2.31830484216e-06,1.52904547654e-05,-0.703387114403,0.71080698298,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.34133517614e-07,-1.5560028015e-07,-7.10688328637e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247774590044,-0.000176817779568,9.80998312551,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121717750000,12641,121717750000,RH_EXTIMU,2.31861859013e-06,1.52903916958e-05,-0.703387177547,0.710806920494,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.14789604126e-07,1.41331978125e-07,-7.10681331846e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242297182117,-0.000182533083506,9.81002502532,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121720250000,12642,121720250000,RH_EXTIMU,2.31846868424e-06,1.52904931569e-05,-0.703387240691,0.71080685801,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.41448170504e-07,-2.60108939962e-08,-7.10672780654e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246467283207,-0.000176026152331,9.81000495154,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121722750000,12643,121722750000,RH_EXTIMU,2.3184725556e-06,1.52904355236e-05,-0.703387303835,0.710806795525,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.55205269573e-08,-2.99472362992e-08,-7.10665541536e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245053377067,-0.000179907658666,9.81000816647,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121725250000,12644,121725250000,RH_EXTIMU,2.31859200138e-06,1.52904986537e-05,-0.703387366977,0.710806733042,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.32866592494e-08,1.03759145041e-07,-7.10658248161e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243376904983,-0.000179412087248,9.81001084972,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121727750000,12645,121727750000,RH_EXTIMU,2.31848359124e-06,1.5290483332e-05,-0.703387430119,0.710806670559,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.21369970714e-08,-6.90688607756e-08,-7.10650552421e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247083614757,-0.000177606882536,9.80999716334,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121730250000,12646,121730250000,RH_EXTIMU,2.31848090505e-06,1.52904972664e-05,-0.70338749326,0.710806608077,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.48026225221e-09,7.05938934162e-09,-7.10644462703e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244658747787,-0.000178606006066,9.80999191368,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121732750000,12647,121732750000,RH_EXTIMU,2.31856649419e-06,1.5290458041e-05,-0.703387556401,0.710806545595,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.16306321793e-08,2.65037240357e-08,-7.10637896877e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245003748241,-0.000179923515229,9.80999512805,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121735250000,12648,121735250000,RH_EXTIMU,2.3187975268e-06,1.52903077291e-05,-0.703387619541,0.710806483114,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.16845853645e-07,4.51774022781e-08,-7.10630350394e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244160995653,-0.000183129056234,9.81002094185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121737750000,12649,121737750000,RH_EXTIMU,2.31859223185e-06,1.52904340871e-05,-0.70338768268,0.710806420634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.86954653818e-07,-4.3021536271e-08,-7.10620601029e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246609110702,-0.0001743073706,9.81001567407,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121740250000,12650,121740250000,RH_EXTIMU,2.31856137758e-06,1.52905455286e-05,-0.703387745819,0.710806358154,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.93661665945e-08,4.66558119345e-08,-7.10613767429e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243798693846,-0.000178096803309,9.81000620109,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121742750000,12651,121742750000,RH_EXTIMU,2.31850672801e-06,1.52905776556e-05,-0.703387808957,0.710806295675,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.82661653195e-08,-1.183586309e-08,-7.10607240914e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246383938911,-0.000177604759924,9.80998517799,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121745250000,12652,121745250000,RH_EXTIMU,2.31862106345e-06,1.52903862516e-05,-0.703387872095,0.710806233197,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.7360948057e-07,-4.38560467133e-08,-7.10601538388e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245200516581,-0.000182269401622,9.809990125,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121747750000,12653,121747750000,RH_EXTIMU,2.31887226092e-06,1.52902913034e-05,-0.703387935231,0.710806170719,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.97158718216e-07,8.80067084032e-08,-7.1059423316e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024360595247,-0.00018221843443,9.81001683062,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121750250000,12654,121750250000,RH_EXTIMU,2.31871407744e-06,1.52904202835e-05,-0.703387998367,0.710806108242,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.61640473149e-07,-1.50204962282e-08,-7.1058472369e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246072531388,-0.000174976278755,9.81001619426,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121752750000,12655,121752750000,RH_EXTIMU,2.31856524662e-06,1.52905276983e-05,-0.703388061503,0.710806045765,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.4418711909e-07,-2.2020660834e-08,-7.10577183331e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024559344712,-0.000176593251038,9.81000358633,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121755250000,12656,121755250000,RH_EXTIMU,2.31867194052e-06,1.52904506222e-05,-0.703388124638,0.710805983289,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04930588562e-07,1.68560238676e-08,-7.10570598973e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244549095586,-0.000181221554362,9.81000346019,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121757750000,12657,121757750000,RH_EXTIMU,2.31863248333e-06,1.52904070724e-05,-0.703388187772,0.710805920814,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.95697320139e-09,-4.63202387084e-08,-7.1056262325e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246390133041,-0.000178346552426,9.81000436515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121760250000,12658,121760250000,RH_EXTIMU,2.31863211768e-06,1.52904348382e-05,-0.703388250905,0.710805858339,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.49438747347e-08,1.62302172282e-08,-7.10556022409e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244629143498,-0.000178542953714,9.80999767329,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121762750000,12659,121762750000,RH_EXTIMU,2.31869754033e-06,1.52903949345e-05,-0.703388314038,0.710805795865,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.0544651841e-08,1.47700635008e-08,-7.10549294332e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024519866827,-0.000179855019976,9.80999663919,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121765250000,12660,121765250000,RH_EXTIMU,2.31886432229e-06,1.52902787109e-05,-0.70338837717,0.710805733392,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.61128068281e-07,2.84071394496e-08,-7.10542216287e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244434945885,-0.000181856081417,9.81001023069,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121767750000,12661,121767750000,RH_EXTIMU,2.31871313528e-06,1.52903940392e-05,-0.703388440301,0.710805670919,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.49980037271e-07,-1.8846639668e-08,-7.10534066854e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246153319389,-0.000175095197814,9.8099985253,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121770250000,12662,121770250000,RH_EXTIMU,2.31873167639e-06,1.52903849051e-05,-0.703388503432,0.710805608447,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.65713022112e-08,5.8862743388e-09,-7.10528055501e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244774588764,-0.000179595344169,9.80999447933,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121772750000,12663,121772750000,RH_EXTIMU,2.31879499783e-06,1.52903399401e-05,-0.703388566563,0.710805545976,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.21977958966e-08,1.07096209544e-08,-7.10520881601e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245121837421,-0.000179746504936,9.81000171916,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121775250000,12664,121775250000,RH_EXTIMU,2.31869666078e-06,1.52902697718e-05,-0.703388629692,0.710805483505,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.55462500421e-08,-9.45890808913e-08,-7.10514399281e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246884907142,-0.00017835538123,9.80998114762,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121777750000,12665,121777750000,RH_EXTIMU,2.31886078487e-06,1.52901528168e-05,-0.703388692821,0.710805421034,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.60028181452e-07,2.64956571332e-08,-7.10506849197e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244585193936,-0.000181311600379,9.8100163274,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121780250000,12666,121780250000,RH_EXTIMU,2.31878287353e-06,1.52902212712e-05,-0.70338875595,0.710805358565,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.19358464274e-08,-4.26828782885e-09,-7.10498759051e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245263962822,-0.000177189874876,9.8100079543,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121782750000,12667,121782750000,RH_EXTIMU,2.31877542742e-06,1.52902570866e-05,-0.703388819077,0.710805296096,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.34998186409e-08,1.68232221378e-08,-7.10491656458e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244970706132,-0.000178472156626,9.81000245645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121785250000,12668,121785250000,RH_EXTIMU,2.31878976156e-06,1.5290256031e-05,-0.703388882204,0.710805233628,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.63310914983e-09,8.11272601525e-09,-7.10484129691e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245184804778,-0.000178894954784,9.81000674431,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121787750000,12669,121787750000,RH_EXTIMU,2.31884701119e-06,1.52903173335e-05,-0.703388945331,0.71080517116,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.05291054474e-09,6.77213648478e-08,-7.10477241949e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243968751514,-0.000178777507193,9.8100032665,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121790250000,12670,121790250000,RH_EXTIMU,2.31889491544e-06,1.52903362884e-05,-0.703389008456,0.710805108693,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.74623940547e-08,3.83818528328e-08,-7.10470268492e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024484433596,-0.000179071687248,9.8099999146,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121797750000,12671,121792750000,RH_EXTIMU,2.3189075947e-06,1.52902499573e-05,-0.703389071581,0.710805046226,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.66775062903e-08,-4.13099079573e-08,-7.10462767945e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246156747452,-0.000179731457741,9.81000256983,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121797750000,12672,121795250000,RH_EXTIMU,2.31873607438e-06,1.52902167143e-05,-0.703389134706,0.71080498376,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.79397454904e-08,-1.14772868937e-07,-7.10456055655e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246946029223,-0.000177162558987,9.80998441128,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121797750000,12673,121797750000,RH_EXTIMU,2.31893386434e-06,1.52900666778e-05,-0.70338919783,0.710804921295,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.97787324757e-07,2.66282802669e-08,-7.10449951335e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244455173733,-0.000182435662124,9.81000056946,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121800250000,12674,121800250000,RH_EXTIMU,2.31891137071e-06,1.52900706887e-05,-0.703389260953,0.71080485883,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.41598591596e-08,-9.72965242224e-09,-7.10441935158e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245538202202,-0.00017792639991,9.81000509976,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121802750000,12675,121802750000,RH_EXTIMU,2.3189297855e-06,1.52901111688e-05,-0.703389324076,0.710804796366,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.14191163264e-08,3.40278846294e-08,-7.10434702991e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244402619849,-0.000178670479582,9.81000643006,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121805250000,12676,121805250000,RH_EXTIMU,2.31911213788e-06,1.52901251606e-05,-0.703389387197,0.710804733903,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.67081647774e-08,1.11215127297e-07,-7.1042728925e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243299642751,-0.000180911994149,9.81001811032,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121807750000,12677,121807750000,RH_EXTIMU,2.31886815795e-06,1.52902484314e-05,-0.703389450319,0.71080467144,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.07215548547e-07,-6.6546232672e-08,-7.10418801634e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247551987412,-0.000174020724144,9.80999543957,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121810250000,12678,121810250000,RH_EXTIMU,2.31891683775e-06,1.52901217081e-05,-0.703389513439,0.710804608978,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.98780884308e-08,-4.40207535691e-08,-7.10412757906e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245061582798,-0.000181592459235,9.80999880795,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121812750000,12679,121812750000,RH_EXTIMU,2.31894827993e-06,1.52900914981e-05,-0.703389576559,0.710804546517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.57668826036e-08,1.16109122369e-09,-7.10405228438e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245239983728,-0.000178831885042,9.81000260871,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121815250000,12680,121815250000,RH_EXTIMU,2.3189057915e-06,1.52900804049e-05,-0.703389639678,0.710804484056,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.70305331773e-08,-2.95699075505e-08,-7.10397575189e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245846989488,-0.000178379538663,9.81000481777,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121817750000,12681,121817750000,RH_EXTIMU,2.31891748874e-06,1.52900793692e-05,-0.703389702797,0.710804421596,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.12228146859e-09,6.64018544928e-09,-7.10391192341e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244897000597,-0.000179003687357,9.80999317859,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121820250000,12682,121820250000,RH_EXTIMU,2.319137211e-06,1.52900055194e-05,-0.703389765915,0.710804359136,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.67387735988e-07,8.22929937454e-08,-7.10384770547e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243594941958,-0.000181984795864,9.81000414629,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121822750000,12683,121822750000,RH_EXTIMU,2.31911564824e-06,1.52900254194e-05,-0.703389829032,0.710804296677,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.25715285489e-08,-1.70737399319e-10,-7.10377136336e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246062087856,-0.000177582418987,9.8099989695,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121825250000,12684,121825250000,RH_EXTIMU,2.31907800045e-06,1.52899991994e-05,-0.703389892149,0.710804234219,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.76596617521e-09,-3.54477765167e-08,-7.10370263757e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245481629966,-0.000178808150334,9.80999583428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121827750000,12685,121827750000,RH_EXTIMU,2.31913390865e-06,1.52899632715e-05,-0.703389955265,0.710804171761,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.28967836833e-08,1.16769567275e-08,-7.1036397338e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245024208477,-0.000179545912843,9.80999286381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121830250000,12686,121830250000,RH_EXTIMU,2.31930723415e-06,1.52898785937e-05,-0.703390018381,0.710804109304,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.4709753648e-07,5.00277104307e-08,-7.10356780418e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244158162114,-0.000181643748248,9.81001295217,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121832750000,12687,121832750000,RH_EXTIMU,2.3191310371e-06,1.5289945084e-05,-0.703390081496,0.710804046847,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.367202965e-07,-6.06920462868e-08,-7.10348305253e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246694275141,-0.000175661095671,9.810000483,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121835250000,12688,121835250000,RH_EXTIMU,2.31915349183e-06,1.52899695022e-05,-0.70339014461,0.710803984391,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.37662526697e-11,2.71676169483e-08,-7.10341417248e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244500071136,-0.000178933911224,9.81000530509,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121837750000,12689,121837750000,RH_EXTIMU,2.3191369834e-06,1.52899574096e-05,-0.703390207724,0.710803921936,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.69490358368e-09,-1.55189759382e-08,-7.10334211616e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245656030323,-0.000178731204599,9.80999846143,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121840250000,12690,121840250000,RH_EXTIMU,2.31904909244e-06,1.52899580744e-05,-0.703390270836,0.710803859481,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.94647882232e-08,-4.84324656551e-08,-7.10327480557e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246157375617,-0.000177436263123,9.80998762735,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121842750000,12691,121842750000,RH_EXTIMU,2.31919039668e-06,1.52898392134e-05,-0.703390333949,0.710803797027,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.48124044901e-07,1.25710200067e-08,-7.10321553232e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244611436361,-0.000181851163075,9.80999670871,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121845250000,12692,121845250000,RH_EXTIMU,2.31925446803e-06,1.52898009417e-05,-0.703390397061,0.710803734574,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.88575540194e-08,1.49375993964e-08,-7.10313230247e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245179375726,-0.000179210471158,9.8100137094,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121847750000,12693,121847750000,RH_EXTIMU,2.31924720244e-06,1.52898089907e-05,-0.703390460172,0.710803672121,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.77295829748e-09,1.13538199315e-09,-7.10305554027e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245219868843,-0.000178740024421,9.81000801036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121850250000,12694,121850250000,RH_EXTIMU,2.31934330459e-06,1.52898988587e-05,-0.703390523282,0.710803609669,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.96576174599e-09,1.05827525244e-07,-7.10296993157e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243399917326,-0.000178741793637,9.81003053282,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121852750000,12695,121852750000,RH_EXTIMU,2.31898760342e-06,1.52900239121e-05,-0.703390586391,0.710803547217,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.71748203323e-07,-1.28399952374e-07,-7.10290378089e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247650225985,-0.000174173278482,9.80997151698,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121855250000,12696,121855250000,RH_EXTIMU,2.31929160336e-06,1.52898133605e-05,-0.7033906495,0.710803484766,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.92235218728e-07,5.19827201526e-08,-7.10284994562e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243730734224,-0.000184450948622,9.80999952661,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121857750000,12697,121857750000,RH_EXTIMU,2.31919222706e-06,1.52897574741e-05,-0.703390712609,0.710803422316,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.41738453598e-08,-8.70528929801e-08,-7.10277544382e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247240596577,-0.000177407472603,9.80998721066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121860250000,12698,121860250000,RH_EXTIMU,2.31941468625e-06,1.52896940313e-05,-0.703390775717,0.710803359866,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.63087676413e-07,8.97510539348e-08,-7.10270398471e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243391784023,-0.000181619057908,9.81001777732,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121862750000,12699,121862750000,RH_EXTIMU,2.31931383674e-06,1.52897864771e-05,-0.703390838824,0.710803297417,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.08479987575e-07,-3.53387732362e-09,-7.10262815934e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245505677437,-0.00017663508675,9.80999874255,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121865250000,12700,121865250000,RH_EXTIMU,2.31924113838e-06,1.52897708712e-05,-0.703390901931,0.710803234969,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.16699599298e-08,-4.91357080052e-08,-7.10257089715e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246031057822,-0.000178315855682,9.80997776448,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121865250000,12701,121867750000,RH_EXTIMU,2.31952146354e-06,1.52895596709e-05,-0.703390965037,0.710803172521,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.79137719686e-07,3.82917814585e-08,-7.1025041313e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244290136119,-0.000183998298227,9.81001127721,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121870250000,12702,121870250000,RH_EXTIMU,2.31936867155e-06,1.52896717524e-05,-0.703391028142,0.710803110074,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.49066008244e-07,-2.15969132334e-08,-7.10241028462e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245921901879,-0.000174870703027,9.81001344442,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121872750000,12703,121872750000,RH_EXTIMU,2.31930032541e-06,1.52898352214e-05,-0.703391091246,0.710803047627,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.29962844483e-07,5.51428781833e-08,-7.10233879009e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244164488125,-0.000176885651886,9.81000657211,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121875250000,12704,121875250000,RH_EXTIMU,2.31931002438e-06,1.52898570806e-05,-0.70339115435,0.710802985181,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.89745110222e-09,1.85345435581e-08,-7.10226721891e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245158065239,-0.000178844805301,9.81000131,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121877750000,12705,121877750000,RH_EXTIMU,2.31933029928e-06,1.52898245492e-05,-0.703391217454,0.710802922736,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.07226995636e-08,-6.44301147972e-09,-7.10219705174e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245381378757,-0.000179277152527,9.80999953523,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121880250000,12706,121880250000,RH_EXTIMU,2.31942479422e-06,1.52897210357e-05,-0.703391280556,0.710802860291,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12869972185e-07,-5.04192401959e-09,-7.1021404418e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024524483744,-0.000180905102805,9.8099842802,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121885250000,12707,121882750000,RH_EXTIMU,2.31947845306e-06,1.52896072404e-05,-0.703391343659,0.710802797847,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.5434484518e-08,-3.38675555333e-08,-7.10207513378e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245842391664,-0.000179960567018,9.80999134577,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121885250000,12708,121885250000,RH_EXTIMU,2.31948753803e-06,1.52895068699e-05,-0.70339140676,0.710802735403,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.25336261078e-08,-5.13160038525e-08,-7.1019956964e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246126720498,-0.000179542961579,9.81000718586,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121887750000,12709,121887750000,RH_EXTIMU,2.31950101904e-06,1.52895989957e-05,-0.703391469861,0.710802672961,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.32868437175e-08,6.06192527269e-08,-7.10192697709e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243782294727,-0.00017786180667,9.8100030521,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121890250000,12710,121890250000,RH_EXTIMU,2.31953639053e-06,1.52896123604e-05,-0.703391532961,0.710802610518,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34808907462e-08,2.81504429117e-08,-7.10185388523e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245186245484,-0.000179092221567,9.81000359168,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121892750000,12711,121892750000,RH_EXTIMU,2.3194873017e-06,1.5289565326e-05,-0.703391596061,0.710802548077,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.59422761427e-10,-5.37219883555e-08,-7.1017769372e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246172521422,-0.000178612122654,9.810002505,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121895250000,12712,121895250000,RH_EXTIMU,2.31948054575e-06,1.52895368525e-05,-0.703391659159,0.710802485636,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.30684204363e-08,-1.93462673436e-08,-7.1017101248e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245329650283,-0.000178995664586,9.809995711,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121897750000,12713,121897750000,RH_EXTIMU,2.31953415087e-06,1.52895345924e-05,-0.703391722258,0.710802423195,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.26415206172e-08,2.95258356636e-08,-7.10163153558e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244866229578,-0.000178960460101,9.81001148398,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121900250000,12714,121900250000,RH_EXTIMU,2.31950654078e-06,1.52895509254e-05,-0.703391785355,0.710802360755,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.40033930239e-08,-5.60229215619e-09,-7.10156125762e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245225375857,-0.00017855622182,9.80999983689,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121902750000,12715,121902750000,RH_EXTIMU,2.31942060475e-06,1.52894916178e-05,-0.703391848452,0.710802298316,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.46059910238e-08,-8.14355031779e-08,-7.10148995055e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246691486899,-0.000178392573407,9.8099929584,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121905250000,12716,121905250000,RH_EXTIMU,2.3195684758e-06,1.52894127952e-05,-0.703391911549,0.710802235878,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.29327851861e-07,3.90338254516e-08,-7.10142399396e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243912743835,-0.000181262550546,9.81000443017,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121907750000,12717,121907750000,RH_EXTIMU,2.31953670436e-06,1.52894555141e-05,-0.703391974644,0.71080217344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.12174687707e-08,7.06018123001e-09,-7.10135144797e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245921843226,-0.000177264404084,9.80999533562,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121910250000,12718,121910250000,RH_EXTIMU,2.31961064791e-06,1.52893836189e-05,-0.703392037739,0.710802111003,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.33914383241e-08,1.37302733296e-09,-7.1012889841e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244839520947,-0.000180587595555,9.80999434799,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121912750000,12719,121912750000,RH_EXTIMU,2.31970951065e-06,1.52893377282e-05,-0.703392100834,0.710802048566,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.29283668257e-08,3.01826880342e-08,-7.10121634914e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244769082121,-0.000179906666475,9.81000579741,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121915250000,12720,121915250000,RH_EXTIMU,2.31960262558e-06,1.52894376333e-05,-0.703392163928,0.71080198613,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.16109641956e-07,-2.68891678104e-09,-7.10114854628e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245224474733,-0.000176426560331,9.80999033401,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121917750000,12721,121917750000,RH_EXTIMU,2.31973398504e-06,1.52893415795e-05,-0.703392227021,0.710801923694,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.29634780104e-07,1.99442319874e-08,-7.10106997387e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245169881133,-0.000181123936306,9.81001506666,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121920250000,12722,121920250000,RH_EXTIMU,2.31953929457e-06,1.52893475874e-05,-0.703392290114,0.710801861259,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.13202179631e-07,-1.05492134308e-07,-7.10099578989e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246928141572,-0.000176557912353,9.80999176408,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121922750000,12723,121922750000,RH_EXTIMU,2.31962973083e-06,1.52893175438e-05,-0.703392353205,0.710801798825,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.92192684997e-08,3.44523310667e-08,-7.10093369041e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244309183308,-0.000179987596063,9.80999617612,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121925250000,12724,121925250000,RH_EXTIMU,2.31988229247e-06,1.52892217007e-05,-0.703392416297,0.710801736391,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.9843686407e-07,8.82661079337e-08,-7.10086761451e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243539239139,-0.000182674437725,9.81000979523,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121927750000,12725,121927750000,RH_EXTIMU,2.31972945514e-06,1.52893295215e-05,-0.703392479387,0.710801673958,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.46694365718e-07,-2.40457440932e-08,-7.10078024928e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246484805184,-0.000174960710298,9.81000449183,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121932750000,12726,121930250000,RH_EXTIMU,2.31964955963e-06,1.52893792757e-05,-0.703392542477,0.710801611526,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.25417364856e-08,-1.601947273e-08,-7.10071044146e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245117043424,-0.000177953973956,9.81000134663,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121932750000,12727,121932750000,RH_EXTIMU,2.31965927428e-06,1.52893135163e-05,-0.703392605567,0.710801549094,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.34154043357e-08,-3.12803552036e-08,-7.10064575128e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245780389436,-0.000179641807651,9.80999007032,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121935250000,12728,121935250000,RH_EXTIMU,2.31982780303e-06,1.52892181226e-05,-0.703392668655,0.710801486663,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.50399319972e-07,4.12352314278e-08,-7.10057420712e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244453074992,-0.000181221684927,9.81000966645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121937750000,12729,121937750000,RH_EXTIMU,2.3198384015e-06,1.52892940881e-05,-0.703392731744,0.710801424233,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.58326303289e-08,4.98075638678e-08,-7.10051245816e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244292167935,-0.000177979354155,9.80998851093,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121941500000,12730,121940250000,RH_EXTIMU,2.31994648972e-06,1.52892053752e-05,-0.703392794831,0.710801361803,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12270944266e-07,1.10234818849e-08,-7.10042304961e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024557565247,-0.000180490463788,9.81002671347,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121941500000,12731,121942750000,RH_EXTIMU,2.31970018677e-06,1.52893250367e-05,-0.703392857918,0.710801299374,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.06505712187e-07,-6.99072159466e-08,-7.10035221262e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246348136636,-0.000175034673428,9.80998783895,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121945250000,12732,121945250000,RH_EXTIMU,2.31970696924e-06,1.5289270916e-05,-0.703392921004,0.710801236945,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.51987492027e-08,-2.63121206258e-08,-7.1002952218e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245294148708,-0.000179338232213,9.80998138196,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121947750000,12733,121947750000,RH_EXTIMU,2.31994115114e-06,1.52891456936e-05,-0.70339298409,0.710801174517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.04517353006e-07,6.12174380915e-08,-7.10024480593e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244162839177,-0.000182487137946,9.80998710372,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121950250000,12734,121950250000,RH_EXTIMU,2.32004674618e-06,1.52889907072e-05,-0.703393047175,0.710801112089,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.48146261722e-07,-2.80653266802e-08,-7.10014656324e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246173328537,-0.000180694229381,9.81003146677,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121952750000,12735,121952750000,RH_EXTIMU,2.31967730437e-06,1.52891729225e-05,-0.703393110259,0.710801049662,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.11727482202e-07,-1.03628657296e-07,-7.10007434053e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246477080044,-0.000173110294329,9.80998588096,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121955250000,12736,121955250000,RH_EXTIMU,2.31998222471e-06,1.52891056225e-05,-0.703393173343,0.710800987236,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.12148295926e-07,1.33960047943e-07,-7.10001572759e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242283810265,-0.000183355552575,9.81000902244,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121957750000,12737,121957750000,RH_EXTIMU,2.31992699345e-06,1.52891078037e-05,-0.703393236426,0.71080092481,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.17466939268e-08,-2.91926510215e-08,-7.09993831297e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246742620249,-0.000177398386568,9.80999425477,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121962750000,12738,121960250000,RH_EXTIMU,2.31998834811e-06,1.52890467589e-05,-0.703393299508,0.710800862385,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.01269797691e-08,4.5908019407e-10,-7.09986382619e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245091552122,-0.000179965696432,9.81001076487,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121962750000,12739,121962750000,RH_EXTIMU,2.31983053529e-06,1.52891071695e-05,-0.70339336259,0.710800799961,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.22845268197e-07,-5.38052439665e-08,-7.09978896895e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246310925608,-0.000176118264956,9.80999437977,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121965250000,12740,121965250000,RH_EXTIMU,2.31985864771e-06,1.52890558731e-05,-0.703393425671,0.710800737537,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.57385135022e-08,-1.27034861132e-08,-7.09972679158e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245058152557,-0.00017994345542,9.80999411334,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121967750000,12741,121967750000,RH_EXTIMU,2.31991174363e-06,1.52889686653e-05,-0.703393488751,0.710800675114,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.01530051768e-08,-1.90655907593e-08,-7.09965519052e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245611458931,-0.00017995201589,9.80999944878,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121970250000,12742,121970250000,RH_EXTIMU,2.31995862526e-06,1.52889719946e-05,-0.703393551831,0.710800612692,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.56727755535e-08,2.89205616253e-08,-7.09959518213e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024448968809,-0.000179067829726,9.8099889151,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121972750000,12743,121972750000,RH_EXTIMU,2.3201187133e-06,1.52889232506e-05,-0.703393614911,0.71080055027,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.19348857178e-07,6.30125623473e-08,-7.09951555038e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244451999967,-0.00018057917496,9.81001845767,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121975250000,12744,121975250000,RH_EXTIMU,2.32000989168e-06,1.52890045132e-05,-0.703393677989,0.710800487849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.06720619705e-07,-1.43799839806e-08,-7.09943364975e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024557065154,-0.00017674170948,9.81000797102,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121977750000,12745,121977750000,RH_EXTIMU,2.31986584278e-06,1.52890642108e-05,-0.703393741067,0.710800425428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.14617426364e-07,-4.64655547386e-08,-7.09936418165e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246208402123,-0.000176524237847,9.80998970266,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121980250000,12746,121980250000,RH_EXTIMU,2.31996172768e-06,1.52889450604e-05,-0.703393804144,0.710800363008,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22459104796e-07,-1.31514513969e-08,-7.09930861776e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024505023021,-0.000181350082954,9.80998857924,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121982750000,12747,121982750000,RH_EXTIMU,2.3203053042e-06,1.52888386102e-05,-0.703393867221,0.710800300588,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.56159943803e-07,1.33450191742e-07,-7.09923695391e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242968304954,-0.000183068251344,9.81001769385,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121985250000,12748,121985250000,RH_EXTIMU,2.32026465083e-06,1.52889115574e-05,-0.703393930297,0.71080023817,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.32783067754e-08,1.92508347638e-08,-7.0991573428e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245242667104,-0.000177318254737,9.81000571645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121987750000,12749,121987750000,RH_EXTIMU,2.32024721037e-06,1.52889373589e-05,-0.703393993373,0.710800175751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.35488771058e-08,5.50409996742e-09,-7.09908524519e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245190514969,-0.000178412301072,9.81000242,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121990250000,12750,121990250000,RH_EXTIMU,2.3202752221e-06,1.52889123755e-05,-0.703394056447,0.710800113334,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.08744732856e-08,2.20242507758e-09,-7.09901195627e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245247839125,-0.000179294458356,9.81000417289,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121992750000,12751,121992750000,RH_EXTIMU,2.32026616752e-06,1.52888976284e-05,-0.703394119521,0.710800050917,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.03696130183e-09,-1.28346130739e-08,-7.09893965518e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245424101961,-0.000178737325395,9.81000115254,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121995250000,12752,121995250000,RH_EXTIMU,2.32027595048e-06,1.52888788525e-05,-0.703394182595,0.710799988501,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.70157601827e-08,-4.52533743266e-09,-7.09886906072e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245268218971,-0.000178981482188,9.81000029921,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +121997750000,12753,121997750000,RH_EXTIMU,2.32029160355e-06,1.52888568927e-05,-0.703394245668,0.710799926085,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.21454030447e-08,-3.03268417098e-09,-7.09879837028e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245273608962,-0.000179040000512,9.81000005453,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122000250000,12754,122000250000,RH_EXTIMU,2.32030646067e-06,1.52888351941e-05,-0.70339430874,0.71079986367,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.15457668284e-08,-3.33201197972e-09,-7.09872752851e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245280450574,-0.000179016207334,9.8100001112,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122002750000,12755,122002750000,RH_EXTIMU,2.32031982028e-06,1.52888150487e-05,-0.703394371811,0.710799801255,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.98202621821e-08,-3.2915366079e-09,-7.09865659576e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245278753825,-0.000178984661905,9.81000020981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122007750000,12756,122005250000,RH_EXTIMU,2.32033220152e-06,1.52887960371e-05,-0.703394434882,0.710799738842,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.8625823884e-08,-3.1972812268e-09,-7.09858559202e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024527741438,-0.000178965612734,9.81000027075,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122007750000,12757,122007750000,RH_EXTIMU,2.32012531981e-06,1.52887913014e-05,-0.703394497953,0.710799676428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.14089025931e-07,-1.18462182055e-07,-7.09850987612e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247294504513,-0.000176384545507,9.8099923155,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122007750000,12758,122010250000,RH_EXTIMU,2.32017519727e-06,1.52887437855e-05,-0.703394561022,0.710799614016,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.59874922403e-08,1.69370890739e-09,-7.09844680084e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244778128975,-0.000179829170738,9.80999564671,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122012750000,12759,122012750000,RH_EXTIMU,2.3202415197e-06,1.52887014013e-05,-0.703394624091,0.710799551604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.24510521822e-08,1.3865634882e-08,-7.09837871545e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245049139075,-0.000179640876367,9.80999780279,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122015250000,12760,122015250000,RH_EXTIMU,2.32013088046e-06,1.52886996739e-05,-0.70339468716,0.710799489192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.10545547066e-08,-6.25944522817e-08,-7.09830981226e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246671360424,-0.000177067287049,9.80998448045,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122017750000,12761,122017750000,RH_EXTIMU,2.32031360294e-06,1.52885399677e-05,-0.703394750228,0.710799426782,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.94659624979e-07,1.26518528719e-08,-7.09823890446e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244577766864,-0.000182480302781,9.8100140709,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122020250000,12762,122020250000,RH_EXTIMU,2.32026178844e-06,1.52885819064e-05,-0.703394813295,0.710799364372,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.21761378416e-08,-4.66257106788e-09,-7.09815836658e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245196002236,-0.000177548938806,9.81000813918,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122022750000,12763,122022750000,RH_EXTIMU,2.31991514634e-06,1.52887351567e-05,-0.703394876361,0.710799301962,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.82463542641e-07,-1.072705802e-07,-7.09809163988e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247792108139,-0.000172733848103,9.80996718627,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122025250000,12764,122025250000,RH_EXTIMU,2.32033193963e-06,1.52883760407e-05,-0.703394939427,0.710799239553,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.39972571376e-07,3.09749712563e-08,-7.098060286e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243303167702,-0.000188361454021,9.80998496324,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122029000000,12765,122027750000,RH_EXTIMU,2.32054428509e-06,1.52882258802e-05,-0.703395002493,0.710799177144,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.06132880218e-07,3.47492348202e-08,-7.09797437038e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245020463159,-0.000181128137785,9.81001631552,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122030250000,12766,122030250000,RH_EXTIMU,2.32037207351e-06,1.52883766541e-05,-0.703395065557,0.710799114737,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.8188198683e-07,-1.05240395525e-08,-7.09788140691e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245707227338,-0.000174832569849,9.81001832473,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122032750000,12767,122032750000,RH_EXTIMU,2.32025204167e-06,1.52885181131e-05,-0.703395128621,0.71079905233,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.46968889456e-07,1.35415048983e-08,-7.09780780198e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244771548612,-0.000176480502638,9.81000142281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122035250000,12768,122035250000,RH_EXTIMU,2.32037243414e-06,1.52884769828e-05,-0.703395191685,0.710798989923,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.24916941693e-08,4.50047293953e-08,-7.09775300622e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024467713535,-0.000180719311009,9.80998887187,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122040250000,12769,122037750000,RH_EXTIMU,2.32047819872e-06,1.52883475113e-05,-0.703395254748,0.710798927517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.33884739726e-07,-1.34609154596e-08,-7.09768512325e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245531899353,-0.000180898770161,9.80999860955,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122040250000,12770,122040250000,RH_EXTIMU,2.32042921933e-06,1.52883886792e-05,-0.70339531781,0.710798865112,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.01302714632e-08,-3.5056614186e-09,-7.09760681962e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245116059624,-0.000177294470557,9.81000385362,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122040250000,12771,122042750000,RH_EXTIMU,2.33000353267e-06,1.5285620269e-05,-0.70339538087,0.710798802708,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.0030453594e-06,3.81404166318e-06,-7.09736816575e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00016043382686,-0.000333772406287,9.81115629506,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122045250000,12772,122045250000,RH_EXTIMU,2.31530119178e-06,1.52941887954e-05,-0.703395443925,0.71079874031,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.31810871861e-05,-3.40020279074e-06,-7.09685730011e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000334697746113,8.88796122022e-05,9.80923609281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122047750000,12773,122047750000,RH_EXTIMU,2.31924725821e-06,1.52901294545e-05,-0.703395506985,0.710798677907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.52903187878e-06,-8.71366436255e-08,-7.09737943764e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000236138757043,-0.000277884361811,9.80972348144,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122050250000,12774,122050250000,RH_EXTIMU,2.32107159027e-06,1.52877492958e-05,-0.703395570046,0.710798615503,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.37762775151e-06,-3.2622303567e-07,-7.09739286499e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000250638276778,-0.000210214639607,9.80985157919,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122052750000,12775,122052750000,RH_EXTIMU,2.32138382359e-06,1.52874013636e-05,-0.703395633105,0.7107985531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.74222292256e-07,-2.15028497184e-08,-7.09731437553e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244415870879,-0.000179698392626,9.80999131893,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122055250000,12776,122055250000,RH_EXTIMU,2.32093073207e-06,1.52878862789e-05,-0.703395696164,0.710798490698,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.29628189135e-07,2.14256554434e-08,-7.09722021794e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244935626803,-0.000167983460732,9.80999954715,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122057750000,12777,122057750000,RH_EXTIMU,2.32078345861e-06,1.52880976734e-05,-0.703395759222,0.710798428297,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.01813492789e-07,3.79799940381e-08,-7.097145884e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244954086683,-0.00017547847424,9.80999899823,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122060250000,12778,122060250000,RH_EXTIMU,2.32101225121e-06,1.52880115488e-05,-0.703395822279,0.710798365896,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.79451120328e-07,8.04177630398e-08,-7.09708120425e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243470714988,-0.000182893612002,9.81001188869,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122062750000,12779,122062750000,RH_EXTIMU,2.32090475458e-06,1.52879809255e-05,-0.703395885336,0.710798303497,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.30074043709e-08,-7.72576643249e-08,-7.09699195258e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247344185771,-0.000177180353472,9.81000585463,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122062750000,12780,122065250000,RH_EXTIMU,2.320838425e-06,1.52879781967e-05,-0.703395948392,0.710798241097,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.52949760426e-08,-3.82303699745e-08,-7.09692114186e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245459998896,-0.000178182993975,9.81000232978,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122062750000,12781,122067750000,RH_EXTIMU,2.32096102325e-06,1.52879730961e-05,-0.703396011447,0.710798178698,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.34713517445e-08,6.67337610424e-08,-7.09685288799e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024371241494,-0.000180397287024,9.81001036927,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122070250000,12782,122070250000,RH_EXTIMU,2.3208653402e-06,1.52880876627e-05,-0.703396074502,0.710798116301,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.17990580239e-07,1.19506000429e-08,-7.09676186553e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245586792788,-0.000175985620165,9.8100145336,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122072750000,12783,122072750000,RH_EXTIMU,2.32083910188e-06,1.5288168252e-05,-0.703396137556,0.710798053903,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.93820314164e-08,3.17074997947e-08,-7.0966990731e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244530821059,-0.000178078007032,9.80999400569,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122075250000,12784,122075250000,RH_EXTIMU,2.32093392845e-06,1.52881011917e-05,-0.703396200609,0.710797991506,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.25450138352e-08,1.58735348554e-08,-7.09663318879e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0002451687161,-0.000180343507432,9.80999725461,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122077750000,12785,122077750000,RH_EXTIMU,2.32086179723e-06,1.52881077952e-05,-0.703396263662,0.71079792911,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.3845473703e-08,-3.61883828795e-08,-7.09656535858e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245809862647,-0.000177572107309,9.80998994632,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122080250000,12786,122080250000,RH_EXTIMU,2.32107982358e-06,1.52880272242e-05,-0.703396326714,0.710797866714,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.70203841683e-07,7.75174224096e-08,-7.09650140654e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243847356146,-0.000181848439923,9.81000269784,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122082750000,12787,122082750000,RH_EXTIMU,2.32093303917e-06,1.528802241e-05,-0.703396389766,0.71079780432,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.98712242637e-08,-8.46895650948e-08,-7.0964235995e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247231289997,-0.000176526091797,9.80999261881,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122085250000,12788,122085250000,RH_EXTIMU,2.32095754298e-06,1.52879378898e-05,-0.703396452817,0.710797741925,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.23817913831e-08,-3.36267033655e-08,-7.09636164576e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245151599855,-0.000180201114299,9.80999601545,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122087750000,12789,122087750000,RH_EXTIMU,2.32110948878e-06,1.52878845348e-05,-0.703396515867,0.710797679531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17312912555e-07,5.58088753618e-08,-7.09628421046e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243994517131,-0.000180901142499,9.81001739092,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122090250000,12790,122090250000,RH_EXTIMU,2.32104956107e-06,1.52880057091e-05,-0.703396578917,0.710797617138,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0137708139e-07,3.58279909304e-08,-7.09619846312e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244999964558,-0.000176409349102,9.8100120254,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122092750000,12791,122092750000,RH_EXTIMU,2.3208689923e-06,1.52880626139e-05,-0.703396641965,0.710797554746,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.33812610167e-07,-6.86049321298e-08,-7.09612752657e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246562285754,-0.000176449152451,9.80999382472,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122096500000,12792,122095250000,RH_EXTIMU,2.32099971996e-06,1.52880378289e-05,-0.703396705014,0.710797492354,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.91706032717e-08,6.01150615024e-08,-7.09606189364e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243962178191,-0.000180441751577,9.81000359357,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122097750000,12793,122097750000,RH_EXTIMU,2.32088924591e-06,1.52879435416e-05,-0.703396768061,0.710797429963,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.87570555753e-09,-1.15134993222e-07,-7.09599902483e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024743461185,-0.000178464096227,9.80997620644,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122100250000,12794,122100250000,RH_EXTIMU,2.32116311809e-06,1.52877490753e-05,-0.703396831109,0.710797367572,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.66050637111e-07,4.41777132495e-08,-7.095937648e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243741785327,-0.000183576286545,9.81000733264,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122102750000,12795,122102750000,RH_EXTIMU,2.32106409821e-06,1.52878614678e-05,-0.703396894155,0.710797305182,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.18664748912e-07,8.83637626751e-09,-7.09585077508e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245787872621,-0.000175497556726,9.81000586867,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122105250000,12796,122105250000,RH_EXTIMU,2.3210040807e-06,1.52878620646e-05,-0.703396957201,0.710797242793,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.35771584917e-08,-3.27875468945e-08,-7.09578198214e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245667630878,-0.00017849403861,9.80999845051,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122107750000,12797,122107750000,RH_EXTIMU,2.32109777052e-06,1.52877856856e-05,-0.703397020246,0.710797180404,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.71422825844e-08,9.93489529903e-09,-7.09571277735e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244731902984,-0.000180672330652,9.81000353572,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122110250000,12798,122110250000,RH_EXTIMU,2.32113506615e-06,1.52878437845e-05,-0.70339708329,0.710797118016,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.05986366147e-08,5.46700472375e-08,-7.09564218904e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244330766162,-0.000177982200104,9.8100020627,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122112750000,12799,122112750000,RH_EXTIMU,2.32114244335e-06,1.52879508632e-05,-0.703397146334,0.710797055628,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.51732534024e-08,6.56862347182e-08,-7.09557492024e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244480650298,-0.000177730266604,9.80999394029,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122115250000,12800,122115250000,RH_EXTIMU,2.32129002705e-06,1.52878922843e-05,-0.703397209378,0.710796993241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17771934e-07,5.03837397452e-08,-7.09550741849e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244465714726,-0.00018087124438,9.81000532107,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122117750000,12801,122117750000,RH_EXTIMU,2.32116524385e-06,1.52878565586e-05,-0.70339727242,0.710796930855,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.9966083282e-08,-8.98867387231e-08,-7.0954321075e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246975642777,-0.000177577468511,9.80999298294,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122120250000,12802,122120250000,RH_EXTIMU,2.3211720668e-06,1.52877440686e-05,-0.703397335462,0.710796868469,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.80668217645e-08,-5.94807439238e-08,-7.09536120262e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246068669803,-0.000179938671806,9.81000167721,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122122750000,12803,122122750000,RH_EXTIMU,2.32119004551e-06,1.52876635011e-05,-0.703397398504,0.710796806084,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.64469783219e-08,-3.5050835806e-08,-7.0952836648e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245384170667,-0.000179707290447,9.81000879052,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122125250000,12804,122125250000,RH_EXTIMU,2.32124375384e-06,1.52877013767e-05,-0.703397461544,0.7107967437,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.01141489586e-08,5.24060133831e-08,-7.09521611223e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244320945219,-0.000178698364146,9.8100005371,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122127750000,12805,122127750000,RH_EXTIMU,2.32132283358e-06,1.52877652639e-05,-0.703397524584,0.710796681316,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.90401863676e-09,8.14741847293e-08,-7.09513460903e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244076773952,-0.000178684837735,9.81001989011,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122130250000,12806,122130250000,RH_EXTIMU,2.32108201346e-06,1.52878864222e-05,-0.703397587624,0.710796618933,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.04230414187e-07,-6.59728253624e-08,-7.0950541551e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246945969047,-0.00017480226263,9.80999617882,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122132750000,12807,122132750000,RH_EXTIMU,2.32115182522e-06,1.52877744016e-05,-0.703397650662,0.71079655655,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03620380892e-07,-2.37688244516e-08,-7.0949932439e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244856962475,-0.000181356105828,9.80999791159,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122135250000,12808,122135250000,RH_EXTIMU,2.32114309199e-06,1.52877478409e-05,-0.7033977137,0.710796494168,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.08669635689e-08,-1.93718757607e-08,-7.09492310994e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245907291403,-0.000178221997955,9.80999194934,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122137750000,12809,122137750000,RH_EXTIMU,2.32108368993e-06,1.52876832083e-05,-0.703397776738,0.710796431787,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.47853430403e-09,-6.95332461616e-08,-7.09486122662e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246109622114,-0.000178774487777,9.80998541242,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122140250000,12810,122140250000,RH_EXTIMU,2.32133664257e-06,1.52875671764e-05,-0.703397839775,0.710796369406,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.10018312756e-07,7.70068864633e-08,-7.09479450895e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243329639877,-0.000182706863034,9.8100108022,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122142750000,12811,122142750000,RH_EXTIMU,2.32122483215e-06,1.52876800951e-05,-0.703397902811,0.710796307026,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.26234182967e-07,1.93783387147e-09,-7.09471151419e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246168894448,-0.000175350728456,9.81000042333,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122145250000,12812,122145250000,RH_EXTIMU,2.32127730248e-06,1.52876268156e-05,-0.703397965847,0.710796244647,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.07046937772e-08,-1.24822538073e-10,-7.09464550747e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244715796778,-0.000180517994854,9.81000427,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122147750000,12813,122147750000,RH_EXTIMU,2.32127084674e-06,1.52876576965e-05,-0.703398028882,0.710796182268,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.0161445972e-08,1.45730916678e-08,-7.09457235088e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245171857438,-0.00017789516095,9.8099967784,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122150250000,12814,122150250000,RH_EXTIMU,2.32138142431e-06,1.5287611234e-05,-0.703398091916,0.710796119889,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.99105206626e-08,3.64496083332e-08,-7.09451330678e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024458040434,-0.000180397734181,9.80999552531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122152750000,12815,122152750000,RH_EXTIMU,2.32132116282e-06,1.52876300975e-05,-0.70339815495,0.710796057512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.39949706796e-08,-2.25379733811e-08,-7.09443751838e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245966987722,-0.000177439036869,9.80999556972,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122155250000,12816,122155250000,RH_EXTIMU,2.32143119128e-06,1.52875484255e-05,-0.703398217983,0.710795995135,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.09411320093e-07,1.61191742401e-08,-7.09437375937e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244396723362,-0.000180986939843,9.81000120848,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122157750000,12817,122157750000,RH_EXTIMU,2.32126115217e-06,1.52875123969e-05,-0.703398281015,0.710795932758,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.55298080677e-08,-1.15525544636e-07,-7.094286263e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247737202901,-0.000176741020578,9.81000437846,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122160250000,12818,122160250000,RH_EXTIMU,2.32115690903e-06,1.52875544352e-05,-0.703398344047,0.710795870382,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.2045499916e-08,-3.41092319881e-08,-7.09421996271e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245150220085,-0.000177193607482,9.80999096633,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122162750000,12819,122162750000,RH_EXTIMU,2.3214393587e-06,1.52874842997e-05,-0.703398407078,0.710795808007,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.00964509406e-07,1.19703891094e-07,-7.09417156224e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243029645332,-0.000182757827746,9.80999363729,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122165250000,12820,122165250000,RH_EXTIMU,2.32150352735e-06,1.52874756565e-05,-0.703398470109,0.710795745632,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.22390317871e-08,3.18398513208e-08,-7.09409439612e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245240771976,-0.00017876467293,9.81000190391,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122167750000,12821,122167750000,RH_EXTIMU,2.32148965566e-06,1.52874911044e-05,-0.703398533139,0.710795683258,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.56940982451e-08,1.62417635899e-09,-7.09402156791e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245242454828,-0.000178313074345,9.81000188178,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122170250000,12822,122170250000,RH_EXTIMU,2.32147543305e-06,1.52874840784e-05,-0.703398596168,0.710795620885,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.24714102355e-09,-1.13528031598e-08,-7.09394792629e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245502444917,-0.000178576216929,9.81000394249,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122172750000,12823,122172750000,RH_EXTIMU,2.32140797033e-06,1.52875024026e-05,-0.703398659197,0.710795558512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.77864847835e-08,-2.68969593716e-08,-7.09387021457e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245610901971,-0.000177734927589,9.81000457352,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122175250000,12824,122175250000,RH_EXTIMU,2.32139276985e-06,1.52875070787e-05,-0.703398722225,0.71079549614,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.03881575889e-08,-5.24888743077e-09,-7.09379907038e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245222970398,-0.000178573740612,9.81000129211,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122177750000,12825,122177750000,RH_EXTIMU,2.32134797145e-06,1.5287442225e-05,-0.703398785252,0.710795433769,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.19070255986e-08,-6.14412908691e-08,-7.09372847722e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024633300522,-0.000178891007036,9.80999451131,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122180250000,12826,122180250000,RH_EXTIMU,2.32146682473e-06,1.52873884578e-05,-0.703398848279,0.710795371398,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.87267856929e-08,3.69527431325e-08,-7.09366720137e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244277729649,-0.000180415401481,9.80999571616,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122182750000,12827,122182750000,RH_EXTIMU,2.32151935258e-06,1.52873588414e-05,-0.703398911305,0.710795309027,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.7421591656e-08,1.33632012031e-08,-7.0935919304e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245224917559,-0.000179212539685,9.81000547797,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122185250000,12828,122185250000,RH_EXTIMU,2.32141644909e-06,1.52873869206e-05,-0.703398974331,0.710795246658,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.34287112913e-08,-4.12932078609e-08,-7.09351550637e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246201526529,-0.000177008337215,9.80999772833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122187750000,12829,122187750000,RH_EXTIMU,2.32156300678e-06,1.52872774008e-05,-0.703399037356,0.710795184289,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.45853497383e-07,2.08396410262e-08,-7.09345623352e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244211567848,-0.000182021231963,9.80999946489,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122190250000,12830,122190250000,RH_EXTIMU,2.32163678838e-06,1.52872598789e-05,-0.70339910038,0.71079512192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.27014089106e-08,3.22004380671e-08,-7.09338134263e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244987762362,-0.000179031458847,9.81000467103,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122192750000,12831,122192750000,RH_EXTIMU,2.32154442451e-06,1.52873375681e-05,-0.703399163404,0.710795059552,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.53520374734e-08,-7.15235347001e-09,-7.09330756236e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245543431513,-0.000176666400528,9.80999651337,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122195250000,12832,122195250000,RH_EXTIMU,2.32161750144e-06,1.52872895653e-05,-0.703399226427,0.710794997185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.94528884236e-08,1.4471363367e-08,-7.09324734549e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244815980503,-0.000180242184988,9.80999331208,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122197750000,12833,122197750000,RH_EXTIMU,2.32155157678e-06,1.52872793918e-05,-0.703399289449,0.710794934818,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.08757724272e-08,-4.22363715836e-08,-7.09318128465e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246285617102,-0.000177422352211,9.80998315872,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122200250000,12834,122200250000,RH_EXTIMU,2.32169227112e-06,1.52871796206e-05,-0.703399352471,0.710794872452,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.37033641107e-07,2.30836106427e-08,-7.09310272173e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244555773026,-0.000181246238625,9.81002112135,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122202750000,12835,122202750000,RH_EXTIMU,2.32159916266e-06,1.52872172966e-05,-0.703399415492,0.710794810087,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.32592334308e-08,-3.03243942902e-08,-7.09302470148e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245727974815,-0.00017738877181,9.81000148628,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122205250000,12836,122205250000,RH_EXTIMU,2.32168612584e-06,1.52871924437e-05,-0.703399478512,0.710794747722,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.43221150036e-08,3.5449323161e-08,-7.09295670991e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244339486817,-0.000180067884401,9.81000630071,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122207750000,12837,122207750000,RH_EXTIMU,2.32166692339e-06,1.52872547224e-05,-0.703399541532,0.710794685358,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.5078105301e-08,2.52539629778e-08,-7.09287944025e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245125684954,-0.000177544476147,9.81000436422,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122210250000,12838,122210250000,RH_EXTIMU,2.32165132048e-06,1.52872506399e-05,-0.703399604551,0.710794622995,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.68848183935e-09,-1.04559216819e-08,-7.09280498116e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245470230548,-0.000178678172517,9.81000508753,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122212750000,12839,122212750000,RH_EXTIMU,2.32162173221e-06,1.52872506231e-05,-0.70339966757,0.710794560632,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.59290128949e-08,-1.60137645492e-08,-7.09273359607e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245452556572,-0.000178354207431,9.80999915092,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122215250000,12840,122215250000,RH_EXTIMU,2.321716969e-06,1.52872475402e-05,-0.703399730588,0.710794498269,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.67764100793e-08,5.24841641129e-08,-7.0926655261e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244223374322,-0.000179731684728,9.8100040228,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122217750000,12841,122217750000,RH_EXTIMU,2.32155505389e-06,1.52872841863e-05,-0.703399793605,0.710794435908,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.11805684244e-07,-6.96289090269e-08,-7.09259711415e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247050148043,-0.000176082509687,9.80997903165,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122220250000,12842,122220250000,RH_EXTIMU,2.32194236379e-06,1.52869991903e-05,-0.703399856622,0.710794373547,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.81497592733e-07,5.65337270418e-08,-7.09254733673e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243008537475,-0.000186765454059,9.81000526515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122222750000,12843,122222750000,RH_EXTIMU,2.32182510103e-06,1.5287104648e-05,-0.703399919638,0.710794311186,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.25136403855e-07,-5.37352350134e-09,-7.09245260563e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246409612616,-0.000174622444823,9.81001016817,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122225250000,12844,122225250000,RH_EXTIMU,2.32168850958e-06,1.52872402806e-05,-0.703399982653,0.710794248826,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.53107443996e-07,9.08383012373e-10,-7.09238056073e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244678024948,-0.000176410905877,9.81000078453,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122227750000,12845,122227750000,RH_EXTIMU,2.32165072217e-06,1.5287183778e-05,-0.703400045668,0.710794186467,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.11943433109e-08,-5.27474886233e-08,-7.0923144265e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246399639622,-0.000179094196581,9.80999170765,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122230250000,12846,122230250000,RH_EXTIMU,2.32164444536e-06,1.52871039284e-05,-0.703400108682,0.710794124109,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.22502281143e-08,-4.82918069879e-08,-7.09224793735e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245908127648,-0.000179137649836,9.80999108593,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122232750000,12847,122232750000,RH_EXTIMU,2.32174887563e-06,1.52870142145e-05,-0.703400171695,0.710794061751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.1075304119e-07,8.39607452371e-09,-7.09218490832e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244778356221,-0.000180700896768,9.80999672986,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122235250000,12848,122235250000,RH_EXTIMU,2.32180688938e-06,1.52869742552e-05,-0.703400234708,0.710793999393,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.63609610254e-08,1.05688475649e-08,-7.09211191986e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245157250016,-0.000179409027342,9.81000182634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122237750000,12849,122237750000,RH_EXTIMU,2.32179113764e-06,1.52869976931e-05,-0.70340029772,0.710793937036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.12594958391e-08,5.10931649265e-09,-7.09204268691e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245102949531,-0.000177958523255,9.80999582357,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122240250000,12850,122240250000,RH_EXTIMU,2.32197817408e-06,1.52869355016e-05,-0.703400360732,0.71079387468,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.42238344773e-07,7.053046002e-08,-7.09197478669e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243966371966,-0.000181739587885,9.81001157906,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122242750000,12851,122242750000,RH_EXTIMU,2.32173370321e-06,1.52870190895e-05,-0.703400423743,0.710793812325,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.85164930237e-07,-8.93921443156e-08,-7.09188642107e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000247407464629,-0.000174247116214,9.8099976554,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122245250000,12852,122245250000,RH_EXTIMU,2.32191152175e-06,1.52869885847e-05,-0.703400486753,0.71079374997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.19165961126e-07,8.33615232812e-08,-7.09183225158e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243101479223,-0.000181656558691,9.8100004424,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122247750000,12853,122247750000,RH_EXTIMU,2.32194945684e-06,1.52869810562e-05,-0.703400549763,0.710793687615,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.6694074187e-08,1.77114102041e-08,-7.09176371435e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245366523114,-0.000178709726695,9.80999186322,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122250250000,12854,122250250000,RH_EXTIMU,2.32205192719e-06,1.52868780673e-05,-0.703400612772,0.710793625262,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17108587592e-07,-2.55413259107e-10,-7.09169264932e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245170826303,-0.000180962437404,9.81000845312,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122252750000,12855,122252750000,RH_EXTIMU,2.32187374061e-06,1.52869559967e-05,-0.703400675781,0.710793562909,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.44289184805e-07,-5.53103688751e-08,-7.0916025448e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246206321049,-0.000175410057858,9.81000820731,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122255250000,12856,122255250000,RH_EXTIMU,2.32188224414e-06,1.52869776744e-05,-0.703400738788,0.710793500556,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.47672295682e-09,1.77573251439e-08,-7.09153720314e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244765564589,-0.00017907133305,9.8100017105,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122257750000,12857,122257750000,RH_EXTIMU,2.32181100867e-06,1.52869709759e-05,-0.703400801795,0.710793438204,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.58511977029e-08,-4.32491880842e-08,-7.09146591653e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024614059079,-0.000177653090021,9.80999207317,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122260250000,12858,122260250000,RH_EXTIMU,2.32181444488e-06,1.52869263952e-05,-0.703400864802,0.710793375853,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.79267620938e-08,-2.27709816164e-08,-7.09140656352e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245462662515,-0.00017918401457,9.80998600115,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122262750000,12859,122262750000,RH_EXTIMU,2.32201641121e-06,1.5286762993e-05,-0.703400927808,0.710793313503,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.07681191132e-07,2.1379983494e-08,-7.09134210646e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244495649741,-0.000182685272414,9.81000341295,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122266500000,12860,122265250000,RH_EXTIMU,2.32195617528e-06,1.52867928985e-05,-0.703400990813,0.710793251153,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.01943461897e-08,-1.62452432214e-08,-7.0912606368e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245826080545,-0.000176895672659,9.81000214247,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122270250000,12861,122267750000,RH_EXTIMU,2.32212472001e-06,1.52867467991e-05,-0.703401053818,0.710793188803,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22667806962e-07,6.92753503222e-08,-7.09118984373e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243618259346,-0.000181587405636,9.81002024082,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122270250000,12862,122270250000,RH_EXTIMU,2.32193910759e-06,1.5286927823e-05,-0.703401116822,0.710793126455,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.06525256783e-07,-8.66060541103e-10,-7.09110421784e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024571719206,-0.000174294589253,9.81000200389,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122272750000,12863,122272750000,RH_EXTIMU,2.32195061877e-06,1.528694912e-05,-0.703401179825,0.710793064106,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.55225380646e-09,1.92331993441e-08,-7.09103757923e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244906948705,-0.000178952555658,9.81000040766,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122275250000,12864,122275250000,RH_EXTIMU,2.32207643379e-06,1.52868929083e-05,-0.703401242828,0.710793001759,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04060569808e-07,3.94802865609e-08,-7.09097307607e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244590902929,-0.000180622945697,9.80999781165,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122277750000,12865,122277750000,RH_EXTIMU,2.32205640002e-06,1.52868232805e-05,-0.70340130583,0.710792939412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.86753901022e-08,-5.02206959964e-08,-7.09090992579e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246188221858,-0.000178964399188,9.80998471752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122280250000,12866,122280250000,RH_EXTIMU,2.32213454337e-06,1.52867196131e-05,-0.703401368831,0.710792877066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03657138862e-07,-1.43305331041e-08,-7.09084379351e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245374514941,-0.000180249020607,9.80999663183,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122284000000,12867,122282750000,RH_EXTIMU,2.32212432471e-06,1.52866984065e-05,-0.703401431832,0.71079281472,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.00897467589e-09,-1.71636179897e-08,-7.0907693469e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245458986841,-0.000178480322403,9.81000157287,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122285250000,12868,122285250000,RH_EXTIMU,2.32225509793e-06,1.52867047627e-05,-0.703401494832,0.710792752375,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.16716667259e-08,7.78485714564e-08,-7.09068918266e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243888868017,-0.000179922094866,9.81002170125,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122290250000,12869,122287750000,RH_EXTIMU,2.32216797427e-06,1.52867988117e-05,-0.703401557832,0.710792690031,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.01578594848e-07,5.09854520221e-09,-7.09060951052e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245317972012,-0.00017690258179,9.81000719792,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122290250000,12870,122290250000,RH_EXTIMU,2.32215599703e-06,1.52868157862e-05,-0.70340162083,0.710792627687,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.54763021025e-08,3.55780567487e-09,-7.09053885809e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245176126765,-0.000178589637869,9.81000160874,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122290250000,12871,122292750000,RH_EXTIMU,2.32203862308e-06,1.52868179726e-05,-0.703401683829,0.710792565344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.70869381557e-08,-6.41601510642e-08,-7.09047096447e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246664364087,-0.000177064496697,9.80998548563,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122295250000,12872,122295250000,RH_EXTIMU,2.32212122832e-06,1.52866643931e-05,-0.703401746826,0.710792503001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34280866053e-07,-4.02014208627e-08,-7.09041494025e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245365522949,-0.000181416979351,9.80998748926,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122297750000,12873,122297750000,RH_EXTIMU,2.32220636446e-06,1.52865619155e-05,-0.703401809823,0.710792440659,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.06963829953e-07,-9.71890640314e-09,-7.09034722582e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245317421572,-0.000180138036695,9.80999559063,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122300250000,12874,122300250000,RH_EXTIMU,2.32222855154e-06,1.52865331043e-05,-0.70340187282,0.710792378318,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.97152692165e-08,-3.25257217099e-09,-7.09027584247e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245247444073,-0.000178912244667,9.8099998464,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122302750000,12875,122302750000,RH_EXTIMU,2.32234097037e-06,1.52866309456e-05,-0.703401935816,0.710792315977,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.75394006957e-09,1.19541739596e-07,-7.09020170422e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024307834933,-0.000178651018175,9.8100145318,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122302750000,12876,122305250000,RH_EXTIMU,2.32227916729e-06,1.52866485976e-05,-0.703401998811,0.710792253637,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.41903034971e-08,-2.40950388253e-08,-7.09011621728e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246225000827,-0.000177979164484,9.81001167226,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122307750000,12877,122307750000,RH_EXTIMU,2.32220817353e-06,1.52866457854e-05,-0.703402061805,0.710792191298,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.79007512075e-08,-4.09035271399e-08,-7.09004251842e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000245710894017,-0.000178129314404,9.81000319704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122310250000,12878,122310250000,RH_EXTIMU,2.31843890509e-06,1.5280981444e-05,-0.703402124796,0.710792128962,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04500041798e-06,-5.34133935409e-06,-7.08965623387e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000344977150593,-0.000199396687476,9.80997906052,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122314000000,12879,122312750000,RH_EXTIMU,2.31630774632e-06,1.52780163203e-05,-0.703402187786,0.710792066626,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.57576404081e-07,-2.88467335607e-06,-7.08958411794e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000271713015895,-0.000184932970003,9.80997958496,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122315250000,12880,122315250000,RH_EXTIMU,2.30653658561e-06,1.52632534093e-05,-0.703402250762,0.710792004306,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.75208551702e-06,-1.38924876745e-05,-7.08795295763e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00050225719697,-0.000226450180989,9.81096339711,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122319000000,12881,122317750000,RH_EXTIMU,2.29441229459e-06,1.52613068062e-05,-0.703402313733,0.710791941989,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.79799940414e-06,-7.9288620512e-06,-7.08746374846e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00031669272434,-8.00545108116e-05,9.81034961267,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122324000000,12882,122320250000,RH_EXTIMU,2.29069000598e-06,1.52539018317e-05,-0.703402376699,0.710791879678,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.05120588937e-06,-6.30468492496e-06,-7.08683643689e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000361662086732,-0.000245076514202,9.81060978804,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122324000000,12883,122322750000,RH_EXTIMU,2.27559635704e-06,1.52449371902e-05,-0.703402439654,0.710791817378,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.53727194806e-06,-1.35904774607e-05,-7.08556065153e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000441264062782,-0.000101723084148,9.81044938695,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122325250000,12884,122325250000,RH_EXTIMU,2.27086665314e-06,1.52445458147e-05,-0.703402502608,0.710791755078,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.46835110408e-06,-2.88341217585e-06,-7.08555461885e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246348083766,-0.000147320562259,9.81011898513,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122329000000,12885,122327750000,RH_EXTIMU,2.27153236225e-06,1.52447028083e-05,-0.703402565562,0.710791692778,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.91081659867e-07,4.64526356893e-07,-7.0855466955e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000230740650973,-0.000190192853793,9.80996884273,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122332750000,12886,122330250000,RH_EXTIMU,2.26309429361e-06,1.52293524387e-05,-0.703402628503,0.710791630492,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.84070500192e-06,-1.34763741954e-05,-7.08404673101e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000503479981932,-0.00024858965345,9.81072943427,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122334000000,12887,122332750000,RH_EXTIMU,2.24608877165e-06,1.52151578538e-05,-0.703402691432,0.710791568218,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.68142003379e-06,-1.76402519999e-05,-7.08261430457e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000501900064839,-0.0001510266593,9.81082189265,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122335250000,12888,122335250000,RH_EXTIMU,2.2369945405e-06,1.52136906526e-05,-0.703402754358,0.710791505946,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.34477780963e-06,-5.95117981277e-06,-7.082377124e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000278783588005,-0.000113081204353,9.81024129763,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122337750000,12889,122337750000,RH_EXTIMU,2.23681534489e-06,1.52142969342e-05,-0.703402817284,0.710791443674,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.42187338142e-07,2.44559768229e-07,-7.08238506411e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000224732992835,-0.000181697366983,9.81000180444,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122341500000,12890,122340250000,RH_EXTIMU,2.24416815853e-06,1.51935001507e-05,-0.703402880196,0.710791381416,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.58847436385e-05,-7.68750355409e-06,-7.08079154099e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000417930866686,-0.000527570479569,9.81246485927,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122344000000,12891,122342750000,RH_EXTIMU,2.20174243143e-06,1.51886897369e-05,-0.70340294307,0.710791319196,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.14168698816e-05,-2.66086200675e-05,-7.07648233906e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00066071367343,0.000282349446077,9.81231566513,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122344000000,12892,122345250000,RH_EXTIMU,2.18310341667e-06,1.51974246079e-05,-0.703403005941,0.710791256979,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.55131935614e-05,-5.5210086101e-06,-7.07618126523e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000240323116123,3.22673194409e-05,9.81077721266,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122347750000,12893,122347750000,RH_EXTIMU,2.18343596676e-06,1.51992279907e-05,-0.703403068813,0.71079119476,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.24831885146e-07,1.21324301521e-06,-7.07634083071e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000212414219309,-0.000200554363402,9.80996490981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122347750000,12894,122350250000,RH_EXTIMU,2.19834393738e-06,1.52179979216e-05,-0.70340313172,0.710791132507,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.0842245756e-06,1.90628982354e-05,-7.08022253453e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00012999773736,-0.000156383074838,9.80615338093,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122347750000,12895,122352750000,RH_EXTIMU,2.23349724826e-06,1.52078258778e-05,-0.703403194642,0.710791070238,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.57142428681e-05,1.39980477175e-05,-7.08189468467e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000100439286206,-0.000606329795534,9.80847858947,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122355250000,12896,122355250000,RH_EXTIMU,2.24182204128e-06,1.52017723639e-05,-0.703403257563,0.710791007972,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.1410763787e-06,1.24296705505e-06,-7.08173722702e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000258408796851,-0.000265924829828,9.80961728288,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122357750000,12897,122357750000,RH_EXTIMU,2.24049051409e-06,1.51948268173e-05,-0.703403320477,0.710790945712,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.15214279213e-06,-4.69810174842e-06,-7.08094963913e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000349199508995,-0.000233550094793,9.8104787022,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122360250000,12898,122360250000,RH_EXTIMU,2.22726356007e-06,1.51876052615e-05,-0.703403383379,0.710790883463,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.45667003542e-06,-1.15488759463e-05,-7.07977218828e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000411562437367,-0.000100332248977,9.81040820208,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122362750000,12899,122362750000,RH_EXTIMU,2.21208585099e-06,1.51804441557e-05,-0.703403446273,0.710790821224,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.59994988253e-06,-1.26122363953e-05,-7.07869342972e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000434821278058,-0.000102290768499,9.81046082431,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122365250000,12900,122365250000,RH_EXTIMU,2.20504862803e-06,1.51794333832e-05,-0.703403509164,0.710790758987,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.43193617472e-06,-4.53411922718e-06,-7.0784436821e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000271975175122,-0.000128596596038,9.810177007,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122367750000,12901,122367750000,RH_EXTIMU,2.20313278096e-06,1.51693353888e-05,-0.703403572049,0.710790696756,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.59383205764e-06,-6.81949495279e-06,-7.07770586504e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000383426493393,-0.00029061692569,9.81059516145,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122370250000,12902,122370250000,RH_EXTIMU,2.18630470467e-06,1.51518172353e-05,-0.703403634918,0.71079063454,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.89745944609e-07,-1.94302914081e-05,-7.07597359136e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000549372524704,-0.000175460535894,9.81070182992,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122372750000,12903,122372750000,RH_EXTIMU,2.17360491975e-06,1.51449316766e-05,-0.703403697782,0.71079057233,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.34597814408e-06,-1.10611682578e-05,-7.07537799834e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000354474266977,-0.000118955416483,9.81030732466,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122375250000,12904,122375250000,RH_EXTIMU,2.17201283006e-06,1.51452325495e-05,-0.703403760646,0.710790510119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.07375210599e-06,-7.24174900433e-07,-7.07541064149e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000220665471165,-0.000170222888277,9.81002822509,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122377750000,12905,122377750000,RH_EXTIMU,2.17378708487e-06,1.51455973424e-05,-0.70340382351,0.710790447908,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.04491206627e-07,1.20649157918e-06,-7.07539956673e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000220549758965,-0.000196357377518,9.80993288184,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122380250000,12906,122380250000,RH_EXTIMU,2.17355191913e-06,1.51338414943e-05,-0.703403886367,0.710790385704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.48243375248e-06,-6.81644445333e-06,-7.07459526958e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000401252389333,-0.000316930098671,9.81058199795,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122382750000,12907,122382750000,RH_EXTIMU,2.15617865545e-06,1.51231510653e-05,-0.703403949212,0.710790323513,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.86237859025e-06,-1.58546166191e-05,-7.07319611211e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000457916505634,-8.04778795867e-05,9.81033370151,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122385250000,12908,122385250000,RH_EXTIMU,2.15552423877e-06,1.51251771029e-05,-0.703404012059,0.710790261319,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.51135309893e-06,7.84459008489e-07,-7.07358276908e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000176673157883,-0.000169046291551,9.8099807626,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122387750000,12909,122387750000,RH_EXTIMU,2.15574549816e-06,1.51108748981e-05,-0.703404074899,0.710790199133,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.17486539451e-06,-8.00754240576e-06,-7.07259701291e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000437528038104,-0.00035768885601,9.81072534332,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122390250000,12910,122390250000,RH_EXTIMU,2.13175729411e-06,1.50850278091e-05,-0.703404137716,0.710790136969,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.05160493581e-07,-2.81955632798e-05,-7.07012277359e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000694003053178,-0.0001806218456,9.8110256702,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122392750000,12911,122392750000,RH_EXTIMU,2.11166101878e-06,1.50714630576e-05,-0.703404200524,0.710790074814,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.79332158999e-06,-1.90213528916e-05,-7.06903878681e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000461161084939,-0.000115423411361,9.81060801377,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122395250000,12912,122395250000,RH_EXTIMU,2.09624933576e-06,1.5049829528e-05,-0.703404263317,0.710790012674,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.4109775205e-06,-2.09733894241e-05,-7.06743053993e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000566084691443,-0.00025640644148,9.8108497842,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122397750000,12913,122397750000,RH_EXTIMU,2.08604529418e-06,1.50375506859e-05,-0.703404326105,0.710789950538,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.10810740214e-06,-1.27235529596e-05,-7.06685627201e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000392197575365,-0.00022018771643,9.81047858062,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122400250000,12914,122400250000,RH_EXTIMU,2.07724017384e-06,1.502947461e-05,-0.703404388887,0.710789888408,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.61416502155e-07,-9.54652002641e-06,-7.066199779e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000353817369355,-0.000163623915908,9.81017767135,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122402750000,12915,122402750000,RH_EXTIMU,2.07603287811e-06,1.50230261182e-05,-0.703404451668,0.710789826281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.94306912867e-06,-4.34554920966e-06,-7.06596050323e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00030004415067,-0.000249973316488,9.81021994314,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122405250000,12916,122405250000,RH_EXTIMU,2.07039735053e-06,1.50096824045e-05,-0.70340451444,0.710789764161,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.30513914802e-06,-1.07582625658e-05,-7.06507514763e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000417059712334,-0.000259531350884,9.81034513443,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122407750000,12917,122407750000,RH_EXTIMU,2.06221119602e-06,1.50018786035e-05,-0.703404577207,0.710789702046,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.62668204967e-07,-9.04339003336e-06,-7.06449568491e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000345056839626,-0.000162264871456,9.81014992145,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122410250000,12918,122410250000,RH_EXTIMU,2.05796077831e-06,1.49930163169e-05,-0.70340463997,0.710789639935,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.57095157575e-06,-7.43054639093e-06,-7.06402013366e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000346079946892,-0.000232110976786,9.81010866778,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122412750000,12919,122412750000,RH_EXTIMU,2.06715866339e-06,1.49727268471e-05,-0.703404702725,0.710789577833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.6648429863e-05,-6.36072633992e-06,-7.06307417347e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00034427589633,-0.00054016750742,9.81199545583,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122415250000,12920,122415250000,RH_EXTIMU,2.028437297e-06,1.49831671434e-05,-0.703404765458,0.710789515752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.78923436201e-05,-1.58521100815e-05,-7.06067735584e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000467260605894,0.000447555034794,9.80976431019,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122417750000,12921,122417750000,RH_EXTIMU,2.04416323603e-06,1.49774591232e-05,-0.703404828211,0.71078945365,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.21551579174e-05,5.60424220354e-06,-7.06295273406e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000117145857817,-0.000538542320267,9.80925105607,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122420250000,12922,122420250000,RH_EXTIMU,2.04343000786e-06,1.49495015359e-05,-0.703404890954,0.71078939156,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.53163181208e-05,-1.63095301527e-05,-7.06174958041e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000546354126594,-0.000416371666604,9.80988034137,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122422750000,12923,122422750000,RH_EXTIMU,2.04227697557e-06,1.49212658357e-05,-0.703404953684,0.710789329483,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.52341049317e-05,-1.67039079316e-05,-7.06020925771e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000470899649158,-0.00047335324063,9.81203472643,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122425250000,12924,122425250000,RH_EXTIMU,2.01064979369e-06,1.49204162148e-05,-0.703405016384,0.710789267434,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.7505258829e-05,-1.82798560969e-05,-7.05704609405e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000493873930006,0.000201172014211,9.81185757289,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122425250000,12925,122427750000,RH_EXTIMU,2.0074335026e-06,1.49424029285e-05,-0.70340507911,0.710789205359,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.42004874083e-05,1.06930919672e-05,-7.0599162947e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.857854031e-05,-1.12523205687e-05,9.80748334628,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122430250000,12926,122430250000,RH_EXTIMU,2.02733042337e-06,1.49164176911e-05,-0.703405141841,0.710789143281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.59373811133e-05,-3.57890354061e-06,-7.06028055881e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000373123669267,-0.000641043985813,9.80911165398,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122432750000,12927,122432750000,RH_EXTIMU,2.02654726268e-06,1.48956264962e-05,-0.703405204567,0.710789081207,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12552262499e-05,-1.22625889167e-05,-7.05985287509e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000426030325947,-0.000329022081069,9.8096795495,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122435250000,12928,122435250000,RH_EXTIMU,2.02215073282e-06,1.48847338193e-05,-0.703405267289,0.710789019137,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.63041620751e-06,-8.66731225385e-06,-7.05939813494e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000346854982467,-0.000229102752876,9.8100479365,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122437750000,12929,122437750000,RH_EXTIMU,2.01879497885e-06,1.48747904329e-05,-0.703405330006,0.710788957071,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.68804508454e-06,-7.54184631002e-06,-7.05892781583e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000341620766481,-0.00024643830028,9.81010320354,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122440250000,12930,122440250000,RH_EXTIMU,2.0159773833e-06,1.48688337531e-05,-0.703405392722,0.710788895007,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.75064215071e-06,-4.9720458918e-06,-7.05868099145e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000288056690428,-0.000198719784262,9.80995677291,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122442750000,12931,122442750000,RH_EXTIMU,2.0176173844e-06,1.48656803216e-05,-0.703405455436,0.710788832944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.70791429203e-06,-8.69633649564e-07,-7.05858602803e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243378175817,-0.000234831468978,9.81002467218,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122445250000,12932,122445250000,RH_EXTIMU,2.01958092685e-06,1.48689701548e-05,-0.703405518154,0.710788770877,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.33891996171e-07,2.97627142977e-06,-7.05897828886e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000148031126598,-0.000142391147374,9.80937154796,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122447750000,12933,122447750000,RH_EXTIMU,2.03655176576e-06,1.4877130807e-05,-0.703405580883,0.7107887088,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.05879363514e-06,1.41909424214e-05,-7.06019610435e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.45476848696e-05,-0.000279609500223,9.80943586388,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122450250000,12934,122450250000,RH_EXTIMU,2.04437479009e-06,1.48791515305e-05,-0.703405643611,0.710788646723,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.31215105086e-06,5.55188975681e-06,-7.06011170488e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000188538613555,-0.000220450033552,9.80979594221,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122454000000,12935,122452750000,RH_EXTIMU,2.04589430805e-06,1.48683845062e-05,-0.703405706333,0.710788584653,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.92376150336e-06,-5.26675661967e-06,-7.05935808485e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000377927313378,-0.000321677545257,9.81044275246,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122455250000,12936,122455250000,RH_EXTIMU,2.03467632762e-06,1.48733096047e-05,-0.703405769054,0.710788522583,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.14951617419e-06,-3.51143451652e-06,-7.05934490282e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000190041495997,5.27950650834e-05,9.80914748628,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122457750000,12937,122457750000,RH_EXTIMU,2.06130006493e-06,1.48702433722e-05,-0.703405831787,0.710788460502,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.68653695027e-05,1.32389145877e-05,-7.06059627345e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000104157662517,-0.00057900078853,9.81021191241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122460250000,12938,122460250000,RH_EXTIMU,2.04269180552e-06,1.4834956732e-05,-0.703405894494,0.710788398447,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.27628221469e-06,-3.05357610066e-05,-7.05778511379e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000788349475924,-0.000293132202347,9.8104579931,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122460250000,12939,122462750000,RH_EXTIMU,2.02894036105e-06,1.48169957314e-05,-0.703405957198,0.710788336395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.28845078023e-06,-1.79508204083e-05,-7.05736168748e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000425330502074,-0.000216126505701,9.81016881026,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122466500000,12940,122465250000,RH_EXTIMU,2.02734549746e-06,1.4806935909e-05,-0.703406019901,0.710788274343,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.75486683845e-06,-6.61715903583e-06,-7.05728127981e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000296452103602,-0.000269580407096,9.80992845975,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122467750000,12941,122467750000,RH_EXTIMU,2.02970334304e-06,1.47986045558e-05,-0.703406082605,0.710788212291,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.02984578581e-06,-3.41001096831e-06,-7.05733780984e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00027395625521,-0.000282370683658,9.80971555336,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122470250000,12942,122470250000,RH_EXTIMU,2.03455350656e-06,1.47916851952e-05,-0.70340614531,0.710788150237,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.65249062412e-06,-1.20461949579e-06,-7.05755435322e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000241935602006,-0.000291438457948,9.80963689902,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122472750000,12943,122472750000,RH_EXTIMU,2.04022788025e-06,1.47858670691e-05,-0.703406208017,0.710788088181,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.50146961628e-06,-1.14620346363e-07,-7.05776453366e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000233545162289,-0.000285620163447,9.80962290368,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122475250000,12944,122475250000,RH_EXTIMU,2.04579337109e-06,1.47799920281e-05,-0.703406270726,0.710788026123,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.47158303032e-06,-2.08255018656e-07,-7.05794251068e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000237067638215,-0.000285795634596,9.80963577068,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122477750000,12945,122477750000,RH_EXTIMU,2.05121719707e-06,1.4774277498e-05,-0.703406333437,0.710787964064,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.30070451893e-06,-1.96701914878e-07,-7.05811858974e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000235954459031,-0.000281880153283,9.80963325766,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122480250000,12946,122480250000,RH_EXTIMU,2.06548586342e-06,1.47582942447e-05,-0.703406396142,0.71078790201,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.71086172658e-05,-1.05859647295e-06,-7.0575448926e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000256169196894,-0.000521199029068,9.81144224604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122485250000,12947,122482750000,RH_EXTIMU,2.0392119574e-06,1.4786533815e-05,-0.703406458839,0.710787839964,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.08304123561e-05,1.27351805277e-06,-7.05669811842e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000159592364762,0.000528325132096,9.80882203533,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122485250000,12948,122485250000,RH_EXTIMU,2.07496297123e-06,1.47964035606e-05,-0.703406521567,0.710787777887,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.47759977719e-05,2.57308633163e-05,-7.060048993e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000150710902518,-0.00060368449882,9.80883261024,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122487750000,12949,122487750000,RH_EXTIMU,2.09013498132e-06,1.47762139678e-05,-0.703406584279,0.710787715827,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.99893018113e-05,-2.94210943312e-06,-7.05824248992e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000362101507221,-0.000464234951058,9.81137873118,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122490250000,12950,122490250000,RH_EXTIMU,2.08175151767e-06,1.48042246723e-05,-0.703406647008,0.710787653748,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.05285762325e-05,1.12107738454e-05,-7.06031338203e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.08051828955e-05,0.000209408607886,9.80734979185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122490250000,12951,122492750000,RH_EXTIMU,2.10744551398e-06,1.4789034574e-05,-0.703406709744,0.710787591664,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.31590796064e-05,5.82174557493e-06,-7.06094981972e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000250773531229,-0.000636485079843,9.8095504244,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122495250000,12952,122495250000,RH_EXTIMU,2.10074047781e-06,1.47609131022e-05,-0.703406772469,0.710787529591,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.20128271211e-05,-1.97631798624e-05,-7.05979924059e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000571791852845,-0.00033337275439,9.80964414814,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122497750000,12953,122497750000,RH_EXTIMU,2.09786200679e-06,1.47520493619e-05,-0.703406835196,0.710787467516,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.35191197344e-06,-6.65935005303e-06,-7.05996159272e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000266336790919,-0.000214455803301,9.80978364392,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122500250000,12954,122500250000,RH_EXTIMU,2.10061490578e-06,1.47528684347e-05,-0.703406897923,0.71078740544,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.10531222531e-06,2.01550303979e-06,-7.06001893364e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000185487239604,-0.000191894245004,9.80982986453,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122502750000,12955,122502750000,RH_EXTIMU,2.11241122501e-06,1.47397351757e-05,-0.703406960656,0.710787343358,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.40990048156e-05,-8.29246943904e-07,-7.06065655361e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000262063610247,-0.00045424157478,9.80919784382,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122505250000,12956,122505250000,RH_EXTIMU,2.12563735293e-06,1.47242308333e-05,-0.703407023397,0.71078728127,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.6246306078e-05,-1.37292577991e-06,-7.06146816856e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000249843627131,-0.000450846911808,9.80905741653,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122507750000,12957,122507750000,RH_EXTIMU,2.13758814568e-06,1.47120996398e-05,-0.703407086143,0.710787219176,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.36229552416e-05,-1.72516454767e-07,-7.06208672135e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000231275015712,-0.000396822326723,9.80920057174,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122510250000,12958,122510250000,RH_EXTIMU,2.14840743189e-06,1.47021094758e-05,-0.703407148893,0.710787157077,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17747347798e-05,4.08208905706e-07,-7.06261227324e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000226620066555,-0.000368517015784,9.80929831167,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122512750000,12959,122512750000,RH_EXTIMU,2.15854105151e-06,1.46930029144e-05,-0.703407211648,0.710787094974,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.08876184776e-05,5.24809473178e-07,-7.0631144658e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000224640876642,-0.000354591681084,9.80932145239,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122515250000,12960,122515250000,RH_EXTIMU,2.1689467019e-06,1.46848295491e-05,-0.703407274407,0.710787032866,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0517169824e-05,1.20853122803e-06,-7.06365726036e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000213143512051,-0.000349577116589,9.80931648809,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122517750000,12961,122517750000,RH_EXTIMU,2.17976803484e-06,1.46769449015e-05,-0.703407337172,0.710786970753,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.05910704322e-05,1.60661999235e-06,-7.06423531141e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000209501522185,-0.000351152324806,9.80928304278,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122520250000,12962,122520250000,RH_EXTIMU,2.19104486709e-06,1.46692176579e-05,-0.703407399943,0.710786908634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.07615055846e-05,1.9524458683e-06,-7.06485704912e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000202928085812,-0.000353386473811,9.80925079003,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122522750000,12963,122522750000,RH_EXTIMU,2.20706723515e-06,1.4648750502e-05,-0.703407462703,0.710786846526,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.06290360732e-05,-2.62140849752e-06,-7.06373897408e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000307895772483,-0.0005293050561,9.81168431964,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122525250000,12964,122525250000,RH_EXTIMU,2.18547365188e-06,1.4686911668e-05,-0.703407525468,0.710786784411,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.3752181858e-05,9.54891084522e-06,-7.06439038492e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.34171810081e-05,0.000551469391064,9.80799436247,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122527750000,12965,122527750000,RH_EXTIMU,2.23068518192e-06,1.46996237934e-05,-0.703407588266,0.710786722266,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.85560091528e-05,3.26708133939e-05,-7.06787852521e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000221215950576,-0.000679767298588,9.80873578731,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122530250000,12966,122530250000,RH_EXTIMU,2.24181251855e-06,1.46659352743e-05,-0.703407651056,0.710786660128,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.52855878209e-05,-1.28940206095e-05,-7.06710928887e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000557191119947,-0.00056406682797,9.8089561709,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122532750000,12967,122532750000,RH_EXTIMU,2.24620566683e-06,1.46483905756e-05,-0.703407713852,0.710786597984,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.23717813893e-05,-7.50367442021e-06,-7.06778077512e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000297496800865,-0.000353045008206,9.8091031314,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122535250000,12968,122535250000,RH_EXTIMU,2.25659725353e-06,1.46405270368e-05,-0.703407776655,0.710786535833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03348272003e-05,1.37679483612e-06,-7.06849382324e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00018765593183,-0.000343076757252,9.80921796005,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122545250000,12969,122537750000,RH_EXTIMU,2.26944457177e-06,1.463399717e-05,-0.703407839464,0.710786473676,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.09807357593e-05,3.51706439301e-06,-7.06924106852e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000175624097676,-0.000354668644753,9.80917188349,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122545250000,12970,122540250000,RH_EXTIMU,2.28353877311e-06,1.46291262889e-05,-0.703407902281,0.710786411512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.07561951475e-05,5.16206597155e-06,-7.07009051407e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000153479234591,-0.000348416522597,9.80913079552,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122545250000,12971,122542750000,RH_EXTIMU,2.29805654726e-06,1.4625150028e-05,-0.703407965105,0.710786349339,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04936248183e-05,5.90912869715e-06,-7.0709442938e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000146935530843,-0.000343279396741,9.80912745382,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122545250000,12972,122545250000,RH_EXTIMU,2.31241833297e-06,1.46215324537e-05,-0.703408027937,0.71078628716,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0203082861e-05,6.0253096527e-06,-7.07178966713e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000146448416606,-0.000338396419454,9.80910816443,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122547750000,12973,122547750000,RH_EXTIMU,2.3251486422e-06,1.46186483309e-05,-0.703408090774,0.710786224975,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.86264556537e-06,5.5242965719e-06,-7.07242424611e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000159115926202,-0.000306622641791,9.80939758043,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122550250000,12974,122550250000,RH_EXTIMU,2.32966949727e-06,1.46217136361e-05,-0.703408153611,0.710786162791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.466113913e-07,4.28763651296e-06,-7.07230515673e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000176986688944,-0.00016007058203,9.80993518988,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122552750000,12975,122552750000,RH_EXTIMU,2.3306347732e-06,1.46282301815e-05,-0.703408216445,0.710786100609,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.11729822043e-06,4.2492928452e-06,-7.07206177287e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000174182447337,-0.000107084227573,9.81013892066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122555250000,12976,122555250000,RH_EXTIMU,2.3313439205e-06,1.46350252117e-05,-0.703408279277,0.710786038429,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.41965120051e-06,4.26351697971e-06,-7.07185761035e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000174603308166,-0.000110687843258,9.81014163927,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122557750000,12977,122557750000,RH_EXTIMU,2.33258260636e-06,1.46410452101e-05,-0.703408342108,0.71078597625,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.68240932923e-06,4.12079700549e-06,-7.07170754153e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000177077180634,-0.000125271728037,9.8100964159,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122560250000,12978,122560250000,RH_EXTIMU,2.33425424439e-06,1.46464108343e-05,-0.703408404937,0.710785914072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.06798636767e-06,3.99233464341e-06,-7.07158928626e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000178811366959,-0.000135205743289,9.81006268003,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122562750000,12979,122562750000,RH_EXTIMU,2.3361292981e-06,1.4651439736e-05,-0.703408467766,0.710785851895,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.76283569828e-06,3.91533204994e-06,-7.07148265251e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000179814100754,-0.000139610773288,9.81004694879,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122565250000,12980,122565250000,RH_EXTIMU,2.33805257151e-06,1.46563350819e-05,-0.703408530594,0.710785789719,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.66026118291e-06,3.86652289329e-06,-7.07137729562e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000180531688002,-0.000140895689715,9.81004200783,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122567750000,12981,122567750000,RH_EXTIMU,2.3485751348e-06,1.46498817109e-05,-0.703408593411,0.710785727555,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.6157685592e-06,2.25236848468e-06,-7.07008021888e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000226174619593,-0.000352912610144,9.81201937374,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122570250000,12982,122570250000,RH_EXTIMU,2.32263968985e-06,1.48524512728e-05,-0.703408656283,0.710785665331,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000128738117998,0.000100592882,-7.07667426783e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0020112461588,0.00263352086168,9.80395364386,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122575250000,12983,122572750000,RH_EXTIMU,2.45479939646e-06,1.49200726534e-05,-0.703408719202,0.710785603064,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.7098271715e-05,0.000112821894628,-7.08153512958e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000972495824762,-0.00128054491052,9.81007798949,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122575250000,12984,122575250000,RH_EXTIMU,2.50687003783e-06,1.49873115693e-05,-0.703408782139,0.710785540778,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.22742845826e-06,6.75361370538e-05,-7.08370787489e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000598604025392,-5.00813900187e-07,9.80953056895,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122575250000,12985,122577750000,RH_EXTIMU,2.47002618967e-06,1.48149317438e-05,-0.703408845007,0.710785478566,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.60532054169e-05,-0.000118752479244,-7.07569055557e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00275387960977,-0.00168138923473,9.81016285575,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122580250000,12986,122580250000,RH_EXTIMU,2.41827468718e-06,1.46760353342e-05,-0.70340890787,0.710785416358,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.87342652142e-05,-0.000108101799344,-7.07525883269e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00156601642162,-0.000976879022705,9.80860985895,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122582750000,12987,122582750000,RH_EXTIMU,2.40803533914e-06,1.46439029703e-05,-0.703408970743,0.710785354139,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22602279794e-05,-2.40327225987e-05,-7.07635307204e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000292307064228,-0.000300503070978,9.80937508689,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122585250000,12988,122585250000,RH_EXTIMU,2.41119832747e-06,1.46418817279e-05,-0.703409033614,0.71078529192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.93682904677e-06,6.31171684211e-07,-7.07624008729e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000192098745218,-0.000214314411046,9.80994012889,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122587750000,12989,122587750000,RH_EXTIMU,2.41678316363e-06,1.46766527409e-05,-0.703409096501,0.710785229685,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.63900435217e-05,2.29151267646e-05,-7.07814011538e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000290566516719,0.000226356238376,9.80840188797,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122590250000,12990,122590250000,RH_EXTIMU,2.46785726515e-06,1.47096798064e-05,-0.703409159414,0.710785167425,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04578019752e-05,4.75215197802e-05,-7.0808500705e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000353194823494,-0.000487582399484,9.80950826598,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122592750000,12991,122592750000,RH_EXTIMU,2.4774492179e-06,1.46651799367e-05,-0.703409222321,0.710785105171,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.04964101397e-05,-1.9905615549e-05,-7.0802767764e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000704487932236,-0.000686849214246,9.80837689929,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122595250000,12992,122595250000,RH_EXTIMU,2.4832248729e-06,1.46484481885e-05,-0.703409285237,0.710785042908,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.27004739868e-05,-6.26341696345e-06,-7.08127740034e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243545405781,-0.000335849131837,9.80897012051,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122597750000,12993,122597750000,RH_EXTIMU,2.50218449735e-06,1.46468108581e-05,-0.703409348168,0.71078498063,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17032058499e-05,9.7386735622e-06,-7.0828925789e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.20970362662e-05,-0.000365185933927,9.80877367717,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122600250000,12994,122600250000,RH_EXTIMU,2.51566240683e-06,1.4650226836e-05,-0.703409411103,0.710784918348,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.74251400989e-06,9.52741445012e-06,-7.08345873688e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.84137014192e-05,-0.000234223913761,9.80925309432,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122602750000,12995,122602750000,RH_EXTIMU,2.54062248309e-06,1.46503999403e-05,-0.703409474043,0.710784856061,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.40964490976e-05,1.41447573346e-05,-7.0840357579e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.54967134481e-06,-0.000448182703647,9.81073240051,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122605250000,12996,122605250000,RH_EXTIMU,2.54349225266e-06,1.47104804751e-05,-0.703409537,0.710784793756,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.21762783629e-05,3.57789681406e-05,-7.08598232848e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000377688869917,0.000498726757995,9.80814246903,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122607750000,12997,122607750000,RH_EXTIMU,2.57036872151e-06,1.47170797517e-05,-0.703409599963,0.710784731446,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.15699807673e-05,1.88772691602e-05,-7.08654248055e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000107493825219,-0.00045221473684,9.80949957306,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122610250000,12998,122610250000,RH_EXTIMU,2.57950431699e-06,1.46913399297e-05,-0.703409662929,0.710784669134,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.96801332074e-05,-9.49492134026e-06,-7.08686782877e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000434832956107,-0.000489622698691,9.80897660819,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122612750000,12999,122612750000,RH_EXTIMU,2.59716916538e-06,1.46836151361e-05,-0.703409725913,0.710784606804,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.4392547167e-05,5.54857074417e-06,-7.08889923827e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.05284360868e-05,-0.000409189246098,9.80814698899,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122615250000,13000,122615250000,RH_EXTIMU,2.62709348989e-06,1.46797359381e-05,-0.703409788916,0.710784544454,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.91996015138e-05,1.46340308231e-05,-7.09107094058e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.84802180648e-06,-0.000483688987528,9.8082284811,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122617750000,13001,122617750000,RH_EXTIMU,2.65480680959e-06,1.46804610197e-05,-0.703409851935,0.710784482089,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.53514069932e-05,1.60079577079e-05,-7.09288557761e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.41267943117e-07,-0.000403623672323,9.80842732176,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122617750000,13002,122620250000,RH_EXTIMU,2.680796332e-06,1.46857920224e-05,-0.703409914969,0.710784419708,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17793283114e-05,1.76569827986e-05,-7.09462498254e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.13873275043e-05,-0.000344540522493,9.80856621998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122622750000,13003,122622750000,RH_EXTIMU,2.70573782557e-06,1.46923990654e-05,-0.703409978019,0.710784357313,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04653269245e-05,1.77928195257e-05,-7.0962810411e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.58384558454e-05,-0.000328628090965,9.80863444069,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122625250000,13004,122625250000,RH_EXTIMU,2.73010079762e-06,1.46980216103e-05,-0.703410041082,0.710784294903,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.06903685808e-05,1.69074567088e-05,-7.09789362173e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.21301570058e-06,-0.000336247237725,9.80866003729,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122627750000,13005,122627750000,RH_EXTIMU,2.7638416981e-06,1.47042201375e-05,-0.703410104169,0.71078423247,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.56987948441e-05,2.25121995543e-05,-7.10055726937e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.96889031123e-05,-0.000438196634543,9.80815051905,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122630250000,13006,122630250000,RH_EXTIMU,2.78417749008e-06,1.47083356065e-05,-0.703410167264,0.710784170031,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.24847854377e-06,1.37842845846e-05,-7.10135604613e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.89363271039e-05,-0.000280328894846,9.80893495207,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122632750000,13007,122632750000,RH_EXTIMU,2.8131872963e-06,1.47158223713e-05,-0.70341023038,0.710784107569,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22836374296e-05,2.05824076073e-05,-7.10382836475e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.80696350714e-05,-0.000382071476163,9.80833786679,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122635250000,13008,122635250000,RH_EXTIMU,2.8416267752e-06,1.47215262641e-05,-0.703410293512,0.710784045091,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.29626063271e-05,1.92476788748e-05,-7.10566656059e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.81544031671e-05,-0.000367528582519,9.80845301175,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122640250000,13009,122637750000,RH_EXTIMU,2.86698681433e-06,1.47225778148e-05,-0.703410356647,0.710783982611,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.38295572937e-05,1.48693427328e-05,-7.10590734807e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.38434269353e-05,-0.000401373649983,9.81062943572,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122640250000,13010,122640250000,RH_EXTIMU,2.86821022277e-06,1.47392624056e-05,-0.703410419772,0.71078392014,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.69234114908e-06,1.01763495e-05,-7.10486961346e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000142179446964,4.63427446833e-05,9.81094695281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122642750000,13011,122642750000,RH_EXTIMU,2.88072990415e-06,1.47920246177e-05,-0.703410482922,0.710783857645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.25708732035e-05,3.70477970186e-05,-7.10767284351e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000467191487493,0.000201280115365,9.80848229999,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122645250000,13012,122645250000,RH_EXTIMU,2.92089302482e-06,1.48078909839e-05,-0.703410546086,0.710783795135,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.3910275191e-05,3.16235677818e-05,-7.1092466376e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.49120879408e-05,-0.000412295213789,9.80934238165,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122647750000,13013,122647750000,RH_EXTIMU,2.92724676157e-06,1.48231169028e-05,-0.703410609267,0.71078373261,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.95425654626e-06,1.22338906071e-05,-7.11106196854e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.7396700875e-05,-4.35045205047e-05,9.80721178944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122647750000,13014,122650250000,RH_EXTIMU,2.9498802041e-06,1.48100573832e-05,-0.703410672459,0.710783670074,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.02198457376e-05,5.31108121491e-06,-7.11231743616e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000227050281827,-0.000536730325237,9.80849295825,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122652750000,13015,122652750000,RH_EXTIMU,2.97003515028e-06,1.47846875858e-05,-0.703410735667,0.710783607521,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.5737850849e-05,-3.08359481483e-06,-7.11419762131e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000285623175715,-0.00058719623448,9.80780164329,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122655250000,13016,122655250000,RH_EXTIMU,2.99531118991e-06,1.47784196311e-05,-0.703410798896,0.710783544948,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.79006895515e-05,1.06600124052e-05,-7.1164611189e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.38452961932e-05,-0.000431054551671,9.80809980274,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122657750000,13017,122657750000,RH_EXTIMU,3.02237078175e-06,1.4784506662e-05,-0.703410862142,0.710783482358,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.19623612356e-05,1.86890448014e-05,-7.11845526285e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.90372832068e-05,-0.000336241340324,9.8084135342,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122660250000,13018,122660250000,RH_EXTIMU,3.04876704332e-06,1.47954465741e-05,-0.703410925405,0.710783419751,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.85431859044e-06,2.10752482514e-05,-7.12032846248e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.56133815116e-05,-0.000289194240794,9.80856241526,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122662750000,13019,122662750000,RH_EXTIMU,3.07458691163e-06,1.48078273671e-05,-0.703410988683,0.710783357128,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.71574110624e-06,2.15702187514e-05,-7.12213119056e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.57086414995e-05,-0.000276329604162,9.80865943456,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122665250000,13020,122665250000,RH_EXTIMU,3.09961910621e-06,1.48200686413e-05,-0.703411051978,0.71078329449,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.34636023497e-06,2.10476381325e-05,-7.12391636431e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.56526405984e-05,-0.000270847342199,9.8086381254,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122667750000,13021,122667750000,RH_EXTIMU,3.12139650582e-06,1.48264363862e-05,-0.703411115283,0.710783231842,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.80080167023e-06,1.58762259738e-05,-7.12505774699e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.76296533722e-05,-0.000301837751083,9.80932603963,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122667750000,13022,122670250000,RH_EXTIMU,3.14109490245e-06,1.48445491827e-05,-0.703411178605,0.710783169175,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.00934564704e-06,2.13848597542e-05,-7.12709102993e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000116447621748,-0.000157524997105,9.80827848655,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122672750000,13023,122672750000,RH_EXTIMU,3.16933823903e-06,1.4851254753e-05,-0.703411241942,0.710783106495,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22874018257e-05,1.97068933713e-05,-7.12868720689e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.43862336253e-06,-0.000371729697274,9.80910834756,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122675250000,13024,122675250000,RH_EXTIMU,3.12460630178e-06,1.47715381542e-05,-0.703411305246,0.710783043849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.94239881439e-05,-7.05003436885e-05,-7.12490937357e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00164177344966,-0.000512285873284,9.80842217875,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122677750000,13025,122677750000,RH_EXTIMU,3.10388081806e-06,1.47192149789e-05,-0.703411368563,0.710782981191,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.76596173761e-05,-4.14145901401e-05,-7.12631609536e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000650021060434,-0.000439893313999,9.80830526064,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122680250000,13026,122680250000,RH_EXTIMU,3.10948807789e-06,1.47032003102e-05,-0.703411431892,0.710782918519,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22012572241e-05,-5.9504141627e-06,-7.12777945024e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000230234218565,-0.000340655950263,9.80857263944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122682750000,13027,122682750000,RH_EXTIMU,3.11740805788e-06,1.46945343057e-05,-0.703411495229,0.710782855839,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.38102343727e-06,-4.70335093794e-07,-7.12872936322e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00025448254788,-0.00030088174506,9.80871825762,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122685250000,13028,122685250000,RH_EXTIMU,3.12292315094e-06,1.4683858473e-05,-0.703411558574,0.710782793151,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.14453059294e-06,-2.96647622477e-06,-7.12954468518e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000294939292617,-0.000302657911652,9.80877366797,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122687750000,13029,122687750000,RH_EXTIMU,3.12861252805e-06,1.46731745096e-05,-0.703411621927,0.710782730455,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.24820859668e-06,-2.87302475435e-06,-7.13049646105e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00028932539468,-0.000305876477494,9.80868030355,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122690250000,13030,122690250000,RH_EXTIMU,3.14125757464e-06,1.46528678114e-05,-0.703411685297,0.710782667743,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.86183794772e-05,-4.43060462199e-06,-7.132357783e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000307109997638,-0.000493607909789,9.80790859162,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122692750000,13031,122692750000,RH_EXTIMU,3.15290781149e-06,1.46335874297e-05,-0.703411748678,0.710782605019,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.74751663148e-05,-4.40682268466e-06,-7.13370366314e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000310629191575,-0.000430465266998,9.80822065437,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122695250000,13032,122695250000,RH_EXTIMU,3.15689543262e-06,1.46280701559e-05,-0.70341181206,0.710782542294,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.37309782833e-06,-8.92739757875e-07,-7.1337596473e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00024833731248,-0.000196033597417,9.80985948013,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122697750000,13033,122697750000,RH_EXTIMU,3.15387876077e-06,1.46266644065e-05,-0.703411875445,0.710782479567,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.2340140904e-07,-2.49634178923e-06,-7.13409084817e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00028990540783,-0.000139103696399,9.80922798104,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122700250000,13034,122700250000,RH_EXTIMU,3.16707448561e-06,1.46127934512e-05,-0.70341193884,0.71078241683,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.53099278446e-05,-4.61187813943e-07,-7.13512205793e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000234041839308,-0.000467610536292,9.80947402699,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122704000000,13035,122702750000,RH_EXTIMU,3.15537643028e-06,1.46189502811e-05,-0.703412002231,0.710782354096,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.01155477657e-05,-3.0813355027e-06,-7.1348630548e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000332122136171,0.00014270792154,9.80903210306,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122705250000,13036,122705250000,RH_EXTIMU,3.15466499772e-06,1.4618061834e-05,-0.703412065634,0.71078229135,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.63164257708e-08,-9.04964436464e-07,-7.13609016218e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000244975236786,-0.000224419489309,9.80846747973,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122707750000,13037,122707750000,RH_EXTIMU,3.17672201422e-06,1.45980459706e-05,-0.703412129046,0.710782228596,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.38066091315e-05,1.03117412078e-06,-7.13715231819e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000220103343042,-0.000571536443663,9.81001710825,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122710250000,13038,122710250000,RH_EXTIMU,3.16385274471e-06,1.45994885764e-05,-0.703412192463,0.710782165836,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.12869544801e-06,-6.4210456157e-06,-7.13773297679e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000352213842445,2.84444639361e-05,9.80790658134,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122712750000,13039,122712750000,RH_EXTIMU,3.17021835922e-06,1.45877208465e-05,-0.703412255891,0.710782103067,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.02426036697e-05,-3.10874077766e-06,-7.13886595529e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000304878230996,-0.000343414632305,9.80843720944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122715250000,13040,122715250000,RH_EXTIMU,3.18544597793e-06,1.45592272292e-05,-0.703412319338,0.710782040278,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.46939224644e-05,-7.63259582084e-06,-7.14105280621e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000364741726661,-0.000589808709355,9.80756786085,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122717750000,13041,122717750000,RH_EXTIMU,3.19778935123e-06,1.4536824731e-05,-0.703412382799,0.710781977475,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.962621225e-05,-5.79208028417e-06,-7.14267498363e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00032002688536,-0.000453241051922,9.80799428726,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122720250000,13042,122720250000,RH_EXTIMU,3.20530437844e-06,1.45229898453e-05,-0.703412446271,0.710781914662,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.2059439462e-05,-3.63737124738e-06,-7.14382525623e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00029073143019,-0.000327529560244,9.80849618905,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122722750000,13043,122722750000,RH_EXTIMU,3.21479473784e-06,1.4507792057e-05,-0.703412509757,0.710781851834,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.39496101754e-05,-3.30077377474e-06,-7.14550342397e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000285930609527,-0.000392932679771,9.80814282674,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122722750000,13044,122725250000,RH_EXTIMU,3.22211374744e-06,1.44950912878e-05,-0.703412573253,0.710781788997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.13097778352e-05,-3.10278865082e-06,-7.14657591313e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000292178585336,-0.000319128298201,9.80859880951,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122722750000,13045,122727750000,RH_EXTIMU,3.21989835712e-06,1.44914199725e-05,-0.70341263675,0.710781726158,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.07130513232e-07,-3.33370498241e-06,-7.14668705797e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000304740738516,-0.000120853800748,9.8094046981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122730250000,13046,122730250000,RH_EXTIMU,3.21794590571e-06,1.448752396e-05,-0.703412700252,0.710781663314,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.08308815531e-06,-3.31350978237e-06,-7.14731905073e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000290937048665,-0.000170979399043,9.80916103234,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122732750000,13047,122732750000,RH_EXTIMU,3.21998459657e-06,1.44807890938e-05,-0.703412763762,0.710781600463,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.9500615086e-06,-2.68181774841e-06,-7.14821399337e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00028393599901,-0.000236294336653,9.80895512901,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122735250000,13048,122735250000,RH_EXTIMU,3.22345903043e-06,1.44726874069e-05,-0.703412827281,0.710781537603,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.53561267041e-06,-2.65109049889e-06,-7.14914838086e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000284291011004,-0.000257647032023,9.80890767937,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122737750000,13049,122737750000,RH_EXTIMU,3.22648595135e-06,1.44647364052e-05,-0.703412890808,0.710781474735,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.19635050123e-06,-2.81723607818e-06,-7.15005506532e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000288484860078,-0.000246068005649,9.80890113086,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122740250000,13050,122740250000,RH_EXTIMU,3.23894297016e-06,1.44548188422e-05,-0.70341295434,0.710781411861,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.26651853653e-05,1.37112960245e-06,-7.15065171449e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000192799722153,-0.000391942925877,9.81035677776,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122742750000,13051,122742750000,RH_EXTIMU,3.23132421133e-06,1.4462171534e-05,-0.703413017861,0.710781348998,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.46890324575e-06,-1.05819228532e-07,-7.14947491894e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000276125499162,5.30022843881e-05,9.81106910941,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122745250000,13052,122745250000,RH_EXTIMU,3.20417994811e-06,1.44830029181e-05,-0.703413081379,0.710781286138,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.71564648275e-05,-3.42909201708e-06,-7.14916948818e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000292512912722,0.000332619072989,9.8095358792,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122747750000,13053,122747750000,RH_EXTIMU,3.19811362088e-06,1.44842028466e-05,-0.703413144902,0.710781223274,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.12380467396e-06,-2.73083221884e-06,-7.14964947616e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000309770493072,-0.000117791319995,9.80913561727,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122750250000,13054,122750250000,RH_EXTIMU,3.20922892979e-06,1.44613195479e-05,-0.703413208444,0.710781160391,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.9198469952e-05,-6.75652563461e-06,-7.15177171826e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000347728866368,-0.000521784247628,9.80794849193,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122754000000,13055,122752750000,RH_EXTIMU,3.22031286605e-06,1.44408330298e-05,-0.703413271997,0.710781097498,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.7831889107e-05,-5.4113107084e-06,-7.15289348472e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000315271829021,-0.000429548667754,9.80906275188,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122755250000,13056,122755250000,RH_EXTIMU,3.21051503063e-06,1.44498413436e-05,-0.703413335553,0.7107810346,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.06396506898e-05,-3.90627732168e-07,-7.15345433495e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000231769785339,9.64407969178e-05,9.80855243547,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122757750000,13057,122757750000,RH_EXTIMU,3.23131867767e-06,1.44361857994e-05,-0.703413399125,0.710780971688,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.95147601833e-05,3.94253274805e-06,-7.15506990374e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000160895737856,-0.000548169672434,9.80985570208,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122760250000,13058,122760250000,RH_EXTIMU,3.21531962333e-06,1.44487077009e-05,-0.703413462686,0.710780908784,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.61430206592e-05,-1.88233374786e-06,-7.15407476653e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000327399713979,0.00024791155525,9.80974296005,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122762750000,13059,122762750000,RH_EXTIMU,3.20742374036e-06,1.44494585465e-05,-0.703413526258,0.710780845871,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.91142155593e-06,-4.01574325124e-06,-7.15518004703e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000304692680859,-0.000125470891492,9.80861996326,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122769000000,13060,122765250000,RH_EXTIMU,3.22506684233e-06,1.44230643045e-05,-0.703413589857,0.710780782933,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.48860532878e-05,-5.07953572138e-06,-7.15807147771e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000311913358136,-0.000628892760374,9.80742840883,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122769000000,13061,122767750000,RH_EXTIMU,3.23600526688e-06,1.44063413339e-05,-0.703413653467,0.710780719982,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.56312857817e-05,-3.35314148464e-06,-7.1594426501e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00028651098243,-0.00036437823906,9.80845581412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122770250000,13062,122770250000,RH_EXTIMU,3.23059585772e-06,1.44045638196e-05,-0.703413717075,0.710780657033,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.07476465488e-06,-4.05421931579e-06,-7.15928878121e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000313992429141,-5.1932450876e-05,9.80972846712,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122770250000,13063,122772750000,RH_EXTIMU,3.22876042469e-06,1.4404814971e-05,-0.703413780693,0.710780594075,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.18410711373e-06,-8.8948304403e-07,-7.16033192358e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242198129258,-0.000145717785168,9.80919167519,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122775250000,13064,122775250000,RH_EXTIMU,3.22338339957e-06,1.4404883902e-05,-0.703413844311,0.710780531117,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.09540196563e-06,-2.98606180385e-06,-7.1602785537e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000303078383633,-6.9628753791e-05,9.80982750326,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122777750000,13065,122777750000,RH_EXTIMU,3.21799522458e-06,1.44055819557e-05,-0.703413907932,0.710780468155,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.45576886587e-06,-2.63460164693e-06,-7.16072875935e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000282144215554,-9.24181686522e-05,9.80962428174,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122780250000,13066,122780250000,RH_EXTIMU,3.22156747943e-06,1.44013588918e-05,-0.703413971566,0.71078040518,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.40861613579e-06,-3.90556129228e-07,-7.16213148257e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242560555922,-0.000248229884172,9.80895597843,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122782750000,13067,122782750000,RH_EXTIMU,3.21787905482e-06,1.43982606777e-05,-0.7034140352,0.710780342206,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.52970795918e-07,-3.83674993501e-06,-7.16217377701e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000317552217073,-0.000109712234567,9.80971452679,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122785250000,13068,122785250000,RH_EXTIMU,3.21862764892e-06,1.43953946625e-05,-0.703414098845,0.71078027922,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.03936022414e-06,-1.2078668245e-06,-7.16340157453e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000250727554113,-0.000201550636207,9.80913377204,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122787750000,13069,122787750000,RH_EXTIMU,3.21311442088e-06,1.43935263889e-05,-0.70341416249,0.710780216235,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.08272388112e-06,-4.16425001761e-06,-7.16336327169e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000321410499408,-8.33020094037e-05,9.80981114442,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122790250000,13070,122790250000,RH_EXTIMU,3.20568434589e-06,1.43939877167e-05,-0.703414226139,0.710780153245,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.48362901665e-06,-3.91825213644e-06,-7.16390699638e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000302224233176,-6.69391115772e-05,9.8094310612,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122792750000,13071,122792750000,RH_EXTIMU,3.20296686726e-06,1.43910394743e-05,-0.703414289797,0.710780090247,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.1473922485e-07,-3.20509007075e-06,-7.16486621548e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000290481744722,-0.000156457801333,9.80910829704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122795250000,13072,122795250000,RH_EXTIMU,3.21200553941e-06,1.43832265069e-05,-0.703414353462,0.710780027242,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.53710331934e-06,6.44265789727e-07,-7.16561622023e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000205527694559,-0.000342236987305,9.81037407737,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122797750000,13073,122797750000,RH_EXTIMU,3.19589161879e-06,1.43989187727e-05,-0.703414417134,0.71077996423,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.79923998452e-05,-1.44249668892e-07,-7.16649506166e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000270425407696,0.00022440299822,9.80784394213,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122800250000,13074,122800250000,RH_EXTIMU,3.20933697868e-06,1.4380418457e-05,-0.703414480825,0.710779901199,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.80569598174e-05,-2.95303179416e-06,-7.16856219785e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000302366814743,-0.000511328467717,9.80882586842,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122802750000,13075,122802750000,RH_EXTIMU,3.20816073659e-06,1.43698030465e-05,-0.703414544524,0.710779838161,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.30568204585e-06,-6.69752325888e-06,-7.16937777523e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000346981454703,-0.000204062707926,9.80886807982,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122805250000,13076,122805250000,RH_EXTIMU,3.19822367295e-06,1.43676267705e-05,-0.703414608221,0.710779775123,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.42489820103e-06,-6.8288213624e-06,-7.16931699079e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000349145062407,-2.72620741776e-05,9.80977656733,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122807750000,13077,122807750000,RH_EXTIMU,3.20513069877e-06,1.43690937693e-05,-0.703414671924,0.71077971208,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.10286620794e-06,4.72153437563e-06,-7.16992056171e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00014055255058,-0.000225377326231,9.81097715513,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122807750000,13078,122810250000,RH_EXTIMU,3.18108429863e-06,1.43844296324e-05,-0.703414735617,0.710779649047,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.23024377874e-05,-4.81077495343e-06,-7.16883724804e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000351827899968,0.000298158704616,9.81029116404,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122812750000,13079,122812750000,RH_EXTIMU,3.16634247965e-06,1.43927813384e-05,-0.703414799317,0.710779586007,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.30814249118e-05,-3.54614872921e-06,-7.16964115457e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000296681612613,2.78758767879e-05,9.80907557154,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122815250000,13080,122815250000,RH_EXTIMU,3.17367217766e-06,1.43749879452e-05,-0.703414863038,0.710779522947,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.4181642059e-05,-5.99252538206e-06,-7.17183511214e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000335344476641,-0.00043724420704,9.80818239283,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122817750000,13081,122817750000,RH_EXTIMU,3.17842093664e-06,1.43601113415e-05,-0.70341492677,0.710779459875,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.107268888e-05,-5.78634658451e-06,-7.17322687207e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000325545703653,-0.000307503690848,9.80864998616,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122820250000,13082,122820250000,RH_EXTIMU,3.18637237101e-06,1.4351962644e-05,-0.703414990509,0.710779396797,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.10779797374e-06,-1.58452767654e-07,-7.17391330134e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00021144829988,-0.00030826038725,9.81043408127,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122822750000,13083,122822750000,RH_EXTIMU,3.16754737263e-06,1.43677480547e-05,-0.703415054239,0.710779333727,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.9586399925e-05,-1.61691141538e-06,-7.17302672892e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000299523745267,0.000278537829968,9.81047673798,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122825250000,13084,122825250000,RH_EXTIMU,3.1620143335e-06,1.43756204136e-05,-0.703415117971,0.710779270655,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.57535213586e-06,1.36335308358e-06,-7.17328760737e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000198791421433,-0.00010006564471,9.81088072863,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122827750000,13085,122827750000,RH_EXTIMU,3.14798508136e-06,1.43823147401e-05,-0.703415181705,0.710779207581,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.17435810832e-05,-4.08759551959e-06,-7.17343510916e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000348017543541,0.000102970762673,9.80948795371,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122832750000,13086,122830250000,RH_EXTIMU,3.13778312874e-06,1.43830088236e-05,-0.703415245451,0.710779144496,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.19075943785e-06,-5.34572926096e-06,-7.17474529846e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000323931225212,-7.61139159193e-05,9.80848240578,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122832750000,13087,122832750000,RH_EXTIMU,3.14664844435e-06,1.43603038058e-05,-0.703415309213,0.710779081395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.78187617183e-05,-7.92123793469e-06,-7.17655028934e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000370404890631,-0.000490831367343,9.80899717254,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122835250000,13088,122835250000,RH_EXTIMU,3.13329572358e-06,1.43524568908e-05,-0.703415372971,0.710779018298,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.17606423439e-06,-1.19753806412e-05,-7.17612999337e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000426281575022,-3.22373501317e-05,9.809883045,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122837750000,13089,122837750000,RH_EXTIMU,3.12309706624e-06,1.435138357e-05,-0.703415436735,0.710778955194,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.19431074387e-06,-6.34886427204e-06,-7.17682215926e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000313690911503,-6.01118989323e-05,9.80966444898,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122840250000,13090,122840250000,RH_EXTIMU,3.13308246906e-06,1.43512433833e-05,-0.703415500508,0.710778892082,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.75770879524e-06,5.53996105572e-06,-7.17777678973e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000136376121065,-0.000272889186106,9.81079977602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122842750000,13091,122842750000,RH_EXTIMU,3.11531801698e-06,1.43666023938e-05,-0.703415564277,0.710778828973,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.87434005842e-05,-1.26257965346e-06,-7.17746242495e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000282297901115,0.000209297094838,9.81005133178,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122845250000,13092,122845250000,RH_EXTIMU,3.11656639668e-06,1.43644574178e-05,-0.703415628053,0.710778765858,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.91779537708e-06,-5.16612611295e-07,-7.1780520009e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000260775399566,-0.000229131724908,9.81059034569,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122847750000,13093,122847750000,RH_EXTIMU,3.09329488053e-06,1.43698157731e-05,-0.703415691822,0.71077870275,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.62471501558e-05,-1.00481881654e-05,-7.17739815579e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000417776619802,0.00018720504644,9.80994480819,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122850250000,13094,122850250000,RH_EXTIMU,3.07807597555e-06,1.43774049991e-05,-0.703415755599,0.710778639634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.29236339308e-05,-4.2481973834e-06,-7.17829042554e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000279568204239,5.2968782122e-05,9.80944046207,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122852750000,13095,122852750000,RH_EXTIMU,3.07744589737e-06,1.43749053967e-05,-0.703415819392,0.710778576501,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04922004068e-06,-1.77532761824e-06,-7.18013846472e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000268514300522,-0.000198225800108,9.80824568709,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122855250000,13096,122855250000,RH_EXTIMU,3.10319664688e-06,1.43534254625e-05,-0.70341588321,0.710778513345,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.67308146934e-05,2.27737513832e-06,-7.18277207108e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000173318865784,-0.000662805213754,9.80928122577,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122859000000,13097,122857750000,RH_EXTIMU,3.1049046783e-06,1.43632710613e-05,-0.703415947035,0.710778450181,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.56832517219e-06,6.56016407688e-06,-7.18366893771e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000162876371336,1.35293052756e-05,9.80933015811,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122859000000,13098,122860250000,RH_EXTIMU,3.09816027178e-06,1.4364296653e-05,-0.703416010855,0.710778387022,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.41126689188e-06,-3.2115564772e-06,-7.18315251943e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00031867274444,-8.12938549681e-05,9.81104782034,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122862750000,13099,122862750000,RH_EXTIMU,3.08685315705e-06,1.43753605264e-05,-0.703416074683,0.710778323854,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.26545966737e-05,-7.11471157136e-08,-7.18407370646e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000242611877684,7.92404340565e-05,9.80954365054,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122865250000,13100,122865250000,RH_EXTIMU,3.09266463138e-06,1.43721266265e-05,-0.70341613852,0.710778260679,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.12524782076e-06,1.43200774154e-06,-7.18497157238e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000229588764287,-0.00026884258608,9.81052578679,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122867750000,13101,122867750000,RH_EXTIMU,3.06761210479e-06,1.43779790599e-05,-0.703416202348,0.710778197512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.75378997169e-05,-1.07694869481e-05,-7.18407817225e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000439030009494,0.000216875012299,9.81009413674,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122870250000,13102,122870250000,RH_EXTIMU,3.04951797764e-06,1.43793182933e-05,-0.703416266176,0.710778134345,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.10414704687e-05,-9.42007349263e-06,-7.18405545823e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000382519457993,2.40931754597e-06,9.81084678749,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122872750000,13103,122872750000,RH_EXTIMU,3.03769086127e-06,1.43728772539e-05,-0.703416330017,0.710778071165,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.09969056019e-06,-1.03174577551e-05,-7.18544488329e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000392183555955,-0.000139025179419,9.80862053667,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122875250000,13104,122875250000,RH_EXTIMU,3.0449936069e-06,1.43642848464e-05,-0.703416393862,0.710778007982,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.98862463582e-06,-7.75768110351e-07,-7.18587419664e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000232980338856,-0.000291402508269,9.81133680213,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122877750000,13105,122877750000,RH_EXTIMU,3.02308263421e-06,1.43782317801e-05,-0.703416457704,0.710777944801,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.03065839241e-05,-4.39892038123e-06,-7.18565186812e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000314125116104,0.000225544776268,9.81002935704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122880250000,13106,122880250000,RH_EXTIMU,3.02869975025e-06,1.43768317395e-05,-0.703416521568,0.710777881598,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.98275450784e-06,2.36541563283e-06,-7.18805604664e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000155364658779,-0.000296905626159,9.80888357387,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122882750000,13107,122882750000,RH_EXTIMU,3.03047689709e-06,1.43689250123e-05,-0.703416585432,0.710777818396,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.46079101612e-06,-3.49530968185e-06,-7.18807808651e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000371915640329,-0.000197825371445,9.81068188664,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122885250000,13108,122885250000,RH_EXTIMU,3.00800412467e-06,1.43792484292e-05,-0.703416649304,0.710777755185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.85869612173e-05,-6.77548032255e-06,-7.18896858162e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000321879332215,0.000197721493506,9.80837023924,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122887750000,13109,122887750000,RH_EXTIMU,3.03695213744e-06,1.43677853683e-05,-0.703416713205,0.710777691946,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.29120164375e-05,9.77243403563e-06,-7.19220952148e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.48295533922e-05,-0.00061524413124,9.80963931911,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122890250000,13110,122890250000,RH_EXTIMU,3.02906997873e-06,1.43707114058e-05,-0.703416777107,0.710777628706,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.1276608895e-06,-2.77117232347e-06,-7.19232693714e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000328495460039,1.6548872196e-05,9.80960739279,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122892750000,13111,122892750000,RH_EXTIMU,3.01455922686e-06,1.43682398465e-05,-0.703416841005,0.71077756547,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.85941737087e-06,-9.57049613132e-06,-7.19189916597e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00039269364261,-3.81474285936e-05,9.81088725985,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122895250000,13112,122895250000,RH_EXTIMU,2.99881393326e-06,1.43723311494e-05,-0.703416904907,0.710777502229,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.12545471867e-05,-6.53342589584e-06,-7.19243689979e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000332922941918,7.3311089923e-05,9.80998889267,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122897750000,13113,122897750000,RH_EXTIMU,3.00799327379e-06,1.4370751977e-05,-0.703416968832,0.710777438966,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.10911501842e-06,4.26814448639e-06,-7.19492728105e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000156049647558,-0.000330045638315,9.80942687736,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122900250000,13114,122900250000,RH_EXTIMU,2.99128777225e-06,1.43697137724e-05,-0.703417032751,0.710777375709,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.9139952574e-06,-9.99051907899e-06,-7.19429665383e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000436231547659,7.63127145516e-05,9.81012863405,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122902750000,13115,122902750000,RH_EXTIMU,2.97657690715e-06,1.43738669224e-05,-0.703417096675,0.710777312448,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.07011509828e-05,-5.91615215762e-06,-7.19478813373e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00030632563434,-2.64700628794e-07,9.81048461531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122905250000,13116,122905250000,RH_EXTIMU,2.96721954877e-06,1.4365803236e-05,-0.703417160601,0.710777249184,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.82204781328e-07,-9.8503137265e-06,-7.19504234163e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00043457741471,-0.000152581507937,9.8107227784,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122907750000,13117,122907750000,RH_EXTIMU,2.94137846742e-06,1.43718407678e-05,-0.703417224524,0.710777185922,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.80904401741e-05,-1.11080005426e-05,-7.19479454678e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000392421760592,0.000182603755124,9.81026644556,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122910250000,13118,122910250000,RH_EXTIMU,2.93966147325e-06,1.4377376565e-05,-0.703417288468,0.71077712264,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.09061616343e-06,2.18214113988e-06,-7.19710151885e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000144391410798,-0.000108730269228,9.80886891769,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122912750000,13119,122912750000,RH_EXTIMU,2.96486195568e-06,1.4363424446e-05,-0.703417352446,0.710777059325,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.21817552043e-05,6.24826422124e-06,-7.20080188584e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000172109605814,-0.000595615909746,9.80816482341,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122915250000,13120,122915250000,RH_EXTIMU,2.96677224449e-06,1.43569928498e-05,-0.703417416432,0.710776996002,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.70639411824e-06,-2.58158473826e-06,-7.20179628359e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00031105980049,-0.000165451991505,9.80912270091,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122917750000,13121,122917750000,RH_EXTIMU,2.96817584597e-06,1.43461336917e-05,-0.703417480434,0.710776932663,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.90982027169e-06,-5.38432203353e-06,-7.20359079663e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00032899300007,-0.000279416473695,9.80928035961,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122920250000,13122,122920250000,RH_EXTIMU,2.9473034254e-06,1.43417437484e-05,-0.703417544428,0.710776869331,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.39725290095e-06,-1.42412618402e-05,-7.20281099864e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000471680464738,7.95375237014e-05,9.81048092392,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122922750000,13123,122922750000,RH_EXTIMU,2.92260378001e-06,1.43490948814e-05,-0.703417608428,0.710776805994,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.81805984195e-05,-9.7187430958e-06,-7.20333284677e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00037183008053,0.000160470975952,9.8096350331,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122927750000,13124,122925250000,RH_EXTIMU,2.93051977434e-06,1.43346229029e-05,-0.703417672448,0.710776742637,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.26459627845e-05,-3.7738998838e-06,-7.20567212129e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000269597993922,-0.000451455422198,9.80971645472,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122927750000,13125,122927750000,RH_EXTIMU,2.92303054674e-06,1.43317844142e-05,-0.703417736472,0.710776679276,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.66033780901e-06,-5.82789292557e-06,-7.20602121602e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000345501082608,-4.3434549271e-05,9.81004821816,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122930250000,13126,122930250000,RH_EXTIMU,2.90415540953e-06,1.43294490171e-05,-0.703417800492,0.710776615919,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.4177159132e-06,-1.19490649516e-05,-7.20566894615e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000464862131608,1.05259869807e-05,9.81123804062,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122932750000,13127,122932750000,RH_EXTIMU,2.8594184142e-06,1.4326733899e-05,-0.703417864489,0.710776552585,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.39096373888e-05,-2.67183357228e-05,-7.2030959582e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000684771123527,0.000281156155883,9.8124331845,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122935250000,13128,122935250000,RH_EXTIMU,2.83469018716e-06,1.4322294784e-05,-0.703417928495,0.710776489242,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.15620744551e-05,-1.64390168125e-05,-7.20411364147e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000427344747126,-3.11202930491e-05,9.81019406198,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122935250000,13129,122937750000,RH_EXTIMU,2.82064766978e-06,1.43233049049e-05,-0.703417992511,0.710776425889,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.55242554443e-06,-7.32724991797e-06,-7.20514258793e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000323276697788,-8.4796663108e-07,9.80980445028,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122935250000,13130,122940250000,RH_EXTIMU,2.78970729521e-06,1.43157103315e-05,-0.70341805651,0.710776362552,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.33187471372e-05,-2.17290666216e-05,-7.2033793878e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000630418376269,0.000101626901268,9.81185251242,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122935250000,13131,122942750000,RH_EXTIMU,2.74335033516e-06,1.43248331908e-05,-0.703418120504,0.71077629922,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.14924181061e-05,-2.08986255068e-05,-7.2027959003e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000492747423115,0.000413778791108,9.8098200225,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122935250000,13132,122945250000,RH_EXTIMU,2.78397925179e-06,1.43670572966e-05,-0.703418184549,0.710776235838,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.57631061758e-07,4.68733936324e-05,-7.20841765804e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000756269567125,-0.00016472967437,9.81100909127,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122935250000,13133,122947750000,RH_EXTIMU,2.76100447212e-06,1.44433874609e-05,-0.703418248564,0.710776172483,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.60166855102e-05,3.04748168337e-05,-7.20526524152e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.66371416002e-05,0.000822087923166,9.81115629254,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122951500000,13134,122950250000,RH_EXTIMU,2.80082223121e-06,1.43668368574e-05,-0.703418312656,0.710776109057,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.57197653467e-05,-2.11208539797e-05,-7.21352743418e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000678125818021,-0.00154197107089,9.80342273194,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122951500000,13135,122952750000,RH_EXTIMU,2.8581328083e-06,1.42918693954e-05,-0.703418376794,0.710776045584,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.47756590554e-05,-1.03768313694e-05,-7.21883656725e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000277500728799,-0.00136368736523,9.80716305672,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122956500000,13136,122955250000,RH_EXTIMU,2.87231631436e-06,1.42836751596e-05,-0.703418440956,0.710775982086,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.26770967085e-05,3.32271709765e-06,-7.22155929035e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00019549712383,-0.000243634123727,9.80806820133,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122957750000,13137,122957750000,RH_EXTIMU,2.85650357836e-06,1.42833939982e-05,-0.703418505102,0.710775918604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.83235223208e-06,-9.05767227458e-06,-7.21987174463e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0004088893336,9.05878598361e-05,9.81201517027,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122960250000,13138,122960250000,RH_EXTIMU,2.8424226594e-06,1.4296599479e-05,-0.703418569268,0.710775855103,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.5437007772e-05,-4.14334025423e-07,-7.22206429739e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000231419916686,6.29988169174e-05,9.80929447095,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122962750000,13139,122962750000,RH_EXTIMU,2.8350458647e-06,1.43083928671e-05,-0.70341863343,0.710775791605,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.08302704195e-05,2.55536530122e-06,-7.22164367237e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000222048576803,7.04764790595e-05,9.81193019588,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122965250000,13140,122965250000,RH_EXTIMU,2.7903751059e-06,1.4319018371e-05,-0.703418697581,0.710775728117,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.13791787599e-05,-1.90953332913e-05,-7.22051621457e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000593222974386,0.000399004644104,9.81036909389,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122967750000,13141,122967750000,RH_EXTIMU,2.79119453375e-06,1.42990914048e-05,-0.703418761756,0.710775664607,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.16804209347e-05,-1.08691781625e-05,-7.22299002588e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000326403495711,-0.000458458197219,9.80997662119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122970250000,13142,122970250000,RH_EXTIMU,2.80332421948e-06,1.42868080988e-05,-0.703418825971,0.710775601056,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.38103111809e-05,-1.58157616086e-07,-7.2276465264e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00023333386094,-0.000418797803071,9.80686122875,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122972750000,13143,122972750000,RH_EXTIMU,2.8037608057e-06,1.42672623748e-05,-0.703418890187,0.710775537505,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12481925269e-05,-1.0867834274e-05,-7.22768326405e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000432545921795,-0.000267410186324,9.81058649012,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122975250000,13144,122975250000,RH_EXTIMU,2.76479707747e-06,1.42704344399e-05,-0.703418954399,0.710775473958,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.39397288454e-05,-2.01219756677e-05,-7.2272719891e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000595532340087,0.000311953116538,9.80969912569,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122977750000,13145,122977750000,RH_EXTIMU,2.78518889566e-06,1.4262585606e-05,-0.703419018649,0.710775410374,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.60128923597e-05,7.0127700479e-06,-7.23147769058e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.30380641091e-05,-0.000519264572465,9.80952185311,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122980250000,13146,122980250000,RH_EXTIMU,2.75341735442e-06,1.4250699989e-05,-0.703419082874,0.710775346813,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.1376614545e-05,-2.46367863584e-05,-7.22880422968e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000747726515127,0.0001230446445,9.81214347569,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122982750000,13147,122982750000,RH_EXTIMU,2.71481715911e-06,1.42443595112e-05,-0.703419147111,0.710775283242,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.83799709073e-05,-2.53264322461e-05,-7.23007602439e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000568056564599,0.000116957113263,9.80908083104,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122985250000,13148,122985250000,RH_EXTIMU,2.71667513193e-06,1.42287347398e-05,-0.703419211374,0.710775219644,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.84996202735e-06,-7.83842895901e-06,-7.23292854085e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000309043433596,-0.000357810461138,9.8090311196,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122987750000,13149,122987750000,RH_EXTIMU,2.71754023116e-06,1.42040848968e-05,-0.703419275656,0.710775156028,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.43641213617e-05,-1.35289916872e-05,-7.23515467837e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000460764018466,-0.000406554831677,9.80877730736,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122990250000,13150,122990250000,RH_EXTIMU,2.71310085273e-06,1.4195186786e-05,-0.703419339971,0.710775092379,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.48383138113e-06,-7.55725690014e-06,-7.23879868737e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000308098827761,-0.000151463216813,9.80642124791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122992750000,13151,122992750000,RH_EXTIMU,2.73707738058e-06,1.41479619784e-05,-0.703419404321,0.710775028695,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.02094783903e-05,-1.33599473303e-05,-7.24275621636e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000497370600341,-0.000889366676737,9.80816961882,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122992750000,13152,122995250000,RH_EXTIMU,2.69403949836e-06,1.41159970827e-05,-0.703419468645,0.710774965038,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.48355180476e-06,-4.23942452661e-05,-7.23985752431e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000945140740198,9.40845603792e-05,9.81203356541,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +122997750000,13153,122997750000,RH_EXTIMU,2.61622498563e-06,1.41107051562e-05,-0.703419532931,0.710774901418,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.12680677102e-05,-4.67975097683e-05,-7.2356144716e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000934741179725,0.000603109143015,9.81387949818,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123000250000,13154,123000250000,RH_EXTIMU,2.53249280039e-06,1.41105505655e-05,-0.703419597181,0.710774837833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.75239364748e-05,-4.72064037382e-05,-7.23166407434e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000922353864802,0.000635985884576,9.81406743698,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123002750000,13155,123002750000,RH_EXTIMU,2.45181728932e-06,1.41074747783e-05,-0.703419661397,0.710774774281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.4141989733e-05,-4.7147354833e-05,-7.2278257697e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000934317885765,0.000559568800549,9.81390730404,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123005250000,13156,123005250000,RH_EXTIMU,2.37356863309e-06,1.40992985497e-05,-0.703419725583,0.71077471076,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.98918318713e-05,-4.86818892178e-05,-7.22441936372e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000943094120151,0.000483959120747,9.81363544649,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123006500000,13157,123007750000,RH_EXTIMU,2.30820317866e-06,1.41013744974e-05,-0.703419789747,0.710774647261,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.83354552785e-05,-3.56024607624e-05,-7.22184615647e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000664041073634,0.000466469529226,9.81313140557,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123010250000,13158,123010250000,RH_EXTIMU,2.18754140282e-06,1.41094819931e-05,-0.703419853952,0.71077458372,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.31722016968e-05,-6.32900246327e-05,-7.2266315196e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00147019112226,0.00125813911724,9.79681800071,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123012750000,13159,123012750000,RH_EXTIMU,2.33540592894e-06,1.41773997205e-05,-0.703419918201,0.710774520134,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.5859771734e-05,0.000121828635486,-7.23135150973e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00313076001713,-0.000803290445405,9.83288211176,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123015250000,13160,123015250000,RH_EXTIMU,1.89708771093e-06,1.49875488315e-05,-0.703419981916,0.710774457063,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000705135513477,0.000214009860726,-7.17288477091e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00224112442446,0.0132831935143,9.86017780789,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123017750000,13161,123017750000,RH_EXTIMU,1.54823469309e-06,1.53813158435e-05,-0.703420045453,0.710774394176,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000419950661838,2.75921381492e-05,-7.15222277002e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000508414897296,0.00574206384664,9.83280009956,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123020250000,13162,123020250000,RH_EXTIMU,1.42787993464e-06,1.54080145406e-05,-0.70342010898,0.710774331306,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.34595238081e-05,-5.25458646188e-05,-7.15029338391e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00123034913192,0.000397763019088,9.81486833802,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123027750000,13163,123022750000,RH_EXTIMU,1.44338885589e-06,1.51249039722e-05,-0.703420172722,0.710774268229,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000168136065777,-0.000152254045595,-7.17402325153e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00314510300063,-0.00406398216802,9.76967036558,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123027750000,13164,123025250000,RH_EXTIMU,2.09354443169e-06,1.42082496885e-05,-0.703420237149,0.710774204486,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000885526427821,-0.000155360687372,-7.24958317446e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0018863002175,-0.0163286479249,9.74983302371,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123027750000,13165,123027750000,RH_EXTIMU,2.47517219291e-06,1.3973564201e-05,-0.70342030166,0.710774140646,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000349067791934,8.13096573087e-05,-7.26031557121e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00227883661769,-0.00395475732979,9.81235715406,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123030250000,13166,123030250000,RH_EXTIMU,2.16340951027e-06,1.46035700336e-05,-0.703420365749,0.710774077208,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000531800554551,0.000182793905486,-7.2145577655e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00203162431538,0.0105877259136,9.84813479249,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123032750000,13167,123032750000,RH_EXTIMU,4.24585799856e-06,2.01069248322e-05,-0.703420440324,0.710774003261,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00191281615493,0.00430118361957,-8.40028657321e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0713794541531,0.0395672635701,9.75759755592,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123035250000,13168,123035250000,RH_EXTIMU,7.30653459392e-06,2.26224759769e-05,-0.703420515659,0.710773928605,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000324768875374,0.0031527456138,-8.48071937136e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0312145912063,-0.00809749439903,9.7813298953,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123037750000,13169,123037750000,RH_EXTIMU,5.2575607051e-06,2.14341627423e-05,-0.703420596753,0.710773848405,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000496376713437,-0.00182872889099,-9.12731393999e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0273948376931,0.00469450777749,9.80774138481,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123040250000,13170,123040250000,RH_EXTIMU,5.91139437658e-06,2.14288536412e-05,-0.7034206708,0.710773775119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000374771502748,0.000364918146205,-8.3334397837e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000309486589661,-0.00176023759565,9.83373581569,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123042750000,13171,123042750000,RH_EXTIMU,7.96155587249e-06,2.14124981433e-05,-0.703420744796,0.710773701869,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00117496627206,0.00114440163832,-8.32604523106e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0428411059742,-0.0339737846962,9.84449778759,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123045250000,13172,123045250000,RH_EXTIMU,4.71227740374e-06,2.1269364146e-05,-0.703420825543,0.710773621991,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00176705271822,-0.00190987575534,-9.09196808973e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0508299108618,0.0397074487931,9.78250417538,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123047750000,13173,123047750000,RH_EXTIMU,5.62681758473e-06,2.15745776449e-05,-0.703420899496,0.710773548787,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000348271538724,0.000688196417304,-8.32314449293e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00821268844652,-0.00255220988039,9.81604629331,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123050250000,13174,123050250000,RH_EXTIMU,8.04910383275e-06,2.15591698839e-05,-0.703420973519,0.710773475507,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00138602971452,0.00135434920564,-8.3286375133e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0421997701797,-0.037832228569,9.83832921798,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123052750000,13175,123052750000,RH_EXTIMU,4.95358930315e-06,2.15786838539e-05,-0.703421054407,0.710773395484,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00177114701475,-0.00173086300601,-9.10795660214e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0450586202873,0.0403493098893,9.77296744916,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123055250000,13176,123055250000,RH_EXTIMU,5.97792920109e-06,2.1810365959e-05,-0.703421128591,0.710773322051,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000452084353043,0.000708173555716,-8.34893546721e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00510501678309,-0.00451558662627,9.81739655957,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123057750000,13177,123057750000,RH_EXTIMU,8.63551430249e-06,2.21036510164e-05,-0.70342120302,0.710773248356,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00134611179914,0.00166228949461,-8.37470825567e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.050377619798,-0.0368780851787,9.83012373508,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123060250000,13178,123060250000,RH_EXTIMU,5.41443431655e-06,2.18955247005e-05,-0.703421284092,0.710773168161,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00171444362947,-0.00193096440312,-9.12840100866e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0522871823374,0.0393193769542,9.77947310045,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123062750000,13179,123062750000,RH_EXTIMU,6.20522219585e-06,2.20217802164e-05,-0.703421358374,0.710773094637,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000378609610951,0.000516797812939,-8.35989314195e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00403546649562,-0.00307801312206,9.82035164835,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123065250000,13180,123065250000,RH_EXTIMU,8.94371628212e-06,2.24512974904e-05,-0.703421432983,0.710773020757,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0013154547148,0.0017852845729,-8.39526370654e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.052922666077,-0.0364716981771,9.82894526048,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123067750000,13181,123067750000,RH_EXTIMU,5.93122117231e-06,2.24751943968e-05,-0.703421514299,0.710772940313,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00172640584023,-0.0016816538175,-9.15616566591e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0464986120378,0.0396410830714,9.77130954309,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123070250000,13182,123070250000,RH_EXTIMU,9.49260789732e-06,2.27912163164e-05,-0.703421589148,0.710772866189,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00184723425509,0.00218382167532,-8.42096694623e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0524921090735,-0.0424856225678,9.8378106521,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123072750000,13183,123072750000,RH_EXTIMU,6.4525872114e-06,2.28804103703e-05,-0.703421670726,0.710772785486,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00177880209124,-0.00166001472294,-9.18580029395e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0451302855376,0.0411410293542,9.77142226877,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123075250000,13184,123075250000,RH_EXTIMU,6.2763558448e-06,2.27880362571e-05,-0.703421752384,0.710772704677,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.82240931882e-05,-0.000151696516779,-9.19091608316e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000319311605575,-0.00113372633945,9.80577955604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123077750000,13185,123077750000,RH_EXTIMU,6.28215220719e-06,2.29072826591e-05,-0.703421834028,0.710772623874,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.38065993999e-05,7.10685632067e-05,-9.18956496256e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00359375369507,0.00127958511808,9.80474882064,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123080250000,13186,123080250000,RH_EXTIMU,6.66663366713e-06,2.31394198517e-05,-0.703421915897,0.710772542841,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,8.79927286228e-05,0.000348360605668,-9.21465837328e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00338438770038,-0.00212235081593,9.80691888742,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123082750000,13187,123082750000,RH_EXTIMU,7.56855761586e-06,2.39575892829e-05,-0.703421998252,0.710772461301,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.24375351066e-05,0.000972773421436,-9.27019333679e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0169190218163,-0.00115257136599,9.79020959302,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123085250000,13188,123085250000,RH_EXTIMU,7.95077475291e-06,2.40930639071e-05,-0.703422080689,0.710772379708,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000141100941581,0.000292122324234,-9.27838446281e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000460896877703,-0.00250926695709,9.80806961693,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123087750000,13189,123087750000,RH_EXTIMU,8.61553098784e-06,2.47745062573e-05,-0.703422163492,0.71077229773,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.47886244435e-06,0.000761564745287,-9.32065893849e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0142863072536,6.96616878557e-05,9.79311038356,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123090250000,13190,123090250000,RH_EXTIMU,8.93184113601e-06,2.48928823043e-05,-0.703422246353,0.710772215718,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000113247132081,0.000245311441267,-9.3262452633e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000776347885156,-0.00213536748799,9.81046756915,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123092750000,13191,123092750000,RH_EXTIMU,8.96721077865e-06,2.51275880475e-05,-0.703422329199,0.71077213372,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000111963749694,0.000153362732586,-9.32521378056e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00501027400887,0.00237552403972,9.80349977796,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123095250000,13192,123095250000,RH_EXTIMU,9.72055764022e-06,2.56545354631e-05,-0.703422412463,0.710772051288,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00013183536736,0.000723569494132,-9.37216636297e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00855603235521,-0.00322096812995,9.80339394337,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123097750000,13193,123097750000,RH_EXTIMU,9.98177633542e-06,2.59958761782e-05,-0.703422495778,0.710771968819,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.35494579491e-05,0.000341091064629,-9.37797836935e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0064787200755,0.00128474009456,9.79886879754,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123100250000,13194,123100250000,RH_EXTIMU,1.08295305799e-05,2.65559534967e-05,-0.703422579556,0.710771885873,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000166873579273,0.000795534387861,-9.43013305263e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00924016706007,-0.00372099964976,9.80107077551,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123102750000,13195,123102750000,RH_EXTIMU,1.11538094183e-05,2.69630968492e-05,-0.703422663405,0.710771802872,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.47219361778e-05,0.000413993921329,-9.43825302473e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00773107983127,0.00141818176426,9.79714463279,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123105250000,13196,123105250000,RH_EXTIMU,1.2086886687e-05,2.75820393982e-05,-0.703422747752,0.710771719357,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000182264001517,0.000877020735978,-9.4943673232e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0100926440247,-0.00403141649797,9.80045558413,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123107750000,13197,123107750000,RH_EXTIMU,1.24310694297e-05,2.80293921912e-05,-0.703422832167,0.710771635791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.6031546079e-05,0.000448058375238,-9.50222320358e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00839360055724,0.00171817506498,9.79598105061,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123110250000,13198,123110250000,RH_EXTIMU,1.34455963434e-05,2.86982356194e-05,-0.703422917124,0.710771551668,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00020049651399,0.000951230107495,-9.56317240104e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0108791038199,-0.00443496584268,9.7999773554,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123112750000,13199,123112750000,RH_EXTIMU,1.31656917123e-05,2.8416840395e-05,-0.703423001788,0.710771467896,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.03874640921e-07,-0.00031751822933,-9.528629688e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00856550294788,0.000558167654955,9.81751776796,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123115250000,13200,123115250000,RH_EXTIMU,1.31893911541e-05,2.8616315169e-05,-0.703423086508,0.710771384043,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.87733966925e-05,0.000126762382333,-9.53618479988e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00361863786096,0.00148291836014,9.80927775524,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123117750000,13201,123117750000,RH_EXTIMU,1.43771037084e-05,2.97476414988e-05,-0.703423171883,0.710771299481,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.8715676616e-05,0.00131166408474,-9.6116649177e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0225942284776,-0.00130328256555,9.78597373531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123120250000,13202,123120250000,RH_EXTIMU,1.54857197826e-05,3.06817241825e-05,-0.703423257717,0.710771214472,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000104736687282,0.00115499735446,-9.6629187454e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0173888004594,-0.00145213826893,9.78374574864,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123122750000,13203,123122750000,RH_EXTIMU,1.68025887137e-05,3.1518004012e-05,-0.703423344197,0.71077112882,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000278190261732,0.00121657692188,-9.73514813249e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0139498462745,-0.00538282081517,9.79159714323,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123125250000,13204,123125250000,RH_EXTIMU,1.68390174119e-05,3.14453742003e-05,-0.703423430533,0.710771043378,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.15889029676e-05,-2.0797707407e-05,-9.71717751983e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00474418238558,-0.000471473968904,9.81262596608,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123127750000,13205,123127750000,RH_EXTIMU,1.65868034224e-05,3.13658441679e-05,-0.703423516691,0.71077095812,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.86551738599e-05,-0.000187151714865,-9.69739734402e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00348781858569,0.0017661148487,9.81953277764,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123130250000,13206,123130250000,RH_EXTIMU,1.63704849721e-05,3.13510480145e-05,-0.703423602699,0.710770873006,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000114672640251,-0.000130143134454,-9.68079979992e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00240356849541,0.00171271627114,9.81965821838,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123132750000,13207,123132750000,RH_EXTIMU,1.88070006445e-05,3.40230340568e-05,-0.703423690108,0.710770786319,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000118183613823,0.00289045901692,-9.84582831722e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0568657698852,0.00167075269588,9.74372121982,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123135250000,13208,123135250000,RH_EXTIMU,2.17602206541e-05,3.59144033875e-05,-0.703423778827,0.710770698339,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000614906550076,0.00273735704644,-9.99050119083e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0318304883728,-0.0115914102835,9.76603050644,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123137750000,13209,123137750000,RH_EXTIMU,2.23694152591e-05,3.60581036394e-05,-0.703423867609,0.710770610448,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000265536481359,0.000424528899271,-9.99273728585e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00209610175652,-0.00341227546802,9.80163771551,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123140250000,13210,123140250000,RH_EXTIMU,2.12746262218e-05,3.53891997966e-05,-0.703423955493,0.71077052354,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000246092664929,-0.000996429410894,-9.88988034049e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0200587169285,0.00542249552566,9.85047020224,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123142750000,13211,123142750000,RH_EXTIMU,2.12563187235e-05,3.59058174257e-05,-0.703424043498,0.71077043642,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00030112694269,0.000283455888545,-9.90759385508e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00962192196621,0.00417813608875,9.80611749829,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123145250000,13212,123145250000,RH_EXTIMU,2.16130011171e-05,3.61305749573e-05,-0.703424131698,0.710770349109,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.63395773339e-05,0.000328520992516,-9.9278505525e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00265521450267,-0.00197820131938,9.80750018471,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123147750000,13213,123147750000,RH_EXTIMU,2.3757004233e-05,3.77784061881e-05,-0.703424221133,0.710770260445,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000291819790449,0.00214349950388,-0.000100715787487,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0325782238626,-0.006816056506,9.77539699278,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123150250000,13214,123150250000,RH_EXTIMU,2.23868001275e-05,3.64017291495e-05,-0.703424309481,0.710770173125,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.40555450898e-06,-0.00155386772253,-9.93897807181e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0330581925872,0.00234733745812,9.83805203074,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123152750000,13215,123152750000,RH_EXTIMU,2.14087452426e-05,3.59605741011e-05,-0.703424397445,0.710770086123,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000307878323852,-0.000801236987531,-9.89978354035e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00799107479379,0.00512588633904,9.83140213346,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123155250000,13216,123155250000,RH_EXTIMU,2.10999504457e-05,3.59514444829e-05,-0.703424485251,0.710769999234,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000170444072475,-0.00017896128699,-9.88322395625e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00188182213746,0.00224823110093,9.82230046044,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123157750000,13217,123157750000,RH_EXTIMU,2.02136935757e-05,3.52028991107e-05,-0.703424572575,0.710769912876,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.26997520522e-05,-0.000924365691237,-9.82639232654e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0176360498013,0.00107005519929,9.83467371802,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123160250000,13218,123160250000,RH_EXTIMU,1.88245389599e-05,3.46830124601e-05,-0.703424658867,0.71076982754,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00049733079805,-0.00107734721707,-9.71194731301e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0163568866188,0.00924362123786,9.86167007464,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123164000000,13219,123162750000,RH_EXTIMU,2.1759618943e-05,3.78174716479e-05,-0.70342474715,0.710769739925,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.49479042175e-05,0.00343399042329,-9.94698741602e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0682376173519,-0.00111020878727,9.72657968363,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123165250000,13220,123165250000,RH_EXTIMU,2.25733018363e-05,3.74210516419e-05,-0.70342483549,0.710769652494,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000685758451386,0.000232482178453,-9.9400565566e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0155556183118,-0.0116597037213,9.81479295792,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123167750000,13221,123167750000,RH_EXTIMU,2.42236105144e-05,3.98070901067e-05,-0.703424924889,0.710769563834,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000404323233726,0.0022854345124,-0.000100720191786,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0569909754961,0.00980072628148,9.71911556469,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123170250000,13222,123170250000,RH_EXTIMU,2.83615608972e-05,4.13091862075e-05,-0.703425016432,0.710769472999,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00150761855702,0.00318270642089,-0.000103066197355,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0194829587951,-0.0317806798294,9.80247028449,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123174000000,13223,123172750000,RH_EXTIMU,2.460465607e-05,3.88062152483e-05,-0.70342510535,0.710769385281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000727707772057,-0.00353738807021,-9.99899232312e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0550923293762,0.019734109002,9.85033758604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123175250000,13224,123175250000,RH_EXTIMU,2.55703712585e-05,4.0294018727e-05,-0.70342519514,0.710769296302,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00028812148329,0.0013894357726,-0.000101127660686,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0321464688481,0.00192683012302,9.80556985167,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123177750000,13225,123177750000,RH_EXTIMU,2.42087083515e-05,3.88696163169e-05,-0.703425283861,0.710769208624,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.73105391179e-05,-0.00157619858437,-9.98027522842e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0383608328868,-0.000492898432696,9.86062859367,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123181500000,13226,123180250000,RH_EXTIMU,2.27140140575e-05,3.80965312405e-05,-0.703425371968,0.710769121519,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000414855646206,-0.00128071165847,-9.91476916956e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0143836267804,0.00695670862075,9.83587092802,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123181500000,13227,123182750000,RH_EXTIMU,2.30678995678e-05,3.89485483049e-05,-0.703425460331,0.710769034011,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000278235338531,0.000683616634976,-9.94932784569e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0180971517267,0.00440512015682,9.80130944804,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123185250000,13228,123185250000,RH_EXTIMU,2.64903143661e-05,4.27267919942e-05,-0.703425550424,0.710768944512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000180128618133,0.00407429898389,-0.000101556373222,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0767014327979,0.00322404369252,9.71669291807,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123187750000,13229,123187750000,RH_EXTIMU,3.24294600365e-05,4.66483886838e-05,-0.703425643561,0.710768851845,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00117025233901,0.00557207795539,-0.000104986348904,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0730533589123,-0.023216768428,9.71193215224,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123190250000,13230,123190250000,RH_EXTIMU,3.21681512095e-05,4.51740471699e-05,-0.703425736051,0.710768760417,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000681093386278,-0.000985380871486,-0.000104013259522,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0401780163515,-0.00904582869158,9.83002105395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123192750000,13231,123192750000,RH_EXTIMU,4.00421106714e-05,5.34882110022e-05,-0.70342583319,0.710768663305,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000201459915963,0.0091585559309,-0.000109813361252,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.180751684918,0.00265968843341,9.58486841731,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123195250000,13232,123195250000,RH_EXTIMU,4.64498277333e-05,5.70646726172e-05,-0.703425932758,0.710768564098,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00163091063816,0.00563951349937,-0.000112284134303,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0540302718324,-0.0278233972597,9.71856690669,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123197750000,13233,123197750000,RH_EXTIMU,4.72682763009e-05,5.70920940471e-05,-0.70342603237,0.710768465459,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00044995906743,0.000476167391383,-0.000112112305704,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00928682517139,-0.0043802411161,9.79897926193,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123200250000,13234,123200250000,RH_EXTIMU,4.01412963808e-05,5.10475774403e-05,-0.703426127681,0.71076837203,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000651001911284,-0.007447643338,-0.000106868433661,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.136472090717,0.0154626788463,9.99432353075,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123202750000,13235,123202750000,RH_EXTIMU,3.82499208687e-05,5.21241998684e-05,-0.703426222375,0.710768278341,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00168131651572,-0.000452170240345,-0.000106678697346,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0275604391708,0.0271822341844,9.82984525763,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123207750000,13236,123205250000,RH_EXTIMU,4.36641108509e-05,5.77636763738e-05,-0.70342631993,0.710768181045,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.49698844311e-05,0.0062534764424,-0.000110170541359,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.114082155319,-0.00165813261552,9.68296602062,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123207750000,13237,123207750000,RH_EXTIMU,4.86724975991e-05,5.92034984212e-05,-0.703426419992,0.710768081573,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00203760267056,0.0036371297068,-0.000112692986853,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.015052249122,-0.0402041479024,9.78106817967,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123207750000,13238,123210250000,RH_EXTIMU,5.81823971692e-05,6.90709455535e-05,-0.7034265251,0.710767975946,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000145342858762,0.0109623857724,-0.000119140247228,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.211281867733,0.00657137373448,9.50072260659,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123207750000,13239,123212750000,RH_EXTIMU,5.2471751541e-05,6.02229744983e-05,-0.70342662575,0.710767877584,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0017319729392,-0.00824469852062,-0.000112486927908,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.219249934234,-0.0257660298002,10.0748043755,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123207750000,13240,123215250000,RH_EXTIMU,4.80411097569e-05,6.16206102086e-05,-0.703426724618,0.710767779931,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00330582476073,-0.00169858891163,-0.000111443220121,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0475390649389,0.0641974174792,9.7634392366,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123217750000,13241,123217750000,RH_EXTIMU,5.65403888995e-05,6.69514635574e-05,-0.703426827985,0.710767676524,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00183292831525,0.00781409623602,-0.000116753760617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0939438642522,-0.0470820905023,9.77663629983,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123220250000,13242,123220250000,RH_EXTIMU,5.62979214737e-05,6.83687973346e-05,-0.703426930573,0.71076757488,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000935452797198,0.000669470358624,-0.000115609235732,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0246539212833,0.0282372522196,9.69799938453,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123222750000,13243,123222750000,RH_EXTIMU,5.9699704723e-05,6.96249134711e-05,-0.70342703489,0.710767471241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00122744342297,0.0026285710261,-0.000117508158052,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0135521281045,-0.0273810673883,9.8373169093,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123225250000,13244,123225250000,RH_EXTIMU,6.32175933014e-05,7.51803462117e-05,-0.703427140736,0.710767365618,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00112594170886,0.00513855987795,-0.000119693374766,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.115315759234,0.026163697415,9.63222817346,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123227750000,13245,123227750000,RH_EXTIMU,7.71762916189e-05,8.55281912039e-05,-0.703427253573,0.710767251398,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00211395833513,0.0137390713804,-0.000128121058392,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.200385155121,-0.0445974424524,9.57660685192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123230250000,13246,123230250000,RH_EXTIMU,8.12963973184e-05,8.6046063389e-05,-0.70342736783,0.710767137799,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00205133546717,0.00261302569934,-0.000128644758756,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0171781844429,-0.032437190033,9.78549831312,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123232750000,13247,123232750000,RH_EXTIMU,7.23543733367e-05,7.22937193277e-05,-0.703427475315,0.710767033922,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00265447686926,-0.0128518227357,-0.000119294906847,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.265367787735,-0.0551977488642,10.5013547044,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123235250000,13248,123235250000,RH_EXTIMU,3.46705267159e-05,3.86222841282e-05,-0.703427544001,0.710766971409,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00247921099959,-0.0403523197482,-7.44646716606e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.721348921339,0.0242973211254,11.5941462612,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123237750000,13249,123237750000,RH_EXTIMU,-2.16639387805e-05,7.46222826783e-06,-0.703427582568,0.710766934767,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0144974664917,-0.0494198025634,-4.34261947147e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.821136855561,0.15304864717,10.7585492701,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123240250000,13250,123240250000,RH_EXTIMU,-4.31602414881e-05,3.72985583079e-05,-0.703475813917,0.710719196293,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0290137864184,0.00486958857755,-0.0542890570965,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.52376453702,-0.966135431648,12.4857610646,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123244000000,13251,123242750000,RH_EXTIMU,-0.000351700411324,0.00050275944347,-0.70372548898,0.710471716326,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.437381844015,0.0910251632368,-0.281229180291,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.692136561126,4.22333736335,25.1962740488,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123245250000,13252,123245250000,RH_EXTIMU,-0.00102746097185,0.00147130823294,-0.704136562864,0.710062307417,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.929311111149,0.170341648318,-0.464133701087,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.434537990824,2.57133895357,22.6611619698,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123249000000,13253,123247750000,RH_EXTIMU,-0.00204802396578,0.00290765531002,-0.704649006195,0.709547129659,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.38865937772,0.242051908048,-0.581318721227,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.403804952217,2.04871488447,22.4881219715,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123250250000,13254,123250250000,RH_EXTIMU,-0.00338969781313,0.00477896940546,-0.705200349234,0.708983877702,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.81612249922,0.308114950754,-0.630534567781,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.397320905238,1.67389206312,22.4150615136,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123252750000,13255,123252750000,RH_EXTIMU,-0.00502824900768,0.00705499744825,-0.705731417456,0.708426502989,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.21289393813,0.370099842027,-0.615757018835,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.414744010841,1.44282208423,22.3634067171,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123255250000,13256,123255250000,RH_EXTIMU,-0.0069397398825,0.00970771200621,-0.706190421056,0.707921386559,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.58044990455,0.428901367669,-0.545436136611,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.420202325467,1.30619369163,22.0774539414,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123257750000,13257,123257750000,RH_EXTIMU,-0.00910132254894,0.0127107314749,-0.706535758637,0.707504646629,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.92038585448,0.484685031184,-0.431131768078,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.438901727516,1.2231181317,21.9742128923,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123260250000,13258,123260250000,RH_EXTIMU,-0.0114919425868,0.0160388841141,-0.706737567994,0.707200607634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.23443764157,0.537062478917,-0.286153941353,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.451529698072,1.18273096192,21.8222549241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123262750000,13259,123262750000,RH_EXTIMU,-0.0140927005425,0.0196678425456,-0.706778198725,0.707021321862,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.52432175478,0.585354527988,-0.12436164795,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.468311706077,1.16155091121,21.8280788066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123265250000,13260,123265250000,RH_EXTIMU,-0.0168868903013,0.0235739336431,-0.70665170916,0.706967088717,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.79164965584,0.628883504162,0.0409535198198,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.454732031813,1.2025415823,21.352027711,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123267750000,13261,123267750000,RH_EXTIMU,-0.0198596422125,0.027733966218,-0.706362640958,0.707027751356,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.03771522354,0.667198420386,0.197920561394,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.417997582832,1.2816160726,20.8126383248,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123272750000,13262,123270250000,RH_EXTIMU,-0.0229974936147,0.0321252386835,-0.705924210732,0.707184624429,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.2635590955,0.700189595478,0.336782167833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.374956005716,1.39045548859,20.2143858921,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123272750000,13263,123272750000,RH_EXTIMU,-0.0262879233157,0.0367256039323,-0.705356165336,0.707412789767,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.46998560209,0.728100003345,0.450299578771,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.30429737983,1.4389280155,19.3429632583,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123275250000,13264,123275250000,RH_EXTIMU,-0.0297188805761,0.0415134637318,-0.704682460537,0.707683580619,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.65752587102,0.751437325954,0.533963376018,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.226156546406,1.55607271296,18.1929322287,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123277750000,13265,123277750000,RH_EXTIMU,-0.033278377655,0.0464676223796,-0.703929089745,0.707966910428,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.82639935991,0.77081305018,0.585820242854,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.109819314528,1.80328289582,17.208210139,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123280250000,13266,123280250000,RH_EXTIMU,-0.0369542872923,0.0515672467965,-0.703121970839,0.708233502336,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.97669698839,0.786835771516,0.606381446096,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0210335676677,2.07914852424,16.1835888214,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123282750000,13267,123282750000,RH_EXTIMU,-0.0407342194854,0.0567917371177,-0.702285169021,0.708456747678,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.10838023477,0.799981758256,0.598217346378,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.167542809346,2.38240263266,15.1253162521,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123285250000,13268,123285250000,RH_EXTIMU,-0.0446054804675,0.0621205992803,-0.701439513211,0.708614134465,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.22133204824,0.810528988575,0.565486059387,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.333349743887,2.71077878826,14.0424611761,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123287750000,13269,123287750000,RH_EXTIMU,-0.048555080724,0.0675333487925,-0.700601659675,0.708688200408,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.31540293493,0.818543220802,0.513407418543,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.513517174749,3.06216150203,12.9425436593,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123290250000,13270,123290250000,RH_EXTIMU,-0.0525697507747,0.0730094866611,-0.699783593301,0.708667029505,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.39045425505,0.82392502635,0.447756946502,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.734869594916,3.32196079731,11.7051321478,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123292750000,13271,123292750000,RH_EXTIMU,-0.0566359572819,0.0785285419683,-0.698992559255,0.708544309514,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.44639139191,0.826473113856,0.374375790845,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.955363672511,3.60027684557,10.4647588514,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123299000000,13272,123295250000,RH_EXTIMU,-0.0607399216071,0.0840701808927,-0.698231417027,0.708318964086,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.48319522165,0.825962014894,0.298695125262,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.29006765123,3.52088866302,8.67365811006,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123299000000,13273,123297750000,RH_EXTIMU,-0.0648675941308,0.0896142833104,-0.697499222176,0.707994569557,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.5008721207,0.822183190494,0.225489193417,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.5460725741,3.4548842708,6.88723203617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123299000000,13274,123300250000,RH_EXTIMU,-0.069004723136,0.0951411058719,-0.69679226657,0.707578303374,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.49954415334,0.815015352535,0.158354253652,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.81149705677,3.88849442084,5.84356938906,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123299000000,13275,123302750000,RH_EXTIMU,-0.0731369161087,0.100631529419,-0.69610488074,0.707080109887,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.47949267128,0.804478652674,0.0999733412604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.05675813349,4.31881248513,4.84548969631,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123305250000,13276,123305250000,RH_EXTIMU,-0.0772497229608,0.106067170621,-0.695430364011,0.706511744014,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.44108801411,0.790688072325,0.0519708855192,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.30760802698,4.38185573901,4.19221655644,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123322750000,13277,123307750000,RH_EXTIMU,-0.0813290011253,0.111430649612,-0.694761857243,0.705885802112,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.38503713619,0.773811500998,0.0149270362576,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.55280626248,4.43391871878,3.58827703675,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123322750000,13278,123310250000,RH_EXTIMU,-0.0853610783205,0.116705583336,-0.694093143192,0.705214862081,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.31211255914,0.754041509065,-0.0115198290214,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.78759300986,4.83497532291,2.75200720919,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123322750000,13279,123312750000,RH_EXTIMU,-0.0893326940333,0.121876325796,-0.693419320915,0.704510806424,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.22288349957,0.731575080541,-0.0284964436084,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.01551776334,5.21865450926,1.98306961589,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123322750000,13280,123315250000,RH_EXTIMU,-0.0932312770529,0.126928049807,-0.692737200103,0.703784321185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.11810771087,0.706602535321,-0.0376468830153,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.87200053425,3.88070995891,2.47706553182,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123322750000,13281,123317750000,RH_EXTIMU,-0.0970456537242,0.131847363466,-0.692045443834,0.703044463394,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.99929012325,0.67935697936,-0.0409581079386,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.06577279209,4.21621572368,1.82182996951,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123322750000,13282,123320250000,RH_EXTIMU,-0.100765700071,0.136621712266,-0.691344743494,0.702298531303,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.8673899933,0.649994180136,-0.0405953854745,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.57199008869,2.89619603961,3.01991921036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123322750000,13283,123322750000,RH_EXTIMU,-0.104382882867,0.141240064066,-0.690637501886,0.701552064394,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.72407450871,0.618771070111,-0.0385486173454,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.38865872806,2.27283036316,3.59352011724,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123325250000,13284,123325250000,RH_EXTIMU,-0.107890162687,0.145692808761,-0.68992756456,0.700809013877,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.57090945548,0.585936406514,-0.0365591254878,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.2067233896,1.61921563447,4.20596244243,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123329000000,13285,123327750000,RH_EXTIMU,-0.111281805591,0.149971565117,-0.689219907519,0.700072002355,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.40925683942,0.551707748714,-0.0360436997475,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.33995428746,1.84792465738,3.71202842259,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123330250000,13286,123330250000,RH_EXTIMU,-0.114552753141,0.154068413118,-0.688520494962,0.699342633367,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.23968853763,0.516193758027,-0.0381609471967,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.10579356168,1.45251373187,4.13906572692,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123332750000,13287,123332750000,RH_EXTIMU,-0.117698925608,0.157976532262,-0.687835743838,0.698621762948,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.06333681669,0.479628766878,-0.0435989065447,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.87412621672,1.03147432729,4.60127478767,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123332750000,13288,123335250000,RH_EXTIMU,-0.12071708659,0.161690258566,-0.687172065651,0.697909877763,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.88131169973,0.442272122884,-0.0525578571342,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.96430254525,1.19229401999,4.21716717697,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123337750000,13289,123337750000,RH_EXTIMU,-0.123604358209,0.16520453158,-0.686535710028,0.697207389687,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.69414164802,0.404289397763,-0.0649779957617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.05407249986,1.33260643385,3.87779223912,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123340250000,13290,123340250000,RH_EXTIMU,-0.126358119809,0.168514965393,-0.685932501859,0.696514849009,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.50235350366,0.365885136072,-0.0805143089928,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.73273025144,0.732280820534,4.4993082815,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123342750000,13291,123342750000,RH_EXTIMU,-0.128976219885,0.17161865853,-0.685367417383,0.695833079077,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.30708306805,0.327532019457,-0.0984567965042,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.41275443455,0.106180182045,5.14944197346,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123345250000,13292,123345250000,RH_EXTIMU,-0.131456222677,0.174514895094,-0.684844515555,0.695163148063,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3.10944713499,0.290492625374,-0.117892786675,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.46254032292,0.173370231142,4.89115510269,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123347750000,13293,123347750000,RH_EXTIMU,-0.133803809307,0.177195540195,-0.684365344898,0.694508715462,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.90995244627,0.245578251299,-0.137907626693,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.45612408488,0.221288007197,4.66652384504,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123350250000,13294,123350250000,RH_EXTIMU,-0.136016554103,0.17966158592,-0.683932177651,0.693871737375,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.70915096752,0.202620104147,-0.157767902932,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.779300496057,-1.22363624832,6.15778881611,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123352750000,13295,123352750000,RH_EXTIMU,-0.13808808236,0.181919113606,-0.683546788705,0.693253853408,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.50772636476,0.166592725704,-0.176234806821,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0213329462395,-2.68532947022,7.65142932917,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123355250000,13296,123355250000,RH_EXTIMU,-0.140021921303,0.183970722581,-0.683207784305,0.692658471581,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.30952207249,0.129532417558,-0.192364066922,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.500844068491,-3.55339290796,9.34772245355,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123357750000,13297,123357750000,RH_EXTIMU,-0.141819580162,0.185819890375,-0.68291337694,0.692089224464,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.11392159165,0.0929349334934,-0.20542654467,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.01018828385,-4.32103412374,10.9981302134,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123360250000,13298,123360250000,RH_EXTIMU,-0.143483373282,0.187471922997,-0.682660762752,0.691549768765,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.92250954584,0.0572347434529,-0.214756399883,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.1894593505,-4.51911996136,11.3305058468,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123361500000,13299,123362750000,RH_EXTIMU,-0.145015902517,0.188932881407,-0.682446606267,0.69104369177,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.73593833076,0.0226201834865,-0.220049776279,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.62530288885,-5.15445655417,12.6900000503,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123365250000,13300,123365250000,RH_EXTIMU,-0.146420276367,0.190209728098,-0.682267155096,0.690574319738,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.55506821276,-0.0107174307864,-0.221185801177,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.90439631482,-5.48242884123,13.4548595805,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123369000000,13301,123367750000,RH_EXTIMU,-0.14769994992,0.191309931807,-0.682118546524,0.690144566938,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.38042779694,-0.0426583827805,-0.218316258639,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.99614362923,-5.59886826478,13.5989029223,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123370250000,13302,123370250000,RH_EXTIMU,-0.14885865949,0.19224123963,-0.681997062607,0.689756777332,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.21236611028,-0.0731163643437,-0.21183652139,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.20783241132,-5.85464852331,14.1795320314,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123372750000,13303,123372750000,RH_EXTIMU,-0.149900494793,0.193011729189,-0.68189924228,0.689412603188,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.05129870067,-0.101980158378,-0.202274611933,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.3951543109,-6.06825721261,14.6982132677,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123375250000,13304,123375250000,RH_EXTIMU,-0.150829868643,0.193629714666,-0.681821982982,0.689112957247,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.897564120198,-0.129150727605,-0.190246867964,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.54931042565,-6.24758439288,15.1658112263,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123377750000,13305,123377750000,RH_EXTIMU,-0.151651482609,0.194103663191,-0.681762602826,0.688858003617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.7514287114,-0.154544102292,-0.176413338988,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.69039110771,-6.36180557952,15.5504197776,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123380250000,13306,123380250000,RH_EXTIMU,-0.152370277133,0.194442104124,-0.68171887953,0.688647178229,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.613074122625,-0.178094582092,-0.161447461248,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.80481464823,-6.42428359844,15.8620928969,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123380250000,13307,123382750000,RH_EXTIMU,-0.152991382911,0.194653552805,-0.68168905387,0.688479240769,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.482607509347,-0.199757158286,-0.145997932239,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.90970509414,-6.41651403346,16.0903201357,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123380250000,13308,123385250000,RH_EXTIMU,-0.153520055868,0.19474645091,-0.681671779509,0.688352378746,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.360063449758,-0.219504680192,-0.130626304787,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.88846673566,-6.18642913318,15.8831392186,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123387750000,13309,123387750000,RH_EXTIMU,-0.153961514903,0.194728950816,-0.68166611615,0.688264334203,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.245255671744,-0.237359587004,-0.11582263517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.71743088311,-5.74350764821,15.3086419119,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123387750000,13310,123390250000,RH_EXTIMU,-0.154320795749,0.194608699606,-0.68167154058,0.68821250846,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.137785518362,-0.253397663871,-0.102030191109,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.62637007995,-5.43548626884,15.0698187936,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123387750000,13311,123392750000,RH_EXTIMU,-0.154602800381,0.194392984544,-0.681687811183,0.688194064025,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.037369804803,-0.267673602212,-0.0895524447952,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.51687204316,-5.24405745361,14.8280431697,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123394000000,13312,123395250000,RH_EXTIMU,-0.154812325239,0.194088811524,-0.681714854479,0.688206026112,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0562109421406,-0.280243994905,-0.0785702339803,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.53569420603,-5.14173493959,14.878686241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123394000000,13313,123397750000,RH_EXTIMU,-0.15495403428,0.193702908178,-0.681752723957,0.688245344336,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.143190415652,-0.291163793865,-0.0692039375659,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.27840653549,-4.55697658354,14.1934056869,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123400250000,13314,123400250000,RH_EXTIMU,-0.15503225374,0.193241463707,-0.681801582965,0.688309042851,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.224073064306,-0.300544832064,-0.0614834963808,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.01613506347,-3.94967351544,13.4856388854,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123402750000,13315,123402750000,RH_EXTIMU,-0.155050920623,0.192710098658,-0.681861632582,0.688394322973,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.299409768912,-0.308512420588,-0.0553396102489,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.66690632989,-3.72505544307,12.3048993387,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123405250000,13316,123405250000,RH_EXTIMU,-0.155013644329,0.192113870764,-0.681933153921,0.688498514388,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.369714881909,-0.315209548413,-0.0507623397802,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.48239389958,-3.25887463326,11.9191636584,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123407750000,13317,123407750000,RH_EXTIMU,-0.15492373582,0.191457400394,-0.682016438526,0.688619109156,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.435411830335,-0.320739991418,-0.0476743631293,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.40093728171,-3.0574275893,11.8888268191,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123407750000,13318,123410250000,RH_EXTIMU,-0.154784321538,0.190745152672,-0.682111596547,0.68875385327,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.496689455758,-0.325152095173,-0.0458256940515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.53919688622,-3.16874165029,12.3440147607,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123412750000,13319,123412750000,RH_EXTIMU,-0.154598407503,0.189981626118,-0.682218438488,0.688900802963,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.553587592782,-0.328448213143,-0.0448571633594,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.73330836293,-3.38584884013,12.8044455976,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123415250000,13320,123415250000,RH_EXTIMU,-0.154368881941,0.189171403479,-0.682336438453,0.689058352502,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.606115195653,-0.330612334426,-0.0443684534861,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.74472713205,-3.26452208005,12.8081631724,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123417750000,13321,123417750000,RH_EXTIMU,-0.154098434313,0.188319000253,-0.682464792299,0.689225241817,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.654418791012,-0.331660956655,-0.0439937696405,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.75436720428,-3.10610354983,12.7317475856,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123420250000,13322,123420250000,RH_EXTIMU,-0.153789501528,0.187428758883,-0.682602492323,0.689400527297,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.698740440364,-0.331625094111,-0.0434296483958,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.74291896289,-2.9178065587,12.5984423248,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123422750000,13323,123422750000,RH_EXTIMU,-0.153444291753,0.186504860209,-0.682748364343,0.689583539126,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.7393035249,-0.330530676519,-0.0424188823648,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.89066207822,-2.94809631277,12.7722079352,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123425250000,13324,123425250000,RH_EXTIMU,-0.1530648243,0.185551336878,-0.682901147066,0.689773792109,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.776303310228,-0.328394205054,-0.0408013878627,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.51387987508,-2.2078383684,11.9020289621,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123427750000,13325,123427750000,RH_EXTIMU,-0.152652729032,0.18457159226,-0.683059708347,0.689970946115,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.810336033856,-0.325355155461,-0.0385874716098,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.47072668078,-2.036903989,11.6426355933,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123430250000,13326,123430250000,RH_EXTIMU,-0.152209412393,0.183568679222,-0.683223019138,0.690174717667,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.841739301342,-0.321479848557,-0.0358122618292,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.41054892265,-1.74202166222,11.3773385879,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123432750000,13327,123432750000,RH_EXTIMU,-0.151736070117,0.182545311729,-0.683390182297,0.690384844077,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.870837184989,-0.31682635339,-0.0325471546791,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.35403634922,-1.58424920601,11.0863901498,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123435250000,13328,123435250000,RH_EXTIMU,-0.151233727966,0.18150389349,-0.683560457444,0.690601040538,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.897913922853,-0.31145002788,-0.0289034851712,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.293603333,-1.32344939096,10.8206492132,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123437750000,13329,123437750000,RH_EXTIMU,-0.150703214674,0.180446427945,-0.68373334164,0.690822947838,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.923323176485,-0.305424087027,-0.0250729494851,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.872681608313,-0.578062392585,9.91100169101,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123440250000,13330,123440250000,RH_EXTIMU,-0.150145029796,0.179374190472,-0.683908700002,0.691050113872,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.947687343438,-0.298912773122,-0.0213502100165,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.62941251823,-0.138307540388,9.2848570213,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123442750000,13331,123442750000,RH_EXTIMU,-0.149559463512,0.17828800487,-0.684086618732,0.691282035254,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.971394901343,-0.292017601892,-0.017910084195,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.861510189628,-0.763888193546,9.2085488649,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123445250000,13332,123445250000,RH_EXTIMU,-0.148946898055,0.177188785609,-0.68426725369,0.69151809907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.99434212293,-0.284715579541,-0.0148537426425,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.814998972792,-0.612841981877,8.89987918066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123447750000,13333,123447750000,RH_EXTIMU,-0.14830762749,0.176077256005,-0.684450874609,0.691757651055,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.01669354844,-0.277045747826,-0.0122775409864,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.974444298086,-0.676884414813,8.84948548209,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123450250000,13334,123450250000,RH_EXTIMU,-0.147641879689,0.1749541333,-0.684637725295,0.692000080713,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03849053234,-0.268985701235,-0.0101350573996,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.939117969166,-0.495302811174,8.49232189168,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123452750000,13335,123452750000,RH_EXTIMU,-0.146949736948,0.173819899123,-0.684828121734,0.69224479858,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.05995520052,-0.260581701016,-0.00846280243193,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.699717325183,-0.0808143816823,7.82456096281,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123455250000,13336,123455250000,RH_EXTIMU,-0.146231057022,0.172674651349,-0.685022429894,0.692491309178,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.08144003926,-0.251931684831,-0.00725153055145,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.840434585139,-0.0865814354187,7.62868450597,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123457750000,13337,123457750000,RH_EXTIMU,-0.145485597913,0.171518421326,-0.685220976136,0.692739190322,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.10303978955,-0.243033836627,-0.00643380221378,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.78906394726,0.0426227268295,7.16729995522,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123460250000,13338,123460250000,RH_EXTIMU,-0.144712972719,0.170350990035,-0.685424114205,0.692988080264,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12498277319,-0.233953652075,-0.0060016647938,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.538450270183,0.475316854731,6.51899498724,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123462750000,13339,123462750000,RH_EXTIMU,-0.143912599226,0.169171779644,-0.685632238604,0.693237698155,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.14758894679,-0.224790325291,-0.00594898637194,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.474224931073,0.654775495787,6.04716226331,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123465250000,13340,123465250000,RH_EXTIMU,-0.143083772392,0.167980023261,-0.685845727694,0.693487839596,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17103678279,-0.215594605348,-0.00623063969887,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.41955461117,0.820105616409,5.56733939067,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123467750000,13341,123467750000,RH_EXTIMU,-0.142225669768,0.166774858565,-0.686064894945,0.693738398342,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.19544638035,-0.206376583247,-0.00675247492538,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.548187471478,0.748716517286,5.20450726643,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123470250000,13342,123470250000,RH_EXTIMU,-0.141337423248,0.165555352651,-0.686290008451,0.69398932434,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22088233134,-0.197163720456,-0.00746098097212,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.311504077494,1.11114794646,4.57584905576,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123470250000,13343,123472750000,RH_EXTIMU,-0.140418038218,0.164320283823,-0.686521346439,0.694240635335,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.24758266359,-0.18805526793,-0.00834096480541,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.254114698256,1.25710459538,4.05237569364,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123475250000,13344,123475250000,RH_EXTIMU,-0.139466429582,0.163068358548,-0.686759121249,0.69449242965,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.27563774906,-0.179059914717,-0.00930804684778,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.372526158807,1.26580245161,3.59134102203,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123477750000,13345,123477750000,RH_EXTIMU,-0.138481469059,0.161798231023,-0.687003534545,0.694744815517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.30510036473,-0.170185698302,-0.0103513183693,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0173842341839,1.6858306174,2.9381382601,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123481500000,13346,123480250000,RH_EXTIMU,-0.137461941091,0.160508221502,-0.687254853659,0.694997907697,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.33621217941,-0.161564025402,-0.0115296224758,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0565450566279,1.73431101522,2.38786926028,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123486500000,13347,123482750000,RH_EXTIMU,-0.136406608182,0.159196550925,-0.687513347514,0.695251819421,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.36904045342,-0.153238070964,-0.0128526454857,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.107160631358,1.88370122066,1.86072741602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123486500000,13348,123485250000,RH_EXTIMU,-0.135314205285,0.157861368144,-0.687779261359,0.695506680011,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.40363938452,-0.145237840743,-0.0143024140814,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.010344173174,1.82757589181,1.27230743993,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123489000000,13349,123487750000,RH_EXTIMU,-0.134183468476,0.156500879052,-0.688052767109,0.695762647256,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.43997133145,-0.137544114848,-0.0158159716767,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0235131508444,1.90568410522,0.686763738463,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123489000000,13350,123490250000,RH_EXTIMU,-0.133013140518,0.155113287057,-0.688334004407,0.696019878312,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.47803047126,-0.130165499508,-0.0173763462181,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.176699774099,2.00833128701,0.171711063291,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123492750000,13351,123492750000,RH_EXTIMU,-0.131802002589,0.153696690097,-0.688623162819,0.696278463832,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.51785332951,-0.123168398133,-0.0190633888072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.458565231193,2.1636718738,-0.214043446146,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123495250000,13352,123495250000,RH_EXTIMU,-0.130548892432,0.152249014449,-0.688920503608,0.696538415303,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.55950420816,-0.1166626866,-0.0209848526675,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.714028096152,2.26653961971,-0.546648315594,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123497750000,13353,123497750000,RH_EXTIMU,-0.129252728871,0.150768062372,-0.689226351562,0.696799655396,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.60300557212,-0.110745510282,-0.0232465926788,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.943954420643,2.31436450871,-0.824022051906,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123500250000,13354,123500250000,RH_EXTIMU,-0.127912533484,0.14925156164,-0.689541073573,0.697062022334,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.64833846782,-0.10550174433,-0.0259369606058,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.14361420194,2.30654660389,-1.0454307771,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123502750000,13355,123502750000,RH_EXTIMU,-0.126527429342,0.147697248873,-0.689864985605,0.697325342961,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.69543517303,-0.100987923867,-0.0290428346302,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.752452597443,0.818970382538,-0.725034737934,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123505250000,13356,123505250000,RH_EXTIMU,-0.125097180354,0.146103811769,-0.690198022714,0.697589464582,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.74337148525,-0.0970697450246,-0.032317319793,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.541741684045,-0.663715658777,-0.194395625441,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123507750000,13357,123507750000,RH_EXTIMU,-0.123622202114,0.14447084078,-0.690539770316,0.697854249053,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.79124713824,-0.0936405997874,-0.0355407749842,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.482751807046,-0.773139822724,-0.480363628941,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123510250000,13358,123510250000,RH_EXTIMU,-0.122102977823,0.142798080496,-0.690889637065,0.698119674848,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.83893177929,-0.0906825350513,-0.0385405375819,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.398319542087,-1.29079468746,-0.27589295689,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123512750000,13359,123512750000,RH_EXTIMU,-0.120540232428,0.141085648466,-0.691246824122,0.698385796179,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.88606949881,-0.0881488062014,-0.0411479178309,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.285908945518,-1.84981124141,-0.0292105184486,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123517750000,13360,123515250000,RH_EXTIMU,-0.11893495053,0.1393340734,-0.691610352327,0.698652713503,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.93227361634,-0.0859741341041,-0.0432242105806,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0487009333597,-2.23567545166,0.684459253514,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123517750000,13361,123517750000,RH_EXTIMU,-0.11728829479,0.137544243809,-0.691979082951,0.698920586088,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.97723508028,-0.084075257238,-0.0446314376329,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0272334535355,-2.61168014755,0.943118291943,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123520250000,13362,123520250000,RH_EXTIMU,-0.115601598486,0.135717338543,-0.692351756092,0.69918961683,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.02069031523,-0.0823973438767,-0.0452676641463,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0609940384683,-2.97967697616,1.03153571451,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123522750000,13363,123522750000,RH_EXTIMU,-0.11387635529,0.133854753435,-0.692727088107,0.699459978906,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.06242592922,-0.0809031711193,-0.045132042619,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.230802543814,-3.29284555662,1.5371482936,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123525250000,13364,123525250000,RH_EXTIMU,-0.112114228978,0.131958167754,-0.69310378226,0.699731797648,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.10218573572,-0.0795207517133,-0.0442348993451,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.459831854331,-3.98484214401,2.3726924131,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123527750000,13365,123527750000,RH_EXTIMU,-0.110317153017,0.130029681159,-0.693480492202,0.70000515334,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.13957820435,-0.078160268101,-0.042563248734,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.553431232168,-4.44427436705,2.54756467034,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123530250000,13366,123530250000,RH_EXTIMU,-0.108487254878,0.128071670835,-0.693855882258,0.700280070625,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.1743387068,-0.0767633736626,-0.0401490511439,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.669446786927,-4.9284087317,2.74642224249,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123532750000,13367,123532750000,RH_EXTIMU,-0.106626840448,0.126086748033,-0.694228702579,0.700556462666,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.2062381972,-0.0752753932406,-0.0370999185584,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.824629070794,-5.25846039772,3.68196874511,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123532750000,13368,123535250000,RH_EXTIMU,-0.104738420523,0.124077765524,-0.694597824437,0.700834098526,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.23502924126,-0.0736467123149,-0.0335637638905,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.908844669567,-5.61290161028,4.44022840606,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123537750000,13369,123537750000,RH_EXTIMU,-0.102824673795,0.122047770359,-0.694962205667,0.70111265921,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.26051245383,-0.0718432881442,-0.0296386116606,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.9477657228,-5.6856343726,4.74233563196,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123540250000,13370,123540250000,RH_EXTIMU,-0.100888304767,0.119999812456,-0.695320944841,0.701391744061,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.2826801447,-0.0698563877554,-0.025451421025,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.06193578257,-6.02021069473,5.00285484834,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123540250000,13371,123542750000,RH_EXTIMU,-0.0989320987173,0.117937040964,-0.695673273034,0.701670856882,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.30143800328,-0.067654131232,-0.0211298336601,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.08924129991,-5.98961881075,5.21762898556,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123545250000,13372,123545250000,RH_EXTIMU,-0.0969588336672,0.115862577931,-0.696018584039,0.701949412908,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.31681456716,-0.0652258748102,-0.0168165252144,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.11174835593,-6.03449302128,5.36429785969,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123547750000,13373,123547750000,RH_EXTIMU,-0.0949712859282,0.113779536693,-0.696356402118,0.702226767582,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.32882396422,-0.0625600818577,-0.0126192492337,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.20370842819,-6.27456085504,5.5942440235,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123550250000,13374,123550250000,RH_EXTIMU,-0.0929722269734,0.111691011201,-0.696686416002,0.70250218561,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.33748847685,-0.0596449616192,-0.00868275321608,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.91607831164,-5.56579959813,5.45944825488,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123552750000,13375,123552750000,RH_EXTIMU,-0.0909641532511,0.109599568729,-0.697008573121,0.702774861783,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.34327463654,-0.0565993100289,-0.00520686655643,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.688301603849,-5.13319332052,5.35406516944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123555250000,13376,123555250000,RH_EXTIMU,-0.0889493827021,0.107507448165,-0.697322973988,0.703043971495,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.34647824555,-0.0534980717999,-0.00229699648193,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.920005375215,-5.73966199752,5.73263663374,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123557750000,13377,123557750000,RH_EXTIMU,-0.0869303485512,0.105417172302,-0.69762969767,0.70330870833,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.34687571009,-0.0502522682434,7.94426288323e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.15937459892,-6.352286983,6.12011262544,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123560250000,13378,123560250000,RH_EXTIMU,-0.0849096197628,0.103331611688,-0.697928731221,0.703568348232,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.34419458286,-0.0467584202813,0.00203249035802,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.40394467093,-6.96743488711,6.51421586296,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123562750000,13379,123562750000,RH_EXTIMU,-0.0828898677022,0.101253921258,-0.698219969115,0.703822270173,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.33821770088,-0.0429308576803,0.00368159408285,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.41062917846,-6.93299603605,6.51316341997,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123565250000,13380,123565250000,RH_EXTIMU,-0.0808737083915,0.0991872526021,-0.698503253059,0.704069980668,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.32898204925,-0.0387560734778,0.00513041533306,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.4577240275,-7.25219166843,6.99405836147,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123567750000,13381,123567750000,RH_EXTIMU,-0.0788637901337,0.097134800795,-0.698778408728,0.70431105953,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.31644823713,-0.0342355304558,0.00642753164623,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.27682358823,-7.16875602862,7.37528651739,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123570250000,13382,123570250000,RH_EXTIMU,-0.0768626982244,0.0950995635531,-0.699045285098,0.704545163929,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.30076825012,-0.0294505048581,0.00759382006412,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.10101399597,-7.00272110551,7.44054532689,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123572750000,13383,123572750000,RH_EXTIMU,-0.0748728579478,0.0930841973335,-0.69930379786,0.704772009694,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.28223111671,-0.0245048371942,0.00861441376564,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.718208915168,-6.45499485949,7.07920827929,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123575250000,13384,123575250000,RH_EXTIMU,-0.0728964821472,0.0910909470769,-0.699553937587,0.704991369208,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.26119497015,-0.0195121170863,0.00946919260245,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.985775691437,-7.06881830662,7.5288106077,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123575250000,13385,123577750000,RH_EXTIMU,-0.0709358469735,0.0891222393525,-0.699795671864,0.705203055657,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.2375222117,-0.0144104499399,0.010199819072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.890562497205,-6.85106711044,7.35671614904,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123581500000,13386,123580250000,RH_EXTIMU,-0.0689930808367,0.0871802989543,-0.700028997509,0.705406941359,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.21141354498,-0.00923406526372,0.0108214986974,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.726376314402,-6.68749430349,7.23670308395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123582750000,13387,123582750000,RH_EXTIMU,-0.0670701470693,0.0852670698321,-0.700253976906,0.705602926583,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.18312437947,-0.00404779254495,0.0113085581341,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.564396563966,-6.4495788343,7.05850528663,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123585250000,13388,123585250000,RH_EXTIMU,-0.0651688656623,0.0833842689215,-0.700470706743,0.705790954632,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.15286622851,0.00109882938267,0.0116633277979,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.851062876717,-7.06559168122,7.54397912352,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123587750000,13389,123587750000,RH_EXTIMU,-0.0632911150882,0.081533796666,-0.700679258466,0.705970999056,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.12050184533,0.00627272616631,0.0119228989475,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.657228540191,-6.72850951111,7.59542610071,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123590250000,13390,123590250000,RH_EXTIMU,-0.06143865854,0.0797173812985,-0.700879707662,0.70614309155,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.08619475074,0.011437299028,0.0121161603853,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.948064969899,-7.33906014138,8.092882045,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123592750000,13391,123592750000,RH_EXTIMU,-0.0596133538595,0.077937025447,-0.701072036843,0.706307346176,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.04973435597,0.0166844374411,0.0123493305624,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.24117679768,-7.9419652137,8.58983758824,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123595250000,13392,123595250000,RH_EXTIMU,-0.0578171920338,0.0761950852535,-0.701256123195,0.706463962966,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.01084327514,0.0221291692723,0.0127381911481,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.30662428626,-8.13355502949,8.76110099902,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123597750000,13393,123597750000,RH_EXTIMU,-0.0560521459268,0.0744939352333,-0.701431837702,0.706613181032,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.96952141975,0.0277903013285,0.0133090023104,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.08870315656,-7.72889321586,8.77647362241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123600250000,13394,123600250000,RH_EXTIMU,-0.0543199221032,0.0728354415872,-0.701599188303,0.70675520761,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.92620980702,0.0335390008957,0.0139583051544,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.567586232672,-6.81817142818,8.38102543228,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123602750000,13395,123602750000,RH_EXTIMU,-0.0526218629517,0.0712207498082,-0.701758324609,0.706890230643,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.8815247702,0.039179962807,0.0145844887311,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0628924670403,-5.94532487266,7.68055178743,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123605250000,13396,123605250000,RH_EXTIMU,-0.0509589448461,0.069650306976,-0.701909575528,0.70701836501,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.83607102649,0.044535404987,0.0150369801931,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.163756767998,-5.59428974491,7.38118203847,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123607750000,13397,123607750000,RH_EXTIMU,-0.0493318263959,0.0681239778122,-0.702053417705,0.707139656107,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.79035925575,0.0494635247326,0.0151884104973,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.604247685665,-4.86684144161,6.71685161432,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123610250000,13398,123610250000,RH_EXTIMU,-0.0477408732212,0.0666411032062,-0.702190448178,0.70725408933,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.74485220626,0.0538392362595,0.0149341718845,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.523935747452,-5.04454712814,6.88547725934,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123612750000,13399,123612750000,RH_EXTIMU,-0.0461863928922,0.0652010022224,-0.702321272941,0.707361630282,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.69959338416,0.0576824193147,0.014262799469,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.671634248781,-4.83074177938,6.68014027268,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123615250000,13400,123615250000,RH_EXTIMU,-0.0446684756948,0.0638026451232,-0.702446537489,0.707462233426,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.65490213536,0.0609180217218,0.0131464453876,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04776250064,-4.22332899217,6.09634111882,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123617750000,13401,123617750000,RH_EXTIMU,-0.0431869149834,0.0624445146484,-0.702566913293,0.707555867272,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.61122115114,0.0634353144782,0.0115786563332,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.16512224134,-4.04343808806,5.92656993715,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123620250000,13402,123620250000,RH_EXTIMU,-0.0417413499784,0.0611248955241,-0.702683042206,0.707642529138,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.56874741353,0.0652045065895,0.00959631967496,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.25717877164,-3.92045013931,5.80898834645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123622750000,13403,123622750000,RH_EXTIMU,-0.0403312910454,0.0598419197844,-0.702795505933,0.70772226787,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.52763749119,0.0662053759422,0.00726680772587,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.32993548707,-3.81839693413,5.71362344763,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123625250000,13404,123625250000,RH_EXTIMU,-0.0389561336009,0.0585935987869,-0.702904807944,0.707795196936,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.48802173804,0.0664272227154,0.0046755367153,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.3849185453,-3.73431694582,5.63920696334,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123627750000,13405,123627750000,RH_EXTIMU,-0.0376151707546,0.0573778497096,-0.703011357157,0.707861506934,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.45000816882,0.0658666588154,0.001924441341,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.42294531014,-3.66867538684,5.58757108344,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123630250000,13406,123630250000,RH_EXTIMU,-0.0363076444237,0.0561926091822,-0.703115443236,0.70792147807,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.41361127356,0.0645551659983,-0.000862492368986,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.21127856394,-4.01199227524,5.94966344782,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123632750000,13407,123632750000,RH_EXTIMU,-0.0350328438649,0.0550360224714,-0.703217221001,0.707975477096,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.3786826113,0.0625763117131,-0.00355335062473,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.223793561,-3.97627540301,5.93581240287,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123635250000,13408,123635250000,RH_EXTIMU,-0.0337899866603,0.0539062048698,-0.703316755456,0.70802393983,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.34527694278,0.0599481986268,-0.00605354748852,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22925524831,-3.93836676272,5.92968605226,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123637750000,13409,123637750000,RH_EXTIMU,-0.0325781781157,0.0528011590954,-0.703414061568,0.708067339945,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.31351944025,0.0566678876174,-0.00830921245618,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.47310180713,-3.48505582844,5.51836393224,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123640250000,13410,123640250000,RH_EXTIMU,-0.0313963219993,0.0517186087321,-0.703509143188,0.708106165717,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.28368067748,0.0526905787235,-0.0103021973376,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.45750789649,-3.4611735194,5.54873744483,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123642750000,13411,123642750000,RH_EXTIMU,-0.0302433216166,0.0506563813876,-0.703601960504,0.708140913729,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.25570025344,0.0480748860437,-0.0119979453738,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.17574618054,-3.8862434977,6.02948708766,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123645250000,13412,123645250000,RH_EXTIMU,-0.0291181895963,0.0496126176966,-0.703692418676,0.70817208297,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.22933739752,0.0429361417756,-0.0133585317105,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12616581258,-3.91709485852,6.12075185575,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123649000000,13413,123647750000,RH_EXTIMU,-0.0280198723215,0.048585428532,-0.703780430974,0.708200146758,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.20464569343,0.0372970461597,-0.0143992626091,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.32049572087,-3.50729645691,5.78741976424,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123650250000,13414,123650250000,RH_EXTIMU,-0.0269471477065,0.0475727158735,-0.703865951133,0.708225536655,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.18183845927,0.0311376301444,-0.0151630223898,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.25907820857,-3.51713889195,5.88691494968,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123652750000,13415,123652750000,RH_EXTIMU,-0.0258988197987,0.0465725580306,-0.703948940605,0.708248640657,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.16080062195,0.024545771954,-0.0156741954995,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.930990875385,-3.99279781269,6.45125694673,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123655250000,13416,123655250000,RH_EXTIMU,-0.0248739792963,0.0455831333627,-0.704029360311,0.708269809414,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.14131233671,0.0174188877867,-0.0159607349044,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.09467136627,-3.61452503873,6.17864973393,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123657750000,13417,123657750000,RH_EXTIMU,-0.0238712532185,0.0446029279021,-0.704107222863,0.708289319985,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.12346321423,0.0101968535921,-0.0160687200896,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.752752026003,-4.09014353656,6.76326160859,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123660250000,13418,123660250000,RH_EXTIMU,-0.0228896671762,0.0436305868897,-0.704182527162,0.708307421579,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.10693646549,0.00274663426908,-0.0160169286402,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.659703746844,-4.12659292863,6.91972914112,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123662750000,13419,123662750000,RH_EXTIMU,-0.0219282576737,0.0426648669887,-0.704255291939,0.708324321491,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0916628745,-0.00487247477087,-0.0158378890197,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.563822158277,-4.1582368496,7.08598484001,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123665250000,13420,123665250000,RH_EXTIMU,-0.0209860004976,0.0417045499117,-0.704325571855,0.70834017755,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0776629159,-0.0126093796667,-0.0155768557034,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.737030582884,-3.68362811948,6.7779858292,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123667750000,13421,123667750000,RH_EXTIMU,-0.0200617630818,0.0407483178837,-0.704393458897,0.708355105378,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.06505442612,-0.0204571251831,-0.0152765236103,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.371635351436,-4.17791135571,7.41844661546,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123670250000,13422,123670250000,RH_EXTIMU,-0.0191546021992,0.0397952737143,-0.70445903056,0.708369191642,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.05349202617,-0.0282832238651,-0.0149441772828,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.272816367212,-4.19538060944,7.60270357983,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123672750000,13423,123672750000,RH_EXTIMU,-0.018263598663,0.0388446356952,-0.704522369805,0.708382499562,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.04289669781,-0.0360348519016,-0.0145952428895,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.171794051917,-4.20201555349,7.79038928323,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123687750000,13424,123675250000,RH_EXTIMU,-0.0173878554507,0.0378957331777,-0.704583561008,0.708395074409,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.03319295022,-0.0436609302764,-0.0142399763583,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0765903497032,-4.17792405484,7.96112907948,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123687750000,13425,123677750000,RH_EXTIMU,-0.0165264857067,0.0369479861916,-0.704642688098,0.708406947804,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.02432359872,-0.0511153683022,-0.0138852760163,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0150762032441,-4.14084879329,8.1317751644,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123687750000,13426,123680250000,RH_EXTIMU,-0.0156785443047,0.0360007848263,-0.704699844471,0.708418136373,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.01633852823,-0.0583817120893,-0.0135441725343,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.177608288658,-3.5460778935,7.79590473877,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123687750000,13427,123682750000,RH_EXTIMU,-0.0148428914076,0.0350532622138,-0.704755144532,0.708428643999,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.00949330551,-0.0654952134732,-0.0132339700529,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.087056369661,-3.47796168964,7.97082444368,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123687750000,13428,123685250000,RH_EXTIMU,-0.0140183948054,0.0341046281147,-0.704808696339,0.708438466286,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.00374004727,-0.0724166478972,-0.0129556066566,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0120589071514,-3.43684821114,8.17763505654,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123687750000,13429,123687750000,RH_EXTIMU,-0.0132039431204,0.0331541863991,-0.704860595819,0.708447595995,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.999013449678,-0.0791045478094,-0.0127039917754,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.112635082945,-3.38213008268,8.37798061574,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123687750000,13430,123690250000,RH_EXTIMU,-0.0123984463712,0.0322013348145,-0.704910923321,0.708456027391,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.995247991673,-0.0855180306125,-0.0124698018311,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0724097250055,-2.71626016398,8.04122376197,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123687750000,13431,123692750000,RH_EXTIMU,-0.0116006048239,0.0312451889843,-0.704959768508,0.70846375272,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.992721821288,-0.0916985966816,-0.012257729876,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.303977035508,-3.22062921936,8.76288526799,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123687750000,13432,123695250000,RH_EXTIMU,-0.0108093685302,0.0302853198538,-0.705007176663,0.708470774137,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.991035522662,-0.0975297484366,-0.0120399050333,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.687868056058,-3.7296040785,9.50545455587,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123687750000,13433,123697750000,RH_EXTIMU,-0.0100240214387,0.02932187191,-0.705053141335,0.708477109521,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.98967522556,-0.102875542532,-0.0117823319218,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.780186434473,-3.61668135221,9.67792164219,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13434,123700250000,RH_EXTIMU,-0.00924386264233,0.0283550501171,-0.705097639963,0.70848278755,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.988597927384,-0.107710535211,-0.0114709420415,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.844251128756,-3.43609192364,9.80701217537,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13435,123702750000,RH_EXTIMU,-0.00737836753199,0.0240139309144,-0.704949078266,0.708812872249,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.50515140992,-1.41679321171,0.280611326813,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-41.3489482245,-90.8602426071,83.8501516794,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13436,123705250000,RH_EXTIMU,-0.00386379042056,0.0153074591544,-0.704225669302,0.709800647727,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.89507344222,-2.97821994923,0.983416504129,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.16818617078,-24.8448714521,3.74273150674,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13437,123707750000,RH_EXTIMU,-0.00058066228879,0.00741011518538,-0.70355317984,0.710603740605,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.30782820895,-2.6467274934,0.850118313475,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.30051672676,4.59111934295,12.946278147,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13438,123710250000,RH_EXTIMU,0.00265480819513,-0.000241001854944,-0.702964682659,0.711219761287,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,6.14255300633,-2.53242410761,0.69690738115,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.776789759772,4.61249872622,7.42042495177,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13439,123712750000,RH_EXTIMU,-0.000384919741491,-0.000338542735549,-0.70296812833,0.71122116657,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.67468365722,-1.7649652769,-0.000376986556658,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.41201313444,81.4694270313,143.286493745,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13440,123715250000,RH_EXTIMU,-4.83968959637e-06,-8.70773937765e-05,-0.70296820285,0.711221272303,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0748391007693,0.356825373074,-8.44256009906e-06,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,10.577290394,-4.84462516385,29.103115498,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13441,123717750000,RH_EXTIMU,2.76970696745e-05,1.18306514317e-05,-0.702968224811,0.711221255306,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0371107020325,0.0745742493918,-2.39378519661e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.182108708299,0.645002551179,16.0840362443,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13442,123720250000,RH_EXTIMU,9.88278767418e-06,2.45469656968e-05,-0.702969574154,0.711219921763,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0172872063797,-0.00278302623683,-0.00151814583033,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.536604093676,0.279460160909,8.85005143093,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13443,123722750000,RH_EXTIMU,4.80184197865e-06,4.02584239441e-06,-0.702969675452,0.711219822105,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00864964718505,-0.0145334243982,-0.000113618815343,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0881974320794,-0.260473066626,8.5321283003,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13444,123725250000,RH_EXTIMU,1.38740333504e-05,1.03340812676e-05,-0.70296971828,0.711219779591,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00161425766141,0.00869121593527,-4.82717815948e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.101423385951,-0.00858060077757,9.63147298395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13445,123727750000,RH_EXTIMU,9.39802966607e-06,1.21155750482e-05,-0.702969761608,0.711219736811,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00354860599488,-0.00150356927527,-4.87679379104e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.141184010034,0.0510989903782,10.2718730406,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13446,123730250000,RH_EXTIMU,3.4218778804e-06,6.98621411745e-06,-0.702969811689,0.711219687434,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000515656318951,-0.00627932527977,-5.62822942032e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0506099772086,0.0141261000061,9.59829111419,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13447,123732750000,RH_EXTIMU,3.51346337994e-06,1.71778543717e-07,-0.702969868029,0.711219631781,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00388438438913,-0.00382574296112,-6.33349720666e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.076502579416,-0.0780003188287,9.84508773129,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13448,123735250000,RH_EXTIMU,1.15505637687e-05,3.21733241941e-06,-0.702969912748,0.711219587488,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00286016890906,0.00625271756493,-5.03610829039e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.169933971054,-0.0610462118886,9.73613871381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13449,123737750000,RH_EXTIMU,4.92444225006e-06,7.21898207121e-06,-0.702969962218,0.71121953864,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00602053279705,-0.00144953029235,-5.56724078836e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0500569874744,0.150734696637,9.74238537216,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123742750000,13450,123740250000,RH_EXTIMU,4.70457471286e-06,5.59557944883e-06,-0.702970016579,0.711219484925,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000787863879001,-0.00104732465476,-6.11323663284e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0141392591053,-0.00495639141197,9.83690605146,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13451,123742750000,RH_EXTIMU,4.62567987459e-06,9.28341859221e-06,-0.702970063934,0.711219438081,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00211884112372,0.00205392191169,-5.33022184615e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0519483114265,0.0466173071746,9.79799688573,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13452,123745250000,RH_EXTIMU,4.27003617739e-06,5.96445176872e-06,-0.702970118757,0.711219383933,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00166415549525,-0.00208841627417,-6.16349581158e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0567119379112,-0.0393137639619,9.80964994033,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13453,123747750000,RH_EXTIMU,3.38339120649e-06,5.2877582377e-06,-0.702970173737,0.7112193296,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000123922558552,-0.000883649910011,-6.18393749583e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00841599707231,0.00439401069028,9.79668695181,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13454,123750250000,RH_EXTIMU,2.92338057239e-06,5.3617830721e-06,-0.702970228793,0.711219275185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00030336418426,-0.000216580608681,-6.19297528911e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000854761348819,0.00562177200217,9.79554203094,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13455,123752750000,RH_EXTIMU,3.00731475342e-06,5.42395563016e-06,-0.702970284215,0.711219220404,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.27924858668e-05,8.25773469869e-05,-6.23410267323e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00174798500615,-0.00108288476584,9.7934821374,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13456,123755250000,RH_EXTIMU,2.76464342407e-06,5.58779535263e-06,-0.702970339697,0.711219165565,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000230213203201,-4.32517144521e-05,-6.2409322399e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00161121915966,0.00546628599146,9.80334011746,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13457,123757750000,RH_EXTIMU,2.4166365895e-06,5.95732744541e-06,-0.702970395118,0.711219110785,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00040582301614,1.45439814707e-05,-6.23424624845e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00107549875409,0.00740220515973,9.79773559603,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13458,123760250000,RH_EXTIMU,2.27010279254e-06,6.25232735852e-06,-0.702970450794,0.711219055753,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000249274702062,8.54406784291e-05,-6.26287505858e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000541050515892,0.00449040623583,9.78980540411,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13459,123762750000,RH_EXTIMU,2.06063138942e-06,6.36301753982e-06,-0.702970506368,0.711219000824,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000181433206459,-5.48216185565e-05,-6.25121072369e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00102082053008,0.00254826797861,9.82527328577,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13460,123765250000,RH_EXTIMU,1.52439366172e-06,6.73425484405e-06,-0.702970561792,0.71121894604,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000513880696819,-9.03424383958e-05,-6.23475195417e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00154612022053,0.0100821277003,9.80247926466,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13461,123767750000,RH_EXTIMU,3.29774943118e-06,7.97909427745e-06,-0.702970615154,0.711218893278,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000308927348211,0.00170557645232,-6.0025271423e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0171577559179,-0.000121847665855,9.80266696382,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13462,123770250000,RH_EXTIMU,1.42319182691e-06,7.63020052942e-06,-0.702970670689,0.711218838397,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000870366486313,-0.00125271878622,-6.24730904334e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0137676508914,0.0105319950167,9.79593478552,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13463,123772750000,RH_EXTIMU,2.85026891473e-06,8.69830225102e-06,-0.702970724058,0.711218785631,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000211296325932,0.00141027818401,-6.00324688208e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0149792701798,0.00174354959481,9.8050108752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13464,123775250000,RH_EXTIMU,9.25379519308e-07,8.36809989458e-06,-0.702970779503,0.711218730837,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000909515416147,-0.00127038935389,-6.23742352411e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0131845974729,0.0108167873586,9.7997030538,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13465,123777750000,RH_EXTIMU,2.42138173358e-06,9.46233052484e-06,-0.702970832905,0.711218678038,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000235818506218,0.00146390684412,-6.00682033425e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.015936844973,0.00130407775435,9.80138800343,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13466,123780250000,RH_EXTIMU,2.692946704e-06,9.86828281169e-06,-0.702970886449,0.711218625108,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.37839225202e-05,0.000383698778828,-6.0230391843e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00232624149301,0.000691578008604,9.80838579832,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13467,123782750000,RH_EXTIMU,4.88784315632e-06,4.99290854919e-06,-0.702970946873,0.711218565424,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.003990638529,-0.00153960659911,-6.79167111896e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0154739949478,-0.0970240403315,9.8263645598,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123785250000,13468,123785250000,RH_EXTIMU,-1.28268490379e-07,9.7093660381e-06,-0.702971002087,0.711218510819,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00550646701894,-0.00013739889759,-6.21626518261e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00269701448889,0.125471773941,9.73798496498,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123787750000,13469,123787750000,RH_EXTIMU,6.2120010326e-06,6.96199765936e-06,-0.702971061046,0.711218452548,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00515251033254,0.00200243755714,-6.62670743175e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.020774320434,-0.114358200464,9.82939803068,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123790250000,13470,123790250000,RH_EXTIMU,4.76418223385e-06,6.22705163461e-06,-0.702971121765,0.711218392551,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000410455090698,-0.00123238548094,-6.8293792092e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0140789526427,0.00687049439824,9.79403864228,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123792750000,13471,123792750000,RH_EXTIMU,4.23879941751e-06,6.25012889712e-06,-0.702971182396,0.711218332626,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000311907126588,-0.000282332711965,-6.82000917605e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00169048341851,0.00655758478581,9.80306253563,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123795250000,13472,123795250000,RH_EXTIMU,4.10068831066e-06,6.35426651453e-06,-0.702971243004,0.711218272721,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000137145810023,-1.84187423733e-05,-6.81743514852e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000115071088844,0.00140216895108,9.8111224022,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123797750000,13473,123797750000,RH_EXTIMU,3.20312716501e-06,7.79218569115e-06,-0.702971303391,0.711218213025,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00131934167207,0.000313371880463,-6.79403388663e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00656497434237,0.0279735268071,9.75418822564,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123800250000,13474,123800250000,RH_EXTIMU,3.55865666434e-06,8.56476697383e-06,-0.702971364269,0.711218152842,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00023219419913,0.000639520950992,-6.84826699764e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00920146194814,0.000524438610317,9.76742297291,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123802750000,13475,123802750000,RH_EXTIMU,2.96241516962e-06,1.07655326849e-05,-0.702971425134,0.711218092655,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00157690585074,0.000916867300633,-6.84892706572e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0153307854043,0.0304744401548,9.70580106783,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123805250000,13476,123805250000,RH_EXTIMU,3.69137766349e-06,1.0403558572e-05,-0.702971486411,0.711218032091,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00061832768924,0.000203998188399,-6.89178528425e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00155968159432,-0.0125967696125,9.81816454911,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123807750000,13477,123807750000,RH_EXTIMU,1.97093027707e-06,1.2581778368e-05,-0.702971547008,0.711217972168,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00220387100843,0.000271811311954,-6.81981222597e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00644130983272,0.0493521937847,9.73302404656,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123810250000,13478,123810250000,RH_EXTIMU,4.71446036972e-06,1.5055103123e-05,-0.70297160762,0.711217912198,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000170057488458,0.00295015779633,-6.81884395627e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0351340982756,-0.00532359247621,9.73779728129,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123812750000,13479,123812750000,RH_EXTIMU,7.10894570652e-06,1.52700668701e-05,-0.702971668806,0.711217851697,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.001241510926,0.00146891351707,-6.88094413423e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0449070765577,-0.0363985800187,9.63366595261,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123815250000,13480,123815250000,RH_EXTIMU,3.97762703174e-06,1.08892104921e-05,-0.702971733888,0.711217787474,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000682055702668,-0.00425357684642,-7.31610395812e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0774985225977,-0.0143131682617,8.90463496688,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123817750000,13481,123817750000,RH_EXTIMU,5.37432709286e-06,1.67470417304e-06,-0.7029718058,0.711217716469,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00597671718152,-0.00445734371692,-8.08062696772e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0622155813882,-0.104032680186,8.85956663588,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123820250000,13482,123820250000,RH_EXTIMU,2.04741439941e-05,7.39708888367e-06,-0.702971854743,0.711217667782,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00537326602081,0.0117476854081,-5.52327827498e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.279155554076,-0.111671072931,9.45216156418,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123822750000,13483,123822750000,RH_EXTIMU,-8.12130834325e-07,-1.32363352182e-05,-0.702971927587,0.711217595992,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000507565056062,-0.0237108070636,-8.16067131324e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.557198607831,0.0233916084839,9.65282929696,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123825250000,13484,123825250000,RH_EXTIMU,3.66579046418e-06,-3.95248336107e-06,-0.702971966245,0.711217557886,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00267320908571,0.00780055303462,-4.34669384934e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.145001944886,0.0314376300782,8.80243774145,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123827750000,13485,123827750000,RH_EXTIMU,3.73016435414e-06,-2.56608389701e-06,-0.702972008412,0.711217516214,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000743052904225,0.000825027489386,-4.74315454883e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0455943317222,0.0284898042197,9.29448708639,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123830250000,13486,123830250000,RH_EXTIMU,2.14559610949e-05,6.36584311942e-06,-0.70297204483,0.71121747988,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00506240199968,0.0150506253242,-4.12175269942e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.455743476702,-0.0980560545015,9.80138136824,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123832750000,13487,123832750000,RH_EXTIMU,5.20123361845e-06,-1.23949241211e-05,-0.70297211888,0.711217406914,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0013021205079,-0.0198156845892,-8.29275145968e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.446619478732,-0.0039876905083,9.81935342279,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123834000000,13488,123835250000,RH_EXTIMU,4.5491441272e-06,-3.21875779896e-06,-0.702972160713,0.71121736567,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00553149342712,0.00485427820564,-4.70285512766e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.7729933395e-05,0.100652409781,9.82043163305,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123837750000,13489,123837750000,RH_EXTIMU,2.16034713623e-05,6.66129577071e-06,-0.702972196875,0.711217329591,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00414714490533,0.0152124661273,-4.09449675971e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.448206998909,-0.0937749203468,9.92891931132,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123840250000,13490,123840250000,RH_EXTIMU,6.59738340765e-06,-1.24380940315e-05,-0.702972270598,0.711217256942,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0022030018131,-0.0193061445913,-8.25522205789e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.437298863106,-0.023130614219,9.82118604178,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123842750000,13491,123842750000,RH_EXTIMU,5.46665084233e-06,-3.57679105135e-06,-0.702972312419,0.711217215715,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00562675763053,0.0044059497368,-4.70156309004e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00650855540317,0.103526817649,9.78563201364,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123845250000,13492,123845250000,RH_EXTIMU,2.39130769097e-05,5.69562373303e-06,-0.70297234839,0.711217179766,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00528093199455,0.0156496219924,-4.07770187868e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.456500352557,-0.116549351558,9.96295725338,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123849000000,13493,123847750000,RH_EXTIMU,2.21032617095e-06,-9.91502615556e-06,-0.702972413463,0.7112171158,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00356920964941,-0.0210871977891,-7.27987377579e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.516666072735,0.0829082209676,9.80614826003,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123850250000,13494,123850250000,RH_EXTIMU,7.32403804652e-06,-4.72095342332e-06,-0.702972455379,0.711217074389,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.1464605742e-05,0.00583112904286,-4.71872945163e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0746787179986,-0.00370345888226,9.86761964071,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123852750000,13495,123852750000,RH_EXTIMU,2.52171077927e-05,5.08282183828e-06,-0.702972491247,0.711217038525,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00466725827428,0.0156407576821,-4.07020508437e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.444885734807,-0.096172794056,9.93061765072,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123855250000,13496,123855250000,RH_EXTIMU,3.69973594903e-06,-1.02617617696e-05,-0.702972556105,0.7112169748,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00361335950197,-0.0208315608925,-7.25180508616e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.510031699319,0.0813793029052,9.7712202576,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123857750000,13497,123857750000,RH_EXTIMU,8.71204911712e-06,-5.14285694553e-06,-0.702972597902,0.7112169335,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.68861412375e-05,0.00573133601965,-4.70637531169e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0739162852428,-0.0041009523057,9.83907946375,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123860250000,13498,123860250000,RH_EXTIMU,2.64104473522e-05,4.52182467985e-06,-0.702972633556,0.711216897826,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00463471543868,0.0154521389777,-4.04884622745e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.44001860684,-0.0951927119854,9.92649121259,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123862750000,13499,123862750000,RH_EXTIMU,5.01077354676e-06,-1.06830391222e-05,-0.702972698269,0.711216834271,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00362496359839,-0.0206858740338,-7.23181958848e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.506344006138,0.0816630987962,9.77392350929,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123867750000,13500,123865250000,RH_EXTIMU,9.94054947213e-06,-5.68694730306e-06,-0.702972739791,0.711216793235,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.78140606388e-06,0.00561504147603,-4.67652336413e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0720915728162,-0.00341900487121,9.84953835225,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123867750000,13501,123867750000,RH_EXTIMU,2.7055267945e-05,3.9100413246e-06,-0.702972775191,0.711216757812,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00434068316094,0.0150853755679,-4.02168764537e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.433501198291,-0.0917403748294,9.90808576637,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123870250000,13502,123870250000,RH_EXTIMU,5.96148343189e-06,-1.11211679103e-05,-0.702972839786,0.711216694379,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00354857615422,-0.0204150445112,-7.21667107045e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.500068746289,0.0801933308647,9.76776081769,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123872750000,13503,123872750000,RH_EXTIMU,1.0797335646e-05,-6.13670678885e-06,-0.702972881227,0.711216653422,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-5.1681743909e-05,0.00555560321864,-4.66785995193e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0705819669297,-0.0022447390651,9.84900087175,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123875250000,13504,123875250000,RH_EXTIMU,2.757867466e-05,3.32587345905e-06,-0.702972916481,0.711216618143,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00422658451015,0.0148214162385,-4.00630930675e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.427252927876,-0.0883845645163,9.91520918276,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123877750000,13505,123877750000,RH_EXTIMU,-2.6869123418e-06,-2.25752083451e-06,-0.702972973268,0.711216562548,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.014080329395,-0.0201975137248,-6.35333616926e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.494169658155,0.300023948675,9.67380057482,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123880250000,13506,123880250000,RH_EXTIMU,8.38148794315e-06,2.83968945837e-06,-0.702973006462,0.711216529692,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00343106269237,0.00912480532476,-3.73727967691e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.107332906188,-0.0341574564928,9.84701061762,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123882750000,13507,123882750000,RH_EXTIMU,1.84172111696e-05,1.8046667082e-05,-0.702973032045,0.711216503993,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00284201779626,0.0142962369925,-2.90877252078e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.47654534542,0.0244551491875,9.85041139641,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123885250000,13508,123885250000,RH_EXTIMU,-4.12817140869e-06,-4.37084448708e-06,-0.702973103232,0.711216434074,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000220591622053,-0.0254340001685,-7.98197735597e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.605088470481,0.0019955502276,9.76901036769,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123887750000,13509,123887750000,RH_EXTIMU,5.06205510895e-06,4.93436280238e-06,-0.702973128444,0.711216409144,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.05642031836e-06,0.0104627987174,-2.836614983e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.122402683523,-0.000122587313842,9.81390245532,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123890250000,13510,123890250000,RH_EXTIMU,1.80488037756e-05,1.79856000884e-05,-0.702973153844,0.711216383617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.93759221797e-05,0.0147292715634,-2.88095082472e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.479732171273,-0.00116753475784,9.85010292975,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123892750000,13511,123892750000,RH_EXTIMU,-3.51201360358e-06,-4.67769977741e-06,-0.702973224999,0.711216313719,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000477829888273,-0.0250201487969,-7.97775505344e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.59742787227,-0.0103244936705,9.81878525561,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123895250000,13512,123895250000,RH_EXTIMU,5.35687574208e-06,4.71521143298e-06,-0.702973250102,0.711216288895,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000236213202487,0.0103319867232,-2.82497343748e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.119456999397,0.00671634523171,9.90299147625,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123897750000,13513,123897750000,RH_EXTIMU,1.75429371406e-05,1.74778844346e-05,-0.702973275599,0.711216263299,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000243913678798,0.0141147968807,-2.89109324051e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.465007452987,0.00310550128363,9.88459693379,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123900250000,13514,123900250000,RH_EXTIMU,-3.93730419605e-06,-4.56108792637e-06,-0.702973345911,0.711216194207,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000172571243369,-0.0246196089707,-7.88519254016e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.586821494552,-0.00448287666795,9.78351277399,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123902750000,13515,123902750000,RH_EXTIMU,5.3551067287e-06,4.65949942454e-06,-0.702973370983,0.711216169416,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000101668623695,0.0104721185835,-2.82121673584e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.123411275982,-0.00118194899692,9.8350318159,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123905250000,13516,123905250000,RH_EXTIMU,1.78745837719e-05,1.72398904276e-05,-0.702973396322,0.711216143973,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.82999106756e-05,0.0141985891703,-2.87331477294e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.462995379729,-0.00123854540138,9.86733727403,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123907750000,13517,123907750000,RH_EXTIMU,-3.71161235184e-06,-4.42009624747e-06,-0.702973466304,0.711216075212,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000100843469865,-0.0244635630996,-7.8475830424e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.58407751345,0.00226858548536,9.77365236673,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123910250000,13518,123910250000,RH_EXTIMU,5.40979883151e-06,4.88880764149e-06,-0.70297349116,0.71121605063,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.52946985609e-05,0.0104262016877,-2.79713586081e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.123560588041,0.000906952623594,9.81994949698,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123912750000,13519,123912750000,RH_EXTIMU,1.82460474375e-05,1.76704346296e-05,-0.702973516181,0.711216025483,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000115361080265,0.0144912326013,-2.83834463504e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.46859287658,-0.00306675244662,9.86099713696,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123915250000,13520,123915250000,RH_EXTIMU,-3.02158464519e-06,-3.72774620146e-06,-0.702973585868,0.711215957041,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.68190899708e-05,-0.0241354490366,-7.81286556011e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.580165313204,0.0021069395189,9.77765658364,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123917750000,13521,123917750000,RH_EXTIMU,6.10197729258e-06,5.50248527988e-06,-0.702973610485,0.711215932677,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.7099759148e-07,0.0103826487615,-2.77131413824e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.122329504378,-0.000416493797531,9.82592664152,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123920250000,13522,123920250000,RH_EXTIMU,1.8740414778e-05,1.81857099817e-05,-0.70297363529,0.711215907728,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.8148905049e-05,0.0143239996021,-2.81501212577e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.464432648397,-0.00137204263616,9.86667930949,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123922750000,13523,123922750000,RH_EXTIMU,-2.38450797197e-06,-3.18787713503e-06,-0.702973704654,0.711215839636,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.51730223002e-07,-0.0240411991757,-7.77466561472e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.577332853204,9.81979148281e-05,9.78618029983,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123925250000,13524,123925250000,RH_EXTIMU,6.61321556066e-06,5.8849265227e-06,-0.702973729031,0.711215815497,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.71047703488e-05,0.0102223077583,-2.74509158077e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.120102944587,-9.9921182009e-05,9.84289326616,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123927750000,13525,123927750000,RH_EXTIMU,1.90133397157e-05,1.83239490013e-05,-0.702973753653,0.711215790726,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.98869637091e-05,0.0140510328141,-2.79470893995e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.45844282091,-0.00197065670323,9.87233472167,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123930250000,13526,123930250000,RH_EXTIMU,-1.89294215814e-06,-2.8827006023e-06,-0.702973822618,0.711215723041,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.10742646599e-05,-0.0238232572686,-7.72880661807e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.571847467678,-0.000415935155961,9.79106686284,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123932750000,13527,123932750000,RH_EXTIMU,6.87369615673e-06,6.06589166343e-06,-0.702973846879,0.711215699011,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.45241758172e-05,0.0100216773946,-2.73244455959e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.117098446051,0.00109185776546,9.83028782047,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123935250000,13528,123935250000,RH_EXTIMU,1.9316382052e-05,1.82967430815e-05,-0.702973871391,0.711215674345,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000201172154263,0.0139565250337,-2.78249642451e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.455242292137,-0.00453507970137,9.88232986386,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123937750000,13529,123937750000,RH_EXTIMU,-1.3479501726e-06,-2.62310000696e-06,-0.702973939917,0.711215607105,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.44692755566e-06,-0.0235240048245,-7.67832271209e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.565933198967,0.000471831639094,9.80858216525,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123940250000,13530,123940250000,RH_EXTIMU,7.28627160423e-06,6.13344637601e-06,-0.702973964039,0.711215583204,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.18645788018e-05,0.009837940258,-2.71749453611e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.115501185091,-6.30185145363e-05,9.84897871196,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123942750000,13531,123942750000,RH_EXTIMU,1.94522575331e-05,1.82409609296e-05,-0.702973988478,0.711215558612,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000113097285096,0.0137307394823,-2.77458039668e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.448269882963,-0.00267147022004,9.88779670956,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123945250000,13532,123945250000,RH_EXTIMU,-1.20710071626e-06,-2.44298465766e-06,-0.702974056568,0.711215491806,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00012238299957,-0.0233869883945,-7.62908575532e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.561217478607,0.00233094265098,9.7793715007,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123947750000,13533,123947750000,RH_EXTIMU,7.33970619398e-06,6.23948480615e-06,-0.702974080555,0.711215468037,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.99435098026e-05,0.00974663222838,-2.70243917031e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.114708066457,0.000237474840503,9.82039580939,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123950250000,13534,123950250000,RH_EXTIMU,1.90027434106e-05,1.85929816399e-05,-0.702974104892,0.71121544355,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000311404219242,0.013587848697,-2.76316539441e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.44475307003,0.0065061828678,9.85825216584,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123952750000,13535,123952750000,RH_EXTIMU,-1.01042435579e-06,-2.08099667609e-06,-0.702974172654,0.711215377066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0002396799478,-0.0230179131281,-7.59277699043e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.5538050259,-0.00703225057117,9.80042904873,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123955250000,13536,123955250000,RH_EXTIMU,7.63098522311e-06,6.27734236738e-06,-0.702974196565,0.711215353368,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000216165459591,0.00961541358317,-2.69392920868e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.112242882405,-0.00293471698012,9.85885233083,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123957750000,13537,123957750000,RH_EXTIMU,1.92784308964e-05,1.79766599196e-05,-0.702974220773,0.711215329021,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.76193371582e-05,0.0132068704002,-2.74791045488e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.435501662233,-0.00115911499113,9.89144292354,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123960250000,13538,123960250000,RH_EXTIMU,-6.68136806808e-07,-2.25224619085e-06,-0.70297428804,0.711215263018,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.72778239496e-05,-0.022727224894,-7.53665546961e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.54611925421,-0.000739896139587,9.80796194479,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123962750000,13539,123962750000,RH_EXTIMU,7.5717591566e-06,6.20423248427e-06,-0.702974311913,0.711215239358,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.74778965544e-05,0.00944544933326,-2.68989850402e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.110498098325,0.00161697305168,9.83717919221,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123965250000,13540,123965250000,RH_EXTIMU,1.92022343113e-05,1.78058752032e-05,-0.702974336044,0.711215215092,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.28917577025e-05,0.0131417522728,-2.73895743876e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.431836478469,-0.00230055276524,9.87223187399,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123967750000,13541,123967750000,RH_EXTIMU,-4.62383774846e-07,-2.21993212875e-06,-0.702974403032,0.711215149358,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.34843888448e-05,-0.022453104665,-7.50541529028e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.539850715425,-0.00178251748531,9.79094304339,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123970250000,13542,123970250000,RH_EXTIMU,1.22472474739e-05,-3.55315097979e-06,-0.702974441724,0.711215111004,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00798120072754,0.00638907194283,-4.36073380529e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0792290709623,-0.18091309478,9.90262937942,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123972750000,13543,123972750000,RH_EXTIMU,4.6881681235e-06,-1.23137918752e-05,-0.702974502166,0.711215051254,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000625900560287,-0.00923563258077,-6.78846487037e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0972640891957,-0.00406479478015,9.80487882972,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123975250000,13544,123975250000,RH_EXTIMU,1.18942780908e-05,-4.29695300924e-06,-0.702974540728,0.711215013148,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000408431789781,0.00861392590553,-4.34716989524e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0944864128245,0.0077934246676,9.80080902815,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123977750000,13545,123977750000,RH_EXTIMU,4.25558678656e-06,-1.20541651727e-05,-0.702974600892,0.71121495368,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.62969363252e-05,-0.00870948178687,-6.75750543537e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0946750044669,0.000695207248603,9.82488172235,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123980250000,13546,123980250000,RH_EXTIMU,1.18438361247e-05,-4.39039052819e-06,-0.702974639251,0.711214915767,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.54974276238e-06,0.00862794964704,-4.32459089882e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0938414662305,-0.000383396135525,9.83358232988,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123982750000,13547,123982750000,RH_EXTIMU,4.44437943753e-06,-1.20166678052e-05,-0.702974699179,0.711214856531,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,7.87807932962e-05,-0.00850044281321,-6.73121458578e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0911231685093,-0.000754353761627,9.846487148,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123985250000,13548,123985250000,RH_EXTIMU,1.21241660487e-05,-4.4224439014e-06,-0.702974737334,0.711214818816,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,9.87446221624e-05,0.00863985593952,-4.30201323461e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0947987066032,-0.00220340519609,9.87156972947,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123987750000,13549,123987750000,RH_EXTIMU,4.67081140746e-06,-1.18793673092e-05,-0.702974796875,0.711214759967,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.71256373481e-05,-0.00843439634718,-6.68738795021e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0909933415385,0.00104308399983,9.85320924497,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123990250000,13550,123990250000,RH_EXTIMU,1.21123067411e-05,-4.35895183677e-06,-0.702974834918,0.711214722363,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,4.67080166428e-06,0.00846385082515,-4.28919621604e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0924210834232,-0.000415451014933,9.85638108844,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123992750000,13551,123992750000,RH_EXTIMU,-2.81672880102e-06,-4.03467907786e-06,-0.702974887988,0.711214670008,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00867656404398,-0.00821128768551,-5.95899838384e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0867545063007,0.183342438473,9.77231171453,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123995250000,13552,123995250000,RH_EXTIMU,7.55023479954e-06,5.67556461042e-06,-0.70297491145,0.711214646772,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000437663173575,0.0113550262473,-2.6428214551e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.12112316297,-0.00641559411986,9.85836575109,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +123999000000,13553,123997750000,RH_EXTIMU,1.17986082448e-05,1.58734723803e-05,-0.702974942837,0.711214615536,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00331789398268,0.00819152100747,-3.54671105379e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.312088362042,0.0701699424535,9.85366020029,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124000250000,13554,124000250000,RH_EXTIMU,1.90818400564e-06,1.93858563984e-06,-0.702975002127,0.711214557203,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00220933085326,-0.0134907322434,-6.65337987406e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.32929955785,-0.0183409842439,9.80650909563,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124002750000,13555,124002750000,RH_EXTIMU,1.30412212818e-05,1.24662238164e-05,-0.702975039495,0.711214520044,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000413849480408,0.0122509251428,-4.21575967932e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.321073747609,-0.00625228830565,9.85712517498,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124005250000,13556,124005250000,RH_EXTIMU,-9.21822261956e-07,-3.24984567171e-06,-0.702975104695,0.71121445582,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000893829525765,-0.0167945343647,-7.31902434269e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.414423045124,-0.0508562907048,9.81449155548,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124007750000,13557,124007750000,RH_EXTIMU,7.67558353959e-06,5.78562678544e-06,-0.702975127978,0.71121443275,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000189690403883,0.00997593665357,-2.62372431788e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.109274539554,0.00597298704429,9.82982184152,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124010250000,13558,124010250000,RH_EXTIMU,1.15480239545e-05,1.55309816038e-05,-0.702975159264,0.711214401628,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00327728489418,0.00772261298826,-3.53453684546e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.305832411093,0.0674231443032,9.83054508386,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124012750000,13559,124012750000,RH_EXTIMU,2.01945421664e-06,1.52728893251e-06,-0.702975218243,0.711214343591,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00245391491819,-0.0133263804106,-6.61849988176e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.324341361922,-0.0235243071201,9.82254458385,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124015250000,13560,124015250000,RH_EXTIMU,1.74900626541e-05,1.53004345284e-05,-0.702975241867,0.711214319866,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00105659094219,0.0165368904294,-2.67873000244e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.410896100592,-0.0513059993848,9.88478486602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124019000000,13561,124017750000,RH_EXTIMU,4.50928340003e-07,-2.28752322843e-06,-0.702975306625,0.711214256234,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000196339711617,-0.0195895177127,-7.25935134297e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.492886833416,-0.00279781198467,9.81624330446,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124020250000,13562,124020250000,RH_EXTIMU,1.20968142087e-05,-3.56373654487e-06,-0.702975343946,0.711214219237,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00734389314819,0.00582328718681,-4.20618857975e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0701438509317,-0.166918206874,9.92850739408,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124022750000,13563,124022750000,RH_EXTIMU,-2.23350224796e-06,-4.20511932006e-06,-0.702975396432,0.711214167455,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00779283849135,-0.00842401640762,-5.89367383809e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0873592871266,0.173001608849,9.74579556957,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124025250000,13564,124025250000,RH_EXTIMU,7.8623137228e-06,4.75862148601e-06,-0.702975419679,0.711214144434,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000703198363703,0.0107777997157,-2.61918420295e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.116586031648,-0.0111768234041,9.85086297005,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124025250000,13565,124027750000,RH_EXTIMU,1.18742739053e-05,1.43552583597e-05,-0.702975451019,0.711214113273,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00311426928883,0.00771645854291,-3.54008856457e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.296803933448,0.0662143584135,9.84889688847,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124030250000,13566,124030250000,RH_EXTIMU,2.57689381976e-06,9.48374259412e-07,-0.702975509332,0.711214055874,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00224982718612,-0.0128567960121,-6.54376573843e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.314468841869,-0.0205282651781,9.82148742492,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124034000000,13567,124032750000,RH_EXTIMU,1.73892755851e-05,1.42962071904e-05,-0.702975532919,0.711214032209,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000921259634207,0.0159247263799,-2.67452756404e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.397523065725,-0.0478284440062,9.86472135457,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124035250000,13568,124035250000,RH_EXTIMU,8.8639094061e-07,-2.72638997931e-06,-0.702975597295,0.711213968929,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000183510565366,-0.018966267453,-7.21675752999e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.47794146777,-0.00271334755576,9.79186142785,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124037750000,13569,124037750000,RH_EXTIMU,1.24112076779e-05,-3.81420150642e-06,-0.702975634381,0.71121393216,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0071690524341,0.00586239843441,-4.18038232486e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0711681409866,-0.163372973386,9.88974142164,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124040250000,13570,124040250000,RH_EXTIMU,4.1767091693e-06,-1.10103679766e-05,-0.702975692308,0.711213874925,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000638207907787,-0.00872533328161,-6.50498322328e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0954598242833,0.0187524037031,9.68219922,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124042750000,13571,124042750000,RH_EXTIMU,4.75054218579e-06,2.46894145644e-06,-0.702975723077,0.711213844589,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00725400727169,0.00799204967436,-3.4617377099e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0895967230014,0.157857284641,9.75164387602,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124045250000,13572,124045250000,RH_EXTIMU,1.73514717708e-05,1.44546029137e-05,-0.702975746555,0.711213821045,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000429061372702,0.0139060127191,-2.66188828769e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.408372412179,-0.00628051287097,9.86750086214,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124047750000,13573,124047750000,RH_EXTIMU,-9.79491626543e-07,-3.18440454606e-06,-0.702975811382,0.71121375732,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000509950432819,-0.0203450630245,-7.26899141845e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.497541545116,0.0101820434869,9.75480900815,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124051500000,13574,124050250000,RH_EXTIMU,6.00350223352e-06,4.29654075341e-06,-0.702975834509,0.71121373443,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000234017909849,0.00818354155153,-2.60430315542e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0936315029053,0.00506373658261,9.77711996282,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124051500000,13575,124052750000,RH_EXTIMU,1.59247092814e-05,1.49390230198e-05,-0.702975857852,0.711213711061,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000340247117828,0.0116347586567,-2.64410259474e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.391085270747,0.00663745077038,9.78131652894,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124055250000,13576,124055250000,RH_EXTIMU,-2.75230893535e-06,-3.46006159168e-06,-0.702975923362,0.711213646631,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000279389715539,-0.0209721393868,-7.34961736889e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.504219027022,0.00539890954865,9.71180514106,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124057750000,13577,124057750000,RH_EXTIMU,4.93181566286e-06,4.10733597632e-06,-0.702975946335,0.711213623909,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000116284673464,0.00862703279142,-2.58546324354e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.102624175352,-0.00283788197582,9.77575049327,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124060250000,13578,124060250000,RH_EXTIMU,1.50498928386e-05,1.50422523573e-05,-0.702975969313,0.711213600907,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000392694918462,0.0119118610928,-2.60191127765e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.397460385418,0.00794610390742,9.78697564083,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124062750000,13579,124062750000,RH_EXTIMU,3.49627027592e-06,-1.12572550847e-05,-0.702976040792,0.711213530477,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00821666429335,-0.0214611891439,-8.01000442526e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.515307473425,-0.173985789233,9.79972475098,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124065250000,13580,124065250000,RH_EXTIMU,7.36064039041e-06,-5.65228357163e-06,-0.702976077981,0.711213493756,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000953414928846,0.00536231251031,-4.18619948487e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0640763563021,0.0167786504597,9.71764189653,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124067750000,13581,124067750000,RH_EXTIMU,2.14344647326e-05,2.80551079236e-06,-0.702976108182,0.711213463636,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00325109337739,0.0127270871405,-3.42355123379e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.366196703537,-0.0689905565516,9.78863036945,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124070250000,13582,124070250000,RH_EXTIMU,3.53603002001e-06,-9.77682014095e-06,-0.702976167492,0.711213405266,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00310762263764,-0.0172247169999,-6.63963848846e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.425685868581,0.0694401792564,9.70283447181,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124072750000,13583,124072750000,RH_EXTIMU,7.67496101696e-06,-5.33937089693e-06,-0.702976204544,0.711213368658,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000140606469844,0.0048524341987,-4.17138225739e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0623167745559,0.000750634524292,9.80294497737,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124075250000,13584,124075250000,RH_EXTIMU,2.19615816543e-05,2.96054219148e-06,-0.702976234493,0.711213338772,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00346095540719,0.012756930488,-3.39592076698e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.369058400104,-0.0731602811055,9.87310432378,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124077750000,13585,124077750000,RH_EXTIMU,3.90506400812e-06,-9.49091507036e-06,-0.702976293792,0.711213280431,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00327116496429,-0.0172391571248,-6.63739194768e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.426494526322,0.0735043161641,9.75060667725,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124080250000,13586,124080250000,RH_EXTIMU,7.22708414647e-06,-5.16779257869e-06,-0.702976330786,0.711213243883,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000541110395953,0.00432797043396,-4.16406165106e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0533657953147,0.00734893853843,9.79146829374,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124082750000,13587,124082750000,RH_EXTIMU,2.15234945567e-05,2.98566522073e-06,-0.702976360499,0.711213214238,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00354888691006,0.0126791079495,-3.36837379339e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.369671082331,-0.0753762486103,9.86044333941,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124085250000,13588,124085250000,RH_EXTIMU,3.50790667402e-06,-9.54937590653e-06,-0.7029764199,0.711213155785,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00320086811111,-0.0172636963187,-6.64977565952e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.426986389917,0.0724050927872,9.74170770643,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124087750000,13589,124087750000,RH_EXTIMU,7.51275953056e-06,-5.10884080521e-06,-0.702976456696,0.71121311943,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000218630122613,0.00477878690392,-4.14244133221e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0613468387523,0.00143307175839,9.80755891911,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124090250000,13590,124090250000,RH_EXTIMU,2.18929797528e-05,3.18439110502e-06,-0.70297648609,0.711213090089,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00351796365601,0.0128057689804,-3.33335595587e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.370434820735,-0.0745063768455,9.8652886118,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124092750000,13591,124092750000,RH_EXTIMU,3.85549073683e-06,-9.34159345245e-06,-0.702976545519,0.711213031621,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.003218419378,-0.0172708607572,-6.65210812708e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.427386963621,0.0726136018748,9.7421713719,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124095250000,13592,124095250000,RH_EXTIMU,3.22388864229e-06,-3.49134105549e-06,-0.702976582135,0.711212995485,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00364943525084,0.00297341904452,-4.11687258945e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0251391352552,0.0697550552111,9.54026991908,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124097750000,13593,124097750000,RH_EXTIMU,2.6970810322e-06,-2.14949341749e-07,-0.702976619103,0.711212958956,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00214231926275,0.0015679029642,-4.15845772937e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0189353939138,0.0332490588352,9.41724964449,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124100250000,13594,124100250000,RH_EXTIMU,2.08098605397e-05,4.93437436897e-06,-0.702976647029,0.711212931037,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00740975152438,0.0131161009387,-3.16042186661e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.389600635966,-0.153534236987,9.92406560353,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124102750000,13595,124102750000,RH_EXTIMU,7.18462578624e-06,-7.22497036373e-06,-0.702976698463,0.711212880447,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000914165158693,-0.0145808846965,-5.75662278326e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.365423766471,0.036556523241,9.94441101204,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124105250000,13596,124105250000,RH_EXTIMU,3.50249886511e-06,-3.68808868608e-06,-0.702976734131,0.711212845247,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00408409720256,-5.83793049208e-05,-4.0088759912e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0523130720512,0.0821539456866,9.94250465314,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124107750000,13597,124107750000,RH_EXTIMU,2.07320728769e-06,-3.7058225522e-06,-0.702976769766,0.71121281003,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000803251233833,-0.00081389722667,-4.00769072613e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00942680786583,0.00982460264176,9.90157797645,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124111500000,13598,124110250000,RH_EXTIMU,1.41485800323e-06,-3.65767311358e-06,-0.702976805286,0.711212774923,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000401659552166,-0.000342847967617,-3.99515569472e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00307626507461,0.00611218626163,9.8288543578,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124112750000,13599,124112750000,RH_EXTIMU,1.28935165661e-06,-3.66717654902e-06,-0.702976840789,0.711212739832,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-6.60648820388e-05,-7.59897550669e-05,-3.9933919448e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000167048388561,0.000162831725615,9.80637369512,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124115250000,13600,124115250000,RH_EXTIMU,1.2005309174e-06,-3.57123137624e-06,-0.702976876053,0.711212704977,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000104494208161,4.6386666252e-06,-3.9665484303e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00020154732293,0.00267599319058,9.79368549246,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124117750000,13601,124117750000,RH_EXTIMU,6.41022290131e-07,-3.19593285242e-06,-0.702976911056,0.711212670381,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000529404729268,-0.000101123771356,-3.93711604644e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00167102466591,0.0112150078524,9.79316579464,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124120250000,13602,124120250000,RH_EXTIMU,6.94774433593e-06,-1.18612538228e-06,-0.702976938122,0.711212643601,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00245805784884,0.00469030433401,-3.04772809213e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0995551732412,-0.0532555693277,9.78541807971,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124122750000,13603,124122750000,RH_EXTIMU,1.51460876456e-05,5.63420750581e-06,-0.702976965167,0.711212616721,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000828983073966,0.00849116243326,-3.05500700745e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.277079402059,-0.0178508490625,9.81799058064,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124125250000,13604,124125250000,RH_EXTIMU,1.54961676164e-05,5.14757160788e-06,-0.702977005733,0.711212576621,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000472860763765,-8.00030587272e-05,-4.56249136719e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0106613751237,0.00781766204477,9.83098393435,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124125250000,13605,124127750000,RH_EXTIMU,1.52512660004e-05,5.38553418853e-06,-0.702977045857,0.711212536965,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000273166808622,-2.33491378175e-06,-4.51358166975e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000975868903614,0.00326587648297,9.80949654509,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124130250000,13606,124130250000,RH_EXTIMU,1.49111721587e-05,4.97195385864e-06,-0.702977085791,0.711212497504,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.90874331726e-05,-0.000426577661066,-4.4908915521e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00889505572665,-0.000279683472841,9.84519046843,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124132750000,13607,124132750000,RH_EXTIMU,1.42200816054e-05,4.83481903898e-06,-0.702977125375,0.711212458393,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000316087058009,-0.000466682573252,-4.45191928241e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00716636761391,0.00611301619831,9.84497490897,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124135250000,13608,124135250000,RH_EXTIMU,1.35557608263e-05,4.95219662082e-06,-0.702977164641,0.711212419595,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000443988982363,-0.000306817827072,-4.41642516743e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00420769636413,0.00798888146979,9.82820400994,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124137750000,13609,124137750000,RH_EXTIMU,1.26054104973e-05,5.3663765521e-06,-0.702977203739,0.711212380963,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000773647418698,-0.000298804005865,-4.39798638824e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00489786970375,0.0155138765868,9.79682171545,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124140250000,13610,124140250000,RH_EXTIMU,1.22624950737e-05,5.49078237053e-06,-0.702977242564,0.711212342593,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000265071565844,-0.000122066440634,-4.36713360698e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00126177338526,0.0033678478595,9.79912840145,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124142750000,13611,124142750000,RH_EXTIMU,1.18990854146e-05,5.54037886969e-06,-0.702977281188,0.711212304422,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00023466077204,-0.000176156273405,-4.34442602724e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00328730836728,0.00483683175909,9.8125841902,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124142750000,13612,124145250000,RH_EXTIMU,1.13886509674e-05,5.65556607853e-06,-0.702977319574,0.711212266488,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000355200469051,-0.000221521205028,-4.31778534777e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00375764174207,0.00692903585363,9.81341724501,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124147750000,13613,124147750000,RH_EXTIMU,1.11777398234e-05,5.70034725901e-06,-0.702977357696,0.71121222881,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000145185681806,-9.31336374855e-05,-4.28805865444e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000627107309634,0.00186898778263,9.81320951983,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124150250000,13614,124150250000,RH_EXTIMU,1.12697683822e-05,5.72694654071e-06,-0.702977395656,0.711212191288,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,3.7403023555e-05,6.68892136809e-05,-4.27002935867e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0013738797412,-0.000778251604975,9.80416728823,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124152750000,13615,124152750000,RH_EXTIMU,1.09739395576e-05,5.87526905806e-06,-0.702977433401,0.711212153984,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000251731045577,-8.1977924646e-05,-4.24568894703e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00194670688956,0.00524386714945,9.80003880241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124155250000,13616,124155250000,RH_EXTIMU,1.00378636809e-05,7.35258688662e-06,-0.702977471258,0.711212116565,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00136341520236,0.000314116785654,-4.26011903531e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00694791581824,0.0287158323192,9.72163868416,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124169000000,13617,124157750000,RH_EXTIMU,1.05905184409e-05,6.7972587141e-06,-0.702977508832,0.711212079423,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000626750884146,-5.16190665004e-06,-4.22586846849e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00338409496616,-0.0152921614845,9.8450012039,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124169000000,13618,124160250000,RH_EXTIMU,1.00599132257e-05,6.84681921339e-06,-0.702977546077,0.711212042617,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00032976968943,-0.000270204520669,-4.18937412245e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00470799856728,0.00770930875889,9.83432449764,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124169000000,13619,124162750000,RH_EXTIMU,9.53175406697e-06,6.99623240855e-06,-0.702977583006,0.711212006122,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000384533324375,-0.000212015749819,-4.15393975272e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00355683408442,0.00681289108361,9.82594633944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124169000000,13620,124165250000,RH_EXTIMU,8.98518111076e-06,7.10032030088e-06,-0.702977619661,0.711211969897,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000369520081599,-0.000248160058387,-4.1231518162e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00350664621068,0.00628226912191,9.81903196471,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124169000000,13621,124167750000,RH_EXTIMU,8.97754858654e-06,7.1386685143e-06,-0.702977656158,0.711211933822,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.59085560785e-05,1.7526514335e-05,-4.10536874299e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00108292339622,-5.0829826321e-05,9.80951462575,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124171500000,13622,124170250000,RH_EXTIMU,8.86363327391e-06,7.31788271352e-06,-0.702977692485,0.711211897915,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000165600740632,3.79034303295e-05,-4.0864732702e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000425267519861,0.00334910019761,9.80136656091,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124172750000,13623,124172750000,RH_EXTIMU,8.45040840693e-06,7.74407699905e-06,-0.702977728715,0.711211862106,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000474795947872,1.01012193231e-05,-4.07574581245e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000120378760762,0.0099295705062,9.78771780867,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124179000000,13624,124175250000,RH_EXTIMU,8.35896774753e-06,7.92354540125e-06,-0.702977764726,0.71121182651,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000152956313387,5.06874246431e-05,-4.05093474316e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000630621286158,0.00189941203359,9.80666562339,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124179000000,13625,124177750000,RH_EXTIMU,8.31531083018e-06,8.01700823517e-06,-0.702977800616,0.711211791036,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-7.74008233251e-05,2.86256094046e-05,-4.03712914895e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-2.0348746739e-05,0.00175723678586,9.81015689889,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124181500000,13626,124180250000,RH_EXTIMU,7.99839219611e-06,8.41387116562e-06,-0.702977836276,0.711211755788,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000403505216258,4.75734538107e-05,-4.01171470688e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00113375518022,0.00742808684407,9.78405242183,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124181500000,13627,124182750000,RH_EXTIMU,1.13161803982e-05,1.31462401486e-05,-0.702977861746,0.711211730496,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000773680095187,0.00455843842733,-2.87235118361e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0963760372119,0.0482779403209,9.79622135266,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124187750000,13628,124185250000,RH_EXTIMU,1.14884686119e-05,7.87963873595e-06,-0.70297790142,0.711211691355,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00305987085032,-0.00289964307118,-4.45359455988e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0815750336975,-0.0663630695131,9.80725754862,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124187750000,13629,124187750000,RH_EXTIMU,8.72431593279e-06,8.92830277136e-06,-0.70297793692,0.711211656293,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00216246773001,-0.0009578530071,-3.99435215134e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00817824069288,0.0182628087459,9.80517161238,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124190250000,13630,124190250000,RH_EXTIMU,1.11449320016e-05,1.37116985044e-05,-0.702977961822,0.71121163157,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00131284068984,0.00408291719643,-2.80886810253e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0911658624985,0.0567582123464,9.78717223057,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124192750000,13631,124192750000,RH_EXTIMU,1.13391794997e-05,7.8865576326e-06,-0.702978000987,0.711211592943,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00338647816399,-0.00320508491208,-4.39526315346e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0861086781133,-0.07331463732,9.84686726485,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124195250000,13632,124195250000,RH_EXTIMU,8.45101280914e-06,9.14477986046e-06,-0.702978036102,0.71121155826,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00235087960717,-0.000908364429057,-3.95141651837e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00578180489557,0.0222550925743,9.81488779358,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124197750000,13633,124197750000,RH_EXTIMU,1.12205928126e-05,1.40667023176e-05,-0.702978060545,0.711211533981,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00119219651528,0.00435798565401,-2.75742613631e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.095232255168,0.0536910661312,9.79366610066,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124200250000,13634,124200250000,RH_EXTIMU,1.146089552e-05,8.31161788422e-06,-0.702978099212,0.711211495849,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00337328409779,-0.00313932383553,-4.33910902324e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.085896965586,-0.072923125989,9.84298715991,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124202750000,13635,124202750000,RH_EXTIMU,8.80056487127e-06,9.59758053373e-06,-0.702978134208,0.711211461279,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00223684850569,-0.000764450301531,-3.93823254461e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00383342976684,0.0202445202028,9.80838317573,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124205250000,13636,124205250000,RH_EXTIMU,1.26640555599e-05,1.49589627726e-05,-0.702978157944,0.711211437667,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000816940151333,0.0052232207921,-2.67921365982e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.110169052285,0.0465510568812,9.76083695741,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124207750000,13637,124207750000,RH_EXTIMU,-2.17131535774e-06,-5.80617559025e-06,-0.702978218853,0.711211377707,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00323708392642,-0.0201578764045,-6.83425689892e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.447556157623,-0.0687037325768,9.85098793973,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124210250000,13638,124210250000,RH_EXTIMU,1.99765492424e-07,2.20547710252e-06,-0.70297822773,0.711211368957,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00315654218601,0.00589183736855,-9.96918165807e-06,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0506889900916,0.0402548446297,10.1438928719,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124212750000,13639,124212750000,RH_EXTIMU,4.27102709946e-06,1.05459702056e-05,-0.70297823995,0.71121135679,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00237412599182,0.00703508944906,-1.37897256727e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.27541562072,0.0779255573937,10.0326419278,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124215250000,13640,124215250000,RH_EXTIMU,2.67537386963e-06,6.95864443978e-06,-0.70297827356,0.711211323621,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00110957260044,-0.00293844489437,-3.77772125131e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0718252163565,-0.0437709886465,9.8785726905,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124217750000,13641,124217750000,RH_EXTIMU,2.77232929048e-06,6.67352827019e-06,-0.702978306909,0.711211290661,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000215509268819,-0.000107696123052,-3.75100274274e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00638862374288,-0.00463922889538,9.81108477795,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124220250000,13642,124220250000,RH_EXTIMU,2.81619536287e-06,8.10264903428e-06,-0.702978340163,0.711211257777,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000778754028844,0.000837795078144,-3.74164847987e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0170661273178,0.0148298660917,9.67077105918,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124220250000,13643,124222750000,RH_EXTIMU,3.92170577598e-06,6.42630757854e-06,-0.702978373322,0.711211225014,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00157174683711,-0.000332066294289,-3.72809668015e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0130979051741,-0.0283338868225,9.90905687217,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124225250000,13644,124225250000,RH_EXTIMU,2.78637737464e-06,6.48512104926e-06,-0.702978405556,0.711211193157,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00067904205527,-0.000605025947173,-3.62618344719e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00872137714826,0.0139548978877,9.88017353573,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124227750000,13645,124227750000,RH_EXTIMU,2.06706478492e-06,6.40501577425e-06,-0.702978437143,0.711211161939,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000364216475848,-0.000450106296922,-3.55323106465e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00691211591326,0.00491742454661,9.86328579511,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124230250000,13646,124230250000,RH_EXTIMU,2.04973264856e-06,6.69396895611e-06,-0.702978468475,0.711211130967,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00017236352021,0.000154658194913,-3.5245662467e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00466641899237,0.0019372512873,9.82139345731,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124232750000,13647,124232750000,RH_EXTIMU,2.10780572452e-06,6.6466290329e-06,-0.702978499403,0.711211100397,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,5.96651476029e-05,5.72446633186e-06,-3.47884721337e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0014640922695,-0.00163772040325,9.81947795031,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124232750000,13648,124235250000,RH_EXTIMU,1.73502620834e-06,6.57683776639e-06,-0.702978529922,0.711211070234,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00017285032292,-0.000249353737706,-3.43293076134e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00432940951947,0.00365166161012,9.83955853149,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124237750000,13649,124237750000,RH_EXTIMU,2.46390475814e-06,6.9301945971e-06,-0.702978560303,0.711211040198,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000215987584019,0.000610957924824,-3.41742275826e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0110161366731,-0.00473258403826,9.88150815987,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124240250000,13650,124240250000,RH_EXTIMU,2.89031867113e-06,7.64510884736e-06,-0.702978590307,0.711211010533,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00015943906141,0.000646571902349,-3.37534301416e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00887116641805,0.00233012599706,9.85134414846,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124242750000,13651,124242750000,RH_EXTIMU,3.14013653236e-06,8.0477226603e-06,-0.702978619936,0.711210981241,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-8.42842927373e-05,0.000369568098305,-3.33310654118e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00464510684382,0.000643295958937,9.81271542889,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124245250000,13652,124245250000,RH_EXTIMU,3.71238258503e-06,8.02597629026e-06,-0.702978649327,0.711210952188,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000337820190049,0.000309448499741,-3.30580050416e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0038993428137,-0.00685359004988,9.86494769494,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124247750000,13653,124247750000,RH_EXTIMU,3.11372843909e-06,9.35804232149e-06,-0.702978678364,0.711210923474,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00108974641994,0.000421231192132,-3.26768084578e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00675178568975,0.0231128535022,9.78787941538,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124250250000,13654,124250250000,RH_EXTIMU,3.12540998366e-06,8.2196291653e-06,-0.702978706786,0.711210895395,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000646870857252,-0.000641151856926,-3.19598252338e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0150929618743,-0.0157891302641,9.86880094532,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124252750000,13655,124252750000,RH_EXTIMU,2.41578168723e-06,7.15709021821e-06,-0.702978734399,0.711210868116,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000193797752844,-0.00100363417613,-3.10540049234e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0166767813054,-0.00291483819884,9.94288295389,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124252750000,13656,124255250000,RH_EXTIMU,1.55970849425e-06,6.88832888311e-06,-0.702978761127,0.711210841702,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000335931840385,-0.000634357686246,-3.00662588187e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00819238732831,0.0044930793435,9.8901978659,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124257750000,13657,124257750000,RH_EXTIMU,4.36078816328e-06,7.68065168619e-06,-0.702978778296,0.711210824712,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00114813781706,0.00202608653876,-1.93094011445e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0206616889947,-0.0154934729539,9.84922707523,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124260250000,13658,124260250000,RH_EXTIMU,2.44135185102e-06,6.91152823565e-06,-0.702978804323,0.711210799004,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000659556885616,-0.00151706546677,-2.92750529159e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0148346145437,0.00488266224034,9.79847951926,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124262750000,13659,124262750000,RH_EXTIMU,2.46151790755e-06,6.9084640456e-06,-0.702978830144,0.711210773481,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.31972949032e-05,9.59771090915e-06,-2.90446234246e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00432732362596,-0.000709218619838,9.80558664203,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124265250000,13660,124265250000,RH_EXTIMU,2.66457998068e-06,7.09500536248e-06,-0.702978855653,0.711210748264,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.06284605545e-05,0.000220334915517,-2.86949807573e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0033102692507,-0.000107118413675,9.81012793039,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124267750000,13661,124267750000,RH_EXTIMU,5.83914410747e-06,1.32051419464e-05,-0.702978882724,0.711210721401,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00163000994556,0.00526179710988,-3.05044354221e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.109150892733,0.0265011952637,9.03138606248,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124272750000,13662,124270250000,RH_EXTIMU,1.31161355012e-05,1.76569401036e-05,-0.702978913699,0.711210690591,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00163676383442,0.00662539046773,-3.48949842806e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.117410316065,-0.0278105571675,8.22928891415,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124272750000,13663,124272750000,RH_EXTIMU,-2.40722538313e-06,-6.75749101612e-06,-0.702978997505,0.711210608059,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00489796209233,-0.0226211195475,-9.40605704122e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.508506401124,-0.0596421411748,9.16169683972,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124275250000,13664,124275250000,RH_EXTIMU,7.66130842299e-06,5.58579844324e-06,-0.702979009187,0.711210596485,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00121298024513,0.0126853169231,-1.31867382353e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.147812122229,0.0116428585911,9.70394577789,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124277750000,13665,124277750000,RH_EXTIMU,1.89900665771e-05,1.17451459553e-05,-0.702979040099,0.711210565643,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00298179299361,0.00987557786908,-3.49199969396e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.368012214,-0.0621454069364,9.97532536737,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124280250000,13666,124280250000,RH_EXTIMU,4.44128202327e-06,-1.40613528221e-06,-0.702979101647,0.711210505143,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000881737887828,-0.0156646569821,-6.89803621377e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.379119193081,0.0187269207987,9.89120251185,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124282750000,13667,124282750000,RH_EXTIMU,1.03458456189e-06,-1.81749968126e-06,-0.702979145118,0.711210462187,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00170695865359,-0.00214992324516,-4.88859924975e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0110882596659,0.018059362198,9.85936298282,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124282750000,13668,124285250000,RH_EXTIMU,9.78126613386e-06,8.6496909053e-06,-0.70297915607,0.711210451245,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000909988204436,0.0108744881266,-1.24058578969e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.106312327414,0.0157671074282,9.86001528978,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124282750000,13669,124287750000,RH_EXTIMU,1.66522772219e-05,1.41721218344e-05,-0.70297918446,0.711210422968,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000803665267647,0.00700623050885,-3.20511381883e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.271891175945,-0.00517385519766,9.85877814928,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124282750000,13670,124290250000,RH_EXTIMU,2.29315273784e-06,-2.7916517028e-07,-0.702979243339,0.711210365102,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-4.27225973898e-05,-0.0162976573794,-6.60135743007e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.3776992778,0.00120243698219,9.80724773619,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124291500000,13671,124292750000,RH_EXTIMU,1.61596350055e-05,1.54557781267e-05,-0.702979254046,0.711210354172,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000959482075706,0.0167509631626,-1.22706653735e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.387635027797,0.00604483792428,9.82234389208,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124295250000,13672,124295250000,RH_EXTIMU,2.56671075075e-06,-1.79272898225e-07,-0.702979312262,0.711210296976,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.00105895188572,-0.0165402831904,-6.52552050218e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.385583307364,-0.00871062383178,9.80117772956,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124297750000,13673,124297750000,RH_EXTIMU,1.62812427003e-05,1.52580450582e-05,-0.702979322058,0.711210286948,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000878559036445,0.0164961693605,-1.12468266707e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.383848380239,0.00569190660419,9.82095651598,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124300250000,13674,124300250000,RH_EXTIMU,4.54406386377e-06,2.05127572239e-06,-0.702979379667,0.711210230338,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.000749188181383,-0.0141150274445,-6.45857802832e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.343256313438,-0.00184209153251,9.79568625152,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124302750000,13675,124302750000,RH_EXTIMU,1.66987921926e-05,1.48219285585e-05,-0.702979404529,0.711210205431,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000266350648052,0.0141017138119,-2.81793290496e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.352980757823,0.00581173431987,9.87083591004,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124305250000,13676,124305250000,RH_EXTIMU,3.03049490136e-06,1.72817069646e-06,-0.702979458996,0.711210151936,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000413110975134,-0.015136756662,-6.10620843704e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.373114017452,0.00712647943961,9.83988213763,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124307750000,13677,124307750000,RH_EXTIMU,1.42248770911e-05,1.32577036e-05,-0.702979481852,0.711210129088,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000114773149053,0.0128554732435,-2.58661722717e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.341036127855,0.00112751418499,9.84835302451,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124310250000,13678,124310250000,RH_EXTIMU,1.07456287075e-06,-1.1686367146e-08,-0.70297953414,0.71121007767,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.96210927515e-05,-0.0149453805532,-5.86550476226e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.373417743974,-0.00021898378786,9.89347370318,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124312750000,13679,124312750000,RH_EXTIMU,1.25866466607e-05,1.5379821455e-05,-0.702979538775,0.711210072812,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.0021059239897,0.0152314838155,-5.38234505887e-06,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.358577642633,0.0297462365377,9.94361933757,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124315250000,13680,124315250000,RH_EXTIMU,-6.06512422357e-06,-2.47197234142e-06,-0.702979605251,0.711210007352,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.000572703770506,-0.0206465509536,-7.46860402049e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.467875559425,0.0532397578196,9.8096555236,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124320250000,13681,124317750000,RH_EXTIMU,1.10747774393e-05,2.18215748282e-05,-0.702979611465,0.711210000819,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00391023893398,0.0234614521535,-7.12578174347e-06,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.41239583596,0.0855695666077,9.78695254151,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +124320250000,13682,124320250000,RH_EXTIMU,1.54441756041e-05,3.33331097357e-05,-0.702979677557,0.711209934964,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-0.00398784999429,0.00900697382457,-7.46660532534e-05,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.154699949727,0.0598659055842,9.97228429688,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 From fd43d817df34b7809e11080c126e0715f7d00448 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 15 Dec 2020 10:50:28 -0500 Subject: [PATCH 176/261] save time in CSV, formatting --- tests/testImuPreintegration.cpp | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/testImuPreintegration.cpp b/tests/testImuPreintegration.cpp index 43b3461ee..9c55960f8 100644 --- a/tests/testImuPreintegration.cpp +++ b/tests/testImuPreintegration.cpp @@ -34,7 +34,7 @@ using namespace gtsam; * acceleration input. */ TEST(TestImuPreintegration, LoadedSimulationData) { - Eigen::Vector3d finalPos; + Vector3 finalPos(0, 0, 0); vector imuMeasurements; @@ -72,10 +72,8 @@ TEST(TestImuPreintegration, LoadedSimulationData) { // Assume a Z-up navigation (assuming we are performing optimization in the // IMU frame). - boost::shared_ptr - imuPreintegratedParams = - PreintegratedCombinedMeasurements::Params::MakeSharedU( - gravity); + auto imuPreintegratedParams = + PreintegratedCombinedMeasurements::Params::MakeSharedU(gravity); imuPreintegratedParams->accelerometerCovariance = I_3x3 * pow(accNoiseSigma, 2); imuPreintegratedParams->biasAccCovariance = I_3x3 * pow(accBiasRwSigma, 2); @@ -86,29 +84,29 @@ TEST(TestImuPreintegration, LoadedSimulationData) { // Initial state Pose3 priorPose; - Vector3 priorVelocity; + Vector3 priorVelocity(0, 0, 0); imuBias::ConstantBias priorImuBias; PreintegratedCombinedMeasurements imuPreintegrated; - Eigen::Vector3d position; - Eigen::Vector3d velocity; + Vector3 position(0, 0, 0); + Vector3 velocity(0, 0, 0); NavState propState; NavState initialNavState(priorPose, priorVelocity); // Bias estimated by my Algorithm - priorImuBias = imuBias::ConstantBias( - Eigen::Vector3d(-0.0314648, 0.0219921, 6.95945e-05), - Eigen::Vector3d(4.88581e-08, -1.04971e-09, -0.000122868)); + priorImuBias = + imuBias::ConstantBias(Vector3(-0.0314648, 0.0219921, 6.95945e-05), + Vector3(4.88581e-08, -1.04971e-09, -0.000122868)); // zero bias - // priorImuBias = imuBias::ConstantBias(Eigen::Vector3d(0,0,0), - // Eigen::Vector3d(0,0,0)); + // priorImuBias = imuBias::ConstantBias(Vector3(0, 0, 0), Vector3(0, 0, 0)); - imuPreintegrated = PreintegratedCombinedMeasurements( - imuPreintegratedParams, priorImuBias); + imuPreintegrated = + PreintegratedCombinedMeasurements(imuPreintegratedParams, priorImuBias); // Put header row in output csv - outputFile << "X Position," + outputFile << "Time [s]," + << "X Position," << "Y Position," << "Z Position," << "X Velocity," @@ -128,11 +126,13 @@ TEST(TestImuPreintegration, LoadedSimulationData) { // cout << "IMU Position " << position.transpose() << endl; // cout << "IMU Velocity " << velocity.transpose() << endl; + size_t time = imuMeasurements[n].time - imuMeasurements[0].time; + // Write to csv - outputFile << to_string(position.x()) << "," << to_string(position.y()) - << "," << to_string(position.z()) << "," - << to_string(velocity.x()) << "," << to_string(velocity.y()) - << "," << to_string(velocity.z()) << "," + outputFile << time << "," << to_string(position.x()) << "," + << to_string(position.y()) << "," << to_string(position.z()) + << "," << to_string(velocity.x()) << "," + << to_string(velocity.y()) << "," << to_string(velocity.z()) << "\n"; } From 75bd3dc52cb48126f84df1f7822f5b46278b8a69 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Mon, 21 Dec 2020 20:32:21 -0500 Subject: [PATCH 177/261] templating on params is still problematic --- gtsam/nonlinear/GaussNewtonOptimizer.h | 2 ++ gtsam/nonlinear/GncOptimizer.h | 14 ++++++++++---- gtsam/nonlinear/LevenbergMarquardtParams.h | 3 +++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/gtsam/nonlinear/GaussNewtonOptimizer.h b/gtsam/nonlinear/GaussNewtonOptimizer.h index a436597e5..3ef4dfdeb 100644 --- a/gtsam/nonlinear/GaussNewtonOptimizer.h +++ b/gtsam/nonlinear/GaussNewtonOptimizer.h @@ -28,6 +28,8 @@ class GaussNewtonOptimizer; * NonlinearOptimizationParams. */ class GTSAM_EXPORT GaussNewtonParams : public NonlinearOptimizerParams { +public: + typedef GaussNewtonOptimizer OptimizerType; }; /** diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index 811487779..730c1aa43 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -36,6 +36,9 @@ namespace gtsam { template class GncParams { public: + //typedef BaseOptimizerParameters::OptimizerType GncOptimizerType; + typedef BaseOptimizerParameters::OptimizerType OptimizerType; + /** Verbosity levels */ enum VerbosityGNC { SILENT = 0, SUMMARY, VALUES @@ -46,8 +49,6 @@ public: GM /*Geman McClure*/, TLS /*Truncated least squares*/ }; - using BaseOptimizer = GaussNewtonOptimizer; // BaseOptimizerParameters::OptimizerType; - /// Constructor GncParams(const BaseOptimizerParameters& baseOptimizerParams) : baseOptimizerParams(baseOptimizerParams) { @@ -145,6 +146,11 @@ template class GncOptimizer { public: // types etc +// typedef BaseOptimizerParameters::OptimizerType GncOptimizerType; + // typedef GncParameters::BaseOptimizerParameters::OptimizerType BaseOptimizer; // + //typedef BaseOptimizerParameters::OptimizerType BaseOptimizer; + //typedef GaussNewtonOptimizer BaseOptimizer; + typedef GncParameters::OptimizerType BaseOptimizer; private: NonlinearFactorGraph nfg_; @@ -198,7 +204,7 @@ public: Values optimize() { // start by assuming all measurements are inliers weights_ = Vector::Ones(nfg_.size()); - GaussNewtonOptimizer baseOptimizer(nfg_, state_); + BaseOptimizer baseOptimizer(nfg_, state_); Values result = baseOptimizer.optimize(); double mu = initializeMu(); double mu_prev = mu; @@ -229,7 +235,7 @@ public: // variable/values update NonlinearFactorGraph graph_iter = this->makeWeightedGraph(weights_); - GaussNewtonOptimizer baseOptimizer_iter(graph_iter, state_); + BaseOptimizer baseOptimizer_iter(graph_iter, state_); result = baseOptimizer_iter.optimize(); // update mu diff --git a/gtsam/nonlinear/LevenbergMarquardtParams.h b/gtsam/nonlinear/LevenbergMarquardtParams.h index 4962ad366..20a8eb4c1 100644 --- a/gtsam/nonlinear/LevenbergMarquardtParams.h +++ b/gtsam/nonlinear/LevenbergMarquardtParams.h @@ -25,6 +25,8 @@ namespace gtsam { +class LevenbergMarquardtOptimizer; + /** Parameters for Levenberg-Marquardt optimization. Note that this parameters * class inherits from NonlinearOptimizerParams, which specifies the parameters * common to all nonlinear optimization algorithms. This class also contains @@ -40,6 +42,7 @@ public: static VerbosityLM verbosityLMTranslator(const std::string &s); static std::string verbosityLMTranslator(VerbosityLM value); + typedef LevenbergMarquardtOptimizer OptimizerType; public: From 7efd5cc3681816d0977ac6e59b054aaeed99cfca Mon Sep 17 00:00:00 2001 From: lcarlone Date: Mon, 21 Dec 2020 21:06:25 -0500 Subject: [PATCH 178/261] finally fixed the typedef --- gtsam/nonlinear/GncOptimizer.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index 730c1aa43..dd6c8d17d 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -36,8 +36,8 @@ namespace gtsam { template class GncParams { public: - //typedef BaseOptimizerParameters::OptimizerType GncOptimizerType; - typedef BaseOptimizerParameters::OptimizerType OptimizerType; + /** For each parameter, specify the corresponding optimizer: e.g., GaussNewtonParams -> GaussNewtonOptimizer */ + typedef typename BaseOptimizerParameters::OptimizerType OptimizerType; /** Verbosity levels */ enum VerbosityGNC { @@ -145,12 +145,8 @@ public: template class GncOptimizer { public: - // types etc -// typedef BaseOptimizerParameters::OptimizerType GncOptimizerType; - // typedef GncParameters::BaseOptimizerParameters::OptimizerType BaseOptimizer; // - //typedef BaseOptimizerParameters::OptimizerType BaseOptimizer; - //typedef GaussNewtonOptimizer BaseOptimizer; - typedef GncParameters::OptimizerType BaseOptimizer; + /** For each parameter, specify the corresponding optimizer: e.g., GaussNewtonParams -> GaussNewtonOptimizer */ + typedef typename GncParameters::OptimizerType BaseOptimizer; private: NonlinearFactorGraph nfg_; From 0e09f019ef14265f83b5a91348807280fcfc634a Mon Sep 17 00:00:00 2001 From: lcarlone Date: Mon, 21 Dec 2020 22:28:07 -0500 Subject: [PATCH 179/261] fixed templating, added a strict unit test on inlier threshold --- gtsam/nonlinear/GncOptimizer.h | 12 +++--- tests/testGncOptimizer.cpp | 70 ++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index dd6c8d17d..d4b25409f 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -264,11 +264,12 @@ public: // set initial mu switch (params_.lossType) { case GncParameters::GM: + // surrogate cost is convex for large mu return 2 * rmax_sq / params_.barcSq; // initial mu case GncParameters::TLS: - // initialize mu to the value specified in Remark 5 in GNC paper - // degenerate case: residual is close to zero so mu approximately equals - // to -1 + // initialize mu to the value specified in Remark 5 in GNC paper. + // surrogate cost is convex for mu close to zero + // degenerate case: 2 * rmax_sq - params_.barcSq < 0 (handled in the main loop) return params_.barcSq / (2 * rmax_sq - params_.barcSq); default: throw std::runtime_error( @@ -280,9 +281,10 @@ public: double updateMu(const double mu) const { switch (params_.lossType) { case GncParameters::GM: - return std::max(1.0, mu / params_.muStep); // reduce mu, but saturate at 1 + // reduce mu, but saturate at 1 (original cost is recovered for mu -> 1) + return std::max(1.0, mu / params_.muStep); case GncParameters::TLS: - // increases mu at each iteration + // increases mu at each iteration (original cost is recovered for mu -> inf) return mu * params_.muStep; default: throw std::runtime_error( diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index b3bef11e0..85a196bd7 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -285,6 +286,75 @@ TEST(GncOptimizer, calculateWeightsTLS) { CHECK(assert_equal(weights_expected, weights_actual, tol)); } +/* ************************************************************************* */ +TEST(GncOptimizer, calculateWeightsTLS2) { + + // create values + Point2 x_val(0.0, 0.0); + Point2 x_prior(1.0, 0.0); + Values initial; + initial.insert(X(1), x_val); + + // create very simple factor graph with a single factor 0.5 * 1/sigma^2 * || x - [1;0] ||^2 + double sigma = 1; + SharedDiagonal noise = + noiseModel::Diagonal::Sigmas(Vector2(sigma, sigma)); + NonlinearFactorGraph nfg; + nfg.add(PriorFactor(X(1),x_prior,noise)); + + // cost of the factor: + DOUBLES_EQUAL(0.5 * 1/(sigma*sigma), nfg.error(initial), tol); + + // check the TLS weights are correct: CASE 1: residual below barcsq + { + // expected: + Vector weights_expected = Vector::Zero(1); + weights_expected[0] = 1.0; // inlier + // actual: + GaussNewtonParams gnParams; + GncParams gncParams(gnParams); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + gncParams.setInlierThreshold(0.51); // if inlier threshold is slightly larger than 0.5, then measurement is inlier + auto gnc = GncOptimizer>(nfg, initial, gncParams); + double mu = 1e6; + Vector weights_actual = gnc.calculateWeights(initial, mu); + CHECK(assert_equal(weights_expected, weights_actual, tol)); + } + // check the TLS weights are correct: CASE 2: residual above barcsq + { + // expected: + Vector weights_expected = Vector::Zero(1); + weights_expected[0] = 0.0; // outlier + // actual: + GaussNewtonParams gnParams; + GncParams gncParams(gnParams); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + gncParams.setInlierThreshold(0.49); // if inlier threshold is slightly below 0.5, then measurement is outlier + auto gnc = GncOptimizer>(nfg, initial, gncParams); + double mu = 1e6; // very large mu recovers original TLS cost + Vector weights_actual = gnc.calculateWeights(initial, mu); + CHECK(assert_equal(weights_expected, weights_actual, tol)); + } + // check the TLS weights are correct: CASE 2: residual at barcsq + { + // expected: + Vector weights_expected = Vector::Zero(1); + weights_expected[0] = 0.5; // undecided + // actual: + GaussNewtonParams gnParams; + GncParams gncParams(gnParams); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + gncParams.setInlierThreshold(0.5); // if inlier threshold is slightly below 0.5, then measurement is outlier + auto gnc = GncOptimizer>(nfg, initial, gncParams); + double mu = 1e6; // very large mu recovers original TLS cost + Vector weights_actual = gnc.calculateWeights(initial, mu); + CHECK(assert_equal(weights_expected, weights_actual, 1e-5)); + } +} + /* ************************************************************************* */ TEST(GncOptimizer, makeWeightedGraph) { // create original factor From cd82a56214b931884e83e19a0182252add9b7687 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Mon, 21 Dec 2020 22:32:34 -0500 Subject: [PATCH 180/261] made function name less ambiguous, added more comments on inlierThreshold --- gtsam/nonlinear/GncOptimizer.h | 5 ++++- tests/testGncOptimizer.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index d4b25409f..df87c4433 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -83,8 +83,11 @@ public: } /** Set the maximum weighted residual error for an inlier. For a factor in the form f(x) = 0.5 * || r(x) ||^2_Omega, * the inlier threshold is the largest value of f(x) for the corresponding measurement to be considered an inlier. + * In other words, an inlier at x is such that 0.5 * || r(x) ||^2_Omega <= barcSq. + * Assuming a isotropic measurement covariance sigma^2 * Identity, the cost becomes: 0.5 * 1/sigma^2 || r(x) ||^2 <= barcSq. + * Hence || r(x) ||^2 <= 2 * barcSq * sigma^2 * */ - void setInlierThreshold(const double inth) { + void setInlierCostThreshold(const double inth) { barcSq = inth; } /// Set the graduated non-convexity step: at each GNC iteration, mu is updated as mu <- mu * muStep diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 85a196bd7..7c4fbd5fa 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -254,7 +254,7 @@ TEST(GncOptimizer, calculateWeightsGM) { double barcSq = 5.0; weights_expected[3] = std::pow(mu * barcSq / (50.0 + mu * barcSq), 2); // outlier, error = 50 - gncParams.setInlierThreshold(barcSq); + gncParams.setInlierCostThreshold(barcSq); auto gnc2 = GncOptimizer>(fg, initial, gncParams); weights_actual = gnc2.calculateWeights(initial, mu); @@ -315,7 +315,7 @@ TEST(GncOptimizer, calculateWeightsTLS2) { GncParams gncParams(gnParams); gncParams.setLossType( GncParams::RobustLossType::TLS); - gncParams.setInlierThreshold(0.51); // if inlier threshold is slightly larger than 0.5, then measurement is inlier + gncParams.setInlierCostThreshold(0.51); // if inlier threshold is slightly larger than 0.5, then measurement is inlier auto gnc = GncOptimizer>(nfg, initial, gncParams); double mu = 1e6; Vector weights_actual = gnc.calculateWeights(initial, mu); @@ -331,7 +331,7 @@ TEST(GncOptimizer, calculateWeightsTLS2) { GncParams gncParams(gnParams); gncParams.setLossType( GncParams::RobustLossType::TLS); - gncParams.setInlierThreshold(0.49); // if inlier threshold is slightly below 0.5, then measurement is outlier + gncParams.setInlierCostThreshold(0.49); // if inlier threshold is slightly below 0.5, then measurement is outlier auto gnc = GncOptimizer>(nfg, initial, gncParams); double mu = 1e6; // very large mu recovers original TLS cost Vector weights_actual = gnc.calculateWeights(initial, mu); @@ -347,7 +347,7 @@ TEST(GncOptimizer, calculateWeightsTLS2) { GncParams gncParams(gnParams); gncParams.setLossType( GncParams::RobustLossType::TLS); - gncParams.setInlierThreshold(0.5); // if inlier threshold is slightly below 0.5, then measurement is outlier + gncParams.setInlierCostThreshold(0.5); // if inlier threshold is slightly below 0.5, then measurement is outlier auto gnc = GncOptimizer>(nfg, initial, gncParams); double mu = 1e6; // very large mu recovers original TLS cost Vector weights_actual = gnc.calculateWeights(initial, mu); From 046db8749e985144ece86d44a42dc932b41528e6 Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Tue, 22 Dec 2020 13:40:52 -0500 Subject: [PATCH 181/261] Fix TLS convergence check --- gtsam/nonlinear/GncOptimizer.h | 61 +++++++++++++++++++++++++++------- tests/testGncOptimizer.cpp | 4 +-- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index df87c4433..0f4d5ea27 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -66,7 +66,7 @@ public: size_t maxIterations = 100; /* maximum number of iterations*/ double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ - double relativeMuTol = 1e-5; ///< The maximum relative mu decrease to stop iterating + double relativeCostTol = 1e-5; ///< The maximum relative cost change to stop iterating VerbosityGNC verbosityGNC = SILENT; /* verbosity level */ std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ @@ -95,8 +95,7 @@ public: muStep = step; } /// Set the maximum relative difference in mu values to stop iterating - void setRelativeMuTol(double value) { - relativeMuTol = value; + void setRelativeMuTol(double value) { relativeCostTol = value; } /// Set the verbosity level void setVerbosityGNC(const VerbosityGNC verbosity) { @@ -206,7 +205,8 @@ public: BaseOptimizer baseOptimizer(nfg_, state_); Values result = baseOptimizer.optimize(); double mu = initializeMu(); - double mu_prev = mu; + double cost = calculateWeightedCost(); + double prev_cost = cost; // handle the degenerate case that corresponds to small // maximum residual errors at initialization @@ -232,17 +232,17 @@ public: // weights update weights_ = calculateWeights(result, mu); + // update cost + prev_cost = cost; + cost = calculateWeightedCost(); + // variable/values update NonlinearFactorGraph graph_iter = this->makeWeightedGraph(weights_); BaseOptimizer baseOptimizer_iter(graph_iter, state_); result = baseOptimizer_iter.optimize(); - // update mu - mu_prev = mu; - mu = updateMu(mu); - // stopping condition - if (checkMuConvergence(mu, mu_prev)) { + if (checkConvergence(mu, cost, prev_cost)) { // display info if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { std::cout << "final iterations: " << iter << std::endl; @@ -251,6 +251,9 @@ public: } break; } + + // update mu + mu = updateMu(mu); } return result; } @@ -295,19 +298,53 @@ public: } } + /// calculated sum of weighted squared residuals + double calculateWeightedCost() const { + double cost = 0; + for (size_t i = 0; i < nfg_.size(); i++) { + cost += weights_[i] * nfg_[i]->error(state_); + } + return cost; + } + /// check if we have reached the value of mu for which the surrogate loss matches the original loss - bool checkMuConvergence(const double mu, const double mu_prev) const { + bool checkMuConvergence(const double mu) const { switch (params_.lossType) { case GncParameters::GM: return std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function - case GncParameters::TLS: - return std::fabs(mu - mu_prev) < params_.relativeMuTol; default: throw std::runtime_error( "GncOptimizer::checkMuConvergence: called with unknown loss type."); } } + /// check convergence of relative cost differences + bool checkCostConvergence(const double cost, const double prev_cost) const { + switch (params_.lossType) { + case GncParameters::TLS: + return std::fabs(cost - prev_cost) < params_.relativeCostTol; + default: + throw std::runtime_error( + "GncOptimizer::checkMuConvergence: called with unknown loss type."); + } + } + + /// check for convergence between consecutive GNC iterations + bool checkConvergence(const double mu, + const double cost, + const double prev_cost) const { + switch (params_.lossType) { + case GncParameters::GM: + return checkMuConvergence(mu); + case GncParameters::TLS: + return checkCostConvergence(cost, prev_cost); + default: + throw std::runtime_error( + "GncOptimizer::checkMuConvergence: called with unknown loss type."); + } + } + + /// create a graph where each factor is weighted by the gnc weights NonlinearFactorGraph makeWeightedGraph(const Vector& weights) const { // make sure all noiseModels are Gaussian or convert to Gaussian diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 7c4fbd5fa..a0e371463 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -202,7 +202,7 @@ TEST(GncOptimizer, checkMuConvergenceGM) { GncOptimizer>(fg, initial, gncParams); double mu = 1.0; - CHECK(gnc.checkMuConvergence(mu, 0)); + CHECK(gnc.checkMuConvergence(mu)); } /* ************************************************************************* */ @@ -222,7 +222,7 @@ TEST(GncOptimizer, checkMuConvergenceTLS) { GncOptimizer>(fg, initial, gncParams); double mu = 1.0; - CHECK(gnc.checkMuConvergence(mu, mu)); + CHECK(gnc.checkMuConvergence(mu)); } /* ************************************************************************* */ From be5d3d234382f32da17b4aed14432baa7d8c085d Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Tue, 22 Dec 2020 20:28:10 -0500 Subject: [PATCH 182/261] update function name --- gtsam/nonlinear/GncOptimizer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index 0f4d5ea27..d47b6bc82 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -95,7 +95,7 @@ public: muStep = step; } /// Set the maximum relative difference in mu values to stop iterating - void setRelativeMuTol(double value) { relativeCostTol = value; + void setRelativeCostTol(double value) { relativeCostTol = value; } /// Set the verbosity level void setVerbosityGNC(const VerbosityGNC verbosity) { From c57174436f31662f0154fc241d05b9bbe5cce49a Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Tue, 22 Dec 2020 21:08:42 -0500 Subject: [PATCH 183/261] fix test --- tests/testGncOptimizer.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index a0e371463..dc96762b8 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -206,7 +206,7 @@ TEST(GncOptimizer, checkMuConvergenceGM) { } /* ************************************************************************* */ -TEST(GncOptimizer, checkMuConvergenceTLS) { +TEST(GncOptimizer, checkConvergenceTLS) { // has to have Gaussian noise models ! auto fg = example::createReallyNonlinearFactorGraph(); @@ -216,13 +216,14 @@ TEST(GncOptimizer, checkMuConvergenceTLS) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); + gncParams.setRelativeCostTol(1e-5); gncParams.setLossType( GncParams::RobustLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); - double mu = 1.0; - CHECK(gnc.checkMuConvergence(mu)); + CHECK(gnc.checkCostConvergence(1.0, 1.0)); + CHECK(!gnc.checkCostConvergence(1.0, 2.0)); } /* ************************************************************************* */ From dc5c769e7ca4a9cd6d23a1def4d4a95bfa32a93e Mon Sep 17 00:00:00 2001 From: lcarlone Date: Wed, 23 Dec 2020 22:08:44 -0500 Subject: [PATCH 184/261] - fixed stopping conditions - handled degenerate case in mu initialization - set TLS as default - added more unit tests --- gtsam/nonlinear/GncOptimizer.h | 128 +++++++++++++++++---------- tests/testGncOptimizer.cpp | 155 ++++++++++++++++++++++++++++++++- 2 files changed, 233 insertions(+), 50 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index d47b6bc82..b66e0f523 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -62,11 +62,12 @@ public: /// GNC parameters BaseOptimizerParameters baseOptimizerParams; /*optimization parameters used to solve the weighted least squares problem at each GNC iteration*/ /// any other specific GNC parameters: - RobustLossType lossType = GM; /* default loss*/ + RobustLossType lossType = TLS; /* default loss*/ size_t maxIterations = 100; /* maximum number of iterations*/ double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ - double relativeCostTol = 1e-5; ///< The maximum relative cost change to stop iterating + double relativeCostTol = 1e-5; ///< if relative cost change if below this threshold, stop iterating + double weightsTol = 1e-4; ///< if the weights are within weightsTol from being binary, stop iterating (only for TLS) VerbosityGNC verbosityGNC = SILENT; /* verbosity level */ std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ @@ -97,6 +98,9 @@ public: /// Set the maximum relative difference in mu values to stop iterating void setRelativeCostTol(double value) { relativeCostTol = value; } + /// Set the maximum difference between the weights and their rounding in {0,1} to stop iterating + void setWeightsTol(double value) { weightsTol = value; + } /// Set the verbosity level void setVerbosityGNC(const VerbosityGNC verbosity) { verbosityGNC = verbosity; @@ -136,6 +140,8 @@ public: std::cout << "maxIterations: " << maxIterations << "\n"; std::cout << "barcSq: " << barcSq << "\n"; std::cout << "muStep: " << muStep << "\n"; + std::cout << "relativeCostTol: " << relativeCostTol << "\n"; + std::cout << "weightsTol: " << weightsTol << "\n"; std::cout << "verbosityGNC: " << verbosityGNC << "\n"; for (size_t i = 0; i < knownInliers.size(); i++) std::cout << "knownInliers: " << knownInliers[i] << "\n"; @@ -205,8 +211,8 @@ public: BaseOptimizer baseOptimizer(nfg_, state_); Values result = baseOptimizer.optimize(); double mu = initializeMu(); - double cost = calculateWeightedCost(); - double prev_cost = cost; + double prev_cost = nfg_.error(result); + double cost = 0.0; // this will be updated in the main loop // handle the degenerate case that corresponds to small // maximum residual errors at initialization @@ -215,16 +221,21 @@ public: if (mu <= 0) { if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { std::cout << "GNC Optimizer stopped because maximum residual at " - "initialization is small." << std::endl; + "initialization is small." << std::endl; + } + if (params_.verbosityGNC >= GncParameters::VerbosityGNC::VALUES) { result.print("result\n"); + std::cout << "mu: " << mu << std::endl; } return result; } - for (size_t iter = 0; iter < params_.maxIterations; iter++) { + size_t iter; + for (iter = 0; iter < params_.maxIterations; iter++) { // display info if (params_.verbosityGNC >= GncParameters::VerbosityGNC::VALUES) { + std::cout << "iter: " << iter << std::endl; result.print("result\n"); std::cout << "mu: " << mu << std::endl; std::cout << "weights: " << weights_ << std::endl; @@ -232,28 +243,34 @@ public: // weights update weights_ = calculateWeights(result, mu); - // update cost - prev_cost = cost; - cost = calculateWeightedCost(); - // variable/values update NonlinearFactorGraph graph_iter = this->makeWeightedGraph(weights_); BaseOptimizer baseOptimizer_iter(graph_iter, state_); result = baseOptimizer_iter.optimize(); // stopping condition - if (checkConvergence(mu, cost, prev_cost)) { - // display info - if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { - std::cout << "final iterations: " << iter << std::endl; - std::cout << "final mu: " << mu << std::endl; - std::cout << "final weights: " << weights_ << std::endl; - } - break; - } + cost = graph_iter.error(result); + if (checkConvergence(mu, weights_, cost, prev_cost)) { break; } // update mu mu = updateMu(mu); + + // get ready for next iteration + prev_cost = cost; + + // display info + if (params_.verbosityGNC >= GncParameters::VerbosityGNC::VALUES) { + std::cout << "previous cost: " << prev_cost << std::endl; + std::cout << "current cost: " << cost << std::endl; + } + } + // display info + if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { + std::cout << "final iterations: " << iter << std::endl; + std::cout << "final mu: " << mu << std::endl; + std::cout << "final weights: " << weights_ << std::endl; + std::cout << "previous cost: " << prev_cost << std::endl; + std::cout << "current cost: " << cost << std::endl; } return result; } @@ -276,7 +293,9 @@ public: // initialize mu to the value specified in Remark 5 in GNC paper. // surrogate cost is convex for mu close to zero // degenerate case: 2 * rmax_sq - params_.barcSq < 0 (handled in the main loop) - return params_.barcSq / (2 * rmax_sq - params_.barcSq); + // according to remark mu = params_.barcSq / (2 * rmax_sq - params_.barcSq) = params_.barcSq/ excessResidual + // however, if the denominator is 0 or negative, we return mu = -1 which leads to termination of the main GNC loop + return (2 * rmax_sq - params_.barcSq) > 0 ? params_.barcSq / (2 * rmax_sq - params_.barcSq) : -1; default: throw std::runtime_error( "GncOptimizer::initializeMu: called with unknown loss type."); @@ -298,53 +317,68 @@ public: } } - /// calculated sum of weighted squared residuals - double calculateWeightedCost() const { - double cost = 0; - for (size_t i = 0; i < nfg_.size(); i++) { - cost += weights_[i] * nfg_[i]->error(state_); - } - return cost; - } - /// check if we have reached the value of mu for which the surrogate loss matches the original loss bool checkMuConvergence(const double mu) const { + bool muConverged = false; switch (params_.lossType) { case GncParameters::GM: - return std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function + muConverged = std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function + break; + case GncParameters::TLS: + muConverged = false; // for TLS there is no stopping condition on mu (it must tend to infinity) + break; default: throw std::runtime_error( "GncOptimizer::checkMuConvergence: called with unknown loss type."); } + if (muConverged && params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) + std::cout << "muConverged = true " << std::endl; + return muConverged; } /// check convergence of relative cost differences bool checkCostConvergence(const double cost, const double prev_cost) const { - switch (params_.lossType) { - case GncParameters::TLS: - return std::fabs(cost - prev_cost) < params_.relativeCostTol; - default: - throw std::runtime_error( - "GncOptimizer::checkMuConvergence: called with unknown loss type."); - } + bool costConverged = std::fabs(cost - prev_cost) / std::max(prev_cost,1e-7) < params_.relativeCostTol; + if (costConverged && params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) + std::cout << "checkCostConvergence = true " << std::endl; + return costConverged; } + /// check convergence of weights to binary values + bool checkWeightsConvergence(const Vector& weights) const { + bool weightsConverged = false; + switch (params_.lossType) { + case GncParameters::GM: + weightsConverged = false; // for GM, there is no clear binary convergence for the weights + break; + case GncParameters::TLS: + weightsConverged = true; + for(size_t i=0; i params_.weightsTol ){ + weightsConverged = false; + break; + } + } + break; + default: + throw std::runtime_error( + "GncOptimizer::checkWeightsConvergence: called with unknown loss type."); + } + if (weightsConverged && params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) + std::cout << "weightsConverged = true " << std::endl; + return weightsConverged; + } + /// check for convergence between consecutive GNC iterations bool checkConvergence(const double mu, + const Vector& weights, const double cost, const double prev_cost) const { - switch (params_.lossType) { - case GncParameters::GM: - return checkMuConvergence(mu); - case GncParameters::TLS: - return checkCostConvergence(cost, prev_cost); - default: - throw std::runtime_error( - "GncOptimizer::checkMuConvergence: called with unknown loss type."); - } + return checkCostConvergence(cost,prev_cost) || + checkWeightsConvergence(weights) || + checkMuConvergence(mu); } - /// create a graph where each factor is weighted by the gnc weights NonlinearFactorGraph makeWeightedGraph(const Vector& weights) const { // make sure all noiseModels are Gaussian or convert to Gaussian diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index dc96762b8..9036fc97f 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -66,7 +66,7 @@ TEST(GncOptimizer, gncParamsConstructor) { // change something at the gncParams level GncParams gncParams2c(gncParams2b); - gncParams2c.setLossType(GncParams::RobustLossType::TLS); + gncParams2c.setLossType(GncParams::RobustLossType::GM); CHECK(!gncParams2c.equals(gncParams2b.baseOptimizerParams)); } @@ -186,7 +186,7 @@ TEST(GncOptimizer, updateMuTLS) { } /* ************************************************************************* */ -TEST(GncOptimizer, checkMuConvergenceGM) { +TEST(GncOptimizer, checkMuConvergence) { // has to have Gaussian noise models ! auto fg = example::createReallyNonlinearFactorGraph(); @@ -194,6 +194,7 @@ TEST(GncOptimizer, checkMuConvergenceGM) { Values initial; initial.insert(X(1), p0); + { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); gncParams.setLossType( @@ -203,6 +204,112 @@ TEST(GncOptimizer, checkMuConvergenceGM) { double mu = 1.0; CHECK(gnc.checkMuConvergence(mu)); + } + { + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + auto gnc = + GncOptimizer>(fg, initial, gncParams); + + double mu = 1.0; + CHECK(!gnc.checkMuConvergence(mu)); //always false for TLS + } +} + +/* ************************************************************************* */ +TEST(GncOptimizer, checkCostConvergence) { + // has to have Gaussian noise models ! + auto fg = example::createReallyNonlinearFactorGraph(); + + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + { + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setRelativeCostTol(0.49); + auto gnc = + GncOptimizer>(fg, initial, gncParams); + + double prev_cost = 1.0; + double cost = 0.5; + // relative cost reduction = 0.5 > 0.49, hence checkCostConvergence = false + CHECK(!gnc.checkCostConvergence(cost, prev_cost)); + } + { + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setRelativeCostTol(0.51); + auto gnc = + GncOptimizer>(fg, initial, gncParams); + + double prev_cost = 1.0; + double cost = 0.5; + // relative cost reduction = 0.5 < 0.51, hence checkCostConvergence = true + CHECK(gnc.checkCostConvergence(cost, prev_cost)); + } +} + +/* ************************************************************************* */ +TEST(GncOptimizer, checkWeightsConvergence) { + // has to have Gaussian noise models ! + auto fg = example::createReallyNonlinearFactorGraph(); + + Point2 p0(3, 3); + Values initial; + initial.insert(X(1), p0); + + { + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setLossType( + GncParams::RobustLossType::GM); + auto gnc = + GncOptimizer>(fg, initial, gncParams); + + Vector weights = Vector::Ones(fg.size()); + CHECK(!gnc.checkWeightsConvergence(weights)); //always false for GM + } + { + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + auto gnc = + GncOptimizer>(fg, initial, gncParams); + + Vector weights = Vector::Ones(fg.size()); + // weights are binary, so checkWeightsConvergence = true + CHECK(gnc.checkWeightsConvergence(weights)); + } + { + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + auto gnc = + GncOptimizer>(fg, initial, gncParams); + + Vector weights = Vector::Ones(fg.size()); + weights[0] = 0.9; // more than weightsTol = 1e-4 from 1, hence checkWeightsConvergence = false + CHECK(!gnc.checkWeightsConvergence(weights)); + } + { + LevenbergMarquardtParams lmParams; + GncParams gncParams(lmParams); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + gncParams.setWeightsTol(0.1); + auto gnc = + GncOptimizer>(fg, initial, gncParams); + + Vector weights = Vector::Ones(fg.size()); + weights[0] = 0.9; // exactly weightsTol = 0.1 from 1, hence checkWeightsConvergence = true + CHECK(gnc.checkWeightsConvergence(weights)); + } } /* ************************************************************************* */ @@ -455,9 +562,12 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { knownInliers.push_back(2); // nonconvexity with known inliers + { GncParams gncParams; gncParams.setKnownInliers(knownInliers); - // gncParams.setVerbosityGNC(GncParams::VerbosityGNC::VALUES); + gncParams.setLossType( + GncParams::RobustLossType::GM); + //gncParams.setVerbosityGNC(GncParams::VerbosityGNC::SUMMARY); auto gnc = GncOptimizer>(fg, initial, gncParams); Values gnc_result = gnc.optimize(); @@ -468,6 +578,45 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { DOUBLES_EQUAL(1.0, finalWeights[0], tol); DOUBLES_EQUAL(1.0, finalWeights[1], tol); DOUBLES_EQUAL(1.0, finalWeights[2], tol); + } + { + GncParams gncParams; + gncParams.setKnownInliers(knownInliers); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + // gncParams.setVerbosityGNC(GncParams::VerbosityGNC::SUMMARY); + auto gnc = GncOptimizer>(fg, initial, gncParams); + + Values gnc_result = gnc.optimize(); + CHECK(assert_equal(Point2(0.0, 0.0), gnc_result.at(X(1)), 1e-3)); + + // check weights were actually fixed: + Vector finalWeights = gnc.getWeights(); + DOUBLES_EQUAL(1.0, finalWeights[0], tol); + DOUBLES_EQUAL(1.0, finalWeights[1], tol); + DOUBLES_EQUAL(1.0, finalWeights[2], tol); + DOUBLES_EQUAL(0.0, finalWeights[3], tol); + } + { + // if we set the threshold large, they are all inliers + GncParams gncParams; + gncParams.setKnownInliers(knownInliers); + gncParams.setLossType( + GncParams::RobustLossType::TLS); + //gncParams.setVerbosityGNC(GncParams::VerbosityGNC::VALUES); + gncParams.setInlierCostThreshold( 100.0 ); + auto gnc = GncOptimizer>(fg, initial, gncParams); + + Values gnc_result = gnc.optimize(); + CHECK(assert_equal(Point2(0.25, 0.0), gnc_result.at(X(1)), 1e-3)); + + // check weights were actually fixed: + Vector finalWeights = gnc.getWeights(); + DOUBLES_EQUAL(1.0, finalWeights[0], tol); + DOUBLES_EQUAL(1.0, finalWeights[1], tol); + DOUBLES_EQUAL(1.0, finalWeights[2], tol); + DOUBLES_EQUAL(1.0, finalWeights[3], tol); + } } /* ************************************************************************* */ From 92ed225a557cfec8b58f1038ed8c6cb5b066adf7 Mon Sep 17 00:00:00 2001 From: jingnanshi Date: Thu, 24 Dec 2020 11:19:47 -0500 Subject: [PATCH 185/261] minor fixes --- gtsam/nonlinear/GncOptimizer.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index b66e0f523..6637e33d4 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -66,7 +66,7 @@ public: size_t maxIterations = 100; /* maximum number of iterations*/ double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ - double relativeCostTol = 1e-5; ///< if relative cost change if below this threshold, stop iterating + double relativeCostTol = 1e-5; ///< if relative cost change is below this threshold, stop iterating double weightsTol = 1e-4; ///< if the weights are within weightsTol from being binary, stop iterating (only for TLS) VerbosityGNC verbosityGNC = SILENT; /* verbosity level */ std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ @@ -111,7 +111,7 @@ public: * This functionality is commonly used in SLAM when one may assume the odometry is outlier free, and * only apply GNC to prune outliers from the loop closures * */ - void setKnownInliers(const std::vector knownIn) { + void setKnownInliers(const std::vector& knownIn) { for (size_t i = 0; i < knownIn.size(); i++) knownInliers.push_back(knownIn[i]); } @@ -338,7 +338,7 @@ public: /// check convergence of relative cost differences bool checkCostConvergence(const double cost, const double prev_cost) const { - bool costConverged = std::fabs(cost - prev_cost) / std::max(prev_cost,1e-7) < params_.relativeCostTol; + bool costConverged = std::fabs(cost - prev_cost) / std::max(prev_cost,1e-7) < params_.relativeCostTol; if (costConverged && params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) std::cout << "checkCostConvergence = true " << std::endl; return costConverged; @@ -406,7 +406,7 @@ public: } /// calculate gnc weights - Vector calculateWeights(const Values currentEstimate, const double mu) { + Vector calculateWeights(const Values& currentEstimate, const double mu) { Vector weights = Vector::Ones(nfg_.size()); // do not update the weights that the user has decided are known inliers From f91f7facb4e6c0089eeee642b0cf8b4e5217f9b4 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sat, 26 Dec 2020 17:14:09 -0500 Subject: [PATCH 186/261] wrap Symbol class and methods --- gtsam/gtsam.i | 15 +++++++++++++++ gtsam/inference/Symbol.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 3a6c6edf1..3ebe71538 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -1936,6 +1936,21 @@ class KalmanFilter { //************************************************************************* #include + +class Symbol { + Symbol(); + Symbol(char c, uint64_t j); + Symbol(size_t key); + + size_t key() const; + void print(const string& s) const; + bool equals(const gtsam::Symbol& expected, double tol) const; + + char chr() const; + uint64_t index() const; + string string() const; +}; + size_t symbol(char chr, size_t index); char symbolChr(size_t key); size_t symbolIndex(size_t key); diff --git a/gtsam/inference/Symbol.h b/gtsam/inference/Symbol.h index 42cdbb1c3..d5699e7fe 100644 --- a/gtsam/inference/Symbol.h +++ b/gtsam/inference/Symbol.h @@ -80,6 +80,9 @@ public: /** Create a string from the key */ operator std::string() const; + /// Return string representation of the key + std::string string() const { return std::string(*this); }; + /** Comparison for use in maps */ bool operator<(const Symbol& comp) const { return c_ < comp.c_ || (comp.c_ == c_ && j_ < comp.j_); From 085d01580e5c04b1f005fc70c5c58ffb87027ba3 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sun, 27 Dec 2020 19:13:41 -0500 Subject: [PATCH 187/261] minor formatting of cmake file --- cmake/GtsamTesting.cmake | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/cmake/GtsamTesting.cmake b/cmake/GtsamTesting.cmake index 3b42ffa21..573fb696a 100644 --- a/cmake/GtsamTesting.cmake +++ b/cmake/GtsamTesting.cmake @@ -88,36 +88,36 @@ enable_testing() option(GTSAM_BUILD_TESTS "Enable/Disable building of tests" ON) option(GTSAM_BUILD_EXAMPLES_ALWAYS "Build examples with 'make all' (build with 'make examples' if not)" ON) - option(GTSAM_BUILD_TIMING_ALWAYS "Build timing scripts with 'make all' (build with 'make timing' if not" OFF) +option(GTSAM_BUILD_TIMING_ALWAYS "Build timing scripts with 'make all' (build with 'make timing' if not" OFF) - # Add option for combining unit tests - if(MSVC OR XCODE_VERSION) - option(GTSAM_SINGLE_TEST_EXE "Combine unit tests into single executable (faster compile)" ON) - else() - option(GTSAM_SINGLE_TEST_EXE "Combine unit tests into single executable (faster compile)" OFF) - endif() - mark_as_advanced(GTSAM_SINGLE_TEST_EXE) +# Add option for combining unit tests +if(MSVC OR XCODE_VERSION) + option(GTSAM_SINGLE_TEST_EXE "Combine unit tests into single executable (faster compile)" ON) +else() + option(GTSAM_SINGLE_TEST_EXE "Combine unit tests into single executable (faster compile)" OFF) +endif() +mark_as_advanced(GTSAM_SINGLE_TEST_EXE) - # Enable make check (http://www.cmake.org/Wiki/CMakeEmulateMakeCheck) - if(GTSAM_BUILD_TESTS) - add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -C $ --output-on-failure) - # Also add alternative checks using valgrind. - # We don't look for valgrind being installed in the system, since these - # targets are not invoked unless directly instructed by the user. - if (UNIX) - # Run all tests using valgrind: - add_custom_target(check_valgrind) - endif() +# Enable make check (http://www.cmake.org/Wiki/CMakeEmulateMakeCheck) +if(GTSAM_BUILD_TESTS) + add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -C $ --output-on-failure) + # Also add alternative checks using valgrind. + # We don't look for valgrind being installed in the system, since these + # targets are not invoked unless directly instructed by the user. + if (UNIX) + # Run all tests using valgrind: + add_custom_target(check_valgrind) + endif() - # Add target to build tests without running - add_custom_target(all.tests) - endif() + # Add target to build tests without running + add_custom_target(all.tests) +endif() - # Add examples target - add_custom_target(examples) +# Add examples target +add_custom_target(examples) - # Add timing target - add_custom_target(timing) +# Add timing target +add_custom_target(timing) # Implementations of this file's macros: From d6ef5454990827a525a79515b6f13a1df1852443 Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Mon, 28 Dec 2020 22:05:12 +0530 Subject: [PATCH 188/261] Wrapping Cal3Bundler's prior and GeneralSFMFactor2 --- gtsam/gtsam.i | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 3a6c6edf1..c37a83b8a 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -2505,7 +2505,7 @@ class NonlinearISAM { #include #include -template}> +template}> virtual class PriorFactor : gtsam::NoiseModelFactor { PriorFactor(size_t key, const T& prior, const gtsam::noiseModel::Base* noiseModel); T prior() const; @@ -2651,7 +2651,7 @@ typedef gtsam::GeneralSFMFactor Gene typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; typedef gtsam::GeneralSFMFactor, gtsam::Point3> GeneralSFMFactorCal3Bundler; -template +template virtual class GeneralSFMFactor2 : gtsam::NoiseModelFactor { GeneralSFMFactor2(const gtsam::Point2& measured, const gtsam::noiseModel::Base* model, size_t poseKey, size_t landmarkKey, size_t calibKey); gtsam::Point2 measured() const; @@ -2659,6 +2659,9 @@ virtual class GeneralSFMFactor2 : gtsam::NoiseModelFactor { // enabling serialization functionality void serialize() const; }; +typedef gtsam::GeneralSFMFactor2 GeneralSFMFactor2Cal3_S2; +typedef gtsam::GeneralSFMFactor2 GeneralSFMFactor2Cal3DS2; +typedef gtsam::GeneralSFMFactor2 GeneralSFMFactor2Cal3Bundler; #include class SmartProjectionParams { From 06dfeb7ac5f5323f525263855803964d330f6d80 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Mon, 28 Dec 2020 20:43:35 -0500 Subject: [PATCH 189/261] moved GncParams to separate file, addressing comments by Frank, 1/n --- gtsam/nonlinear/GaussNewtonOptimizer.h | 2 +- gtsam/nonlinear/GncOptimizer.h | 136 ++----------------- gtsam/nonlinear/GncParams.h | 151 +++++++++++++++++++++ gtsam/nonlinear/LevenbergMarquardtParams.h | 2 +- tests/testGncOptimizer.cpp | 50 +++---- 5 files changed, 180 insertions(+), 161 deletions(-) create mode 100644 gtsam/nonlinear/GncParams.h diff --git a/gtsam/nonlinear/GaussNewtonOptimizer.h b/gtsam/nonlinear/GaussNewtonOptimizer.h index 3ef4dfdeb..a3923524b 100644 --- a/gtsam/nonlinear/GaussNewtonOptimizer.h +++ b/gtsam/nonlinear/GaussNewtonOptimizer.h @@ -29,7 +29,7 @@ class GaussNewtonOptimizer; */ class GTSAM_EXPORT GaussNewtonParams : public NonlinearOptimizerParams { public: - typedef GaussNewtonOptimizer OptimizerType; + using OptimizerType = GaussNewtonOptimizer; }; /** diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index 6637e33d4..f28394545 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -26,129 +26,11 @@ #pragma once -#include -#include +#include #include namespace gtsam { -/* ************************************************************************* */ -template -class GncParams { -public: - /** For each parameter, specify the corresponding optimizer: e.g., GaussNewtonParams -> GaussNewtonOptimizer */ - typedef typename BaseOptimizerParameters::OptimizerType OptimizerType; - - /** Verbosity levels */ - enum VerbosityGNC { - SILENT = 0, SUMMARY, VALUES - }; - - /** Choice of robust loss function for GNC */ - enum RobustLossType { - GM /*Geman McClure*/, TLS /*Truncated least squares*/ - }; - - /// Constructor - GncParams(const BaseOptimizerParameters& baseOptimizerParams) : - baseOptimizerParams(baseOptimizerParams) { - } - - /// Default constructor - GncParams() : - baseOptimizerParams() { - } - - /// GNC parameters - BaseOptimizerParameters baseOptimizerParams; /*optimization parameters used to solve the weighted least squares problem at each GNC iteration*/ - /// any other specific GNC parameters: - RobustLossType lossType = TLS; /* default loss*/ - size_t maxIterations = 100; /* maximum number of iterations*/ - double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ - double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ - double relativeCostTol = 1e-5; ///< if relative cost change is below this threshold, stop iterating - double weightsTol = 1e-4; ///< if the weights are within weightsTol from being binary, stop iterating (only for TLS) - VerbosityGNC verbosityGNC = SILENT; /* verbosity level */ - std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ - - /// Set the robust loss function to be used in GNC (chosen among the ones in RobustLossType) - void setLossType(const RobustLossType type) { - lossType = type; - } - /// Set the maximum number of iterations in GNC (changing the max nr of iters might lead to less accurate solutions and is not recommended) - void setMaxIterations(const size_t maxIter) { - std::cout - << "setMaxIterations: changing the max nr of iters might lead to less accurate solutions and is not recommended! " - << std::endl; - maxIterations = maxIter; - } - /** Set the maximum weighted residual error for an inlier. For a factor in the form f(x) = 0.5 * || r(x) ||^2_Omega, - * the inlier threshold is the largest value of f(x) for the corresponding measurement to be considered an inlier. - * In other words, an inlier at x is such that 0.5 * || r(x) ||^2_Omega <= barcSq. - * Assuming a isotropic measurement covariance sigma^2 * Identity, the cost becomes: 0.5 * 1/sigma^2 || r(x) ||^2 <= barcSq. - * Hence || r(x) ||^2 <= 2 * barcSq * sigma^2 - * */ - void setInlierCostThreshold(const double inth) { - barcSq = inth; - } - /// Set the graduated non-convexity step: at each GNC iteration, mu is updated as mu <- mu * muStep - void setMuStep(const double step) { - muStep = step; - } - /// Set the maximum relative difference in mu values to stop iterating - void setRelativeCostTol(double value) { relativeCostTol = value; - } - /// Set the maximum difference between the weights and their rounding in {0,1} to stop iterating - void setWeightsTol(double value) { weightsTol = value; - } - /// Set the verbosity level - void setVerbosityGNC(const VerbosityGNC verbosity) { - verbosityGNC = verbosity; - } - /** (Optional) Provide a vector of measurements that must be considered inliers. The enties in the vector - * corresponds to the slots in the factor graph. For instance, if you have a nonlinear factor graph nfg, - * and you provide knownIn = {0, 2, 15}, GNC will not apply outlier rejection to nfg[0], nfg[2], and nfg[15]. - * This functionality is commonly used in SLAM when one may assume the odometry is outlier free, and - * only apply GNC to prune outliers from the loop closures - * */ - void setKnownInliers(const std::vector& knownIn) { - for (size_t i = 0; i < knownIn.size(); i++) - knownInliers.push_back(knownIn[i]); - } - /// equals - bool equals(const GncParams& other, double tol = 1e-9) const { - return baseOptimizerParams.equals(other.baseOptimizerParams) - && lossType == other.lossType && maxIterations == other.maxIterations - && std::fabs(barcSq - other.barcSq) <= tol - && std::fabs(muStep - other.muStep) <= tol - && verbosityGNC == other.verbosityGNC - && knownInliers == other.knownInliers; - } - /// print function - void print(const std::string& str) const { - std::cout << str << "\n"; - switch (lossType) { - case GM: - std::cout << "lossType: Geman McClure" << "\n"; - break; - case TLS: - std::cout << "lossType: Truncated Least-squares" << "\n"; - break; - default: - throw std::runtime_error("GncParams::print: unknown loss type."); - } - std::cout << "maxIterations: " << maxIterations << "\n"; - std::cout << "barcSq: " << barcSq << "\n"; - std::cout << "muStep: " << muStep << "\n"; - std::cout << "relativeCostTol: " << relativeCostTol << "\n"; - std::cout << "weightsTol: " << weightsTol << "\n"; - std::cout << "verbosityGNC: " << verbosityGNC << "\n"; - for (size_t i = 0; i < knownInliers.size(); i++) - std::cout << "knownInliers: " << knownInliers[i] << "\n"; - baseOptimizerParams.print(str); - } -}; - /* ************************************************************************* */ template class GncOptimizer { @@ -219,11 +101,11 @@ public: // For GM: if residual error is small, mu -> 0 // For TLS: if residual error is small, mu -> -1 if (mu <= 0) { - if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { + if (params_.verbosity >= GncParameters::Verbosity::SUMMARY) { std::cout << "GNC Optimizer stopped because maximum residual at " "initialization is small." << std::endl; } - if (params_.verbosityGNC >= GncParameters::VerbosityGNC::VALUES) { + if (params_.verbosity >= GncParameters::Verbosity::VALUES) { result.print("result\n"); std::cout << "mu: " << mu << std::endl; } @@ -234,7 +116,7 @@ public: for (iter = 0; iter < params_.maxIterations; iter++) { // display info - if (params_.verbosityGNC >= GncParameters::VerbosityGNC::VALUES) { + if (params_.verbosity >= GncParameters::Verbosity::VALUES) { std::cout << "iter: " << iter << std::endl; result.print("result\n"); std::cout << "mu: " << mu << std::endl; @@ -259,13 +141,13 @@ public: prev_cost = cost; // display info - if (params_.verbosityGNC >= GncParameters::VerbosityGNC::VALUES) { + if (params_.verbosity >= GncParameters::Verbosity::VALUES) { std::cout << "previous cost: " << prev_cost << std::endl; std::cout << "current cost: " << cost << std::endl; } } // display info - if (params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) { + if (params_.verbosity >= GncParameters::Verbosity::SUMMARY) { std::cout << "final iterations: " << iter << std::endl; std::cout << "final mu: " << mu << std::endl; std::cout << "final weights: " << weights_ << std::endl; @@ -331,7 +213,7 @@ public: throw std::runtime_error( "GncOptimizer::checkMuConvergence: called with unknown loss type."); } - if (muConverged && params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) + if (muConverged && params_.verbosity >= GncParameters::Verbosity::SUMMARY) std::cout << "muConverged = true " << std::endl; return muConverged; } @@ -339,7 +221,7 @@ public: /// check convergence of relative cost differences bool checkCostConvergence(const double cost, const double prev_cost) const { bool costConverged = std::fabs(cost - prev_cost) / std::max(prev_cost,1e-7) < params_.relativeCostTol; - if (costConverged && params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) + if (costConverged && params_.verbosity >= GncParameters::Verbosity::SUMMARY) std::cout << "checkCostConvergence = true " << std::endl; return costConverged; } @@ -364,7 +246,7 @@ public: throw std::runtime_error( "GncOptimizer::checkWeightsConvergence: called with unknown loss type."); } - if (weightsConverged && params_.verbosityGNC >= GncParameters::VerbosityGNC::SUMMARY) + if (weightsConverged && params_.verbosity >= GncParameters::Verbosity::SUMMARY) std::cout << "weightsConverged = true " << std::endl; return weightsConverged; } diff --git a/gtsam/nonlinear/GncParams.h b/gtsam/nonlinear/GncParams.h new file mode 100644 index 000000000..98fb19f5f --- /dev/null +++ b/gtsam/nonlinear/GncParams.h @@ -0,0 +1,151 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file GncOptimizer.h + * @brief The GncOptimizer class + * @author Jingnan Shi + * @author Luca Carlone + * @author Frank Dellaert + * + * Implementation of the paper: Yang, Antonante, Tzoumas, Carlone, "Graduated Non-Convexity for Robust Spatial Perception: + * From Non-Minimal Solvers to Global Outlier Rejection", ICRA/RAL, 2020. (arxiv version: https://arxiv.org/pdf/1909.08605.pdf) + * + * See also: + * Antonante, Tzoumas, Yang, Carlone, "Outlier-Robust Estimation: Hardness, Minimally-Tuned Algorithms, and Applications", + * arxiv: https://arxiv.org/pdf/2007.15109.pdf, 2020. + */ + +#pragma once + +#include +#include + +namespace gtsam { + +/* ************************************************************************* */ +template +class GncParams { +public: + /** For each parameter, specify the corresponding optimizer: e.g., GaussNewtonParams -> GaussNewtonOptimizer */ + typedef typename BaseOptimizerParameters::OptimizerType OptimizerType; + + /** Verbosity levels */ + enum Verbosity { + SILENT = 0, SUMMARY, VALUES + }; + + /** Choice of robust loss function for GNC */ + enum RobustLossType { + GM /*Geman McClure*/, TLS /*Truncated least squares*/ + }; + + /// Constructor + GncParams(const BaseOptimizerParameters& baseOptimizerParams) : + baseOptimizerParams(baseOptimizerParams) { + } + + /// Default constructor + GncParams() : + baseOptimizerParams() { + } + + /// GNC parameters + BaseOptimizerParameters baseOptimizerParams; /*optimization parameters used to solve the weighted least squares problem at each GNC iteration*/ + /// any other specific GNC parameters: + RobustLossType lossType = TLS; /* default loss*/ + size_t maxIterations = 100; /* maximum number of iterations*/ + double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ + double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ + double relativeCostTol = 1e-5; ///< if relative cost change is below this threshold, stop iterating + double weightsTol = 1e-4; ///< if the weights are within weightsTol from being binary, stop iterating (only for TLS) + Verbosity verbosity = SILENT; /* verbosity level */ + std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ + + /// Set the robust loss function to be used in GNC (chosen among the ones in RobustLossType) + void setLossType(const RobustLossType type) { + lossType = type; + } + /// Set the maximum number of iterations in GNC (changing the max nr of iters might lead to less accurate solutions and is not recommended) + void setMaxIterations(const size_t maxIter) { + std::cout + << "setMaxIterations: changing the max nr of iters might lead to less accurate solutions and is not recommended! " + << std::endl; + maxIterations = maxIter; + } + /** Set the maximum weighted residual error for an inlier. For a factor in the form f(x) = 0.5 * || r(x) ||^2_Omega, + * the inlier threshold is the largest value of f(x) for the corresponding measurement to be considered an inlier. + * In other words, an inlier at x is such that 0.5 * || r(x) ||^2_Omega <= barcSq. + * Assuming a isotropic measurement covariance sigma^2 * Identity, the cost becomes: 0.5 * 1/sigma^2 || r(x) ||^2 <= barcSq. + * Hence || r(x) ||^2 <= 2 * barcSq * sigma^2 + * */ + void setInlierCostThreshold(const double inth) { + barcSq = inth; + } + /// Set the graduated non-convexity step: at each GNC iteration, mu is updated as mu <- mu * muStep + void setMuStep(const double step) { + muStep = step; + } + /// Set the maximum relative difference in mu values to stop iterating + void setRelativeCostTol(double value) { relativeCostTol = value; + } + /// Set the maximum difference between the weights and their rounding in {0,1} to stop iterating + void setWeightsTol(double value) { weightsTol = value; + } + /// Set the verbosity level + void setVerbosityGNC(const Verbosity verbosity) { + verbosity = verbosity; + } + /** (Optional) Provide a vector of measurements that must be considered inliers. The enties in the vector + * corresponds to the slots in the factor graph. For instance, if you have a nonlinear factor graph nfg, + * and you provide knownIn = {0, 2, 15}, GNC will not apply outlier rejection to nfg[0], nfg[2], and nfg[15]. + * This functionality is commonly used in SLAM when one may assume the odometry is outlier free, and + * only apply GNC to prune outliers from the loop closures + * */ + void setKnownInliers(const std::vector& knownIn) { + for (size_t i = 0; i < knownIn.size(); i++) + knownInliers.push_back(knownIn[i]); + } + /// equals + bool equals(const GncParams& other, double tol = 1e-9) const { + return baseOptimizerParams.equals(other.baseOptimizerParams) + && lossType == other.lossType && maxIterations == other.maxIterations + && std::fabs(barcSq - other.barcSq) <= tol + && std::fabs(muStep - other.muStep) <= tol + && verbosity == other.verbosity + && knownInliers == other.knownInliers; + } + /// print function + void print(const std::string& str) const { + std::cout << str << "\n"; + switch (lossType) { + case GM: + std::cout << "lossType: Geman McClure" << "\n"; + break; + case TLS: + std::cout << "lossType: Truncated Least-squares" << "\n"; + break; + default: + throw std::runtime_error("GncParams::print: unknown loss type."); + } + std::cout << "maxIterations: " << maxIterations << "\n"; + std::cout << "barcSq: " << barcSq << "\n"; + std::cout << "muStep: " << muStep << "\n"; + std::cout << "relativeCostTol: " << relativeCostTol << "\n"; + std::cout << "weightsTol: " << weightsTol << "\n"; + std::cout << "verbosity: " << verbosity << "\n"; + for (size_t i = 0; i < knownInliers.size(); i++) + std::cout << "knownInliers: " << knownInliers[i] << "\n"; + baseOptimizerParams.print(str); + } +}; + +} diff --git a/gtsam/nonlinear/LevenbergMarquardtParams.h b/gtsam/nonlinear/LevenbergMarquardtParams.h index 20a8eb4c1..30e783fc9 100644 --- a/gtsam/nonlinear/LevenbergMarquardtParams.h +++ b/gtsam/nonlinear/LevenbergMarquardtParams.h @@ -42,7 +42,7 @@ public: static VerbosityLM verbosityLMTranslator(const std::string &s); static std::string verbosityLMTranslator(VerbosityLM value); - typedef LevenbergMarquardtOptimizer OptimizerType; + using OptimizerType = LevenbergMarquardtOptimizer; public: diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 9036fc97f..f8e12fcd3 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -80,8 +80,7 @@ TEST(GncOptimizer, gncConstructor) { Values initial; initial.insert(X(1), p0); - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -100,8 +99,7 @@ TEST(GncOptimizer, gncConstructorWithRobustGraphAsInput) { Values initial; initial.insert(X(1), p0); - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; auto gnc = GncOptimizer>( fg_robust, initial, gncParams); @@ -119,8 +117,7 @@ TEST(GncOptimizer, initializeMu) { initial.insert(X(1), p0); // testing GM mu initialization - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setLossType( GncParams::RobustLossType::GM); auto gnc_gm = @@ -148,8 +145,7 @@ TEST(GncOptimizer, updateMuGM) { Values initial; initial.insert(X(1), p0); - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setLossType( GncParams::RobustLossType::GM); gncParams.setMuStep(1.4); @@ -173,8 +169,7 @@ TEST(GncOptimizer, updateMuTLS) { Values initial; initial.insert(X(1), p0); - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setMuStep(1.4); gncParams.setLossType( GncParams::RobustLossType::TLS); @@ -195,8 +190,7 @@ TEST(GncOptimizer, checkMuConvergence) { initial.insert(X(1), p0); { - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setLossType( GncParams::RobustLossType::GM); auto gnc = @@ -206,8 +200,7 @@ TEST(GncOptimizer, checkMuConvergence) { CHECK(gnc.checkMuConvergence(mu)); } { - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setLossType( GncParams::RobustLossType::TLS); auto gnc = @@ -228,8 +221,7 @@ TEST(GncOptimizer, checkCostConvergence) { initial.insert(X(1), p0); { - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setRelativeCostTol(0.49); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -240,8 +232,7 @@ TEST(GncOptimizer, checkCostConvergence) { CHECK(!gnc.checkCostConvergence(cost, prev_cost)); } { - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setRelativeCostTol(0.51); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -263,8 +254,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { initial.insert(X(1), p0); { - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setLossType( GncParams::RobustLossType::GM); auto gnc = @@ -274,8 +264,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { CHECK(!gnc.checkWeightsConvergence(weights)); //always false for GM } { - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setLossType( GncParams::RobustLossType::TLS); auto gnc = @@ -286,8 +275,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { CHECK(gnc.checkWeightsConvergence(weights)); } { - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setLossType( GncParams::RobustLossType::TLS); auto gnc = @@ -298,8 +286,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { CHECK(!gnc.checkWeightsConvergence(weights)); } { - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setLossType( GncParams::RobustLossType::TLS); gncParams.setWeightsTol(0.1); @@ -321,8 +308,7 @@ TEST(GncOptimizer, checkConvergenceTLS) { Values initial; initial.insert(X(1), p0); - LevenbergMarquardtParams lmParams; - GncParams gncParams(lmParams); + GncParams gncParams; gncParams.setRelativeCostTol(1e-5); gncParams.setLossType( GncParams::RobustLossType::TLS); @@ -542,7 +528,7 @@ TEST(GncOptimizer, optimize) { // .. but graduated nonconvexity ensures both robustness and convergence in // the face of nonconvexity GncParams gncParams(gnParams); - // gncParams.setVerbosityGNC(GncParams::VerbosityGNC::SUMMARY); + // gncParams.setVerbosityGNC(GncParams::Verbosity::SUMMARY); auto gnc = GncOptimizer>(fg, initial, gncParams); Values gnc_result = gnc.optimize(); CHECK(assert_equal(Point2(0.0, 0.0), gnc_result.at(X(1)), 1e-3)); @@ -567,7 +553,7 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { gncParams.setKnownInliers(knownInliers); gncParams.setLossType( GncParams::RobustLossType::GM); - //gncParams.setVerbosityGNC(GncParams::VerbosityGNC::SUMMARY); + //gncParams.setVerbosityGNC(GncParams::Verbosity::SUMMARY); auto gnc = GncOptimizer>(fg, initial, gncParams); Values gnc_result = gnc.optimize(); @@ -584,7 +570,7 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { gncParams.setKnownInliers(knownInliers); gncParams.setLossType( GncParams::RobustLossType::TLS); - // gncParams.setVerbosityGNC(GncParams::VerbosityGNC::SUMMARY); + // gncParams.setVerbosityGNC(GncParams::Verbosity::SUMMARY); auto gnc = GncOptimizer>(fg, initial, gncParams); Values gnc_result = gnc.optimize(); @@ -603,7 +589,7 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { gncParams.setKnownInliers(knownInliers); gncParams.setLossType( GncParams::RobustLossType::TLS); - //gncParams.setVerbosityGNC(GncParams::VerbosityGNC::VALUES); + //gncParams.setVerbosityGNC(GncParams::Verbosity::VALUES); gncParams.setInlierCostThreshold( 100.0 ); auto gnc = GncOptimizer>(fg, initial, gncParams); From eea52766d1220d69a276916f767527005945d3fe Mon Sep 17 00:00:00 2001 From: lcarlone Date: Mon, 28 Dec 2020 20:49:17 -0500 Subject: [PATCH 190/261] renamed enum --- gtsam/nonlinear/GncParams.h | 12 +++++------ tests/testGncOptimizer.cpp | 40 ++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/gtsam/nonlinear/GncParams.h b/gtsam/nonlinear/GncParams.h index 98fb19f5f..30ceef4c7 100644 --- a/gtsam/nonlinear/GncParams.h +++ b/gtsam/nonlinear/GncParams.h @@ -44,7 +44,7 @@ public: }; /** Choice of robust loss function for GNC */ - enum RobustLossType { + enum GncLossType { GM /*Geman McClure*/, TLS /*Truncated least squares*/ }; @@ -61,7 +61,7 @@ public: /// GNC parameters BaseOptimizerParameters baseOptimizerParams; /*optimization parameters used to solve the weighted least squares problem at each GNC iteration*/ /// any other specific GNC parameters: - RobustLossType lossType = TLS; /* default loss*/ + GncLossType lossType = TLS; /* default loss*/ size_t maxIterations = 100; /* maximum number of iterations*/ double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ @@ -70,8 +70,8 @@ public: Verbosity verbosity = SILENT; /* verbosity level */ std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ - /// Set the robust loss function to be used in GNC (chosen among the ones in RobustLossType) - void setLossType(const RobustLossType type) { + /// Set the robust loss function to be used in GNC (chosen among the ones in GncLossType) + void setLossType(const GncLossType type) { lossType = type; } /// Set the maximum number of iterations in GNC (changing the max nr of iters might lead to less accurate solutions and is not recommended) @@ -101,8 +101,8 @@ public: void setWeightsTol(double value) { weightsTol = value; } /// Set the verbosity level - void setVerbosityGNC(const Verbosity verbosity) { - verbosity = verbosity; + void setVerbosityGNC(const Verbosity value) { + verbosity = value; } /** (Optional) Provide a vector of measurements that must be considered inliers. The enties in the vector * corresponds to the slots in the factor graph. For instance, if you have a nonlinear factor graph nfg, diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index f8e12fcd3..15a83eb4b 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -66,7 +66,7 @@ TEST(GncOptimizer, gncParamsConstructor) { // change something at the gncParams level GncParams gncParams2c(gncParams2b); - gncParams2c.setLossType(GncParams::RobustLossType::GM); + gncParams2c.setLossType(GncParams::GncLossType::GM); CHECK(!gncParams2c.equals(gncParams2b.baseOptimizerParams)); } @@ -119,7 +119,7 @@ TEST(GncOptimizer, initializeMu) { // testing GM mu initialization GncParams gncParams; gncParams.setLossType( - GncParams::RobustLossType::GM); + GncParams::GncLossType::GM); auto gnc_gm = GncOptimizer>(fg, initial, gncParams); // according to rmk 5 in the gnc paper: m0 = 2 rmax^2 / barcSq @@ -128,7 +128,7 @@ TEST(GncOptimizer, initializeMu) { // testing TLS mu initialization gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); auto gnc_tls = GncOptimizer>(fg, initial, gncParams); // according to rmk 5 in the gnc paper: m0 = barcSq / (2 * rmax^2 - barcSq) @@ -147,7 +147,7 @@ TEST(GncOptimizer, updateMuGM) { GncParams gncParams; gncParams.setLossType( - GncParams::RobustLossType::GM); + GncParams::GncLossType::GM); gncParams.setMuStep(1.4); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -172,7 +172,7 @@ TEST(GncOptimizer, updateMuTLS) { GncParams gncParams; gncParams.setMuStep(1.4); gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -192,7 +192,7 @@ TEST(GncOptimizer, checkMuConvergence) { { GncParams gncParams; gncParams.setLossType( - GncParams::RobustLossType::GM); + GncParams::GncLossType::GM); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -202,7 +202,7 @@ TEST(GncOptimizer, checkMuConvergence) { { GncParams gncParams; gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -256,7 +256,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { { GncParams gncParams; gncParams.setLossType( - GncParams::RobustLossType::GM); + GncParams::GncLossType::GM); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -266,7 +266,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { { GncParams gncParams; gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -277,7 +277,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { { GncParams gncParams; gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -288,7 +288,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { { GncParams gncParams; gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); gncParams.setWeightsTol(0.1); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -311,7 +311,7 @@ TEST(GncOptimizer, checkConvergenceTLS) { GncParams gncParams; gncParams.setRelativeCostTol(1e-5); gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -338,7 +338,7 @@ TEST(GncOptimizer, calculateWeightsGM) { GaussNewtonParams gnParams; GncParams gncParams(gnParams); gncParams.setLossType( - GncParams::RobustLossType::GM); + GncParams::GncLossType::GM); auto gnc = GncOptimizer>(fg, initial, gncParams); double mu = 1.0; Vector weights_actual = gnc.calculateWeights(initial, mu); @@ -373,7 +373,7 @@ TEST(GncOptimizer, calculateWeightsTLS) { GaussNewtonParams gnParams; GncParams gncParams(gnParams); gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); double mu = 1.0; Vector weights_actual = gnc.calculateWeights(initial, mu); @@ -408,7 +408,7 @@ TEST(GncOptimizer, calculateWeightsTLS2) { GaussNewtonParams gnParams; GncParams gncParams(gnParams); gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); gncParams.setInlierCostThreshold(0.51); // if inlier threshold is slightly larger than 0.5, then measurement is inlier auto gnc = GncOptimizer>(nfg, initial, gncParams); double mu = 1e6; @@ -424,7 +424,7 @@ TEST(GncOptimizer, calculateWeightsTLS2) { GaussNewtonParams gnParams; GncParams gncParams(gnParams); gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); gncParams.setInlierCostThreshold(0.49); // if inlier threshold is slightly below 0.5, then measurement is outlier auto gnc = GncOptimizer>(nfg, initial, gncParams); double mu = 1e6; // very large mu recovers original TLS cost @@ -440,7 +440,7 @@ TEST(GncOptimizer, calculateWeightsTLS2) { GaussNewtonParams gnParams; GncParams gncParams(gnParams); gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); gncParams.setInlierCostThreshold(0.5); // if inlier threshold is slightly below 0.5, then measurement is outlier auto gnc = GncOptimizer>(nfg, initial, gncParams); double mu = 1e6; // very large mu recovers original TLS cost @@ -552,7 +552,7 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { GncParams gncParams; gncParams.setKnownInliers(knownInliers); gncParams.setLossType( - GncParams::RobustLossType::GM); + GncParams::GncLossType::GM); //gncParams.setVerbosityGNC(GncParams::Verbosity::SUMMARY); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -569,7 +569,7 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { GncParams gncParams; gncParams.setKnownInliers(knownInliers); gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); // gncParams.setVerbosityGNC(GncParams::Verbosity::SUMMARY); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -588,7 +588,7 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { GncParams gncParams; gncParams.setKnownInliers(knownInliers); gncParams.setLossType( - GncParams::RobustLossType::TLS); + GncParams::GncLossType::TLS); //gncParams.setVerbosityGNC(GncParams::Verbosity::VALUES); gncParams.setInlierCostThreshold( 100.0 ); auto gnc = GncOptimizer>(fg, initial, gncParams); From dfdd2067081ec48422324f3703b1e9b9ca9d0e54 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Mon, 28 Dec 2020 21:03:20 -0500 Subject: [PATCH 191/261] addressed all except 2 comments by Frank. waiting for inputs on the 2 outstanding issues --- gtsam/nonlinear/GncOptimizer.h | 232 ++++++++++---------- gtsam/nonlinear/GncParams.h | 92 ++++---- tests/testGncOptimizer.cpp | 390 ++++++++++++++++----------------- 3 files changed, 357 insertions(+), 357 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index f28394545..bbc3b9f84 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -34,21 +34,22 @@ namespace gtsam { /* ************************************************************************* */ template class GncOptimizer { -public: - /** For each parameter, specify the corresponding optimizer: e.g., GaussNewtonParams -> GaussNewtonOptimizer */ + public: + /// For each parameter, specify the corresponding optimizer: e.g., GaussNewtonParams -> GaussNewtonOptimizer. typedef typename GncParameters::OptimizerType BaseOptimizer; -private: - NonlinearFactorGraph nfg_; - Values state_; - GncParameters params_; - Vector weights_; // this could be a local variable in optimize, but it is useful to make it accessible from outside + private: + NonlinearFactorGraph nfg_; ///< Original factor graph to be solved by GNC. + Values state_; ///< Initial values to be used at each iteration by GNC. + GncParameters params_; ///< GNC parameters. + Vector weights_; ///< Weights associated to each factor in GNC (this could be a local variable in optimize, but it is useful to make it accessible from outside). -public: - /// Constructor + public: + /// Constructor. GncOptimizer(const NonlinearFactorGraph& graph, const Values& initialValues, - const GncParameters& params = GncParameters()) : - state_(initialValues), params_(params) { + const GncParameters& params = GncParameters()) + : state_(initialValues), + params_(params) { // make sure all noiseModels are Gaussian or convert to Gaussian nfg_.resize(graph.size()); @@ -58,35 +59,39 @@ public: NoiseModelFactor>(graph[i]); noiseModel::Robust::shared_ptr robust = boost::dynamic_pointer_cast< noiseModel::Robust>(factor->noiseModel()); - if (robust) { // if the factor has a robust loss, we have to change it: + if (robust) { // if the factor has a robust loss, we have to change it: SharedNoiseModel gaussianNoise = robust->noise(); - NoiseModelFactor::shared_ptr gaussianFactor = - factor->cloneWithNewNoiseModel(gaussianNoise); + NoiseModelFactor::shared_ptr gaussianFactor = factor + ->cloneWithNewNoiseModel(gaussianNoise); nfg_[i] = gaussianFactor; - } else { // else we directly push it back + } else { // else we directly push it back nfg_[i] = factor; } } } } - /// Access a copy of the internal factor graph + /// Access a copy of the internal factor graph. NonlinearFactorGraph getFactors() const { return NonlinearFactorGraph(nfg_); } - /// Access a copy of the internal values + + /// Access a copy of the internal values. Values getState() const { return Values(state_); } - /// Access a copy of the parameters + + /// Access a copy of the parameters. GncParameters getParams() const { return GncParameters(params_); } - /// Access a copy of the GNC weights + + /// Access a copy of the GNC weights. Vector getWeights() const { return weights_; } - /// Compute optimal solution using graduated non-convexity + + /// Compute optimal solution using graduated non-convexity. Values optimize() { // start by assuming all measurements are inliers weights_ = Vector::Ones(nfg_.size()); @@ -94,7 +99,7 @@ public: Values result = baseOptimizer.optimize(); double mu = initializeMu(); double prev_cost = nfg_.error(result); - double cost = 0.0; // this will be updated in the main loop + double cost = 0.0; // this will be updated in the main loop // handle the degenerate case that corresponds to small // maximum residual errors at initialization @@ -103,7 +108,8 @@ public: if (mu <= 0) { if (params_.verbosity >= GncParameters::Verbosity::SUMMARY) { std::cout << "GNC Optimizer stopped because maximum residual at " - "initialization is small." << std::endl; + "initialization is small." + << std::endl; } if (params_.verbosity >= GncParameters::Verbosity::VALUES) { result.print("result\n"); @@ -132,7 +138,9 @@ public: // stopping condition cost = graph_iter.error(result); - if (checkConvergence(mu, weights_, cost, prev_cost)) { break; } + if (checkConvergence(mu, weights_, cost, prev_cost)) { + break; + } // update mu mu = updateMu(mu); @@ -157,7 +165,7 @@ public: return result; } - /// initialize the gnc parameter mu such that loss is approximately convex (remark 5 in GNC paper) + /// Initialize the gnc parameter mu such that loss is approximately convex (remark 5 in GNC paper). double initializeMu() const { // compute largest error across all factors double rmax_sq = 0.0; @@ -168,75 +176,80 @@ public: } // set initial mu switch (params_.lossType) { - case GncParameters::GM: - // surrogate cost is convex for large mu - return 2 * rmax_sq / params_.barcSq; // initial mu - case GncParameters::TLS: - // initialize mu to the value specified in Remark 5 in GNC paper. - // surrogate cost is convex for mu close to zero - // degenerate case: 2 * rmax_sq - params_.barcSq < 0 (handled in the main loop) - // according to remark mu = params_.barcSq / (2 * rmax_sq - params_.barcSq) = params_.barcSq/ excessResidual - // however, if the denominator is 0 or negative, we return mu = -1 which leads to termination of the main GNC loop - return (2 * rmax_sq - params_.barcSq) > 0 ? params_.barcSq / (2 * rmax_sq - params_.barcSq) : -1; - default: - throw std::runtime_error( - "GncOptimizer::initializeMu: called with unknown loss type."); + case GncParameters::GM: + // surrogate cost is convex for large mu + return 2 * rmax_sq / params_.barcSq; // initial mu + case GncParameters::TLS: + /* initialize mu to the value specified in Remark 5 in GNC paper. + surrogate cost is convex for mu close to zero + degenerate case: 2 * rmax_sq - params_.barcSq < 0 (handled in the main loop) + according to remark mu = params_.barcSq / (2 * rmax_sq - params_.barcSq) = params_.barcSq/ excessResidual + however, if the denominator is 0 or negative, we return mu = -1 which leads to termination of the main GNC loop + */ + return + (2 * rmax_sq - params_.barcSq) > 0 ? + params_.barcSq / (2 * rmax_sq - params_.barcSq) : -1; + default: + throw std::runtime_error( + "GncOptimizer::initializeMu: called with unknown loss type."); } } - /// update the gnc parameter mu to gradually increase nonconvexity + /// Update the gnc parameter mu to gradually increase nonconvexity. double updateMu(const double mu) const { switch (params_.lossType) { - case GncParameters::GM: - // reduce mu, but saturate at 1 (original cost is recovered for mu -> 1) - return std::max(1.0, mu / params_.muStep); - case GncParameters::TLS: - // increases mu at each iteration (original cost is recovered for mu -> inf) - return mu * params_.muStep; - default: - throw std::runtime_error( - "GncOptimizer::updateMu: called with unknown loss type."); + case GncParameters::GM: + // reduce mu, but saturate at 1 (original cost is recovered for mu -> 1) + return std::max(1.0, mu / params_.muStep); + case GncParameters::TLS: + // increases mu at each iteration (original cost is recovered for mu -> inf) + return mu * params_.muStep; + default: + throw std::runtime_error( + "GncOptimizer::updateMu: called with unknown loss type."); } } - /// check if we have reached the value of mu for which the surrogate loss matches the original loss + /// Check if we have reached the value of mu for which the surrogate loss matches the original loss. bool checkMuConvergence(const double mu) const { bool muConverged = false; switch (params_.lossType) { - case GncParameters::GM: - muConverged = std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function - break; - case GncParameters::TLS: - muConverged = false; // for TLS there is no stopping condition on mu (it must tend to infinity) - break; - default: - throw std::runtime_error( - "GncOptimizer::checkMuConvergence: called with unknown loss type."); + case GncParameters::GM: + muConverged = std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function + break; + case GncParameters::TLS: + muConverged = false; // for TLS there is no stopping condition on mu (it must tend to infinity) + break; + default: + throw std::runtime_error( + "GncOptimizer::checkMuConvergence: called with unknown loss type."); } if (muConverged && params_.verbosity >= GncParameters::Verbosity::SUMMARY) std::cout << "muConverged = true " << std::endl; return muConverged; } - /// check convergence of relative cost differences + /// Check convergence of relative cost differences. bool checkCostConvergence(const double cost, const double prev_cost) const { - bool costConverged = std::fabs(cost - prev_cost) / std::max(prev_cost,1e-7) < params_.relativeCostTol; + bool costConverged = std::fabs(cost - prev_cost) / std::max(prev_cost, 1e-7) + < params_.relativeCostTol; if (costConverged && params_.verbosity >= GncParameters::Verbosity::SUMMARY) std::cout << "checkCostConvergence = true " << std::endl; return costConverged; } - /// check convergence of weights to binary values + /// Check convergence of weights to binary values. bool checkWeightsConvergence(const Vector& weights) const { - bool weightsConverged = false; - switch (params_.lossType) { + bool weightsConverged = false; + switch (params_.lossType) { case GncParameters::GM: - weightsConverged = false; // for GM, there is no clear binary convergence for the weights + weightsConverged = false; // for GM, there is no clear binary convergence for the weights break; case GncParameters::TLS: weightsConverged = true; - for(size_t i=0; i params_.weightsTol ){ + for (size_t i = 0; i < weights.size(); i++) { + if (std::fabs(weights[i] - std::round(weights[i])) + > params_.weightsTol) { weightsConverged = false; break; } @@ -245,23 +258,21 @@ public: default: throw std::runtime_error( "GncOptimizer::checkWeightsConvergence: called with unknown loss type."); - } - if (weightsConverged && params_.verbosity >= GncParameters::Verbosity::SUMMARY) - std::cout << "weightsConverged = true " << std::endl; - return weightsConverged; } - - /// check for convergence between consecutive GNC iterations - bool checkConvergence(const double mu, - const Vector& weights, - const double cost, - const double prev_cost) const { - return checkCostConvergence(cost,prev_cost) || - checkWeightsConvergence(weights) || - checkMuConvergence(mu); + if (weightsConverged + && params_.verbosity >= GncParameters::Verbosity::SUMMARY) + std::cout << "weightsConverged = true " << std::endl; + return weightsConverged; } - /// create a graph where each factor is weighted by the gnc weights + /// Check for convergence between consecutive GNC iterations. + bool checkConvergence(const double mu, const Vector& weights, + const double cost, const double prev_cost) const { + return checkCostConvergence(cost, prev_cost) + || checkWeightsConvergence(weights) || checkMuConvergence(mu); + } + + /// Create a graph where each factor is weighted by the gnc weights. NonlinearFactorGraph makeWeightedGraph(const Vector& weights) const { // make sure all noiseModels are Gaussian or convert to Gaussian NonlinearFactorGraph newGraph; @@ -287,7 +298,7 @@ public: return newGraph; } - /// calculate gnc weights + /// Calculate gnc weights. Vector calculateWeights(const Values& currentEstimate, const double mu) { Vector weights = Vector::Ones(nfg_.size()); @@ -298,42 +309,43 @@ public: } std::vector unknownWeights; std::set_difference(allWeights.begin(), allWeights.end(), - params_.knownInliers.begin(), params_.knownInliers.end(), - std::inserter(unknownWeights, unknownWeights.begin())); + params_.knownInliers.begin(), + params_.knownInliers.end(), + std::inserter(unknownWeights, unknownWeights.begin())); // update weights of known inlier/outlier measurements switch (params_.lossType) { - case GncParameters::GM: { // use eq (12) in GNC paper - for (size_t k : unknownWeights) { - if (nfg_[k]) { - double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual - weights[k] = std::pow( - (mu * params_.barcSq) / (u2_k + mu * params_.barcSq), 2); - } - } - return weights; - } - case GncParameters::TLS: { // use eq (14) in GNC paper - double upperbound = (mu + 1) / mu * params_.barcSq; - double lowerbound = mu / (mu + 1) * params_.barcSq; - for (size_t k : unknownWeights) { - if (nfg_[k]) { - double u2_k = nfg_[k]->error( - currentEstimate); // squared (and whitened) residual - if (u2_k >= upperbound) { - weights[k] = 0; - } else if (u2_k <= lowerbound) { - weights[k] = 1; - } else { - weights[k] = std::sqrt(params_.barcSq * mu * (mu + 1) / u2_k) - mu; + case GncParameters::GM: { // use eq (12) in GNC paper + for (size_t k : unknownWeights) { + if (nfg_[k]) { + double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual + weights[k] = std::pow( + (mu * params_.barcSq) / (u2_k + mu * params_.barcSq), 2); } } + return weights; } - return weights; - } - default: - throw std::runtime_error( - "GncOptimizer::calculateWeights: called with unknown loss type."); + case GncParameters::TLS: { // use eq (14) in GNC paper + double upperbound = (mu + 1) / mu * params_.barcSq; + double lowerbound = mu / (mu + 1) * params_.barcSq; + for (size_t k : unknownWeights) { + if (nfg_[k]) { + double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual + if (u2_k >= upperbound) { + weights[k] = 0; + } else if (u2_k <= lowerbound) { + weights[k] = 1; + } else { + weights[k] = std::sqrt(params_.barcSq * mu * (mu + 1) / u2_k) + - mu; + } + } + } + return weights; + } + default: + throw std::runtime_error( + "GncOptimizer::calculateWeights: called with unknown loss type."); } } }; diff --git a/gtsam/nonlinear/GncParams.h b/gtsam/nonlinear/GncParams.h index 30ceef4c7..9c4f21b81 100644 --- a/gtsam/nonlinear/GncParams.h +++ b/gtsam/nonlinear/GncParams.h @@ -34,47 +34,50 @@ namespace gtsam { /* ************************************************************************* */ template class GncParams { -public: - /** For each parameter, specify the corresponding optimizer: e.g., GaussNewtonParams -> GaussNewtonOptimizer */ + public: + /// For each parameter, specify the corresponding optimizer: e.g., GaussNewtonParams -> GaussNewtonOptimizer. typedef typename BaseOptimizerParameters::OptimizerType OptimizerType; - /** Verbosity levels */ + /// Verbosity levels enum Verbosity { - SILENT = 0, SUMMARY, VALUES + SILENT = 0, + SUMMARY, + VALUES }; - /** Choice of robust loss function for GNC */ + /// Choice of robust loss function for GNC. enum GncLossType { - GM /*Geman McClure*/, TLS /*Truncated least squares*/ + GM /*Geman McClure*/, + TLS /*Truncated least squares*/ }; - /// Constructor - GncParams(const BaseOptimizerParameters& baseOptimizerParams) : - baseOptimizerParams(baseOptimizerParams) { + /// Constructor. + GncParams(const BaseOptimizerParameters& baseOptimizerParams) + : baseOptimizerParams(baseOptimizerParams) { } - /// Default constructor - GncParams() : - baseOptimizerParams() { + /// Default constructor. + GncParams() + : baseOptimizerParams() { } - /// GNC parameters - BaseOptimizerParameters baseOptimizerParams; /*optimization parameters used to solve the weighted least squares problem at each GNC iteration*/ + /// GNC parameters. + BaseOptimizerParameters baseOptimizerParams; ///< Optimization parameters used to solve the weighted least squares problem at each GNC iteration /// any other specific GNC parameters: - GncLossType lossType = TLS; /* default loss*/ - size_t maxIterations = 100; /* maximum number of iterations*/ - double barcSq = 1.0; /* a factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance*/ - double muStep = 1.4; /* multiplicative factor to reduce/increase the mu in gnc */ - double relativeCostTol = 1e-5; ///< if relative cost change is below this threshold, stop iterating - double weightsTol = 1e-4; ///< if the weights are within weightsTol from being binary, stop iterating (only for TLS) - Verbosity verbosity = SILENT; /* verbosity level */ - std::vector knownInliers = std::vector(); /* slots in the factor graph corresponding to measurements that we know are inliers */ + GncLossType lossType = TLS; ///< Default loss + size_t maxIterations = 100; ///< Maximum number of iterations + double barcSq = 1.0; ///< A factor is considered an inlier if factor.error() < barcSq. Note that factor.error() whitens by the covariance + double muStep = 1.4; ///< Multiplicative factor to reduce/increase the mu in gnc + double relativeCostTol = 1e-5; ///< If relative cost change is below this threshold, stop iterating + double weightsTol = 1e-4; ///< If the weights are within weightsTol from being binary, stop iterating (only for TLS) + Verbosity verbosity = SILENT; ///< Verbosity level + std::vector knownInliers = std::vector(); ///< Slots in the factor graph corresponding to measurements that we know are inliers - /// Set the robust loss function to be used in GNC (chosen among the ones in GncLossType) + /// Set the robust loss function to be used in GNC (chosen among the ones in GncLossType). void setLossType(const GncLossType type) { lossType = type; } - /// Set the maximum number of iterations in GNC (changing the max nr of iters might lead to less accurate solutions and is not recommended) + /// Set the maximum number of iterations in GNC (changing the max nr of iters might lead to less accurate solutions and is not recommended). void setMaxIterations(const size_t maxIter) { std::cout << "setMaxIterations: changing the max nr of iters might lead to less accurate solutions and is not recommended! " @@ -85,22 +88,24 @@ public: * the inlier threshold is the largest value of f(x) for the corresponding measurement to be considered an inlier. * In other words, an inlier at x is such that 0.5 * || r(x) ||^2_Omega <= barcSq. * Assuming a isotropic measurement covariance sigma^2 * Identity, the cost becomes: 0.5 * 1/sigma^2 || r(x) ||^2 <= barcSq. - * Hence || r(x) ||^2 <= 2 * barcSq * sigma^2 + * Hence || r(x) ||^2 <= 2 * barcSq * sigma^2. * */ void setInlierCostThreshold(const double inth) { barcSq = inth; } - /// Set the graduated non-convexity step: at each GNC iteration, mu is updated as mu <- mu * muStep + /// Set the graduated non-convexity step: at each GNC iteration, mu is updated as mu <- mu * muStep. void setMuStep(const double step) { muStep = step; } - /// Set the maximum relative difference in mu values to stop iterating - void setRelativeCostTol(double value) { relativeCostTol = value; + /// Set the maximum relative difference in mu values to stop iterating. + void setRelativeCostTol(double value) { + relativeCostTol = value; } - /// Set the maximum difference between the weights and their rounding in {0,1} to stop iterating - void setWeightsTol(double value) { weightsTol = value; + /// Set the maximum difference between the weights and their rounding in {0,1} to stop iterating. + void setWeightsTol(double value) { + weightsTol = value; } - /// Set the verbosity level + /// Set the verbosity level. void setVerbosityGNC(const Verbosity value) { verbosity = value; } @@ -108,33 +113,32 @@ public: * corresponds to the slots in the factor graph. For instance, if you have a nonlinear factor graph nfg, * and you provide knownIn = {0, 2, 15}, GNC will not apply outlier rejection to nfg[0], nfg[2], and nfg[15]. * This functionality is commonly used in SLAM when one may assume the odometry is outlier free, and - * only apply GNC to prune outliers from the loop closures + * only apply GNC to prune outliers from the loop closures. * */ void setKnownInliers(const std::vector& knownIn) { for (size_t i = 0; i < knownIn.size(); i++) knownInliers.push_back(knownIn[i]); } - /// equals + /// Equals. bool equals(const GncParams& other, double tol = 1e-9) const { return baseOptimizerParams.equals(other.baseOptimizerParams) && lossType == other.lossType && maxIterations == other.maxIterations && std::fabs(barcSq - other.barcSq) <= tol && std::fabs(muStep - other.muStep) <= tol - && verbosity == other.verbosity - && knownInliers == other.knownInliers; + && verbosity == other.verbosity && knownInliers == other.knownInliers; } - /// print function + /// Print. void print(const std::string& str) const { std::cout << str << "\n"; switch (lossType) { - case GM: - std::cout << "lossType: Geman McClure" << "\n"; - break; - case TLS: - std::cout << "lossType: Truncated Least-squares" << "\n"; - break; - default: - throw std::runtime_error("GncParams::print: unknown loss type."); + case GM: + std::cout << "lossType: Geman McClure" << "\n"; + break; + case TLS: + std::cout << "lossType: Truncated Least-squares" << "\n"; + break; + default: + throw std::runtime_error("GncParams::print: unknown loss type."); } std::cout << "maxIterations: " << maxIterations << "\n"; std::cout << "barcSq: " << barcSq << "\n"; diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index 15a83eb4b..f46563b91 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -73,16 +73,16 @@ TEST(GncOptimizer, gncParamsConstructor) { /* ************************************************************************* */ TEST(GncOptimizer, gncConstructor) { // has to have Gaussian noise models ! - auto fg = example::createReallyNonlinearFactorGraph(); // just a unary factor - // on a 2D point + auto fg = example::createReallyNonlinearFactorGraph(); // just a unary factor + // on a 2D point Point2 p0(3, 3); Values initial; initial.insert(X(1), p0); GncParams gncParams; - auto gnc = - GncOptimizer>(fg, initial, gncParams); + auto gnc = GncOptimizer>(fg, initial, + gncParams); CHECK(gnc.getFactors().equals(fg)); CHECK(gnc.getState().equals(initial)); @@ -100,8 +100,9 @@ TEST(GncOptimizer, gncConstructorWithRobustGraphAsInput) { initial.insert(X(1), p0); GncParams gncParams; - auto gnc = GncOptimizer>( - fg_robust, initial, gncParams); + auto gnc = GncOptimizer>(fg_robust, + initial, + gncParams); // make sure that when parsing the graph is transformed into one without // robust loss @@ -118,19 +119,17 @@ TEST(GncOptimizer, initializeMu) { // testing GM mu initialization GncParams gncParams; - gncParams.setLossType( - GncParams::GncLossType::GM); - auto gnc_gm = - GncOptimizer>(fg, initial, gncParams); + gncParams.setLossType(GncParams::GncLossType::GM); + auto gnc_gm = GncOptimizer>(fg, initial, + gncParams); // according to rmk 5 in the gnc paper: m0 = 2 rmax^2 / barcSq // (barcSq=1 in this example) EXPECT_DOUBLES_EQUAL(gnc_gm.initializeMu(), 2 * 198.999, 1e-3); // testing TLS mu initialization - gncParams.setLossType( - GncParams::GncLossType::TLS); - auto gnc_tls = - GncOptimizer>(fg, initial, gncParams); + gncParams.setLossType(GncParams::GncLossType::TLS); + auto gnc_tls = GncOptimizer>(fg, initial, + gncParams); // according to rmk 5 in the gnc paper: m0 = barcSq / (2 * rmax^2 - barcSq) // (barcSq=1 in this example) EXPECT_DOUBLES_EQUAL(gnc_tls.initializeMu(), 1 / (2 * 198.999 - 1), 1e-3); @@ -146,11 +145,10 @@ TEST(GncOptimizer, updateMuGM) { initial.insert(X(1), p0); GncParams gncParams; - gncParams.setLossType( - GncParams::GncLossType::GM); + gncParams.setLossType(GncParams::GncLossType::GM); gncParams.setMuStep(1.4); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + auto gnc = GncOptimizer>(fg, initial, + gncParams); double mu = 5.0; EXPECT_DOUBLES_EQUAL(gnc.updateMu(mu), mu / 1.4, tol); @@ -171,10 +169,9 @@ TEST(GncOptimizer, updateMuTLS) { GncParams gncParams; gncParams.setMuStep(1.4); - gncParams.setLossType( - GncParams::GncLossType::TLS); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + gncParams.setLossType(GncParams::GncLossType::TLS); + auto gnc = GncOptimizer>(fg, initial, + gncParams); double mu = 5.0; EXPECT_DOUBLES_EQUAL(gnc.updateMu(mu), mu * 1.4, tol); @@ -190,24 +187,23 @@ TEST(GncOptimizer, checkMuConvergence) { initial.insert(X(1), p0); { - GncParams gncParams; - gncParams.setLossType( - GncParams::GncLossType::GM); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + GncParams gncParams; + gncParams.setLossType(GncParams::GncLossType::GM); + auto gnc = GncOptimizer>(fg, initial, + gncParams); - double mu = 1.0; - CHECK(gnc.checkMuConvergence(mu)); + double mu = 1.0; + CHECK(gnc.checkMuConvergence(mu)); } { - GncParams gncParams; - gncParams.setLossType( - GncParams::GncLossType::TLS); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + GncParams gncParams; + gncParams.setLossType( + GncParams::GncLossType::TLS); + auto gnc = GncOptimizer>(fg, initial, + gncParams); - double mu = 1.0; - CHECK(!gnc.checkMuConvergence(mu)); //always false for TLS + double mu = 1.0; + CHECK(!gnc.checkMuConvergence(mu)); //always false for TLS } } @@ -221,26 +217,26 @@ TEST(GncOptimizer, checkCostConvergence) { initial.insert(X(1), p0); { - GncParams gncParams; - gncParams.setRelativeCostTol(0.49); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + GncParams gncParams; + gncParams.setRelativeCostTol(0.49); + auto gnc = GncOptimizer>(fg, initial, + gncParams); - double prev_cost = 1.0; - double cost = 0.5; - // relative cost reduction = 0.5 > 0.49, hence checkCostConvergence = false - CHECK(!gnc.checkCostConvergence(cost, prev_cost)); + double prev_cost = 1.0; + double cost = 0.5; + // relative cost reduction = 0.5 > 0.49, hence checkCostConvergence = false + CHECK(!gnc.checkCostConvergence(cost, prev_cost)); } { - GncParams gncParams; - gncParams.setRelativeCostTol(0.51); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + GncParams gncParams; + gncParams.setRelativeCostTol(0.51); + auto gnc = GncOptimizer>(fg, initial, + gncParams); - double prev_cost = 1.0; - double cost = 0.5; - // relative cost reduction = 0.5 < 0.51, hence checkCostConvergence = true - CHECK(gnc.checkCostConvergence(cost, prev_cost)); + double prev_cost = 1.0; + double cost = 0.5; + // relative cost reduction = 0.5 < 0.51, hence checkCostConvergence = true + CHECK(gnc.checkCostConvergence(cost, prev_cost)); } } @@ -254,48 +250,47 @@ TEST(GncOptimizer, checkWeightsConvergence) { initial.insert(X(1), p0); { - GncParams gncParams; - gncParams.setLossType( - GncParams::GncLossType::GM); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + GncParams gncParams; + gncParams.setLossType(GncParams::GncLossType::GM); + auto gnc = GncOptimizer>(fg, initial, + gncParams); - Vector weights = Vector::Ones(fg.size()); - CHECK(!gnc.checkWeightsConvergence(weights)); //always false for GM + Vector weights = Vector::Ones(fg.size()); + CHECK(!gnc.checkWeightsConvergence(weights)); //always false for GM } { - GncParams gncParams; - gncParams.setLossType( - GncParams::GncLossType::TLS); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + GncParams gncParams; + gncParams.setLossType( + GncParams::GncLossType::TLS); + auto gnc = GncOptimizer>(fg, initial, + gncParams); - Vector weights = Vector::Ones(fg.size()); - // weights are binary, so checkWeightsConvergence = true - CHECK(gnc.checkWeightsConvergence(weights)); + Vector weights = Vector::Ones(fg.size()); + // weights are binary, so checkWeightsConvergence = true + CHECK(gnc.checkWeightsConvergence(weights)); } { - GncParams gncParams; - gncParams.setLossType( - GncParams::GncLossType::TLS); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + GncParams gncParams; + gncParams.setLossType( + GncParams::GncLossType::TLS); + auto gnc = GncOptimizer>(fg, initial, + gncParams); - Vector weights = Vector::Ones(fg.size()); - weights[0] = 0.9; // more than weightsTol = 1e-4 from 1, hence checkWeightsConvergence = false - CHECK(!gnc.checkWeightsConvergence(weights)); + Vector weights = Vector::Ones(fg.size()); + weights[0] = 0.9; // more than weightsTol = 1e-4 from 1, hence checkWeightsConvergence = false + CHECK(!gnc.checkWeightsConvergence(weights)); } { - GncParams gncParams; - gncParams.setLossType( - GncParams::GncLossType::TLS); - gncParams.setWeightsTol(0.1); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + GncParams gncParams; + gncParams.setLossType( + GncParams::GncLossType::TLS); + gncParams.setWeightsTol(0.1); + auto gnc = GncOptimizer>(fg, initial, + gncParams); - Vector weights = Vector::Ones(fg.size()); - weights[0] = 0.9; // exactly weightsTol = 0.1 from 1, hence checkWeightsConvergence = true - CHECK(gnc.checkWeightsConvergence(weights)); + Vector weights = Vector::Ones(fg.size()); + weights[0] = 0.9; // exactly weightsTol = 0.1 from 1, hence checkWeightsConvergence = true + CHECK(gnc.checkWeightsConvergence(weights)); } } @@ -310,10 +305,9 @@ TEST(GncOptimizer, checkConvergenceTLS) { GncParams gncParams; gncParams.setRelativeCostTol(1e-5); - gncParams.setLossType( - GncParams::GncLossType::TLS); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + gncParams.setLossType(GncParams::GncLossType::TLS); + auto gnc = GncOptimizer>(fg, initial, + gncParams); CHECK(gnc.checkCostConvergence(1.0, 1.0)); CHECK(!gnc.checkCostConvergence(1.0, 2.0)); @@ -333,12 +327,11 @@ TEST(GncOptimizer, calculateWeightsGM) { weights_expected[0] = 1.0; // zero error weights_expected[1] = 1.0; // zero error weights_expected[2] = 1.0; // zero error - weights_expected[3] = std::pow(1.0 / (50.0 + 1.0), 2); // outlier, error = 50 + weights_expected[3] = std::pow(1.0 / (50.0 + 1.0), 2); // outlier, error = 50 GaussNewtonParams gnParams; GncParams gncParams(gnParams); - gncParams.setLossType( - GncParams::GncLossType::GM); + gncParams.setLossType(GncParams::GncLossType::GM); auto gnc = GncOptimizer>(fg, initial, gncParams); double mu = 1.0; Vector weights_actual = gnc.calculateWeights(initial, mu); @@ -346,11 +339,10 @@ TEST(GncOptimizer, calculateWeightsGM) { mu = 2.0; double barcSq = 5.0; - weights_expected[3] = - std::pow(mu * barcSq / (50.0 + mu * barcSq), 2); // outlier, error = 50 + weights_expected[3] = std::pow(mu * barcSq / (50.0 + mu * barcSq), 2); // outlier, error = 50 gncParams.setInlierCostThreshold(barcSq); - auto gnc2 = - GncOptimizer>(fg, initial, gncParams); + auto gnc2 = GncOptimizer>(fg, initial, + gncParams); weights_actual = gnc2.calculateWeights(initial, mu); CHECK(assert_equal(weights_expected, weights_actual, tol)); } @@ -372,8 +364,7 @@ TEST(GncOptimizer, calculateWeightsTLS) { GaussNewtonParams gnParams; GncParams gncParams(gnParams); - gncParams.setLossType( - GncParams::GncLossType::TLS); + gncParams.setLossType(GncParams::GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); double mu = 1.0; Vector weights_actual = gnc.calculateWeights(initial, mu); @@ -391,45 +382,44 @@ TEST(GncOptimizer, calculateWeightsTLS2) { // create very simple factor graph with a single factor 0.5 * 1/sigma^2 * || x - [1;0] ||^2 double sigma = 1; - SharedDiagonal noise = - noiseModel::Diagonal::Sigmas(Vector2(sigma, sigma)); + SharedDiagonal noise = noiseModel::Diagonal::Sigmas(Vector2(sigma, sigma)); NonlinearFactorGraph nfg; - nfg.add(PriorFactor(X(1),x_prior,noise)); + nfg.add(PriorFactor(X(1), x_prior, noise)); // cost of the factor: - DOUBLES_EQUAL(0.5 * 1/(sigma*sigma), nfg.error(initial), tol); + DOUBLES_EQUAL(0.5 * 1 / (sigma * sigma), nfg.error(initial), tol); // check the TLS weights are correct: CASE 1: residual below barcsq { - // expected: - Vector weights_expected = Vector::Zero(1); - weights_expected[0] = 1.0; // inlier - // actual: - GaussNewtonParams gnParams; - GncParams gncParams(gnParams); - gncParams.setLossType( - GncParams::GncLossType::TLS); - gncParams.setInlierCostThreshold(0.51); // if inlier threshold is slightly larger than 0.5, then measurement is inlier - auto gnc = GncOptimizer>(nfg, initial, gncParams); - double mu = 1e6; - Vector weights_actual = gnc.calculateWeights(initial, mu); - CHECK(assert_equal(weights_expected, weights_actual, tol)); + // expected: + Vector weights_expected = Vector::Zero(1); + weights_expected[0] = 1.0; // inlier + // actual: + GaussNewtonParams gnParams; + GncParams gncParams(gnParams); + gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setInlierCostThreshold(0.51); // if inlier threshold is slightly larger than 0.5, then measurement is inlier + auto gnc = GncOptimizer>(nfg, initial, + gncParams); + double mu = 1e6; + Vector weights_actual = gnc.calculateWeights(initial, mu); + CHECK(assert_equal(weights_expected, weights_actual, tol)); } // check the TLS weights are correct: CASE 2: residual above barcsq { - // expected: - Vector weights_expected = Vector::Zero(1); - weights_expected[0] = 0.0; // outlier - // actual: - GaussNewtonParams gnParams; - GncParams gncParams(gnParams); - gncParams.setLossType( - GncParams::GncLossType::TLS); - gncParams.setInlierCostThreshold(0.49); // if inlier threshold is slightly below 0.5, then measurement is outlier - auto gnc = GncOptimizer>(nfg, initial, gncParams); - double mu = 1e6; // very large mu recovers original TLS cost - Vector weights_actual = gnc.calculateWeights(initial, mu); - CHECK(assert_equal(weights_expected, weights_actual, tol)); + // expected: + Vector weights_expected = Vector::Zero(1); + weights_expected[0] = 0.0; // outlier + // actual: + GaussNewtonParams gnParams; + GncParams gncParams(gnParams); + gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setInlierCostThreshold(0.49); // if inlier threshold is slightly below 0.5, then measurement is outlier + auto gnc = GncOptimizer>(nfg, initial, + gncParams); + double mu = 1e6; // very large mu recovers original TLS cost + Vector weights_actual = gnc.calculateWeights(initial, mu); + CHECK(assert_equal(weights_expected, weights_actual, tol)); } // check the TLS weights are correct: CASE 2: residual at barcsq { @@ -439,11 +429,11 @@ TEST(GncOptimizer, calculateWeightsTLS2) { // actual: GaussNewtonParams gnParams; GncParams gncParams(gnParams); - gncParams.setLossType( - GncParams::GncLossType::TLS); - gncParams.setInlierCostThreshold(0.5); // if inlier threshold is slightly below 0.5, then measurement is outlier - auto gnc = GncOptimizer>(nfg, initial, gncParams); - double mu = 1e6; // very large mu recovers original TLS cost + gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setInlierCostThreshold(0.5); // if inlier threshold is slightly below 0.5, then measurement is outlier + auto gnc = GncOptimizer>(nfg, initial, + gncParams); + double mu = 1e6; // very large mu recovers original TLS cost Vector weights_actual = gnc.calculateWeights(initial, mu); CHECK(assert_equal(weights_expected, weights_actual, 1e-5)); } @@ -453,17 +443,16 @@ TEST(GncOptimizer, calculateWeightsTLS2) { TEST(GncOptimizer, makeWeightedGraph) { // create original factor double sigma1 = 0.1; - NonlinearFactorGraph nfg = - example::nonlinearFactorGraphWithGivenSigma(sigma1); + NonlinearFactorGraph nfg = example::nonlinearFactorGraphWithGivenSigma( + sigma1); // create expected double sigma2 = 10; - NonlinearFactorGraph expected = - example::nonlinearFactorGraphWithGivenSigma(sigma2); + NonlinearFactorGraph expected = example::nonlinearFactorGraphWithGivenSigma( + sigma2); // create weights - Vector weights = Vector::Ones( - 1); // original info:1/0.1^2 = 100. New info: 1/10^2 = 0.01. Ratio is 10-4 + Vector weights = Vector::Ones(1); // original info:1/0.1^2 = 100. New info: 1/10^2 = 0.01. Ratio is 10-4 weights[0] = 1e-4; // create actual @@ -491,8 +480,8 @@ TEST(GncOptimizer, optimizeSimple) { LevenbergMarquardtParams lmParams; GncParams gncParams(lmParams); - auto gnc = - GncOptimizer>(fg, initial, gncParams); + auto gnc = GncOptimizer>(fg, initial, + gncParams); Values actual = gnc.optimize(); DOUBLES_EQUAL(0, fg.error(actual), tol); @@ -515,15 +504,13 @@ TEST(GncOptimizer, optimize) { CHECK(assert_equal(Point2(0.25, 0.0), gn_results.at(X(1)), 1e-3)); // try with robust loss function and standard GN - auto fg_robust = - example::sharedRobustFactorGraphWithOutliers(); // same as fg, but with - // factors wrapped in - // Geman McClure losses + auto fg_robust = example::sharedRobustFactorGraphWithOutliers(); // same as fg, but with + // factors wrapped in + // Geman McClure losses GaussNewtonOptimizer gn2(fg_robust, initial, gnParams); Values gn2_results = gn2.optimize(); // converges to incorrect point, this time due to the nonconvexity of the loss - CHECK( - assert_equal(Point2(0.999706, 0.0), gn2_results.at(X(1)), 1e-3)); + CHECK(assert_equal(Point2(0.999706, 0.0), gn2_results.at(X(1)), 1e-3)); // .. but graduated nonconvexity ensures both robustness and convergence in // the face of nonconvexity @@ -549,59 +536,59 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { // nonconvexity with known inliers { - GncParams gncParams; - gncParams.setKnownInliers(knownInliers); - gncParams.setLossType( - GncParams::GncLossType::GM); - //gncParams.setVerbosityGNC(GncParams::Verbosity::SUMMARY); - auto gnc = GncOptimizer>(fg, initial, gncParams); + GncParams gncParams; + gncParams.setKnownInliers(knownInliers); + gncParams.setLossType(GncParams::GncLossType::GM); + //gncParams.setVerbosityGNC(GncParams::Verbosity::SUMMARY); + auto gnc = GncOptimizer>(fg, initial, + gncParams); - Values gnc_result = gnc.optimize(); - CHECK(assert_equal(Point2(0.0, 0.0), gnc_result.at(X(1)), 1e-3)); + Values gnc_result = gnc.optimize(); + CHECK(assert_equal(Point2(0.0, 0.0), gnc_result.at(X(1)), 1e-3)); - // check weights were actually fixed: - Vector finalWeights = gnc.getWeights(); - DOUBLES_EQUAL(1.0, finalWeights[0], tol); - DOUBLES_EQUAL(1.0, finalWeights[1], tol); - DOUBLES_EQUAL(1.0, finalWeights[2], tol); + // check weights were actually fixed: + Vector finalWeights = gnc.getWeights(); + DOUBLES_EQUAL(1.0, finalWeights[0], tol); + DOUBLES_EQUAL(1.0, finalWeights[1], tol); + DOUBLES_EQUAL(1.0, finalWeights[2], tol); } { - GncParams gncParams; - gncParams.setKnownInliers(knownInliers); - gncParams.setLossType( - GncParams::GncLossType::TLS); - // gncParams.setVerbosityGNC(GncParams::Verbosity::SUMMARY); - auto gnc = GncOptimizer>(fg, initial, gncParams); + GncParams gncParams; + gncParams.setKnownInliers(knownInliers); + gncParams.setLossType(GncParams::GncLossType::TLS); + // gncParams.setVerbosityGNC(GncParams::Verbosity::SUMMARY); + auto gnc = GncOptimizer>(fg, initial, + gncParams); - Values gnc_result = gnc.optimize(); - CHECK(assert_equal(Point2(0.0, 0.0), gnc_result.at(X(1)), 1e-3)); + Values gnc_result = gnc.optimize(); + CHECK(assert_equal(Point2(0.0, 0.0), gnc_result.at(X(1)), 1e-3)); - // check weights were actually fixed: - Vector finalWeights = gnc.getWeights(); - DOUBLES_EQUAL(1.0, finalWeights[0], tol); - DOUBLES_EQUAL(1.0, finalWeights[1], tol); - DOUBLES_EQUAL(1.0, finalWeights[2], tol); - DOUBLES_EQUAL(0.0, finalWeights[3], tol); + // check weights were actually fixed: + Vector finalWeights = gnc.getWeights(); + DOUBLES_EQUAL(1.0, finalWeights[0], tol); + DOUBLES_EQUAL(1.0, finalWeights[1], tol); + DOUBLES_EQUAL(1.0, finalWeights[2], tol); + DOUBLES_EQUAL(0.0, finalWeights[3], tol); } { - // if we set the threshold large, they are all inliers - GncParams gncParams; - gncParams.setKnownInliers(knownInliers); - gncParams.setLossType( - GncParams::GncLossType::TLS); - //gncParams.setVerbosityGNC(GncParams::Verbosity::VALUES); - gncParams.setInlierCostThreshold( 100.0 ); - auto gnc = GncOptimizer>(fg, initial, gncParams); + // if we set the threshold large, they are all inliers + GncParams gncParams; + gncParams.setKnownInliers(knownInliers); + gncParams.setLossType(GncParams::GncLossType::TLS); + //gncParams.setVerbosityGNC(GncParams::Verbosity::VALUES); + gncParams.setInlierCostThreshold(100.0); + auto gnc = GncOptimizer>(fg, initial, + gncParams); - Values gnc_result = gnc.optimize(); - CHECK(assert_equal(Point2(0.25, 0.0), gnc_result.at(X(1)), 1e-3)); + Values gnc_result = gnc.optimize(); + CHECK(assert_equal(Point2(0.25, 0.0), gnc_result.at(X(1)), 1e-3)); - // check weights were actually fixed: - Vector finalWeights = gnc.getWeights(); - DOUBLES_EQUAL(1.0, finalWeights[0], tol); - DOUBLES_EQUAL(1.0, finalWeights[1], tol); - DOUBLES_EQUAL(1.0, finalWeights[2], tol); - DOUBLES_EQUAL(1.0, finalWeights[3], tol); + // check weights were actually fixed: + Vector finalWeights = gnc.getWeights(); + DOUBLES_EQUAL(1.0, finalWeights[0], tol); + DOUBLES_EQUAL(1.0, finalWeights[1], tol); + DOUBLES_EQUAL(1.0, finalWeights[2], tol); + DOUBLES_EQUAL(1.0, finalWeights[3], tol); } } @@ -613,24 +600,22 @@ TEST(GncOptimizer, optimizeSmallPoseGraph) { Values::shared_ptr initial; boost::tie(graph, initial) = load2D(filename); // Add a Gaussian prior on first poses - Pose2 priorMean(0.0, 0.0, 0.0); // prior at origin - SharedDiagonal priorNoise = - noiseModel::Diagonal::Sigmas(Vector3(0.01, 0.01, 0.01)); + Pose2 priorMean(0.0, 0.0, 0.0); // prior at origin + SharedDiagonal priorNoise = noiseModel::Diagonal::Sigmas( + Vector3(0.01, 0.01, 0.01)); graph->addPrior(0, priorMean, priorNoise); /// get expected values by optimizing outlier-free graph Values expected = LevenbergMarquardtOptimizer(*graph, *initial).optimize(); // add a few outliers - SharedDiagonal betweenNoise = - noiseModel::Diagonal::Sigmas(Vector3(0.1, 0.1, 0.01)); - graph->push_back(BetweenFactor( - 90, 50, Pose2(), - betweenNoise)); // some arbitrary and incorrect between factor + SharedDiagonal betweenNoise = noiseModel::Diagonal::Sigmas( + Vector3(0.1, 0.1, 0.01)); + graph->push_back(BetweenFactor(90, 50, Pose2(), betweenNoise)); // some arbitrary and incorrect between factor /// get expected values by optimizing outlier-free graph - Values expectedWithOutliers = - LevenbergMarquardtOptimizer(*graph, *initial).optimize(); + Values expectedWithOutliers = LevenbergMarquardtOptimizer(*graph, *initial) + .optimize(); // as expected, the following test fails due to the presence of an outlier! // CHECK(assert_equal(expected, expectedWithOutliers, 1e-3)); @@ -639,13 +624,12 @@ TEST(GncOptimizer, optimizeSmallPoseGraph) { // inliers, but this problem is simple enought to succeed even without that // assumption std::vector knownInliers; GncParams gncParams; - auto gnc = - GncOptimizer>(*graph, *initial, gncParams); + auto gnc = GncOptimizer>(*graph, *initial, + gncParams); Values actual = gnc.optimize(); // compare - CHECK( - assert_equal(expected, actual, 1e-3)); // yay! we are robust to outliers! + CHECK(assert_equal(expected, actual, 1e-3)); // yay! we are robust to outliers! } /* ************************************************************************* */ From c7c0c77a12d52327e130e1c659c305d5ac4b647f Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Tue, 29 Dec 2020 08:53:19 +0530 Subject: [PATCH 192/261] Adding Cal3DS2 prior factor and using template instead of typedefs --- gtsam/gtsam.i | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 870f3edc0..69b8bfebf 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -2520,7 +2520,7 @@ class NonlinearISAM { #include #include -template}> +template}> virtual class PriorFactor : gtsam::NoiseModelFactor { PriorFactor(size_t key, const T& prior, const gtsam::noiseModel::Base* noiseModel); T prior() const; @@ -2666,7 +2666,7 @@ typedef gtsam::GeneralSFMFactor Gene typedef gtsam::GeneralSFMFactor GeneralSFMFactorCal3DS2; typedef gtsam::GeneralSFMFactor, gtsam::Point3> GeneralSFMFactorCal3Bundler; -template +template virtual class GeneralSFMFactor2 : gtsam::NoiseModelFactor { GeneralSFMFactor2(const gtsam::Point2& measured, const gtsam::noiseModel::Base* model, size_t poseKey, size_t landmarkKey, size_t calibKey); gtsam::Point2 measured() const; @@ -2674,9 +2674,6 @@ virtual class GeneralSFMFactor2 : gtsam::NoiseModelFactor { // enabling serialization functionality void serialize() const; }; -typedef gtsam::GeneralSFMFactor2 GeneralSFMFactor2Cal3_S2; -typedef gtsam::GeneralSFMFactor2 GeneralSFMFactor2Cal3DS2; -typedef gtsam::GeneralSFMFactor2 GeneralSFMFactor2Cal3Bundler; #include class SmartProjectionParams { From 24672385b377962ae9bb87ec04cf7726bc43c8b6 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Tue, 29 Dec 2020 21:59:21 -0500 Subject: [PATCH 193/261] moved gncLossType outside params --- gtsam/nonlinear/GncOptimizer.h | 20 ++++++++--------- gtsam/nonlinear/GncParams.h | 12 +++++----- tests/testGncOptimizer.cpp | 40 +++++++++++++++++----------------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index bbc3b9f84..cfabf0ab6 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -176,10 +176,10 @@ class GncOptimizer { } // set initial mu switch (params_.lossType) { - case GncParameters::GM: + case GncLossType::GM: // surrogate cost is convex for large mu return 2 * rmax_sq / params_.barcSq; // initial mu - case GncParameters::TLS: + case GncLossType::TLS: /* initialize mu to the value specified in Remark 5 in GNC paper. surrogate cost is convex for mu close to zero degenerate case: 2 * rmax_sq - params_.barcSq < 0 (handled in the main loop) @@ -198,10 +198,10 @@ class GncOptimizer { /// Update the gnc parameter mu to gradually increase nonconvexity. double updateMu(const double mu) const { switch (params_.lossType) { - case GncParameters::GM: + case GncLossType::GM: // reduce mu, but saturate at 1 (original cost is recovered for mu -> 1) return std::max(1.0, mu / params_.muStep); - case GncParameters::TLS: + case GncLossType::TLS: // increases mu at each iteration (original cost is recovered for mu -> inf) return mu * params_.muStep; default: @@ -214,10 +214,10 @@ class GncOptimizer { bool checkMuConvergence(const double mu) const { bool muConverged = false; switch (params_.lossType) { - case GncParameters::GM: + case GncLossType::GM: muConverged = std::fabs(mu - 1.0) < 1e-9; // mu=1 recovers the original GM function break; - case GncParameters::TLS: + case GncLossType::TLS: muConverged = false; // for TLS there is no stopping condition on mu (it must tend to infinity) break; default: @@ -242,10 +242,10 @@ class GncOptimizer { bool checkWeightsConvergence(const Vector& weights) const { bool weightsConverged = false; switch (params_.lossType) { - case GncParameters::GM: + case GncLossType::GM: weightsConverged = false; // for GM, there is no clear binary convergence for the weights break; - case GncParameters::TLS: + case GncLossType::TLS: weightsConverged = true; for (size_t i = 0; i < weights.size(); i++) { if (std::fabs(weights[i] - std::round(weights[i])) @@ -315,7 +315,7 @@ class GncOptimizer { // update weights of known inlier/outlier measurements switch (params_.lossType) { - case GncParameters::GM: { // use eq (12) in GNC paper + case GncLossType::GM: { // use eq (12) in GNC paper for (size_t k : unknownWeights) { if (nfg_[k]) { double u2_k = nfg_[k]->error(currentEstimate); // squared (and whitened) residual @@ -325,7 +325,7 @@ class GncOptimizer { } return weights; } - case GncParameters::TLS: { // use eq (14) in GNC paper + case GncLossType::TLS: { // use eq (14) in GNC paper double upperbound = (mu + 1) / mu * params_.barcSq; double lowerbound = mu / (mu + 1) * params_.barcSq; for (size_t k : unknownWeights) { diff --git a/gtsam/nonlinear/GncParams.h b/gtsam/nonlinear/GncParams.h index 9c4f21b81..5f130ddf2 100644 --- a/gtsam/nonlinear/GncParams.h +++ b/gtsam/nonlinear/GncParams.h @@ -32,6 +32,12 @@ namespace gtsam { /* ************************************************************************* */ +/// Choice of robust loss function for GNC. +enum GncLossType { + GM /*Geman McClure*/, + TLS /*Truncated least squares*/ +}; + template class GncParams { public: @@ -45,12 +51,6 @@ class GncParams { VALUES }; - /// Choice of robust loss function for GNC. - enum GncLossType { - GM /*Geman McClure*/, - TLS /*Truncated least squares*/ - }; - /// Constructor. GncParams(const BaseOptimizerParameters& baseOptimizerParams) : baseOptimizerParams(baseOptimizerParams) { diff --git a/tests/testGncOptimizer.cpp b/tests/testGncOptimizer.cpp index f46563b91..738c77936 100644 --- a/tests/testGncOptimizer.cpp +++ b/tests/testGncOptimizer.cpp @@ -66,7 +66,7 @@ TEST(GncOptimizer, gncParamsConstructor) { // change something at the gncParams level GncParams gncParams2c(gncParams2b); - gncParams2c.setLossType(GncParams::GncLossType::GM); + gncParams2c.setLossType(GncLossType::GM); CHECK(!gncParams2c.equals(gncParams2b.baseOptimizerParams)); } @@ -119,7 +119,7 @@ TEST(GncOptimizer, initializeMu) { // testing GM mu initialization GncParams gncParams; - gncParams.setLossType(GncParams::GncLossType::GM); + gncParams.setLossType(GncLossType::GM); auto gnc_gm = GncOptimizer>(fg, initial, gncParams); // according to rmk 5 in the gnc paper: m0 = 2 rmax^2 / barcSq @@ -127,7 +127,7 @@ TEST(GncOptimizer, initializeMu) { EXPECT_DOUBLES_EQUAL(gnc_gm.initializeMu(), 2 * 198.999, 1e-3); // testing TLS mu initialization - gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setLossType(GncLossType::TLS); auto gnc_tls = GncOptimizer>(fg, initial, gncParams); // according to rmk 5 in the gnc paper: m0 = barcSq / (2 * rmax^2 - barcSq) @@ -145,7 +145,7 @@ TEST(GncOptimizer, updateMuGM) { initial.insert(X(1), p0); GncParams gncParams; - gncParams.setLossType(GncParams::GncLossType::GM); + gncParams.setLossType(GncLossType::GM); gncParams.setMuStep(1.4); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -169,7 +169,7 @@ TEST(GncOptimizer, updateMuTLS) { GncParams gncParams; gncParams.setMuStep(1.4); - gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setLossType(GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -188,7 +188,7 @@ TEST(GncOptimizer, checkMuConvergence) { { GncParams gncParams; - gncParams.setLossType(GncParams::GncLossType::GM); + gncParams.setLossType(GncLossType::GM); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -198,7 +198,7 @@ TEST(GncOptimizer, checkMuConvergence) { { GncParams gncParams; gncParams.setLossType( - GncParams::GncLossType::TLS); + GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -251,7 +251,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { { GncParams gncParams; - gncParams.setLossType(GncParams::GncLossType::GM); + gncParams.setLossType(GncLossType::GM); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -261,7 +261,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { { GncParams gncParams; gncParams.setLossType( - GncParams::GncLossType::TLS); + GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -272,7 +272,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { { GncParams gncParams; gncParams.setLossType( - GncParams::GncLossType::TLS); + GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -283,7 +283,7 @@ TEST(GncOptimizer, checkWeightsConvergence) { { GncParams gncParams; gncParams.setLossType( - GncParams::GncLossType::TLS); + GncLossType::TLS); gncParams.setWeightsTol(0.1); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -305,7 +305,7 @@ TEST(GncOptimizer, checkConvergenceTLS) { GncParams gncParams; gncParams.setRelativeCostTol(1e-5); - gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setLossType(GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -331,7 +331,7 @@ TEST(GncOptimizer, calculateWeightsGM) { GaussNewtonParams gnParams; GncParams gncParams(gnParams); - gncParams.setLossType(GncParams::GncLossType::GM); + gncParams.setLossType(GncLossType::GM); auto gnc = GncOptimizer>(fg, initial, gncParams); double mu = 1.0; Vector weights_actual = gnc.calculateWeights(initial, mu); @@ -364,7 +364,7 @@ TEST(GncOptimizer, calculateWeightsTLS) { GaussNewtonParams gnParams; GncParams gncParams(gnParams); - gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setLossType(GncLossType::TLS); auto gnc = GncOptimizer>(fg, initial, gncParams); double mu = 1.0; Vector weights_actual = gnc.calculateWeights(initial, mu); @@ -397,7 +397,7 @@ TEST(GncOptimizer, calculateWeightsTLS2) { // actual: GaussNewtonParams gnParams; GncParams gncParams(gnParams); - gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setLossType(GncLossType::TLS); gncParams.setInlierCostThreshold(0.51); // if inlier threshold is slightly larger than 0.5, then measurement is inlier auto gnc = GncOptimizer>(nfg, initial, gncParams); @@ -413,7 +413,7 @@ TEST(GncOptimizer, calculateWeightsTLS2) { // actual: GaussNewtonParams gnParams; GncParams gncParams(gnParams); - gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setLossType(GncLossType::TLS); gncParams.setInlierCostThreshold(0.49); // if inlier threshold is slightly below 0.5, then measurement is outlier auto gnc = GncOptimizer>(nfg, initial, gncParams); @@ -429,7 +429,7 @@ TEST(GncOptimizer, calculateWeightsTLS2) { // actual: GaussNewtonParams gnParams; GncParams gncParams(gnParams); - gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setLossType(GncLossType::TLS); gncParams.setInlierCostThreshold(0.5); // if inlier threshold is slightly below 0.5, then measurement is outlier auto gnc = GncOptimizer>(nfg, initial, gncParams); @@ -538,7 +538,7 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { { GncParams gncParams; gncParams.setKnownInliers(knownInliers); - gncParams.setLossType(GncParams::GncLossType::GM); + gncParams.setLossType(GncLossType::GM); //gncParams.setVerbosityGNC(GncParams::Verbosity::SUMMARY); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -555,7 +555,7 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { { GncParams gncParams; gncParams.setKnownInliers(knownInliers); - gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setLossType(GncLossType::TLS); // gncParams.setVerbosityGNC(GncParams::Verbosity::SUMMARY); auto gnc = GncOptimizer>(fg, initial, gncParams); @@ -574,7 +574,7 @@ TEST(GncOptimizer, optimizeWithKnownInliers) { // if we set the threshold large, they are all inliers GncParams gncParams; gncParams.setKnownInliers(knownInliers); - gncParams.setLossType(GncParams::GncLossType::TLS); + gncParams.setLossType(GncLossType::TLS); //gncParams.setVerbosityGNC(GncParams::Verbosity::VALUES); gncParams.setInlierCostThreshold(100.0); auto gnc = GncOptimizer>(fg, initial, From e75505a4d7e4fe49f7ccf5333a80bff37a5dd1b6 Mon Sep 17 00:00:00 2001 From: cttdev Date: Wed, 30 Dec 2020 01:41:03 -0800 Subject: [PATCH 194/261] Adding BearingFactor3D to the wrapper definition. --- gtsam/gtsam.i | 1 + matlab/+gtsam/Contents.m | 1 + 2 files changed, 2 insertions(+) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index 69b8bfebf..d3a4973ed 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -2599,6 +2599,7 @@ virtual class BearingFactor : gtsam::NoiseModelFactor { }; typedef gtsam::BearingFactor BearingFactor2D; +typedef gtsam::BearingFactor BearingFactor3D; typedef gtsam::BearingFactor BearingFactorPose2; #include diff --git a/matlab/+gtsam/Contents.m b/matlab/+gtsam/Contents.m index 035e7e509..fb6d3081e 100644 --- a/matlab/+gtsam/Contents.m +++ b/matlab/+gtsam/Contents.m @@ -99,6 +99,7 @@ % %% SLAM and SFM % BearingFactor2D - class BearingFactor2D, see Doxygen page for details +% BearingFactor3D - class BearingFactor3D, see Doxygen page for details % BearingRangeFactor2D - class BearingRangeFactor2D, see Doxygen page for details % BetweenFactorLieMatrix - class BetweenFactorLieMatrix, see Doxygen page for details % BetweenFactorLieScalar - class BetweenFactorLieScalar, see Doxygen page for details From 248eec8e41dc191db511fd7d6c7a5d7367b4f084 Mon Sep 17 00:00:00 2001 From: lcarlone Date: Wed, 30 Dec 2020 14:13:40 -0500 Subject: [PATCH 195/261] addressed final comments by Frank --- gtsam/nonlinear/GncOptimizer.h | 35 ++++++++++------------------------ gtsam/nonlinear/GncParams.h | 9 +++++++++ 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/gtsam/nonlinear/GncOptimizer.h b/gtsam/nonlinear/GncOptimizer.h index cfabf0ab6..cd0b4c81a 100644 --- a/gtsam/nonlinear/GncOptimizer.h +++ b/gtsam/nonlinear/GncOptimizer.h @@ -57,39 +57,25 @@ class GncOptimizer { if (graph[i]) { NoiseModelFactor::shared_ptr factor = boost::dynamic_pointer_cast< NoiseModelFactor>(graph[i]); - noiseModel::Robust::shared_ptr robust = boost::dynamic_pointer_cast< + auto robust = boost::dynamic_pointer_cast< noiseModel::Robust>(factor->noiseModel()); - if (robust) { // if the factor has a robust loss, we have to change it: - SharedNoiseModel gaussianNoise = robust->noise(); - NoiseModelFactor::shared_ptr gaussianFactor = factor - ->cloneWithNewNoiseModel(gaussianNoise); - nfg_[i] = gaussianFactor; - } else { // else we directly push it back - nfg_[i] = factor; - } + // if the factor has a robust loss, we remove the robust loss + nfg_[i] = robust ? factor-> cloneWithNewNoiseModel(robust->noise()) : factor; } } } /// Access a copy of the internal factor graph. - NonlinearFactorGraph getFactors() const { - return NonlinearFactorGraph(nfg_); - } + const NonlinearFactorGraph& getFactors() const { return nfg_; } /// Access a copy of the internal values. - Values getState() const { - return Values(state_); - } + const Values& getState() const { return state_; } /// Access a copy of the parameters. - GncParameters getParams() const { - return GncParameters(params_); - } + const GncParameters& getParams() const { return params_;} /// Access a copy of the GNC weights. - Vector getWeights() const { - return weights_; - } + const Vector& getWeights() const { return weights_;} /// Compute optimal solution using graduated non-convexity. Values optimize() { @@ -279,15 +265,14 @@ class GncOptimizer { newGraph.resize(nfg_.size()); for (size_t i = 0; i < nfg_.size(); i++) { if (nfg_[i]) { - NoiseModelFactor::shared_ptr factor = boost::dynamic_pointer_cast< + auto factor = boost::dynamic_pointer_cast< NoiseModelFactor>(nfg_[i]); - noiseModel::Gaussian::shared_ptr noiseModel = + auto noiseModel = boost::dynamic_pointer_cast( factor->noiseModel()); if (noiseModel) { Matrix newInfo = weights[i] * noiseModel->information(); - SharedNoiseModel newNoiseModel = noiseModel::Gaussian::Information( - newInfo); + auto newNoiseModel = noiseModel::Gaussian::Information(newInfo); newGraph[i] = factor->cloneWithNewNoiseModel(newNoiseModel); } else { throw std::runtime_error( diff --git a/gtsam/nonlinear/GncParams.h b/gtsam/nonlinear/GncParams.h index 5f130ddf2..0388a7fd1 100644 --- a/gtsam/nonlinear/GncParams.h +++ b/gtsam/nonlinear/GncParams.h @@ -77,6 +77,7 @@ class GncParams { void setLossType(const GncLossType type) { lossType = type; } + /// Set the maximum number of iterations in GNC (changing the max nr of iters might lead to less accurate solutions and is not recommended). void setMaxIterations(const size_t maxIter) { std::cout @@ -84,6 +85,7 @@ class GncParams { << std::endl; maxIterations = maxIter; } + /** Set the maximum weighted residual error for an inlier. For a factor in the form f(x) = 0.5 * || r(x) ||^2_Omega, * the inlier threshold is the largest value of f(x) for the corresponding measurement to be considered an inlier. * In other words, an inlier at x is such that 0.5 * || r(x) ||^2_Omega <= barcSq. @@ -93,22 +95,27 @@ class GncParams { void setInlierCostThreshold(const double inth) { barcSq = inth; } + /// Set the graduated non-convexity step: at each GNC iteration, mu is updated as mu <- mu * muStep. void setMuStep(const double step) { muStep = step; } + /// Set the maximum relative difference in mu values to stop iterating. void setRelativeCostTol(double value) { relativeCostTol = value; } + /// Set the maximum difference between the weights and their rounding in {0,1} to stop iterating. void setWeightsTol(double value) { weightsTol = value; } + /// Set the verbosity level. void setVerbosityGNC(const Verbosity value) { verbosity = value; } + /** (Optional) Provide a vector of measurements that must be considered inliers. The enties in the vector * corresponds to the slots in the factor graph. For instance, if you have a nonlinear factor graph nfg, * and you provide knownIn = {0, 2, 15}, GNC will not apply outlier rejection to nfg[0], nfg[2], and nfg[15]. @@ -119,6 +126,7 @@ class GncParams { for (size_t i = 0; i < knownIn.size(); i++) knownInliers.push_back(knownIn[i]); } + /// Equals. bool equals(const GncParams& other, double tol = 1e-9) const { return baseOptimizerParams.equals(other.baseOptimizerParams) @@ -127,6 +135,7 @@ class GncParams { && std::fabs(muStep - other.muStep) <= tol && verbosity == other.verbosity && knownInliers == other.knownInliers; } + /// Print. void print(const std::string& str) const { std::cout << str << "\n"; From bac74dbde5206422cbb4fae379285f7dcc158aa3 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 31 Dec 2020 13:21:24 -0500 Subject: [PATCH 196/261] Pose3 interpolateRt method (#647) * Pose3 interpolate() which correctly interpolates between poses * Pose3 template specialization for interpolate * added easy-to-verify test for Pose3 interpolate * added new Pose3 interpolateRt function, updated tests * update documentation of interpolateRt * update docs and tests --- gtsam/geometry/Pose3.h | 19 +++++++++++++++++++ gtsam/geometry/tests/testPose3.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/gtsam/geometry/Pose3.h b/gtsam/geometry/Pose3.h index 990ffdfe2..4c8973996 100644 --- a/gtsam/geometry/Pose3.h +++ b/gtsam/geometry/Pose3.h @@ -112,6 +112,25 @@ public: return Pose3(R_ * T.R_, t_ + R_ * T.t_); } + /** + * Interpolate between two poses via individual rotation and translation + * interpolation. + * + * The default "interpolate" method defined in Lie.h minimizes the geodesic + * distance on the manifold, leading to a screw motion interpolation in + * Cartesian space, which might not be what is expected. + * In contrast, this method executes a straight line interpolation for the + * translation, while still using interpolate (aka "slerp") for the rotational + * component. This might be more intuitive in many applications. + * + * @param T End point of interpolation. + * @param t A value in [0, 1]. + */ + Pose3 interpolateRt(const Pose3& T, double t) const { + return Pose3(interpolate(R_, T.R_, t), + interpolate(t_, T.t_, t)); + } + /// @} /// @name Lie Group /// @{ diff --git a/gtsam/geometry/tests/testPose3.cpp b/gtsam/geometry/tests/testPose3.cpp index 6de2c0a33..594d15c91 100644 --- a/gtsam/geometry/tests/testPose3.cpp +++ b/gtsam/geometry/tests/testPose3.cpp @@ -1016,6 +1016,33 @@ TEST(Pose3, TransformCovariance6) { TEST(Pose3, interpolate) { EXPECT(assert_equal(T2, interpolate(T2,T3, 0.0))); EXPECT(assert_equal(T3, interpolate(T2,T3, 1.0))); + + // Trivial example: start at origin and move to (1, 0, 0) while rotating pi/2 + // about z-axis. + Pose3 start; + Pose3 end(Rot3::Rz(M_PI_2), Point3(1, 0, 0)); + // This interpolation is easy to calculate by hand. + double t = 0.5; + Pose3 expected0(Rot3::Rz(M_PI_4), Point3(0.5, 0, 0)); + EXPECT(assert_equal(expected0, start.interpolateRt(end, t))); + + // Example from Peter Corke + // https://robotacademy.net.au/lesson/interpolating-pose-in-3d/ + t = 0.0759; // corresponds to the 10th element when calling `ctraj` in + // the video + Pose3 O; + Pose3 F(Rot3::Roll(0.6).compose(Rot3::Pitch(0.8)).compose(Rot3::Yaw(1.4)), + Point3(1, 2, 3)); + + // The expected answer matches the result presented in the video. + Pose3 expected1(interpolate(O.rotation(), F.rotation(), t), + interpolate(O.translation(), F.translation(), t)); + EXPECT(assert_equal(expected1, O.interpolateRt(F, t))); + + // Non-trivial interpolation, translation value taken from output. + Pose3 expected2(interpolate(T2.rotation(), T3.rotation(), t), + interpolate(T2.translation(), T3.translation(), t)); + EXPECT(assert_equal(expected2, T2.interpolateRt(T3, t))); } /* ************************************************************************* */ From b5db391e776f1112cc404f4d86ce2be11e3fe76c Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Fri, 1 Jan 2021 21:09:42 +0530 Subject: [PATCH 197/261] adding serialization and other functions to enable testing --- gtsam/slam/dataset.h | 111 ++++++++++++++---- gtsam/slam/tests/testSerializationDataset.cpp | 44 +++++++ 2 files changed, 129 insertions(+), 26 deletions(-) create mode 100644 gtsam/slam/tests/testSerializationDataset.cpp diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index 93bd2b2ee..a6b81eab1 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -30,7 +30,9 @@ #include #include #include +#include +#include #include #include #include // for pair @@ -243,6 +245,25 @@ struct SfmTrack { void add_measurement(size_t idx, const gtsam::Point2& m) { measurements.emplace_back(idx, m); } + + template + void serialize(ARCHIVE & ar, const unsigned int /*version*/) { + ar & p; + ar & r; + ar & g; + ar & b; + ar & measurements; + ar & siftIndices; + } + + /// assert equality up to a tolerance + bool equals(const SfmTrack &sfmTrack, double tol = 1e-9) const { + return true; + } + + // inline bool SfmTrack::operator == (const SfmTrack& rhs) const{ + // return p==rhs.p; + // } }; @@ -250,32 +271,70 @@ struct SfmTrack { typedef PinholeCamera SfmCamera; /// Define the structure for SfM data -struct SfmData { - std::vector cameras; ///< Set of cameras - std::vector tracks; ///< Sparse set of points - size_t number_cameras() const { - return cameras.size(); - } - /// The number of reconstructed 3D points - size_t number_tracks() const { - return tracks.size(); - } - /// The camera pose at frame index `idx` - SfmCamera camera(size_t idx) const { - return cameras[idx]; - } - /// The track formed by series of landmark measurements - SfmTrack track(size_t idx) const { - return tracks[idx]; - } - /// Add a track to SfmData - void add_track(const SfmTrack& t) { - tracks.push_back(t); - } - /// Add a camera to SfmData - void add_camera(const SfmCamera& cam){ - cameras.push_back(cam); - } +class GTSAM_EXPORT SfmData { + public: + std::vector cameras; ///< Set of cameras + std::vector tracks; ///< Sparse set of points + size_t number_cameras() const { + return cameras.size(); + } + /// The number of reconstructed 3D points + size_t number_tracks() const { + return tracks.size(); + } + /// The camera pose at frame index `idx` + SfmCamera camera(size_t idx) const { + return cameras[idx]; + } + /// The track formed by series of landmark measurements + SfmTrack track(size_t idx) const { + return tracks[idx]; + } + /// Add a track to SfmData + void add_track(const SfmTrack& t) { + tracks.push_back(t); + } + /// Add a camera to SfmData + void add_camera(const SfmCamera& cam){ + cameras.push_back(cam); + } + + /// @} + /// @name Testable + /// @{ + + /// assert equality up to a tolerance + bool equals(const SfmData &sfmData, double tol = 1e-9) const { + // check number of cameras and tracks + if (number_cameras() != sfmData.number_cameras() || number_tracks() != sfmData.number_tracks()){ + return false; + } + + // check each camera + for(size_t cam_idx = 0; cam_idx < number_cameras(); cam_idx++){ + if(!camera(cam_idx).equals(sfmData.camera(cam_idx), tol)){ + return false; + } + } + + return true; + } + + /// print + void print(const std::string& s = "") const; + + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int /*version*/) { + // ar & cameras; + // ar & tracks; + } + + // inline bool SfmData::operator == (const SfmData& rhs) const{ + // return cameras==rhs.cameras && tracks==rhs.tracks; + // } }; /** diff --git a/gtsam/slam/tests/testSerializationDataset.cpp b/gtsam/slam/tests/testSerializationDataset.cpp new file mode 100644 index 000000000..38749cb48 --- /dev/null +++ b/gtsam/slam/tests/testSerializationDataset.cpp @@ -0,0 +1,44 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file testSerializationDataset.cpp + * @brief serialization tests for dataset.cpp + * @author Ayush Baid + * @date Jan 1, 2021 + */ + +#include + +#include + +#include +#include + +using namespace std; +using namespace gtsam; +using namespace gtsam::serializationTestHelpers; + +/* ************************************************************************* */ +TEST(dataSet, sfmDataSerialization){ + // Test the serialization of SfmData + const string filename = findExampleDataFile("dubrovnik-3-7-pre"); + SfmData mydata; + CHECK(readBAL(filename, mydata)); + + EXPECT(equalsObj(mydata)); + // EXPECT(equalsXML(mydata)); + // EXPECT(equalsBinary(mydata)); +} + +/* ************************************************************************* */ +int main() { TestResult tr; return TestRegistry::runAllTests(tr); } +/* ************************************************************************* */ \ No newline at end of file From df4419b6093bfcc9beb8c9073dc7d8fbef691ce1 Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Sat, 2 Jan 2021 17:28:22 +0530 Subject: [PATCH 198/261] adding track serialization and testable trait --- gtsam/slam/dataset.h | 55 +++++++++++++++++-- gtsam/slam/tests/testSerializationDataset.cpp | 18 +++++- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index a6b81eab1..89cd1f71b 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -29,8 +29,9 @@ #include #include #include -#include #include +#include + #include #include @@ -224,7 +225,7 @@ struct SfmTrack { float r, g, b; ///< RGB color of the 3D point std::vector measurements; ///< The 2D image projections (id,(u,v)) std::vector siftIndices; - + /// Total number of measurements in this track size_t number_measurements() const { return measurements.size(); @@ -245,7 +246,7 @@ struct SfmTrack { void add_measurement(size_t idx, const gtsam::Point2& m) { measurements.emplace_back(idx, m); } - + template void serialize(ARCHIVE & ar, const unsigned int /*version*/) { ar & p; @@ -258,14 +259,47 @@ struct SfmTrack { /// assert equality up to a tolerance bool equals(const SfmTrack &sfmTrack, double tol = 1e-9) const { + if(!p.isApprox(sfmTrack.p)){ + return false; + } + + // TODO: compare RGB values + + // compare size of vectors + if(number_measurements() != sfmTrack.number_measurements() || + siftIndices.size() != sfmTrack.siftIndices.size()){ + return false; + } + + // compare measurements (order sensitive) + for(size_t idx=0; idx +struct traits : public Testable { +}; + /// Define the structure for the camera poses typedef PinholeCamera SfmCamera; @@ -321,15 +355,18 @@ class GTSAM_EXPORT SfmData { } /// print - void print(const std::string& s = "") const; + void print(const std::string& s = "") const { + cout << "Number of cameras = " << number_cameras() << "\n"; + cout << "Number of tracks = " << number_tracks() << "\n"; + } private: /** Serialization function */ friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int /*version*/) { - // ar & cameras; - // ar & tracks; + ar & cameras; + ar & tracks; } // inline bool SfmData::operator == (const SfmData& rhs) const{ @@ -337,6 +374,12 @@ class GTSAM_EXPORT SfmData { // } }; +/* ************************************************************************* */ +/// traits +template<> +struct traits : public Testable { +}; + /** * @brief This function parses a bundler output file and stores the data into a * SfmData structure diff --git a/gtsam/slam/tests/testSerializationDataset.cpp b/gtsam/slam/tests/testSerializationDataset.cpp index 38749cb48..c6fed7b4f 100644 --- a/gtsam/slam/tests/testSerializationDataset.cpp +++ b/gtsam/slam/tests/testSerializationDataset.cpp @@ -18,8 +18,6 @@ #include -#include - #include #include @@ -39,6 +37,20 @@ TEST(dataSet, sfmDataSerialization){ // EXPECT(equalsBinary(mydata)); } +/* ************************************************************************* */ +TEST(dataSet, sfmTrackSerialization){ + // Test the serialization of SfmData + const string filename = findExampleDataFile("dubrovnik-3-7-pre"); + SfmData mydata; + CHECK(readBAL(filename, mydata)); + + SfmTrack track = mydata.track(0); + + EXPECT(equalsObj(track)); + // EXPECT(equalsXML(mydata)); + // EXPECT(equalsBinary(mydata)); +} + /* ************************************************************************* */ int main() { TestResult tr; return TestRegistry::runAllTests(tr); } -/* ************************************************************************* */ \ No newline at end of file +/* ************************************************************************* */ From 9d61e5bc4a6ed82cefb07b9791072b70d9596f52 Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Sat, 2 Jan 2021 20:40:29 +0530 Subject: [PATCH 199/261] improving formatting --- gtsam/slam/dataset.h | 154 ++++++++++++++++++++++++------------------- 1 file changed, 85 insertions(+), 69 deletions(-) diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index 89cd1f71b..8e275e766 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -247,6 +247,8 @@ struct SfmTrack { measurements.emplace_back(idx, m); } + /** Serialization function */ + friend class boost::serialization::access; template void serialize(ARCHIVE & ar, const unsigned int /*version*/) { ar & p; @@ -259,24 +261,40 @@ struct SfmTrack { /// assert equality up to a tolerance bool equals(const SfmTrack &sfmTrack, double tol = 1e-9) const { - if(!p.isApprox(sfmTrack.p)){ + // check the 3D point + if (!p.isApprox(sfmTrack.p)) { return false; } - // TODO: compare RGB values + // check the RGB values + if (r!=sfmTrack.r || g!=sfmTrack.g || b!=sfmTrack.b) { + return false; + } - // compare size of vectors - if(number_measurements() != sfmTrack.number_measurements() || - siftIndices.size() != sfmTrack.siftIndices.size()){ + // compare size of vectors for measurements and siftIndices + if (number_measurements() != sfmTrack.number_measurements() || + siftIndices.size() != sfmTrack.siftIndices.size()) { return false; } // compare measurements (order sensitive) - for(size_t idx=0; idx : public Testable { typedef PinholeCamera SfmCamera; /// Define the structure for SfM data -class GTSAM_EXPORT SfmData { - public: - std::vector cameras; ///< Set of cameras - std::vector tracks; ///< Sparse set of points - size_t number_cameras() const { - return cameras.size(); - } - /// The number of reconstructed 3D points - size_t number_tracks() const { - return tracks.size(); - } - /// The camera pose at frame index `idx` - SfmCamera camera(size_t idx) const { - return cameras[idx]; - } - /// The track formed by series of landmark measurements - SfmTrack track(size_t idx) const { - return tracks[idx]; - } - /// Add a track to SfmData - void add_track(const SfmTrack& t) { - tracks.push_back(t); - } - /// Add a camera to SfmData - void add_camera(const SfmCamera& cam){ - cameras.push_back(cam); +struct SfmData { + std::vector cameras; ///< Set of cameras + std::vector tracks; ///< Sparse set of points + size_t number_cameras() const { + return cameras.size(); + } + /// The number of reconstructed 3D points + size_t number_tracks() const { + return tracks.size(); + } + /// The camera pose at frame index `idx` + SfmCamera camera(size_t idx) const { + return cameras[idx]; + } + /// The track formed by series of landmark measurements + SfmTrack track(size_t idx) const { + return tracks[idx]; + } + /// Add a track to SfmData + void add_track(const SfmTrack& t) { + tracks.push_back(t); + } + /// Add a camera to SfmData + void add_camera(const SfmCamera& cam) { + cameras.push_back(cam); + } + + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int /*version*/) { + ar & cameras; + ar & tracks; + } + + /// @} + /// @name Testable + /// @{ + + /// assert equality up to a tolerance + bool equals(const SfmData &sfmData, double tol = 1e-9) const { + // check number of cameras and tracks + if (number_cameras() != sfmData.number_cameras() || + number_tracks() != sfmData.number_tracks()) { + return false; } - /// @} - /// @name Testable - /// @{ - - /// assert equality up to a tolerance - bool equals(const SfmData &sfmData, double tol = 1e-9) const { - // check number of cameras and tracks - if (number_cameras() != sfmData.number_cameras() || number_tracks() != sfmData.number_tracks()){ + // check each camera + for (size_t i = 0; i < number_cameras(); ++i) { + if (!camera(i).equals(sfmData.camera(i), tol)) { return false; } + } - // check each camera - for(size_t cam_idx = 0; cam_idx < number_cameras(); cam_idx++){ - if(!camera(cam_idx).equals(sfmData.camera(cam_idx), tol)){ - return false; - } + // check each track + for (size_t j = 0; j < number_tracks(); ++j) { + if (!track(j).equals(sfmData.track(j), tol)) { + return false; } - - return true; } - /// print - void print(const std::string& s = "") const { - cout << "Number of cameras = " << number_cameras() << "\n"; - cout << "Number of tracks = " << number_tracks() << "\n"; - } + return true; + } - private: - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(Archive & ar, const unsigned int /*version*/) { - ar & cameras; - ar & tracks; - } - - // inline bool SfmData::operator == (const SfmData& rhs) const{ - // return cameras==rhs.cameras && tracks==rhs.tracks; - // } + /// print + void print(const std::string& s = "") const { + cout << "Number of cameras = " << number_cameras() << "\n"; + cout << "Number of tracks = " << number_tracks() << "\n"; + } }; /* ************************************************************************* */ From f88b4565d727470af708e0a16262a05818cca142 Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Sat, 2 Jan 2021 21:21:43 +0530 Subject: [PATCH 200/261] fixing variable names and comments --- gtsam/slam/tests/testSerializationDataset.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gtsam/slam/tests/testSerializationDataset.cpp b/gtsam/slam/tests/testSerializationDataset.cpp index c6fed7b4f..a9fd9a259 100644 --- a/gtsam/slam/tests/testSerializationDataset.cpp +++ b/gtsam/slam/tests/testSerializationDataset.cpp @@ -39,7 +39,7 @@ TEST(dataSet, sfmDataSerialization){ /* ************************************************************************* */ TEST(dataSet, sfmTrackSerialization){ - // Test the serialization of SfmData + // Test the serialization of SfmTrack const string filename = findExampleDataFile("dubrovnik-3-7-pre"); SfmData mydata; CHECK(readBAL(filename, mydata)); @@ -47,8 +47,8 @@ TEST(dataSet, sfmTrackSerialization){ SfmTrack track = mydata.track(0); EXPECT(equalsObj(track)); - // EXPECT(equalsXML(mydata)); - // EXPECT(equalsBinary(mydata)); + // EXPECT(equalsXML(track)); + // EXPECT(equalsBinary(track)); } /* ************************************************************************* */ From c46e3dbee61faa3c192812b4dac1a3f0b291a173 Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Sat, 2 Jan 2021 21:25:41 +0530 Subject: [PATCH 201/261] adding serialization functions to wrapper --- gtsam/gtsam.i | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index d3a4973ed..efa740e02 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -2768,6 +2768,9 @@ class SfmTrack { pair measurement(size_t idx) const; pair siftIndex(size_t idx) const; void add_measurement(size_t idx, const gtsam::Point2& m); + + // enabling serialization functionality + void serialize() const; }; class SfmData { @@ -2778,6 +2781,9 @@ class SfmData { gtsam::SfmTrack track(size_t idx) const; void add_track(const gtsam::SfmTrack& t) ; void add_camera(const gtsam::SfmCamera& cam); + + // enabling serialization functionality + void serialize() const; }; gtsam::SfmData readBal(string filename); From b59f1bc573f5b82c4f9b2d8b82687adc9bd3beb8 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Sat, 2 Jan 2021 19:24:30 -0500 Subject: [PATCH 202/261] remove build upload since it can't be used downstream --- .github/workflows/build-linux.yml | 6 ------ .github/workflows/build-macos.yml | 6 ------ .github/workflows/build-windows.yml | 6 ------ 3 files changed, 18 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 32c3bd8aa..be1da35bb 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -83,9 +83,3 @@ jobs: if: runner.os == 'Linux' run: | bash .github/scripts/unix.sh -t - - name: Upload build directory - uses: actions/upload-artifact@v2 - if: matrix.build_type == 'Release' - with: - name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} - path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index cf1a474e3..69873980a 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -51,9 +51,3 @@ jobs: if: runner.os == 'macOS' run: | bash .github/scripts/unix.sh -t - - name: Upload build directory - uses: actions/upload-artifact@v2 - if: matrix.build_type == 'Release' - with: - name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} - path: ${{ github.workspace }}/build/ diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 7eb908c94..887d41972 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -76,9 +76,3 @@ jobs: cmake --build build --config ${{ matrix.build_type }} --target check.base cmake --build build --config ${{ matrix.build_type }} --target check.base_unstable cmake --build build --config ${{ matrix.build_type }} --target check.linear - - name: Upload build directory - uses: actions/upload-artifact@v2 - if: matrix.build_type == 'Release' - with: - name: gtsam-${{ matrix.name }}-${{ matrix.build_type }} - path: ${{ github.workspace }}/build/ From e0cda60b9b2303f6bbb0789b6fdae57b8cb0d99b Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Mon, 4 Jan 2021 00:02:21 +0530 Subject: [PATCH 203/261] fixing xml serialization issues --- gtsam/slam/dataset.h | 160 +++++++++--------- gtsam/slam/tests/testSerializationDataset.cpp | 12 +- 2 files changed, 86 insertions(+), 86 deletions(-) diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index 8e275e766..0156b3008 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -29,11 +29,10 @@ #include #include #include +#include #include #include - -#include #include #include #include // for pair @@ -218,94 +217,95 @@ typedef std::pair SfmMeasurement; typedef std::pair SiftIndex; /// Define the structure for the 3D points -struct SfmTrack { - SfmTrack(): p(0,0,0) {} - SfmTrack(const gtsam::Point3& pt) : p(pt) {} - Point3 p; ///< 3D position of the point - float r, g, b; ///< RGB color of the 3D point - std::vector measurements; ///< The 2D image projections (id,(u,v)) - std::vector siftIndices; +class GTSAM_EXPORT SfmTrack { + public: + SfmTrack(): p(0,0,0) {} + SfmTrack(const gtsam::Point3& pt) : p(pt) {} + Point3 p; ///< 3D position of the point + float r, g, b; ///< RGB color of the 3D point + std::vector measurements; ///< The 2D image projections (id,(u,v)) + std::vector siftIndices; - /// Total number of measurements in this track - size_t number_measurements() const { - return measurements.size(); - } - /// Get the measurement (camera index, Point2) at pose index `idx` - SfmMeasurement measurement(size_t idx) const { - return measurements[idx]; - } - /// Get the SIFT feature index corresponding to the measurement at `idx` - SiftIndex siftIndex(size_t idx) const { - return siftIndices[idx]; - } - /// Get 3D point - const Point3& point3() const { - return p; - } - /// Add measurement (camera_idx, Point2) to track - void add_measurement(size_t idx, const gtsam::Point2& m) { - measurements.emplace_back(idx, m); - } - - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int /*version*/) { - ar & p; - ar & r; - ar & g; - ar & b; - ar & measurements; - ar & siftIndices; - } - - /// assert equality up to a tolerance - bool equals(const SfmTrack &sfmTrack, double tol = 1e-9) const { - // check the 3D point - if (!p.isApprox(sfmTrack.p)) { - return false; + /// Total number of measurements in this track + size_t number_measurements() const { + return measurements.size(); + } + /// Get the measurement (camera index, Point2) at pose index `idx` + SfmMeasurement measurement(size_t idx) const { + return measurements[idx]; + } + /// Get the SIFT feature index corresponding to the measurement at `idx` + SiftIndex siftIndex(size_t idx) const { + return siftIndices[idx]; + } + /// Get 3D point + const Point3& point3() const { + return p; + } + /// Add measurement (camera_idx, Point2) to track + void add_measurement(size_t idx, const gtsam::Point2& m) { + measurements.emplace_back(idx, m); } - // check the RGB values - if (r!=sfmTrack.r || g!=sfmTrack.g || b!=sfmTrack.b) { - return false; + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int /*version*/) { + ar & BOOST_SERIALIZATION_NVP(p); + ar & BOOST_SERIALIZATION_NVP(r); + ar & BOOST_SERIALIZATION_NVP(g); + ar & BOOST_SERIALIZATION_NVP(b); + ar & BOOST_SERIALIZATION_NVP(measurements); + ar & BOOST_SERIALIZATION_NVP(siftIndices); } - // compare size of vectors for measurements and siftIndices - if (number_measurements() != sfmTrack.number_measurements() || - siftIndices.size() != sfmTrack.siftIndices.size()) { - return false; - } - - // compare measurements (order sensitive) - for (size_t idx = 0; idx < number_measurements(); ++idx) { - SfmMeasurement measurement = measurements[idx]; - SfmMeasurement otherMeasurement = sfmTrack.measurements[idx]; - - if (measurement.first != otherMeasurement.first || - !measurement.second.isApprox(otherMeasurement.second)) { + /// assert equality up to a tolerance + bool equals(const SfmTrack &sfmTrack, double tol = 1e-9) const { + // check the 3D point + if (!p.isApprox(sfmTrack.p)) { return false; } - } - // compare sift indices (order sensitive) - for (size_t idx = 0; idx < siftIndices.size(); ++idx) { - SiftIndex index = siftIndices[idx]; - SiftIndex otherIndex = sfmTrack.siftIndices[idx]; - - if (index.first != otherIndex.first || - index.second != otherIndex.second) { + // check the RGB values + if (r!=sfmTrack.r || g!=sfmTrack.g || b!=sfmTrack.b) { return false; } + + // compare size of vectors for measurements and siftIndices + if (number_measurements() != sfmTrack.number_measurements() || + siftIndices.size() != sfmTrack.siftIndices.size()) { + return false; + } + + // compare measurements (order sensitive) + for (size_t idx = 0; idx < number_measurements(); ++idx) { + SfmMeasurement measurement = measurements[idx]; + SfmMeasurement otherMeasurement = sfmTrack.measurements[idx]; + + if (measurement.first != otherMeasurement.first || + !measurement.second.isApprox(otherMeasurement.second)) { + return false; + } + } + + // compare sift indices (order sensitive) + for (size_t idx = 0; idx < siftIndices.size(); ++idx) { + SiftIndex index = siftIndices[idx]; + SiftIndex otherIndex = sfmTrack.siftIndices[idx]; + + if (index.first != otherIndex.first || + index.second != otherIndex.second) { + return false; + } + } + + return true; } - return true; - } - - /// print - void print(const std::string& s = "") const { - cout << "Track with " << measurements.size() << "measurements\n"; - } + /// print + void print(const std::string& s = "") const { + cout << "Track with " << measurements.size() << "measurements\n"; + } }; /* ************************************************************************* */ @@ -350,8 +350,8 @@ struct SfmData { friend class boost::serialization::access; template void serialize(Archive & ar, const unsigned int /*version*/) { - ar & cameras; - ar & tracks; + ar & BOOST_SERIALIZATION_NVP(cameras); + ar & BOOST_SERIALIZATION_NVP(tracks); } /// @} diff --git a/gtsam/slam/tests/testSerializationDataset.cpp b/gtsam/slam/tests/testSerializationDataset.cpp index a9fd9a259..db23ce64d 100644 --- a/gtsam/slam/tests/testSerializationDataset.cpp +++ b/gtsam/slam/tests/testSerializationDataset.cpp @@ -26,19 +26,19 @@ using namespace gtsam; using namespace gtsam::serializationTestHelpers; /* ************************************************************************* */ -TEST(dataSet, sfmDataSerialization){ +TEST(dataSet, sfmDataSerialization) { // Test the serialization of SfmData const string filename = findExampleDataFile("dubrovnik-3-7-pre"); SfmData mydata; CHECK(readBAL(filename, mydata)); EXPECT(equalsObj(mydata)); - // EXPECT(equalsXML(mydata)); - // EXPECT(equalsBinary(mydata)); + EXPECT(equalsXML(mydata)); + EXPECT(equalsBinary(mydata)); } /* ************************************************************************* */ -TEST(dataSet, sfmTrackSerialization){ +TEST(dataSet, sfmTrackSerialization) { // Test the serialization of SfmTrack const string filename = findExampleDataFile("dubrovnik-3-7-pre"); SfmData mydata; @@ -47,8 +47,8 @@ TEST(dataSet, sfmTrackSerialization){ SfmTrack track = mydata.track(0); EXPECT(equalsObj(track)); - // EXPECT(equalsXML(track)); - // EXPECT(equalsBinary(track)); + EXPECT(equalsXML(track)); + EXPECT(equalsBinary(track)); } /* ************************************************************************* */ From 2e8692105a6bf7aad74509ba613a6d4f33c47537 Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Mon, 4 Jan 2021 00:07:20 +0530 Subject: [PATCH 204/261] reverting SfmTrack to struct --- gtsam/slam/dataset.h | 157 +++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 79 deletions(-) diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index 0156b3008..a0f54b6d3 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -217,95 +217,94 @@ typedef std::pair SfmMeasurement; typedef std::pair SiftIndex; /// Define the structure for the 3D points -class GTSAM_EXPORT SfmTrack { - public: - SfmTrack(): p(0,0,0) {} - SfmTrack(const gtsam::Point3& pt) : p(pt) {} - Point3 p; ///< 3D position of the point - float r, g, b; ///< RGB color of the 3D point - std::vector measurements; ///< The 2D image projections (id,(u,v)) - std::vector siftIndices; +struct SfmTrack { + SfmTrack(): p(0,0,0) {} + SfmTrack(const gtsam::Point3& pt) : p(pt) {} + Point3 p; ///< 3D position of the point + float r, g, b; ///< RGB color of the 3D point + std::vector measurements; ///< The 2D image projections (id,(u,v)) + std::vector siftIndices; - /// Total number of measurements in this track - size_t number_measurements() const { - return measurements.size(); - } - /// Get the measurement (camera index, Point2) at pose index `idx` - SfmMeasurement measurement(size_t idx) const { - return measurements[idx]; - } - /// Get the SIFT feature index corresponding to the measurement at `idx` - SiftIndex siftIndex(size_t idx) const { - return siftIndices[idx]; - } - /// Get 3D point - const Point3& point3() const { - return p; - } - /// Add measurement (camera_idx, Point2) to track - void add_measurement(size_t idx, const gtsam::Point2& m) { - measurements.emplace_back(idx, m); + /// Total number of measurements in this track + size_t number_measurements() const { + return measurements.size(); + } + /// Get the measurement (camera index, Point2) at pose index `idx` + SfmMeasurement measurement(size_t idx) const { + return measurements[idx]; + } + /// Get the SIFT feature index corresponding to the measurement at `idx` + SiftIndex siftIndex(size_t idx) const { + return siftIndices[idx]; + } + /// Get 3D point + const Point3& point3() const { + return p; + } + /// Add measurement (camera_idx, Point2) to track + void add_measurement(size_t idx, const gtsam::Point2& m) { + measurements.emplace_back(idx, m); + } + + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int /*version*/) { + ar & BOOST_SERIALIZATION_NVP(p); + ar & BOOST_SERIALIZATION_NVP(r); + ar & BOOST_SERIALIZATION_NVP(g); + ar & BOOST_SERIALIZATION_NVP(b); + ar & BOOST_SERIALIZATION_NVP(measurements); + ar & BOOST_SERIALIZATION_NVP(siftIndices); + } + + /// assert equality up to a tolerance + bool equals(const SfmTrack &sfmTrack, double tol = 1e-9) const { + // check the 3D point + if (!p.isApprox(sfmTrack.p)) { + return false; } - /** Serialization function */ - friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int /*version*/) { - ar & BOOST_SERIALIZATION_NVP(p); - ar & BOOST_SERIALIZATION_NVP(r); - ar & BOOST_SERIALIZATION_NVP(g); - ar & BOOST_SERIALIZATION_NVP(b); - ar & BOOST_SERIALIZATION_NVP(measurements); - ar & BOOST_SERIALIZATION_NVP(siftIndices); + // check the RGB values + if (r!=sfmTrack.r || g!=sfmTrack.g || b!=sfmTrack.b) { + return false; } - /// assert equality up to a tolerance - bool equals(const SfmTrack &sfmTrack, double tol = 1e-9) const { - // check the 3D point - if (!p.isApprox(sfmTrack.p)) { + // compare size of vectors for measurements and siftIndices + if (number_measurements() != sfmTrack.number_measurements() || + siftIndices.size() != sfmTrack.siftIndices.size()) { + return false; + } + + // compare measurements (order sensitive) + for (size_t idx = 0; idx < number_measurements(); ++idx) { + SfmMeasurement measurement = measurements[idx]; + SfmMeasurement otherMeasurement = sfmTrack.measurements[idx]; + + if (measurement.first != otherMeasurement.first || + !measurement.second.isApprox(otherMeasurement.second)) { return false; } - - // check the RGB values - if (r!=sfmTrack.r || g!=sfmTrack.g || b!=sfmTrack.b) { - return false; - } - - // compare size of vectors for measurements and siftIndices - if (number_measurements() != sfmTrack.number_measurements() || - siftIndices.size() != sfmTrack.siftIndices.size()) { - return false; - } - - // compare measurements (order sensitive) - for (size_t idx = 0; idx < number_measurements(); ++idx) { - SfmMeasurement measurement = measurements[idx]; - SfmMeasurement otherMeasurement = sfmTrack.measurements[idx]; - - if (measurement.first != otherMeasurement.first || - !measurement.second.isApprox(otherMeasurement.second)) { - return false; - } - } - - // compare sift indices (order sensitive) - for (size_t idx = 0; idx < siftIndices.size(); ++idx) { - SiftIndex index = siftIndices[idx]; - SiftIndex otherIndex = sfmTrack.siftIndices[idx]; - - if (index.first != otherIndex.first || - index.second != otherIndex.second) { - return false; - } - } - - return true; } - /// print - void print(const std::string& s = "") const { - cout << "Track with " << measurements.size() << "measurements\n"; + // compare sift indices (order sensitive) + for (size_t idx = 0; idx < siftIndices.size(); ++idx) { + SiftIndex index = siftIndices[idx]; + SiftIndex otherIndex = sfmTrack.siftIndices[idx]; + + if (index.first != otherIndex.first || + index.second != otherIndex.second) { + return false; + } } + + return true; + } + + /// print + void print(const std::string& s = "") const { + cout << "Track with " << measurements.size() << "measurements\n"; + } }; /* ************************************************************************* */ From 0ce1db2d89781efb633903ec25568aacef4f5c13 Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Mon, 4 Jan 2021 00:18:04 +0530 Subject: [PATCH 205/261] printing out the 3d point --- gtsam/slam/dataset.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index a0f54b6d3..d96c11167 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -303,7 +303,8 @@ struct SfmTrack { /// print void print(const std::string& s = "") const { - cout << "Track with " << measurements.size() << "measurements\n"; + cout << "Track with " << measurements.size(); + cout << " measurements of point " << p << "\n"; } }; From 915b4398beaf328f90bb1967879781e723c5eafe Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Mon, 4 Jan 2021 22:03:41 +0530 Subject: [PATCH 206/261] adding equals function to wrapper --- gtsam/gtsam.i | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index efa740e02..e1e11964f 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -2771,6 +2771,9 @@ class SfmTrack { // enabling serialization functionality void serialize() const; + + // enabling function to compare objects + bool equals(const gtsam::SfmTrack& expected, double tol) const; }; class SfmData { @@ -2784,6 +2787,9 @@ class SfmData { // enabling serialization functionality void serialize() const; + + // enabling function to compare objects + bool equals(const gtsam::SfmData& expected, double tol) const; }; gtsam::SfmData readBal(string filename); From 1d417546eca4c5103938b8a919350b56d6e9e819 Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Mon, 4 Jan 2021 22:09:55 +0530 Subject: [PATCH 207/261] adding inline comment for round trip --- gtsam/slam/tests/testSerializationDataset.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gtsam/slam/tests/testSerializationDataset.cpp b/gtsam/slam/tests/testSerializationDataset.cpp index db23ce64d..6ef82f07f 100644 --- a/gtsam/slam/tests/testSerializationDataset.cpp +++ b/gtsam/slam/tests/testSerializationDataset.cpp @@ -32,6 +32,7 @@ TEST(dataSet, sfmDataSerialization) { SfmData mydata; CHECK(readBAL(filename, mydata)); + // round-trip equality check on serialization and subsequent deserialization EXPECT(equalsObj(mydata)); EXPECT(equalsXML(mydata)); EXPECT(equalsBinary(mydata)); @@ -46,6 +47,7 @@ TEST(dataSet, sfmTrackSerialization) { SfmTrack track = mydata.track(0); + // round-trip equality check on serialization and subsequent deserialization EXPECT(equalsObj(track)); EXPECT(equalsXML(track)); EXPECT(equalsBinary(track)); From 5333396671a1499b7535b87c37c6d40a85cd1072 Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Mon, 4 Jan 2021 22:59:48 +0530 Subject: [PATCH 208/261] Adding serialization support to be used for GT-SFM (#650) * adding serialization and other functions to enable testing * adding track serialization and testable trait * improving formatting * fixing variable names and comments * adding serialization functions to wrapper * fixing xml serialization issues * reverting SfmTrack to struct * printing out the 3d point * adding equals function to wrapper * adding inline comment for round trip --- gtsam/gtsam.i | 12 ++ gtsam/slam/dataset.h | 124 +++++++++++++++++- gtsam/slam/tests/testSerializationDataset.cpp | 58 ++++++++ 3 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 gtsam/slam/tests/testSerializationDataset.cpp diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index d3a4973ed..e1e11964f 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -2768,6 +2768,12 @@ class SfmTrack { pair measurement(size_t idx) const; pair siftIndex(size_t idx) const; void add_measurement(size_t idx, const gtsam::Point2& m); + + // enabling serialization functionality + void serialize() const; + + // enabling function to compare objects + bool equals(const gtsam::SfmTrack& expected, double tol) const; }; class SfmData { @@ -2778,6 +2784,12 @@ class SfmData { gtsam::SfmTrack track(size_t idx) const; void add_track(const gtsam::SfmTrack& t) ; void add_camera(const gtsam::SfmCamera& cam); + + // enabling serialization functionality + void serialize() const; + + // enabling function to compare objects + bool equals(const gtsam::SfmData& expected, double tol) const; }; gtsam::SfmData readBal(string filename); diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index 93bd2b2ee..d96c11167 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include @@ -222,7 +224,7 @@ struct SfmTrack { float r, g, b; ///< RGB color of the 3D point std::vector measurements; ///< The 2D image projections (id,(u,v)) std::vector siftIndices; - + /// Total number of measurements in this track size_t number_measurements() const { return measurements.size(); @@ -243,6 +245,73 @@ struct SfmTrack { void add_measurement(size_t idx, const gtsam::Point2& m) { measurements.emplace_back(idx, m); } + + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE & ar, const unsigned int /*version*/) { + ar & BOOST_SERIALIZATION_NVP(p); + ar & BOOST_SERIALIZATION_NVP(r); + ar & BOOST_SERIALIZATION_NVP(g); + ar & BOOST_SERIALIZATION_NVP(b); + ar & BOOST_SERIALIZATION_NVP(measurements); + ar & BOOST_SERIALIZATION_NVP(siftIndices); + } + + /// assert equality up to a tolerance + bool equals(const SfmTrack &sfmTrack, double tol = 1e-9) const { + // check the 3D point + if (!p.isApprox(sfmTrack.p)) { + return false; + } + + // check the RGB values + if (r!=sfmTrack.r || g!=sfmTrack.g || b!=sfmTrack.b) { + return false; + } + + // compare size of vectors for measurements and siftIndices + if (number_measurements() != sfmTrack.number_measurements() || + siftIndices.size() != sfmTrack.siftIndices.size()) { + return false; + } + + // compare measurements (order sensitive) + for (size_t idx = 0; idx < number_measurements(); ++idx) { + SfmMeasurement measurement = measurements[idx]; + SfmMeasurement otherMeasurement = sfmTrack.measurements[idx]; + + if (measurement.first != otherMeasurement.first || + !measurement.second.isApprox(otherMeasurement.second)) { + return false; + } + } + + // compare sift indices (order sensitive) + for (size_t idx = 0; idx < siftIndices.size(); ++idx) { + SiftIndex index = siftIndices[idx]; + SiftIndex otherIndex = sfmTrack.siftIndices[idx]; + + if (index.first != otherIndex.first || + index.second != otherIndex.second) { + return false; + } + } + + return true; + } + + /// print + void print(const std::string& s = "") const { + cout << "Track with " << measurements.size(); + cout << " measurements of point " << p << "\n"; + } +}; + +/* ************************************************************************* */ +/// traits +template<> +struct traits : public Testable { }; @@ -269,13 +338,62 @@ struct SfmData { return tracks[idx]; } /// Add a track to SfmData - void add_track(const SfmTrack& t) { + void add_track(const SfmTrack& t) { tracks.push_back(t); } /// Add a camera to SfmData - void add_camera(const SfmCamera& cam){ + void add_camera(const SfmCamera& cam) { cameras.push_back(cam); } + + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(Archive & ar, const unsigned int /*version*/) { + ar & BOOST_SERIALIZATION_NVP(cameras); + ar & BOOST_SERIALIZATION_NVP(tracks); + } + + /// @} + /// @name Testable + /// @{ + + /// assert equality up to a tolerance + bool equals(const SfmData &sfmData, double tol = 1e-9) const { + // check number of cameras and tracks + if (number_cameras() != sfmData.number_cameras() || + number_tracks() != sfmData.number_tracks()) { + return false; + } + + // check each camera + for (size_t i = 0; i < number_cameras(); ++i) { + if (!camera(i).equals(sfmData.camera(i), tol)) { + return false; + } + } + + // check each track + for (size_t j = 0; j < number_tracks(); ++j) { + if (!track(j).equals(sfmData.track(j), tol)) { + return false; + } + } + + return true; + } + + /// print + void print(const std::string& s = "") const { + cout << "Number of cameras = " << number_cameras() << "\n"; + cout << "Number of tracks = " << number_tracks() << "\n"; + } +}; + +/* ************************************************************************* */ +/// traits +template<> +struct traits : public Testable { }; /** diff --git a/gtsam/slam/tests/testSerializationDataset.cpp b/gtsam/slam/tests/testSerializationDataset.cpp new file mode 100644 index 000000000..6ef82f07f --- /dev/null +++ b/gtsam/slam/tests/testSerializationDataset.cpp @@ -0,0 +1,58 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file testSerializationDataset.cpp + * @brief serialization tests for dataset.cpp + * @author Ayush Baid + * @date Jan 1, 2021 + */ + +#include + +#include +#include + +using namespace std; +using namespace gtsam; +using namespace gtsam::serializationTestHelpers; + +/* ************************************************************************* */ +TEST(dataSet, sfmDataSerialization) { + // Test the serialization of SfmData + const string filename = findExampleDataFile("dubrovnik-3-7-pre"); + SfmData mydata; + CHECK(readBAL(filename, mydata)); + + // round-trip equality check on serialization and subsequent deserialization + EXPECT(equalsObj(mydata)); + EXPECT(equalsXML(mydata)); + EXPECT(equalsBinary(mydata)); +} + +/* ************************************************************************* */ +TEST(dataSet, sfmTrackSerialization) { + // Test the serialization of SfmTrack + const string filename = findExampleDataFile("dubrovnik-3-7-pre"); + SfmData mydata; + CHECK(readBAL(filename, mydata)); + + SfmTrack track = mydata.track(0); + + // round-trip equality check on serialization and subsequent deserialization + EXPECT(equalsObj(track)); + EXPECT(equalsXML(track)); + EXPECT(equalsBinary(track)); +} + +/* ************************************************************************* */ +int main() { TestResult tr; return TestRegistry::runAllTests(tr); } +/* ************************************************************************* */ From d4a4e1a826acd0d5afe4dbb581716f9a28744cba Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 4 Jan 2021 12:41:11 -0500 Subject: [PATCH 209/261] documentation for compiling on windows --- INSTALL.md | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 3dbc3a850..d570e6daa 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -70,7 +70,34 @@ execute commands as follows for an out-of-source build: This will build the library and unit tests, run all of the unit tests, and then install the library itself. -## CMake Configuration Options and Details +# Windows Installation + +This section details how to build and install GTSAM using Visual Studio. + +### Prerequisites + +- Visual Studio with C++ CMake tools for Windows +- Python >= 3.6 (we prefer Anaconda) + +### Steps + +1. Open Visual Studio. +2. Select `Open a local folder` and select the GTSAM source directory. +3. Go to `Project -> CMake Settings`. + - (Optional) Set `Configuration name`. + - (Optional) Set `Configuration type`. + - Set the `Toolset` to `msvc_x64_x64`. If you know what toolset you require, then skip this step. + - Update the `Build root` to `${projectDir}\build\${name}`. + - You can optionally create a new configuration for a `Release` build. + - Set the necessary CMake variables for your use case. + - Click on `Show advanved settings`. + - For `CMake generator`, select a version which matches `Visual Studio Win64`, e.g. `Visual Studio 16 2019 Win64`. + - Save. +4. Click on `Project -> Generate Cache`. This will generate the CMake build files (as seen in the Output window). +5. The last step will generate a `GTSAM.sln` file in the `build` directory. At this point, GTSAM can be used as a regular Visual Studio project. + + +# CMake Configuration Options and Details GTSAM has a number of options that can be configured, which is best done with one of the following: @@ -78,7 +105,7 @@ one of the following: - ccmake the curses GUI for cmake - cmake-gui a real GUI for cmake -### Important Options: +## Important Options: #### CMAKE_BUILD_TYPE We support several build configurations for GTSAM (case insensitive) From b14b3b75e253b2685bda5e025c66c3d3b9b56628 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 4 Jan 2021 12:45:05 -0500 Subject: [PATCH 210/261] improvements to windows doc --- INSTALL.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index d570e6daa..1fddf4df0 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -72,12 +72,12 @@ execute commands as follows for an out-of-source build: # Windows Installation -This section details how to build and install GTSAM using Visual Studio. +This section details how to build a GTSAM `.sln` file using Visual Studio. ### Prerequisites - Visual Studio with C++ CMake tools for Windows -- Python >= 3.6 (we prefer Anaconda) +- All the other pre-requisites listed above. ### Steps @@ -90,9 +90,9 @@ This section details how to build and install GTSAM using Visual Studio. - Update the `Build root` to `${projectDir}\build\${name}`. - You can optionally create a new configuration for a `Release` build. - Set the necessary CMake variables for your use case. - - Click on `Show advanved settings`. + - Click on `Show advanced settings`. - For `CMake generator`, select a version which matches `Visual Studio Win64`, e.g. `Visual Studio 16 2019 Win64`. - - Save. + - Save the settings (Ctrl + S). 4. Click on `Project -> Generate Cache`. This will generate the CMake build files (as seen in the Output window). 5. The last step will generate a `GTSAM.sln` file in the `build` directory. At this point, GTSAM can be used as a regular Visual Studio project. From 7cc7232a990fab581506a79d15c6108b491d33f0 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 4 Jan 2021 13:11:36 -0500 Subject: [PATCH 211/261] Squashed 'wrap/' changes from dfa624e77..09f8bbf71 09f8bbf71 Merge pull request #25 from borglab/fix/function-name 0dbfb6c13 fix function name to be the correct one f69f8b01f Merge pull request #24 from borglab/fix/pip 6519a6627 use pip install to overcome superuser issues b11ecf4e8 Merge pull request #23 from borglab/fix/remove-pip-args 813030108 remove pip-args since we are using setup.py 498d233e0 Merge pull request #22 from borglab/fix/package-install 846212ac3 set correct flags for installing gtwrap package 62161cd20 Merge pull request #21 from borglab/feature/script-vars 93be1d9f8 set script variables and move pybind11 loading so gtwrap can be used under gtsam 8770e3c7e Merge pull request #20 from borglab/fix/pybind-include 8c3c83618 proper placement of pybind11 include a9ad4f504 Merge pull request #19 from borglab/feature/package 99d8a12c7 added more documentation 4cbec1579 change to macro so we don't have to deal with function scopes b83e405b8 updates to completely install the package 38a64b3de new scripts which will be installed to bin directory bf9646235 Merge pull request #18 from borglab/fix/cmake-min c7c280099 Consistent cmake minimum required 42df58f62 Merge pull request #17 from borglab/fix/cleanup e580b282d version bump 4ccd66fa5 More finegrained handling of Python version 6476fd710 Merge pull request #16 from borglab/feature/better-find-python 8ac1296a0 use setup.py to install dependencies e9ac473be install dependencies and support versions of CMake<3.12 cf272dbd2 Merge pull request #15 from borglab/feature/utils ffc9cc4f7 new utils to reduce boilerplate 20e8e8b7a Merge pull request #11 from borglab/feature/package 04b844bd6 use new version of FindPython and be consistent 3f9d7a32a Merge pull request #13 from borglab/add_license c791075a6 Add LICENSE 517b67c46 correct working directory for setup.py 1b22b47ae move matlab.h to root directory 37b407214 Proper source directory path for use in other projects 61696dd5d configure PybindWrap within the cmake directory 1b91fc9af add config file so we can use find_package a1e6f4f53 small typo da9f351be updated README and housekeeping 64b8f78d5 files needed to allow for packaging bddda7f54 package structure git-subtree-dir: wrap git-subtree-split: 09f8bbf7172ba8b1bd3d2484795743f16e1a5893 --- .gitignore | 3 + CMakeLists.txt | 55 +++++++++++ LICENSE | 13 +++ README.md | 66 ++++++------- cmake/GtwrapUtils.cmake | 74 +++++++++++++++ cmake/PybindWrap.cmake | 35 +------ cmake/gtwrapConfig.cmake | 27 ++++++ gtwrap/__init__.py | 0 .../interface_parser.py | 0 matlab_wrapper.py => gtwrap/matlab_wrapper.py | 58 +----------- pybind_wrapper.py => gtwrap/pybind_wrapper.py | 78 +--------------- .../template_instantiator.py | 2 +- scripts/matlab_wrap.py | 68 ++++++++++++++ scripts/pybind_wrap.py | 93 +++++++++++++++++++ setup.py | 36 +++++++ tests/interface_parser_test.py | 2 +- tests/test_matlab_wrapper.py | 12 +-- tests/test_pybind_wrapper.py | 6 +- 18 files changed, 424 insertions(+), 204 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 cmake/GtwrapUtils.cmake create mode 100644 cmake/gtwrapConfig.cmake create mode 100644 gtwrap/__init__.py rename interface_parser.py => gtwrap/interface_parser.py (100%) rename matlab_wrapper.py => gtwrap/matlab_wrapper.py (96%) rename pybind_wrapper.py => gtwrap/pybind_wrapper.py (84%) rename template_instantiator.py => gtwrap/template_instantiator.py (99%) create mode 100644 scripts/matlab_wrap.py create mode 100644 scripts/pybind_wrap.py create mode 100644 setup.py diff --git a/.gitignore b/.gitignore index 38da6d9d1..4fd660b95 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ __pycache__/ .vscode/ +*build* +*dist* +*.egg-info diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..4c89ab96e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required(VERSION 3.9) + +# Set the project name and version +project(GTwrap VERSION 1.0) + +# ############################################################################## +# General configuration + +set(WRAP_PYTHON_VERSION + "Default" + CACHE STRING "The Python version to use for wrapping") + +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/GtwrapUtils.cmake) +gtwrap_get_python_version(${WRAP_PYTHON_VERSION}) + +# ############################################################################## +# Install the CMake file to be used by other projects +if(WIN32 AND NOT CYGWIN) + set(SCRIPT_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/CMake") +else() + set(SCRIPT_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/cmake") +endif() + +# Install scripts to the standard CMake script directory. +install(FILES cmake/gtwrapConfig.cmake cmake/PybindWrap.cmake + cmake/GtwrapUtils.cmake + DESTINATION "${SCRIPT_INSTALL_DIR}/gtwrap") + +# Install wrapping scripts as binaries to `CMAKE_INSTALL_PREFIX/bin` so they can +# be invoked for wrapping. +install(PROGRAMS scripts/pybind_wrap.py scripts/matlab_wrap.py TYPE BIN) + +# Install pybind11 directory to `CMAKE_INSTALL_PREFIX/lib/pybind11` This will +# allow the gtwrapConfig.cmake file to load it later. +install(DIRECTORY pybind11 TYPE LIB) + +# ############################################################################## +# Install the Python package +find_package( + Python ${WRAP_PYTHON_VERSION} + COMPONENTS Interpreter + REQUIRED) + +# Detect virtualenv and set Pip args accordingly +# https://www.scivision.dev/cmake-install-python-package/ +if(DEFINED ENV{VIRTUAL_ENV} OR DEFINED ENV{CONDA_PREFIX}) + set(_pip_args) +else() + set(_pip_args "--user") +endif() +#TODO add correct flags for virtualenv + +# Finally install the gtwrap python package. +execute_process(COMMAND ${Python_EXECUTABLE} -m pip install . ${_pip_args} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..406b266b7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2010, Georgia Tech Research Corporation +Atlanta, Georgia 30332-0415 +All Rights Reserved + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md index f72c3f652..347cca601 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,40 @@ It was designed to be more general than just wrapping GTSAM. For notes on creati 1. This library uses `pybind11`, which is included as a subdirectory in GTSAM. 2. The `interface_parser.py` in this library uses `pyparsing` to parse the interface file `gtsam.h`. Please install it first in your current Python environment before attempting the build. - ``` - python3 -m pip install pyparsing - ``` + +``` +python3 -m pip install pyparsing +``` + +## Getting Started + +Clone this repository to your local machine and perform the standard CMake install: + +```sh +mkdir build && cd build +cmake .. +make install # use sudo if needed +``` + +Using `wrap` in your project is straightforward from here. In you `CMakeLists.txt` file, you just need to add the following: + +```cmake +include(PybindWrap) + +pybind_wrap(${PROJECT_NAME}_py # target + ${PROJECT_SOURCE_DIR}/cpp/${PROJECT_NAME}.h # interface header file + "${PROJECT_NAME}.cpp" # the generated cpp + "${PROJECT_NAME}" # module_name + "gtsam" # top namespace in the cpp file + "${ignore}" # ignore classes + ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.tpl + ${PROJECT_NAME} # libs + "${PROJECT_NAME}" # dependencies + ON # use boost + ) +``` + +For more information, please follow our [tutorial](https://github.com/borglab/gtsam-project-python). ## GTSAM Python wrapper @@ -45,32 +76,3 @@ It was designed to be more general than just wrapping GTSAM. For notes on creati python setup.py install ``` - NOTE: It's a good idea to create a virtual environment otherwise it will be installed in your system Python's site-packages. - - -## Old GTSAM Wrapper - -*Outdated note from the original wrap.* - -TODO: Update this. - -It was designed to be more general than just wrapping GTSAM, but a small amount of GTSAM specific code exists in `matlab.h`, the include file that is included by the `mex` files. The GTSAM-specific functionality consists primarily of handling of Eigen Matrix and Vector classes. - -For notes on creating a wrap interface, see `gtsam.h` for what features can be wrapped into a toolbox, as well as the current state of the toolbox for GTSAM. For more technical details on the interface, please read comments in `matlab.h` - -Some good things to know: - -OBJECT CREATION - -- Classes are created by special constructors, e.g., `new_GaussianFactorGraph_.cpp`. - These constructors are called from the MATLAB class `@GaussianFactorGraph`. - `new_GaussianFactorGraph_` calls wrap_constructed in `matlab.h`, see documentation there - -METHOD (AND CONSTRUCTOR) ARGUMENTS - -- Simple argument types of methods, such as "double", will be converted in the - `mex` wrappers by calling unwrap, defined in matlab.h -- Vector and Matrix arguments are normally passed by reference in GTSAM, but - in `gtsam.h` you need to pretend they are passed by value, to trigger the - generation of the correct conversion routines `unwrap` and `unwrap` -- passing classes as arguments works, provided they are passed by reference. - This triggers a call to unwrap_shared_ptr diff --git a/cmake/GtwrapUtils.cmake b/cmake/GtwrapUtils.cmake new file mode 100644 index 000000000..9c6b141a0 --- /dev/null +++ b/cmake/GtwrapUtils.cmake @@ -0,0 +1,74 @@ +# Utilities to help with wrapping. + +macro(get_python_version) + if(${CMAKE_VERSION} VERSION_LESS "3.12.0") + # Use older version of cmake's find_python + find_package(PythonInterp) + + if(NOT ${PYTHONINTERP_FOUND}) + message( + FATAL_ERROR + "Cannot find Python interpreter. Please install Python >= 3.6.") + endif() + + find_package(PythonLibs ${PYTHON_VERSION_STRING}) + + set(Python_VERSION_MAJOR + ${PYTHON_VERSION_MAJOR} + PARENT_SCOPE) + set(Python_VERSION_MINOR + ${PYTHON_VERSION_MINOR} + PARENT_SCOPE) + set(Python_VERSION_PATCH + ${PYTHON_VERSION_PATCH} + PARENT_SCOPE) + set(Python_EXECUTABLE + ${PYTHON_EXECUTABLE} + PARENT_SCOPE) + + else() + # Get info about the Python interpreter + # https://cmake.org/cmake/help/latest/module/FindPython.html#module:FindPython + find_package(Python COMPONENTS Interpreter Development) + + if(NOT ${Python_FOUND}) + message( + FATAL_ERROR + "Cannot find Python interpreter. Please install Python>=3.6.") + endif() + + endif() +endmacro() + +# Set the Python version for the wrapper and set the paths to the executable and +# include/library directories. WRAP_PYTHON_VERSION can be "Default" or a +# specific major.minor version. +macro(gtwrap_get_python_version WRAP_PYTHON_VERSION) + # Unset these cached variables to avoid surprises when the python in the + # current environment are different from the cached! + unset(Python_EXECUTABLE CACHE) + unset(Python_INCLUDE_DIRS CACHE) + unset(Python_VERSION_MAJOR CACHE) + unset(Python_VERSION_MINOR CACHE) + unset(Python_VERSION_PATCH CACHE) + + # Allow override + if(${WRAP_PYTHON_VERSION} STREQUAL "Default") + # Check for Python3 or Python2 in order + get_python_version() + + # Set the wrapper python version + set(WRAP_PYTHON_VERSION + "${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}.${Python_VERSION_PATCH}" + CACHE STRING "The version of Python to build the wrappers against." + FORCE) + + else() + # Find the Python that best matches the python version specified. + find_package( + Python ${WRAP_PYTHON_VERSION} + COMPONENTS Interpreter Development + EXACT REQUIRED) + endif() + +endmacro() diff --git a/cmake/PybindWrap.cmake b/cmake/PybindWrap.cmake index 85f956d50..a94dbc5cc 100644 --- a/cmake/PybindWrap.cmake +++ b/cmake/PybindWrap.cmake @@ -1,32 +1,5 @@ -# Unset these cached variables to avoid surprises when the python in the current -# environment are different from the cached! -unset(PYTHON_EXECUTABLE CACHE) -unset(PYTHON_INCLUDE_DIR CACHE) -unset(PYTHON_MAJOR_VERSION CACHE) - -# Allow override from command line -if(NOT DEFINED WRAP_USE_CUSTOM_PYTHON_LIBRARY) - if(WRAP_PYTHON_VERSION STREQUAL "Default") - find_package(PythonInterp REQUIRED) - find_package(PythonLibs REQUIRED) - else() - find_package(PythonInterp - ${WRAP_PYTHON_VERSION} - EXACT - REQUIRED) - find_package(PythonLibs - ${WRAP_PYTHON_VERSION} - EXACT - REQUIRED) - endif() -endif() - -set(DIR_OF_WRAP_PYBIND_CMAKE ${CMAKE_CURRENT_LIST_DIR}) - set(PYBIND11_PYTHON_VERSION ${WRAP_PYTHON_VERSION}) -add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../pybind11 pybind11) - # User-friendly Pybind11 wrapping and installing function. # Builds a Pybind11 module from the provided interface_header. # For example, for the interface header gtsam.h, this will @@ -65,7 +38,7 @@ function(pybind_wrap add_custom_command(OUTPUT ${generated_cpp} COMMAND ${PYTHON_EXECUTABLE} - ${CMAKE_SOURCE_DIR}/wrap/pybind_wrapper.py + ${PYBIND_WRAP_SCRIPT} --src ${interface_header} --out @@ -89,9 +62,9 @@ function(pybind_wrap # ~~~ add_custom_command(OUTPUT ${generated_cpp} DEPENDS ${interface_header} - ${CMAKE_SOURCE_DIR}/wrap/interface_parser.py - ${CMAKE_SOURCE_DIR}/wrap/pybind_wrapper.py - ${CMAKE_SOURCE_DIR}/wrap/template_instantiator.py + # @GTWRAP_SOURCE_DIR@/gtwrap/interface_parser.py + # @GTWRAP_SOURCE_DIR@/gtwrap/pybind_wrapper.py + # @GTWRAP_SOURCE_DIR@/gtwrap/template_instantiator.py APPEND) pybind11_add_module(${target} ${generated_cpp}) diff --git a/cmake/gtwrapConfig.cmake b/cmake/gtwrapConfig.cmake new file mode 100644 index 000000000..48bd4772d --- /dev/null +++ b/cmake/gtwrapConfig.cmake @@ -0,0 +1,27 @@ +# This config file modifies CMAKE_MODULE_PATH so that the wrap cmake files may +# be included This file also allows the use of `find_package(gtwrap)` in CMake. + +set(GTWRAP_DIR "${CMAKE_CURRENT_LIST_DIR}") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}") + +if(WIN32 AND NOT CYGWIN) + set(SCRIPT_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/CMake") +else() + set(SCRIPT_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/cmake") +endif() + +# Standard includes +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) +include(CMakeDependentOption) + +# Load all the CMake scripts from the standard location +include(${SCRIPT_INSTALL_DIR}/gtwrap/PybindWrap.cmake) +include(${SCRIPT_INSTALL_DIR}/gtwrap/GtwrapUtils.cmake) + +# Set the variables for the wrapping scripts to be used in the build. +set(PYBIND_WRAP_SCRIPT "${CMAKE_INSTALL_FULL_BINDIR}/pybind_wrap.py") +set(MATLAB_WRAP_SCRIPT "${CMAKE_INSTALL_FULL_BINDIR}/matlab_wrap.py") + +# Load the pybind11 code from the library installation path +add_subdirectory(${CMAKE_INSTALL_FULL_LIBDIR}/pybind11 pybind11) diff --git a/gtwrap/__init__.py b/gtwrap/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/interface_parser.py b/gtwrap/interface_parser.py similarity index 100% rename from interface_parser.py rename to gtwrap/interface_parser.py diff --git a/matlab_wrapper.py b/gtwrap/matlab_wrapper.py similarity index 96% rename from matlab_wrapper.py rename to gtwrap/matlab_wrapper.py index 1b6b75a49..355913ba7 100755 --- a/matlab_wrapper.py +++ b/gtwrap/matlab_wrapper.py @@ -2,8 +2,8 @@ import os import argparse import textwrap -import interface_parser as parser -import template_instantiator as instantiator +import gtwrap.interface_parser as parser +import gtwrap.template_instantiator as instantiator from functools import reduce from functools import partial @@ -1666,7 +1666,7 @@ class MatlabWrapper(object): return self.content -def _generate_content(cc_content, path, verbose=False): +def generate_content(cc_content, path, verbose=False): """Generate files and folders from matlab wrapper content. Keyword arguments: @@ -1698,7 +1698,7 @@ def _generate_content(cc_content, path, verbose=False): for sub_content in c: import sys _debug("sub object: {}".format(sub_content[1][0][0])) - _generate_content(sub_content[1], path_to_folder) + generate_content(sub_content[1], path_to_folder) elif type(c[1]) == list: path_to_folder = path + '/' + c[0] @@ -1726,53 +1726,3 @@ def _generate_content(cc_content, path, verbose=False): with open(path_to_file, 'w') as f: f.write(c[1]) - - -if __name__ == "__main__": - arg_parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) - arg_parser.add_argument("--src", type=str, required=True, help="Input interface .h file.") - arg_parser.add_argument("--module_name", type=str, required=True, help="Name of the C++ class being wrapped.") - arg_parser.add_argument("--out", type=str, required=True, help="Name of the output folder.") - arg_parser.add_argument("--top_module_namespaces", - type=str, - default="", - help="C++ namespace for the top module, e.g. `ns1::ns2::ns3`. " - "Only the content within this namespace and its sub-namespaces " - "will be wrapped. The content of this namespace will be available at " - "the top module level, and its sub-namespaces' in the submodules.\n" - "For example, `import ` gives you access to a Python " - "`.Class` of the corresponding C++ `ns1::ns2::ns3::Class`" - ", and `from import ns4` gives you access to a Python " - "`ns4.Class` of the C++ `ns1::ns2::ns3::ns4::Class`. ") - arg_parser.add_argument("--ignore", - nargs='*', - type=str, - help="A space-separated list of classes to ignore. " - "Class names must include their full namespaces.") - args = arg_parser.parse_args() - - top_module_namespaces = args.top_module_namespaces.split("::") - if top_module_namespaces[0]: - top_module_namespaces = [''] + top_module_namespaces - - with open(args.src, 'r') as f: - content = f.read() - - if not os.path.exists(args.src): - os.mkdir(args.src) - - module = parser.Module.parseString(content) - - instantiator.instantiate_namespace_inplace(module) - - import sys - - print("Ignoring classes: {}".format(args.ignore), file=sys.stderr) - wrapper = MatlabWrapper(module=module, - module_name=args.module_name, - top_module_namespace=top_module_namespaces, - ignore_classes=args.ignore) - - cc_content = wrapper.wrap() - - _generate_content(cc_content, args.out) diff --git a/pybind_wrapper.py b/gtwrap/pybind_wrapper.py similarity index 84% rename from pybind_wrapper.py rename to gtwrap/pybind_wrapper.py index 326d9be52..c0e88e37a 100755 --- a/pybind_wrapper.py +++ b/gtwrap/pybind_wrapper.py @@ -9,12 +9,11 @@ See LICENSE for the license information Code generator for wrapping a C++ module with Pybind11 Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar and Frank Dellaert """ -import argparse import re import textwrap -import interface_parser as parser -import template_instantiator as instantiator +import gtwrap.interface_parser as parser +import gtwrap.template_instantiator as instantiator class PybindWrapper(object): @@ -319,76 +318,3 @@ class PybindWrapper(object): wrapped_namespace=wrapped_namespace, boost_class_export=boost_class_export, ) - - -def main(): - arg_parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) - arg_parser.add_argument("--src", type=str, required=True, help="Input interface .h file") - arg_parser.add_argument( - "--module_name", - type=str, - required=True, - help="Name of the Python module to be generated and " - "used in the Python `import` statement.", - ) - arg_parser.add_argument( - "--out", - type=str, - required=True, - help="Name of the output pybind .cc file", - ) - arg_parser.add_argument( - "--use-boost", - action="store_true", - help="using boost's shared_ptr instead of std's", - ) - arg_parser.add_argument( - "--top_module_namespaces", - type=str, - default="", - help="C++ namespace for the top module, e.g. `ns1::ns2::ns3`. " - "Only the content within this namespace and its sub-namespaces " - "will be wrapped. The content of this namespace will be available at " - "the top module level, and its sub-namespaces' in the submodules.\n" - "For example, `import ` gives you access to a Python " - "`.Class` of the corresponding C++ `ns1::ns2::ns3::Class`" - "and `from import ns4` gives you access to a Python " - "`ns4.Class` of the C++ `ns1::ns2::ns3::ns4::Class`. ", - ) - arg_parser.add_argument( - "--ignore", - nargs='*', - type=str, - help="A space-separated list of classes to ignore. " - "Class names must include their full namespaces.", - ) - arg_parser.add_argument("--template", type=str, help="The module template file") - args = arg_parser.parse_args() - - top_module_namespaces = args.top_module_namespaces.split("::") - if top_module_namespaces[0]: - top_module_namespaces = [''] + top_module_namespaces - - with open(args.src, "r") as f: - content = f.read() - module = parser.Module.parseString(content) - instantiator.instantiate_namespace_inplace(module) - - with open(args.template, "r") as f: - template_content = f.read() - wrapper = PybindWrapper( - module=module, - module_name=args.module_name, - use_boost=args.use_boost, - top_module_namespaces=top_module_namespaces, - ignore_classes=args.ignore, - module_template=template_content, - ) - - cc_content = wrapper.wrap() - with open(args.out, "w") as f: - f.write(cc_content) - - -if __name__ == "__main__": - main() diff --git a/template_instantiator.py b/gtwrap/template_instantiator.py similarity index 99% rename from template_instantiator.py rename to gtwrap/template_instantiator.py index 3d98e9699..6032beac4 100644 --- a/template_instantiator.py +++ b/gtwrap/template_instantiator.py @@ -1,4 +1,4 @@ -import interface_parser as parser +import gtwrap.interface_parser as parser def instantiate_type(ctype, template_typenames, instantiations, cpp_typename, instantiated_class=None): diff --git a/scripts/matlab_wrap.py b/scripts/matlab_wrap.py new file mode 100644 index 000000000..232e93490 --- /dev/null +++ b/scripts/matlab_wrap.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +""" +Helper script to wrap C++ to Matlab. +This script is installed via CMake to the user's binary directory +and invoked during the wrapping by CMake. +""" + +import argparse +import os + +import gtwrap.interface_parser as parser +import gtwrap.template_instantiator as instantiator +from gtwrap.matlab_wrapper import MatlabWrapper, generate_content + +if __name__ == "__main__": + arg_parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + arg_parser.add_argument("--src", type=str, required=True, + help="Input interface .h file.") + arg_parser.add_argument("--module_name", type=str, required=True, + help="Name of the C++ class being wrapped.") + arg_parser.add_argument("--out", type=str, required=True, + help="Name of the output folder.") + arg_parser.add_argument( + "--top_module_namespaces", + type=str, + default="", + help="C++ namespace for the top module, e.g. `ns1::ns2::ns3`. " + "Only the content within this namespace and its sub-namespaces " + "will be wrapped. The content of this namespace will be available at " + "the top module level, and its sub-namespaces' in the submodules.\n" + "For example, `import ` gives you access to a Python " + "`.Class` of the corresponding C++ `ns1::ns2::ns3::Class`" + ", and `from import ns4` gives you access to a Python " + "`ns4.Class` of the C++ `ns1::ns2::ns3::ns4::Class`. ") + arg_parser.add_argument("--ignore", + nargs='*', + type=str, + help="A space-separated list of classes to ignore. " + "Class names must include their full namespaces.") + args = arg_parser.parse_args() + + top_module_namespaces = args.top_module_namespaces.split("::") + if top_module_namespaces[0]: + top_module_namespaces = [''] + top_module_namespaces + + with open(args.src, 'r') as f: + content = f.read() + + if not os.path.exists(args.src): + os.mkdir(args.src) + + module = parser.Module.parseString(content) + + instantiator.instantiate_namespace_inplace(module) + + import sys + + print("Ignoring classes: {}".format(args.ignore), file=sys.stderr) + wrapper = MatlabWrapper(module=module, + module_name=args.module_name, + top_module_namespace=top_module_namespaces, + ignore_classes=args.ignore) + + cc_content = wrapper.wrap() + + generate_content(cc_content, args.out) diff --git a/scripts/pybind_wrap.py b/scripts/pybind_wrap.py new file mode 100644 index 000000000..e641cfaaf --- /dev/null +++ b/scripts/pybind_wrap.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 + +""" +Helper script to wrap C++ to Python with Pybind. +This script is installed via CMake to the user's binary directory +and invoked during the wrapping by CMake. +""" + +import argparse + +import gtwrap.interface_parser as parser +import gtwrap.template_instantiator as instantiator +from gtwrap.pybind_wrapper import PybindWrapper + + +def main(): + """Main runner.""" + arg_parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + arg_parser.add_argument( + "--src", + type=str, + required=True, + help="Input interface .i/.h file") + arg_parser.add_argument( + "--module_name", + type=str, + required=True, + help="Name of the Python module to be generated and " + "used in the Python `import` statement.", + ) + arg_parser.add_argument( + "--out", + type=str, + required=True, + help="Name of the output pybind .cc file", + ) + arg_parser.add_argument( + "--use-boost", + action="store_true", + help="using boost's shared_ptr instead of std's", + ) + arg_parser.add_argument( + "--top_module_namespaces", + type=str, + default="", + help="C++ namespace for the top module, e.g. `ns1::ns2::ns3`. " + "Only the content within this namespace and its sub-namespaces " + "will be wrapped. The content of this namespace will be available at " + "the top module level, and its sub-namespaces' in the submodules.\n" + "For example, `import ` gives you access to a Python " + "`.Class` of the corresponding C++ `ns1::ns2::ns3::Class`" + "and `from import ns4` gives you access to a Python " + "`ns4.Class` of the C++ `ns1::ns2::ns3::ns4::Class`. ", + ) + arg_parser.add_argument( + "--ignore", + nargs='*', + type=str, + help="A space-separated list of classes to ignore. " + "Class names must include their full namespaces.", + ) + arg_parser.add_argument("--template", type=str, + help="The module template file") + args = arg_parser.parse_args() + + top_module_namespaces = args.top_module_namespaces.split("::") + if top_module_namespaces[0]: + top_module_namespaces = [''] + top_module_namespaces + + with open(args.src, "r") as f: + content = f.read() + module = parser.Module.parseString(content) + instantiator.instantiate_namespace_inplace(module) + + with open(args.template, "r") as f: + template_content = f.read() + wrapper = PybindWrapper( + module=module, + module_name=args.module_name, + use_boost=args.use_boost, + top_module_namespaces=top_module_namespaces, + ignore_classes=args.ignore, + module_template=template_content, + ) + + cc_content = wrapper.wrap() + with open(args.out, "w") as f: + f.write(cc_content) + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py new file mode 100644 index 000000000..10fc53d34 --- /dev/null +++ b/setup.py @@ -0,0 +1,36 @@ +"""Setup file for the GTwrap package""" + +try: + from setuptools import find_packages, setup +except ImportError: + from distutils.core import find_packages, setup + +packages = find_packages() + +setup( + name='gtwrap', + description='Library to wrap C++ with Python and Matlab', + version='1.1.0', + author="Frank Dellaert et. al.", + author_email="dellaert@gatech.edu", + license='BSD', + keywords="wrap, bindings, cpp, python", + long_description=open("README.md").read(), + long_description_content_type="text/markdown", + python_requires=">=3.6", + # https://pypi.org/classifiers + classifiers=[ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Education', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'Operating System :: MacOS', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX', + 'Programming Language :: Python :: 3', + 'Topic :: Software Development :: Libraries' + ], + packages=packages, + platforms="any", + install_requires=open("requirements.txt").readlines(), +) diff --git a/tests/interface_parser_test.py b/tests/interface_parser_test.py index 3e989a519..3197b4214 100644 --- a/tests/interface_parser_test.py +++ b/tests/interface_parser_test.py @@ -4,7 +4,7 @@ import unittest import sys, os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -from interface_parser import * +from gtwrap.interface_parser import * class TestPyparsing(unittest.TestCase): diff --git a/tests/test_matlab_wrapper.py b/tests/test_matlab_wrapper.py index 18dc49baf..258f2da8f 100644 --- a/tests/test_matlab_wrapper.py +++ b/tests/test_matlab_wrapper.py @@ -10,9 +10,9 @@ import filecmp sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -import template_instantiator as instantiator -import interface_parser as parser -from matlab_wrapper import MatlabWrapper +import gtwrap.template_instantiator as instantiator +import gtwrap.interface_parser as parser +from gtwrap.matlab_wrapper import MatlabWrapper class TestWrap(unittest.TestCase): @@ -20,7 +20,7 @@ class TestWrap(unittest.TestCase): MATLAB_TEST_DIR = TEST_DIR + "expected-matlab/" MATLAB_ACTUAL_DIR = TEST_DIR + "actual-matlab/" - def _generate_content(self, cc_content, path=''): + def generate_content(self, cc_content, path=''): """Generate files and folders from matlab wrapper content. Keyword arguments: @@ -48,7 +48,7 @@ class TestWrap(unittest.TestCase): for sub_content in c: import sys print("sub object: {}".format(sub_content[1][0][0]), file=sys.stderr) - self._generate_content(sub_content[1], path_to_folder) + self.generate_content(sub_content[1], path_to_folder) elif type(c[1]) == list: path_to_folder = path + '/' + c[0] @@ -104,7 +104,7 @@ class TestWrap(unittest.TestCase): cc_content = wrapper.wrap() - self._generate_content(cc_content) + self.generate_content(cc_content) def compare_and_diff(file): output = self.MATLAB_ACTUAL_DIR + file diff --git a/tests/test_pybind_wrapper.py b/tests/test_pybind_wrapper.py index 80032cbcd..d859cc99f 100644 --- a/tests/test_pybind_wrapper.py +++ b/tests/test_pybind_wrapper.py @@ -14,9 +14,9 @@ import os.path as path sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.append(os.path.normpath(os.path.abspath(os.path.join(__file__, '../../../build/wrap')))) -from pybind_wrapper import PybindWrapper -import interface_parser as parser -import template_instantiator as instantiator +from gtwrap.pybind_wrapper import PybindWrapper +import gtwrap.interface_parser as parser +import gtwrap.template_instantiator as instantiator sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) From 3a80b38a9a5c2a86b62b3a14d657cc173d9624a7 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 4 Jan 2021 13:13:01 -0500 Subject: [PATCH 212/261] updates to Cmake to use the new wrap package --- CMakeLists.txt | 5 ++ cmake/GtsamMatlabWrap.cmake | 8 ++- cmake/HandlePython.cmake | 50 ++++++++++++---- python/CMakeLists.txt | 115 +++++++++++++++++++++--------------- 4 files changed, 116 insertions(+), 62 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 35c487fd3..0c39089c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,11 @@ add_subdirectory(CppUnitLite) # This is the new wrapper if(GTSAM_BUILD_PYTHON) + # Need to set this for the wrap package so we don't use the default value. + set(WRAP_PYTHON_VERSION ${GTSAM_PYTHON_VERSION} + CACHE STRING "The Python version to use for wrapping") + + add_subdirectory(wrap) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/wrap/cmake") add_subdirectory(python) endif() diff --git a/cmake/GtsamMatlabWrap.cmake b/cmake/GtsamMatlabWrap.cmake index b17618f49..b76f96a4e 100644 --- a/cmake/GtsamMatlabWrap.cmake +++ b/cmake/GtsamMatlabWrap.cmake @@ -240,12 +240,16 @@ function(wrap_library_internal interfaceHeader linkLibraries extraIncludeDirs ex set(_ignore gtsam::Point2 gtsam::Point3) - add_custom_command( + + # set the matlab wrapping script variable + set(MATLAB_WRAP_SCRIPT "${GTSAM_SOURCE_DIR}/wrap/scripts/matlab_wrap.py") + + add_custom_command( OUTPUT ${generated_cpp_file} DEPENDS ${interfaceHeader} ${module_library_target} ${otherLibraryTargets} ${otherSourcesAndObjects} COMMAND ${PYTHON_EXECUTABLE} - ${CMAKE_SOURCE_DIR}/wrap/matlab_wrapper.py + ${MATLAB_WRAP_SCRIPT} --src ${interfaceHeader} --module_name ${moduleName} --out ${generated_files_path} diff --git a/cmake/HandlePython.cmake b/cmake/HandlePython.cmake index e5d55b451..0c24824bc 100644 --- a/cmake/HandlePython.cmake +++ b/cmake/HandlePython.cmake @@ -1,22 +1,48 @@ # Set Python version if either Python or MATLAB wrapper is requested. if(GTSAM_BUILD_PYTHON OR GTSAM_INSTALL_MATLAB_TOOLBOX) - if(${GTSAM_PYTHON_VERSION} STREQUAL "Default") - # Get info about the Python3 interpreter - # https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3 - find_package(Python3 COMPONENTS Interpreter Development) + if(${GTSAM_PYTHON_VERSION} STREQUAL "Default") - if(NOT ${Python3_FOUND}) - message(FATAL_ERROR "Cannot find Python3 interpreter. Please install Python >= 3.6.") - endif() + if(${CMAKE_VERSION} VERSION_LESS "3.12.0") + # Use older version of cmake's find_python + find_package(PythonInterp) + + if(NOT ${PYTHONINTERP_FOUND}) + message( + FATAL_ERROR + "Cannot find Python interpreter. Please install Python >= 3.6.") + endif() + + find_package(PythonLibs ${PYTHON_VERSION_STRING}) + + set(Python_VERSION_MAJOR ${PYTHON_VERSION_MAJOR}) + set(Python_VERSION_MINOR ${PYTHON_VERSION_MINOR}) + set(Python_EXECUTABLE ${PYTHON_EXECUTABLE}) + + else() + # Get info about the Python3 interpreter + # https://cmake.org/cmake/help/latest/module/FindPython3.html#module:FindPython3 + find_package(Python3 COMPONENTS Interpreter Development) + + if(NOT ${Python3_FOUND}) + message( + FATAL_ERROR + "Cannot find Python3 interpreter. Please install Python >= 3.6.") + endif() + + set(Python_VERSION_MAJOR ${Python3_VERSION_MAJOR}) + set(Python_VERSION_MINOR ${Python3_VERSION_MINOR}) - set(GTSAM_PYTHON_VERSION "${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}" - CACHE - STRING - "The version of Python to build the wrappers against." - FORCE) endif() + + set(GTSAM_PYTHON_VERSION + "${Python_VERSION_MAJOR}.${Python_VERSION_MINOR}" + CACHE STRING "The version of Python to build the wrappers against." + FORCE) + + endif() endif() +# Check for build of Unstable modules if(GTSAM_BUILD_PYTHON) if(GTSAM_UNSTABLE_BUILD_PYTHON) if (NOT GTSAM_BUILD_UNSTABLE) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index bfe08a76a..b50701464 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -4,20 +4,26 @@ if (NOT GTSAM_BUILD_PYTHON) return() endif() -# Common directory for storing data/datasets stored with the package. -# This will store the data in the Python site package directly. -set(GTSAM_PYTHON_DATASET_DIR "./gtsam/Data") - # Generate setup.py. file(READ "${PROJECT_SOURCE_DIR}/README.md" README_CONTENTS) configure_file(${PROJECT_SOURCE_DIR}/python/setup.py.in ${GTSAM_PYTHON_BUILD_DIRECTORY}/setup.py) -set(WRAP_USE_CUSTOM_PYTHON_LIBRARY ${GTSAM_USE_CUSTOM_PYTHON_LIBRARY}) -set(WRAP_PYTHON_VERSION ${GTSAM_PYTHON_VERSION}) +# Supply MANIFEST.in for older versions of Python +file(COPY ${PROJECT_SOURCE_DIR}/python/MANIFEST.in + DESTINATION ${GTSAM_PYTHON_BUILD_DIRECTORY}) include(PybindWrap) +############################################################ +## Load the necessary files to compile the wrapper + +# Load the pybind11 code +add_subdirectory(${PROJECT_SOURCE_DIR}/wrap/pybind11 pybind11) +# Set the wrapping script variable +set(PYBIND_WRAP_SCRIPT "${PROJECT_SOURCE_DIR}/wrap/scripts/pybind_wrap.py") +############################################################ + add_custom_target(gtsam_header DEPENDS "${PROJECT_SOURCE_DIR}/gtsam/gtsam.i") add_custom_target(gtsam_unstable_header DEPENDS "${PROJECT_SOURCE_DIR}/gtsam_unstable/gtsam_unstable.i") @@ -67,55 +73,68 @@ set(GTSAM_MODULE_PATH ${GTSAM_PYTHON_BUILD_DIRECTORY}/gtsam) create_symlinks("${CMAKE_CURRENT_SOURCE_DIR}/gtsam" "${GTSAM_MODULE_PATH}") +# Common directory for data/datasets stored with the package. +# This will store the data in the Python site package directly. +file(COPY "${GTSAM_SOURCE_DIR}/examples/Data" DESTINATION "${GTSAM_MODULE_PATH}") + +# Add gtsam as a dependency to the install target +set(GTSAM_PYTHON_DEPENDENCIES gtsam_py) + + if(GTSAM_UNSTABLE_BUILD_PYTHON) -set(ignore - gtsam::Point2 - gtsam::Point3 - gtsam::LieVector - gtsam::LieMatrix - gtsam::ISAM2ThresholdMapValue - gtsam::FactorIndices - gtsam::FactorIndexSet - gtsam::BetweenFactorPose3s - gtsam::Point2Vector - gtsam::Pose3Vector - gtsam::KeyVector - gtsam::FixedLagSmootherKeyTimestampMapValue - gtsam::BinaryMeasurementsUnit3 - gtsam::CameraSetCal3_S2 - gtsam::CameraSetCal3Bundler - gtsam::KeyPairDoubleMap) - -pybind_wrap(gtsam_unstable_py # target - ${PROJECT_SOURCE_DIR}/gtsam_unstable/gtsam_unstable.i # interface_header - "gtsam_unstable.cpp" # generated_cpp - "gtsam_unstable" # module_name - "gtsam" # top_namespace - "${ignore}" # ignore_classes - ${PROJECT_SOURCE_DIR}/python/gtsam_unstable/gtsam_unstable.tpl - gtsam_unstable # libs - "gtsam_unstable;gtsam_unstable_header" # dependencies - ON # use_boost - ) + set(ignore + gtsam::Point2 + gtsam::Point3 + gtsam::LieVector + gtsam::LieMatrix + gtsam::ISAM2ThresholdMapValue + gtsam::FactorIndices + gtsam::FactorIndexSet + gtsam::BetweenFactorPose3s + gtsam::Point2Vector + gtsam::Pose3Vector + gtsam::KeyVector + gtsam::FixedLagSmootherKeyTimestampMapValue + gtsam::BinaryMeasurementsUnit3 + gtsam::CameraSetCal3_S2 + gtsam::CameraSetCal3Bundler + gtsam::KeyPairDoubleMap) + + pybind_wrap(gtsam_unstable_py # target + ${PROJECT_SOURCE_DIR}/gtsam_unstable/gtsam_unstable.i # interface_header + "gtsam_unstable.cpp" # generated_cpp + "gtsam_unstable" # module_name + "gtsam" # top_namespace + "${ignore}" # ignore_classes + ${PROJECT_SOURCE_DIR}/python/gtsam_unstable/gtsam_unstable.tpl + gtsam_unstable # libs + "gtsam_unstable;gtsam_unstable_header" # dependencies + ON # use_boost + ) -set_target_properties(gtsam_unstable_py PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib" - INSTALL_RPATH_USE_LINK_PATH TRUE - OUTPUT_NAME "gtsam_unstable" - LIBRARY_OUTPUT_DIRECTORY "${GTSAM_PYTHON_BUILD_DIRECTORY}/gtsam_unstable" - DEBUG_POSTFIX "" # Otherwise you will have a wrong name - RELWITHDEBINFO_POSTFIX "" # Otherwise you will have a wrong name - ) + set_target_properties(gtsam_unstable_py PROPERTIES + INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib" + INSTALL_RPATH_USE_LINK_PATH TRUE + OUTPUT_NAME "gtsam_unstable" + LIBRARY_OUTPUT_DIRECTORY "${GTSAM_PYTHON_BUILD_DIRECTORY}/gtsam_unstable" + DEBUG_POSTFIX "" # Otherwise you will have a wrong name + RELWITHDEBINFO_POSTFIX "" # Otherwise you will have a wrong name + ) -set(GTSAM_UNSTABLE_MODULE_PATH ${GTSAM_PYTHON_BUILD_DIRECTORY}/gtsam_unstable) + set(GTSAM_UNSTABLE_MODULE_PATH ${GTSAM_PYTHON_BUILD_DIRECTORY}/gtsam_unstable) + + # Symlink all tests .py files to build folder. + create_symlinks("${CMAKE_CURRENT_SOURCE_DIR}/gtsam_unstable" + "${GTSAM_UNSTABLE_MODULE_PATH}") + + # Add gtsam_unstable to the install target + list(APPEND GTSAM_PYTHON_DEPENDENCIES gtsam_unstable_py) -# Symlink all tests .py files to build folder. -create_symlinks("${CMAKE_CURRENT_SOURCE_DIR}/gtsam_unstable" - "${GTSAM_UNSTABLE_MODULE_PATH}") endif() +# Add custom target so we can install with `make python-install` set(GTSAM_PYTHON_INSTALL_TARGET python-install) add_custom_target(${GTSAM_PYTHON_INSTALL_TARGET} COMMAND ${PYTHON_EXECUTABLE} ${GTSAM_PYTHON_BUILD_DIRECTORY}/setup.py install - DEPENDS gtsam_py gtsam_unstable_py + DEPENDS ${GTSAM_PYTHON_DEPENDENCIES} WORKING_DIRECTORY ${GTSAM_PYTHON_BUILD_DIRECTORY}) From 7477f9e0b08457bce087379d36f1e939e393924e Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 4 Jan 2021 13:13:26 -0500 Subject: [PATCH 213/261] updated python setup files so that example data is loaded correctly --- python/MANIFEST.in | 1 + python/setup.py.in | 20 ++++++++------------ 2 files changed, 9 insertions(+), 12 deletions(-) create mode 100644 python/MANIFEST.in diff --git a/python/MANIFEST.in b/python/MANIFEST.in new file mode 100644 index 000000000..41d7f0c59 --- /dev/null +++ b/python/MANIFEST.in @@ -0,0 +1 @@ +recursive-include gtsam/Data * diff --git a/python/setup.py.in b/python/setup.py.in index 1ffe978f3..9aa4b71f4 100644 --- a/python/setup.py.in +++ b/python/setup.py.in @@ -1,6 +1,4 @@ -import glob -import os -import sys +"""Setup file to install the GTSAM package.""" try: from setuptools import setup, find_packages @@ -10,19 +8,17 @@ except ImportError: packages = find_packages(where=".") print("PACKAGES: ", packages) -data_path = '${GTSAM_SOURCE_DIR}/examples/Data/' -data_files_and_directories = glob.glob(data_path + '**', recursive=True) -data_files = [x for x in data_files_and_directories if not os.path.isdir(x)] - package_data = { '': [ - './*.so', - './*.dll', + "./*.so", + "./*.dll", + "Data/*" # Add the data files to the package + "Data/**/*" # Add the data files in subdirectories ] } # Cleaner to read in the contents rather than copy them over. -readme_contents = open("${PROJECT_SOURCE_DIR}/README.md").read() +readme_contents = open("${GTSAM_SOURCE_DIR}/README.md").read() setup( name='gtsam', @@ -49,9 +45,9 @@ setup( 'Programming Language :: Python :: 3', ], packages=packages, + include_package_data=True, package_data=package_data, - data_files=[('${GTSAM_PYTHON_DATASET_DIR}', data_files),], test_suite="gtsam.tests", - install_requires=["numpy"], + install_requires=open("${GTSAM_SOURCE_DIR}/python/requirements.txt").readlines(), zip_safe=False, ) From 8540b2c07d8852971ff05ca77295f4485e953ed7 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 4 Jan 2021 13:13:44 -0500 Subject: [PATCH 214/261] more precise python version control in CI --- .github/scripts/python.sh | 5 +++-- .github/workflows/build-python.yml | 9 ++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/scripts/python.sh b/.github/scripts/python.sh index a71e14c97..80f531229 100644 --- a/.github/scripts/python.sh +++ b/.github/scripts/python.sh @@ -43,7 +43,7 @@ if [ -z ${PYTHON_VERSION+x} ]; then exit 127 fi -PYTHON="python${PYTHON_VERSION}" +PYTHON="python${PYTHON_MAJOR_VERSION}" if [[ $(uname) == "Darwin" ]]; then brew install wget @@ -66,7 +66,8 @@ mkdir $GITHUB_WORKSPACE/build cd $GITHUB_WORKSPACE/build cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Release \ - -DGTSAM_BUILD_TESTS=OFF -DGTSAM_BUILD_UNSTABLE=ON \ + -DGTSAM_BUILD_TESTS=OFF \ + -DGTSAM_BUILD_UNSTABLE=ON \ -DGTSAM_USE_QUATERNIONS=OFF \ -DGTSAM_WITH_TBB=${GTSAM_WITH_TBB:-OFF} \ -DGTSAM_BUILD_EXAMPLES_ALWAYS=OFF \ diff --git a/.github/workflows/build-python.yml b/.github/workflows/build-python.yml index 3f9a2e98a..e4eafe920 100644 --- a/.github/workflows/build-python.yml +++ b/.github/workflows/build-python.yml @@ -12,6 +12,8 @@ jobs: CTEST_PARALLEL_LEVEL: 2 CMAKE_BUILD_TYPE: ${{ matrix.build_type }} PYTHON_VERSION: ${{ matrix.python_version }} + PYTHON_MAJOR_VERSION: 3 + strategy: fail-fast: false matrix: @@ -26,32 +28,37 @@ jobs: ] build_type: [Debug, Release] - python_version: [3] + include: - name: ubuntu-18.04-gcc-5 os: ubuntu-18.04 compiler: gcc version: "5" + python_version: 3.6.9 - name: ubuntu-18.04-gcc-9 os: ubuntu-18.04 compiler: gcc version: "9" + python_version: 3.6.9 - name: ubuntu-18.04-clang-9 os: ubuntu-18.04 compiler: clang version: "9" + python_version: 3.6.9 - name: macOS-10.15-xcode-11.3.1 os: macOS-10.15 compiler: xcode version: "11.3.1" + python_version: 3.9.1 - name: ubuntu-18.04-gcc-5-tbb os: ubuntu-18.04 compiler: gcc version: "5" + python_version: 3.6.9 flag: tbb steps: From 569311d49cad895909d6460e7a86a74a117c6070 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 4 Jan 2021 13:26:34 -0500 Subject: [PATCH 215/261] Revert "more precise python version control in CI" This reverts commit 8540b2c07d8852971ff05ca77295f4485e953ed7. --- .github/scripts/python.sh | 5 ++--- .github/workflows/build-python.yml | 9 +-------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/.github/scripts/python.sh b/.github/scripts/python.sh index 80f531229..a71e14c97 100644 --- a/.github/scripts/python.sh +++ b/.github/scripts/python.sh @@ -43,7 +43,7 @@ if [ -z ${PYTHON_VERSION+x} ]; then exit 127 fi -PYTHON="python${PYTHON_MAJOR_VERSION}" +PYTHON="python${PYTHON_VERSION}" if [[ $(uname) == "Darwin" ]]; then brew install wget @@ -66,8 +66,7 @@ mkdir $GITHUB_WORKSPACE/build cd $GITHUB_WORKSPACE/build cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Release \ - -DGTSAM_BUILD_TESTS=OFF \ - -DGTSAM_BUILD_UNSTABLE=ON \ + -DGTSAM_BUILD_TESTS=OFF -DGTSAM_BUILD_UNSTABLE=ON \ -DGTSAM_USE_QUATERNIONS=OFF \ -DGTSAM_WITH_TBB=${GTSAM_WITH_TBB:-OFF} \ -DGTSAM_BUILD_EXAMPLES_ALWAYS=OFF \ diff --git a/.github/workflows/build-python.yml b/.github/workflows/build-python.yml index e4eafe920..3f9a2e98a 100644 --- a/.github/workflows/build-python.yml +++ b/.github/workflows/build-python.yml @@ -12,8 +12,6 @@ jobs: CTEST_PARALLEL_LEVEL: 2 CMAKE_BUILD_TYPE: ${{ matrix.build_type }} PYTHON_VERSION: ${{ matrix.python_version }} - PYTHON_MAJOR_VERSION: 3 - strategy: fail-fast: false matrix: @@ -28,37 +26,32 @@ jobs: ] build_type: [Debug, Release] - + python_version: [3] include: - name: ubuntu-18.04-gcc-5 os: ubuntu-18.04 compiler: gcc version: "5" - python_version: 3.6.9 - name: ubuntu-18.04-gcc-9 os: ubuntu-18.04 compiler: gcc version: "9" - python_version: 3.6.9 - name: ubuntu-18.04-clang-9 os: ubuntu-18.04 compiler: clang version: "9" - python_version: 3.6.9 - name: macOS-10.15-xcode-11.3.1 os: macOS-10.15 compiler: xcode version: "11.3.1" - python_version: 3.9.1 - name: ubuntu-18.04-gcc-5-tbb os: ubuntu-18.04 compiler: gcc version: "5" - python_version: 3.6.9 flag: tbb steps: From 5df235d714618c0ce50e72a03422929be113c840 Mon Sep 17 00:00:00 2001 From: Frank Dellaert Date: Mon, 4 Jan 2021 20:45:22 -0500 Subject: [PATCH 216/261] add virtual constructor --- gtsam/geometry/Cal3.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gtsam/geometry/Cal3.h b/gtsam/geometry/Cal3.h index 74c9868f3..08ce4c1e6 100644 --- a/gtsam/geometry/Cal3.h +++ b/gtsam/geometry/Cal3.h @@ -99,6 +99,9 @@ class GTSAM_EXPORT Cal3 { */ Cal3(double fov, int w, int h); + /// Virtual destructor + virtual ~Cal3() {} + /// @} /// @name Advanced Constructors /// @{ From 4d100461d4ca0d54fcee02bde8bb473ab3c6ded5 Mon Sep 17 00:00:00 2001 From: Frank Dellaert Date: Mon, 4 Jan 2021 20:46:16 -0500 Subject: [PATCH 217/261] Removed reference for iterating over values. Also used auto where I could, when changing. --- examples/Pose3Localization.cpp | 4 ++-- examples/Pose3SLAMExample_changeKeys.cpp | 2 +- examples/Pose3SLAMExample_g2o.cpp | 2 +- examples/Pose3SLAMExample_initializePose3Chordal.cpp | 2 +- examples/Pose3SLAMExample_initializePose3Gradient.cpp | 2 +- examples/SolverComparer.cpp | 2 +- gtsam/geometry/tests/testRot3.cpp | 2 +- gtsam/linear/VectorValues.cpp | 4 ++-- gtsam/nonlinear/NonlinearFactorGraph.cpp | 2 +- gtsam/nonlinear/Values-inl.h | 4 ++-- gtsam/nonlinear/Values.cpp | 4 ++-- gtsam/nonlinear/internal/LevenbergMarquardtState.h | 2 +- gtsam/nonlinear/tests/testValues.cpp | 6 +++--- gtsam/slam/InitializePose.h | 4 ++-- gtsam/slam/InitializePose3.cpp | 8 ++++---- gtsam/slam/dataset.cpp | 2 +- gtsam/slam/tests/testLago.cpp | 4 ++-- .../ConcurrentFilteringAndSmoothingExample.cpp | 4 ++-- gtsam_unstable/examples/SmartRangeExample_plaza1.cpp | 4 ++-- gtsam_unstable/examples/SmartRangeExample_plaza2.cpp | 4 ++-- gtsam_unstable/nonlinear/BatchFixedLagSmoother.cpp | 4 ++-- gtsam_unstable/nonlinear/ConcurrentBatchFilter.cpp | 10 +++++----- gtsam_unstable/nonlinear/ConcurrentBatchSmoother.cpp | 10 +++++----- .../nonlinear/ConcurrentIncrementalFilter.cpp | 6 +++--- .../nonlinear/ConcurrentIncrementalSmoother.cpp | 8 ++++---- .../nonlinear/tests/testConcurrentBatchFilter.cpp | 2 +- .../nonlinear/tests/testConcurrentBatchSmoother.cpp | 2 +- .../tests/testConcurrentIncrementalFilter.cpp | 2 +- .../tests/testConcurrentIncrementalSmootherDL.cpp | 4 ++-- .../tests/testConcurrentIncrementalSmootherGN.cpp | 4 ++-- 30 files changed, 60 insertions(+), 60 deletions(-) diff --git a/examples/Pose3Localization.cpp b/examples/Pose3Localization.cpp index 1667b43d9..c18a9e9ce 100644 --- a/examples/Pose3Localization.cpp +++ b/examples/Pose3Localization.cpp @@ -43,7 +43,7 @@ int main(const int argc, const char* argv[]) { auto priorModel = noiseModel::Diagonal::Variances( (Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished()); Key firstKey = 0; - for (const Values::ConstKeyValuePair& key_value : *initial) { + for (const auto key_value : *initial) { std::cout << "Adding prior to g2o file " << std::endl; firstKey = key_value.key; graph->addPrior(firstKey, Pose3(), priorModel); @@ -74,7 +74,7 @@ int main(const int argc, const char* argv[]) { // Calculate and print marginal covariances for all variables Marginals marginals(*graph, result); - for (const auto& key_value : result) { + for (const auto key_value : result) { auto p = dynamic_cast*>(&key_value.value); if (!p) continue; std::cout << marginals.marginalCovariance(key_value.key) << endl; diff --git a/examples/Pose3SLAMExample_changeKeys.cpp b/examples/Pose3SLAMExample_changeKeys.cpp index abadce975..5d4ed6657 100644 --- a/examples/Pose3SLAMExample_changeKeys.cpp +++ b/examples/Pose3SLAMExample_changeKeys.cpp @@ -55,7 +55,7 @@ int main(const int argc, const char *argv[]) { std::cout << "Rewriting input to file: " << inputFileRewritten << std::endl; // Additional: rewrite input with simplified keys 0,1,... Values simpleInitial; - for(const Values::ConstKeyValuePair& key_value: *initial) { + for(const auto key_value: *initial) { Key key; if(add) key = key_value.key + firstKey; diff --git a/examples/Pose3SLAMExample_g2o.cpp b/examples/Pose3SLAMExample_g2o.cpp index 1cca92f59..367964307 100644 --- a/examples/Pose3SLAMExample_g2o.cpp +++ b/examples/Pose3SLAMExample_g2o.cpp @@ -42,7 +42,7 @@ int main(const int argc, const char* argv[]) { auto priorModel = noiseModel::Diagonal::Variances( (Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished()); Key firstKey = 0; - for (const Values::ConstKeyValuePair& key_value : *initial) { + for (const auto key_value : *initial) { std::cout << "Adding prior to g2o file " << std::endl; firstKey = key_value.key; graph->addPrior(firstKey, Pose3(), priorModel); diff --git a/examples/Pose3SLAMExample_initializePose3Chordal.cpp b/examples/Pose3SLAMExample_initializePose3Chordal.cpp index 00a546bb2..992750fed 100644 --- a/examples/Pose3SLAMExample_initializePose3Chordal.cpp +++ b/examples/Pose3SLAMExample_initializePose3Chordal.cpp @@ -42,7 +42,7 @@ int main(const int argc, const char* argv[]) { auto priorModel = noiseModel::Diagonal::Variances( (Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished()); Key firstKey = 0; - for (const Values::ConstKeyValuePair& key_value : *initial) { + for (const auto key_value : *initial) { std::cout << "Adding prior to g2o file " << std::endl; firstKey = key_value.key; graph->addPrior(firstKey, Pose3(), priorModel); diff --git a/examples/Pose3SLAMExample_initializePose3Gradient.cpp b/examples/Pose3SLAMExample_initializePose3Gradient.cpp index 2f92afb9e..384f290a1 100644 --- a/examples/Pose3SLAMExample_initializePose3Gradient.cpp +++ b/examples/Pose3SLAMExample_initializePose3Gradient.cpp @@ -42,7 +42,7 @@ int main(const int argc, const char* argv[]) { auto priorModel = noiseModel::Diagonal::Variances( (Vector(6) << 1e-6, 1e-6, 1e-6, 1e-4, 1e-4, 1e-4).finished()); Key firstKey = 0; - for (const Values::ConstKeyValuePair& key_value : *initial) { + for (const auto key_value : *initial) { std::cout << "Adding prior to g2o file " << std::endl; firstKey = key_value.key; graph->addPrior(firstKey, Pose3(), priorModel); diff --git a/examples/SolverComparer.cpp b/examples/SolverComparer.cpp index 718ae6286..7bae41403 100644 --- a/examples/SolverComparer.cpp +++ b/examples/SolverComparer.cpp @@ -559,7 +559,7 @@ void runPerturb() // Perturb values VectorValues noise; - for(const Values::KeyValuePair& key_val: initial) + for(const Values::KeyValuePair key_val: initial) { Vector noisev(key_val.value.dim()); for(Vector::Index i = 0; i < noisev.size(); ++i) diff --git a/gtsam/geometry/tests/testRot3.cpp b/gtsam/geometry/tests/testRot3.cpp index 889f68580..290945837 100644 --- a/gtsam/geometry/tests/testRot3.cpp +++ b/gtsam/geometry/tests/testRot3.cpp @@ -825,7 +825,7 @@ TEST(Rot3, RQ_derivative) { const auto R = Rot3::RzRyRx(xyz).matrix(); const auto num = numericalDerivative11(RQ_proxy, R); Matrix39 calc; - RQ(R, calc).second; + auto dummy = RQ(R, calc).second; const auto err = vec_err.second; CHECK(assert_equal(num, calc, err)); diff --git a/gtsam/linear/VectorValues.cpp b/gtsam/linear/VectorValues.cpp index 9b5868744..746275847 100644 --- a/gtsam/linear/VectorValues.cpp +++ b/gtsam/linear/VectorValues.cpp @@ -161,7 +161,7 @@ namespace gtsam { bool VectorValues::equals(const VectorValues& x, double tol) const { if(this->size() != x.size()) return false; - for(const auto& values: boost::combine(*this, x)) { + for(const auto values: boost::combine(*this, x)) { if(values.get<0>().first != values.get<1>().first || !equal_with_abs_tol(values.get<0>().second, values.get<1>().second, tol)) return false; @@ -233,7 +233,7 @@ namespace gtsam { double result = 0.0; typedef boost::tuple ValuePair; using boost::adaptors::map_values; - for(const ValuePair& values: boost::combine(*this, v)) { + for(const ValuePair values: boost::combine(*this, v)) { assert_throw(values.get<0>().first == values.get<1>().first, invalid_argument("VectorValues::dot called with a VectorValues of different structure")); assert_throw(values.get<0>().second.size() == values.get<1>().second.size(), diff --git a/gtsam/nonlinear/NonlinearFactorGraph.cpp b/gtsam/nonlinear/NonlinearFactorGraph.cpp index 3063aa329..6a9e0cd0a 100644 --- a/gtsam/nonlinear/NonlinearFactorGraph.cpp +++ b/gtsam/nonlinear/NonlinearFactorGraph.cpp @@ -376,7 +376,7 @@ static Scatter scatterFromValues(const Values& values) { scatter.reserve(values.size()); // use "natural" ordering with keys taken from the initial values - for (const auto& key_value : values) { + for (const auto key_value : values) { scatter.add(key_value.key, key_value.value.dim()); } diff --git a/gtsam/nonlinear/Values-inl.h b/gtsam/nonlinear/Values-inl.h index 6829e859b..19813adba 100644 --- a/gtsam/nonlinear/Values-inl.h +++ b/gtsam/nonlinear/Values-inl.h @@ -217,7 +217,7 @@ namespace gtsam { /** Constructor from a Filtered view copies out all values */ template Values::Values(const Values::Filtered& view) { - for(const typename Filtered::KeyValuePair& key_value: view) { + for(const auto key_value: view) { Key key = key_value.key; insert(key, static_cast(key_value.value)); } @@ -226,7 +226,7 @@ namespace gtsam { /* ************************************************************************* */ template Values::Values(const Values::ConstFiltered& view) { - for(const typename ConstFiltered::KeyValuePair& key_value: view) { + for(const auto key_value: view) { Key key = key_value.key; insert(key, static_cast(key_value.value)); } diff --git a/gtsam/nonlinear/Values.cpp b/gtsam/nonlinear/Values.cpp index b672031ca..89a4206ee 100644 --- a/gtsam/nonlinear/Values.cpp +++ b/gtsam/nonlinear/Values.cpp @@ -206,7 +206,7 @@ namespace gtsam { /* ************************************************************************* */ size_t Values::dim() const { size_t result = 0; - for(const ConstKeyValuePair& key_value: *this) { + for(const auto key_value: *this) { result += key_value.value.dim(); } return result; @@ -215,7 +215,7 @@ namespace gtsam { /* ************************************************************************* */ VectorValues Values::zeroVectors() const { VectorValues result; - for(const ConstKeyValuePair& key_value: *this) + for(const auto key_value: *this) result.insert(key_value.key, Vector::Zero(key_value.value.dim())); return result; } diff --git a/gtsam/nonlinear/internal/LevenbergMarquardtState.h b/gtsam/nonlinear/internal/LevenbergMarquardtState.h index 8ab2e7466..cee839540 100644 --- a/gtsam/nonlinear/internal/LevenbergMarquardtState.h +++ b/gtsam/nonlinear/internal/LevenbergMarquardtState.h @@ -126,7 +126,7 @@ struct LevenbergMarquardtState : public NonlinearOptimizerState { noiseModelCache.resize(0); // for each of the variables, add a prior damped.reserve(damped.size() + values.size()); - for (const auto& key_value : values) { + for (const auto key_value : values) { const Key key = key_value.key; const size_t dim = key_value.value.dim(); const CachedModel* item = getCachedModel(dim); diff --git a/gtsam/nonlinear/tests/testValues.cpp b/gtsam/nonlinear/tests/testValues.cpp index 88cfb666f..a095cc381 100644 --- a/gtsam/nonlinear/tests/testValues.cpp +++ b/gtsam/nonlinear/tests/testValues.cpp @@ -335,7 +335,7 @@ TEST(Values, filter) { int i = 0; Values::Filtered filtered = values.filter(boost::bind(std::greater_equal(), _1, 2)); EXPECT_LONGS_EQUAL(2, (long)filtered.size()); - for(const Values::Filtered<>::KeyValuePair& key_value: filtered) { + for(const auto key_value: filtered) { if(i == 0) { LONGS_EQUAL(2, (long)key_value.key); try {key_value.value.cast();} catch (const std::bad_cast& e) { FAIL("can't cast Value to Pose2");} @@ -370,7 +370,7 @@ TEST(Values, filter) { i = 0; Values::ConstFiltered pose_filtered = values.filter(); EXPECT_LONGS_EQUAL(2, (long)pose_filtered.size()); - for(const Values::ConstFiltered::KeyValuePair& key_value: pose_filtered) { + for(const auto key_value: pose_filtered) { if(i == 0) { EXPECT_LONGS_EQUAL(1, (long)key_value.key); EXPECT(assert_equal(pose1, key_value.value)); @@ -408,7 +408,7 @@ TEST(Values, Symbol_filter) { values.insert(Symbol('y', 3), pose3); int i = 0; - for(const Values::Filtered::KeyValuePair& key_value: values.filter(Symbol::ChrTest('y'))) { + for(const auto key_value: values.filter(Symbol::ChrTest('y'))) { if(i == 0) { LONGS_EQUAL(Symbol('y', 1), (long)key_value.key); EXPECT(assert_equal(pose1, key_value.value.cast())); diff --git a/gtsam/slam/InitializePose.h b/gtsam/slam/InitializePose.h index be249b0b5..f9b99e47e 100644 --- a/gtsam/slam/InitializePose.h +++ b/gtsam/slam/InitializePose.h @@ -62,7 +62,7 @@ static Values computePoses(const Values& initialRot, // Upgrade rotations to full poses Values initialPose; - for (const auto& key_value : initialRot) { + for (const auto key_value : initialRot) { Key key = key_value.key; const auto& rot = initialRot.at(key); Pose initializedPose = Pose(rot, origin); @@ -86,7 +86,7 @@ static Values computePoses(const Values& initialRot, // put into Values structure Values estimate; - for (const auto& key_value : GNresult) { + for (const auto key_value : GNresult) { Key key = key_value.key; if (key != kAnchorKey) { const Pose& pose = GNresult.at(key); diff --git a/gtsam/slam/InitializePose3.cpp b/gtsam/slam/InitializePose3.cpp index af1fc609e..43404df53 100644 --- a/gtsam/slam/InitializePose3.cpp +++ b/gtsam/slam/InitializePose3.cpp @@ -124,7 +124,7 @@ Values InitializePose3::computeOrientationsGradient( // this works on the inverse rotations, according to Tron&Vidal,2011 Values inverseRot; inverseRot.insert(initialize::kAnchorKey, Rot3()); - for(const auto& key_value: givenGuess) { + for(const auto key_value: givenGuess) { Key key = key_value.key; const Pose3& pose = givenGuess.at(key); inverseRot.insert(key, pose.rotation().inverse()); @@ -139,7 +139,7 @@ Values InitializePose3::computeOrientationsGradient( // calculate max node degree & allocate gradient size_t maxNodeDeg = 0; VectorValues grad; - for(const auto& key_value: inverseRot) { + for(const auto key_value: inverseRot) { Key key = key_value.key; grad.insert(key,Z_3x1); size_t currNodeDeg = (adjEdgesMap.at(key)).size(); @@ -162,7 +162,7 @@ Values InitializePose3::computeOrientationsGradient( ////////////////////////////////////////////////////////////////////////// // compute the gradient at each node maxGrad = 0; - for (const auto& key_value : inverseRot) { + for (const auto key_value : inverseRot) { Key key = key_value.key; Vector gradKey = Z_3x1; // collect the gradient for each edge incident on key @@ -203,7 +203,7 @@ Values InitializePose3::computeOrientationsGradient( // Return correct rotations const Rot3& Rref = inverseRot.at(initialize::kAnchorKey); // This will be set to the identity as so far we included no prior Values estimateRot; - for(const auto& key_value: inverseRot) { + for(const auto key_value: inverseRot) { Key key = key_value.key; if (key != initialize::kAnchorKey) { const Rot3& R = inverseRot.at(key); diff --git a/gtsam/slam/dataset.cpp b/gtsam/slam/dataset.cpp index 74e074c9e..c8a8b15c5 100644 --- a/gtsam/slam/dataset.cpp +++ b/gtsam/slam/dataset.cpp @@ -586,7 +586,7 @@ void save2D(const NonlinearFactorGraph &graph, const Values &config, fstream stream(filename.c_str(), fstream::out); // save poses - for (const Values::ConstKeyValuePair key_value : config) { + for (const auto key_value : config) { const Pose2 &pose = key_value.value.cast(); stream << "VERTEX2 " << key_value.key << " " << pose.x() << " " << pose.y() << " " << pose.theta() << endl; diff --git a/gtsam/slam/tests/testLago.cpp b/gtsam/slam/tests/testLago.cpp index 55449d86e..781317d7a 100644 --- a/gtsam/slam/tests/testLago.cpp +++ b/gtsam/slam/tests/testLago.cpp @@ -284,7 +284,7 @@ TEST( Lago, largeGraphNoisy_orientations ) { Values::shared_ptr expected; boost::tie(gmatlab, expected) = readG2o(matlabFile); - for(const Values::KeyValuePair& key_val: *expected){ + for(const auto key_val: *expected){ Key k = key_val.key; EXPECT(assert_equal(expected->at(k), actual.at(k), 1e-5)); } @@ -310,7 +310,7 @@ TEST( Lago, largeGraphNoisy ) { Values::shared_ptr expected; boost::tie(gmatlab, expected) = readG2o(matlabFile); - for(const Values::KeyValuePair& key_val: *expected){ + for(const auto key_val: *expected){ Key k = key_val.key; EXPECT(assert_equal(expected->at(k), actual.at(k), 1e-2)); } diff --git a/gtsam_unstable/examples/ConcurrentFilteringAndSmoothingExample.cpp b/gtsam_unstable/examples/ConcurrentFilteringAndSmoothingExample.cpp index 939d3a5c8..1494d784b 100644 --- a/gtsam_unstable/examples/ConcurrentFilteringAndSmoothingExample.cpp +++ b/gtsam_unstable/examples/ConcurrentFilteringAndSmoothingExample.cpp @@ -308,11 +308,11 @@ int main(int argc, char** argv) { // And to demonstrate the fixed-lag aspect, print the keys contained in each smoother after 3.0 seconds cout << "After 15.0 seconds, each version contains to the following keys:" << endl; cout << " Concurrent Filter Keys: " << endl; - for(const auto& key_value: concurrentFilter.getLinearizationPoint()) { + for(const auto key_value: concurrentFilter.getLinearizationPoint()) { cout << setprecision(5) << " Key: " << key_value.key << endl; } cout << " Concurrent Smoother Keys: " << endl; - for(const auto& key_value: concurrentSmoother.getLinearizationPoint()) { + for(const auto key_value: concurrentSmoother.getLinearizationPoint()) { cout << setprecision(5) << " Key: " << key_value.key << endl; } cout << " Fixed-Lag Smoother Keys: " << endl; diff --git a/gtsam_unstable/examples/SmartRangeExample_plaza1.cpp b/gtsam_unstable/examples/SmartRangeExample_plaza1.cpp index 5fdc7a743..6a1239fba 100644 --- a/gtsam_unstable/examples/SmartRangeExample_plaza1.cpp +++ b/gtsam_unstable/examples/SmartRangeExample_plaza1.cpp @@ -233,7 +233,7 @@ int main(int argc, char** argv) { } } countK = 0; - for(const Values::ConstFiltered::KeyValuePair& it: result.filter()) + for(const auto it: result.filter()) os2 << it.key << "\t" << it.value.x() << "\t" << it.value.y() << "\t1" << endl; if (smart) { @@ -256,7 +256,7 @@ int main(int argc, char** argv) { // Write result to file Values result = isam.calculateEstimate(); ofstream os("rangeResult.txt"); - for(const Values::ConstFiltered::KeyValuePair& it: result.filter()) + for(const auto it: result.filter()) os << it.key << "\t" << it.value.x() << "\t" << it.value.y() << "\t" << it.value.theta() << endl; exit(0); diff --git a/gtsam_unstable/examples/SmartRangeExample_plaza2.cpp b/gtsam_unstable/examples/SmartRangeExample_plaza2.cpp index 90b2a30ff..95aff85a7 100644 --- a/gtsam_unstable/examples/SmartRangeExample_plaza2.cpp +++ b/gtsam_unstable/examples/SmartRangeExample_plaza2.cpp @@ -202,11 +202,11 @@ int main(int argc, char** argv) { // Write result to file Values result = isam.calculateEstimate(); ofstream os2("rangeResultLM.txt"); - for(const Values::ConstFiltered::KeyValuePair& it: result.filter()) + for(const auto it: result.filter()) os2 << it.key << "\t" << it.value.x() << "\t" << it.value.y() << "\t1" << endl; ofstream os("rangeResult.txt"); - for(const Values::ConstFiltered::KeyValuePair& it: result.filter()) + for(const auto it: result.filter()) os << it.key << "\t" << it.value.x() << "\t" << it.value.y() << "\t" << it.value.theta() << endl; exit(0); diff --git a/gtsam_unstable/nonlinear/BatchFixedLagSmoother.cpp b/gtsam_unstable/nonlinear/BatchFixedLagSmoother.cpp index 777e4b2d3..fd18e7c6d 100644 --- a/gtsam_unstable/nonlinear/BatchFixedLagSmoother.cpp +++ b/gtsam_unstable/nonlinear/BatchFixedLagSmoother.cpp @@ -59,7 +59,7 @@ FixedLagSmoother::Result BatchFixedLagSmoother::update( // Add the new variables to theta theta_.insert(newTheta); // Add new variables to the end of the ordering - for (const auto& key_value : newTheta) { + for (const auto key_value : newTheta) { ordering_.push_back(key_value.key); } // Augment Delta @@ -267,7 +267,7 @@ FixedLagSmoother::Result BatchFixedLagSmoother::optimize() { // Put the linearization points and deltas back for specific variables if (enforceConsistency_ && (linearKeys_.size() > 0)) { theta_.update(linearKeys_); - for(const auto& key_value: linearKeys_) { + for(const auto key_value: linearKeys_) { delta_.at(key_value.key) = newDelta.at(key_value.key); } } diff --git a/gtsam_unstable/nonlinear/ConcurrentBatchFilter.cpp b/gtsam_unstable/nonlinear/ConcurrentBatchFilter.cpp index 758bcfe48..83d0ab719 100644 --- a/gtsam_unstable/nonlinear/ConcurrentBatchFilter.cpp +++ b/gtsam_unstable/nonlinear/ConcurrentBatchFilter.cpp @@ -139,7 +139,7 @@ ConcurrentBatchFilter::Result ConcurrentBatchFilter::update(const NonlinearFacto // Add the new variables to theta theta_.insert(newTheta); // Add new variables to the end of the ordering - for(const Values::ConstKeyValuePair& key_value: newTheta) { + for(const auto key_value: newTheta) { ordering_.push_back(key_value.key); } // Augment Delta @@ -222,7 +222,7 @@ void ConcurrentBatchFilter::synchronize(const NonlinearFactorGraph& smootherSumm // Find the set of new separator keys KeySet newSeparatorKeys; - for(const Values::ConstKeyValuePair& key_value: separatorValues_) { + for(const auto key_value: separatorValues_) { newSeparatorKeys.insert(key_value.key); } @@ -236,7 +236,7 @@ void ConcurrentBatchFilter::synchronize(const NonlinearFactorGraph& smootherSumm graph.push_back(smootherShortcut_); Values values; values.insert(smootherSummarizationValues); - for(const Values::ConstKeyValuePair& key_value: separatorValues_) { + for(const auto key_value: separatorValues_) { if(!values.exists(key_value.key)) { values.insert(key_value.key, key_value.value); } @@ -471,7 +471,7 @@ void ConcurrentBatchFilter::optimize(const NonlinearFactorGraph& factors, Values // Put the linearization points and deltas back for specific variables if(linearValues.size() > 0) { theta.update(linearValues); - for(const Values::ConstKeyValuePair& key_value: linearValues) { + for(const auto key_value: linearValues) { delta.at(key_value.key) = newDelta.at(key_value.key); } } @@ -574,7 +574,7 @@ void ConcurrentBatchFilter::moveSeparator(const FastList& keysToMove) { // Calculate the set of new separator keys: AffectedKeys + PreviousSeparatorKeys - KeysToMove KeySet newSeparatorKeys = removedFactors.keys(); - for(const Values::ConstKeyValuePair& key_value: separatorValues_) { + for(const auto key_value: separatorValues_) { newSeparatorKeys.insert(key_value.key); } for(Key key: keysToMove) { diff --git a/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.cpp b/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.cpp index 600baa9f0..75d491bde 100644 --- a/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.cpp +++ b/gtsam_unstable/nonlinear/ConcurrentBatchSmoother.cpp @@ -61,7 +61,7 @@ ConcurrentBatchSmoother::Result ConcurrentBatchSmoother::update(const NonlinearF theta_.insert(newTheta); // Add new variables to the end of the ordering - for(const Values::ConstKeyValuePair& key_value: newTheta) { + for(const auto key_value: newTheta) { ordering_.push_back(key_value.key); } @@ -135,7 +135,7 @@ void ConcurrentBatchSmoother::synchronize(const NonlinearFactorGraph& smootherFa removeFactors(filterSummarizationSlots_); // Insert new linpoints into the values, augment the ordering, and store new dims to augment delta - for(const Values::ConstKeyValuePair& key_value: smootherValues) { + for(const auto key_value: smootherValues) { std::pair iter_inserted = theta_.tryInsert(key_value.key, key_value.value); if(iter_inserted.second) { // If the insert succeeded @@ -146,7 +146,7 @@ void ConcurrentBatchSmoother::synchronize(const NonlinearFactorGraph& smootherFa iter_inserted.first->value = key_value.value; } } - for(const Values::ConstKeyValuePair& key_value: separatorValues) { + for(const auto key_value: separatorValues) { std::pair iter_inserted = theta_.tryInsert(key_value.key, key_value.value); if(iter_inserted.second) { // If the insert succeeded @@ -322,7 +322,7 @@ ConcurrentBatchSmoother::Result ConcurrentBatchSmoother::optimize() { // Put the linearization points and deltas back for specific variables if(separatorValues_.size() > 0) { theta_.update(separatorValues_); - for(const Values::ConstKeyValuePair& key_value: separatorValues_) { + for(const auto key_value: separatorValues_) { delta_.at(key_value.key) = newDelta.at(key_value.key); } } @@ -372,7 +372,7 @@ void ConcurrentBatchSmoother::updateSmootherSummarization() { // Get the set of separator keys gtsam::KeySet separatorKeys; - for(const Values::ConstKeyValuePair& key_value: separatorValues_) { + for(const auto key_value: separatorValues_) { separatorKeys.insert(key_value.key); } diff --git a/gtsam_unstable/nonlinear/ConcurrentIncrementalFilter.cpp b/gtsam_unstable/nonlinear/ConcurrentIncrementalFilter.cpp index b70b9efc2..b9cf66a97 100644 --- a/gtsam_unstable/nonlinear/ConcurrentIncrementalFilter.cpp +++ b/gtsam_unstable/nonlinear/ConcurrentIncrementalFilter.cpp @@ -69,13 +69,13 @@ ConcurrentIncrementalFilter::Result ConcurrentIncrementalFilter::update(const No int group = 1; // Set all existing variables to Group1 if(isam2_.getLinearizationPoint().size() > 0) { - for(const Values::ConstKeyValuePair& key_value: isam2_.getLinearizationPoint()) { + for(const auto key_value: isam2_.getLinearizationPoint()) { orderingConstraints->operator[](key_value.key) = group; } ++group; } // Assign new variables to the root - for(const Values::ConstKeyValuePair& key_value: newTheta) { + for(const auto key_value: newTheta) { orderingConstraints->operator[](key_value.key) = group; } // Set marginalizable variables to Group0 @@ -201,7 +201,7 @@ void ConcurrentIncrementalFilter::synchronize(const NonlinearFactorGraph& smooth // Force iSAM2 not to relinearize anything during this iteration FastList noRelinKeys; - for(const Values::ConstKeyValuePair& key_value: isam2_.getLinearizationPoint()) { + for(const auto key_value: isam2_.getLinearizationPoint()) { noRelinKeys.push_back(key_value.key); } diff --git a/gtsam_unstable/nonlinear/ConcurrentIncrementalSmoother.cpp b/gtsam_unstable/nonlinear/ConcurrentIncrementalSmoother.cpp index 714d7c8d0..3886d0e42 100644 --- a/gtsam_unstable/nonlinear/ConcurrentIncrementalSmoother.cpp +++ b/gtsam_unstable/nonlinear/ConcurrentIncrementalSmoother.cpp @@ -66,7 +66,7 @@ ConcurrentIncrementalSmoother::Result ConcurrentIncrementalSmoother::update(cons // Also, mark the separator keys as fixed linearization points FastMap constrainedKeys; FastList noRelinKeys; - for(const Values::ConstKeyValuePair& key_value: separatorValues_) { + for(const auto key_value: separatorValues_) { constrainedKeys[key_value.key] = 1; noRelinKeys.push_back(key_value.key); } @@ -82,12 +82,12 @@ ConcurrentIncrementalSmoother::Result ConcurrentIncrementalSmoother::update(cons Values values(newTheta); // Unfortunately, we must be careful here, as some of the smoother values // and/or separator values may have been added previously - for(const Values::ConstKeyValuePair& key_value: smootherValues_) { + for(const auto key_value: smootherValues_) { if(!isam2_.getLinearizationPoint().exists(key_value.key)) { values.insert(key_value.key, smootherValues_.at(key_value.key)); } } - for(const Values::ConstKeyValuePair& key_value: separatorValues_) { + for(const auto key_value: separatorValues_) { if(!isam2_.getLinearizationPoint().exists(key_value.key)) { values.insert(key_value.key, separatorValues_.at(key_value.key)); } @@ -246,7 +246,7 @@ void ConcurrentIncrementalSmoother::updateSmootherSummarization() { // Get the set of separator keys KeySet separatorKeys; - for(const Values::ConstKeyValuePair& key_value: separatorValues_) { + for(const auto key_value: separatorValues_) { separatorKeys.insert(key_value.key); } diff --git a/gtsam_unstable/nonlinear/tests/testConcurrentBatchFilter.cpp b/gtsam_unstable/nonlinear/tests/testConcurrentBatchFilter.cpp index 1f19c0e8a..61db05167 100644 --- a/gtsam_unstable/nonlinear/tests/testConcurrentBatchFilter.cpp +++ b/gtsam_unstable/nonlinear/tests/testConcurrentBatchFilter.cpp @@ -64,7 +64,7 @@ NonlinearFactorGraph CalculateMarginals(const NonlinearFactorGraph& factorGraph, std::set KeysToKeep; - for(const Values::ConstKeyValuePair& key_value: linPoint) { // we cycle over all the keys of factorGraph + for(const auto key_value: linPoint) { // we cycle over all the keys of factorGraph KeysToKeep.insert(key_value.key); } // so far we are keeping all keys, but we want to delete the ones that we are going to marginalize for(Key key: keysToMarginalize) { diff --git a/gtsam_unstable/nonlinear/tests/testConcurrentBatchSmoother.cpp b/gtsam_unstable/nonlinear/tests/testConcurrentBatchSmoother.cpp index ae9a3f827..b5fb61428 100644 --- a/gtsam_unstable/nonlinear/tests/testConcurrentBatchSmoother.cpp +++ b/gtsam_unstable/nonlinear/tests/testConcurrentBatchSmoother.cpp @@ -560,7 +560,7 @@ TEST( ConcurrentBatchSmoother, synchronize_3 ) GaussianFactorGraph::shared_ptr linearFactors = allFactors.linearize(allValues); KeySet eliminateKeys = linearFactors->keys(); - for(const Values::ConstKeyValuePair& key_value: filterSeparatorValues) { + for(const auto key_value: filterSeparatorValues) { eliminateKeys.erase(key_value.key); } KeyVector variables(eliminateKeys.begin(), eliminateKeys.end()); diff --git a/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalFilter.cpp b/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalFilter.cpp index c5dba1a69..08d71a420 100644 --- a/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalFilter.cpp +++ b/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalFilter.cpp @@ -80,7 +80,7 @@ NonlinearFactorGraph CalculateMarginals(const NonlinearFactorGraph& factorGraph, std::set KeysToKeep; - for(const Values::ConstKeyValuePair& key_value: linPoint) { // we cycle over all the keys of factorGraph + for(const auto key_value: linPoint) { // we cycle over all the keys of factorGraph KeysToKeep.insert(key_value.key); } // so far we are keeping all keys, but we want to delete the ones that we are going to marginalize for(Key key: keysToMarginalize) { diff --git a/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalSmootherDL.cpp b/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalSmootherDL.cpp index 5de115013..ccb5a104e 100644 --- a/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalSmootherDL.cpp +++ b/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalSmootherDL.cpp @@ -512,7 +512,7 @@ TEST( ConcurrentIncrementalSmootherDL, synchronize_2 ) // Values expectedLinearizationPoint = BatchOptimize(allFactors, allValues, 1); Values expectedLinearizationPoint = filterSeparatorValues; Values actualLinearizationPoint; - for(const Values::ConstKeyValuePair& key_value: filterSeparatorValues) { + for(const auto key_value: filterSeparatorValues) { actualLinearizationPoint.insert(key_value.key, smoother.getLinearizationPoint().at(key_value.key)); } CHECK(assert_equal(expectedLinearizationPoint, actualLinearizationPoint, 1e-6)); @@ -580,7 +580,7 @@ TEST( ConcurrentIncrementalSmootherDL, synchronize_3 ) // GaussianBayesNet::shared_ptr GBNsptr = GSS.eliminate(); KeySet allkeys = LinFactorGraph->keys(); - for(const Values::ConstKeyValuePair& key_value: filterSeparatorValues) { + for(const auto key_value: filterSeparatorValues) { allkeys.erase(key_value.key); } KeyVector variables(allkeys.begin(), allkeys.end()); diff --git a/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalSmootherGN.cpp b/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalSmootherGN.cpp index ec78ee6e2..53c3d1610 100644 --- a/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalSmootherGN.cpp +++ b/gtsam_unstable/nonlinear/tests/testConcurrentIncrementalSmootherGN.cpp @@ -513,7 +513,7 @@ TEST( ConcurrentIncrementalSmootherGN, synchronize_2 ) // Values expectedLinearizationPoint = BatchOptimize(allFactors, allValues, 1); Values expectedLinearizationPoint = filterSeparatorValues; Values actualLinearizationPoint; - for(const Values::ConstKeyValuePair& key_value: filterSeparatorValues) { + for(const auto key_value: filterSeparatorValues) { actualLinearizationPoint.insert(key_value.key, smoother.getLinearizationPoint().at(key_value.key)); } CHECK(assert_equal(expectedLinearizationPoint, actualLinearizationPoint, 1e-6)); @@ -582,7 +582,7 @@ TEST( ConcurrentIncrementalSmootherGN, synchronize_3 ) // GaussianBayesNet::shared_ptr GBNsptr = GSS.eliminate(); KeySet allkeys = LinFactorGraph->keys(); - for(const Values::ConstKeyValuePair& key_value: filterSeparatorValues) + for(const auto key_value: filterSeparatorValues) allkeys.erase(key_value.key); KeyVector variables(allkeys.begin(), allkeys.end()); std::pair result = LinFactorGraph->eliminatePartialSequential(variables, EliminateCholesky); From 02abc53fc15ebb45a3a468293b737e8352c2b549 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 5 Jan 2021 10:07:06 -0500 Subject: [PATCH 218/261] fix metis based warnings in CMake and compiling --- gtsam/3rdparty/metis/CMakeLists.txt | 2 +- gtsam/3rdparty/metis/libmetis/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/gtsam/3rdparty/metis/CMakeLists.txt b/gtsam/3rdparty/metis/CMakeLists.txt index de46165ff..dc26aecb2 100644 --- a/gtsam/3rdparty/metis/CMakeLists.txt +++ b/gtsam/3rdparty/metis/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.0) project(METIS) # Add flags for currect directory and below diff --git a/gtsam/3rdparty/metis/libmetis/CMakeLists.txt b/gtsam/3rdparty/metis/libmetis/CMakeLists.txt index 330e989fa..92f931b98 100644 --- a/gtsam/3rdparty/metis/libmetis/CMakeLists.txt +++ b/gtsam/3rdparty/metis/libmetis/CMakeLists.txt @@ -12,6 +12,7 @@ endif() if(WIN32) set_target_properties(metis-gtsam PROPERTIES PREFIX "" + COMPILE_FLAGS /w RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/../../../bin") endif() From a650a6f8b1fb68da84b2fab17fedfbbe26d407cb Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 5 Jan 2021 10:43:31 -0500 Subject: [PATCH 219/261] add std namespacing --- gtsam/geometry/Pose3.cpp | 4 ++-- gtsam/geometry/SOn-inl.h | 4 +--- gtsam/sfm/ShonanAveraging.h | 4 ++-- gtsam/slam/dataset.h | 8 ++++---- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/gtsam/geometry/Pose3.cpp b/gtsam/geometry/Pose3.cpp index 22849d4f5..c183e32ed 100644 --- a/gtsam/geometry/Pose3.cpp +++ b/gtsam/geometry/Pose3.cpp @@ -106,8 +106,8 @@ Vector6 Pose3::adjointTranspose(const Vector6& xi, const Vector6& y, } /* ************************************************************************* */ -void Pose3::print(const string& s) const { - cout << (s.empty() ? s : s + " ") << *this << endl; +void Pose3::print(const std::string& s) const { + std::cout << (s.empty() ? s : s + " ") << *this << std::endl; } /* ************************************************************************* */ diff --git a/gtsam/geometry/SOn-inl.h b/gtsam/geometry/SOn-inl.h index 6180f4cc7..284ae76de 100644 --- a/gtsam/geometry/SOn-inl.h +++ b/gtsam/geometry/SOn-inl.h @@ -22,8 +22,6 @@ #include -using namespace std; - namespace gtsam { // Implementation for N>=5 just uses dynamic version @@ -108,7 +106,7 @@ typename SO::VectorN2 SO::vec( template void SO::print(const std::string& s) const { - cout << s << matrix_ << endl; + std::cout << s << matrix_ << std::endl; } } // namespace gtsam diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index edd9f33a2..f1ce31fa6 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -354,7 +354,7 @@ class ShonanAveraging2 : public ShonanAveraging<2> { public: ShonanAveraging2(const Measurements &measurements, const Parameters ¶meters = Parameters()); - explicit ShonanAveraging2(string g2oFile, + explicit ShonanAveraging2(std::string g2oFile, const Parameters ¶meters = Parameters()); }; @@ -362,7 +362,7 @@ class ShonanAveraging3 : public ShonanAveraging<3> { public: ShonanAveraging3(const Measurements &measurements, const Parameters ¶meters = Parameters()); - explicit ShonanAveraging3(string g2oFile, + explicit ShonanAveraging3(std::string g2oFile, const Parameters ¶meters = Parameters()); // TODO(frank): Deprecate after we land pybind wrapper diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index d96c11167..80877c136 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -303,8 +303,8 @@ struct SfmTrack { /// print void print(const std::string& s = "") const { - cout << "Track with " << measurements.size(); - cout << " measurements of point " << p << "\n"; + std::cout << "Track with " << measurements.size(); + std::cout << " measurements of point " << p << std::endl; } }; @@ -385,8 +385,8 @@ struct SfmData { /// print void print(const std::string& s = "") const { - cout << "Number of cameras = " << number_cameras() << "\n"; - cout << "Number of tracks = " << number_tracks() << "\n"; + std::cout << "Number of cameras = " << number_cameras() << std::endl; + std::cout << "Number of tracks = " << number_tracks() << std::endl; } }; From 473a6a15ee67bbdf559bb58932773cd8183e1f00 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 5 Jan 2021 10:44:05 -0500 Subject: [PATCH 220/261] fix warnings for vectors and matrices --- gtsam/nonlinear/tests/testValues.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gtsam/nonlinear/tests/testValues.cpp b/gtsam/nonlinear/tests/testValues.cpp index 88cfb666f..455af942c 100644 --- a/gtsam/nonlinear/tests/testValues.cpp +++ b/gtsam/nonlinear/tests/testValues.cpp @@ -175,10 +175,13 @@ TEST(Values, basic_functions) { Values values; const Values& values_c = values; - values.insert(2, Vector3()); - values.insert(4, Vector3()); - values.insert(6, Matrix23()); - values.insert(8, Matrix23()); + Matrix23 M1, M2; + M1 << 0, 0, 0, 0, 0, 0; + M2 << 0, 0, 0, 0, 0, 0; + values.insert(2, Vector3(0, 0, 0)); + values.insert(4, Vector3(0, 0, 0)); + values.insert(6, M1); + values.insert(8, M2); // find EXPECT_LONGS_EQUAL(4, values.find(4)->key); From b7584ce362fd30fe498292f6c32754983a0cc34f Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 5 Jan 2021 10:44:26 -0500 Subject: [PATCH 221/261] verbose printing of exceptions --- gtsam/slam/GeneralSFMFactor.h | 24 +++++++++++++------ .../examples/SmartRangeExample_plaza1.cpp | 3 ++- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/gtsam/slam/GeneralSFMFactor.h b/gtsam/slam/GeneralSFMFactor.h index f848a56ca..3e292c892 100644 --- a/gtsam/slam/GeneralSFMFactor.h +++ b/gtsam/slam/GeneralSFMFactor.h @@ -70,6 +70,7 @@ class GeneralSFMFactor: public NoiseModelFactor2 { protected: Point2 measured_; ///< the 2D measurement + bool verbose_; ///< Flag for print verbosity public: @@ -86,12 +87,17 @@ public: * @param cameraKey is the index of the camera * @param landmarkKey is the index of the landmark */ - GeneralSFMFactor(const Point2& measured, const SharedNoiseModel& model, Key cameraKey, Key landmarkKey) : - Base(model, cameraKey, landmarkKey), measured_(measured) {} + GeneralSFMFactor(const Point2& measured, const SharedNoiseModel& model, + Key cameraKey, Key landmarkKey, bool verbose = false) + : Base(model, cameraKey, landmarkKey), + measured_(measured), + verbose_(verbose) {} - GeneralSFMFactor():measured_(0.0,0.0) {} ///< default constructor - GeneralSFMFactor(const Point2 & p):measured_(p) {} ///< constructor that takes a Point2 - GeneralSFMFactor(double x, double y):measured_(x,y) {} ///< constructor that takes doubles x,y to make a Point2 + GeneralSFMFactor() : measured_(0.0, 0.0) {} ///< default constructor + ///< constructor that takes a Point2 + GeneralSFMFactor(const Point2& p) : measured_(p) {} + ///< constructor that takes doubles x,y to make a Point2 + GeneralSFMFactor(double x, double y) : measured_(x, y) {} virtual ~GeneralSFMFactor() {} ///< destructor @@ -127,7 +133,9 @@ public: catch( CheiralityException& e) { if (H1) *H1 = JacobianC::Zero(); if (H2) *H2 = JacobianL::Zero(); - // TODO warn if verbose output asked for + if (verbose_) { + std::cout << e.what() << std::endl; + } return Z_2x1; } } @@ -149,7 +157,9 @@ public: H1.setZero(); H2.setZero(); b.setZero(); - // TODO warn if verbose output asked for + if (verbose_) { + std::cout << e.what() << std::endl; + } } // Whiten the system if needed diff --git a/gtsam_unstable/examples/SmartRangeExample_plaza1.cpp b/gtsam_unstable/examples/SmartRangeExample_plaza1.cpp index 5fdc7a743..0976674de 100644 --- a/gtsam_unstable/examples/SmartRangeExample_plaza1.cpp +++ b/gtsam_unstable/examples/SmartRangeExample_plaza1.cpp @@ -188,7 +188,8 @@ int main(int argc, char** argv) { smartFactors[j]->addRange(i, range); printf("adding range %g for %d",range,(int)j); } catch (const invalid_argument& e) { - printf("warning: omitting duplicate range %g for %d",range,(int)j); + printf("warning: omitting duplicate range %g for %d: %s", range, + (int)j, e.what()); } cout << endl; } From b244a7d6366c0d3a29080b2ea3fc00306ec1ab8d Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 5 Jan 2021 13:59:58 -0500 Subject: [PATCH 222/261] remove verbose flag and print exception to std::cerr --- gtsam/slam/GeneralSFMFactor.h | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/gtsam/slam/GeneralSFMFactor.h b/gtsam/slam/GeneralSFMFactor.h index 3e292c892..1e48571e3 100644 --- a/gtsam/slam/GeneralSFMFactor.h +++ b/gtsam/slam/GeneralSFMFactor.h @@ -70,7 +70,6 @@ class GeneralSFMFactor: public NoiseModelFactor2 { protected: Point2 measured_; ///< the 2D measurement - bool verbose_; ///< Flag for print verbosity public: @@ -88,10 +87,8 @@ public: * @param landmarkKey is the index of the landmark */ GeneralSFMFactor(const Point2& measured, const SharedNoiseModel& model, - Key cameraKey, Key landmarkKey, bool verbose = false) - : Base(model, cameraKey, landmarkKey), - measured_(measured), - verbose_(verbose) {} + Key cameraKey, Key landmarkKey) + : Base(model, cameraKey, landmarkKey), measured_(measured) {} GeneralSFMFactor() : measured_(0.0, 0.0) {} ///< default constructor ///< constructor that takes a Point2 @@ -133,9 +130,7 @@ public: catch( CheiralityException& e) { if (H1) *H1 = JacobianC::Zero(); if (H2) *H2 = JacobianL::Zero(); - if (verbose_) { - std::cout << e.what() << std::endl; - } + std::cerr << e.what() << std::endl; return Z_2x1; } } @@ -157,9 +152,7 @@ public: H1.setZero(); H2.setZero(); b.setZero(); - if (verbose_) { - std::cout << e.what() << std::endl; - } + std::cerr << e.what() << std::endl; } // Whiten the system if needed From 5b52e4c29f6572e8e6d7a4c3abad95340e2668f4 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 5 Jan 2021 14:13:15 -0500 Subject: [PATCH 223/261] cleanly initialize matrices in test --- gtsam/nonlinear/tests/testValues.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gtsam/nonlinear/tests/testValues.cpp b/gtsam/nonlinear/tests/testValues.cpp index 455af942c..bb66cb695 100644 --- a/gtsam/nonlinear/tests/testValues.cpp +++ b/gtsam/nonlinear/tests/testValues.cpp @@ -175,9 +175,7 @@ TEST(Values, basic_functions) { Values values; const Values& values_c = values; - Matrix23 M1, M2; - M1 << 0, 0, 0, 0, 0, 0; - M2 << 0, 0, 0, 0, 0, 0; + Matrix23 M1 = Matrix23::Zero(), M2 = Matrix23::Zero(); values.insert(2, Vector3(0, 0, 0)); values.insert(4, Vector3(0, 0, 0)); values.insert(6, M1); From 0f03ee1f7635f186cd6082dbc36b146b7d56fba7 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 5 Jan 2021 14:43:43 -0500 Subject: [PATCH 224/261] remove exception print, add TODO --- gtsam/slam/GeneralSFMFactor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtsam/slam/GeneralSFMFactor.h b/gtsam/slam/GeneralSFMFactor.h index 1e48571e3..c9639d4d5 100644 --- a/gtsam/slam/GeneralSFMFactor.h +++ b/gtsam/slam/GeneralSFMFactor.h @@ -130,7 +130,7 @@ public: catch( CheiralityException& e) { if (H1) *H1 = JacobianC::Zero(); if (H2) *H2 = JacobianL::Zero(); - std::cerr << e.what() << std::endl; + //TODO Print the exception via logging return Z_2x1; } } @@ -152,7 +152,7 @@ public: H1.setZero(); H2.setZero(); b.setZero(); - std::cerr << e.what() << std::endl; + //TODO Print the exception via logging } // Whiten the system if needed From 7ae050cc87a77e062920a51e401478bb5653a1c0 Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Wed, 6 Jan 2021 12:08:22 +0530 Subject: [PATCH 225/261] adding default color values to fix equality check --- gtsam/slam/dataset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index d96c11167..8ceacf31c 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -221,7 +221,7 @@ struct SfmTrack { SfmTrack(): p(0,0,0) {} SfmTrack(const gtsam::Point3& pt) : p(pt) {} Point3 p; ///< 3D position of the point - float r, g, b; ///< RGB color of the 3D point + float r = 0, g = 0, b = 0; ///< RGB color of the 3D point std::vector measurements; ///< The 2D image projections (id,(u,v)) std::vector siftIndices; From ecb22263458d67de763d9362ffa8265525715b7b Mon Sep 17 00:00:00 2001 From: John Lambert Date: Wed, 6 Jan 2021 12:55:20 -0500 Subject: [PATCH 226/261] make r,g,b part of constructor w/ default values --- gtsam/slam/dataset.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index e4162fa75..00e3516d0 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -218,10 +218,11 @@ typedef std::pair SiftIndex; /// Define the structure for the 3D points struct SfmTrack { - SfmTrack(): p(0,0,0) {} - SfmTrack(const gtsam::Point3& pt) : p(pt) {} + SfmTrack(float r = 0, float g = 0, float b = 0): p(0,0,0), r(r), g(g), b(b) {} + SfmTrack(const gtsam::Point3& pt, float r = 0, float g = 0, float b = 0) : p(pt), r(r), g(g), b(b) {} + Point3 p; ///< 3D position of the point - float r = 0, g = 0, b = 0; ///< RGB color of the 3D point + float r, g, b; ///< RGB color of the 3D point std::vector measurements; ///< The 2D image projections (id,(u,v)) std::vector siftIndices; From 758ece7238db0e29c7b249c23a3dd4dcff7140eb Mon Sep 17 00:00:00 2001 From: John Lambert Date: Wed, 6 Jan 2021 15:48:49 -0500 Subject: [PATCH 227/261] add getter for rgb --- gtsam/slam/dataset.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index 00e3516d0..5730487ce 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -225,6 +225,9 @@ struct SfmTrack { float r, g, b; ///< RGB color of the 3D point std::vector measurements; ///< The 2D image projections (id,(u,v)) std::vector siftIndices; + + /// Get RGB values describing 3d point + Point3 rgb() const { return Point3(r, g, b); } /// Total number of measurements in this track size_t number_measurements() const { From 7daf01be3db9ff57afc69c2e49ec4b5d15cc5da3 Mon Sep 17 00:00:00 2001 From: John Lambert Date: Wed, 6 Jan 2021 15:50:08 -0500 Subject: [PATCH 228/261] make getter const --- gtsam/slam/dataset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/slam/dataset.h b/gtsam/slam/dataset.h index 5730487ce..ec5d6dce9 100644 --- a/gtsam/slam/dataset.h +++ b/gtsam/slam/dataset.h @@ -227,7 +227,7 @@ struct SfmTrack { std::vector siftIndices; /// Get RGB values describing 3d point - Point3 rgb() const { return Point3(r, g, b); } + const Point3 rgb() const { return Point3(r, g, b); } /// Total number of measurements in this track size_t number_measurements() const { From bd9d50126975b4c4b88794e8aff0a0d5ff7e0cc4 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 6 Jan 2021 17:58:46 -0500 Subject: [PATCH 229/261] use older form of CMake install --- wrap/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wrap/CMakeLists.txt b/wrap/CMakeLists.txt index 4c89ab96e..a877c4a16 100644 --- a/wrap/CMakeLists.txt +++ b/wrap/CMakeLists.txt @@ -28,11 +28,13 @@ install(FILES cmake/gtwrapConfig.cmake cmake/PybindWrap.cmake # Install wrapping scripts as binaries to `CMAKE_INSTALL_PREFIX/bin` so they can # be invoked for wrapping. -install(PROGRAMS scripts/pybind_wrap.py scripts/matlab_wrap.py TYPE BIN) +install(PROGRAMS scripts/pybind_wrap.py scripts/matlab_wrap.py + DESTINATION ${CMAKE_INSTALL_BINDIR}) # Install pybind11 directory to `CMAKE_INSTALL_PREFIX/lib/pybind11` This will # allow the gtwrapConfig.cmake file to load it later. -install(DIRECTORY pybind11 TYPE LIB) +install(DIRECTORY pybind11 + DESTINATION ${CMAKE_INSTALL_LIBDIR}) # ############################################################################## # Install the Python package From 6309917fdfee626531910a53e12b7e38b231b07a Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Thu, 7 Jan 2021 11:17:54 -0500 Subject: [PATCH 230/261] add docs for cmake update --- wrap/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wrap/CMakeLists.txt b/wrap/CMakeLists.txt index a877c4a16..06659b408 100644 --- a/wrap/CMakeLists.txt +++ b/wrap/CMakeLists.txt @@ -28,11 +28,13 @@ install(FILES cmake/gtwrapConfig.cmake cmake/PybindWrap.cmake # Install wrapping scripts as binaries to `CMAKE_INSTALL_PREFIX/bin` so they can # be invoked for wrapping. +# We use DESTINATION (instead of TYPE) so we can support older CMake versions. install(PROGRAMS scripts/pybind_wrap.py scripts/matlab_wrap.py DESTINATION ${CMAKE_INSTALL_BINDIR}) # Install pybind11 directory to `CMAKE_INSTALL_PREFIX/lib/pybind11` This will # allow the gtwrapConfig.cmake file to load it later. +# We use DESTINATION (instead of TYPE) so we can support older CMake versions. install(DIRECTORY pybind11 DESTINATION ${CMAKE_INSTALL_LIBDIR}) From d89dd7d87492b6ba2954444782981e98f2da8120 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Mon, 11 Jan 2021 13:51:32 -0500 Subject: [PATCH 231/261] follow correct doxygen format --- gtsam/sfm/ShonanAveraging.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index 2cb62ca55..a603dec98 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -53,9 +53,9 @@ struct GTSAM_EXPORT ShonanAveragingParameters { double alpha; ///< weight of anchor-based prior (default 0) double beta; ///< weight of Karcher-based prior (default 1) double gamma; ///< weight of gauge-fixing factors (default 0) - ///< if enabled, the Huber loss is used (default false) + /// if enabled, the Huber loss is used (default false) bool useHuber; - ///< if enabled solution optimality is certified (default true) + /// if enabled solution optimality is certified (default true) bool certifyOptimality; ShonanAveragingParameters(const LevenbergMarquardtParams &lm = From e9080bf8856b64d17156469de521e6741acf6c64 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 12 Jan 2021 20:45:43 -0500 Subject: [PATCH 232/261] Squashed 'wrap/' changes from 09f8bbf71..186ed2c79 186ed2c79 Merge pull request #26 from borglab/fix/required 9af1b8f09 unmake python cmake package as required git-subtree-dir: wrap git-subtree-split: 186ed2c792f80bbd315e747ef8622f8355c626f6 --- CMakeLists.txt | 2 +- cmake/GtwrapUtils.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c89ab96e..c5e8c46de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ install(DIRECTORY pybind11 TYPE LIB) find_package( Python ${WRAP_PYTHON_VERSION} COMPONENTS Interpreter - REQUIRED) + EXACT) # Detect virtualenv and set Pip args accordingly # https://www.scivision.dev/cmake-install-python-package/ diff --git a/cmake/GtwrapUtils.cmake b/cmake/GtwrapUtils.cmake index 9c6b141a0..b5f791250 100644 --- a/cmake/GtwrapUtils.cmake +++ b/cmake/GtwrapUtils.cmake @@ -68,7 +68,7 @@ macro(gtwrap_get_python_version WRAP_PYTHON_VERSION) find_package( Python ${WRAP_PYTHON_VERSION} COMPONENTS Interpreter Development - EXACT REQUIRED) + EXACT) endif() endmacro() From 9b03b6d11193c40603dff86f4e56b1dadfa8f96a Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Wed, 13 Jan 2021 10:54:22 -0500 Subject: [PATCH 233/261] Squashed 'wrap/' changes from 186ed2c79..85d34351c 85d34351c Merge pull request #27 from borglab/fix/python3.5 dfe7639c0 support for python 3.5 git-subtree-dir: wrap git-subtree-split: 85d34351cdb29172601845f73d3281e786a531b3 --- cmake/GtwrapUtils.cmake | 4 ++-- setup.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/GtwrapUtils.cmake b/cmake/GtwrapUtils.cmake index b5f791250..acf075c5b 100644 --- a/cmake/GtwrapUtils.cmake +++ b/cmake/GtwrapUtils.cmake @@ -8,7 +8,7 @@ macro(get_python_version) if(NOT ${PYTHONINTERP_FOUND}) message( FATAL_ERROR - "Cannot find Python interpreter. Please install Python >= 3.6.") + "Cannot find Python interpreter. Please install Python>=3.5.") endif() find_package(PythonLibs ${PYTHON_VERSION_STRING}) @@ -34,7 +34,7 @@ macro(get_python_version) if(NOT ${Python_FOUND}) message( FATAL_ERROR - "Cannot find Python interpreter. Please install Python>=3.6.") + "Cannot find Python interpreter. Please install Python>=3.5.") endif() endif() diff --git a/setup.py b/setup.py index 10fc53d34..8ef61f312 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( keywords="wrap, bindings, cpp, python", long_description=open("README.md").read(), long_description_content_type="text/markdown", - python_requires=">=3.6", + python_requires=">=3.5", # https://pypi.org/classifiers classifiers=[ 'Development Status :: 4 - Beta', From e439e1110f3898fc8068910bccf8603c60572064 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 14 Jan 2021 11:56:34 +0000 Subject: [PATCH 234/261] Add getters to line3 --- gtsam/geometry/Line3.h | 21 +++++++++++++++++++++ gtsam/geometry/tests/testLine3.cpp | 10 ++++++++++ 2 files changed, 31 insertions(+) diff --git a/gtsam/geometry/Line3.h b/gtsam/geometry/Line3.h index 1c7ed2f4c..f70e13ca7 100644 --- a/gtsam/geometry/Line3.h +++ b/gtsam/geometry/Line3.h @@ -102,6 +102,27 @@ class Line3 { */ Point3 point(double distance = 0) const; + /** + * Return the rotation of the line. + */ + inline Rot3 R() const { + return R_; + } + + /** + * Return the x-coordinate of the intersection of the line with the xy plane. + */ + inline double a() const { + return a_; + } + + /** + * Return the y-coordinate of the intersection of the line with the xy plane. + */ + inline double b() const { + return b_; + } + /** * Transform a line from world to camera frame * @param wTc - Pose3 of camera in world frame diff --git a/gtsam/geometry/tests/testLine3.cpp b/gtsam/geometry/tests/testLine3.cpp index 9ed12aef7..09371bad4 100644 --- a/gtsam/geometry/tests/testLine3.cpp +++ b/gtsam/geometry/tests/testLine3.cpp @@ -14,6 +14,16 @@ GTSAM_CONCEPT_MANIFOLD_INST(Line3) static const Line3 l(Rot3(), 1, 1); +// Testing getters +TEST(Line3, getMethods) { + const double a = 5, b = 10; + const Rot3 R = Rot3::Expmap(Vector3(0.1, 0.2, 0.3)); + const Line3 line(R, a, b); + EXPECT_DOUBLES_EQUAL(a, line.a(), 1e-8); + EXPECT_DOUBLES_EQUAL(b, line.b(), 1e-8); + EXPECT(assert_equal(R, line.R(), 1e-8)); +} + // Testing equals function of Line3 TEST(Line3, equals) { Line3 l_same = l; From a6c67fb3bc297e99583b4bbfdd4b048503a0fa99 Mon Sep 17 00:00:00 2001 From: John Lambert Date: Thu, 14 Jan 2021 12:09:24 -0500 Subject: [PATCH 235/261] add robust shonan updates to python wrapper --- gtsam/gtsam.i | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index e1e11964f..abba7437d 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -2933,9 +2933,14 @@ class ShonanAveragingParameters2 { void setAnchorWeight(double value); double getAnchorWeight() const; void setKarcherWeight(double value); - double getKarcherWeight(); + double getKarcherWeight() const; void setGaugesWeight(double value); - double getGaugesWeight(); + double getGaugesWeight() const; + void setUseHuber(bool value); + bool getUseHuber() const; + void setCertifyOptimality(bool value); + bool getCertifyOptimality() const; + void print() const; }; class ShonanAveragingParameters3 { @@ -2949,9 +2954,14 @@ class ShonanAveragingParameters3 { void setAnchorWeight(double value); double getAnchorWeight() const; void setKarcherWeight(double value); - double getKarcherWeight(); + double getKarcherWeight() const; void setGaugesWeight(double value); - double getGaugesWeight(); + double getGaugesWeight() const; + void setUseHuber(bool value); + bool getUseHuber() const; + void setCertifyOptimality(bool value); + bool getCertifyOptimality() const; + void print() const; }; class ShonanAveraging2 { From 347ea5d805328a1fb5e014ee1f838cdc890fcccd Mon Sep 17 00:00:00 2001 From: RamadanAhmed Date: Thu, 14 Jan 2021 21:58:53 +0200 Subject: [PATCH 236/261] Fix GTSAM_EXPORT for some classes and function --- gtsam/geometry/Point3.h | 2 +- gtsam/sfm/ShonanAveraging.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gtsam/geometry/Point3.h b/gtsam/geometry/Point3.h index 57188fc5e..001218ff7 100644 --- a/gtsam/geometry/Point3.h +++ b/gtsam/geometry/Point3.h @@ -61,7 +61,7 @@ GTSAM_EXPORT double dot(const Point3& p, const Point3& q, /// mean template -GTSAM_EXPORT Point3 mean(const CONTAINER& points) { +Point3 mean(const CONTAINER& points) { if (points.size() == 0) throw std::invalid_argument("Point3::mean input container is empty"); Point3 sum(0, 0, 0); sum = std::accumulate(points.begin(), points.end(), sum); diff --git a/gtsam/sfm/ShonanAveraging.h b/gtsam/sfm/ShonanAveraging.h index b1f26acb8..e8a828be8 100644 --- a/gtsam/sfm/ShonanAveraging.h +++ b/gtsam/sfm/ShonanAveraging.h @@ -414,7 +414,7 @@ class GTSAM_EXPORT ShonanAveraging { // Subclasses for d=2 and d=3 that explicitly instantiate, as well as provide a // convenience interface with file access. -class ShonanAveraging2 : public ShonanAveraging<2> { +class GTSAM_EXPORT ShonanAveraging2 : public ShonanAveraging<2> { public: ShonanAveraging2(const Measurements &measurements, const Parameters ¶meters = Parameters()); @@ -422,7 +422,7 @@ class ShonanAveraging2 : public ShonanAveraging<2> { const Parameters ¶meters = Parameters()); }; -class ShonanAveraging3 : public ShonanAveraging<3> { +class GTSAM_EXPORT ShonanAveraging3 : public ShonanAveraging<3> { public: ShonanAveraging3(const Measurements &measurements, const Parameters ¶meters = Parameters()); From 252af8f0c59837513d704c0841571fad013989eb Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Fri, 15 Jan 2021 12:41:31 -0500 Subject: [PATCH 237/261] added FunctorizedFactor2 --- gtsam/nonlinear/FunctorizedFactor.h | 116 +++++++++++++++++- .../nonlinear/tests/testFunctorizedFactor.cpp | 101 ++++++++++++++- 2 files changed, 212 insertions(+), 5 deletions(-) diff --git a/gtsam/nonlinear/FunctorizedFactor.h b/gtsam/nonlinear/FunctorizedFactor.h index 688b3aaa2..53a48f097 100644 --- a/gtsam/nonlinear/FunctorizedFactor.h +++ b/gtsam/nonlinear/FunctorizedFactor.h @@ -87,8 +87,8 @@ class GTSAM_EXPORT FunctorizedFactor : public NoiseModelFactor1 { NonlinearFactor::shared_ptr(new FunctorizedFactor(*this))); } - Vector evaluateError(const T ¶ms, - boost::optional H = boost::none) const override { + Vector evaluateError(const T ¶ms, boost::optional H = + boost::none) const override { R x = func_(params, H); Vector error = traits::Local(measured_, x); return error; @@ -96,8 +96,9 @@ class GTSAM_EXPORT FunctorizedFactor : public NoiseModelFactor1 { /// @name Testable /// @{ - void print(const std::string &s = "", - const KeyFormatter &keyFormatter = DefaultKeyFormatter) const override { + void print( + const std::string &s = "", + const KeyFormatter &keyFormatter = DefaultKeyFormatter) const override { Base::print(s, keyFormatter); std::cout << s << (s != "" ? " " : "") << "FunctorizedFactor(" << keyFormatter(this->key()) << ")" << std::endl; @@ -144,4 +145,111 @@ FunctorizedFactor MakeFunctorizedFactor(Key key, const R &z, return FunctorizedFactor(key, z, model, func); } +/** + * Factor which evaluates provided binary functor and uses the result to compute + * error with respect to the provided measurement. + * + * Template parameters are + * @param R: The return type of the functor after evaluation. + * @param T1: The first argument type for the functor. + * @param T2: The second argument type for the functor. + */ +template +class GTSAM_EXPORT FunctorizedFactor2 : public NoiseModelFactor2 { + private: + using Base = NoiseModelFactor2; + + R measured_; ///< value that is compared with functor return value + SharedNoiseModel noiseModel_; ///< noise model + using FunctionType = std::function, + boost::optional)>; + FunctionType func_; ///< functor instance + + public: + /** default constructor - only use for serialization */ + FunctorizedFactor2() {} + + /** Construct with given x and the parameters of the basis + * + * @param key: Factor key + * @param z: Measurement object of same type as that returned by functor + * @param model: Noise model + * @param func: The instance of the functor object + */ + FunctorizedFactor2(Key key1, Key key2, const R &z, + const SharedNoiseModel &model, const FunctionType func) + : Base(model, key1, key2), + measured_(z), + noiseModel_(model), + func_(func) {} + + virtual ~FunctorizedFactor2() {} + + /// @return a deep copy of this factor + NonlinearFactor::shared_ptr clone() const override { + return boost::static_pointer_cast( + NonlinearFactor::shared_ptr(new FunctorizedFactor2(*this))); + } + + Vector evaluateError( + const T1 ¶ms1, const T2 ¶ms2, + boost::optional H1 = boost::none, + boost::optional H2 = boost::none) const override { + R x = func_(params1, params2, H1, H2); + Vector error = traits::Local(measured_, x); + return error; + } + + /// @name Testable + /// @{ + void print( + const std::string &s = "", + const KeyFormatter &keyFormatter = DefaultKeyFormatter) const override { + Base::print(s, keyFormatter); + std::cout << s << (s != "" ? " " : "") << "FunctorizedFactor2(" + << keyFormatter(this->key1()) << ", " + << keyFormatter(this->key2()) << ")" << std::endl; + traits::Print(measured_, " measurement: "); + std::cout << " noise model sigmas: " << noiseModel_->sigmas().transpose() + << std::endl; + } + + bool equals(const NonlinearFactor &other, double tol = 1e-9) const override { + const FunctorizedFactor2 *e = + dynamic_cast *>(&other); + return e && Base::equals(other, tol) && + traits::Equals(this->measured_, e->measured_, tol); + } + /// @} + + private: + /** Serialization function */ + friend class boost::serialization::access; + template + void serialize(ARCHIVE &ar, const unsigned int /*version*/) { + ar &boost::serialization::make_nvp( + "NoiseModelFactor2", boost::serialization::base_object(*this)); + ar &BOOST_SERIALIZATION_NVP(measured_); + ar &BOOST_SERIALIZATION_NVP(func_); + } +}; + +/// traits +template +struct traits> + : public Testable> {}; + +/** + * Helper function to create a functorized factor. + * + * Uses function template deduction to identify return type and functor type, so + * template list only needs the functor argument type. + */ +template +FunctorizedFactor2 MakeFunctorizedFactor2( + Key key1, Key key2, const R &z, const SharedNoiseModel &model, + const FUNC func) { + return FunctorizedFactor2(key1, key2, z, model, func); +} + } // namespace gtsam diff --git a/gtsam/nonlinear/tests/testFunctorizedFactor.cpp b/gtsam/nonlinear/tests/testFunctorizedFactor.cpp index cb91320cf..b0ec5e722 100644 --- a/gtsam/nonlinear/tests/testFunctorizedFactor.cpp +++ b/gtsam/nonlinear/tests/testFunctorizedFactor.cpp @@ -27,8 +27,15 @@ using namespace std; using namespace gtsam; +// Key for FunctorizedFactor Key key = Symbol('X', 0); + +// Keys for FunctorizedFactor2 +Key keyA = Symbol('A', 0); +Key keyx = Symbol('x', 0); + auto model = noiseModel::Isotropic::Sigma(9, 1); +auto model2 = noiseModel::Isotropic::Sigma(3, 1); /// Functor that takes a matrix and multiplies every element by m class MultiplyFunctor { @@ -44,6 +51,21 @@ class MultiplyFunctor { } }; +/// Functor that performs Ax where A is a matrix and x is a vector. +class ProjectionFunctor { + public: + Vector operator()(const Matrix &A, const Vector &x, + OptionalJacobian<-1, -1> H1 = boost::none, + OptionalJacobian<-1, -1> H2 = boost::none) const { + if (H1) { + H1->resize(x.size(), A.size()); + *H1 << I_3x3, I_3x3, I_3x3; + } + if (H2) *H2 = A; + return A * x; + } +}; + /* ************************************************************************* */ // Test identity operation for FunctorizedFactor. TEST(FunctorizedFactor, Identity) { @@ -88,7 +110,7 @@ TEST(FunctorizedFactor, Equality) { EXPECT(factor1.equals(factor2)); } -/* *************************************************************************** */ +/* ************************************************************************* */ // Test Jacobians of FunctorizedFactor. TEST(FunctorizedFactor, Jacobians) { Matrix X = Matrix::Identity(3, 3); @@ -168,6 +190,83 @@ TEST(FunctorizedFactor, Lambda) { EXPECT(assert_equal(Vector::Zero(9), error, 1e-9)); } +/* ************************************************************************* */ +// Test identity operation for FunctorizedFactor2. +TEST(FunctorizedFactor, Identity2) { + // x = Ax since A is I_3x3 + Matrix A = Matrix::Identity(3, 3); + Vector x = Vector::Ones(3); + + auto functor = ProjectionFunctor(); + auto factor = + MakeFunctorizedFactor2(keyA, keyx, x, model2, functor); + + Vector error = factor.evaluateError(A, x); + + EXPECT(assert_equal(Vector::Zero(3), error, 1e-9)); +} + +/* ************************************************************************* */ +// Test Jacobians of FunctorizedFactor2. +TEST(FunctorizedFactor, Jacobians2) { + Matrix A = Matrix::Identity(3, 3); + Vector x = Vector::Ones(3); + Matrix actualH1, actualH2; + + auto factor = MakeFunctorizedFactor2(keyA, keyx, x, model2, + ProjectionFunctor()); + + Values values; + values.insert(keyA, A); + values.insert(keyx, x); + + // Check Jacobians + EXPECT_CORRECT_FACTOR_JACOBIANS(factor, values, 1e-7, 1e-5); +} + +/* ************************************************************************* */ +// Test FunctorizedFactor2 using a std::function type. +TEST(FunctorizedFactor, Functional2) { + Matrix A = Matrix::Identity(3, 3); + Vector3 x(1, 2, 3); + Vector measurement = A * x; + + std::function, + boost::optional)> + functional = ProjectionFunctor(); + auto factor = MakeFunctorizedFactor2(keyA, keyx, measurement, + model2, functional); + + Vector error = factor.evaluateError(A, x); + + EXPECT(assert_equal(Vector::Zero(3), error, 1e-9)); +} + +/* ************************************************************************* */ +// Test FunctorizedFactor2 with a lambda function. +TEST(FunctorizedFactor, Lambda2) { + Matrix A = Matrix::Identity(3, 3); + Vector3 x = Vector3(1, 2, 3); + Matrix measurement = A * x; + + auto lambda = [](const Matrix &A, const Vector &x, + OptionalJacobian<-1, -1> H1 = boost::none, + OptionalJacobian<-1, -1> H2 = boost::none) { + if (H1) { + H1->resize(x.size(), A.size()); + *H1 << I_3x3, I_3x3, I_3x3; + } + if (H2) *H2 = A; + return A * x; + }; + // FunctorizedFactor factor(key, measurement, model, lambda); + auto factor = MakeFunctorizedFactor2(keyA, keyx, measurement, model2, lambda); + + Vector error = factor.evaluateError(A, x); + + EXPECT(assert_equal(Vector::Zero(3), error, 1e-9)); +} + /* ************************************************************************* */ int main() { TestResult tr; From 19b7312edbc0a934b5d7b3f61b4edcc6dd2b3e19 Mon Sep 17 00:00:00 2001 From: Toni Date: Sun, 17 Jan 2021 11:08:53 -0500 Subject: [PATCH 238/261] Split .h/.cpp, use const& (WIP) --- examples/CMakeLists.txt | 2 +- gtsam/slam/SmartFactorBase.h | 6 +- .../slam/SmartStereoProjectionPoseFactor.cpp | 97 ++++++++++++ .../slam/SmartStereoProjectionPoseFactor.h | 147 +++++++----------- 4 files changed, 159 insertions(+), 93 deletions(-) create mode 100644 gtsam_unstable/slam/SmartStereoProjectionPoseFactor.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 476f4ae21..7fc33f921 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,4 +2,4 @@ set (excluded_examples elaboratePoint2KalmanFilter.cpp ) -gtsamAddExamplesGlob("*.cpp" "${excluded_examples}" "gtsam;${Boost_PROGRAM_OPTIONS_LIBRARY}") +gtsamAddExamplesGlob("*.cpp" "${excluded_examples}" "gtsam;gtsam_unstable;${Boost_PROGRAM_OPTIONS_LIBRARY}") diff --git a/gtsam/slam/SmartFactorBase.h b/gtsam/slam/SmartFactorBase.h index d9f2b9c3d..85f9e7c3f 100644 --- a/gtsam/slam/SmartFactorBase.h +++ b/gtsam/slam/SmartFactorBase.h @@ -13,6 +13,7 @@ * @file SmartFactorBase.h * @brief Base class to create smart factors on poses or cameras * @author Luca Carlone + * @author Antoni Rosinol * @author Zsolt Kira * @author Frank Dellaert * @author Chris Beall @@ -131,9 +132,10 @@ protected: /** * Add a bunch of measurements, together with the camera keys */ - void add(ZVector& measurements, KeyVector& cameraKeys) { + void add(const ZVector& measurements, const KeyVector& cameraKeys) { + assert(measurements.size() == cameraKeys.size()); for (size_t i = 0; i < measurements.size(); i++) { - this->add(measurements.at(i), cameraKeys.at(i)); + this->add(measurements[i], cameraKeys[i]); } } diff --git a/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.cpp b/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.cpp new file mode 100644 index 000000000..c28cb25a1 --- /dev/null +++ b/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.cpp @@ -0,0 +1,97 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file SmartStereoProjectionPoseFactor.cpp + * @brief Smart stereo factor on poses, assuming camera calibration is fixed + * @author Luca Carlone + * @author Antoni Rosinol + * @author Chris Beall + * @author Zsolt Kira + * @author Frank Dellaert + */ + +#include + +namespace gtsam { + +SmartStereoProjectionPoseFactor::SmartStereoProjectionPoseFactor( + const SharedNoiseModel& sharedNoiseModel, + const SmartStereoProjectionParams& params, + const boost::optional& body_P_sensor) + : Base(sharedNoiseModel, params, body_P_sensor) {} + +void SmartStereoProjectionPoseFactor::add( + const StereoPoint2& measured, const Key& poseKey, + const boost::shared_ptr& K) { + Base::add(measured, poseKey); + K_all_.push_back(K); +} + +void SmartStereoProjectionPoseFactor::add( + const std::vector& measurements, const KeyVector& poseKeys, + const std::vector>& Ks) { + assert(measurements.size() == poseKeys.size()); + assert(poseKeys.size() == Ks.size()); + Base::add(measurements, poseKeys); + K_all_.insert(K_all_.end(), Ks.begin(), Ks.end()); +} + +void SmartStereoProjectionPoseFactor::add( + const std::vector& measurements, const KeyVector& poseKeys, + const boost::shared_ptr& K) { + assert(poseKeys.size() == measurements.size()); + for (size_t i = 0; i < measurements.size(); i++) { + Base::add(measurements[i], poseKeys[i]); + K_all_.push_back(K); + } +} + +void SmartStereoProjectionPoseFactor::print( + const std::string& s, const KeyFormatter& keyFormatter) const { + std::cout << s << "SmartStereoProjectionPoseFactor, z = \n "; + for (const boost::shared_ptr& K : K_all_) { + K->print("calibration = "); + } + Base::print("", keyFormatter); +} + +bool SmartStereoProjectionPoseFactor::equals(const NonlinearFactor& p, + double tol) const { + const SmartStereoProjectionPoseFactor* e = + dynamic_cast(&p); + + return e && Base::equals(p, tol); +} + +double SmartStereoProjectionPoseFactor::error(const Values& values) const { + if (this->active(values)) { + return this->totalReprojectionError(cameras(values)); + } else { // else of active flag + return 0.0; + } +} + +SmartStereoProjectionPoseFactor::Base::Cameras +SmartStereoProjectionPoseFactor::cameras(const Values& values) const { + assert(keys_.size() == K_all_.size()); + Base::Cameras cameras; + for (size_t i = 0; i < keys_.size(); i++) { + Pose3 pose = values.at(keys_[i]); + if (Base::body_P_sensor_) { + pose = pose.compose(*(Base::body_P_sensor_)); + } + cameras.push_back(StereoCamera(pose, K_all_[i])); + } + return cameras; +} + +} // \ namespace gtsam diff --git a/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h b/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h index 124e45005..31ee121ff 100644 --- a/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h +++ b/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h @@ -1,6 +1,7 @@ /* ---------------------------------------------------------------------------- - * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * GTSAM Copyright 2010, Georgia Tech Research Corpo + * ation, * Atlanta, Georgia 30332-0415 * All Rights Reserved * Authors: Frank Dellaert, et al. (see THANKS for the full author list) @@ -13,6 +14,7 @@ * @file SmartStereoProjectionPoseFactor.h * @brief Smart stereo factor on poses, assuming camera calibration is fixed * @author Luca Carlone + * @author Antoni Rosinol * @author Chris Beall * @author Zsolt Kira * @author Frank Dellaert @@ -28,8 +30,10 @@ namespace gtsam { * @addtogroup SLAM * * If you are using the factor, please cite: - * L. Carlone, Z. Kira, C. Beall, V. Indelman, F. Dellaert, Eliminating conditionally - * independent sets in factor graphs: a unifying perspective based on smart factors, + * L. Carlone, Z. Kira, C. Beall, V. Indelman, F. Dellaert, Eliminating + * conditionally + * independent sets in factor graphs: a unifying perspective based on smart + * factors, * Int. Conf. on Robotics and Automation (ICRA), 2014. * */ @@ -41,14 +45,12 @@ namespace gtsam { * This factor requires that values contains the involved poses (Pose3). * @addtogroup SLAM */ -class SmartStereoProjectionPoseFactor: public SmartStereoProjectionFactor { - -protected: - - std::vector > K_all_; ///< shared pointer to calibration object (one for each camera) - -public: +class SmartStereoProjectionPoseFactor : public SmartStereoProjectionFactor { + protected: + /// shared pointer to calibration object (one for each camera) + std::vector> K_all_; + public: EIGEN_MAKE_ALIGNED_OPERATOR_NEW /// shorthand for base class type @@ -65,129 +67,94 @@ public: * @param Isotropic measurement noise * @param params internal parameters of the smart factors */ - SmartStereoProjectionPoseFactor(const SharedNoiseModel& sharedNoiseModel, + SmartStereoProjectionPoseFactor( + const SharedNoiseModel& sharedNoiseModel, const SmartStereoProjectionParams& params = SmartStereoProjectionParams(), - const boost::optional body_P_sensor = boost::none) : - Base(sharedNoiseModel, params, body_P_sensor) { - } + const boost::optional& body_P_sensor = boost::none); /** Virtual destructor */ - virtual ~SmartStereoProjectionPoseFactor() {} + virtual ~SmartStereoProjectionPoseFactor() = default; /** * add a new measurement and pose key - * @param measured is the 2m dimensional location of the projection of a single landmark in the m view (the measurement) - * @param poseKey is key corresponding to the camera observing the same landmark + * @param measured is the 2m dimensional location of the projection of a + * single landmark in the m view (the measurement) + * @param poseKey is key corresponding to the camera observing the same + * landmark * @param K is the (fixed) camera calibration */ - void add(const StereoPoint2 measured, const Key poseKey, - const boost::shared_ptr K) { - Base::add(measured, poseKey); - K_all_.push_back(K); - } + void add(const StereoPoint2& measured, const Key& poseKey, + const boost::shared_ptr& K); /** * Variant of the previous one in which we include a set of measurements - * @param measurements vector of the 2m dimensional location of the projection of a single landmark in the m view (the measurement) - * @param poseKeys vector of keys corresponding to the camera observing the same landmark + * @param measurements vector of the 2m dimensional location of the projection + * of a single landmark in the m view (the measurement) + * @param poseKeys vector of keys corresponding to the camera observing + * the same landmark * @param Ks vector of calibration objects */ - void add(std::vector measurements, KeyVector poseKeys, - std::vector > Ks) { - Base::add(measurements, poseKeys); - for (size_t i = 0; i < measurements.size(); i++) { - K_all_.push_back(Ks.at(i)); - } - } + void add(const std::vector& measurements, + const KeyVector& poseKeys, + const std::vector>& Ks); /** - * Variant of the previous one in which we include a set of measurements with the same noise and calibration - * @param measurements vector of the 2m dimensional location of the projection of a single landmark in the m view (the measurement) - * @param poseKeys vector of keys corresponding to the camera observing the same landmark + * Variant of the previous one in which we include a set of measurements with + * the same noise and calibration + * @param measurements vector of the 2m dimensional location of the projection + * of a single landmark in the m view (the measurement) + * @param poseKeys vector of keys corresponding to the camera observing the + * same landmark * @param K the (known) camera calibration (same for all measurements) */ - void add(std::vector measurements, KeyVector poseKeys, - const boost::shared_ptr K) { - for (size_t i = 0; i < measurements.size(); i++) { - Base::add(measurements.at(i), poseKeys.at(i)); - K_all_.push_back(K); - } - } + void add(const std::vector& measurements, + const KeyVector& poseKeys, + const boost::shared_ptr& K); /** * print * @param s optional string naming the factor * @param keyFormatter optional formatter useful for printing Symbols - */ - void print(const std::string& s = "", const KeyFormatter& keyFormatter = - DefaultKeyFormatter) const override { - std::cout << s << "SmartStereoProjectionPoseFactor, z = \n "; - for(const boost::shared_ptr& K: K_all_) - K->print("calibration = "); - Base::print("", keyFormatter); - } + */ void print( + const std::string& s = "", + const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override; /// equals - bool equals(const NonlinearFactor& p, double tol = 1e-9) const override { - const SmartStereoProjectionPoseFactor *e = - dynamic_cast(&p); - - return e && Base::equals(p, tol); - } + virtual bool equals(const NonlinearFactor& p, double tol = 1e-9) const; /** * error calculates the error of the factor. */ - double error(const Values& values) const override { - if (this->active(values)) { - return this->totalReprojectionError(cameras(values)); - } else { // else of active flag - return 0.0; - } - } + double error(const Values& values) const override; /** return the calibration object */ - inline const std::vector > calibration() const { + inline std::vector> calibration() const { return K_all_; } /** * Collect all cameras involved in this factor - * @param values Values structure which must contain camera poses corresponding + * @param values Values structure which must contain camera poses + * corresponding * to keys involved in this factor * @return vector of Values */ - Base::Cameras cameras(const Values& values) const override { - Base::Cameras cameras; - size_t i=0; - for(const Key& k: this->keys_) { - Pose3 pose = values.at(k); - - if (Base::body_P_sensor_) - pose = pose.compose(*(Base::body_P_sensor_)); - - StereoCamera camera(pose, K_all_[i++]); - cameras.push_back(camera); - } - return cameras; - } - -private: + Base::Cameras cameras(const Values& values) const override; + private: /// Serialization function friend class boost::serialization::access; - template - void serialize(ARCHIVE & ar, const unsigned int /*version*/) { - ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); - ar & BOOST_SERIALIZATION_NVP(K_all_); + template + void serialize(ARCHIVE& ar, const unsigned int /*version*/) { + ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); + ar& BOOST_SERIALIZATION_NVP(K_all_); } -}; // end of class declaration +}; // end of class declaration /// traits -template<> -struct traits : public Testable< - SmartStereoProjectionPoseFactor> { -}; +template <> +struct traits + : public Testable {}; -} // \ namespace gtsam +} // \ namespace gtsam From 35aeaf5246c18ef86d8dc2b4f0470c909766b59b Mon Sep 17 00:00:00 2001 From: Jose-Luis Blanco Claraco Date: Sun, 17 Jan 2021 22:19:54 +0100 Subject: [PATCH 239/261] CMake scripts compatible with gtsam as git submodule --- CMakeLists.txt | 2 +- cmake/Config.cmake.in | 4 ++-- cmake/GtsamBuildTypes.cmake | 6 +++--- cmake/GtsamMatlabWrap.cmake | 25 ++++++++++++------------- cmake/HandleEigen.cmake | 2 +- gtsam/CMakeLists.txt | 14 +++++++------- 6 files changed, 26 insertions(+), 27 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c39089c1..b19ece0e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ include(GtsamTesting) include(GtsamPrinting) # guard against in-source builds -if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) +if(${GTSAM_SOURCE_DIR} STREQUAL ${GTSAM_BINARY_DIR}) message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ") endif() diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in index 9bd188037..89627a172 100644 --- a/cmake/Config.cmake.in +++ b/cmake/Config.cmake.in @@ -6,7 +6,7 @@ get_filename_component(OUR_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) if(EXISTS "${OUR_CMAKE_DIR}/CMakeCache.txt") # In build tree - set(@PACKAGE_NAME@_INCLUDE_DIR @CMAKE_SOURCE_DIR@ CACHE PATH "@PACKAGE_NAME@ include directory") + set(@PACKAGE_NAME@_INCLUDE_DIR @GTSAM_SOURCE_DIR@ CACHE PATH "@PACKAGE_NAME@ include directory") else() # Find installed library set(@PACKAGE_NAME@_INCLUDE_DIR "${OUR_CMAKE_DIR}/@CONF_REL_INCLUDE_DIR@" CACHE PATH "@PACKAGE_NAME@ include directory") @@ -15,7 +15,7 @@ endif() # Find dependencies, required by cmake exported targets: include(CMakeFindDependencyMacro) # Allow using cmake < 3.8 -if(${CMAKE_VERSION} VERSION_LESS "3.8.0") +if(${CMAKE_VERSION} VERSION_LESS "3.8.0") find_package(Boost @BOOST_FIND_MINIMUM_VERSION@ COMPONENTS @BOOST_FIND_MINIMUM_COMPONENTS@) else() find_dependency(Boost @BOOST_FIND_MINIMUM_VERSION@ COMPONENTS @BOOST_FIND_MINIMUM_COMPONENTS@) diff --git a/cmake/GtsamBuildTypes.cmake b/cmake/GtsamBuildTypes.cmake index 3155161be..1262c6935 100644 --- a/cmake/GtsamBuildTypes.cmake +++ b/cmake/GtsamBuildTypes.cmake @@ -204,9 +204,9 @@ endif() # Make common binary output directory when on Windows if(WIN32) - set(RUNTIME_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin") - set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin") - set(LIBRARY_OUTPUT_PATH "${CMAKE_BINARY_DIR}/lib") + set(RUNTIME_OUTPUT_PATH "${GTSAM_BINARY_DIR}/bin") + set(EXECUTABLE_OUTPUT_PATH "${GTSAM_BINARY_DIR}/bin") + set(LIBRARY_OUTPUT_PATH "${GTSAM_BINARY_DIR}/lib") endif() # Set up build type list for cmake-gui diff --git a/cmake/GtsamMatlabWrap.cmake b/cmake/GtsamMatlabWrap.cmake index b76f96a4e..2be0c61a8 100644 --- a/cmake/GtsamMatlabWrap.cmake +++ b/cmake/GtsamMatlabWrap.cmake @@ -146,7 +146,7 @@ function(wrap_library_internal interfaceHeader linkLibraries extraIncludeDirs ex endif() endif() endforeach() - + ## CHRIS: Temporary fix. On my system the get_target_property above returned Not-found for gtsam module ## This needs to be fixed!! if(UNIX AND NOT APPLE) @@ -159,7 +159,7 @@ function(wrap_library_internal interfaceHeader linkLibraries extraIncludeDirs ex endif() endif() endif() - + #message("AUTOMATIC DEPENDENCIES: ${automaticDependencies}") ## CHRIS: End temporary fix @@ -213,7 +213,7 @@ function(wrap_library_internal interfaceHeader linkLibraries extraIncludeDirs ex endif() endif() endforeach() - + # Check libraries for conflicting versions built-in to MATLAB set(dependentLibraries "") if(NOT "${otherLibraryTargets}" STREQUAL "") @@ -257,7 +257,7 @@ function(wrap_library_internal interfaceHeader linkLibraries extraIncludeDirs ex --ignore ${_ignore} VERBATIM WORKING_DIRECTORY ${generated_files_path}) - + # Set up building of mex module string(REPLACE ";" " " extraMexFlagsSpaced "${extraMexFlags}") string(REPLACE ";" " " mexFlagsSpaced "${GTSAM_BUILD_MEX_BINARY_FLAGS}") @@ -295,8 +295,8 @@ function(wrap_library_internal interfaceHeader linkLibraries extraIncludeDirs ex endif() # Hacking around output issue with custom command - # Deletes generated build folder - add_custom_target(wrap_${moduleName}_matlab_distclean + # Deletes generated build folder + add_custom_target(wrap_${moduleName}_matlab_distclean COMMAND cmake -E remove_directory ${generated_files_path} COMMAND cmake -E remove_directory ${compiled_mex_modules_root}) endfunction() @@ -347,17 +347,17 @@ function(check_conflicting_libraries_internal libraries) set(mxLibPath "${MATLAB_ROOT}/bin/glnx86") endif() endif() - + # List matlab's built-in libraries file(GLOB matlabLibs RELATIVE "${mxLibPath}" "${mxLibPath}/lib*") - + # Convert to base names set(matlabLibNames "") foreach(lib ${matlabLibs}) get_filename_component(libName "${lib}" NAME_WE) list(APPEND matlabLibNames "${libName}") endforeach() - + # Get names of link libraries set(linkLibNames "") foreach(lib ${libraries}) @@ -379,10 +379,10 @@ function(check_conflicting_libraries_internal libraries) endif() endif() endforeach() - + # Remove duplicates list(REMOVE_DUPLICATES linkLibNames) - + set(conflictingLibs "") foreach(lib ${linkLibNames}) list(FIND matlabLibNames "${lib}" libPos) @@ -393,7 +393,7 @@ function(check_conflicting_libraries_internal libraries) set(conflictingLibs "${conflictingLibs}${lib}") endif() endforeach() - + if(NOT "${conflictingLibs}" STREQUAL "") message(WARNING "GTSAM links to the libraries [ ${conflictingLibs} ] on your system, but " "MATLAB is distributed with its own versions of these libraries which may conflict. " @@ -435,4 +435,3 @@ function(install_matlab_scripts source_directory patterns) endif() endfunction() - diff --git a/cmake/HandleEigen.cmake b/cmake/HandleEigen.cmake index fda441907..b21d16885 100644 --- a/cmake/HandleEigen.cmake +++ b/cmake/HandleEigen.cmake @@ -42,7 +42,7 @@ else() set(GTSAM_EIGEN_INCLUDE_FOR_INSTALL "include/gtsam/3rdparty/Eigen/") # The actual include directory (for BUILD cmake target interface): - set(GTSAM_EIGEN_INCLUDE_FOR_BUILD "${CMAKE_SOURCE_DIR}/gtsam/3rdparty/Eigen/") + set(GTSAM_EIGEN_INCLUDE_FOR_BUILD "${GTSAM_SOURCE_DIR}/gtsam/3rdparty/Eigen/") endif() # Detect Eigen version: diff --git a/gtsam/CMakeLists.txt b/gtsam/CMakeLists.txt index e0e037f52..11ae113b9 100644 --- a/gtsam/CMakeLists.txt +++ b/gtsam/CMakeLists.txt @@ -134,15 +134,15 @@ endif() # of any previously installed GTSAM headers. target_include_directories(gtsam BEFORE PUBLIC # main gtsam includes: - $ + $ $ # config.h - $ + $ # unit tests: - $ + $ ) # 3rdparty libraries: use the "system" flag so they are included via "-isystem" -# and warnings (and warnings-considered-errors) in those headers are not +# and warnings (and warnings-considered-errors) in those headers are not # reported as warnings/errors in our targets: target_include_directories(gtsam SYSTEM BEFORE PUBLIC # SuiteSparse_config @@ -156,9 +156,9 @@ target_include_directories(gtsam SYSTEM BEFORE PUBLIC ) if(GTSAM_SUPPORT_NESTED_DISSECTION) target_include_directories(gtsam BEFORE PUBLIC - $ - $ - $ + $ + $ + $ $ ) endif() From 09a2e2ebd46a459099ef2a9a1663e0f9783cd61b Mon Sep 17 00:00:00 2001 From: Ayush Baid Date: Mon, 18 Jan 2021 09:52:02 -0500 Subject: [PATCH 240/261] changing robust noise model to Gaussian --- gtsam/sfm/ShonanAveraging.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gtsam/sfm/ShonanAveraging.cpp b/gtsam/sfm/ShonanAveraging.cpp index 5957047a3..a0e615e9b 100644 --- a/gtsam/sfm/ShonanAveraging.cpp +++ b/gtsam/sfm/ShonanAveraging.cpp @@ -880,9 +880,7 @@ static BinaryMeasurement convert( "parseMeasurements can only convert Pose3 measurements " "with Gaussian noise models."); const Matrix6 M = gaussian->covariance(); - auto model = noiseModel::Robust::Create( - noiseModel::mEstimator::Huber::Create(1.345), - noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3))); + auto model = noiseModel::Gaussian::Covariance(M.block<3, 3>(3, 3)); return BinaryMeasurement(f->key1(), f->key2(), f->measured().rotation(), model); } From a567a570ede8a8e1ba641eba4b5245af5a2d045e Mon Sep 17 00:00:00 2001 From: Toni Date: Mon, 18 Jan 2021 14:41:28 -0500 Subject: [PATCH 241/261] Move example to gtsam_unstable --- .../examples}/ISAM2_SmartFactorStereo_IMU.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {examples => gtsam_unstable/examples}/ISAM2_SmartFactorStereo_IMU.cpp (100%) diff --git a/examples/ISAM2_SmartFactorStereo_IMU.cpp b/gtsam_unstable/examples/ISAM2_SmartFactorStereo_IMU.cpp similarity index 100% rename from examples/ISAM2_SmartFactorStereo_IMU.cpp rename to gtsam_unstable/examples/ISAM2_SmartFactorStereo_IMU.cpp From 5ad65ed46c8883d77eab27487d81afc6ed6e4842 Mon Sep 17 00:00:00 2001 From: Toni Date: Mon, 18 Jan 2021 14:41:59 -0500 Subject: [PATCH 242/261] Fix formatting --- gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h b/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h index 31ee121ff..f014a6917 100644 --- a/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h +++ b/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h @@ -1,7 +1,6 @@ /* ---------------------------------------------------------------------------- - * GTSAM Copyright 2010, Georgia Tech Research Corpo - * ation, + * GTSAM Copyright 2010, Georgia Tech Research Corpoation, * Atlanta, Georgia 30332-0415 * All Rights Reserved * Authors: Frank Dellaert, et al. (see THANKS for the full author list) @@ -30,10 +29,9 @@ namespace gtsam { * @addtogroup SLAM * * If you are using the factor, please cite: - * L. Carlone, Z. Kira, C. Beall, V. Indelman, F. Dellaert, Eliminating - * conditionally - * independent sets in factor graphs: a unifying perspective based on smart - * factors, + * L. Carlone, Z. Kira, C. Beall, V. Indelman, F. Dellaert, + * Eliminating conditionally independent sets in factor graphs: + * a unifying perspective based on smart factors, * Int. Conf. on Robotics and Automation (ICRA), 2014. * */ From 3d7e182822d96f000479aabd317250deb85e25c8 Mon Sep 17 00:00:00 2001 From: Toni Date: Mon, 18 Jan 2021 14:47:39 -0500 Subject: [PATCH 243/261] Remove gtsam_unstable lib from examples --- examples/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 7fc33f921..476f4ae21 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,4 +2,4 @@ set (excluded_examples elaboratePoint2KalmanFilter.cpp ) -gtsamAddExamplesGlob("*.cpp" "${excluded_examples}" "gtsam;gtsam_unstable;${Boost_PROGRAM_OPTIONS_LIBRARY}") +gtsamAddExamplesGlob("*.cpp" "${excluded_examples}" "gtsam;${Boost_PROGRAM_OPTIONS_LIBRARY}") From 96dc9bfa5a4deaaae79feaa7f9c869358e4a8386 Mon Sep 17 00:00:00 2001 From: Toni Date: Mon, 18 Jan 2021 14:48:19 -0500 Subject: [PATCH 244/261] Fix formatting --- gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h b/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h index f014a6917..93a83ab30 100644 --- a/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h +++ b/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h @@ -1,6 +1,6 @@ /* ---------------------------------------------------------------------------- - * GTSAM Copyright 2010, Georgia Tech Research Corpoation, + * GTSAM Copyright 2010, Georgia Tech Research Corporation, * Atlanta, Georgia 30332-0415 * All Rights Reserved * Authors: Frank Dellaert, et al. (see THANKS for the full author list) From 56e9b3ac9ffa2edac339ce54af4cafeac0467b26 Mon Sep 17 00:00:00 2001 From: Gerry Chen Date: Mon, 18 Jan 2021 21:10:52 -0500 Subject: [PATCH 245/261] Mandy+Fan's original code for converting sparse matrices to Eigen format --- gtsam/linear/SparseEigenSolver.cpp | 231 +++++++++++++++++++++++++++++ gtsam/linear/SparseEigenSolver.h | 62 ++++++++ 2 files changed, 293 insertions(+) create mode 100644 gtsam/linear/SparseEigenSolver.cpp create mode 100644 gtsam/linear/SparseEigenSolver.h diff --git a/gtsam/linear/SparseEigenSolver.cpp b/gtsam/linear/SparseEigenSolver.cpp new file mode 100644 index 000000000..f0dfd83f3 --- /dev/null +++ b/gtsam/linear/SparseEigenSolver.cpp @@ -0,0 +1,231 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file SparseEigenSolver.cpp + * + * @brief Eigen SparseSolver based linear solver backend for GTSAM + * + * @date Aug 2019 + * @author Mandy Xie + * @author Fan Jiang + * @author Frank Dellaert + */ + +#include +#include +#include + +#include + +using namespace std; + +namespace gtsam { + + using SpMat = Eigen::SparseMatrix; + + Eigen::SparseMatrix + SparseEigenSolver::sparseJacobianEigen( + const GaussianFactorGraph &gfg, + const Ordering &ordering) { + // First find dimensions of each variable + std::map dims; + for (const boost::shared_ptr &factor : gfg) { + if (!static_cast(factor)) + continue; + + for (auto it = factor->begin(); it != factor->end(); ++it) { + dims[*it] = factor->getDim(it); + } + } + + // Compute first scalar column of each variable + size_t currentColIndex = 0; + std::map columnIndices; + for (const auto key : ordering) { + columnIndices[key] = currentColIndex; + currentColIndex += dims[key]; + } + + // Iterate over all factors, adding sparse scalar entries + vector> entries; + entries.reserve(60 * gfg.size()); + + size_t row = 0; + for (const boost::shared_ptr &factor : gfg) { + if (!static_cast(factor)) continue; + + // Convert to JacobianFactor if necessary + JacobianFactor::shared_ptr jacobianFactor( + boost::dynamic_pointer_cast(factor)); + if (!jacobianFactor) { + HessianFactor::shared_ptr hessian( + boost::dynamic_pointer_cast(factor)); + if (hessian) + jacobianFactor.reset(new JacobianFactor(*hessian)); + else + throw invalid_argument( + "GaussianFactorGraph contains a factor that is neither a JacobianFactor nor a HessianFactor."); + } + + // Whiten the factor and add entries for it + // iterate over all variables in the factor + const JacobianFactor whitened(jacobianFactor->whiten()); + for (JacobianFactor::const_iterator key = whitened.begin(); + key < whitened.end(); ++key) { + JacobianFactor::constABlock whitenedA = whitened.getA(key); + // find first column index for this key + size_t column_start = columnIndices[*key]; + for (size_t i = 0; i < (size_t) whitenedA.rows(); i++) + for (size_t j = 0; j < (size_t) whitenedA.cols(); j++) { + double s = whitenedA(i, j); + if (std::abs(s) > 1e-12) + entries.emplace_back(row + i, column_start + j, s); + } + } + + JacobianFactor::constBVector whitenedb(whitened.getb()); + size_t bcolumn = currentColIndex; + for (size_t i = 0; i < (size_t) whitenedb.size(); i++) { + double s = whitenedb(i); + if (std::abs(s) > 1e-12) + entries.emplace_back(row + i, bcolumn, s); + } + + // Increment row index + row += jacobianFactor->rows(); + } + + // ...and make a sparse matrix with it. + Eigen::SparseMatrix Ab(row + 1, currentColIndex + 1); + Ab.setFromTriplets(entries.begin(), entries.end()); + return Ab; + } + + + /// obtain sparse matrix for eigen sparse solver + std::pair obtainSparseMatrix( + const GaussianFactorGraph &gfg, + const Ordering &ordering) { + + gttic_(EigenOptimizer_obtainSparseMatrix); + + // Get sparse entries of Jacobian [A|b] augmented with RHS b. + auto entries = gfg.sparseJacobian(ordering); + + gttic_(EigenOptimizer_convertSparse); + // Convert boost tuples to Eigen triplets + vector> triplets; + triplets.reserve(entries.size()); + size_t rows = 0, cols = 0; + for (const auto &e : entries) { + size_t temp_rows = e.get<0>(), temp_cols = e.get<1>(); + triplets.emplace_back(temp_rows, temp_cols, e.get<2>()); + rows = std::max(rows, temp_rows); + cols = std::max(cols, temp_cols); + } + + // ...and make a sparse matrix with it. + SpMat Ab(rows + 1, cols + 1); + Ab.setFromTriplets(triplets.begin(), triplets.end()); + Ab.makeCompressed(); + gttoc_(EigenOptimizer_convertSparse); + + gttoc_(EigenOptimizer_obtainSparseMatrix); + + return make_pair(Ab.block(0, 0, rows + 1, cols), + Ab.col(cols)); + } + + bool SparseEigenSolver::isIterative() { + return false; + } + + bool SparseEigenSolver::isSequential() { + return false; + } + + VectorValues SparseEigenSolver::solve(const GaussianFactorGraph &gfg) { + if (solverType == QR) { + gttic_(EigenOptimizer_optimizeEigenQR); + auto Ab_pair = obtainSparseMatrix(gfg, ordering); + + // Solve A*x = b using sparse QR from Eigen + gttic_(EigenOptimizer_optimizeEigenQR_create_solver); + Eigen::SparseQR> solver(Ab_pair.first); + gttoc_(EigenOptimizer_optimizeEigenQR_create_solver); + + gttic_(EigenOptimizer_optimizeEigenQR_solve); + Eigen::VectorXd x = solver.solve(Ab_pair.second); + gttoc_(EigenOptimizer_optimizeEigenQR_solve); + + return VectorValues(x, gfg.getKeyDimMap()); + } else if (solverType == CHOLESKY) { + gttic_(EigenOptimizer_optimizeEigenCholesky); + SpMat Ab = sparseJacobianEigen(gfg, ordering); + auto rows = Ab.rows(), cols = Ab.cols(); + auto A = Ab.block(0, 0, rows, cols - 1); + auto At = A.transpose(); + auto b = Ab.col(cols - 1); + + SpMat AtA(A.cols(), A.cols()); + AtA.selfadjointView().rankUpdate(At); + + gttic_(EigenOptimizer_optimizeEigenCholesky_create_solver); + // Solve A*x = b using sparse Cholesky from Eigen + Eigen::SimplicialLDLT> + solver(AtA); + + gttoc_(EigenOptimizer_optimizeEigenCholesky_create_solver); + + gttic_(EigenOptimizer_optimizeEigenCholesky_solve); + Eigen::VectorXd x = solver.solve(At * b); + gttoc_(EigenOptimizer_optimizeEigenCholesky_solve); + + // NOTE: b is reordered now, so we need to transform back the order. + // First find dimensions of each variable + std::map dims; + for (const boost::shared_ptr &factor : gfg) { + if (!static_cast(factor)) + continue; + + for (auto it = factor->begin(); it != factor->end(); ++it) { + dims[*it] = factor->getDim(it); + } + } + + VectorValues vv; + + std::map columnIndices; + + { + size_t currentColIndex = 0; + for (const auto key : ordering) { + columnIndices[key] = currentColIndex; + currentColIndex += dims[key]; + } + } + + for (const pair keyDim : dims) { + vv.insert(keyDim.first, x.segment(columnIndices[keyDim.first], keyDim.second)); + } + + return vv; + } + + throw std::exception(); + } + + SparseEigenSolver::SparseEigenSolver(SparseEigenSolver::SparseEigenSolverType type, const Ordering &ordering) { + solverType = type; + this->ordering = ordering; + } +} // namespace gtsam \ No newline at end of file diff --git a/gtsam/linear/SparseEigenSolver.h b/gtsam/linear/SparseEigenSolver.h new file mode 100644 index 000000000..d71365864 --- /dev/null +++ b/gtsam/linear/SparseEigenSolver.h @@ -0,0 +1,62 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file SparseEigenSolver.h + * + * @brief Eigen SparseSolver based linear solver backend for GTSAM + * + * @date Aug 2019 + * @author Mandy Xie + * @author Fan Jiang + * @author Frank Dellaert + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace gtsam { + + /** + * Eigen SparseSolver based Backend class + */ + class GTSAM_EXPORT SparseEigenSolver : public LinearSolver { + public: + + typedef enum { + QR, + CHOLESKY + } SparseEigenSolverType; + + + explicit SparseEigenSolver(SparseEigenSolver::SparseEigenSolverType type, const Ordering &ordering); + + bool isIterative() override; + + bool isSequential() override; + + VectorValues solve(const GaussianFactorGraph &gfg) override; + + static Eigen::SparseMatrix + sparseJacobianEigen(const GaussianFactorGraph &gfg, const Ordering &ordering); + + protected: + + SparseEigenSolverType solverType = QR; + + Ordering ordering; + }; +} // namespace gtsam From a477ec681170ee7f5c4d9eadac460b595eeee972 Mon Sep 17 00:00:00 2001 From: Gerry Chen Date: Mon, 18 Jan 2021 20:20:05 -0500 Subject: [PATCH 246/261] merge Mandy + Fan's sparseJacobian unit test additions --- .../linear/tests/testGaussianFactorGraph.cpp | 80 ++++++++++++------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/gtsam/linear/tests/testGaussianFactorGraph.cpp b/gtsam/linear/tests/testGaussianFactorGraph.cpp index 45f652d05..57a663e8c 100644 --- a/gtsam/linear/tests/testGaussianFactorGraph.cpp +++ b/gtsam/linear/tests/testGaussianFactorGraph.cpp @@ -36,9 +36,18 @@ using namespace boost::assign; using namespace std; using namespace gtsam; -// static SharedDiagonal -// sigma0_1 = noiseModel::Isotropic::Sigma(2,0.1), sigma_02 = noiseModel::Isotropic::Sigma(2,0.2), -// constraintModel = noiseModel::Constrained::All(2); +typedef boost::tuple BoostTriplet; +bool triplet_equal(BoostTriplet a, BoostTriplet b) { + if (a.get<0>() == b.get<0>() && a.get<1>() == b.get<1>() && + a.get<2>() == b.get<2>()) return true; + + cout << "not equal:" << endl; + cout << "\texpected: " + "(" << a.get<0>() << ", " << a.get<1>() << ") = " << a.get<2>() << endl; + cout << "\tactual: " + "(" << b.get<0>() << ", " << b.get<1>() << ") = " << b.get<2>() << endl; + return false; +} /* ************************************************************************* */ TEST(GaussianFactorGraph, initialization) { @@ -73,37 +82,48 @@ TEST(GaussianFactorGraph, sparseJacobian) { // 5 6 7 0 0 8 // 9 10 0 11 12 13 // 0 0 0 14 15 16 - - // Expected - NOTE that we transpose this! - Matrix expectedT = (Matrix(16, 3) << - 1., 1., 2., - 1., 2., 4., - 1., 3., 6., - 2., 1.,10., - 2., 2.,12., - 2., 3.,14., - 1., 6., 8., - 2., 6.,16., - 3., 1.,18., - 3., 2.,20., - 3., 4.,22., - 3., 5.,24., - 4., 4.,28., - 4., 5.,30., - 3., 6.,26., - 4., 6.,32.).finished(); - - Matrix expected = expectedT.transpose(); - GaussianFactorGraph gfg; SharedDiagonal model = noiseModel::Isotropic::Sigma(2, 0.5); - gfg.add(0, (Matrix(2, 3) << 1., 2., 3., 5., 6., 7.).finished(), Vector2(4., 8.), model); - gfg.add(0, (Matrix(2, 3) << 9., 10., 0., 0., 0., 0.).finished(), 1, - (Matrix(2, 2) << 11., 12., 14., 15.).finished(), Vector2(13., 16.), model); + const Key x123 = 0, x45 = 1; + gfg.add(x123, (Matrix(2, 3) << 1, 2, 3, 5, 6, 7).finished(), + Vector2(4, 8), model); + gfg.add(x123, (Matrix(2, 3) << 9, 10, 0, 0, 0, 0).finished(), + x45, (Matrix(2, 2) << 11, 12, 14, 15.).finished(), + Vector2(13, 16), model); - Matrix actual = gfg.sparseJacobian_(); + // Check version for MATLAB - NOTE that we transpose this! + Matrix expectedT = (Matrix(16, 3) << + 1, 1, 2., + 1, 2, 4., + 1, 3, 6., + 2, 1, 10., + 2, 2, 12., + 2, 3, 14., + 1, 6, 8., + 2, 6, 16., + 3, 1, 18., + 3, 2, 20., + 3, 4, 22., + 3, 5, 24., + 4, 4, 28., + 4, 5, 30., + 3, 6, 26., + 4, 6, 32.).finished(); - EXPECT(assert_equal(expected, actual)); + // matrix form (matlab) + Matrix expectedMatlab = expectedT.transpose(); + EXPECT(assert_equal(expectedMatlab, gfg.sparseJacobian_())); + + // BoostTriplets + auto boostActual = gfg.sparseJacobian(); + // check the triplets size... + EXPECT_LONGS_EQUAL(16, boostActual.size()); + // check content + for (int i = 0; i < 16; i++) { + EXPECT(triplet_equal( + BoostTriplet(expectedT(i, 0) - 1, expectedT(i, 1) - 1, expectedT(i, 2)), + boostActual.at(i))); + } } /* ************************************************************************* */ From 44c232a128c4fac074079f11d91db0601edff127 Mon Sep 17 00:00:00 2001 From: Gerry Chen Date: Mon, 18 Jan 2021 20:39:34 -0500 Subject: [PATCH 247/261] organize/isolate sparseEigen functionality --- gtsam/linear/SparseEigen.h | 146 ++++++++++++++++ gtsam/linear/SparseEigenSolver.cpp | 231 ------------------------- gtsam/linear/SparseEigenSolver.h | 62 ------- gtsam/linear/tests/testSparseEigen.cpp | 72 ++++++++ 4 files changed, 218 insertions(+), 293 deletions(-) create mode 100644 gtsam/linear/SparseEigen.h delete mode 100644 gtsam/linear/SparseEigenSolver.cpp delete mode 100644 gtsam/linear/SparseEigenSolver.h create mode 100644 gtsam/linear/tests/testSparseEigen.cpp diff --git a/gtsam/linear/SparseEigen.h b/gtsam/linear/SparseEigen.h new file mode 100644 index 000000000..a157be2b1 --- /dev/null +++ b/gtsam/linear/SparseEigen.h @@ -0,0 +1,146 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file SparseEigen.h + * + * @brief Utilities for converting to Eigen's sparse matrix representations + * + * @date Aug 2019 + * @author Mandy Xie + * @author Fan Jiang + * @author Gerry Chen + * @author Frank Dellaert + */ + +#pragma once + +#include +#include + +#include + +namespace gtsam { + +typedef Eigen::SparseMatrix SpMat; + +SpMat sparseJacobianEigen( + const GaussianFactorGraph &gfg, const Ordering &ordering) { + // First find dimensions of each variable + std::map dims; + for (const boost::shared_ptr &factor : gfg) { + if (!static_cast(factor)) continue; + + for (auto it = factor->begin(); it != factor->end(); ++it) { + dims[*it] = factor->getDim(it); + } + } + + // Compute first scalar column of each variable + size_t currentColIndex = 0; + std::map columnIndices; + for (const auto key : ordering) { + columnIndices[key] = currentColIndex; + currentColIndex += dims[key]; + } + + // Iterate over all factors, adding sparse scalar entries + std::vector> entries; + entries.reserve(60 * gfg.size()); + + size_t row = 0; + for (const boost::shared_ptr &factor : gfg) { + if (!static_cast(factor)) continue; + + // Convert to JacobianFactor if necessary + JacobianFactor::shared_ptr jacobianFactor( + boost::dynamic_pointer_cast(factor)); + if (!jacobianFactor) { + HessianFactor::shared_ptr hessian( + boost::dynamic_pointer_cast(factor)); + if (hessian) + jacobianFactor.reset(new JacobianFactor(*hessian)); + else + throw std::invalid_argument( + "GaussianFactorGraph contains a factor that is neither a " + "JacobianFactor nor a HessianFactor."); + } + + // Whiten the factor and add entries for it + // iterate over all variables in the factor + const JacobianFactor whitened(jacobianFactor->whiten()); + for (JacobianFactor::const_iterator key = whitened.begin(); + key < whitened.end(); ++key) { + JacobianFactor::constABlock whitenedA = whitened.getA(key); + // find first column index for this key + size_t column_start = columnIndices[*key]; + for (size_t i = 0; i < (size_t)whitenedA.rows(); i++) + for (size_t j = 0; j < (size_t)whitenedA.cols(); j++) { + double s = whitenedA(i, j); + if (std::abs(s) > 1e-12) + entries.emplace_back(row + i, column_start + j, s); + } + } + + JacobianFactor::constBVector whitenedb(whitened.getb()); + size_t bcolumn = currentColIndex; + for (size_t i = 0; i < (size_t)whitenedb.size(); i++) { + double s = whitenedb(i); + if (std::abs(s) > 1e-12) entries.emplace_back(row + i, bcolumn, s); + } + + // Increment row index + row += jacobianFactor->rows(); + } + + // ...and make a sparse matrix with it. + SpMat Ab(row + 1, currentColIndex + 1); + Ab.setFromTriplets(entries.begin(), entries.end()); + return Ab; +} + +SpMat sparseJacobianEigen(const GaussianFactorGraph &gfg) { + return sparseJacobianEigen(gfg, Ordering(gfg.keys())); +} + +// /// obtain sparse matrix for eigen sparse solver +// std::pair obtainSparseMatrix( +// const GaussianFactorGraph &gfg, const Ordering &ordering) { +// gttic_(EigenOptimizer_obtainSparseMatrix); + +// // Get sparse entries of Jacobian [A|b] augmented with RHS b. +// auto entries = gfg.sparseJacobian(ordering); + +// gttic_(EigenOptimizer_convertSparse); +// // Convert boost tuples to Eigen triplets +// vector> triplets; +// triplets.reserve(entries.size()); +// size_t rows = 0, cols = 0; +// for (const auto &e : entries) { +// size_t temp_rows = e.get<0>(), temp_cols = e.get<1>(); +// triplets.emplace_back(temp_rows, temp_cols, e.get<2>()); +// rows = std::max(rows, temp_rows); +// cols = std::max(cols, temp_cols); +// } + +// // ...and make a sparse matrix with it. +// SpMat Ab(rows + 1, cols + 1); +// Ab.setFromTriplets(triplets.begin(), triplets.end()); +// Ab.makeCompressed(); +// gttoc_(EigenOptimizer_convertSparse); + +// gttoc_(EigenOptimizer_obtainSparseMatrix); + +// return make_pair(Ab.block(0, 0, rows + 1, cols), +// Ab.col(cols)); +// } + +} // namespace gtsam diff --git a/gtsam/linear/SparseEigenSolver.cpp b/gtsam/linear/SparseEigenSolver.cpp deleted file mode 100644 index f0dfd83f3..000000000 --- a/gtsam/linear/SparseEigenSolver.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file SparseEigenSolver.cpp - * - * @brief Eigen SparseSolver based linear solver backend for GTSAM - * - * @date Aug 2019 - * @author Mandy Xie - * @author Fan Jiang - * @author Frank Dellaert - */ - -#include -#include -#include - -#include - -using namespace std; - -namespace gtsam { - - using SpMat = Eigen::SparseMatrix; - - Eigen::SparseMatrix - SparseEigenSolver::sparseJacobianEigen( - const GaussianFactorGraph &gfg, - const Ordering &ordering) { - // First find dimensions of each variable - std::map dims; - for (const boost::shared_ptr &factor : gfg) { - if (!static_cast(factor)) - continue; - - for (auto it = factor->begin(); it != factor->end(); ++it) { - dims[*it] = factor->getDim(it); - } - } - - // Compute first scalar column of each variable - size_t currentColIndex = 0; - std::map columnIndices; - for (const auto key : ordering) { - columnIndices[key] = currentColIndex; - currentColIndex += dims[key]; - } - - // Iterate over all factors, adding sparse scalar entries - vector> entries; - entries.reserve(60 * gfg.size()); - - size_t row = 0; - for (const boost::shared_ptr &factor : gfg) { - if (!static_cast(factor)) continue; - - // Convert to JacobianFactor if necessary - JacobianFactor::shared_ptr jacobianFactor( - boost::dynamic_pointer_cast(factor)); - if (!jacobianFactor) { - HessianFactor::shared_ptr hessian( - boost::dynamic_pointer_cast(factor)); - if (hessian) - jacobianFactor.reset(new JacobianFactor(*hessian)); - else - throw invalid_argument( - "GaussianFactorGraph contains a factor that is neither a JacobianFactor nor a HessianFactor."); - } - - // Whiten the factor and add entries for it - // iterate over all variables in the factor - const JacobianFactor whitened(jacobianFactor->whiten()); - for (JacobianFactor::const_iterator key = whitened.begin(); - key < whitened.end(); ++key) { - JacobianFactor::constABlock whitenedA = whitened.getA(key); - // find first column index for this key - size_t column_start = columnIndices[*key]; - for (size_t i = 0; i < (size_t) whitenedA.rows(); i++) - for (size_t j = 0; j < (size_t) whitenedA.cols(); j++) { - double s = whitenedA(i, j); - if (std::abs(s) > 1e-12) - entries.emplace_back(row + i, column_start + j, s); - } - } - - JacobianFactor::constBVector whitenedb(whitened.getb()); - size_t bcolumn = currentColIndex; - for (size_t i = 0; i < (size_t) whitenedb.size(); i++) { - double s = whitenedb(i); - if (std::abs(s) > 1e-12) - entries.emplace_back(row + i, bcolumn, s); - } - - // Increment row index - row += jacobianFactor->rows(); - } - - // ...and make a sparse matrix with it. - Eigen::SparseMatrix Ab(row + 1, currentColIndex + 1); - Ab.setFromTriplets(entries.begin(), entries.end()); - return Ab; - } - - - /// obtain sparse matrix for eigen sparse solver - std::pair obtainSparseMatrix( - const GaussianFactorGraph &gfg, - const Ordering &ordering) { - - gttic_(EigenOptimizer_obtainSparseMatrix); - - // Get sparse entries of Jacobian [A|b] augmented with RHS b. - auto entries = gfg.sparseJacobian(ordering); - - gttic_(EigenOptimizer_convertSparse); - // Convert boost tuples to Eigen triplets - vector> triplets; - triplets.reserve(entries.size()); - size_t rows = 0, cols = 0; - for (const auto &e : entries) { - size_t temp_rows = e.get<0>(), temp_cols = e.get<1>(); - triplets.emplace_back(temp_rows, temp_cols, e.get<2>()); - rows = std::max(rows, temp_rows); - cols = std::max(cols, temp_cols); - } - - // ...and make a sparse matrix with it. - SpMat Ab(rows + 1, cols + 1); - Ab.setFromTriplets(triplets.begin(), triplets.end()); - Ab.makeCompressed(); - gttoc_(EigenOptimizer_convertSparse); - - gttoc_(EigenOptimizer_obtainSparseMatrix); - - return make_pair(Ab.block(0, 0, rows + 1, cols), - Ab.col(cols)); - } - - bool SparseEigenSolver::isIterative() { - return false; - } - - bool SparseEigenSolver::isSequential() { - return false; - } - - VectorValues SparseEigenSolver::solve(const GaussianFactorGraph &gfg) { - if (solverType == QR) { - gttic_(EigenOptimizer_optimizeEigenQR); - auto Ab_pair = obtainSparseMatrix(gfg, ordering); - - // Solve A*x = b using sparse QR from Eigen - gttic_(EigenOptimizer_optimizeEigenQR_create_solver); - Eigen::SparseQR> solver(Ab_pair.first); - gttoc_(EigenOptimizer_optimizeEigenQR_create_solver); - - gttic_(EigenOptimizer_optimizeEigenQR_solve); - Eigen::VectorXd x = solver.solve(Ab_pair.second); - gttoc_(EigenOptimizer_optimizeEigenQR_solve); - - return VectorValues(x, gfg.getKeyDimMap()); - } else if (solverType == CHOLESKY) { - gttic_(EigenOptimizer_optimizeEigenCholesky); - SpMat Ab = sparseJacobianEigen(gfg, ordering); - auto rows = Ab.rows(), cols = Ab.cols(); - auto A = Ab.block(0, 0, rows, cols - 1); - auto At = A.transpose(); - auto b = Ab.col(cols - 1); - - SpMat AtA(A.cols(), A.cols()); - AtA.selfadjointView().rankUpdate(At); - - gttic_(EigenOptimizer_optimizeEigenCholesky_create_solver); - // Solve A*x = b using sparse Cholesky from Eigen - Eigen::SimplicialLDLT> - solver(AtA); - - gttoc_(EigenOptimizer_optimizeEigenCholesky_create_solver); - - gttic_(EigenOptimizer_optimizeEigenCholesky_solve); - Eigen::VectorXd x = solver.solve(At * b); - gttoc_(EigenOptimizer_optimizeEigenCholesky_solve); - - // NOTE: b is reordered now, so we need to transform back the order. - // First find dimensions of each variable - std::map dims; - for (const boost::shared_ptr &factor : gfg) { - if (!static_cast(factor)) - continue; - - for (auto it = factor->begin(); it != factor->end(); ++it) { - dims[*it] = factor->getDim(it); - } - } - - VectorValues vv; - - std::map columnIndices; - - { - size_t currentColIndex = 0; - for (const auto key : ordering) { - columnIndices[key] = currentColIndex; - currentColIndex += dims[key]; - } - } - - for (const pair keyDim : dims) { - vv.insert(keyDim.first, x.segment(columnIndices[keyDim.first], keyDim.second)); - } - - return vv; - } - - throw std::exception(); - } - - SparseEigenSolver::SparseEigenSolver(SparseEigenSolver::SparseEigenSolverType type, const Ordering &ordering) { - solverType = type; - this->ordering = ordering; - } -} // namespace gtsam \ No newline at end of file diff --git a/gtsam/linear/SparseEigenSolver.h b/gtsam/linear/SparseEigenSolver.h deleted file mode 100644 index d71365864..000000000 --- a/gtsam/linear/SparseEigenSolver.h +++ /dev/null @@ -1,62 +0,0 @@ -/* ---------------------------------------------------------------------------- - - * GTSAM Copyright 2010, Georgia Tech Research Corporation, - * Atlanta, Georgia 30332-0415 - * All Rights Reserved - * Authors: Frank Dellaert, et al. (see THANKS for the full author list) - - * See LICENSE for the license information - - * -------------------------------------------------------------------------- */ - -/** - * @file SparseEigenSolver.h - * - * @brief Eigen SparseSolver based linear solver backend for GTSAM - * - * @date Aug 2019 - * @author Mandy Xie - * @author Fan Jiang - * @author Frank Dellaert - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace gtsam { - - /** - * Eigen SparseSolver based Backend class - */ - class GTSAM_EXPORT SparseEigenSolver : public LinearSolver { - public: - - typedef enum { - QR, - CHOLESKY - } SparseEigenSolverType; - - - explicit SparseEigenSolver(SparseEigenSolver::SparseEigenSolverType type, const Ordering &ordering); - - bool isIterative() override; - - bool isSequential() override; - - VectorValues solve(const GaussianFactorGraph &gfg) override; - - static Eigen::SparseMatrix - sparseJacobianEigen(const GaussianFactorGraph &gfg, const Ordering &ordering); - - protected: - - SparseEigenSolverType solverType = QR; - - Ordering ordering; - }; -} // namespace gtsam diff --git a/gtsam/linear/tests/testSparseEigen.cpp b/gtsam/linear/tests/testSparseEigen.cpp new file mode 100644 index 000000000..225e1dab2 --- /dev/null +++ b/gtsam/linear/tests/testSparseEigen.cpp @@ -0,0 +1,72 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file testSparseMatrix.cpp + * @author Mandy Xie + * @author Fan Jiang + * @author Gerry Chen + * @author Frank Dellaert + * @date Jan, 2021 + */ + +#include +#include + +#include +using boost::assign::list_of; + +#include +#include + +using namespace std; +using namespace gtsam; + +/* ************************************************************************* */ +TEST(SparseEigen, sparseJacobianEigen) { + GaussianFactorGraph gfg; + SharedDiagonal model = noiseModel::Isotropic::Sigma(2, 0.5); + const Key x123 = 0, x45 = 1; + gfg.add(x123, (Matrix(2, 3) << 1, 2, 3, 5, 6, 7).finished(), + Vector2(4, 8), model); + gfg.add(x123, (Matrix(2, 3) << 9, 10, 0, 0, 0, 0).finished(), + x45, (Matrix(2, 2) << 11, 12, 14, 15.).finished(), + Vector2(13, 16), model); + + // Sparse Matrix + auto sparseResult = sparseJacobianEigen(gfg); + EXPECT_LONGS_EQUAL(16, sparseResult.nonZeros()); + EXPECT(assert_equal(4, sparseResult.rows())); + EXPECT(assert_equal(6, sparseResult.cols())); + EXPECT(assert_equal(gfg.augmentedJacobian(), Matrix(sparseResult))); + + // Call sparseJacobian with optional ordering... + auto ordering = Ordering(list_of(x45)(x123)); + + // Eigen Sparse with optional ordering + EXPECT(assert_equal(gfg.augmentedJacobian(ordering), + Matrix(sparseJacobianEigen(gfg, ordering)))); + + // Check matrix dimensions when zero rows / cols + gfg.add(x123, Matrix23::Zero(), Vector2::Zero(), model); // zero row + gfg.add(2, Matrix21::Zero(), Vector2::Zero(), model); // zero col + sparseResult = sparseJacobianEigen(gfg); + EXPECT_LONGS_EQUAL(16, sparseResult.nonZeros()); + EXPECT(assert_equal(8, sparseResult.rows())); + EXPECT(assert_equal(7, sparseResult.cols())); +} + +/* ************************************************************************* */ +int main() { + TestResult tr; + return TestRegistry::runAllTests(tr); +} +/* ************************************************************************* */ From ee5701dcda6a3aeb05d30991bfd7aefd3bf7a443 Mon Sep 17 00:00:00 2001 From: Gerry Chen Date: Mon, 18 Jan 2021 20:39:53 -0500 Subject: [PATCH 248/261] fix off-by-one bug --- gtsam/linear/SparseEigen.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/linear/SparseEigen.h b/gtsam/linear/SparseEigen.h index a157be2b1..35062c4fe 100644 --- a/gtsam/linear/SparseEigen.h +++ b/gtsam/linear/SparseEigen.h @@ -102,7 +102,7 @@ SpMat sparseJacobianEigen( } // ...and make a sparse matrix with it. - SpMat Ab(row + 1, currentColIndex + 1); + SpMat Ab(row, currentColIndex + 1); Ab.setFromTriplets(entries.begin(), entries.end()); return Ab; } From d9c03aa827f3b8e30180c41dd94249515ad376c0 Mon Sep 17 00:00:00 2001 From: Gerry Chen Date: Mon, 18 Jan 2021 20:56:44 -0500 Subject: [PATCH 249/261] cleanup --- gtsam/linear/SparseEigen.h | 37 +++++-------------------------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git a/gtsam/linear/SparseEigen.h b/gtsam/linear/SparseEigen.h index 35062c4fe..5ee67f6d9 100644 --- a/gtsam/linear/SparseEigen.h +++ b/gtsam/linear/SparseEigen.h @@ -32,8 +32,13 @@ namespace gtsam { typedef Eigen::SparseMatrix SpMat; +/// Constructs an Eigen-format SparseMatrix of a GaussianFactorGraph SpMat sparseJacobianEigen( const GaussianFactorGraph &gfg, const Ordering &ordering) { + // TODO(gerry): eliminate copy/pasta by making GaussianFactorGraph version + // more general, or by creating an Eigen::Triplet compatible wrapper for + // boost::tuple return type + // First find dimensions of each variable std::map dims; for (const boost::shared_ptr &factor : gfg) { @@ -111,36 +116,4 @@ SpMat sparseJacobianEigen(const GaussianFactorGraph &gfg) { return sparseJacobianEigen(gfg, Ordering(gfg.keys())); } -// /// obtain sparse matrix for eigen sparse solver -// std::pair obtainSparseMatrix( -// const GaussianFactorGraph &gfg, const Ordering &ordering) { -// gttic_(EigenOptimizer_obtainSparseMatrix); - -// // Get sparse entries of Jacobian [A|b] augmented with RHS b. -// auto entries = gfg.sparseJacobian(ordering); - -// gttic_(EigenOptimizer_convertSparse); -// // Convert boost tuples to Eigen triplets -// vector> triplets; -// triplets.reserve(entries.size()); -// size_t rows = 0, cols = 0; -// for (const auto &e : entries) { -// size_t temp_rows = e.get<0>(), temp_cols = e.get<1>(); -// triplets.emplace_back(temp_rows, temp_cols, e.get<2>()); -// rows = std::max(rows, temp_rows); -// cols = std::max(cols, temp_cols); -// } - -// // ...and make a sparse matrix with it. -// SpMat Ab(rows + 1, cols + 1); -// Ab.setFromTriplets(triplets.begin(), triplets.end()); -// Ab.makeCompressed(); -// gttoc_(EigenOptimizer_convertSparse); - -// gttoc_(EigenOptimizer_obtainSparseMatrix); - -// return make_pair(Ab.block(0, 0, rows + 1, cols), -// Ab.col(cols)); -// } - } // namespace gtsam From 9c781b605ff81533fdf9a4c145004a2ce27433a4 Mon Sep 17 00:00:00 2001 From: jingwuOUO Date: Tue, 19 Jan 2021 00:07:21 -0500 Subject: [PATCH 250/261] Set estimateBeta() as optional --- gtsam/linear/AcceleratedPowerMethod.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/gtsam/linear/AcceleratedPowerMethod.h b/gtsam/linear/AcceleratedPowerMethod.h index 4cb25daf7..6653d43c9 100644 --- a/gtsam/linear/AcceleratedPowerMethod.h +++ b/gtsam/linear/AcceleratedPowerMethod.h @@ -69,10 +69,7 @@ class AcceleratedPowerMethod : public PowerMethod { previousVector_ = Vector::Zero(this->dim_); // initialize beta_ - if (!initialBeta) { - beta_ = estimateBeta(); - } else - beta_ = initialBeta; + beta_ = initialBeta; } /** @@ -97,8 +94,11 @@ class AcceleratedPowerMethod : public PowerMethod { return y; } - /// Tuning the momentum beta using the Best Heavy Ball algorithm in Ref(3) - double estimateBeta() const { + /** + * Tuning the momentum beta using the Best Heavy Ball algorithm in Ref(3), T + * is the iteration time to find beta with largest Rayleigh quotient + */ + double estimateBeta(const size_t T = 10) const { // set initial estimation of maxBeta Vector initVector = this->ritzVector_; const double up = initVector.dot( this->A_ * initVector ); @@ -109,7 +109,6 @@ class AcceleratedPowerMethod : public PowerMethod { std::vector betas; Matrix R = Matrix::Zero(this->dim_, 10); - const size_t T = 10; // run T times of iteration to find the beta that has the largest Rayleigh quotient for (size_t t = 0; t < T; t++) { // after each t iteration, reset the betas with the current maxBeta @@ -120,13 +119,14 @@ class AcceleratedPowerMethod : public PowerMethod { // initialize x0 and x00 in each iteration of each beta Vector x0 = initVector; Vector x00 = Vector::Zero(this->dim_); - // run 10 steps of accelerated power iteration with this beta + // run 10 steps of accelerated power iteration with this beta for (size_t j = 1; j < 10; j++) { if (j < 2) { R.col(0) = acceleratedPowerIteration(x0, x00, betas[k]); R.col(1) = acceleratedPowerIteration(R.col(0), x0, betas[k]); } else { - R.col(j) = acceleratedPowerIteration(R.col(j - 1), R.col(j - 2), betas[k]); + R.col(j) = acceleratedPowerIteration(R.col(j - 1), R.col(j - 2), + betas[k]); } } // compute the Rayleigh quotient for the randomly sampled vector after From bb662f0cb439205b6b3fb05ee87c21b274a7b0b2 Mon Sep 17 00:00:00 2001 From: Russell Buchanan Date: Tue, 19 Jan 2021 10:49:42 +0000 Subject: [PATCH 251/261] clean up --- tests/testImuPreintegration.cpp | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/tests/testImuPreintegration.cpp b/tests/testImuPreintegration.cpp index 43b3461ee..7975ff794 100644 --- a/tests/testImuPreintegration.cpp +++ b/tests/testImuPreintegration.cpp @@ -49,8 +49,6 @@ TEST(TestImuPreintegration, LoadedSimulationData) { double rate = 400.0; // Hz string inFileString = findExampleDataFile("quadraped_imu_data.csv"); - ofstream outputFile; - outputFile.open("imu_preint_output.csv", ios::out); ifstream inputFile(inFileString); string line; while (getline(inputFile, line)) { @@ -95,27 +93,13 @@ TEST(TestImuPreintegration, LoadedSimulationData) { NavState initialNavState(priorPose, priorVelocity); - // Bias estimated by my Algorithm - priorImuBias = imuBias::ConstantBias( - Eigen::Vector3d(-0.0314648, 0.0219921, 6.95945e-05), - Eigen::Vector3d(4.88581e-08, -1.04971e-09, -0.000122868)); - - // zero bias - // priorImuBias = imuBias::ConstantBias(Eigen::Vector3d(0,0,0), - // Eigen::Vector3d(0,0,0)); + // Assume zero bias for simulated data + priorImuBias = imuBias::ConstantBias(Eigen::Vector3d(0,0,0), + Eigen::Vector3d(0,0,0)); imuPreintegrated = PreintegratedCombinedMeasurements( imuPreintegratedParams, priorImuBias); - // Put header row in output csv - outputFile << "X Position," - << "Y Position," - << "Z Position," - << "X Velocity," - << "Y Velocity," - << "Z Velocity," - << "\n"; - // start at 1 to skip header for (size_t n = 1; n < imuMeasurements.size(); n++) { // integrate @@ -127,17 +111,8 @@ TEST(TestImuPreintegration, LoadedSimulationData) { velocity = propState.velocity(); // cout << "IMU Position " << position.transpose() << endl; // cout << "IMU Velocity " << velocity.transpose() << endl; - - // Write to csv - outputFile << to_string(position.x()) << "," << to_string(position.y()) - << "," << to_string(position.z()) << "," - << to_string(velocity.x()) << "," << to_string(velocity.y()) - << "," << to_string(velocity.z()) << "," - << "\n"; } - outputFile.close(); - Vector3 rotation = propState.pose().rotation().rpy(); // Dont have ground truth for x and y position yet From d8491b27fb010e5d0061c8926730b11512433578 Mon Sep 17 00:00:00 2001 From: Gerry Chen Date: Tue, 19 Jan 2021 10:53:22 -0500 Subject: [PATCH 252/261] rename matrix type from `SpMat` to `SparseEigen` --- gtsam/linear/SparseEigen.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gtsam/linear/SparseEigen.h b/gtsam/linear/SparseEigen.h index 5ee67f6d9..ee2a26330 100644 --- a/gtsam/linear/SparseEigen.h +++ b/gtsam/linear/SparseEigen.h @@ -30,10 +30,10 @@ namespace gtsam { -typedef Eigen::SparseMatrix SpMat; +typedef Eigen::SparseMatrix SparseEigen; /// Constructs an Eigen-format SparseMatrix of a GaussianFactorGraph -SpMat sparseJacobianEigen( +SparseEigen sparseJacobianEigen( const GaussianFactorGraph &gfg, const Ordering &ordering) { // TODO(gerry): eliminate copy/pasta by making GaussianFactorGraph version // more general, or by creating an Eigen::Triplet compatible wrapper for @@ -107,12 +107,12 @@ SpMat sparseJacobianEigen( } // ...and make a sparse matrix with it. - SpMat Ab(row, currentColIndex + 1); + SparseEigen Ab(row, currentColIndex + 1); Ab.setFromTriplets(entries.begin(), entries.end()); return Ab; } -SpMat sparseJacobianEigen(const GaussianFactorGraph &gfg) { +SparseEigen sparseJacobianEigen(const GaussianFactorGraph &gfg) { return sparseJacobianEigen(gfg, Ordering(gfg.keys())); } From 25e3b5609e64999c8a42b6416cf5c4634693663c Mon Sep 17 00:00:00 2001 From: Gerry Chen Date: Tue, 19 Jan 2021 11:01:25 -0500 Subject: [PATCH 253/261] roll back some cosmetic changes to minimize the diff --- .../linear/tests/testGaussianFactorGraph.cpp | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/gtsam/linear/tests/testGaussianFactorGraph.cpp b/gtsam/linear/tests/testGaussianFactorGraph.cpp index 57a663e8c..0ae500824 100644 --- a/gtsam/linear/tests/testGaussianFactorGraph.cpp +++ b/gtsam/linear/tests/testGaussianFactorGraph.cpp @@ -82,6 +82,29 @@ TEST(GaussianFactorGraph, sparseJacobian) { // 5 6 7 0 0 8 // 9 10 0 11 12 13 // 0 0 0 14 15 16 + + // Expected + Matrix expected = (Matrix(16, 3) << + 1., 1., 2., + 1., 2., 4., + 1., 3., 6., + 2., 1.,10., + 2., 2.,12., + 2., 3.,14., + 1., 6., 8., + 2., 6.,16., + 3., 1.,18., + 3., 2.,20., + 3., 4.,22., + 3., 5.,24., + 4., 4.,28., + 4., 5.,30., + 3., 6.,26., + 4., 6.,32.).finished(); + + // expected: in matlab format - NOTE the transpose!) + Matrix expectedMatlab = expected.transpose(); + GaussianFactorGraph gfg; SharedDiagonal model = noiseModel::Isotropic::Sigma(2, 0.5); const Key x123 = 0, x45 = 1; @@ -91,28 +114,9 @@ TEST(GaussianFactorGraph, sparseJacobian) { x45, (Matrix(2, 2) << 11, 12, 14, 15.).finished(), Vector2(13, 16), model); - // Check version for MATLAB - NOTE that we transpose this! - Matrix expectedT = (Matrix(16, 3) << - 1, 1, 2., - 1, 2, 4., - 1, 3, 6., - 2, 1, 10., - 2, 2, 12., - 2, 3, 14., - 1, 6, 8., - 2, 6, 16., - 3, 1, 18., - 3, 2, 20., - 3, 4, 22., - 3, 5, 24., - 4, 4, 28., - 4, 5, 30., - 3, 6, 26., - 4, 6, 32.).finished(); + Matrix actual = gfg.sparseJacobian_(); - // matrix form (matlab) - Matrix expectedMatlab = expectedT.transpose(); - EXPECT(assert_equal(expectedMatlab, gfg.sparseJacobian_())); + EXPECT(assert_equal(expected, actual)); // BoostTriplets auto boostActual = gfg.sparseJacobian(); @@ -121,7 +125,7 @@ TEST(GaussianFactorGraph, sparseJacobian) { // check content for (int i = 0; i < 16; i++) { EXPECT(triplet_equal( - BoostTriplet(expectedT(i, 0) - 1, expectedT(i, 1) - 1, expectedT(i, 2)), + BoostTriplet(expected(i, 0) - 1, expected(i, 1) - 1, expected(i, 2)), boostActual.at(i))); } } From e2f5be4e4700e26758f100881375627ae0368c64 Mon Sep 17 00:00:00 2001 From: Gerry Chen Date: Tue, 19 Jan 2021 11:04:26 -0500 Subject: [PATCH 254/261] SparseEigen docstring --- gtsam/linear/SparseEigen.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/linear/SparseEigen.h b/gtsam/linear/SparseEigen.h index ee2a26330..7963d3ef5 100644 --- a/gtsam/linear/SparseEigen.h +++ b/gtsam/linear/SparseEigen.h @@ -12,7 +12,7 @@ /** * @file SparseEigen.h * - * @brief Utilities for converting to Eigen's sparse matrix representations + * @brief Utilities for creating Eigen sparse matrices (gtsam::SparseEigen) * * @date Aug 2019 * @author Mandy Xie From b76993b171a44c902fcc6cbb45794bc245808042 Mon Sep 17 00:00:00 2001 From: Gerry Chen Date: Tue, 19 Jan 2021 11:47:44 -0500 Subject: [PATCH 255/261] typo: `expected` changed to `expectedMatlab` --- gtsam/linear/tests/testGaussianFactorGraph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/linear/tests/testGaussianFactorGraph.cpp b/gtsam/linear/tests/testGaussianFactorGraph.cpp index 0ae500824..8b9ce94a9 100644 --- a/gtsam/linear/tests/testGaussianFactorGraph.cpp +++ b/gtsam/linear/tests/testGaussianFactorGraph.cpp @@ -116,7 +116,7 @@ TEST(GaussianFactorGraph, sparseJacobian) { Matrix actual = gfg.sparseJacobian_(); - EXPECT(assert_equal(expected, actual)); + EXPECT(assert_equal(expectedMatlab, actual)); // BoostTriplets auto boostActual = gfg.sparseJacobian(); From 6f6588457b7330799e261c66c5514fd963ff8623 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 19 Jan 2021 15:22:41 -0500 Subject: [PATCH 256/261] use streams instead of printf --- gtsam/base/Testable.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gtsam/base/Testable.h b/gtsam/base/Testable.h index 92c464940..2145360df 100644 --- a/gtsam/base/Testable.h +++ b/gtsam/base/Testable.h @@ -33,9 +33,9 @@ #pragma once -#include #include -#include +#include +#include #include #define GTSAM_PRINT(x)((x).print(#x)) @@ -72,10 +72,10 @@ namespace gtsam { }; // \ Testable inline void print(float v, const std::string& s = "") { - printf("%s%f\n",s.c_str(),v); + std::cout << (s == "" ? s : s + " ") << v << std::endl; } inline void print(double v, const std::string& s = "") { - printf("%s%lf\n",s.c_str(),v); + std::cout << (s == "" ? s : s + " ") << v << std::endl; } /** Call equal on the object */ From 56eb1bb808483bcbb1a369034ca5e73fe06e4640 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 19 Jan 2021 15:23:14 -0500 Subject: [PATCH 257/261] use of passed in stream for print capture --- gtsam/base/Matrix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gtsam/base/Matrix.cpp b/gtsam/base/Matrix.cpp index 551bdac10..41a80629b 100644 --- a/gtsam/base/Matrix.cpp +++ b/gtsam/base/Matrix.cpp @@ -153,7 +153,7 @@ const Eigen::IOFormat& matlabFormat() { /* ************************************************************************* */ //3 argument call void print(const Matrix& A, const string &s, ostream& stream) { - cout << s << A.format(matlabFormat()) << endl; + stream << s << A.format(matlabFormat()) << endl; } /* ************************************************************************* */ From 2168cd4a04da47478eb1985d1268b157c03c1fc5 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 19 Jan 2021 15:39:37 -0500 Subject: [PATCH 258/261] stream printing for Pose2 --- gtsam/geometry/Pose2.cpp | 8 +++++++- gtsam/geometry/Pose2.h | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/gtsam/geometry/Pose2.cpp b/gtsam/geometry/Pose2.cpp index 71df0f753..bebe53dfa 100644 --- a/gtsam/geometry/Pose2.cpp +++ b/gtsam/geometry/Pose2.cpp @@ -48,7 +48,13 @@ Matrix3 Pose2::matrix() const { /* ************************************************************************* */ void Pose2::print(const string& s) const { - cout << s << "(" << t_.x() << ", " << t_.y() << ", " << r_.theta() << ")" << endl; + cout << s << this << endl; +} + +/* ************************************************************************* */ +std::ostream &operator<<(std::ostream &os, const Pose2& pose) { + os << "(" << pose.x() << ", " << pose.y() << ", " << pose.theta() << ")"; + return os; } /* ************************************************************************* */ diff --git a/gtsam/geometry/Pose2.h b/gtsam/geometry/Pose2.h index 6372779c3..a54951728 100644 --- a/gtsam/geometry/Pose2.h +++ b/gtsam/geometry/Pose2.h @@ -287,6 +287,10 @@ public: */ static std::pair rotationInterval() { return std::make_pair(2, 2); } + /// Output stream operator + GTSAM_EXPORT + friend std::ostream &operator<<(std::ostream &os, const Pose2& p); + /// @} private: From afb28e91b67f16679c6f779d6da1385044a30301 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 19 Jan 2021 15:40:21 -0500 Subject: [PATCH 259/261] add BearingRange measured to wrapper --- gtsam/gtsam.i | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gtsam/gtsam.i b/gtsam/gtsam.i index abba7437d..22c2cc17d 100644 --- a/gtsam/gtsam.i +++ b/gtsam/gtsam.i @@ -2623,6 +2623,8 @@ virtual class BearingRangeFactor : gtsam::NoiseModelFactor { const BEARING& measuredBearing, const RANGE& measuredRange, const gtsam::noiseModel::Base* noiseModel); + BearingRange measured() const; + // enabling serialization functionality void serialize() const; }; From f831bfd62ec56373677c52ea5e035f2816451de0 Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 19 Jan 2021 15:40:37 -0500 Subject: [PATCH 260/261] add override and formatting --- gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h b/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h index 93a83ab30..2ecd7b75c 100644 --- a/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h +++ b/gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h @@ -113,12 +113,13 @@ class SmartStereoProjectionPoseFactor : public SmartStereoProjectionFactor { * print * @param s optional string naming the factor * @param keyFormatter optional formatter useful for printing Symbols - */ void print( - const std::string& s = "", - const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override; + */ + void print(const std::string& s = "", const KeyFormatter& keyFormatter = + DefaultKeyFormatter) const override; /// equals - virtual bool equals(const NonlinearFactor& p, double tol = 1e-9) const; + virtual bool equals(const NonlinearFactor& p, + double tol = 1e-9) const override; /** * error calculates the error of the factor. @@ -155,4 +156,4 @@ template <> struct traits : public Testable {}; -} // \ namespace gtsam +} // namespace gtsam From 7eeed6dc14c61f7eeeda35a642bafb1df5888aad Mon Sep 17 00:00:00 2001 From: Varun Agrawal Date: Tue, 19 Jan 2021 15:47:15 -0500 Subject: [PATCH 261/261] remove cout statements from testImuPreintegration tests --- tests/testImuPreintegration.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/testImuPreintegration.cpp b/tests/testImuPreintegration.cpp index 2a2553697..1f584be0e 100644 --- a/tests/testImuPreintegration.cpp +++ b/tests/testImuPreintegration.cpp @@ -64,8 +64,6 @@ TEST(TestImuPreintegration, LoadedSimulationData) { measurement.I_a_WI = {results[29], results[30], results[31]}; measurement.I_w_WI = {results[17], results[18], results[19]}; imuMeasurements.push_back(measurement); - - // cout << "IMU measurement " << measurement << endl; } // Assume a Z-up navigation (assuming we are performing optimization in the @@ -92,8 +90,8 @@ TEST(TestImuPreintegration, LoadedSimulationData) { NavState initialNavState(priorPose, priorVelocity); // Assume zero bias for simulated data - priorImuBias = imuBias::ConstantBias(Eigen::Vector3d(0,0,0), - Eigen::Vector3d(0,0,0)); + priorImuBias = + imuBias::ConstantBias(Eigen::Vector3d(0, 0, 0), Eigen::Vector3d(0, 0, 0)); imuPreintegrated = PreintegratedCombinedMeasurements(imuPreintegratedParams, priorImuBias); @@ -107,8 +105,6 @@ TEST(TestImuPreintegration, LoadedSimulationData) { propState = imuPreintegrated.predict(initialNavState, priorImuBias); position = propState.pose().translation(); velocity = propState.velocity(); - // cout << "IMU Position " << position.transpose() << endl; - // cout << "IMU Velocity " << velocity.transpose() << endl; } Vector3 rotation = propState.pose().rotation().rpy();