Skip to content

Commit f24d748

Browse files
author
Sammy Guo
committed
Incorporating reviewer comments, and tidying tests.
1 parent 99c88cd commit f24d748

File tree

5 files changed

+110
-30
lines changed

5 files changed

+110
-30
lines changed

gtsam/navigation/PseudorangeFactor.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,10 @@ PseudorangeFactor::PseudorangeFactor(Key receiverPositionKey,
3333
//***************************************************************************
3434
void PseudorangeFactor::print(const std::string& s,
3535
const KeyFormatter& keyFormatter) const {
36-
std::cout << (s.empty() ? "" : s + " ") << "PseudorangeFactor on "
37-
<< keyFormatter(this->key<1>()) << ", "
38-
<< keyFormatter(this->key<2>()) << "\n";
39-
std::cout << " Pseudorange: " << pseudorange_ << " meters\n";
40-
std::cout << " Satellite Position: " << satPos_.transpose()
41-
<< " meters (ECEF)\n";
42-
std::cout << " Satellite clock bias: " << satClkBias_ << " seconds\n";
43-
noiseModel_->print(" noise model: ");
36+
Base::print(s, keyFormatter);
37+
gtsam::print(pseudorange_, "pseudorange (m): ");
38+
gtsam::print(Vector(satPos_), "sat position (ECEF meters): ");
39+
gtsam::print(satClkBias_, "sat clock bias (s): ");
4440
}
4541

4642
//***************************************************************************

gtsam/navigation/PseudorangeFactor.h

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ class GTSAM_EXPORT PseudorangeFactor
4141
private:
4242
typedef NoiseModelFactorN<Point3, double> Base;
4343

44-
const double
45-
pseudorange_; ///< Receiver-reported pseudorange measurement in meters.
46-
const Point3 satPos_; ///< Satellite position in WGS84 ECEF meters.
47-
const double satClkBias_; ///< Satellite clock bias in seconds.
44+
double
45+
pseudorange_; ///< Receiver-reported pseudorange measurement in meters.
46+
Point3 satPos_; ///< Satellite position in WGS84 ECEF meters.
47+
double satClkBias_; ///< Satellite clock bias in seconds.
4848

4949
public:
5050
// Provide access to the Matrix& version of evaluateError:
@@ -72,11 +72,11 @@ class GTSAM_EXPORT PseudorangeFactor
7272
* @param satelliteClockBias Satellite clock bias in seconds.
7373
* @param model 1-D noise model.
7474
*/
75-
PseudorangeFactor(Key receiverPositionKey, Key receiverClockBiasKey,
76-
double measuredPseudorange, const Point3& satellitePosition,
77-
double satelliteClockBias,
78-
const SharedNoiseModel& model =
79-
noiseModel::Diagonal::Sigmas(Vector1(1.0)));
75+
PseudorangeFactor(
76+
Key receiverPositionKey, Key receiverClockBiasKey,
77+
double measuredPseudorange, const Point3& satellitePosition,
78+
double satelliteClockBias = 0.0,
79+
const SharedNoiseModel& model = noiseModel::Unit::Create(1));
8080

8181
/// @return a deep copy of this factor
8282
gtsam::NonlinearFactor::shared_ptr clone() const override {
@@ -112,4 +112,8 @@ class GTSAM_EXPORT PseudorangeFactor
112112
#endif
113113
};
114114

115+
/// traits
116+
template <>
117+
struct traits<PseudorangeFactor> : public Testable<PseudorangeFactor> {};
118+
115119
} // namespace gtsam

gtsam/navigation/navigation.i

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -488,20 +488,22 @@ virtual class GPSFactor2ArmCalib : gtsam::NonlinearFactor{
488488
#include <gtsam/navigation/PseudorangeFactor.h>
489489
virtual class PseudorangeFactor : gtsam::NonlinearFactor {
490490
PseudorangeFactor(gtsam::Key receiverPositionKey,
491-
gtsam::Key receiverClockBiasKey,
492-
double measuredPseudorange,
491+
gtsam::Key receiverClockBiasKey, double measuredPseudorange,
493492
const gtsam::Point3& satellitePosition,
494493
double satelliteClockBias,
495494
const gtsam::noiseModel::Base* model);
496495

497496
// Testable
498497
void print(string s = "", const gtsam::KeyFormatter& keyFormatter =
499-
gtsam::DefaultKeyFormatter) const;
498+
gtsam::DefaultKeyFormatter) const;
500499
bool equals(const gtsam::NonlinearFactor& expected, double tol);
501500

502501
// Standard Interface
503502
gtsam::Vector evaluateError(const gtsam::Point3& receiverPosition,
504503
const double& receiverClock_bias) const;
504+
505+
// enable serialization functionality
506+
void serialize() const;
505507
};
506508

507509
#include <gtsam/navigation/BarometricFactor.h>

gtsam/navigation/tests/testPseudorangeFactor.cpp

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,39 @@ TEST(TestPseudorangeFactor, Constructor) {
2424
factor.evaluateError(Point3::Zero(), 0.0, Hpos, Hbias)[0];
2525
EXPECT_DOUBLES_EQUAL(0.0, error, 1e-9);
2626

27-
// Jacobians are technically undefined if the receiver and satellite positions
28-
// are the same. So make sure this corner-case does not numerically explode:
29-
CHECK(!Hpos.array().isNaN().any());
30-
CHECK(!Hbias.array().isNaN().any());
27+
// Derivatives are technically undefined if the receiver and satellite
28+
// positions are the same (hopefully that's never the case in reality). But
29+
// for all intents and purposes, zero-valued derivatives can substitute for
30+
// undefined gradient at that singularity. So make sure this corner-case does
31+
// not numerically explode:
32+
EXPECT(!Hpos.array().isNaN().any());
33+
EXPECT(!Hbias.array().isNaN().any());
3134
EXPECT_DOUBLES_EQUAL(Hpos.norm(), 0.0, 1e-9);
32-
// Clock bias should always be speed-of-light in vacuum:
35+
// Clock bias derivative should always be speed-of-light in vacuum:
3336
EXPECT_DOUBLES_EQUAL(Hbias.norm(), 299792458.0, 1e-9);
3437
}
3538

36-
TEST(TestPseudorangeFactor, Jacobians) {
39+
// *************************************************************************
40+
TEST(TestPseudorangeFactor, Jacobians1) {
41+
// Synthetic example with exact error/derivatives:
42+
const auto factor = PseudorangeFactor(
43+
Key(0), Key(1), // Receiver position and clock bias keys.
44+
4.0, // Measured pseudorange.
45+
// Satellite position:
46+
Vector3(0.0, 0.0, 3.0),
47+
0.0 // Sat clock drift bias.
48+
);
49+
const double error = factor.evaluateError(Vector3::Zero(), 0.0)[0];
50+
EXPECT_DOUBLES_EQUAL(-1.0, error, 1e-6);
51+
52+
Values values;
53+
values.insert(Key(0), Vector3(1.0, 2.0, 3.0));
54+
values.insert(Key(1), 0.0);
55+
EXPECT_CORRECT_FACTOR_JACOBIANS(factor, values, 1e-3, 1e-5);
56+
}
57+
58+
// *************************************************************************
59+
TEST(TestPseudorangeFactor, Jacobians2) {
3760
// Example values borrowed from `SinglePointPositioningExample.ipynb`:
3861
const auto factor = PseudorangeFactor(
3962
Key(0), Key(1), // Receiver position and clock bias keys.
@@ -50,6 +73,30 @@ TEST(TestPseudorangeFactor, Jacobians) {
5073
EXPECT_CORRECT_FACTOR_JACOBIANS(factor, values, 1e-3, 1e-5);
5174
}
5275

76+
// *************************************************************************
77+
TEST(TestPseudorangeFactor, print) {
78+
// Just make sure `print()` doesn't throw errors
79+
// since there's no elegant way to check stdout.
80+
const auto factor = PseudorangeFactor();
81+
factor.print();
82+
}
83+
84+
// *************************************************************************
85+
TEST(TestPseudorangeFactor, equals) {
86+
const auto factor1 = PseudorangeFactor();
87+
const auto factor2 = PseudorangeFactor(1, 2, 0.0, Point3::Zero(), 0.0);
88+
const auto factor3 =
89+
PseudorangeFactor(1, 2, 10.0, Point3(1.0, 2.0, 3.0), 20.0);
90+
91+
CHECK(factor1.equals(factor1));
92+
CHECK(factor2.equals(factor2));
93+
CHECK(!factor1.equals(factor2));
94+
CHECK(factor2.equals(factor3, 1e99));
95+
96+
// Test print:
97+
factor2.print("factor2");
98+
}
99+
53100
// *************************************************************************
54101
int main() {
55102
TestResult tr;

python/gtsam/tests/test_PseudorangeFactor.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,41 @@
1616
from gtsam.utils.test_case import GtsamTestCase
1717

1818

19-
class TestPriorFactor(GtsamTestCase):
20-
21-
def test_PseudorangeFactor(self):
22-
self.assertEqual(1, 0)
19+
class TestPseudorangeFactor(GtsamTestCase):
20+
def test_singularity(self):
21+
pos = np.zeros(3)
22+
values = gtsam.Values()
23+
values.insert(0, pos)
24+
values.insert(1, 0.0)
25+
26+
model = gtsam.noiseModel.Unit.Create(1)
27+
factor = gtsam.PseudorangeFactor(0, 1, 0.0, pos, 0.0, model)
28+
self.assertEqual(factor.error(values), 0)
29+
# test print:
30+
factor.print("factor")
31+
32+
def test_errors(self):
33+
satpos = np.array([0.0, 0.0, 3.0])
34+
model = gtsam.noiseModel.Unit.Create(1)
35+
factor = gtsam.PseudorangeFactor(0, 1, 4.0, satpos, 0.0, model)
36+
error = factor.evaluateError(np.zeros(3), 0.0)
37+
self.assertEqual(error[0], -1.0)
38+
39+
def test_equality(self):
40+
satpos = np.array([0.0, 0.0, 3.0])
41+
model = gtsam.noiseModel.Unit.Create(1)
42+
factor1 = gtsam.PseudorangeFactor(0, 1, 4.0, satpos, 0.0, model)
43+
factor2 = gtsam.PseudorangeFactor(2, 1, 4.0, satpos, 0.0, model)
44+
factor3 = gtsam.PseudorangeFactor(0, 1, 40.0, satpos, 10.0, model)
45+
self.assertTrue(factor1.equals(factor1, 1e-6))
46+
self.assertFalse(factor1.equals(factor2, 1e-6))
47+
self.assertTrue(factor1.equals(factor3, 1e99))
48+
49+
def test_serialization(self):
50+
satpos = np.array([0.0, 0.0, 3.0])
51+
model = gtsam.noiseModel.Unit.Create(1)
52+
factor = gtsam.PseudorangeFactor(0, 1, 4.0, satpos, 0.0, model)
53+
factor.serialize()
2354

2455

2556
if __name__ == "__main__":

0 commit comments

Comments
 (0)