ephemeris
Version:
JavaScript implementation of Moshier's ephemeris calculations for sun, planets, comets, asteroids and stars.
369 lines (340 loc) • 10.4 kB
JavaScript
var constant = require('./constant')
var epsilon = require('./epsilon')
var util = require('./util')
var nutation = {
/* The answers are posted here by nutlo(): */
/** time to which the nutation applies */
jdnut: {},
/** nutation in longitude (radians) */
nutl: 0.0,
/** nutation in obliquity (radians) */
nuto: 0.0,
/**
* Each term in the expansion has a trigonometric
* argument given by
* W = i*MM + j*MS + k*FF + l*DD + m*OM
* where the variables are defined below.
* The nutation in longitude is a sum of terms of the
* form (a + bT) * sin(W). The terms for nutation in obliquity
* are of the form (c + dT) * cos(W). The coefficients
* are arranged in the tabulation as follows:
*
* Coefficient:
* i j k l m a b c d
* 0, 0, 0, 0, 1, -171996, -1742, 92025, 89,
* The first line of the table, above, is done separately
* since two of the values do not fit into 16 bit integers.
* The values a and c are arc seconds times 10000. b and d
* are arc seconds per Julian century times 100000. i through m
* are integers. See the program for interpretation of MM, MS,
* etc., which are mean orbital elements of the Sun and Moon.
*
* If terms with coefficient less than X are omitted, the peak
* errors will be:
*
* omit error, omit error,
* a < longitude c < obliquity
* .0005" .0100" .0008" .0094"
* .0046 .0492 .0095 .0481
* .0123 .0880 .0224 .0905
* .0386 .1808 .0895 .1129
*/
nt: [
0, 0, 0, 0, 2, 2062, 2, -895, 5,
-2, 0, 2, 0, 1, 46, 0, -24, 0,
2, 0, -2, 0, 0, 11, 0, 0, 0,
-2, 0, 2, 0, 2, -3, 0, 1, 0,
1, -1, 0, -1, 0, -3, 0, 0, 0,
0, -2, 2, -2, 1, -2, 0, 1, 0,
2, 0, -2, 0, 1, 1, 0, 0, 0,
0, 0, 2, -2, 2, -13187, -16, 5736, -31,
0, 1, 0, 0, 0, 1426, -34, 54, -1,
0, 1, 2, -2, 2, -517, 12, 224, -6,
0, -1, 2, -2, 2, 217, -5, -95, 3,
0, 0, 2, -2, 1, 129, 1, -70, 0,
2, 0, 0, -2, 0, 48, 0, 1, 0,
0, 0, 2, -2, 0, -22, 0, 0, 0,
0, 2, 0, 0, 0, 17, -1, 0, 0,
0, 1, 0, 0, 1, -15, 0, 9, 0,
0, 2, 2, -2, 2, -16, 1, 7, 0,
0, -1, 0, 0, 1, -12, 0, 6, 0,
-2, 0, 0, 2, 1, -6, 0, 3, 0,
0, -1, 2, -2, 1, -5, 0, 3, 0,
2, 0, 0, -2, 1, 4, 0, -2, 0,
0, 1, 2, -2, 1, 4, 0, -2, 0,
1, 0, 0, -1, 0, -4, 0, 0, 0,
2, 1, 0, -2, 0, 1, 0, 0, 0,
0, 0, -2, 2, 1, 1, 0, 0, 0,
0, 1, -2, 2, 0, -1, 0, 0, 0,
0, 1, 0, 0, 2, 1, 0, 0, 0,
-1, 0, 0, 1, 1, 1, 0, 0, 0,
0, 1, 2, -2, 0, -1, 0, 0, 0,
0, 0, 2, 0, 2, -2274, -2, 977, -5,
1, 0, 0, 0, 0, 712, 1, -7, 0,
0, 0, 2, 0, 1, -386, -4, 200, 0,
1, 0, 2, 0, 2, -301, 0, 129, -1,
1, 0, 0, -2, 0, -158, 0, -1, 0,
-1, 0, 2, 0, 2, 123, 0, -53, 0,
0, 0, 0, 2, 0, 63, 0, -2, 0,
1, 0, 0, 0, 1, 63, 1, -33, 0,
-1, 0, 0, 0, 1, -58, -1, 32, 0,
-1, 0, 2, 2, 2, -59, 0, 26, 0,
1, 0, 2, 0, 1, -51, 0, 27, 0,
0, 0, 2, 2, 2, -38, 0, 16, 0,
2, 0, 0, 0, 0, 29, 0, -1, 0,
1, 0, 2, -2, 2, 29, 0, -12, 0,
2, 0, 2, 0, 2, -31, 0, 13, 0,
0, 0, 2, 0, 0, 26, 0, -1, 0,
-1, 0, 2, 0, 1, 21, 0, -10, 0,
-1, 0, 0, 2, 1, 16, 0, -8, 0,
1, 0, 0, -2, 1, -13, 0, 7, 0,
-1, 0, 2, 2, 1, -10, 0, 5, 0,
1, 1, 0, -2, 0, -7, 0, 0, 0,
0, 1, 2, 0, 2, 7, 0, -3, 0,
0, -1, 2, 0, 2, -7, 0, 3, 0,
1, 0, 2, 2, 2, -8, 0, 3, 0,
1, 0, 0, 2, 0, 6, 0, 0, 0,
2, 0, 2, -2, 2, 6, 0, -3, 0,
0, 0, 0, 2, 1, -6, 0, 3, 0,
0, 0, 2, 2, 1, -7, 0, 3, 0,
1, 0, 2, -2, 1, 6, 0, -3, 0,
0, 0, 0, -2, 1, -5, 0, 3, 0,
1, -1, 0, 0, 0, 5, 0, 0, 0,
2, 0, 2, 0, 1, -5, 0, 3, 0,
0, 1, 0, -2, 0, -4, 0, 0, 0,
1, 0, -2, 0, 0, 4, 0, 0, 0,
0, 0, 0, 1, 0, -4, 0, 0, 0,
1, 1, 0, 0, 0, -3, 0, 0, 0,
1, 0, 2, 0, 0, 3, 0, 0, 0,
1, -1, 2, 0, 2, -3, 0, 1, 0,
-1, -1, 2, 2, 2, -3, 0, 1, 0,
-2, 0, 0, 0, 1, -2, 0, 1, 0,
3, 0, 2, 0, 2, -3, 0, 1, 0,
0, -1, 2, 2, 2, -3, 0, 1, 0,
1, 1, 2, 0, 2, 2, 0, -1, 0,
-1, 0, 2, -2, 1, -2, 0, 1, 0,
2, 0, 0, 0, 1, 2, 0, -1, 0,
1, 0, 0, 0, 2, -2, 0, 1, 0,
3, 0, 0, 0, 0, 2, 0, 0, 0,
0, 0, 2, 1, 2, 2, 0, -1, 0,
-1, 0, 0, 0, 2, 1, 0, -1, 0,
1, 0, 0, -4, 0, -1, 0, 0, 0,
-2, 0, 2, 2, 2, 1, 0, -1, 0,
-1, 0, 2, 4, 2, -2, 0, 1, 0,
2, 0, 0, -4, 0, -1, 0, 0, 0,
1, 1, 2, -2, 2, 1, 0, -1, 0,
1, 0, 2, 2, 1, -1, 0, 1, 0,
-2, 0, 2, 4, 2, -1, 0, 1, 0,
-1, 0, 4, 0, 2, 1, 0, 0, 0,
1, -1, 0, -2, 0, 1, 0, 0, 0,
2, 0, 2, -2, 1, 1, 0, -1, 0,
2, 0, 2, 2, 2, -1, 0, 0, 0,
1, 0, 0, 2, 1, -1, 0, 0, 0,
0, 0, 4, -2, 2, 1, 0, 0, 0,
3, 0, 2, -2, 2, 1, 0, 0, 0,
1, 0, 2, -2, 0, -1, 0, 0, 0,
0, 1, 2, 0, 1, 1, 0, 0, 0,
-1, -1, 0, 2, 1, 1, 0, 0, 0,
0, 0, -2, 0, 1, -1, 0, 0, 0,
0, 0, 2, -1, 2, -1, 0, 0, 0,
0, 1, 0, 2, 0, -1, 0, 0, 0,
1, 0, -2, -2, 0, -1, 0, 0, 0,
0, -1, 2, 0, 1, -1, 0, 0, 0,
1, 1, 0, -2, 1, -1, 0, 0, 0,
1, 0, -2, 2, 0, -1, 0, 0, 0,
2, 0, 0, 2, 0, 1, 0, 0, 0,
0, 0, 2, 4, 2, -1, 0, 0, 0,
0, 1, 0, 1, 0, 1, 0, 0, 0
],
ss: [],
cc: []
}
/**
* Nutation -- AA page B20
* using nutation in longitude and obliquity from nutlo()
* and obliquity of the ecliptic from epsiln()
* both calculated for Julian date J.
*
* p = equatorial rectangular position vector of object for
* mean ecliptic and equinox of date.
*/
nutation.calc = function (date, p) {
this.calclo(date)
/* be sure we calculated nutl and nuto */
epsilon.calc(date)
/* and also the obliquity of date */
var f = epsilon.eps + this.nuto
var ce = Math.cos(f)
var se = Math.sin(f)
var sino = Math.sin(this.nuto)
var cl = Math.cos(this.nutl)
var sl = Math.sin(this.nutl)
/* Apply adjustment
* to equatorial rectangular coordinates of object.
*
* This is a composite of three rotations: rotate about x axis
* to ecliptic of date; rotate about new z axis by the nutation
* in longitude; rotate about new x axis back to equator of date
* plus nutation in obliquity.
*/
var p1 = {
longitude: cl * p.longitude
- sl * epsilon.coseps * p.latitude
- sl * epsilon.sineps * p.distance,
latitude: sl * ce * p.longitude
+ (cl * epsilon.coseps * ce + epsilon.sineps * se) * p.latitude
- (sino + (1 - cl) * epsilon.sineps * ce) * p.distance,
distance: sl * se * p.longitude
+ (sino + (cl - 1) * se * epsilon.coseps) * p.latitude
+ (cl * epsilon.sineps * se + epsilon.coseps * ce) * p.distance
}
var dp = {
longitude: p1.longitude - p.longitude,
latitude: p1.latitude - p.latitude,
distance: p1.distance - p.distance
}
var result = util.showcor(p, dp)
p.longitude = p1.longitude
p.latitude = p1.latitude
p.distance = p1.distance
return result
}
/**
* Nutation in longitude and obliquity
* computed at Julian date J.
*/
nutation.calclo = function (date) {
if (this.jdnut.julian == date.julian) {
return 0
}
this.jdnut = date
/* Julian centuries from 2000 January 1.5,
* barycentric dynamical time
*/
var T = (date.julian - 2451545) / 36525
var T2 = T * T
var T10 = T / 10
/* Fundamental arguments in the FK5 reference system. */
/**
* longitude of the mean ascending node of the lunar orbit
* on the ecliptic, measured from the mean equinox of date
*/
var OM = (util.mods3600(-6962890.539 * T + 450160.280) + (0.008 * T + 7.455) * T2)
* constant.STR
/**
* mean longitude of the Sun minus the
* mean longitude of the Sun's perigee
*/
var MS = (util.mods3600(129596581.224 * T + 1287099.804) - (0.012 * T + 0.577) * T2)
* constant.STR
/**
* mean longitude of the Moon minus the
* mean longitude of the Moon's perigee
*/
var MM = (util.mods3600(1717915922.633 * T + 485866.733) + (0.064 * T + 31.310) * T2)
* constant.STR
/**
* mean longitude of the Moon minus the
* mean longitude of the Moon's node
*/
var FF = (util.mods3600(1739527263.137 * T + 335778.877) + (0.011 * T - 13.257) * T2)
* constant.STR
/**
* mean elongation of the Moon from the Sun.
*/
var DD = (util.mods3600(1602961601.328 * T + 1072261.307) + (0.019 * T - 6.891) * T2)
* constant.STR
/* Calculate sin( i*MM ), etc. for needed multiple angles */
this.sscc(0, MM, 3)
this.sscc(1, MS, 2)
this.sscc(2, FF, 4)
this.sscc(3, DD, 4)
this.sscc(4, OM, 2)
var C = 0.0
var D = 0.0
var p = this.nt
/* point to start of table */
var p_i = 0
for (var i = 0; i < 105; i++) {
/* argument of sine and cosine */
var k
var k1 = false
var cv = 0.0
var sv = 0.0
for (var m = 0; m < 5; m++) {
var j = p[p_i++] // *p++;
if (j) {
k = j < 0 ? -j : j
var su = this.ss[m][k - 1]
/* sin(k*angle) */
if (j < 0) {
su = -su
}
var cu = this.cc[m][k - 1]
if (!k1) { /* set first angle */
sv = su
cv = cu
k1 = true
} else { /* combine angles */
var sw = su * cv + cu * sv
cv = cu * cv - su * sv
sv = sw
}
}
}
/* longitude coefficient */
var f = p[p_i++] // *p++;
k = p[p_i++] // *p++;
if (k != 0) {
f += T10 * k
}
/* obliquity coefficient */
var g = p[p_i++] // *p++;
k = p[p_i++] // *p++;
if (k != 0) {
g += T10 * k
}
/* accumulate the terms */
C += f * sv
D += g * cv
}
/* first terms, not in table: */
C += (-1742 * T10 - 171996) * this.ss[4][0]
/* sin(OM) */
D += (89 * T10 + 92025) * this.cc[4][0]
/* cos(OM) */
/*
printf( "nutation: in longitude %.3f\", in obliquity %.3f\"\n", C, D );
*/
/* Save answers, expressed in radians */
this.nutl = 0.0001 * constant.STR * C
this.nuto = 0.0001 * constant.STR * D
}
/**
* Prepare lookup table of sin and cos ( i*Lj )
* for required multiple angles
*/
nutation.sscc = function (k, arg, n) {
var su = Math.sin(arg)
var cu = Math.cos(arg)
this.ss[k] = []
this.cc[k] = []
this.ss[k][0] = su
/* sin(L) */
this.cc[k][0] = cu
/* cos(L) */
var sv = 2 * su * cu
var cv = cu * cu - su * su
this.ss[k][1] = sv
/* sin(2L) */
this.cc[k][1] = cv
for (var i = 2; i < n; i++) {
var s = su * cv + cu * sv
cv = cu * cv - su * sv
sv = s
this.ss[k][i] = sv
/* sin( i+1 L ) */
this.cc[k][i] = cv
}
}
module.exports = nutation