@essrt/physics 1.9.0 → 1.11.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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@essrt/physics",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "ESSRT (Expanding Solar System Resonance Theory) physics core \u2014 pure, injectable-constants, no I/O, no globals, no DOM. The complete model incl. fitted coefficients; every published version immutably ships one recorded model identity.",
|
|
5
5
|
"essrt": {
|
|
6
6
|
"modelVersion": "v11.0",
|
package/src/eclipse/finders.cjs
CHANGED
|
@@ -35,6 +35,17 @@
|
|
|
35
35
|
|
|
36
36
|
'use strict';
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* @typedef {Object} FrameworkSunDeps
|
|
40
|
+
* @property {number} sunMeanLongitudeJ2000Deg - L0 anchor (input anchor, 280.46646)
|
|
41
|
+
* @property {number} tropicalRateDegPerCy - the framework tropical rate (from the year chain)
|
|
42
|
+
* @property {(year: number) => number} eccentricityAt - the framework e(t) law
|
|
43
|
+
* @property {(year: number) => number} perihelionLongitudeDegAt - the framework ϖ(t) law (heliocentric)
|
|
44
|
+
* @property {(year: number) => number} [meanLongitudeDegAt] - optional epoch-dependent
|
|
45
|
+
* mean longitude L(t) (e.g. L0 + ∫rate·dt from the f(Y) tropical-year chain);
|
|
46
|
+
* absent = the linear form L0 + rate·T
|
|
47
|
+
*/
|
|
48
|
+
|
|
38
49
|
/**
|
|
39
50
|
* @typedef {Object} EclipseFinderDeps
|
|
40
51
|
* @property {(jd: number) => number} moonLonDegAt - truncated-series ecliptic longitude
|
|
@@ -43,6 +54,13 @@
|
|
|
43
54
|
* @property {(jd: number) => number} deltaTSecondsAt - the engine's ΔT convention
|
|
44
55
|
* @property {() => number} getSynodicMonthDays - live (epoch-mutable)
|
|
45
56
|
* @property {() => number} getSunDistanceKm - live (epoch-mutable)
|
|
57
|
+
* @property {FrameworkSunDeps} [frameworkSun] - E4 (the native-Sun landing,
|
|
58
|
+
* plan §12i item 11): when present, sunLonDegAt uses the FRAMEWORK form —
|
|
59
|
+
* linear tropical rate + Kepler EoC (to e³) on the framework e(t)/ϖ(t)
|
|
60
|
+
* laws, TT clock unchanged — instead of the Meeus Ch. 25 polynomials.
|
|
61
|
+
* Absent = the historical Meeus form (every certified number's current
|
|
62
|
+
* basis). The swap is a conscious matched-pair event: the D2 completion's
|
|
63
|
+
* fitted 2lE residue and the certified statistics re-measure with it.
|
|
46
64
|
* @property {{ rEarthMetres: number, moonDiameterKm: number,
|
|
47
65
|
* sunDiameterKm: number, j2000JD: number, julianCenturyDays: number }} constants
|
|
48
66
|
*/
|
|
@@ -52,10 +70,27 @@ function createEclipseFinders(deps) {
|
|
|
52
70
|
const K = deps.constants;
|
|
53
71
|
|
|
54
72
|
/** Sun's geocentric ecliptic longitude in degrees (0–360) at given JD_UT.
|
|
55
|
-
* MEAN GEOMETRIC — see the module header.
|
|
73
|
+
* MEAN GEOMETRIC — see the module header. Two forms (E4): the framework
|
|
74
|
+
* form when deps.frameworkSun is injected, else Meeus Ch. 25.
|
|
75
|
+
* @param {number} jd @returns {number} */
|
|
56
76
|
function sunLonDegAt(jd) {
|
|
57
77
|
const _d2r = Math.PI / 180;
|
|
58
78
|
const T = (jd + deps.deltaTSecondsAt(jd) / 86400 - K.j2000JD) / K.julianCenturyDays;
|
|
79
|
+
if (deps.frameworkSun) {
|
|
80
|
+
// E4 framework form: linear tropical rate + Kepler EoC (to e³) on the
|
|
81
|
+
// framework e(t)/ϖ(t) laws. Same TT clock; same L0 input anchor.
|
|
82
|
+
const F = deps.frameworkSun;
|
|
83
|
+
const year = 2000 + T * 100;
|
|
84
|
+
const L = F.meanLongitudeDegAt
|
|
85
|
+
? F.meanLongitudeDegAt(year)
|
|
86
|
+
: F.sunMeanLongitudeJ2000Deg + F.tropicalRateDegPerCy * T;
|
|
87
|
+
const e = F.eccentricityAt(year);
|
|
88
|
+
const M = (L - (F.perihelionLongitudeDegAt(year) + 180)) * _d2r;
|
|
89
|
+
const C = (2 * e - e * e * e / 4) * Math.sin(M)
|
|
90
|
+
+ 1.25 * e * e * Math.sin(2 * M)
|
|
91
|
+
+ (13 / 12) * e * e * e * Math.sin(3 * M);
|
|
92
|
+
return ((L + C / _d2r) % 360 + 360) % 360;
|
|
93
|
+
}
|
|
59
94
|
const L0 = 280.46646 + 36000.76983 * T + 0.0003032 * T * T;
|
|
60
95
|
const M = (357.52911 + 35999.05029 * T - 0.0001537 * T * T) * _d2r;
|
|
61
96
|
const C = (1.914602 - 0.004817 * T - 0.000014 * T * T) * Math.sin(M)
|
|
@@ -58,6 +58,17 @@
|
|
|
58
58
|
* recomputes it from live constants and fails on mismatch. The api
|
|
59
59
|
* centerline gate (≤8″ shadow-plane) backstops gross staleness
|
|
60
60
|
* independently.
|
|
61
|
+
*
|
|
62
|
+
* E4/E5 PAIRING VERDICT (20.3h Phase 0): the framework-native Sun
|
|
63
|
+
* landing REPLACED the finder Sun form (Meeus Ch. 25 → the assembled
|
|
64
|
+
* framework Sun with the f(Y)+torque drift). The re-derivation this
|
|
65
|
+
* header calls for was MEASURED INSTEAD: the residual 2lE re-fit under
|
|
66
|
+
* the new chain is noise (−0.12″ sin / −0.03″ cos vs the declared-fitted
|
|
67
|
+
* +1.42″ — tools/explore/e3b-native-sun.mjs §2), the all-phase Sun
|
|
68
|
+
* residual improved to 0.95″, and every gate stayed green — the table's
|
|
69
|
+
* planetary content is chain-independent physics and the pairing holds
|
|
70
|
+
* WITHOUT re-extraction. The +1.42″ 2lE term is thereby measured to be
|
|
71
|
+
* genuinely planetary-class, not a Meeus-EoC absorber.
|
|
61
72
|
*/
|
|
62
73
|
|
|
63
74
|
'use strict';
|
package/src/model.js
CHANGED
|
@@ -829,6 +829,81 @@ export function assembleModel(C, F) {
|
|
|
829
829
|
},
|
|
830
830
|
});
|
|
831
831
|
|
|
832
|
+
// ── E4: the framework-native Sun (§12i item 11 — the 3b landing) ─────────
|
|
833
|
+
// Assembled from the model's own laws, ZERO fitted sun constants:
|
|
834
|
+
// e(t) = the H/16 eccentricity-channel law + the derived H/3
|
|
835
|
+
// inclination-coupling imprint (amplitude base/2, lattice phase,
|
|
836
|
+
// J2000-anchored difference form) — the osculating decomposition:
|
|
837
|
+
// osculating e = H/16 channel + inclination coupling.
|
|
838
|
+
// L(t) = L0 + the mean tropical rate + the f(Y) drift SHAPE only,
|
|
839
|
+
// ∫(rate_SI(y) − rate_SI(2000)) dy: the rate ANCHOR stays the mean
|
|
840
|
+
// year (eclipse-endorsed); the drift is the Step 6c year-harmonic
|
|
841
|
+
// claim in SI/TT (year-in-days × LOD — the LOD-day part of the
|
|
842
|
+
// raw drift is UT-vs-TT and stays ΔT's job) PLUS the derived
|
|
843
|
+
// TORQUE term (E5): the year harmonics carry only the GEOMETRIC
|
|
844
|
+
// equinox displacement (the tilt nodes — the exact 8:3 amplitude
|
|
845
|
+
// signature); the classical luni-solar torque adds a precession-
|
|
846
|
+
// RATE modulation δp = −p₀·tan ε·δε(t) on the model's own
|
|
847
|
+
// two-component obliquity law (−A cos φ₃ + A cos φ₈). Both
|
|
848
|
+
// lengthen the year at obliquity max, so they ADD; per-divisor
|
|
849
|
+
// drift scale 1 + p₀·tan²ε·H/(2π·div) = 1.306 (H/8) / 1.815
|
|
850
|
+
// (H/3) — the structure the ancient corpus blind-selected before
|
|
851
|
+
// the derivation existed. Zero new constants. Trapezoid table,
|
|
852
|
+
// 10-yr steps over −3000..3000; outside, the drift freezes at the
|
|
853
|
+
// edge (rate reverts to linear — the finder domain is the corpus
|
|
854
|
+
// era).
|
|
855
|
+
// ϖ(t) = the shipped H/16 perihelion law (earthPerihelionDeg).
|
|
856
|
+
// Measured (tools/explore/e3b-native-sun.mjs): beats the Meeus Ch. 25
|
|
857
|
+
// basis on JPL all-phase (0.95″ vs 1.28″ scatter) and on ancient-corpus
|
|
858
|
+
// timing structure (0.37 vs 0.50 min detrended vs Meeus-T²); required-ΔT
|
|
859
|
+
// shift 2–4 min ≈ 0.23σ of Stephenson scatter (lunar bias improves); the
|
|
860
|
+
// D2 completion table is unchanged (residual 2lE re-fit ≈ 0.1″ — noise).
|
|
861
|
+
const sunL0Deg = C.earthOrbital.sunMeanLongitudeJ2000_deg;
|
|
862
|
+
const sunTropicalRateDegPerCy = 360 * julianCenturyDays / meanSolarYearDays;
|
|
863
|
+
/** @param {number} year @returns {number} */
|
|
864
|
+
const sunEccentricityAt = (year) => {
|
|
865
|
+
const cos3 = -Math.cos(phaseRadians(balancedYear, year, 3));
|
|
866
|
+
const cos3J2000 = -Math.cos(phaseRadians(balancedYear, 2000, 3));
|
|
867
|
+
return eccentricityAt(year) + (eccentricityBase / 2) * (cos3 - cos3J2000);
|
|
868
|
+
};
|
|
869
|
+
const sunMeanLongitudeDegAt = (() => {
|
|
870
|
+
const Y_LO = -3000, Y_HI = 3000, STEP = 10;
|
|
871
|
+
/** @type {Float64Array|null} */
|
|
872
|
+
let cum = null;
|
|
873
|
+
const precessionP0DegPerYr = 13 * 360 / H;
|
|
874
|
+
const tanEps = Math.tan(earthtiltMean * Math.PI / 180);
|
|
875
|
+
/** E5 — the two-component obliquity excursion, radians, integrated phase.
|
|
876
|
+
* @param {number} year @returns {number} */
|
|
877
|
+
const obliquityExcursionRad = (year) => (
|
|
878
|
+
-earthInclAmplitude * Math.cos(phaseRadians(balancedYear, year, 3))
|
|
879
|
+
+ earthInclAmplitude * Math.cos(phaseRadians(balancedYear, year, 8))
|
|
880
|
+
) * Math.PI / 180;
|
|
881
|
+
/** @param {number} year @returns {number} */
|
|
882
|
+
const rateSIYr = (year) => 360 * (365.25 * 86400)
|
|
883
|
+
/ (tropicalYearDirectDays(year)
|
|
884
|
+
* (deepLod.lodSecondsAtAge(yearToTMa(year)) ?? meanLengthOfDay))
|
|
885
|
+
- precessionP0DegPerYr * tanEps * obliquityExcursionRad(year);
|
|
886
|
+
return /** @param {number} year @returns {number} */ (year) => {
|
|
887
|
+
if (cum === null) {
|
|
888
|
+
const n = (Y_HI - Y_LO) / STEP + 1;
|
|
889
|
+
cum = new Float64Array(n);
|
|
890
|
+
const ref = rateSIYr(2000);
|
|
891
|
+
let prev = rateSIYr(Y_LO) - ref;
|
|
892
|
+
for (let i = 1; i < n; i++) {
|
|
893
|
+
const next = rateSIYr(Y_LO + i * STEP) - ref;
|
|
894
|
+
cum[i] = cum[i - 1] + 0.5 * (prev + next) * STEP;
|
|
895
|
+
prev = next;
|
|
896
|
+
}
|
|
897
|
+
const at2000 = cum[(2000 - Y_LO) / STEP];
|
|
898
|
+
for (let i = 0; i < n; i++) cum[i] -= at2000;
|
|
899
|
+
}
|
|
900
|
+
const x = (Math.min(Math.max(year, Y_LO), Y_HI) - Y_LO) / STEP;
|
|
901
|
+
const i = Math.min(Math.floor(x), cum.length - 2);
|
|
902
|
+
const drift = cum[i] + (x - i) * (cum[i + 1] - cum[i]);
|
|
903
|
+
return sunL0Deg + sunTropicalRateDegPerCy * (year - 2000) / 100 + drift;
|
|
904
|
+
};
|
|
905
|
+
})();
|
|
906
|
+
|
|
832
907
|
// Eclipse finders — wired like the engine probe (tools/verify/
|
|
833
908
|
// eclipse-audit.js). The finder axis is JD(UT): the series wrapper applies
|
|
834
909
|
// UT→TT internally. Ground-track/umbra paths deliberately absent: the
|
|
@@ -841,6 +916,13 @@ export function assembleModel(C, F) {
|
|
|
841
916
|
deltaTSecondsAt: frameworkDeltaTSecondsAtJD,
|
|
842
917
|
getSynodicMonthDays: () => moonSynodicMonthDays,
|
|
843
918
|
getSunDistanceKm: () => currentAUDistance,
|
|
919
|
+
frameworkSun: {
|
|
920
|
+
sunMeanLongitudeJ2000Deg: sunL0Deg,
|
|
921
|
+
tropicalRateDegPerCy: sunTropicalRateDegPerCy,
|
|
922
|
+
eccentricityAt: sunEccentricityAt,
|
|
923
|
+
perihelionLongitudeDegAt: earthPerihelionDeg,
|
|
924
|
+
meanLongitudeDegAt: sunMeanLongitudeDegAt,
|
|
925
|
+
},
|
|
844
926
|
constants: {
|
|
845
927
|
rEarthMetres: (C.bodyDiametersKm.earth / 2) * 1000,
|
|
846
928
|
moonDiameterKm: C.bodyDiametersKm.moon,
|
|
@@ -956,6 +1038,18 @@ export function assembleModel(C, F) {
|
|
|
956
1038
|
findLunarInRange: /** @param {number} jdStart @param {number} jdEnd */ (jdStart, jdEnd) => eclipseFinders.findLunarEclipsesInRange(jdStart, jdEnd),
|
|
957
1039
|
findSolarInRange: /** @param {number} jdStart @param {number} jdEnd */ (jdStart, jdEnd) => eclipseFinders.findSolarEclipsesInRange(jdStart, jdEnd),
|
|
958
1040
|
deltaTSecondsAtJD: frameworkDeltaTSecondsAtJD,
|
|
1041
|
+
// E4 — the framework-native Sun deps, exported so the OTHER finder
|
|
1042
|
+
// construction sites (tools/verify/eclipse-audit.js, the browser
|
|
1043
|
+
// _eclipse twins) spread the SAME assembly into their own
|
|
1044
|
+
// createEclipseFinders call instead of triplicating it (the
|
|
1045
|
+
// three-runtimes rule — cf. recession-history):
|
|
1046
|
+
frameworkSunDeps: Object.freeze({
|
|
1047
|
+
sunMeanLongitudeJ2000Deg: sunL0Deg,
|
|
1048
|
+
tropicalRateDegPerCy: sunTropicalRateDegPerCy,
|
|
1049
|
+
eccentricityAt: sunEccentricityAt,
|
|
1050
|
+
perihelionLongitudeDegAt: earthPerihelionDeg,
|
|
1051
|
+
meanLongitudeDegAt: sunMeanLongitudeDegAt,
|
|
1052
|
+
}),
|
|
959
1053
|
// 20.3g location tier (see eclipse/besselian.cjs):
|
|
960
1054
|
umbraGroundAtJD: /** @param {number} jd @returns {{latDeg: number, lonDeg: number} | null} */ (jd) => besselian.umbraGroundAt(jd),
|
|
961
1055
|
solarLocalCircumstances: /** @param {number} jdGreatest @param {number} latDeg @param {number} lonDeg */ (jdGreatest, latDeg, lonDeg) => besselian.localCircumstances(jdGreatest, latDeg, lonDeg),
|
|
@@ -62,7 +62,14 @@ const DELAUNAY = {
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
/** Longitude tail: [kD, kM, kMp, kF, sin″] — 47 derived terms ≥ 0.1″
|
|
65
|
-
* (RMS content 2.02″).
|
|
65
|
+
* (RMS content 2.02″), plus the 20.3h ROUND-2 block at the end: five
|
|
66
|
+
* dt-halving-converged terms beyond the D2 catalog's order-7 bound
|
|
67
|
+
* (m20h-extraction-r2.mjs, the same D1 3-body lab). The lead term
|
|
68
|
+
* [6,0,−2,0] extracted at 0.572″ vs the MPP02-comparison target 0.57″
|
|
69
|
+
* (m20h-alias-breaker.mjs) — the integrator predicted the independent
|
|
70
|
+
* reference again. 4-gate out-of-sample (m20h-gate-preview.mjs):
|
|
71
|
+
* all-phase λ 3.03 → 2.96″, β unchanged, fleet improves, centerlines
|
|
72
|
+
* 2.71 → 2.69″ with the 2001 max 7.3 → 6.7″. */
|
|
66
73
|
const LON_TERMS = [
|
|
67
74
|
[2, 0, 1, 2, -0.9900],
|
|
68
75
|
[2, 0, -4, 0, 0.9465],
|
|
@@ -111,6 +118,12 @@ const LON_TERMS = [
|
|
|
111
118
|
[1, 0, -3, 0, -0.1252],
|
|
112
119
|
[2, 0, 2, 2, -0.1236],
|
|
113
120
|
[1, -1, 1, 0, -0.1225],
|
|
121
|
+
// 20.3h ROUND 2 — beyond the order-7 catalog bound (see header note):
|
|
122
|
+
[6, 0, -2, 0, 0.572],
|
|
123
|
+
[6, 0, -3, 0, 0.294],
|
|
124
|
+
[4, 0, -2, 2, -0.169],
|
|
125
|
+
[4, -2, -2, 0, 0.161],
|
|
126
|
+
[0, 0, 5, 0, 0.112],
|
|
114
127
|
];
|
|
115
128
|
|
|
116
129
|
/** Latitude tail: [kD, kM, kMp, kF, sin″] — 30 derived terms ≥ 0.1″
|