Documents

Physics

Gravity harmonics & third body

GGM03S spherical-harmonic geopotential, J2/J3 fallback, gravity-gradient torque, and Sun/Moon point-mass perturbations. The Moon can come from a JPL ephemeris file.

Source: cpp/src/orbit/gravity.cpp, third_body.cpp, frames.cpp, attitude/integrate.cpp.

Spherical-harmonic geopotential

\[ U=\frac{\mu}{r}\sum_{n=0}^{N}\Bigl(\frac{R}{r}\Bigr)^n\sum_{m=0}^{n}\bar P_{nm}(\sin\phi)\bigl(\bar C_{nm}\cos m\lambda+\bar S_{nm}\sin m\lambda\bigr),\qquad \mathbf a=\nabla U \]
  • Coefficients: GRACE GGM03S (data/GGM03S.txt). The header supplies R, μ, ω and nmax.
  • Reference model: Basilisk SphericalHarmonicsGravityModel, Autonomous Vehicle Systems Laboratory, University of Colorado Boulder (AVSLab/basilisk, ISC). The plant does not link Basilisk. tests/basilisk_ref/ compares the two fields. Cite Basilisk when you reuse this evaluator.
  • v2.7.5 stores the GGM03S coefficients fully normalised and evaluates fully normalised associated Legendre functions, so a 70×70 field stays finite. Degrees 2, 8 and 24 match the previous unnormalised evaluator to roundoff.
  • Degree cap SH_MAX_DEGREE = 70. Presets stay at fast 2, standard 4, high 8. gravity.model: twobody forces degree 0.
  • Frame: the gravity is evaluated in ECEF after a GMST rotation (accel_gravity_N) and rotated back. Earth orientation is GMST-only.
  • Gradient: spherical components (∂U/∂r, ∂U/∂φ, ∂U/∂λ) mapped to Cartesian, with a pole guard (cos φ < 1e-14).
  • Fallback when no GGM file is found: two-body + closed-form J2 + J3 (J2 = 1.0826e-3, J3 = −2.5327e-6). ArlamxV2Env refuses the silent fallback when a GGM path was requested but failed to load.
YAMLSimParamsDefault
gravity.model—ggm03s | twobody
gravity.degreesh_degree4 (0–70)
gravity.lunisolarlunisolarfalse (high: true)
gravity.gradient_torquegravity_gradienttrue

Magnitude guide at 400 km

Term|a| (m/s²)
Two-body8.7
J2≈ 1e-2
degree 3–8 terms1e-5 … 1e-6
Moon third body0.6–1.2e-6 (computed with cpp.accel_third_body)
Sun third body0.3–0.5e-6
Drag on the 0.625 kg SolarCat, face-on, ρ = 3e-12 kg/m³≈ 2e-4
SRP on the same sail, face-on≈ 9e-6

Gravity-gradient torque

\[ \boldsymbol\tau_{gg}=\frac{3\mu}{r^3}\,\hat u\times\mathbf I\hat u,\qquad \hat u=\text{nadir-to-spacecraft in body axes} \]

It uses the full inertia tensor, and it is on by default (gravity.gradient_torque). The mean over the step is reported as tau_gg_mean.

Third-body perturbation

\[ \mathbf a_{3B}=\mu_k\left(\frac{\mathbf r_k-\mathbf r}{|\mathbf r_k-\mathbf r|^3}-\frac{\mathbf r_k}{|\mathbf r_k|^3}\right),\qquad \mu_\odot=1.32712440018\times10^{20},\ \mu_\text{☾}=4.902800118\times10^{12}\ \mathrm{m^3s^{-2}} \]
  • This is the direct form (Montenbruck & Gill §3.3). It is accurate here because |r|/|r_k| is tiny, so there is no cancellation problem worth a Battin f(q) formulation at LEO.
  • With lunisolar: true, Sun and Moon positions are computed once per advisor step (300 s) and held. The Moon moves ≈ 0.04° in that time, which is negligible.
  • Presets: only high enables lunisolar.

Moon: analytic vs ephemeris file

Ephemeris::moon_pos(jd) returns the CSPICE spkezr_c("MOON", et, "J2000", "NONE", "EARTH") position when kernels are loaded. Otherwise it falls back to a truncated Meeus series (5 longitude terms, 2 latitude terms, parallax distance).

SourceMoon direction errorMoon distance errorEffect on a_3B at 400 km
Analytic Meeus (current build)0.25° mean, 0.44° maxup to ≈ 3000 km≈ 3e-8 m/s² (≈ 3 % of the lunar term)
DE440/DE430 via CSPICE< 1e-6° (kernel accuracy)metresnegligible

The analytic errors above were measured for this page against astropy's built-in ephemeris over 40 epochs in 2026 (TETE frame).

Current state: the ephemeris path is present but not wired
  1. The shipped .so was built without CSPICE (CSPICE_INCLUDE and CSPICE_LIB are empty in build/CMakeCache.txt). load_spice therefore returns False and does nothing.
  2. Nothing in env.py, physics.py or the YAMLs calls load_spice, and there is no ephemeris: config key.
  3. The time argument is converted as et = (jd − 2451545.0)·86400, which treats the UTC Julian date as TDB. That is ≈ 69 s off in 2026, or ≈ 70 km of lunar motion.
  4. SPICE returns J2000 axes, while the plant's inertial axes are effectively of-date (GMST rotation, analytic Sun of date). That is a ≈ 0.36° precession mismatch in 2026 for the Sun direction used in SRP and eclipse once SPICE is on. It is harmless for third-body accelerations but visible in eclipse entry/exit timing (up to a few seconds).

How to use an ephemeris file today (no code changes)

  1. Rebuild with CSPICE (instructions) and confirm ARLAMX: CSPICE enabled in the configure output.
  2. Download an SPK, for example de440s.bsp (1849–2150, ≈ 32 MB) from NAIF generic_kernels/spk/planets/.
  3. In your own driver script, after the env is built:
    env = ArlamxV2Env(variant="v10", physics="high")          # high => lunisolar: true
    ok = env.sim.load_spice(["/data/kernels/de440s.bsp"])     # True only if CSPICE is linked
    assert ok, "CSPICE not linked or kernel failed to load"
    With SubprocVecEnv each worker must call it, so wrap it in make_env or an env_kw hook. SPICE state is process-global.
  4. For a standard-physics run with the Moon on, pass --physics a copy of physics.yaml with gravity.lunisolar: true.

A proper ephemeris: {kernels: [...]} YAML key, the TDB conversion and a J2000→of-date rotation are small follow-ups. They are listed in Validation & known limits.

Validation

  • tests/orbit/test_gravity.py: J2/J3 closed form vs SH, finite-difference gradient of U.
  • tests/basilisk_ref/test_gravity_vs_basilisk.py: SH acceleration vs Basilisk computeField (passes here; skipped without Basilisk).
  • tests/orbit/test_third_body.py: hand-evaluated third-body case, eclipse, analytic Sun.
  • ACEnv/Reports/verify_gravity.md: audit record.

References

  1. Tapley, B. et al. (2007). GGM03 — CSR GRACE gravity model.
  2. Montenbruck, O. & Gill, E. (2000). Satellite Orbits, §3.2–3.3.
  3. Kaula, W. M. (1966). Theory of Satellite Geodesy.
  4. Meeus, J. (1998). Astronomical Algorithms, ch. 47.
  5. Acton, C. H. (1996). NAIF SPICE. Planet. Space Sci. 44(1).