Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change the orbital analyser to use the Trajectory interface #3519

Merged
merged 65 commits into from
Feb 12, 2023
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
5d2e8cd
Start to use Trajectory, but unwinding makes our life harder.
pleroy Jan 1, 2023
600bbf0
A promising attempt
eggrobin Jan 1, 2023
af60f79
the integrator is confused
eggrobin Jan 2, 2023
f0bfe5f
merge
eggrobin Jan 2, 2023
95a1d7b
unwinding
eggrobin Jan 2, 2023
c95b242
unwinding that works
eggrobin Jan 2, 2023
437f173
more traces
eggrobin Jan 2, 2023
788ca62
back to fixed step
eggrobin Jan 2, 2023
0e66b9a
bad unwinding
eggrobin Jan 2, 2023
8400e7e
An attempt at Clenshaw-Curtis that does not work too badly
eggrobin Jan 2, 2023
c3501d4
do we really need dense output?
eggrobin Jan 2, 2023
5414a4d
Merge remote-tracking branch 'la-vache/master' into better-integration
eggrobin Jan 12, 2023
ca81bbd
use RK4
eggrobin Jan 12, 2023
d19fbd3
a bug
eggrobin Jan 15, 2023
0d6dbd6
Trying to throw more automated Clenshaw Curtis at the problem
eggrobin Jan 16, 2023
b9ca286
do interpolation correctly
eggrobin Jan 16, 2023
8ac094d
compute osculating elements, and notice the noise
eggrobin Jan 19, 2023
50959b2
Merge branch 'better-integration' of https://github.com/eggrobin/Prin…
pleroy Jan 28, 2023
5e8ed38
ELMS.
pleroy Jan 28, 2023
e5d28e6
Merge.
pleroy Jan 28, 2023
2de7b6d
Merge branch 'Orbit' into Benchmarque
pleroy Jan 28, 2023
9bc51ed
AB order 6.
pleroy Jan 28, 2023
44bffc8
Merge branch 'Benchmark' into Benchmarque
pleroy Jan 28, 2023
afcab79
remove logger and don’t densely sample outside of tests
eggrobin Jan 28, 2023
024d755
Avoid allocations in the integrator.
pleroy Jan 29, 2023
ad1eebd
Avoid allocation in the ODE's equation.
pleroy Jan 29, 2023
b3ffd31
Unused code.
pleroy Jan 29, 2023
c9c0dcd
Move instead of copy.
pleroy Jan 29, 2023
4f40081
Merge.
pleroy Jan 29, 2023
5ca5aa3
Adjust for non-vector ODEs.
pleroy Jan 29, 2023
6286a1f
Je n'en sais rien.
pleroy Jan 30, 2023
aaad34a
Let's make a pause.
pleroy Jan 30, 2023
536f97b
A benchmark with a more inclined trajectory.
pleroy Jan 30, 2023
38970e6
Cleaned up the Augean stables.
pleroy Jan 30, 2023
c100c60
It kind-of works.
pleroy Jan 30, 2023
0a31db0
All tests passing.
pleroy Jan 30, 2023
58440f8
Cleanup.
pleroy Jan 30, 2023
d866566
Bring the projects back alive.
pleroy Jan 30, 2023
6fc31b8
Fix a compilation error.
pleroy Jan 30, 2023
2342674
Minor fixes.
pleroy Jan 30, 2023
04b2c47
Tolerances.
pleroy Jan 31, 2023
8f3720c
Lint.
pleroy Jan 31, 2023
1c290e3
Parameterization of Clenshaw-Curtis.
pleroy Jan 31, 2023
47a87f5
Specific downsampling tolerance for the orbit analyser.
pleroy Feb 7, 2023
bbe0517
Smaller tolerance.
pleroy Feb 7, 2023
413773c
Fix compilation error.
pleroy Feb 7, 2023
89129e7
Merge branch 'Benchmarque' of https://github.com/pleroy/Principia int…
pleroy Feb 8, 2023
35612b0
Heun
eggrobin Feb 8, 2023
cef4f0b
remove bad condition
eggrobin Feb 8, 2023
5629624
Compile out the logging.
pleroy Feb 8, 2023
86167ae
Mathematica logging.
pleroy Feb 10, 2023
ec5d1c5
Moal traces.
pleroy Feb 10, 2023
df94c90
Merge.
pleroy Feb 10, 2023
5127615
Code cleanup and better tolerances.
pleroy Feb 10, 2023
778f2eb
Bring back the tests.
pleroy Feb 10, 2023
a547281
Fix the tolerances.
pleroy Feb 10, 2023
9b6c6dd
Fixed-step integrator in test.
pleroy Feb 10, 2023
778d1a8
Minor cleanup.
pleroy Feb 11, 2023
c10ba43
More funky tolerance.
pleroy Feb 11, 2023
836ad9e
Logging the errors.
pleroy Feb 11, 2023
34d3ebc
Combined.
pleroy Feb 11, 2023
98cbeb8
Remove bad tests.
pleroy Feb 12, 2023
6302dc3
Benchmark downsampling tolerance.
pleroy Feb 12, 2023
b30a10b
After egg+phl's review.
pleroy Feb 12, 2023
3d4be26
Compilation error.
pleroy Feb 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 38 additions & 37 deletions astronomy/orbit_analysis_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,11 @@ class OrbitAnalysisTest : public ::testing::Test {
std::tuple<OrbitalElements, OrbitRecurrence, OrbitGroundTrack>
ElementsAndRecurrence(SP3Orbit const& orbit) {
auto const earth_centred_trajectory = EarthCentredTrajectory(orbit);
auto elements = OrbitalElements::ForTrajectory(
*earth_centred_trajectory,
earth_,
MasslessBody{}).value();
auto elements =
OrbitalElements::ForTrajectory(*earth_centred_trajectory,
earth_,
MasslessBody{},
/*sample_dense_elements=*/true).value();
pleroy marked this conversation as resolved.
Show resolved Hide resolved

{
auto const identifier = (std::stringstream() << orbit.satellite).str();
Expand Down Expand Up @@ -361,7 +362,7 @@ TEST_F(OrbitAnalysisTest, 北斗MEO) {
EXPECT_THAT(elements.mean_eccentricity_interval().midpoint(),
IsNear(0.000558_(1)));
EXPECT_THAT(elements.mean_argument_of_periapsis_interval().midpoint(),
IsNear(1.003_(1) * Degree));
IsNear(1.033_(1) * Degree));
}

// COSPAR ID 2016-030A.
Expand All @@ -377,7 +378,7 @@ TEST_F(OrbitAnalysisTest, GalileoNominalSlot) {
Property(&OrbitRecurrence::Cᴛₒ, 10)));

// Reference elements from
// https://www.gsc-europa.eu/system-status/orbital-and-technical-parameters.
// https://www.gsc-europa.eu/system-service-status/orbital-and-technical-parameters.
Instant const reference_epoch = "2016-11-21T00:00:00"_UTC;
Instant const initial_time = elements.mean_elements().front().time;
Instant const mean_time =
Expand All @@ -399,14 +400,14 @@ TEST_F(OrbitAnalysisTest, GalileoNominalSlot) {

EXPECT_THAT(elements.mean_semimajor_axis_interval().midpoint(),
AbsoluteErrorFrom(29'599.8 * Kilo(Metre),
IsNear(0.35_(1) * Kilo(Metre))));
IsNear(0.33_(1) * Kilo(Metre))));
EXPECT_THAT(elements.mean_semimajor_axis_interval().measure(),
IsNear(00'000.084_(1) * Kilo(Metre)));
IsNear(00'000.085_(1) * Kilo(Metre)));

EXPECT_THAT(elements.mean_eccentricity_interval().midpoint(),
IsNear(0.000'17_(1))); // Nominal: 0.0.
EXPECT_THAT(elements.mean_eccentricity_interval().measure(),
IsNear(0.000'015_(1)));
IsNear(0.000'023_(1)));

EXPECT_THAT(elements.mean_inclination_interval().midpoint(),
AbsoluteErrorFrom(56.0 * Degree, IsNear(0.61_(1) * Degree)));
Expand All @@ -425,7 +426,7 @@ TEST_F(OrbitAnalysisTest, GalileoNominalSlot) {
EXPECT_THAT(elements.mean_argument_of_periapsis_interval().midpoint(),
IsNear(88_(1) * Degree));
EXPECT_THAT(elements.mean_argument_of_periapsis_interval().measure(),
IsNear(6.3_(1) * Degree));
IsNear(8.9_(1) * Degree));

// Since the reference parameters conventionally set ω = 0, the given mean
// anomaly is actually the mean argument of latitude; in order to get numbers
Expand Down Expand Up @@ -468,20 +469,20 @@ TEST_F(OrbitAnalysisTest, GalileoExtendedSlot) {
RelativeErrorFrom(nominal_nodal_precession, IsNear(0.0059_(1)))));
EXPECT_THAT(2 * π * Radian / elements.anomalistic_period(),
AllOf(AbsoluteErrorFrom(nominal_anomalistic_mean_motion,
IsNear(0.00047_(1) * Degree / Day)),
IsNear(0.00097_(1) * Degree / Day)),
RelativeErrorFrom(nominal_anomalistic_mean_motion,
IsNear(7.1e-07_(1)))));
IsNear(1.5e-06_(1)))));

EXPECT_THAT(elements.mean_semimajor_axis_interval().midpoint(),
AbsoluteErrorFrom(27'977.6 * Kilo(Metre),
IsNear(0.0997_(1) * Kilo(Metre))));
IsNear(0.0677_(1) * Kilo(Metre))));
EXPECT_THAT(elements.mean_semimajor_axis_interval().measure(),
IsNear(00'000.096_(1) * Kilo(Metre)));
IsNear(00'000.492_(1) * Kilo(Metre)));

EXPECT_THAT(elements.mean_eccentricity_interval().midpoint(),
AbsoluteErrorFrom(0.162, IsNear(0.0041_(1))));
EXPECT_THAT(elements.mean_eccentricity_interval().measure(),
IsNear(0.000'15_(1)));
IsNear(0.000'16_(1)));

EXPECT_THAT(elements.mean_inclination_interval().midpoint(),
AbsoluteErrorFrom(49.850 * Degree, IsNear(0.77_(1) * Degree)));
Expand Down Expand Up @@ -562,20 +563,20 @@ TEST_F(OrbitAnalysisTest, TOPEXPoséidon) {
Property(&OrbitRecurrence::Dᴛₒ, -3),
Property(&OrbitRecurrence::Cᴛₒ, 10)));

// Reference semimajor axis from the legend of figure 7 of Bhat et al.; that
// value is given as 7 714.42942 in table 1 of Bhat et al., 7 714.4278 km in
// Blanc et al., and 7 714.43 km in Benada.
// Figure 7 of Bhat et al. shows that the mean semimajor axis varies by up to
// Reference semimajor axis from the legend of figure 7 of [BSFL98]; that
// value is given as 7 714.42942 in table 1 of [BSFL98], 7 714.4278 km in
// [BS96], and 7 714.43 km in [Ben97].
// Figure 7 of [BSFL98] shows that the mean semimajor axis varies by up to
// 6 m either side of the reference value. Our test data is from cycle 198;
// reading the graph around that time shows that the mean semimajor axis was a
// bit less than 3 m above the nominal value around that time.
EXPECT_THAT(
elements.mean_semimajor_axis_interval().midpoint(),
DifferenceFrom(7714.42938 * Kilo(Metre), IsNear(2.93_(1) * Metre)));
// Reference inclination from the legend of figure 9 of Bhat et al.; that
// value is given as 66.040° in table 1 of Bhat et al., 66.039° in Blanc et
// al., and 66.04° in Benada.
// Figure 9 of Bhat et al. shows that the observed values of the mean
DifferenceFrom(7714.42938 * Kilo(Metre), IsNear(2.55_(1) * Metre)));
// Reference inclination from the legend of figure 9 of [BSFL98]; that
// value is given as 66.040° in table 1 of [BSFL98], 66.039° in [BS96], and
// 66.04° in [Ben97].
// Figure 9 of [BSFL98] shows that the observed values of the mean
// inclination vary between 66.0375° and 66.0455° over the course of the
// mission (66.0408° ± 0.0040° according to the abstract). We can see from
// the graph that during the period under test, in early December 1997, the
Expand All @@ -589,25 +590,25 @@ TEST_F(OrbitAnalysisTest, TOPEXPoséidon) {
AllOf(Field(&Interval<Angle>::min, IsNear(66.0365_(1) * Degree)),
Field(&Interval<Angle>::max, IsNear(66.0401_(1) * Degree))));

// The same nominal values are given by Blanc et al., Benada, and Bhat et al:
// The same nominal values are given by [BS96], [Ben97], and [BSFL98]:
// e = 0.000095, ω = 90.0°.
// However, these values are only meaningful if we take mean elements that are
// free of variations over one 127-revolution ground track cycle (rather than
// simply over one revolution). Figure 8 of Bhat et al. shows that both the
// simply over one revolution). Figure 8 of [BSFL98] shows that both the
// theoretical and observed mean e and ω vary between 40 ppm and 140 ppm, and
// between 60° and 120°, respectively.
EXPECT_THAT(elements.mean_eccentricity_interval(),
AllOf(Field(&Interval<double>::min, IsNear(88e-6_(1))),
Field(&Interval<double>::max, IsNear(110e-6_(1)))));
EXPECT_THAT(elements.mean_argument_of_periapsis_interval(),
AllOf(Field(&Interval<Angle>::min, IsNear(74.7_(1) * Degree)),
Field(&Interval<Angle>::max, IsNear(98.5_(1) * Degree))));
AllOf(Field(&Interval<Angle>::min, IsNear(74.6_(1) * Degree)),
Field(&Interval<Angle>::max, IsNear(98.7_(1) * Degree))));

// Nominal longitude of the equatorial crossing of the first ascending pass
// East of the ITRF zero-meridian (pass 135), as given in section 2 of Benada.
// Blanc et al. round these longitudes to a hundredth of a degree, thus 0.71°
// for pass 135.
// We can see from figure 6 of Bhat et al. that, during the period under test,
// East of the ITRF zero-meridian (pass 135), as given in section 2 of
// [Ben97]. [BS96] round these longitudes to a hundredth of a degree, thus
// 0.71° for pass 135.
// We can see from figure 6 of [BSFL98] that, during the period under test,
// the equatorial crossing is about 600 m east of the reference.
EXPECT_THAT(
ground_track
Expand All @@ -620,7 +621,7 @@ TEST_F(OrbitAnalysisTest, TOPEXPoséidon) {
IsNear(573_(1) * Metre *
(Radian / TerrestrialEquatorialRadius)))));
// Nominal longitude of the equatorial crossing of the following (descending)
// pass (pass 136), as given in section 2 of Benada. Blanc et al. round these
// pass (pass 136), as given in section 2 of [Ben97]. [BS96] round these
// longitudes to a hundredth of a degree, thus 166.54° for pass 136.
EXPECT_THAT(ground_track
.equator_crossing_longitudes(
Expand All @@ -630,10 +631,10 @@ TEST_F(OrbitAnalysisTest, TOPEXPoséidon) {
DifferenceFrom(166.5385 * Degree, IsNear(0.0071_(1) * Degree)));

// Nominal longitude of the equatorial crossing of pass 1, as given in the
// auxiliary data table in Blanc et al. The reference grid there lists that
// longitude as 99.92°, and the table of equator crossing longitudes in Benada
// lists it as 99.9249°. However, the auxiliary data table in Benada gives a
// longitude of 99.947° for pass 1, which looks like a typo.
// auxiliary data table in [BS96]. The reference grid there lists that
// longitude as 99.92°, and the table of equator crossing longitudes in
// [Ben97] lists it as 99.9249°. However, the auxiliary data table in [Ben97]
// gives a longitude of 99.947° for pass 1, which looks like a typo.
EXPECT_THAT(ground_track
.equator_crossing_longitudes(
recurrence, /*first_ascending_pass_index=*/135)
Expand Down
36 changes: 21 additions & 15 deletions astronomy/orbital_elements.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
#include "geometry/interval.hpp"
#include "geometry/named_quantities.hpp"
#include "physics/body.hpp"
#include "physics/discrete_trajectory.hpp"
#include "physics/massive_body.hpp"
#include "physics/trajectory.hpp"
#include "quantities/named_quantities.hpp"
#include "quantities/quantities.hpp"

Expand All @@ -18,8 +18,8 @@ namespace internal_orbital_elements {
using geometry::Instant;
using geometry::Interval;
using physics::Body;
using physics::DiscreteTrajectory;
using physics::MassiveBody;
using physics::Trajectory;
using quantities::Angle;
using quantities::AngularFrequency;
using quantities::Difference;
Expand All @@ -37,9 +37,10 @@ class OrbitalElements {

template<typename PrimaryCentred>
static absl::StatusOr<OrbitalElements> ForTrajectory(
DiscreteTrajectory<PrimaryCentred> const& trajectory,
Trajectory<PrimaryCentred> const& trajectory,
MassiveBody const& primary,
Body const& secondary);
Body const& secondary,
bool fill_osculating_equinoctial_elements = false);

// The classical Keplerian elements (a, e, i, Ω, ω, M),
// together with an epoch.
Expand Down Expand Up @@ -144,26 +145,31 @@ class OrbitalElements {
private:
OrbitalElements() = default;

template<typename PrimaryCentred>
static std::vector<EquinoctialElements> OsculatingEquinoctialElements(
DiscreteTrajectory<PrimaryCentred> const& trajectory,
MassiveBody const& primary,
Body const& secondary);

// TODO(egg): This is not an orbital element, and it doesn't work for non-
// discrete trajectories. It should move to the orbit analyser, at a place
// where we know that we have a discrete trajectory and we could use apsides.
template<typename PrimaryCentred>
static std::vector<Length> RadialDistances(
DiscreteTrajectory<PrimaryCentred> const& trajectory);
Trajectory<PrimaryCentred> const& trajectory);

// |equinoctial_elements| must contain at least 2 elements.
// The functor EquinoctialElementsComputation must have the profile
// |EquinoctialElements(Instant const&)|.
template<typename EquinoctialElementsComputation>
static absl::StatusOr<Time> SiderealPeriod(
std::vector<EquinoctialElements> const& equinoctial_elements);
EquinoctialElementsComputation const& equinoctial_elements,
Instant const& t_min,
Instant const& t_max);

// |osculating| must contain at least 2 elements.
// The resulting elements are averaged over one period, centred on
// their |EquinoctialElements::t|.
template<typename EquinoctialElementsComputation>
static absl::StatusOr<std::vector<EquinoctialElements>>
MeanEquinoctialElements(std::vector<EquinoctialElements> const& osculating,
Time const& period);
MeanEquinoctialElements(
EquinoctialElementsComputation const& equinoctial_elements,
Instant const& t_min,
Instant const& t_max,
Time const& period);

static absl::StatusOr<std::vector<ClassicalElements>> ToClassicalElements(
std::vector<EquinoctialElements> const& equinoctial_elements);
Expand Down
Loading