@essrt/physics 4.4.0 → 4.5.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 +1 -1
- package/src/earth/deep-orbital-history.cjs +196 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@essrt/physics",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.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": "v13.0",
|
|
@@ -83,6 +83,46 @@ function createDeepOrbitalHistory({
|
|
|
83
83
|
const s0 = sum(0), R = [anchor[0] - s0[0], anchor[1] - s0[1]];
|
|
84
84
|
return (/** @type {number} */ t) => { const [x, y] = sum(t); return [x + R[0], y + R[1]]; };
|
|
85
85
|
};
|
|
86
|
+
// CO-ROTATING anchor (the ϖ̇ fix, measured): the DC residual above is a
|
|
87
|
+
// spurious zero-frequency mode — it preserves the J2000 VALUE but dilutes
|
|
88
|
+
// the local argument rate by |sum(0)|/|anchor| (z: 11.47 → 7.93″/yr, a
|
|
89
|
+
// 92 s-class anomalistic-year bias in the mode tier). Here the residual
|
|
90
|
+
// ROTATES at the raw sum's own local arg-rate g* = Im(ż·z̄)/|z|²
|
|
91
|
+
// (analytic), so at t=0 both the value AND the rate are exact, and at
|
|
92
|
+
// depth the residual is one |R|-amplitude term at a physical frequency
|
|
93
|
+
// instead of a DC offset (deep envelope measured unchanged:
|
|
94
|
+
// [0.0001, 0.0672] → [0.0003, 0.0678] over 10–50 Myr).
|
|
95
|
+
// z ONLY: ζ keeps the DC anchor DELIBERATELY — its anchor is ~0 by
|
|
96
|
+
// definition (Earth's inclination to the J2000 ecliptic at J2000), i.e.
|
|
97
|
+
// the coordinate origin; a rotating residual there would inject a fake
|
|
98
|
+
// wobble into n̂(t).
|
|
99
|
+
const mkAnchoredCoRot = (
|
|
100
|
+
/** @type {ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>} */ modes,
|
|
101
|
+
/** @type {[number, number]} */ anchor,
|
|
102
|
+
) => {
|
|
103
|
+
const sum = (/** @type {number} */ t) => {
|
|
104
|
+
let re = 0, im = 0;
|
|
105
|
+
for (const m of modes) {
|
|
106
|
+
const c = Math.cos(m.omegaRadPerYr * t), s = Math.sin(m.omegaRadPerYr * t);
|
|
107
|
+
re += m.re * c - m.im * s;
|
|
108
|
+
im += m.re * s + m.im * c;
|
|
109
|
+
}
|
|
110
|
+
return [re, im];
|
|
111
|
+
};
|
|
112
|
+
let q0 = 0, p0 = 0, dq0 = 0, dp0 = 0;
|
|
113
|
+
for (const m of modes) {
|
|
114
|
+
q0 += m.re; p0 += m.im;
|
|
115
|
+
dq0 += -m.omegaRadPerYr * m.im;
|
|
116
|
+
dp0 += m.omegaRadPerYr * m.re;
|
|
117
|
+
}
|
|
118
|
+
const gStar = (dp0 * q0 - dq0 * p0) / (q0 * q0 + p0 * p0);
|
|
119
|
+
const R = [anchor[0] - q0, anchor[1] - p0];
|
|
120
|
+
return (/** @type {number} */ t) => {
|
|
121
|
+
const [x, y] = sum(t);
|
|
122
|
+
const c = Math.cos(gStar * t), s = Math.sin(gStar * t);
|
|
123
|
+
return [x + R[0] * c - R[1] * s, y + R[0] * s + R[1] * c];
|
|
124
|
+
};
|
|
125
|
+
};
|
|
86
126
|
const s2h = Math.sin(anchorInclEclipticDeg / 2 * D2R);
|
|
87
127
|
const zetaAnchor = /** @type {[number, number]} */ (
|
|
88
128
|
[s2h * Math.cos(anchorAscNodeEclipticDeg * D2R), s2h * Math.sin(anchorAscNodeEclipticDeg * D2R)]);
|
|
@@ -91,16 +131,29 @@ function createDeepOrbitalHistory({
|
|
|
91
131
|
// engine's own ζ series (anchored at J2000 exactly like the mode sums);
|
|
92
132
|
// outside it, the anchored mode sum is the tail. Without zetaSeries the
|
|
93
133
|
// mode sum serves at every t — the pre-C-2 behavior, bit-identical.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
134
|
+
// C1 series interpolation (D4g, measured): the 500-yr LINEAR series lerp
|
|
135
|
+
// put kinks in n̂(t)/z(t) at its nodes, and the equinox RATE inherited
|
|
136
|
+
// them — the grid-dependent bump around J2000 in per-year P(t) (the same
|
|
137
|
+
// interpolation-order disease as the spin grid, one level down). Cubic
|
|
138
|
+
// Hermite with central-difference node slopes (one-sided at the ends);
|
|
139
|
+
// exact at nodes, so the J2000 anchors are unchanged.
|
|
140
|
+
const mkSeriesCubic = (/** @type {number} */ t0Yr, /** @type {number} */ stepYr, /** @type {number} */ nS) =>
|
|
141
|
+
(/** @type {ReadonlyArray<number>} */ arr, /** @type {number} */ tt) => {
|
|
99
142
|
const x = (tt - t0Yr) / stepYr;
|
|
100
143
|
const i = Math.max(0, Math.min(nS - 2, Math.floor(x)));
|
|
101
144
|
const f = x - i;
|
|
102
|
-
|
|
145
|
+
const y0 = arr[i], y1 = arr[i + 1];
|
|
146
|
+
const m0 = i > 0 ? (y1 - arr[i - 1]) / 2 : y1 - y0;
|
|
147
|
+
const m1 = i + 2 < nS ? (arr[i + 2] - y0) / 2 : y1 - y0;
|
|
148
|
+
const f2 = f * f, f3 = f2 * f;
|
|
149
|
+
return (2 * f3 - 3 * f2 + 1) * y0 + (f3 - 2 * f2 + f) * m0
|
|
150
|
+
+ (-2 * f3 + 3 * f2) * y1 + (f3 - f2) * m1;
|
|
103
151
|
};
|
|
152
|
+
let zetaAt = zetaModeSum;
|
|
153
|
+
if (zetaSeries) {
|
|
154
|
+
const { t0Yr, stepYr, q: sq, p: sp } = zetaSeries;
|
|
155
|
+
const nS = sq.length, tEndYr = t0Yr + (nS - 1) * stepYr;
|
|
156
|
+
const li = mkSeriesCubic(t0Yr, stepYr, nS);
|
|
104
157
|
const R = [zetaAnchor[0] - li(sq, 0), zetaAnchor[1] - li(sp, 0)];
|
|
105
158
|
zetaAt = (/** @type {number} */ t) => (t >= t0Yr && t <= tEndYr)
|
|
106
159
|
? [li(sq, t) + R[0], li(sp, t) + R[1]]
|
|
@@ -108,19 +161,14 @@ function createDeepOrbitalHistory({
|
|
|
108
161
|
}
|
|
109
162
|
const zAnchor = /** @type {[number, number]} */ (
|
|
110
163
|
[anchorE * Math.cos(anchorPeriEclipticDeg * D2R), anchorE * Math.sin(anchorPeriEclipticDeg * D2R)]);
|
|
111
|
-
const zModeSum =
|
|
164
|
+
const zModeSum = mkAnchoredCoRot(zModes, zAnchor); // co-rotating residual — the ϖ̇ fix (see mkAnchoredCoRot)
|
|
112
165
|
// C-4a: the z-side one-source path — same construction as zetaSeries
|
|
113
166
|
// (anchored engine series inside the span, anchored mode sum as the tail).
|
|
114
167
|
let zAt = zModeSum;
|
|
115
168
|
if (zSeries) {
|
|
116
169
|
const { t0Yr, stepYr, q: sq, p: sp } = zSeries;
|
|
117
170
|
const nS = sq.length, tEndYr = t0Yr + (nS - 1) * stepYr;
|
|
118
|
-
const li = (
|
|
119
|
-
const x = (tt - t0Yr) / stepYr;
|
|
120
|
-
const i = Math.max(0, Math.min(nS - 2, Math.floor(x)));
|
|
121
|
-
const f = x - i;
|
|
122
|
-
return arr[i] * (1 - f) + arr[i + 1] * f;
|
|
123
|
-
};
|
|
171
|
+
const li = mkSeriesCubic(t0Yr, stepYr, nS); // C1 (see mkSeriesCubic)
|
|
124
172
|
const R = [zAnchor[0] - li(sq, 0), zAnchor[1] - li(sp, 0)];
|
|
125
173
|
zAt = (/** @type {number} */ t) => (t >= t0Yr && t <= tEndYr)
|
|
126
174
|
? [li(sq, t) + R[0], li(sp, t) + R[1]]
|
|
@@ -149,7 +197,7 @@ function createDeepOrbitalHistory({
|
|
|
149
197
|
// constants: ψ̇(t) comes from the same certified year-length machinery
|
|
150
198
|
// as the J2000 anchor. Absent the option, α stays constant (the
|
|
151
199
|
// pre-D1 ±Myr-class behavior, bit-identical).
|
|
152
|
-
const
|
|
200
|
+
const alphaAtGeneral = axialPrecessionYearsAtYearFn
|
|
153
201
|
? (/** @type {number} */ t) =>
|
|
154
202
|
((2 * Math.PI) / axialPrecessionYearsAtYearFn(2000 + t)) / Math.cos(EPS0)
|
|
155
203
|
: () => ALPHA;
|
|
@@ -157,6 +205,71 @@ function createDeepOrbitalHistory({
|
|
|
157
205
|
const cross = (/** @type {number[]} */ a, /** @type {number[]} */ b) =>
|
|
158
206
|
[a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
159
207
|
const dot = (/** @type {number[]} */ a, /** @type {number[]} */ b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
208
|
+
|
|
209
|
+
// THE LUNISOLAR SELF-ANCHOR (D4e — measured, plan 02): the injected
|
|
210
|
+
// anchor axialPrecessionYearsJ2000 = sid/(sid−sol) is the GENERAL
|
|
211
|
+
// precession period, but ŝ must precess at the LUNISOLAR rate — the
|
|
212
|
+
// n̂(t) geometry supplies the planetary part itself, so integrating at
|
|
213
|
+
// the general rate DOUBLE-COUNTS the planetary mean (measured:
|
|
214
|
+
// −0.0966″/yr of equinox rate → +2.4 s of tropical year at J2000, and
|
|
215
|
+
// 0.19% of ε wobble phasing — the dominant term of the old 0.039° rms
|
|
216
|
+
// vs La2004 over −200 kyr; the lunisolar anchor collapses it to
|
|
217
|
+
// 0.0048°). Self-anchored at construction, no pasted numbers: a one-RK4
|
|
218
|
+
// -step probe at the general rate measures the realized equinox rate at
|
|
219
|
+
// J2000; the deficit rescales α so the REALIZED general precession hits
|
|
220
|
+
// the injected anchor exactly (dp/dα = 1 to first order — one
|
|
221
|
+
// fixed-point step lands on target, measured). H(t) shape preserved
|
|
222
|
+
// (constant factor on the caller's evaluator).
|
|
223
|
+
|
|
224
|
+
// THE ANCHORED SPIN AXIS (measured): ε₀ is defined against the ECLIPTIC
|
|
225
|
+
// — Earth's own mean orbit plane — never against the chain artifact's
|
|
226
|
+
// coordinate pole. The anchor elements carry i₀ ≈ 0.37″ of integrator-
|
|
227
|
+
// frame residue, and tilting ŝ(0) from the coordinate pole projected
|
|
228
|
+
// −0.2865″ of it straight into ε(J2000) (the C-1 era gate's offset,
|
|
229
|
+
// masked until the C1 series interpolation removed the lerp kink at the
|
|
230
|
+
// J2000 node). Build ŝ(0) FROM n̂(0): tilt ε₀ about the J2000 equinox
|
|
231
|
+
// direction projected into the orbit plane. Frame-invariant (the
|
|
232
|
+
// artifact's coordinate frame drops out) and ε(J2000) ≡ ε₀ by
|
|
233
|
+
// construction; reduces to [0, sin ε₀, cos ε₀] exactly when n̂(0) = ẑ.
|
|
234
|
+
const S0A = (() => {
|
|
235
|
+
const n0 = orbitNormal(0);
|
|
236
|
+
const px = [1 - n0[0] * n0[0], -n0[0] * n0[1], -n0[0] * n0[2]];
|
|
237
|
+
const pm = Math.hypot(px[0], px[1], px[2]);
|
|
238
|
+
const u = [px[0] / pm, px[1] / pm, px[2] / pm];
|
|
239
|
+
const v = cross(n0, u);
|
|
240
|
+
return [0, 1, 2].map((i) => Math.cos(EPS0) * n0[i] + Math.sin(EPS0) * v[i]);
|
|
241
|
+
})();
|
|
242
|
+
|
|
243
|
+
const K_LUNI = (() => {
|
|
244
|
+
const S0P = S0A;
|
|
245
|
+
const dv = (/** @type {number[]} */ s, /** @type {number} */ t) => {
|
|
246
|
+
const n = orbitNormal(t);
|
|
247
|
+
const k = alphaAtGeneral(t) * dot(s, n);
|
|
248
|
+
const c = cross(s, n);
|
|
249
|
+
return [k * c[0], k * c[1], k * c[2]];
|
|
250
|
+
};
|
|
251
|
+
const step = (/** @type {number[]} */ s, /** @type {number} */ t, /** @type {number} */ h) => {
|
|
252
|
+
const k1 = dv(s, t);
|
|
253
|
+
const k2 = dv([s[0] + h / 2 * k1[0], s[1] + h / 2 * k1[1], s[2] + h / 2 * k1[2]], t + h / 2);
|
|
254
|
+
const k3 = dv([s[0] + h / 2 * k2[0], s[1] + h / 2 * k2[1], s[2] + h / 2 * k2[2]], t + h / 2);
|
|
255
|
+
const k4 = dv([s[0] + h * k3[0], s[1] + h * k3[1], s[2] + h * k3[2]], t + h);
|
|
256
|
+
const o = [0, 1, 2].map((i) => s[i] + h / 6 * (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]));
|
|
257
|
+
const r = Math.hypot(o[0], o[1], o[2]);
|
|
258
|
+
return [o[0] / r, o[1] / r, o[2] / r];
|
|
259
|
+
};
|
|
260
|
+
const eqLonDeg = (/** @type {number[]} */ s, /** @type {number} */ t) => {
|
|
261
|
+
const n = orbitNormal(t);
|
|
262
|
+
const g = cross(s, n);
|
|
263
|
+
return Math.atan2(g[1], g[0]) * R2D;
|
|
264
|
+
};
|
|
265
|
+
const lM = eqLonDeg(step(S0P, 0, -0.5), -0.5);
|
|
266
|
+
const lP = eqLonDeg(step(S0P, 0, +0.5), +0.5);
|
|
267
|
+
const pProbeDegYr = ((lM - lP + 540) % 360) - 180; // retrograde → positive
|
|
268
|
+
const pTargetDegYr = 360 / axialPrecessionYearsJ2000;
|
|
269
|
+
const psiDot0 = alphaAtGeneral(0) * Math.cos(EPS0);
|
|
270
|
+
return (psiDot0 + (pTargetDegYr - pProbeDegYr) * D2R) / psiDot0;
|
|
271
|
+
})();
|
|
272
|
+
const alphaAt = (/** @type {number} */ t) => alphaAtGeneral(t) * K_LUNI;
|
|
160
273
|
const deriv = (/** @type {number[]} */ s, /** @type {number} */ t) => {
|
|
161
274
|
const n = orbitNormal(t);
|
|
162
275
|
const k = alphaAt(t) * dot(s, n);
|
|
@@ -173,6 +286,14 @@ function createDeepOrbitalHistory({
|
|
|
173
286
|
return [o[0] / r, o[1] / r, o[2] / r];
|
|
174
287
|
};
|
|
175
288
|
|
|
289
|
+
/** Equinox-node longitude only (J2000 ecliptic frame) — the light read
|
|
290
|
+
* used for the node-rate finite difference at store time. */
|
|
291
|
+
function eqLonOnlyDeg(/** @type {number[]} */ s, /** @type {number} */ t) {
|
|
292
|
+
const n = orbitNormal(t);
|
|
293
|
+
const g = cross(s, n);
|
|
294
|
+
return Math.atan2(g[1], g[0]) * R2D;
|
|
295
|
+
}
|
|
296
|
+
|
|
176
297
|
/** One quantity bundle at time t (years from J2000) from spin axis s. */
|
|
177
298
|
function sampleAt(/** @type {number[]} */ s, /** @type {number} */ t) {
|
|
178
299
|
const n = orbitNormal(t);
|
|
@@ -198,6 +319,26 @@ function createDeepOrbitalHistory({
|
|
|
198
319
|
eSinPeri: e * Math.sin(periOfDateDeg * D2R),
|
|
199
320
|
eCosPeri: e * Math.cos(periOfDateDeg * D2R),
|
|
200
321
|
inclEclDeg: i * R2D,
|
|
322
|
+
// The equinox node (ŝ×n̂) longitude in the J2000 ecliptic frame —
|
|
323
|
+
// its year-over-year retrograde advance IS the general precession of
|
|
324
|
+
// date, wobble included (the n̂(t) geometry generates the equinox
|
|
325
|
+
// wobble; ψ̇ itself is the secular α(H(t))). Consumers derive the
|
|
326
|
+
// tropical year of date from it: T_trop = T_sid·(1 − p_yr/360°).
|
|
327
|
+
// ⚠ RATE-CONSUMER CONTRACT (measured): this field's rate is correct
|
|
328
|
+
// AS IS — α is self-anchored to the LUNISOLAR rate at construction
|
|
329
|
+
// (K_LUNI, the one-RK4-step probe above), so the realized general
|
|
330
|
+
// precession p_geom(J2000) equals 360/axialPrecessionYearsJ2000 by
|
|
331
|
+
// construction. No correction, no δ subtraction. History (why this
|
|
332
|
+
// contract exists): before the self-anchor, α carried the GENERAL
|
|
333
|
+
// sid/(sid−sol) rate and the n̂(t) geometry re-added the planetary
|
|
334
|
+
// mean — a double-count of +0.097″/yr ≈ +2.4 s of tropical year at
|
|
335
|
+
// J2000 — and consumers had to subtract the runtime anchor
|
|
336
|
+
// δ = p_geom(J2000) − 360/axialPrecessionYearsJ2000.
|
|
337
|
+
// A consumer may still measure δ at runtime as a SELF-CHECK; it
|
|
338
|
+
// must read ≈0 (sub-1e-4 ″/yr class). The LONGITUDE itself is raw
|
|
339
|
+
// geometry and has always needed no correction.
|
|
340
|
+
equinoxLonJ2000Deg: ((Math.atan2(gu[1], gu[0]) * R2D) % 360 + 360) % 360,
|
|
341
|
+
equinoxLonRateDegPerYr: 0, // filled at store time (build's ±2.5-yr central difference)
|
|
201
342
|
};
|
|
202
343
|
}
|
|
203
344
|
|
|
@@ -216,7 +357,7 @@ function createDeepOrbitalHistory({
|
|
|
216
357
|
throw new Error(`deep-orbital-history: builds beyond ±50 kyr need stepYr % 250 === 0 (got ${stepYr})`);
|
|
217
358
|
}
|
|
218
359
|
const grid = new Map();
|
|
219
|
-
const S0 =
|
|
360
|
+
const S0 = S0A;
|
|
220
361
|
// D1-revised adaptive stepping: 5-yr RK4 near the era (the certified-
|
|
221
362
|
// precision zone), 250-yr beyond ±50 kyr — still 103 steps per
|
|
222
363
|
// precession cycle and ≥196 samples of the fastest ζ mode (49 kyr), so
|
|
@@ -229,7 +370,23 @@ function createDeepOrbitalHistory({
|
|
|
229
370
|
const hStepAt = (/** @type {number} */ t) => (Math.abs(t) < 50000 ? 5 : 250);
|
|
230
371
|
for (const dir of [-1, +1]) {
|
|
231
372
|
let s = S0, t = 0;
|
|
232
|
-
|
|
373
|
+
// Each stored node also carries the equinox-node RATE (deg/yr) from a
|
|
374
|
+
// ±2.5-yr central difference on the integrator's own state — the C1
|
|
375
|
+
// (Hermite) interpolation input. Linear interpolation of the node
|
|
376
|
+
// longitude made the realized equinox rate PIECEWISE-CONSTANT per
|
|
377
|
+
// grid cell — the report's per-year precession column showed flat
|
|
378
|
+
// centuries with steps at the 1700/1800/1900/2000 cell edges
|
|
379
|
+
// (measured; the levels were the real wobble at 100-yr resolution,
|
|
380
|
+
// the staircase was this interpolation order).
|
|
381
|
+
const storeWithRate = (/** @type {number} */ key, /** @type {number[]} */ sv, /** @type {number} */ tv) => {
|
|
382
|
+
const smp = sampleAt(sv, tv);
|
|
383
|
+
const hR = 2.5;
|
|
384
|
+
const lp = eqLonOnlyDeg(rk4(sv, tv, +hR), tv + hR);
|
|
385
|
+
const lm = eqLonOnlyDeg(rk4(sv, tv, -hR), tv - hR);
|
|
386
|
+
smp.equinoxLonRateDegPerYr = (((lp - lm + 540) % 360) - 180) / (2 * hR);
|
|
387
|
+
grid.set(key, smp);
|
|
388
|
+
};
|
|
389
|
+
storeWithRate(0, s, 0);
|
|
233
390
|
const end = dir < 0 ? tMin : tMax;
|
|
234
391
|
while (dir < 0 ? t > end : t < end) {
|
|
235
392
|
const H_STEP = hStepAt(t);
|
|
@@ -243,7 +400,7 @@ function createDeepOrbitalHistory({
|
|
|
243
400
|
// 100-yr keys, 50 yr off). Exact alignment is guaranteed by the
|
|
244
401
|
// guard below (coarse builds use 250-aligned grids; the 50,000-yr
|
|
245
402
|
// zone boundary is itself 250-aligned, so the walk stays on-grid).
|
|
246
|
-
if (Math.abs(t - Math.round(t / stepYr) * stepYr) < 1e-6)
|
|
403
|
+
if (Math.abs(t - Math.round(t / stepYr) * stepYr) < 1e-6) storeWithRate(Math.round(t / stepYr) * stepYr, s, t);
|
|
247
404
|
}
|
|
248
405
|
}
|
|
249
406
|
return {
|
|
@@ -262,12 +419,33 @@ function createDeepOrbitalHistory({
|
|
|
262
419
|
eSinPeri: lerp(a.eSinPeri, b.eSinPeri),
|
|
263
420
|
eCosPeri: lerp(a.eCosPeri, b.eCosPeri),
|
|
264
421
|
inclEclDeg: lerp(a.inclEclDeg, b.inclEclDeg),
|
|
422
|
+
// C1 (cubic Hermite) — linear interpolation here made the
|
|
423
|
+
// realized equinox RATE piecewise-constant per grid cell (the
|
|
424
|
+
// measured per-year precession staircase). Node rates come from
|
|
425
|
+
// the build's own ±2.5-yr central differences.
|
|
426
|
+
equinoxLonJ2000Deg: (() => {
|
|
427
|
+
const l0 = a.equinoxLonJ2000Deg;
|
|
428
|
+
const dl = ((b.equinoxLonJ2000Deg - l0 + 540) % 360) - 180; // unwrapped segment
|
|
429
|
+
const m0 = a.equinoxLonRateDegPerYr * stepYr;
|
|
430
|
+
const m1 = (b.equinoxLonRateDegPerYr ?? a.equinoxLonRateDegPerYr) * stepYr;
|
|
431
|
+
const f2 = f * f, f3 = f2 * f;
|
|
432
|
+
const v = (2 * f3 - 3 * f2 + 1) * l0 + (f3 - 2 * f2 + f) * m0
|
|
433
|
+
+ (-2 * f3 + 3 * f2) * (l0 + dl) + (f3 - f2) * m1;
|
|
434
|
+
return ((v % 360) + 360) % 360;
|
|
435
|
+
})(),
|
|
436
|
+
equinoxLonRateDegPerYr: lerp(a.equinoxLonRateDegPerYr, b.equinoxLonRateDegPerYr ?? a.equinoxLonRateDegPerYr),
|
|
265
437
|
};
|
|
266
438
|
},
|
|
267
439
|
};
|
|
268
440
|
}
|
|
269
441
|
|
|
270
|
-
return {
|
|
442
|
+
return {
|
|
443
|
+
build,
|
|
444
|
+
alphaArcsecPerYr: ALPHA * R2D * 3600, // the injected GENERAL-anchor form (input echo, unchanged semantics)
|
|
445
|
+
// D4e diagnostics: the self-anchored lunisolar rate actually integrated.
|
|
446
|
+
alphaLunisolarArcsecPerYr: ALPHA * K_LUNI * R2D * 3600,
|
|
447
|
+
axialPrecessionYearsLunisolarJ2000: axialPrecessionYearsJ2000 / K_LUNI,
|
|
448
|
+
};
|
|
271
449
|
}
|
|
272
450
|
|
|
273
451
|
module.exports = { createDeepOrbitalHistory };
|