@tubular/astronomy
Version:
Astronomical calculations for planetary positions, moon phases, eclipses, rise, transit, and set times, and more.
243 lines • 7.38 kB
JavaScript
/*
This is an implementation of the Chapront ELP 2000-82 lunar theory, as
presented in a shorter but lower-accuracy form, by Jean Meeus.
*/
import { cos_deg, sin_deg, SphericalPosition3D, Unit } from '@tubular/math';
import { JD_J2000, KM_PER_AU } from './astro-constants';
// From _Astronomical Algorithms, 2nd Ed._ by Jean Meeus
// pp. 339-341, tables 47.A and 47.B.
const lon_table = [
'0 0 1 0 6288774 -20905355',
'2 0 -1 0 1274027 -3699111',
'2 0 0 0 658314 -2955968',
'0 0 2 0 213618 -569925',
'0 1 0 0 -185116 48888',
'0 0 0 2 -114332 -3149',
'2 0 -2 0 58793 246158',
'2 -1 -1 0 57066 -152138',
'2 0 1 0 53322 -170733',
'2 -1 0 0 45758 -204586',
'0 1 -1 0 -40923 -129620',
'1 0 0 0 -34720 108743',
'0 1 1 0 -30383 104755',
'2 0 0 -2 15327 10321',
'0 0 1 2 -12528 0',
'0 0 1 -2 10980 79661',
'4 0 -1 0 10675 -34782',
'0 0 3 0 10034 -23210',
'4 0 -2 0 8548 -21636',
'2 1 -1 0 -7888 24208',
'2 1 0 0 -6766 30824',
'1 0 -1 0 -5163 -8379',
'1 1 0 0 4987 -16675',
'2 -1 1 0 4036 -12831',
'2 0 2 0 3994 -10445',
'4 0 0 0 3861 -11650',
'2 0 -3 0 3665 14403',
'0 1 -2 0 -2689 -7003',
'2 0 -1 2 -2602 0',
'2 -1 -2 0 2390 10056',
'1 0 1 0 -2348 6322',
'2 -2 0 0 2236 -9884',
'0 1 2 0 -2120 5751',
'0 2 0 0 -2069 0',
'2 -2 -1 0 2048 -4950',
'2 0 1 -2 -1773 4130',
'2 0 0 2 -1595 0',
'4 -1 -1 0 1215 -3958',
'0 0 2 2 -1110 0',
'3 0 -1 0 -892 3258',
'2 1 1 0 -810 2616',
'4 -1 -2 0 759 -1897',
'0 2 -1 0 -713 -2117',
'2 2 -1 0 -700 2354',
'2 1 -2 0 691 0',
'2 -1 0 -2 596 0',
'4 0 1 0 549 -1423',
'0 0 4 0 537 -1117',
'4 -1 0 0 520 -1571',
'1 0 -2 0 -487 -1739',
'2 1 0 -2 -399 0',
'0 0 2 -2 -381 -4421',
'1 1 1 0 351 0',
'3 0 -2 0 -340 0',
'4 0 -3 0 330 0',
'2 -1 2 0 327 0',
'0 2 1 0 -323 1165',
'1 1 -1 0 299 0',
'2 0 3 0 294 0',
'2 0 -1 -2 0 8752'
];
const lat_table = [
'0 0 0 1 5128122',
'0 0 1 1 280602',
'0 0 1 -1 277693',
'2 0 0 -1 173237',
'2 0 -1 1 55413',
'2 0 -1 -1 46271',
'2 0 0 1 32573',
'0 0 2 1 17198',
'2 0 1 -1 9266',
'0 0 2 -1 8822',
'2 -1 0 -1 8216',
'2 0 -2 -1 4324',
'2 0 1 1 4200',
'2 1 0 -1 -3359',
'2 -1 -1 1 2463',
'2 -1 0 1 2211',
'2 -1 -1 -1 2065',
'0 1 -1 -1 -1870',
'4 0 -1 -1 1828',
'0 1 0 1 -1794',
'0 0 0 3 -1749',
'0 1 -1 1 -1565',
'1 0 0 1 -1491',
'0 1 1 1 -1475',
'0 1 1 -1 -1410',
'0 1 0 -1 -1344',
'1 0 0 -1 -1335',
'0 0 3 1 1107',
'4 0 0 -1 1021',
'4 0 -1 1 833',
'0 0 1 -3 777',
'4 0 -2 1 671',
'2 0 0 -3 607',
'2 0 2 -1 596',
'2 -1 1 -1 491',
'2 0 -2 1 -451',
'0 0 3 -1 439',
'2 0 2 1 422',
'2 0 -3 -1 421',
'2 1 -1 1 -366',
'2 1 0 1 -351',
'4 0 0 1 331',
'2 -1 1 1 315',
'2 -2 0 -1 302',
'0 0 1 3 -283',
'2 1 1 -1 -229',
'1 1 0 -1 223',
'1 1 0 1 223',
'0 1 -2 -1 -220',
'2 1 -1 -1 -220',
'1 0 1 1 -185',
'2 -1 -2 -1 181',
'0 1 2 1 -177',
'4 0 -2 -1 176',
'4 -1 -1 -1 166',
'1 0 1 -1 -164',
'4 0 1 -1 132',
'1 0 -1 -1 -119',
'4 -1 0 -1 115',
'2 -2 0 1 107'
];
let termsLR;
let termsB;
(function () {
termsLR = lon_table.map((line) => {
const fields = line.split(' ');
return {
fD: Number(fields[0]),
fM: Number(fields[1]),
fM1: Number(fields[2]),
fF: Number(fields[3]),
cs: Number(fields[4]),
cc: Number(fields[5])
};
});
termsB = lat_table.map((line) => {
const fields = line.split(' ');
return {
fD: Number(fields[0]),
fM: Number(fields[1]),
fM1: Number(fields[2]),
fF: Number(fields[3]),
cs: Number(fields[4])
};
});
})();
const CACHE_SIZE = 6;
export class MeeusMoon {
constructor() {
this.cachedTimes = [];
this.cachedPositions = [];
this.cachedPositions.length = CACHE_SIZE;
this.cachedPositions.fill(null, 0, CACHE_SIZE);
}
getEclipticPosition(time_JDE) {
for (let i = 0; i < CACHE_SIZE; ++i) {
if (this.cachedPositions[i] !== null && this.cachedTimes[i] === time_JDE)
return this.cachedPositions[i];
}
const T = (time_JDE - JD_J2000) / 36525;
const T2 = T ** 2;
const T3 = T2 * T;
const T4 = T3 * T;
const L1 = 218.3164477 + 481267.88123421 * T - 0.0015786 * T2
+ T3 / 538841 - T4 / 65194000
// Undoing the built-in 0.7' light-time adjustment
+ 0.0001944;
const D = 297.8501921 + 445267.1114034 * T - 0.0018819 * T2
+ T3 / 545868 - T4 / 113065000;
const M = 357.5291092 + 35999.0502909 * T - 0.0001536 * T2
+ T3 / 24490000;
const M1 = 134.9633964 + 477198.8675055 * T + 0.0087414 * T2
+ T3 / 69699 - T4 / 14712000;
const F = 93.2720950 + 483202.0175233 * T - 0.0036539 * T2
- T3 / 3526000 + T4 / 863310000;
const A1 = 119.75 + 131.849 * T;
const A2 = 53.09 + 479264.290 * T;
const A3 = 313.45 + 481266.484 * T;
const E = 1 - 0.002516 * T - 0.0000074 * T2;
const E2 = E ** 2;
let L = 0, B = 0, R = 0;
let arg;
for (const term of termsLR) {
arg = term.fD * D + term.fM * M + term.fM1 * M1 + term.fF * F;
if (term.fM === -2 || term.fM === 2) {
L += term.cs * E2 * sin_deg(arg);
R += term.cc * E2 * cos_deg(arg);
}
else if (term.fM === -1 || term.fM === 1) {
L += term.cs * E * sin_deg(arg);
R += term.cc * E * cos_deg(arg);
}
else {
L += term.cs * sin_deg(arg);
R += term.cc * cos_deg(arg);
}
}
L += 3958 * sin_deg(A1)
+ 1962 * sin_deg(L1 - F)
+ 318 * sin_deg(A2);
L = L1 + L / 1000000;
R = 385000.56 + R / 1000;
for (const term of termsB) {
arg = term.fD * D + term.fM * M + term.fM1 * M1 + term.fF * F;
if (term.fM === -2 || term.fM === 2)
B += term.cs * E2 * sin_deg(arg);
else if (term.fM === -1 || term.fM === 1)
B += term.cs * E * sin_deg(arg);
else
B += term.cs * sin_deg(arg);
}
// eslint-disable-next-line space-unary-ops
B += -2235 * sin_deg(L1)
+ 382 * sin_deg(A3)
+ 175 * sin_deg(A1 - F)
+ 175 * sin_deg(A1 + F)
+ 127 * sin_deg(L1 - M1)
- 115 * sin_deg(L1 + M1);
B /= 1000000;
// Convert to AU for consistency with other code
const pos = new SphericalPosition3D(L, B, R / KM_PER_AU, Unit.DEGREES, Unit.DEGREES);
// Shuffle cache
for (let i = 0; i < CACHE_SIZE - 1; ++i) {
this.cachedTimes[i] = this.cachedTimes[i + 1];
this.cachedPositions[i] = this.cachedPositions[i + 1];
}
this.cachedTimes[CACHE_SIZE - 1] = time_JDE;
this.cachedPositions[CACHE_SIZE - 1] = pos;
return pos;
}
}
//# sourceMappingURL=meeus-moon.js.map