@essrt/physics 10.0.0 → 11.0.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 +2 -2
- package/src/constants/generated.js +1 -1
- package/src/earth/deep-orbital-history.cjs +84 -33
- package/src/earth/sidereal-channel-artifact.cjs +4 -3
- package/src/earth/sidereal-year-channel.cjs +14 -4
- package/src/earth/year-lengths.cjs +88 -53
- package/src/model.js +9 -14
- package/types/earth/deep-orbital-history.d.cts +2 -0
- package/types/earth/sidereal-channel-artifact.d.cts +2 -2
- package/types/earth/year-lengths.d.cts +14 -16
- package/types/model.d.ts +4 -2
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@essrt/physics",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "11.0.0",
|
|
4
4
|
"description": "ESSRT (Expanding Solar System Resonance Theory) physics core — 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
|
-
"modelVersion": "
|
|
6
|
+
"modelVersion": "v16.0",
|
|
7
7
|
"_note": "The model identity this package version ships (IP-unified-architecture §10: package semver tracks the API axis; the model version + CONSTANTS_HASH/COEFFICIENTS_HASH in src/constants/ carry the scientific identity). The version-pinning gate enforces this pairing against public/input/model-version.json."
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
export const CONSTANTS_HASH = "726b10e23d8ace09";
|
|
37
37
|
|
|
38
38
|
/** Model version label — single source: public/input/model-version.json (§10 two-axis scheme). */
|
|
39
|
-
export const MODEL_VERSION = "
|
|
39
|
+
export const MODEL_VERSION = "v16.0";
|
|
40
40
|
|
|
41
41
|
/** Canonical preprint DOI — single source: public/input/model-version.json. */
|
|
42
42
|
export const PREPRINT_DOI = "10.21203/rs.3.rs-8758810/v4";
|
|
@@ -342,12 +342,46 @@ function createDeepOrbitalHistory({
|
|
|
342
342
|
return [o[0] / r, o[1] / r, o[2] / r];
|
|
343
343
|
};
|
|
344
344
|
|
|
345
|
-
/**
|
|
346
|
-
*
|
|
347
|
-
|
|
345
|
+
/** The equinox's GENERAL-PRECESSION longitude (deg, J2000 ecliptic frame):
|
|
346
|
+
* the broken angle through the ascending node of the ecliptic of date on
|
|
347
|
+
* the J2000 ecliptic — Π (the node's longitude) plus the arc along the
|
|
348
|
+
* ecliptic of date from that node to the equinox. This is the p_A of the
|
|
349
|
+
* precession literature (Lieske 1977; Simon et al. 1994: p_A = Λ_A − Π_A):
|
|
350
|
+
* the quantity the mean longitude OF DATE subtracts from the fixed-frame
|
|
351
|
+
* mean longitude — the N-body λ = Ω + ω + M is itself this broken angle
|
|
352
|
+
* (lattice-long-window-test.mjs), so the tropical year of date must be
|
|
353
|
+
* built on THIS rate. NOT the projected longitude atan2(g_y, g_x)
|
|
354
|
+
* (equinoxLonJ2000Deg, which the frame reconstruction needs): the two
|
|
355
|
+
* agree at J2000, where the ecliptic of date coincides with the J2000
|
|
356
|
+
* ecliptic, and part with the SQUARE of the ecliptic's tilt to its J2000
|
|
357
|
+
* position — (i²/4)·sin 2u class: 0.9″ at 0 AD, 5.9″ at −3000,
|
|
358
|
+
* arcminutes at deep time; as a rate 0.05 s of tropical year at ±4 kyr,
|
|
359
|
+
* 0.1–0.2 s at ±10 kyr, ~1 s beyond 100 kyr (measured 2026-09: the scene's
|
|
360
|
+
* own sidereal angle read exactly this against the projected-rate law at
|
|
361
|
+
* 16 epochs, and the re-booked Sun is flat against DE441 in the inertial
|
|
362
|
+
* frame over −2500…+2000 where the projected booking ramped to +5.6″).
|
|
363
|
+
* Degenerate node as i → 0: the dogleg's two parts compensate each other's
|
|
364
|
+
* error, and below 1e-9 the projected form is the exact limit.
|
|
365
|
+
* @param {number[]} n the ecliptic pole of date @param {number[]} gu the unit equinox */
|
|
366
|
+
function generalPrecessionLonDeg(n, gu) {
|
|
367
|
+
const Nx = -n[1], Ny = n[0]; // ẑ × n̂ — the ascending node of the ecliptic of date
|
|
368
|
+
const sN = Math.hypot(Nx, Ny);
|
|
369
|
+
if (sN < 1e-9) return Math.atan2(gu[1], gu[0]) * R2D;
|
|
370
|
+
const N = [Nx / sN, Ny / sN, 0];
|
|
371
|
+
const Pi = Math.atan2(N[1], N[0]);
|
|
372
|
+
const u = Math.atan2(dot(n, cross(N, gu)), dot(N, gu));
|
|
373
|
+
return (Pi + u) * R2D;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/** Equinox-node longitudes only (J2000 ecliptic frame; projected and
|
|
377
|
+
* general-precession forms) — the light read used for the node-rate
|
|
378
|
+
* finite differences at store time. */
|
|
379
|
+
function eqLonsOnlyDeg(/** @type {number[]} */ s, /** @type {number} */ t) {
|
|
348
380
|
const n = orbitNormal(t);
|
|
349
381
|
const g = cross(s, n);
|
|
350
|
-
|
|
382
|
+
const gn = Math.hypot(g[0], g[1], g[2]);
|
|
383
|
+
const gu = [g[0] / gn, g[1] / gn, g[2] / gn];
|
|
384
|
+
return { proj: Math.atan2(gu[1], gu[0]) * R2D, general: generalPrecessionLonDeg(n, gu) };
|
|
351
385
|
}
|
|
352
386
|
|
|
353
387
|
/** One quantity bundle at time t (years from J2000) from spin axis s. */
|
|
@@ -383,26 +417,38 @@ function createDeepOrbitalHistory({
|
|
|
383
417
|
// interpolation on the grid is exact to the ζ series' own resolution.
|
|
384
418
|
orbitNormalX: n[0],
|
|
385
419
|
orbitNormalY: n[1],
|
|
386
|
-
// The equinox node (ŝ×n̂) longitude in the J2000 ecliptic
|
|
387
|
-
//
|
|
388
|
-
//
|
|
389
|
-
//
|
|
390
|
-
// tropical
|
|
391
|
-
//
|
|
420
|
+
// The equinox node (ŝ×n̂) PROJECTED longitude in the J2000 ecliptic
|
|
421
|
+
// frame — the frame reconstruction's input (frame-of-date.cjs rebuilds
|
|
422
|
+
// the unit equinox from it). Its rate is the general precession only
|
|
423
|
+
// to first order in the ecliptic's tilt to its J2000 position: the
|
|
424
|
+
// tropical-year consumers read generalPrecessionLonDeg below (measured
|
|
425
|
+
// 2026-09 — the projected rate booked the Sun's mean longitude of date
|
|
426
|
+
// 5.9″ off at −3000 and the sidereal year of date 1 s off at depth).
|
|
427
|
+
// ⚠ RATE-CONSUMER CONTRACT (measured): these fields' rates are correct
|
|
392
428
|
// AS IS — α is self-anchored to the LUNISOLAR rate at construction
|
|
393
429
|
// (K_LUNI, the one-RK4-step probe above), so the realized general
|
|
394
|
-
// precession p_geom(J2000) equals 360/axialPrecessionYearsJ2000
|
|
395
|
-
//
|
|
396
|
-
//
|
|
397
|
-
// sid/(sid−sol) rate and
|
|
398
|
-
// mean — a double-count of
|
|
399
|
-
// J2000 — and consumers had to
|
|
430
|
+
// precession p_geom(J2000) equals 360/axialPrecessionYearsJ2000 per
|
|
431
|
+
// JULIAN year (the sampler's time unit) by construction. No
|
|
432
|
+
// correction, no δ subtraction. History (why this contract exists):
|
|
433
|
+
// before the self-anchor, α carried the GENERAL sid/(sid−sol) rate and
|
|
434
|
+
// the n̂(t) geometry re-added the planetary mean — a double-count of
|
|
435
|
+
// +0.097″/yr ≈ +2.4 s of tropical year at J2000 — and consumers had to
|
|
436
|
+
// subtract the runtime anchor
|
|
400
437
|
// δ = p_geom(J2000) − 360/axialPrecessionYearsJ2000.
|
|
401
438
|
// A consumer may still measure δ at runtime as a SELF-CHECK; it
|
|
402
439
|
// must read ≈0 (sub-1e-4 ″/yr class). The LONGITUDE itself is raw
|
|
403
440
|
// geometry and has always needed no correction.
|
|
404
441
|
equinoxLonJ2000Deg: ((Math.atan2(gu[1], gu[0]) * R2D) % 360 + 360) % 360,
|
|
405
442
|
equinoxLonRateDegPerYr: 0, // filled at store time (build's ±2.5-yr central difference)
|
|
443
|
+
// The equinox's GENERAL-PRECESSION longitude (the broken angle through
|
|
444
|
+
// the node of the ecliptic of date — the literature's p_A; see
|
|
445
|
+
// generalPrecessionLonDeg above): its year-over-year retrograde advance
|
|
446
|
+
// IS the general precession of date, wobble included (the n̂(t)
|
|
447
|
+
// geometry generates the equinox wobble; ψ̇ itself is the secular
|
|
448
|
+
// α(H(t)) times the two factors of date). The tropical year of date is
|
|
449
|
+
// built on this rate (earth/year-lengths.cjs).
|
|
450
|
+
generalPrecessionLonDeg: ((generalPrecessionLonDeg(n, gu) % 360) + 360) % 360,
|
|
451
|
+
generalPrecessionLonRateDegPerYr: 0, // filled at store time (build's ±2.5-yr central difference)
|
|
406
452
|
};
|
|
407
453
|
}
|
|
408
454
|
|
|
@@ -445,9 +491,10 @@ function createDeepOrbitalHistory({
|
|
|
445
491
|
const storeWithRate = (/** @type {number} */ key, /** @type {number[]} */ sv, /** @type {number} */ tv) => {
|
|
446
492
|
const smp = sampleAt(sv, tv);
|
|
447
493
|
const hR = 2.5;
|
|
448
|
-
const lp =
|
|
449
|
-
const lm =
|
|
450
|
-
smp.equinoxLonRateDegPerYr = (((lp - lm + 540) % 360) - 180) / (2 * hR);
|
|
494
|
+
const lp = eqLonsOnlyDeg(rk4(sv, tv, +hR), tv + hR);
|
|
495
|
+
const lm = eqLonsOnlyDeg(rk4(sv, tv, -hR), tv - hR);
|
|
496
|
+
smp.equinoxLonRateDegPerYr = (((lp.proj - lm.proj + 540) % 360) - 180) / (2 * hR);
|
|
497
|
+
smp.generalPrecessionLonRateDegPerYr = (((lp.general - lm.general + 540) % 360) - 180) / (2 * hR);
|
|
451
498
|
grid.set(key, smp);
|
|
452
499
|
};
|
|
453
500
|
storeWithRate(0, s, 0);
|
|
@@ -476,6 +523,19 @@ function createDeepOrbitalHistory({
|
|
|
476
523
|
const f = (tYr - k0) / stepYr;
|
|
477
524
|
const lerp = (/** @type {number} */ x, /** @type {number} */ y) => x + (y - x) * f;
|
|
478
525
|
const dAng = (/** @type {number} */ x, /** @type {number} */ y) => x + (((y - x + 540) % 360) - 180) * f;
|
|
526
|
+
// C1 (cubic Hermite) on a wrapped angle with node rates (deg/yr) —
|
|
527
|
+
// linear interpolation here made the realized equinox RATE
|
|
528
|
+
// piecewise-constant per grid cell (the measured per-year
|
|
529
|
+
// precession staircase). Node rates come from the build's own
|
|
530
|
+
// ±2.5-yr central differences.
|
|
531
|
+
const hermiteAngle = (/** @type {number} */ l0, /** @type {number} */ l1, /** @type {number} */ r0, /** @type {number} */ r1) => {
|
|
532
|
+
const dl = ((l1 - l0 + 540) % 360) - 180; // unwrapped segment
|
|
533
|
+
const m0 = r0 * stepYr, m1 = r1 * stepYr;
|
|
534
|
+
const f2 = f * f, f3 = f2 * f;
|
|
535
|
+
const v = (2 * f3 - 3 * f2 + 1) * l0 + (f3 - 2 * f2 + f) * m0
|
|
536
|
+
+ (-2 * f3 + 3 * f2) * (l0 + dl) + (f3 - f2) * m1;
|
|
537
|
+
return ((v % 360) + 360) % 360;
|
|
538
|
+
};
|
|
479
539
|
return {
|
|
480
540
|
epsDeg: lerp(a.epsDeg, b.epsDeg),
|
|
481
541
|
e: lerp(a.e, b.e),
|
|
@@ -485,21 +545,12 @@ function createDeepOrbitalHistory({
|
|
|
485
545
|
inclEclDeg: lerp(a.inclEclDeg, b.inclEclDeg),
|
|
486
546
|
orbitNormalX: lerp(a.orbitNormalX, b.orbitNormalX),
|
|
487
547
|
orbitNormalY: lerp(a.orbitNormalY, b.orbitNormalY),
|
|
488
|
-
|
|
489
|
-
// realized equinox RATE piecewise-constant per grid cell (the
|
|
490
|
-
// measured per-year precession staircase). Node rates come from
|
|
491
|
-
// the build's own ±2.5-yr central differences.
|
|
492
|
-
equinoxLonJ2000Deg: (() => {
|
|
493
|
-
const l0 = a.equinoxLonJ2000Deg;
|
|
494
|
-
const dl = ((b.equinoxLonJ2000Deg - l0 + 540) % 360) - 180; // unwrapped segment
|
|
495
|
-
const m0 = a.equinoxLonRateDegPerYr * stepYr;
|
|
496
|
-
const m1 = (b.equinoxLonRateDegPerYr ?? a.equinoxLonRateDegPerYr) * stepYr;
|
|
497
|
-
const f2 = f * f, f3 = f2 * f;
|
|
498
|
-
const v = (2 * f3 - 3 * f2 + 1) * l0 + (f3 - 2 * f2 + f) * m0
|
|
499
|
-
+ (-2 * f3 + 3 * f2) * (l0 + dl) + (f3 - f2) * m1;
|
|
500
|
-
return ((v % 360) + 360) % 360;
|
|
501
|
-
})(),
|
|
548
|
+
equinoxLonJ2000Deg: hermiteAngle(a.equinoxLonJ2000Deg, b.equinoxLonJ2000Deg, a.equinoxLonRateDegPerYr, b.equinoxLonRateDegPerYr ?? a.equinoxLonRateDegPerYr),
|
|
502
549
|
equinoxLonRateDegPerYr: lerp(a.equinoxLonRateDegPerYr, b.equinoxLonRateDegPerYr ?? a.equinoxLonRateDegPerYr),
|
|
550
|
+
// the same C1 form for the general-precession longitude (its
|
|
551
|
+
// year-over-year difference is the tropical-year law's p).
|
|
552
|
+
generalPrecessionLonDeg: hermiteAngle(a.generalPrecessionLonDeg, b.generalPrecessionLonDeg, a.generalPrecessionLonRateDegPerYr, b.generalPrecessionLonRateDegPerYr ?? a.generalPrecessionLonRateDegPerYr),
|
|
553
|
+
generalPrecessionLonRateDegPerYr: lerp(a.generalPrecessionLonRateDegPerYr, b.generalPrecessionLonRateDegPerYr ?? a.generalPrecessionLonRateDegPerYr),
|
|
503
554
|
};
|
|
504
555
|
},
|
|
505
556
|
};
|