@essrt/physics 7.0.0 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +2 -2
  2. package/package.json +4 -2
  3. package/src/constants/coefficients.d.ts +1 -38
  4. package/src/constants/coefficients.js +2 -5
  5. package/src/constants/generated.d.ts +109 -25
  6. package/src/constants/generated.js +226 -96
  7. package/src/earth/deep-orbital-history.cjs +10 -0
  8. package/src/earth/frame-of-date.cjs +105 -0
  9. package/src/eclipse/besselian.cjs +41 -17
  10. package/src/eclipse/sun-planetary-completion.cjs +55 -14
  11. package/src/index.js +9 -1
  12. package/src/model.js +262 -124
  13. package/src/moon/apparent.cjs +45 -126
  14. package/src/moon/deep-ecc-channel.cjs +59 -12
  15. package/src/moon/deep-modes-artifact.cjs +4 -2
  16. package/src/moon/month-chain.cjs +21 -10
  17. package/src/moon/series-extension.cjs +2 -1
  18. package/src/moon/series.cjs +21 -4
  19. package/src/planets/chain-artifact.js +2 -2
  20. package/src/planets/fibonacci-laws.cjs +7 -42
  21. package/src/planets/model.cjs +10 -13
  22. package/src/planets/secular-shape.cjs +36 -0
  23. package/src/planets/spin-channel.cjs +391 -0
  24. package/types/constants/coefficients.d.ts +1 -38
  25. package/types/constants/generated.d.ts +109 -25
  26. package/types/earth/deep-orbital-history.d.cts +2 -0
  27. package/types/earth/frame-of-date.d.cts +37 -0
  28. package/types/eclipse/besselian.d.cts +5 -7
  29. package/types/eclipse/sun-planetary-completion.d.cts +14 -10
  30. package/types/index.d.ts +3 -1
  31. package/types/model.d.ts +26 -0
  32. package/types/moon/apparent.d.cts +7 -68
  33. package/types/moon/deep-ecc-channel.d.cts +31 -2
  34. package/types/moon/deep-modes-artifact.d.cts +2 -0
  35. package/types/moon/month-chain.d.cts +4 -0
  36. package/types/planets/fibonacci-laws.d.cts +0 -29
  37. package/types/planets/model.d.cts +10 -4
  38. package/types/planets/secular-shape.d.cts +30 -0
  39. package/types/planets/spin-channel.d.cts +193 -0
  40. package/src/planets/predict.cjs +0 -324
  41. package/types/planets/predict.d.cts +0 -88
@@ -0,0 +1,37 @@
1
+ export type Vec3 = {
2
+ x: number;
3
+ y: number;
4
+ z: number;
5
+ };
6
+ /**
7
+ * The Earth frame of date from a one-source sample, unit vectors in the J2000
8
+ * ecliptic frame: `n` the ecliptic pole of date, `g` the equinox of date, `s`
9
+ * the spin axis of date. Every vector is `[x, y, z]`.
10
+ * @param {{epsDeg: number, equinoxLonJ2000Deg: number, orbitNormalX: number, orbitNormalY: number}} sample
11
+ * @returns {{n: number[], g: number[], s: number[]}}
12
+ */
13
+ export function computeEarthFrameOfDate(sample: {
14
+ epsDeg: number;
15
+ equinoxLonJ2000Deg: number;
16
+ orbitNormalX: number;
17
+ orbitNormalY: number;
18
+ }): {
19
+ n: number[];
20
+ g: number[];
21
+ s: number[];
22
+ };
23
+ /**
24
+ * The wheel angle θ that puts the Sun at ecliptic longitude λ on the scene's
25
+ * offset circle: the Sun sits at radius 1 (100 scene units) about a centre
26
+ * displaced by −e along the perihelion direction ϖ (the one eccentricity law's
27
+ * single arm), P(θ) = −e·û(ϖ) + û(θ), and the geocentric longitude is the
28
+ * direction of P. Two Newton steps from θ₀ = λ (the offset-circle Jacobian
29
+ * dλ/dθ = 1 − e·cos(θ − ϖ) + O(e²)); converged to <1e-12 rad for e < 0.1.
30
+ * Angles in radians; θ increases with λ (the scene's node angles are
31
+ * λ-handed).
32
+ * @param {number} lambdaRad - the target geocentric ecliptic longitude
33
+ * @param {number} e - the eccentricity (the centre offset in units of the radius)
34
+ * @param {number} periRad - the perihelion longitude ϖ of date (the offset direction is −û(ϖ))
35
+ * @returns {number} θ in radians, in (−π, π]
36
+ */
37
+ export function solveWheelAngleForLongitude(lambdaRad: number, e: number, periRad: number): number;
@@ -16,12 +16,9 @@ export type BesselianDeps = {
16
16
  */
17
17
  sunCompletionDeg: (T: number) => number;
18
18
  /**
19
- * - derived series-extension tail (deg) at T centuries TT, ADDED to the full-series Moon longitude/latitude (see moon/series-extension.cjs; same finder-scoping rationale as sunCompletionDeg — the finders stay on the bare series)
19
+ * - the Sun's derived planetary aberration κ (deg) at calendar year, SUBTRACTED from the geometric Sun longitude (the apparent Sun; see the header)
20
20
  */
21
- moonExtensionAt: (T: number) => {
22
- dLonDeg: number;
23
- dLatDeg: number;
24
- };
21
+ sunAberrationDegAt: (year: number) => number;
25
22
  /**
26
23
  * - framework ΔT (J2000-zeroed convention)
27
24
  */
@@ -54,6 +51,7 @@ export type BesselianDeps = {
54
51
  gmstMeanSiderealT0Deg: number;
55
52
  gmstMeanSiderealRateDegPerDay: number;
56
53
  gmstMeanSiderealT2Deg: number;
54
+ speedOfLightKmS: number;
57
55
  };
58
56
  };
59
57
  /**
@@ -62,7 +60,7 @@ export type BesselianDeps = {
62
60
  * full-series Moon: ecliptic-of-date longitude/latitude (deg) + distance (km), TT axis (days since J2000)
63
61
  * @property {(jdUT: number) => number} sunLonDegAt - geometric mean sun longitude (deg), JD(UT) axis with the finder's internal ΔT
64
62
  * @property {(T: number) => number} sunCompletionDeg - planetary completion (deg) at T centuries TT, SUBTRACTED from the finder sun (see eclipse/sun-planetary-completion.cjs; the finders deliberately stay without it — their fitted anchors and certified canon statistics were produced on the bare form, and elongation-class timing absorbs the omission into the fitted phases)
65
- * @property {(T: number) => {dLonDeg: number, dLatDeg: number}} moonExtensionAt - derived series-extension tail (deg) at T centuries TT, ADDED to the full-series Moon longitude/latitude (see moon/series-extension.cjs; same finder-scoping rationale as sunCompletionDeg — the finders stay on the bare series)
63
+ * @property {(year: number) => number} sunAberrationDegAt - the Sun's derived planetary aberration κ (deg) at calendar year, SUBTRACTED from the geometric Sun longitude (the apparent Sun; see the header)
66
64
  * @property {(jd: number) => number} deltaTSecondsAt - framework ΔT (J2000-zeroed convention)
67
65
  * @property {(year: number) => number} obliquityDegAt - framework obliquity (deg) at calendar year
68
66
  * @property {(year: number) => number} eccentricityAt - framework Earth-orbit eccentricity at calendar year
@@ -72,7 +70,7 @@ export type BesselianDeps = {
72
70
  * moonDiameterKm: number, sunDiameterKm: number, sunDistanceKm: number,
73
71
  * earthFlatteningInverse: number, ttBridgeSeconds: number,
74
72
  * gmstMeanSiderealT0Deg: number, gmstMeanSiderealRateDegPerDay: number,
75
- * gmstMeanSiderealT2Deg: number }} constants
73
+ * gmstMeanSiderealT2Deg: number, speedOfLightKmS: number }} constants
76
74
  */
77
75
  /** @param {BesselianDeps} deps */
78
76
  export function createBesselian(deps: BesselianDeps): {
@@ -27,13 +27,17 @@ export function createSunPlanetaryCompletion({ embWobbleArcsec, carrierRatesDegP
27
27
  * landings. */
28
28
  export const PAIRED_SUN_HARMONICS_SHA256: "cbc189cea1c20292";
29
29
  /** sha256/16 of JSON.stringify([...planets, moonElongation]) — the seven
30
- * full-precision carrier rates (deg/cy TT) the TERMS table was extracted
31
- * under at N3. The model wiring recomputes the rates live from the planet
32
- * records, so a planet-period / year / month input change moves the
33
- * carriers automatically while the table stays frozen — a silent few-
34
- * arcsec stale below the api gate's ≤8″ backstop. test:model recomputes
35
- * this fingerprint from live constants (identical arithmetic to model.js)
36
- * and fails on mismatch: re-run the N3 extraction chain
37
- * (tools/explore/n2-sun-framework-carriers.mjs →
38
- * n3-carrier-swap-preview.mjs), re-embed TERMS, and update this value. */
39
- export const PAIRED_CARRIER_RATES_SHA256: "893e055ee12343bd";
30
+ * full-precision carrier rates (deg/cy TT) the TERMS table pairs with:
31
+ * the SIDEREAL carriers of plan 06 I2 (record rate − the model's J2000
32
+ * precession; Earth the framework sidereal year; the N3 literals kept,
33
+ * the two long-period rows derived on these rates). The model wiring
34
+ * recomputes the rates live from the planet records, so a planet-period /
35
+ * year / month input change moves the carriers automatically while the
36
+ * table stays frozen — a silent few-arcsec stale below the api gate's
37
+ * ≤12″ backstop. test:model recomputes this fingerprint from live
38
+ * constants (identical arithmetic to model.js) and fails on mismatch:
39
+ * re-run the extraction chain (tools/explore/n2-sun-framework-carriers.mjs
40
+ * → i2-sidereal-carrier-table.mjs for the short-period rows,
41
+ * i2-long-inequality.mjs for the long-period rows), re-embed TERMS, and
42
+ * update this value. */
43
+ export const PAIRED_CARRIER_RATES_SHA256: "2d066e92bae955e4";
package/types/index.d.ts CHANGED
@@ -15,6 +15,7 @@ export * as planetFibonacciLaws from "./planets/fibonacci-laws.cjs";
15
15
  export * as planetOrientation from "./planets/orientation.cjs";
16
16
  export { integrateAscendingNode } from "./planets/asc-node-integrator.cjs";
17
17
  export * as planetOrbitChain from "./planets/orbit-chain.cjs";
18
+ export { computeSecularShape } from "./planets/secular-shape.cjs";
18
19
  export { createSecularSeriesOverride } from "./planets/secular-series.cjs";
19
20
  export { createDeepEccChannel } from "./moon/deep-ecc-channel.cjs";
20
21
  export { createDeepOrbitalHistory } from "./earth/deep-orbital-history.cjs";
@@ -66,13 +67,14 @@ import { REFERENCE_DATA } from './constants/index.js';
66
67
  import { assembleModel } from './model.js';
67
68
  export { GENERATED as DEFAULT_CONSTANTS, CONSTANTS_HASH, MODEL_VERSION, PREPRINT_DOI, REFERENCE_DATA };
68
69
  export { FITTED_COEFFICIENTS, COEFFICIENTS_HASH } from "./constants/index.js";
70
+ export { computeEarthFrameOfDate, solveWheelAngleForLongitude } from "./earth/frame-of-date.cjs";
69
71
  export { eccentricityFromCycles, computeEccentricityIntegrated } from "./planets/ecc-channel.cjs";
70
72
  export { buildPlanetChainsFromArtifactData, computePlanetElementsAtYear, computeHeliocentricEclipticFromElements, computePoissonArgRad, computeOsculatingElements, solveKeplerRad, computeApsidalSecularDegPerYr, ANCHOR_EPOCH_YEAR, ANCHOR_EPOCH_JD } from "./planets/keplerian-chain.cjs";
71
73
  export { computeEquatorNodeOriginSFrameDeg, convertNodeSFrameToEquatorOriginDeg } from "./planets/inv-plane-frame.cjs";
74
+ export { computePlanetPrecessionConstant, createPlanetSpinChannel, createPlanetSpinChannelFromArtifacts, computeObliquityJ2000Deg } from "./planets/spin-channel.cjs";
72
75
  export { CHAIN_ARTIFACT, CHAIN_ARTIFACT_HASH } from "./planets/chain-artifact.js";
73
76
  export { DEEP_MODES_ARTIFACT, DEEP_MODES_ARTIFACT_HASH } from "./moon/deep-modes-artifact.cjs";
74
77
  export { createYearLengths, ONE_FAMILY_WINDOW_YEARS } from "./earth/year-lengths.cjs";
75
78
  export { computeSolarTorqueShare, createComposedPrecession } from "./earth/precession-composed.cjs";
76
- export { createPredictivePrecession, calcPlanetPerihelionLongDeg } from "./planets/predict.cjs";
77
79
  export { createMoonRecessionHistory, createSolarChannelBudget } from "./deltat/recession-history.cjs";
78
80
  export { evalClimateL1OrbitalPermil, laggedL1Terms, createAlphaGiaChannel } from "./climate/l1-orbital.cjs";
package/types/model.d.ts CHANGED
@@ -89,6 +89,7 @@ export function assembleModel(C: Readonly<Record<string, any>>, F: Readonly<Reco
89
89
  }>;
90
90
  cardinal: Readonly<{
91
91
  jd: (year: number, type: string) => number;
92
+ jdNearUT: (jdUT: number, type: string) => number;
92
93
  raDeg: (year: number, type: string) => number;
93
94
  yearLengthDays: (year: number, type: string) => number;
94
95
  }>;
@@ -135,6 +136,8 @@ export function assembleModel(C: Readonly<Record<string, any>>, F: Readonly<Reco
135
136
  eclipse: Readonly<{
136
137
  sunLonDegAtJD: (jd: number) => number;
137
138
  sunLonCompletedDegAtJD: (jd: number) => number;
139
+ /** The APPARENT Sun (completed geometric − the derived aberration constant + the leading nutation terms on the model's own arguments) — the quantity Horizons' observer ecliptic longitude is; the cardinal instants are its crossings (plan 06 R1/I1). @param {number} jdUT @returns {number} */
140
+ sunApparentLonDegAtJD: (jdUT: number) => number;
138
141
  findLunarInRange: (jdStart: number, jdEnd: number) => {
139
142
  jd: number;
140
143
  beta: number;
@@ -186,5 +189,28 @@ export function assembleModel(C: Readonly<Record<string, any>>, F: Readonly<Reco
186
189
  perihelionLongitudeDeg: (k: string, year: number) => number;
187
190
  ascendingNodeInvPlaneDeg: (k: string, year: number) => number;
188
191
  invPlaneInclinationDeg: (k: string, year: number) => number;
192
+ spin: (k: string) => Readonly<{
193
+ key: string;
194
+ cassiniLocked: boolean;
195
+ momentOfInertiaFactor: number;
196
+ momentOfInertiaFactorClass: string;
197
+ alphaArcsecPerYr: number;
198
+ satelliteQuadrupole: number;
199
+ satelliteAngularMomentum: number;
200
+ spinRetrograde: boolean;
201
+ meanMotionRadPerYr: number;
202
+ obliquityJ2000Deg: number;
203
+ spinPrecessionRateArcsecPerYrJ2000: number | null;
204
+ axialPrecessionPeriodYearsJ2000: number | null;
205
+ obliquityDegAtYear: (year: number) => number | null;
206
+ spinPrecessionRateArcsecPerYrAtYear: (year: number) => number | null;
207
+ obliquityEnvelopeDeg: (year: number, spanYr: number) => {
208
+ minDeg: number;
209
+ meanDeg: number;
210
+ maxDeg: number;
211
+ } | null;
212
+ stepYr: number;
213
+ maxSpanYr: 10000000;
214
+ }>;
189
215
  }>;
190
216
  }>;
@@ -1,75 +1,14 @@
1
- export type MoonCorrectionTable = {
2
- raSinD: number;
3
- raCosD: number;
4
- raSinMp: number;
5
- raCosMp: number;
6
- raSinMs: number;
7
- raCosMs: number;
8
- decSinD: number;
9
- decCosD: number;
10
- decSinMp: number;
11
- decCosMp: number;
12
- decSinMs: number;
13
- decCosMs: number;
14
- };
15
- /**
16
- * @typedef {{raSinD: number, raCosD: number, raSinMp: number, raCosMp: number,
17
- * raSinMs: number, raCosMs: number, decSinD: number, decCosD: number,
18
- * decSinMp: number, decCosMp: number, decSinMs: number, decCosMs: number}} MoonCorrectionTable
19
- */
20
1
  /**
21
- * @param {{
22
- * constants: {
23
- * j2000JD: number,
24
- * julianCenturyDays: number,
25
- * sunMeanLongitudeJ2000Deg: number,
26
- * perihelionLongitudeJ2000Deg: number,
27
- * eccentricityJ2000: number,
28
- * eccentricityDotJ2000: number,
29
- * d5RateLDegPerDay: number,
30
- * d5RatePeriDegPerDay: number,
31
- * speedOfLight: number,
32
- * },
33
- * fns: {
34
- * computeObliquityEarth: (year: number) => number,
35
- * getAuDistanceKm: () => number,
36
- * isFrameworkNative: () => boolean,
37
- * getCorrectionResidual: () => (MoonCorrectionTable | null),
38
- * getCorrectionLegacy: () => (MoonCorrectionTable | null),
39
- * },
40
- * }} deps — the D5 rates are the engines' J2000-frozen values (the year
41
- * globals are deep-time-mutable, same pattern as FW_A2_RATE); the AU
42
- * distance is a GETTER (browser-mutable under deep time).
2
+ * No dependencies since R3 item 1 (the former D5 optics constants and the
3
+ * fitted-patch getters are gone); the factory shape is kept for the two
4
+ * scene twins' call sites.
5
+ * @param {object} [_deps] ignored
43
6
  */
44
- export function createMoonApparent({ constants, fns }: {
45
- constants: {
46
- j2000JD: number;
47
- julianCenturyDays: number;
48
- sunMeanLongitudeJ2000Deg: number;
49
- perihelionLongitudeJ2000Deg: number;
50
- eccentricityJ2000: number;
51
- eccentricityDotJ2000: number;
52
- d5RateLDegPerDay: number;
53
- d5RatePeriDegPerDay: number;
54
- speedOfLight: number;
55
- };
56
- fns: {
57
- computeObliquityEarth: (year: number) => number;
58
- getAuDistanceKm: () => number;
59
- isFrameworkNative: () => boolean;
60
- getCorrectionResidual: () => (MoonCorrectionTable | null);
61
- getCorrectionLegacy: () => (MoonCorrectionTable | null);
62
- };
63
- }): {
64
- sunGeoVecEqD5: (jd: number) => [number, number, number];
65
- moonAberrationRaDec: (jd: number, ra: number, dec: number) => {
66
- dRA: number;
67
- dDec: number;
68
- };
69
- overrideRaDec: ({ lonDeg, betRad, meeusT, obliquityDeg }: {
7
+ export function createMoonApparent(_deps?: object): {
8
+ overrideRaDec: ({ lonDeg, betRad, obliquityDeg }: {
70
9
  lonDeg: number;
71
10
  betRad: number;
72
- meeusT: (number | undefined);
11
+ meeusT?: (number | undefined);
73
12
  obliquityDeg: number;
74
13
  }) => {
75
14
  raRad: number;
@@ -1,12 +1,39 @@
1
1
  /**
2
+ * THE SLOPE ANCHOR (owner-approved model change, after the Moon panels).
3
+ * The 18-term table reproduces the attractor and the 405-kyr beat, but
4
+ * nothing constrained its local DERIVATIVE at J2000: measured, its ė read
5
+ * −5.00e-5/cy against the run's own −4.24e-5 (and the observed −4.20e-5),
6
+ * a 19 % slope error that the lunar chain multiplied straight into the
7
+ * perigee and node curvature (−44″/cy² against Meeus's −37″/cy² — the
8
+ * "18 % split" the Moon precession panels showed). Against the ±10-Myr
9
+ * series the table compresses, the error is a LINEAR vector drift of
10
+ * 2.25e-4 per kyr out to ±20 kyr (an unresolved ultra-long mode), then
11
+ * spectrum-class either way. So the anchored form gains a second,
12
+ * BOUNDED term of the same class as the constant remainder:
13
+ *
14
+ * z(t) = Σ … + (z_J2000 − Σ(0)) + (ż_J2000 − Σ̇(0))·I(t),
15
+ * I(t) = ∫₀ᵗ cos²(π τ / 2T_q) dτ (the arguments' taper: linear near
16
+ * J2000, saturating at ±T_q/2 beyond |t| ≥ T_q)
17
+ *
18
+ * — ż_J2000 is the run's own z-rate at J2000 (script-written into the
19
+ * artifact by generate.mjs from the banked series: "we are the source"),
20
+ * T_q the H/12 taper the arguments' rate anchors ride. Inside the canon it
21
+ * restores the run's slope exactly; beyond ±T_q it is a constant vector
22
+ * offset of ~3e-3, the size of the table's own spectrum-class scatter
23
+ * there, never a growing polynomial. Absent the two fields (an older
24
+ * artifact), the channel is the value-anchored form above, unchanged.
25
+ *
2
26
  * @param {{
3
27
  * earthZ: ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>,
4
28
  * anchorE: number,
5
29
  * anchorPeriEclipticDeg: number,
30
+ * anchorZDotPerYr?: ReadonlyArray<number>,
31
+ * slopeTaperYears?: number,
6
32
  * }} artifact — the embedded deep-modes artifact (earth z-modes + the J2000
7
- * anchor pair joined from the chain artifact's one home).
33
+ * anchor pair joined from the chain artifact's one home, + the J2000
34
+ * z-rate pair and the taper from the series' one home).
8
35
  */
9
- export function createDeepEccChannel({ earthZ, anchorE, anchorPeriEclipticDeg }: {
36
+ export function createDeepEccChannel({ earthZ, anchorE, anchorPeriEclipticDeg, anchorZDotPerYr, slopeTaperYears }: {
10
37
  earthZ: ReadonlyArray<{
11
38
  omegaRadPerYr: number;
12
39
  re: number;
@@ -14,6 +41,8 @@ export function createDeepEccChannel({ earthZ, anchorE, anchorPeriEclipticDeg }:
14
41
  }>;
15
42
  anchorE: number;
16
43
  anchorPeriEclipticDeg: number;
44
+ anchorZDotPerYr?: ReadonlyArray<number>;
45
+ slopeTaperYears?: number;
17
46
  }): {
18
47
  eccAt: (tYr: number) => number;
19
48
  eccRateAt: (tYr: number) => number;
@@ -136,5 +136,7 @@ export const DEEP_MODES_ARTIFACT: Readonly<{
136
136
  anchorPeriEclipticDeg: 462.9179213996577;
137
137
  anchorInclEclipticDeg: 0.00010345820355474172;
138
138
  anchorAscNodeEclipticDeg: 140.29217988414328;
139
+ anchorZDotPerYr: number[];
140
+ slopeTaperYears: 27943.083333333332;
139
141
  }>;
140
142
  export const DEEP_MODES_ARTIFACT_HASH: "77e0baf779e85de5";
@@ -14,6 +14,8 @@
14
14
  * nNodalOfDateJ2000: number,
15
15
  * moonApsidalJ2000Seconds: number,
16
16
  * moonNodalJ2000Seconds: number,
17
+ * moonApsidalOfDateJ2000Seconds: number,
18
+ * moonNodalOfDateJ2000Seconds: number,
17
19
  * moonSiderealMonthJ2000Seconds: number,
18
20
  * sPerigee: number,
19
21
  * sNode: number,
@@ -47,6 +49,8 @@ export function createMoonMonthChain({ constants, fns }: {
47
49
  nNodalOfDateJ2000: number;
48
50
  moonApsidalJ2000Seconds: number;
49
51
  moonNodalJ2000Seconds: number;
52
+ moonApsidalOfDateJ2000Seconds: number;
53
+ moonNodalOfDateJ2000Seconds: number;
50
54
  moonSiderealMonthJ2000Seconds: number;
51
55
  sPerigee: number;
52
56
  sNode: number;
@@ -25,35 +25,6 @@ export function computeInclinationLaw(b: {
25
25
  amplitude: number;
26
26
  mean: number;
27
27
  };
28
- /**
29
- * Wobble period: beat of axial precession and perihelion ICRF precession.
30
- * @param {number} periEclYr @param {number} axialYr @param {number} H
31
- * @returns {number} years */
32
- export function computeWobblePeriodYears(periEclYr: number, axialYr: number, H: number): number;
33
- /**
34
- * Obliquity cycle with the Venus/Neptune fallback: the record's cycle if
35
- * present, else |ICRF| (tidally damped — the two-component obliquity
36
- * formula cancels exactly, constant tilt).
37
- * @param {number | null | undefined} obliquityCycleYears
38
- * @param {number} periEclYr @param {number} H @returns {number} */
39
- export function resolveObliquityCycleYears(obliquityCycleYears: number | null | undefined, periEclYr: number, H: number): number;
40
- /**
41
- * Mean obliquity, SNAPSHOT form (the load-time law both engines ship):
42
- * mean = tiltJ2000 + amp·cos(ωᵢ·t₂₀₀₀) − amp·cos(ωₒ·t₂₀₀₀).
43
- * @param {{ axialTiltJ2000: number, invPlaneInclinationAmplitude: number,
44
- * perihelionEclipticYears: number }} b
45
- * @param {number | null | undefined} obliqCycleYears — falsy ⇒ static tilt
46
- * @param {{ H: number, t2000: number }} env — t2000 = 2000 − eccentricity
47
- * anchor (balancedYear − systemResetN·H)
48
- * @returns {number} degrees */
49
- export function computeObliquityMeanSnapshot(b: {
50
- axialTiltJ2000: number;
51
- invPlaneInclinationAmplitude: number;
52
- perihelionEclipticYears: number;
53
- }, obliqCycleYears: number | null | undefined, env: {
54
- H: number;
55
- t2000: number;
56
- }): number;
57
28
  /**
58
29
  * K constant from Earth's calibration. @param {{
59
30
  * eccentricityAmplitude: number, massEarthAlone: number, massSun: number,
@@ -10,8 +10,14 @@ export type PlanetModelBody = {
10
10
  inclinationCycleAnchor?: number | undefined;
11
11
  antiPhase?: boolean | undefined;
12
12
  perihelionEclipticYears?: number | undefined;
13
- axialPrecessionYears?: number | undefined;
14
- obliquityCycle?: number | null | undefined;
13
+ /**
14
+ * - carriers: the chain's g-mode beat (input since Phase 7 commit 2)
15
+ */
16
+ wobblePeriodYears?: number | undefined;
17
+ /**
18
+ * - carriers: the derived J2000 obliquity (input since Phase 7 commit 2)
19
+ */
20
+ obliquityMeanDeg?: number | undefined;
15
21
  axialTiltJ2000?: number | undefined;
16
22
  orbitalEccentricityJ2000?: number | undefined;
17
23
  ascendingNode?: number | undefined;
@@ -60,8 +66,8 @@ export type PlanetModelRecord = {
60
66
  * @property {number} [inclinationCycleAnchor]
61
67
  * @property {boolean} [antiPhase]
62
68
  * @property {number} [perihelionEclipticYears]
63
- * @property {number} [axialPrecessionYears]
64
- * @property {number|null} [obliquityCycle]
69
+ * @property {number} [wobblePeriodYears] - carriers: the chain's g-mode beat (input since Phase 7 commit 2)
70
+ * @property {number} [obliquityMeanDeg] - carriers: the derived J2000 obliquity (input since Phase 7 commit 2)
65
71
  * @property {number} [axialTiltJ2000]
66
72
  * @property {number} [orbitalEccentricityJ2000]
67
73
  * @property {number} [ascendingNode]
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @param {{ secularModes: Record<string, { z: ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}> }> }} artifact
3
+ * @param {string} key
4
+ * @returns {{ dom: { arcsecPerYr: number, amp: number }, sub: { arcsecPerYr: number, amp: number },
5
+ * rest: { count: number, amp: number }, ampSumAll: number, beatYears: number }}
6
+ */
7
+ export function computeSecularShape(artifact: {
8
+ secularModes: Record<string, {
9
+ z: ReadonlyArray<{
10
+ omegaRadPerYr: number;
11
+ re: number;
12
+ im: number;
13
+ }>;
14
+ }>;
15
+ }, key: string): {
16
+ dom: {
17
+ arcsecPerYr: number;
18
+ amp: number;
19
+ };
20
+ sub: {
21
+ arcsecPerYr: number;
22
+ amp: number;
23
+ };
24
+ rest: {
25
+ count: number;
26
+ amp: number;
27
+ };
28
+ ampSumAll: number;
29
+ beatYears: number;
30
+ };
@@ -0,0 +1,193 @@
1
+ export type SpinSatellite = {
2
+ name?: string;
3
+ gmKm3S2: number;
4
+ semiMajorAxisKm: number;
5
+ orbitalPeriodDays: number;
6
+ retrograde?: boolean;
7
+ };
8
+ export type SpinInputs = {
9
+ j2: number;
10
+ j2ReferenceRadiusKm: number;
11
+ momentOfInertiaFactor: number;
12
+ momentOfInertiaFactorClass?: string;
13
+ rotationRateDegPerDay: number;
14
+ poleRaJ2000Deg: number;
15
+ poleDecJ2000Deg: number;
16
+ cassiniLocked?: boolean;
17
+ satellites: ReadonlyArray<SpinSatellite>;
18
+ };
19
+ /** @typedef {{ name?: string, gmKm3S2: number, semiMajorAxisKm: number, orbitalPeriodDays: number, retrograde?: boolean }} SpinSatellite */
20
+ /** @typedef {{ j2: number, j2ReferenceRadiusKm: number, momentOfInertiaFactor: number,
21
+ * momentOfInertiaFactorClass?: string, rotationRateDegPerDay: number,
22
+ * poleRaJ2000Deg: number, poleDecJ2000Deg: number, cassiniLocked?: boolean,
23
+ * satellites: ReadonlyArray<SpinSatellite> }} SpinInputs */
24
+ /**
25
+ * The precession constant from the planet's own torques.
26
+ * @param {{
27
+ * j2: number, j2ReferenceRadiusKm: number, momentOfInertiaFactor: number,
28
+ * rotationRateDegPerDay: number, satellites: ReadonlyArray<SpinSatellite>,
29
+ * gmPlanetSystemKm3S2: number, meanMotionRadPerYr: number, eccentricity: number,
30
+ * }} p
31
+ * @returns {{ alphaArcsecPerYr: number, alphaRadPerYr: number, q: number, l: number,
32
+ * spinRadPerYr: number, spinRetrograde: boolean, gmPlanetAloneKm3S2: number }}
33
+ */
34
+ export function computePlanetPrecessionConstant(p: {
35
+ j2: number;
36
+ j2ReferenceRadiusKm: number;
37
+ momentOfInertiaFactor: number;
38
+ rotationRateDegPerDay: number;
39
+ satellites: ReadonlyArray<SpinSatellite>;
40
+ gmPlanetSystemKm3S2: number;
41
+ meanMotionRadPerYr: number;
42
+ eccentricity: number;
43
+ }): {
44
+ alphaArcsecPerYr: number;
45
+ alphaRadPerYr: number;
46
+ q: number;
47
+ l: number;
48
+ spinRadPerYr: number;
49
+ spinRetrograde: boolean;
50
+ gmPlanetAloneKm3S2: number;
51
+ };
52
+ /**
53
+ * @param {{
54
+ * key: string,
55
+ * spin: SpinInputs,
56
+ * zetaModes: ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>,
57
+ * anchorInclEclipticDeg: number, anchorAscNodeEclipticDeg: number,
58
+ * semiMajorAxisAU: number, eccentricity: number, massFractionOfSun: number,
59
+ * gmSunKm3S2: number, obliquityJ2000Deg: number, stepYr?: number,
60
+ * }} deps — spin from the astro-reference planetSpinPhysical block; the ζ
61
+ * table and the J2000 anchor elements from the governed artifacts; the
62
+ * mass fraction (planet system / Sun) for the two-body mean motion
63
+ * n = 2π√((1 + μ)/a³); the J2000 obliquity of the ecliptic for the pole
64
+ * conversion.
65
+ */
66
+ export function createPlanetSpinChannel(deps: {
67
+ key: string;
68
+ spin: SpinInputs;
69
+ zetaModes: ReadonlyArray<{
70
+ omegaRadPerYr: number;
71
+ re: number;
72
+ im: number;
73
+ }>;
74
+ anchorInclEclipticDeg: number;
75
+ anchorAscNodeEclipticDeg: number;
76
+ semiMajorAxisAU: number;
77
+ eccentricity: number;
78
+ massFractionOfSun: number;
79
+ gmSunKm3S2: number;
80
+ obliquityJ2000Deg: number;
81
+ stepYr?: number;
82
+ }): Readonly<{
83
+ key: string;
84
+ cassiniLocked: boolean;
85
+ momentOfInertiaFactor: number;
86
+ momentOfInertiaFactorClass: string;
87
+ alphaArcsecPerYr: number;
88
+ satelliteQuadrupole: number;
89
+ satelliteAngularMomentum: number;
90
+ spinRetrograde: boolean;
91
+ meanMotionRadPerYr: number;
92
+ obliquityJ2000Deg: number;
93
+ spinPrecessionRateArcsecPerYrJ2000: number | null;
94
+ axialPrecessionPeriodYearsJ2000: number | null;
95
+ obliquityDegAtYear: (year: number) => number | null;
96
+ spinPrecessionRateArcsecPerYrAtYear: (year: number) => number | null;
97
+ obliquityEnvelopeDeg: (year: number, spanYr: number) => {
98
+ minDeg: number;
99
+ meanDeg: number;
100
+ maxDeg: number;
101
+ } | null;
102
+ stepYr: number;
103
+ maxSpanYr: 10000000;
104
+ }>;
105
+ /**
106
+ * The channel from the governed artifacts — the ONE construction every
107
+ * runtime shares (the package model, the Node scene engine, the browser
108
+ * through the model): the spin block, the chain's J2000 anchor elements and
109
+ * the deep ζ table for `key`.
110
+ * @param {{
111
+ * key: string,
112
+ * planetSpinPhysical: Record<string, SpinInputs>,
113
+ * chainAnchorElements: Record<string, { aAU: number, e: number, inclEclipticDeg: number, ascNodeEclipticDeg: number }>,
114
+ * planetZeta: Record<string, ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>>,
115
+ * massFractionOfSun: number, gmSunKm3S2: number, obliquityJ2000Deg: number,
116
+ * }} deps
117
+ */
118
+ export function createPlanetSpinChannelFromArtifacts(deps: {
119
+ key: string;
120
+ planetSpinPhysical: Record<string, SpinInputs>;
121
+ chainAnchorElements: Record<string, {
122
+ aAU: number;
123
+ e: number;
124
+ inclEclipticDeg: number;
125
+ ascNodeEclipticDeg: number;
126
+ }>;
127
+ planetZeta: Record<string, ReadonlyArray<{
128
+ omegaRadPerYr: number;
129
+ re: number;
130
+ im: number;
131
+ }>>;
132
+ massFractionOfSun: number;
133
+ gmSunKm3S2: number;
134
+ obliquityJ2000Deg: number;
135
+ }): Readonly<{
136
+ key: string;
137
+ cassiniLocked: boolean;
138
+ momentOfInertiaFactor: number;
139
+ momentOfInertiaFactorClass: string;
140
+ alphaArcsecPerYr: number;
141
+ satelliteQuadrupole: number;
142
+ satelliteAngularMomentum: number;
143
+ spinRetrograde: boolean;
144
+ meanMotionRadPerYr: number;
145
+ obliquityJ2000Deg: number;
146
+ spinPrecessionRateArcsecPerYrJ2000: number | null;
147
+ axialPrecessionPeriodYearsJ2000: number | null;
148
+ obliquityDegAtYear: (year: number) => number | null;
149
+ spinPrecessionRateArcsecPerYrAtYear: (year: number) => number | null;
150
+ obliquityEnvelopeDeg: (year: number, spanYr: number) => {
151
+ minDeg: number;
152
+ meanDeg: number;
153
+ maxDeg: number;
154
+ } | null;
155
+ stepYr: number;
156
+ maxSpanYr: 10000000;
157
+ }>;
158
+ /**
159
+ * The DERIVED J2000 obliquity to the planet's own orbit, degrees: the angle
160
+ * between the J2000 spin axis (angular-momentum sense — Venus ≈ 177°,
161
+ * Uranus ≈ 98°) and the chain's J2000 orbit plane. Needs no mode table and
162
+ * no integration — the load-time twins read it for the K device's
163
+ * "mean obliquity" slot (commit 2 of Phase 7); the acute form is
164
+ * `min(ε, 180 − ε)`.
165
+ * @param {{ spin: SpinInputs, anchorInclEclipticDeg: number,
166
+ * anchorAscNodeEclipticDeg: number, obliquityJ2000Deg: number }} p
167
+ * @returns {number}
168
+ */
169
+ export function computeObliquityJ2000Deg(p: {
170
+ spin: SpinInputs;
171
+ anchorInclEclipticDeg: number;
172
+ anchorAscNodeEclipticDeg: number;
173
+ obliquityJ2000Deg: number;
174
+ }): number;
175
+ /**
176
+ * The IAU pole (ICRF equatorial RA/Dec) as an ecliptic-J2000 unit vector.
177
+ * @param {number} raDeg @param {number} decDeg @param {number} obliquityJ2000Deg
178
+ * @returns {number[]}
179
+ */
180
+ export function poleEclipticJ2000(raDeg: number, decDeg: number, obliquityJ2000Deg: number): number[];
181
+ /**
182
+ * The planet's orbit normal n̂(t) in ecliptic J2000 from its deep ζ table,
183
+ * DC-anchored at the chain's J2000 plane (the Earth hybrid's ζ convention:
184
+ * ζ = sin(i/2)·e^{iΩ}; the anchor is the coordinate the modes wander around).
185
+ * @param {ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>} zetaModes
186
+ * @param {number} anchorInclEclipticDeg @param {number} anchorAscNodeEclipticDeg
187
+ * @returns {(tYr: number) => number[]}
188
+ */
189
+ export function createOrbitNormalEvaluator(zetaModes: ReadonlyArray<{
190
+ omegaRadPerYr: number;
191
+ re: number;
192
+ im: number;
193
+ }>, anchorInclEclipticDeg: number, anchorAscNodeEclipticDeg: number): (tYr: number) => number[];