Draw four moons' nodes at JPL's current rates, which Horizons and the IAU's poles agree with
The archived satellite table the moons are read from gives older node
periods than JPL's current one for Miranda (17.727 years against URA182's
17.787), Ganymede (132.654 against 137.812), Callisto (338.82 against
577.264) and Titan (704.60 against 687.370), and 74ea1d6 turned the IAU's
poles after those older rates, taking them for the right ones. They were
not: fitted to Horizons' osculating elements on Uranus's equator over
1601-2399, Miranda's node turns 2023.97 degrees a century (rms 0.04),
against the current table's 2023.95, the IAU's U11 2024.22 and the row's
2030.80. That commit moved Miranda's axis from 0.38 to 2.36 degrees of
Horizons' orbit normal. Mimas's node, 0.986 years in both tables, now takes
the IAU's S3, 36505.5 degrees a century, 1.2 from a Horizons fit where
the row's is 4.5.
The ETL spec carries the node period (nodePeriodYears), and the periapsis
keeps the row's longitude rate: the row gives the longitude's rate (Callisto
68.7 degrees a century, the current table 67.2), so the argument takes up
the change. On the row's argument Callisto's periapsis moved 44 degrees by
2100 and it strayed 0.71 degrees from Horizons over 1950-2100.
Worst angle from Horizons' osculating orbit normal (ICRF), HEAD then now:
- Miranda, 1601-2399: drawn orbit 2.11 -> 0.12, axis 2.36 -> 0.34.
- Mimas, 1750-2249: orbit 0.33 -> 0.11, axis 0.65 -> 0.40.
- Ganymede, 1600-2199: orbit 0.17 -> 0.11, axis 0.13 -> 0.01.
- Callisto, 1600-2199: orbit 0.53 -> 0.20, axis 0.02 -> 0.03.
- Titan, 1750-2249: orbit 0.048 -> 0.052.
Against the 1950-2100 Horizons tracks the ETL checks: Callisto 0.19 -> 0.08,
Miranda 1.73 -> 1.62, Ganymede 0.30 -> 0.29, Mimas 7.43 -> 7.42, Titan 0.06.
lockedToOrbit now barely moves the IAU's node terms: Miranda's U11 to
-2023.95, Ganymede's J5 to 261.23 (262.1), Mimas's S3 not at all, and
Callisto's J6, 3.1 per cent from its new node rate, to 62.36 (64.3), which
takes Callisto's axis from 0.56 to 0.22 degrees of its drawn orbit.
With the drawn rates right, leaving every node term at the IAU's rate no
longer failed the ETL (Mimas used to), nor did a 1 per cent tolerance, the
node's angle without its harmonics, or the older node periods. The axis
ceiling is now 0.25 degrees for Europa (0.13 measured), Ganymede (0.16),
Callisto (0.22), Rhea (0.17), Miranda (0.23) and Triton (0.15), and
Callisto's track ceiling 0.15 (0.08). Guarded mutants, each through the
solar ETL on the real catalogue and then the suite on the bodies.json it
wrote:
- node terms left at the IAU's rates: ETL "europa's spin axis leans up to
0.33"; suite fails only 'turns the poles of Europa, Ganymede, Callisto,
Rhea, Miranda and Triton round with their drawn nodes'.
- tolerance 1 per cent: ETL, Callisto 0.33; the same test, alone.
- harmonics dropped: ETL, Triton 0.29 (the suite's three dates miss it).
- the archived node periods: ETL, Callisto's track 0.19; the suite fails
that test and 'draws Miranda's orbit, and turns its axis, where Horizons
has its orbit in 1601 and 2390' (orbit 2.02, axis 2.36 at 1601).
- the row's argument kept: ETL, Callisto's track 0.71.
The docs that called the IAU's rates the wrong ones are corrected
(lockedToOrbit, the axis ceiling in build.ts, whose Titan node now turns
in 687 years), and the README and BodyRecord doc no longer say every
locked moon's node terms are re-rated: only those within 5 per cent of a
multiple of the node's rate, never the Moon's or Phobos's, and not the
circles Ariel's, Umbriel's, Titania's and Oberon's poles go round on
(0.36 to 0.50 degrees off their orbits). The README also names the five
bodies the IAU's elements do not turn. Unit suite 866 passed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import { lockedToOrbit } from './lib/locked-spin';
|
||||
import { dataPath, ensureDataDir } from './lib/paths';
|
||||
|
||||
const HOURS_PER_DAY = 24;
|
||||
const DAYS_PER_JULIAN_YEAR = 365.25;
|
||||
|
||||
interface BodySpec {
|
||||
id: string;
|
||||
@@ -51,6 +52,25 @@ interface BodySpec {
|
||||
nodeOffsetDeg?: number;
|
||||
epochJd?: number;
|
||||
periodDays?: number;
|
||||
/**
|
||||
* The node's period, in Julian years, where the row's is out of date. The archived table the rows
|
||||
* are read from (see `fetchSatelliteMeanElementsHtml`) has older node periods for four moons than
|
||||
* JPL's current one (ssd.jpl.nasa.gov/sats/elem), and Horizons and the IAU agree with the current
|
||||
* ones: Miranda 17.787 years there (URA182) against the row's 17.727, Ganymede 137.812 (JUP365)
|
||||
* against 132.654, Callisto 577.264 against 338.82, Titan 687.370 (SAT441) against 704.60. Fitted
|
||||
* to Horizons' osculating elements on Uranus's equator over 1601-2399, Miranda's node turns
|
||||
* 2023.97 degrees a century (rms 0.04): the current table's 2023.95, the IAU's U11 2024.22, the
|
||||
* row's 2030.80. On the row's rate Miranda's drawn orbit was 2.0 degrees from Horizons' at 1601
|
||||
* and 2.1 at 2399, and the axis `lockedToOrbit` turned after it 2.4 at 1601; on this one, at most 0.12 and 0.34 over 1601-2399.
|
||||
*
|
||||
* The row's periapsis turns at its argument's rate from that node, and it is the longitude, node
|
||||
* plus argument, the row gives the rate of: Callisto's turns 68.7 degrees a century in the row and
|
||||
* 67.2 in the current table, where their arguments turn at 175.0 and 129.5. So the argument takes
|
||||
* up what the node's rate gives: on the new node and the row's argument, Callisto's periapsis
|
||||
* moved 44 degrees by 2100 and Callisto strayed 0.71 degrees from Horizons over 1950-2100 (0.19
|
||||
* before); keeping the row's longitude, 0.08.
|
||||
*/
|
||||
nodePeriodYears?: number;
|
||||
/**
|
||||
* The terms of the IAU's W that are this locked moon's motion along its orbit, which its row has
|
||||
* no column for: W's quadratic, and the term whose angle turns at `angleRateDegPerCentury`, if
|
||||
@@ -72,6 +92,14 @@ interface BodySpec {
|
||||
/** S5 in pck00011.tpc, 316.45 + 506.2 T: the libration of Mimas and Tethys in their 4:2 resonance. */
|
||||
const MIMAS_TETHYS_LIBRATION = { angleRateDegPerCentury: 506.2 };
|
||||
|
||||
/**
|
||||
* Mimas's node period, 0.986 years in both JPL's tables, is given to three figures: anywhere from
|
||||
* 36 493 to 36 530 degrees a century. It takes the IAU's S3, 36 505.5, which a fit to Horizons'
|
||||
* osculating elements on Saturn's equator over 1750-2249, 36 506.7, is 1.2 from; the row's figure,
|
||||
* 36 511.2, is 4.5.
|
||||
*/
|
||||
const MIMAS_NODE_PERIOD_YEARS = 36000 / 36505.5;
|
||||
|
||||
/**
|
||||
* The poles of the equators JPL refers Uranus's and Pluto's moons to, from the IAU WGCCRE 2015
|
||||
* report, each taken at the end the table's inclinations are measured from (Titania 0.079
|
||||
@@ -125,14 +153,14 @@ const BODY_SPECS: BodySpec[] = [
|
||||
{ id: 'deimos', name: 'Deimos', kind: 'moon', horizonsCommand: '402', center: '500@499', parentBodyId: 'mars' },
|
||||
{ id: 'io', name: 'Io', kind: 'moon', horizonsCommand: '501', center: '500@599', parentBodyId: 'jupiter', apsidesRegress: true },
|
||||
{ id: 'europa', name: 'Europa', kind: 'moon', horizonsCommand: '502', center: '500@599', parentBodyId: 'jupiter', apsidesRegress: true },
|
||||
{ id: 'ganymede', name: 'Ganymede', kind: 'moon', horizonsCommand: '503', center: '500@599', parentBodyId: 'jupiter' },
|
||||
{ id: 'callisto', name: 'Callisto', kind: 'moon', horizonsCommand: '504', center: '500@599', parentBodyId: 'jupiter' },
|
||||
{ id: 'mimas', name: 'Mimas', kind: 'moon', horizonsCommand: '601', center: '500@699', parentBodyId: 'saturn', orbitFromW: MIMAS_TETHYS_LIBRATION },
|
||||
{ id: 'ganymede', name: 'Ganymede', kind: 'moon', horizonsCommand: '503', center: '500@599', parentBodyId: 'jupiter', nodePeriodYears: 137.812 },
|
||||
{ id: 'callisto', name: 'Callisto', kind: 'moon', horizonsCommand: '504', center: '500@599', parentBodyId: 'jupiter', nodePeriodYears: 577.264 },
|
||||
{ id: 'mimas', name: 'Mimas', kind: 'moon', horizonsCommand: '601', center: '500@699', parentBodyId: 'saturn', orbitFromW: MIMAS_TETHYS_LIBRATION, nodePeriodYears: MIMAS_NODE_PERIOD_YEARS },
|
||||
{ id: 'enceladus', name: 'Enceladus', kind: 'moon', horizonsCommand: '602', center: '500@699', parentBodyId: 'saturn' },
|
||||
{ id: 'tethys', name: 'Tethys', kind: 'moon', horizonsCommand: '603', center: '500@699', parentBodyId: 'saturn', orbitFromW: MIMAS_TETHYS_LIBRATION },
|
||||
{ id: 'dione', name: 'Dione', kind: 'moon', horizonsCommand: '604', center: '500@699', parentBodyId: 'saturn' },
|
||||
{ id: 'rhea', name: 'Rhea', kind: 'moon', horizonsCommand: '605', center: '500@699', parentBodyId: 'saturn' },
|
||||
{ id: 'titan', name: 'Titan', kind: 'moon', horizonsCommand: '606', center: '500@699', parentBodyId: 'saturn' },
|
||||
{ id: 'titan', name: 'Titan', kind: 'moon', horizonsCommand: '606', center: '500@699', parentBodyId: 'saturn', nodePeriodYears: 687.37 },
|
||||
// Hyperion tumbles ("Rotational period = Chaotic") and Phoebe, captured, turns in 9.27 hours.
|
||||
// Hyperion's eccentricity is 0.105 in JPL's current table (ssd.jpl.nasa.gov/sats/elem, SAT441).
|
||||
{ id: 'hyperion', name: 'Hyperion', kind: 'moon', horizonsCommand: '607', center: '500@699', parentBodyId: 'saturn', spinsFreely: true, measuredEccentricity: 0.105, trackStepDays: 1 },
|
||||
@@ -147,7 +175,7 @@ const BODY_SPECS: BodySpec[] = [
|
||||
// (2.58 in 1969). The table's note on misstated retrograde mean motions is about another source,
|
||||
// Jacobson 2000 on Jupiter's outer moons, and says the table carries the corrected values.
|
||||
{ id: 'phoebe', name: 'Phoebe', kind: 'moon', horizonsCommand: '609', center: '500@699', parentBodyId: 'saturn', spinsFreely: true, periodDays: 550.30391 },
|
||||
{ id: 'miranda', name: 'Miranda', horizonsCommand: '705', ...URANUS_MOON },
|
||||
{ id: 'miranda', name: 'Miranda', horizonsCommand: '705', ...URANUS_MOON, nodePeriodYears: 17.787 },
|
||||
{ id: 'ariel', name: 'Ariel', horizonsCommand: '701', ...URANUS_MOON },
|
||||
{ id: 'umbriel', name: 'Umbriel', horizonsCommand: '702', ...URANUS_MOON },
|
||||
{ id: 'titania', name: 'Titania', horizonsCommand: '703', ...URANUS_MOON },
|
||||
@@ -215,6 +243,9 @@ export async function fetchSolarSystem(): Promise<{ bodies: BodyRecord[]; horizo
|
||||
(parentName
|
||||
? parseSatelliteMeanElements(satelliteElements, parentName, spec.name, spec.apsidesRegress ?? false, spec.equatorPole)
|
||||
: parsePlanetMeanElements(planetElements, spec.id));
|
||||
const nodeRate = spec.nodePeriodYears
|
||||
? Math.sign(read.rates.longitudeOfAscendingNodeDegPerDay) * (360 / (spec.nodePeriodYears * DAYS_PER_JULIAN_YEAR))
|
||||
: read.rates.longitudeOfAscendingNodeDegPerDay;
|
||||
const corrected: MeanOrbit = {
|
||||
...read,
|
||||
orbit: {
|
||||
@@ -222,7 +253,13 @@ export async function fetchSolarSystem(): Promise<{ bodies: BodyRecord[]; horizo
|
||||
longitudeOfAscendingNodeDeg: read.orbit.longitudeOfAscendingNodeDeg + (spec.nodeOffsetDeg ?? 0),
|
||||
epochJd: spec.epochJd ?? read.orbit.epochJd
|
||||
},
|
||||
rates: spec.periodDays ? { ...read.rates, meanMotionDegPerDay: 360 / spec.periodDays } : read.rates
|
||||
rates: {
|
||||
...read.rates,
|
||||
...(spec.periodDays ? { meanMotionDegPerDay: 360 / spec.periodDays } : {}),
|
||||
longitudeOfAscendingNodeDegPerDay: nodeRate,
|
||||
// The periapsis's longitude keeps the row's rate; see `nodePeriodYears`.
|
||||
argumentOfPeriapsisDegPerDay: read.rates.argumentOfPeriapsisDegPerDay + (read.rates.longitudeOfAscendingNodeDegPerDay - nodeRate)
|
||||
}
|
||||
};
|
||||
if (spec.orbitFromW && !rotation) {
|
||||
throw new Error(`${spec.name}'s orbit takes terms from a W the kernel does not give.`);
|
||||
|
||||
Reference in New Issue
Block a user