The IAU gives a locked moon's W the mean motion of whichever orbit its authors had, and JPL's table has another. Near the present the difference is nothing; over the clock's AD 1 to 3000 it turned Proteus's far side to Neptune at AD 1 (146 degrees), Mimas 52 degrees from Saturn and Miranda 23. Iapetus was worse for another reason: its IAU pole is a straight line, 3.9 degrees a century in right ascension, through its orbit normal's 3 439-year circle round the Laplace pole, which by AD 1 has run past the celestial pole (Dec 97.9), 11 degrees off the orbit, with the face 87 degrees from Saturn. Mimas and Iapetus carry mission maps, so a wrong hemisphere was drawn facing Saturn. The ETL's lock check sampled only 1950-2100, so none of it failed. tools/etl/lib/locked-spin.ts, lockedToOrbit, called for every locked moon: - W's rate becomes the orbit's own mean motion, its constant moved so W is unchanged on 2025-01-01; the pole and every periodic term stay the IAU's. A W with a quadratic is left (Phobos's orbit already takes it; the Moon's is its tidal slowing, 0.75 degrees at AD 1). The kernel's rate must be within 1e-5 of the orbit's first (at most 3.4e-6, Iapetus). - Iapetus (poleFollowsOrbit): the pole follows its orbit normal, as a moon in a Cassini state does, in the IAU's own form: sines of the node's angle and four harmonics on right ascension, cosines on declination, fitted to the normal's circle and pinned to the IAU pole at the present; W takes sines of the same angles, fitted to hold the face where it is today. build.ts samples the lock over AD 1 to 3000 (8 114 dates, every 135 days) instead of 1950-2100, and subPlanetLongitudeDeg moved to the lib, shared by both. Measured on the real catalogue: at most 5.36 degrees (Titan) but the Moon 7.62 (its eccentricity, and W's quadratic at AD 1: a new named ceiling of 8), Mimas 8.94 (ceiling 11 -> 9.5) and Iapetus 15.95 (19 -> 16.5, 9.4 of it its row's lag); Proteus's own ceiling of 9 is gone, at 2.66. Iapetus's axis stays within 0.74 degrees of its orbit normal (11.06 before) and its pole is the IAU's at the present to 1e-4 degrees. Live on :4301, the longitude facing the planet at AD 1 / 1000 / 2025 / 2999: Proteus 2.6 / 2.6 / 2.6 / 2.6 (was -146.5 / -72.9 / 2.6 / 74.5), Iapetus -15.9 / -15.4 / -15.3 / -9.3 (-87.0 / -50.9 / -15.3 / 22.8), Mimas 4.1 / 6.8 / 5.7 / 8.4 (48.6 / 29.3 / 5.7 / -13.0), Miranda -0.1 / 2.2 / 0.0 / 1.4 (-23.4 / -9.6 / 0.0 / 12.6); the present is unchanged. The renderer spec now takes the rotational elements from bodies.json too, so no hand copy is left, and a new test turns Proteus, Miranda, Mimas and Iapetus to their planets at AD 1 and AD 3000. Guarded mutants, each run through the solar ETL and then the full suite on what it wrote: lockedToOrbit bypassed (validator: Mimas 52.30, ceiling 9.5; the new test fails), Iapetus on the IAU's straight pole (98.48), and its pole round the orbit without W's terms (73.13); each fails the new test and only it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
129 lines
5.9 KiB
TypeScript
129 lines
5.9 KiB
TypeScript
/**
|
|
* Keplerian orbital elements at a reference epoch. Positions are derived client-side by
|
|
* propagating these elements forward/backward from `epochJd` (see `shared/astro/kepler.ts`),
|
|
* rather than fetching per-frame positions.
|
|
*/
|
|
export interface OrbitalElements {
|
|
semiMajorAxisAu: number;
|
|
eccentricity: number;
|
|
inclinationDeg: number;
|
|
longitudeOfAscendingNodeDeg: number;
|
|
argumentOfPeriapsisDeg: number;
|
|
meanAnomalyAtEpochDeg: number;
|
|
epochJd: number;
|
|
}
|
|
|
|
/**
|
|
* How a body's mean elements move away from their epoch, per day.
|
|
*
|
|
* Mean elements rather than one osculating set, because the map's clock runs decades in minutes.
|
|
* An osculating orbit is exact at its instant and drifts from then on: fed to Kepler with a mass
|
|
* ratio, the Moon's went round in 27.70 days instead of 27.32 and was 66 degrees out after a year.
|
|
* A mean set carries its own measured motion, and the slow turning of its node and periapsis, so
|
|
* it holds for as long as its source was fit over.
|
|
*/
|
|
export interface MeanElementRates {
|
|
/**
|
|
* How fast the body goes round in space, in degrees per day: the rate of its mean longitude.
|
|
* 360 over this is its sidereal period.
|
|
*/
|
|
meanMotionDegPerDay: number;
|
|
longitudeOfAscendingNodeDegPerDay: number;
|
|
argumentOfPeriapsisDegPerDay: number;
|
|
semiMajorAxisAuPerDay?: number;
|
|
eccentricityPerDay?: number;
|
|
inclinationDegPerDay?: number;
|
|
/**
|
|
* Standish's extra terms in the mean anomaly of Jupiter and beyond, `b T² + c cos(f T) +
|
|
* s sin(f T)` degrees, with T in Julian centuries from the epoch and f in degrees per century:
|
|
* the great-inequality wobble his 3000 BC to AD 3000 fit needs on top of its linear rates.
|
|
*/
|
|
meanAnomalyTerms?: { b: number; c: number; s: number; f: number };
|
|
}
|
|
|
|
/**
|
|
* A solar-system planet, moon, or dwarf planet: JPL mean orbital elements, and JPL Horizons
|
|
* physical data. `systemStarId` links back to the HYG star index (the Sun, see `SUN_STAR_ID`).
|
|
*/
|
|
export interface BodyRecord {
|
|
id: string;
|
|
systemStarId: number;
|
|
name: string;
|
|
kind: 'planet' | 'moon' | 'dwarf';
|
|
radiusKm: number;
|
|
/** Mean elements at `orbit.epochJd`, moving at `rates`. */
|
|
orbit: OrbitalElements;
|
|
rates: MeanElementRates;
|
|
/**
|
|
* The pole of the plane a moon's elements are measured against, where that is its local
|
|
* Laplace plane or, for Uranus's and Pluto's moons, the planet's equator: right ascension and
|
|
* declination in the ICRF. The node is then counted from where that plane crosses the ICRF
|
|
* equator. Absent means the J2000 ecliptic, as for the planets and the Moon.
|
|
*/
|
|
laplacePole?: { raDeg: number; decDeg: number };
|
|
/** Where the elements come from and the span they hold over, as the card prints it. */
|
|
orbitSource: string;
|
|
/**
|
|
* The eccentricity the card prints, where it is not the orbit's own: Hyperion's row in the table
|
|
* its orbit is drawn from gives 0.0232, under a quarter of the 0.105 JPL's current table (SAT441)
|
|
* and Horizons (0.074 to 0.132 from 1980 to 2100) give. The older row still places Hyperion
|
|
* nearer where Horizons has it than the same row with 0.105 does, so the orbit keeps it.
|
|
*/
|
|
measuredEccentricity?: number;
|
|
/**
|
|
* For `kind: 'moon'`, the `id` of the planet it orbits — its `orbit` is expressed
|
|
* relative to that planet, not heliocentrically. Undefined for planets/dwarfs.
|
|
*/
|
|
parentBodyId?: string;
|
|
/**
|
|
* For a moon heavy enough that it and its planet go round a point outside the planet — Charon,
|
|
* an eighth of Pluto's mass, puts it 2 100 km from Pluto's centre, 900 km above its surface —
|
|
* the moon's mass over the planet's, from the GMs on their Horizons pages. The planet's own
|
|
* elements then place that barycentre, as Standish's "Pluto" does, and both bodies are drawn
|
|
* going round it. Absent for every other moon.
|
|
*/
|
|
massRatio?: number;
|
|
/**
|
|
* How the body turns on its own axis: the sidereal rotation period in hours, negative where
|
|
* Horizons gives a negative rate (Venus, Uranus), and the tilt of that axis from its orbital
|
|
* plane — which past 90 degrees already says the turn is retrograde.
|
|
*
|
|
* Absent where Horizons publishes neither — the view then leaves the body still rather than
|
|
* spinning it at an invented rate.
|
|
*/
|
|
rotationPeriodHours?: number;
|
|
obliquityDeg?: number;
|
|
/**
|
|
* Where the body's pole points and which way its prime meridian faces at any date, from the IAU
|
|
* WGCCRE 2015 report (Archinal et al. 2018) as NAIF's `pck00011.tpc` carries it, but that a locked
|
|
* moon's W turns at its drawn orbit's rate and Iapetus's pole goes round with its orbit's, so they
|
|
* keep their faces to their planets over the clock's AD 1 to 3000 (see `lockedToOrbit` in the
|
|
* ETL). Where present it alone sets how the body is drawn, and the ETL checks the period and
|
|
* obliquity above against it. Absent where the report gives none: Hyperion tumbles, and Nereid,
|
|
* Eris, Haumea and Makemake have no model.
|
|
*/
|
|
rotationalElements?: RotationalElements;
|
|
}
|
|
|
|
/**
|
|
* The IAU's rotational elements for one body: polynomials in time, plus periodic terms.
|
|
*
|
|
* The pole's right ascension and declination are in degrees in the ICRF, `[c0, c1, c2]` for
|
|
* `c0 + c1 T + c2 T²`, T in Julian centuries from J2000.0 TDB. The prime meridian W is the angle
|
|
* along the body's equator, anticlockwise seen from above that pole, from where the equator rises
|
|
* through the ICRF equator to the body's longitude 0, `c0 + c1 d + c2 d²` with d in days. A
|
|
* negative rate turns the body clockwise about the pole the IAU names: Venus, Uranus and its
|
|
* moons, Triton.
|
|
*/
|
|
export interface RotationalElements {
|
|
poleRaDeg: number[];
|
|
poleDecDeg: number[];
|
|
primeMeridianDeg: number[];
|
|
/**
|
|
* Each adds `ra sin θ` to the right ascension, `dec cos θ` to the declination and `pm sin θ` to
|
|
* W, θ being `angleDeg[0] + angleDeg[1] T + angleDeg[2] T²`. The smallest are left out; see
|
|
* `parsePckRotationalElements`.
|
|
*/
|
|
terms?: Array<{ angleDeg: number[]; ra: number; dec: number; pm: number }>;
|
|
}
|