meeusjs
Version:
Implementation of the Astronomical Algorithms of Jean Meeus in Javascript
456 lines (386 loc) • 12.6 kB
JavaScript
// Copyright (c) 2016 Fabio Soldati, www.peakfinder.org
// License MIT: http://www.opensource.org/licenses/MIT
/**
* Methods for calculations of the position and times of the moon.
* @module A.Moon
*/
A.Moon = {
/**
* parallax returns equatorial horizontal parallax pi of the Moon.
*
* @function parallax
* @static
*
* @param {number} delta - is distance between centers of the Earth and Moon, in km.
* @return {number} result in radians
*/
parallax: function(delta) {
// p. 337
return Math.asin(6378.14 / delta);
},
/**
* apparentEquatorial returns the apparent position of the moon as equatorial coordinates.
*
* @function apparentEquatorial
* @static
*
* @param {A.JulianDay} jdo - julian day
* @return {Map} eq: the apparent position of the moon as equatorial coordinates <br>
* delta: Distance between centers of the Earth and Moon, in km.
*/
apparentEquatorial: function (jdo) {
var moon = A.Moon.geocentricPosition(jdo);
var nut = A.Nutation.nutation(jdo);
var obliquity0 = A.Nutation.meanObliquityLaskar(jdo);
var obliquity = obliquity0 + nut.deltaobliquity; // true obliquity
var apparentlng = moon.lng + nut.deltalng; // apparent longitude
var eq = A.Coord.eclToEq(new A.EclCoord(apparentlng, moon.lat), obliquity);
return {
eq: eq,
delta: moon.delta
};
},
/**
* apparentTopocentric returns the apparent position of the moon as topocentric coordinates.
*
* @function apparentTopocentric
* @static
*
* @param {A.JulianDay} jdo - julian day
* @param {A.EclCoord} eclCoord - geographic location of observer
* @param {?Number} apparent0 - apparent sidereal time at Greenwich for the given JD in radians.
* @return {Map} eq: the corrected apparent position of the moon as equatorial coordinates <br>
* delta: Distance between centers of the Earth and Moon, in km.
*/
apparentTopocentric: function (jdo, eclCoord, apparent0) {
var ae = A.Moon.apparentEquatorial(jdo);
// get the corrected right ascension and declination
var pc = A.Globe.parallaxConstants(eclCoord.lat, eclCoord.h);
var parallax = A.Moon.parallax(ae.delta);
if (!apparent0) // if apparent0 is not provided do the calcuation now
apparent0 = A.Sidereal.apparentInRa(jdo);
var tc = A.Parallax.topocentric(ae.eq, parallax, pc.rhoslat, pc.rhoclat, eclCoord.lng, apparent0);
return {
eq: tc,
delta: ae.delta
};
},
/**
* topocentricPosition calculates topocentric position of the moon for a given viewpoint and a given julian day.
*
* @function topocentricPosition
* @static
*
* @param {A.JulianDay} jdo - julian day
* @param {A.EclCoord} eclCoord - geographic location of the observer
* @param {boolean} refraction - if true the atmospheric refraction is added to the altitude
* @return {Map} hz: position of the Moon as horizontal coordinates with azimuth and altitude.<br>
* eq: position of the Moon as equatorial coordinates<br>
* delta: Distance between centers of the Earth and Moon, in km.<br>
* q: parallactic angle in radians
*/
topocentricPosition: function (jdo, eclCoord, refraction) {
var st0 = A.Sidereal.apparentInRa(jdo);
var aet = A.Moon.apparentTopocentric(jdo, eclCoord, st0);
var hz = A.Coord.eqToHz(aet.eq, eclCoord, st0);
if (refraction === true)
hz.alt += A.Refraction.bennett2(hz.alt);
var H = st0 - (eclCoord.lng + aet.eq.ra);
var q = A.Moon.parallacticAngle(eclCoord.lat, H, aet.eq.dec);
return {
hz: hz,
eq: aet.eq,
delta: aet.delta,
q: q
};
},
/**
* approxTransit times computes UT transit time for the lunar object on a day of interest.
*
* @function approxTransit
* @static
*
* @param {A.JulianDay} jdo - julian day
* @param {A.EclCoord} eclCoord - geographic location of the observer
* @return {NumberMap} transit value in seconds. If value is negative transit was the day before.
*/
approxTransit: function (jdo, eclCoord) {
var jdo0 = jdo.startOfDay(); // make sure jd is at midnight (ends with .5)
return A.Rise.approxTransit(eclCoord,
A.Sidereal.apparent0UT(jdo0),
A.Moon.apparentTopocentric(jdo0, eclCoord).eq);
},
/**
* approxTimes computes UT rise, transit and set times for the lunar object on a day of interest. <br>
* The function argurments do not actually include the day, but do include
* values computed from the day.
*
* @function approxTimes
* @static
*
* @param {A.JulianDay} jdo - julian day
* @param {A.EclCoord} eclCoord - geographic location of the observer
* @return {Map} transit, rise, set in seconds and in in the range [0,86400)
*/
approxTimes: function (jdo, eclCoord) {
jdo = jdo.startOfDay(); // make sure jd is at midnight (ends with .5)
var aet = A.Moon.apparentTopocentric(jdo, eclCoord);
var parallax = A.Moon.parallax(aet.delta);
var h0 = A.Rise.stdh0Lunar(parallax);
var Th0 = A.Sidereal.apparent0UT(jdo);
return A.Rise.approxTimes(eclCoord, h0, Th0, aet.eq);
},
/**
* times computes UT rise, transit and set times for the lunar object on a day of interest.
* This method has a higher accuarcy than approxTimes but needs more cpu power. <br>
* The function argurments do not actually include the day, but do include
* values computed from the day.
*
* @function times
* @static
*
* @param {A.JulianDay} jdo - julian day
* @param {A.EclCoord} eclCoord - geographic location of the observer
* @return {Map} transit, rise, set in seconds and in in the range [0,86400)
*/
times: function (jdo, eclCoord) {
jdo = jdo.startOfDay(); // make sure jd is at midnight (ends with .5)
var aet1 = A.Moon.apparentTopocentric(new A.JulianDay(jdo.jd-1, jdo.deltaT), eclCoord);
var aet2 = A.Moon.apparentTopocentric(jdo, eclCoord);
var aet3 = A.Moon.apparentTopocentric(new A.JulianDay(jdo.jd+1, jdo.deltaT), eclCoord);
var parallax = A.Moon.parallax(aet2.delta);
var h0 = A.Rise.stdh0Lunar(parallax);
var Th0 = A.Sidereal.apparent0UT(jdo);
return A.Rise.times(eclCoord, jdo.deltaT, h0, Th0, [aet1.eq, aet2.eq, aet3.eq]);
},
/**
* parallacticAngle q calculates the parallactic angle of the moon formula 14.1
*
* @function parallacticAngle
* @static
*
* @param {number} lat - atitude of observer on Earth
* @param {number} H - is hour angle of observed object. st0 - ra
* @param {number} dec - declination of observed object.
* @return {number} q, result in radians
*/
parallacticAngle: function (lat, H, dec) {
return Math.atan2(Math.sin(H), Math.tan(lat) * Math.cos(dec) - Math.sin(dec) * Math.cos(H));
},
/**
* geocentricPosition returns geocentric location of the Moon. <br>
* Results are referenced to mean equinox of date and do not include the effect of nutation.
*
* @function geocentricPosition
* @static
*
* @param {A.JulianDay} jdo - julian day
* @return {number} result in radians
*/
geocentricPosition: function (jdo) {
var p = Math.PI / 180;
var T = jdo.jdeJ2000Century();
var L_ = A.Math.pMod(A.Math.horner(T, [218.3164477*p, 481267.88123421*p,
-0.0015786*p, p/538841, -p/65194000]), 2*Math.PI);
var D = A.Math.pMod(A.Math.horner(T, [297.8501921*p, 445267.1114034*p,
-0.0018819*p, p/545868, -p/113065000]), 2*Math.PI);
var M = A.Math.pMod(A.Math.horner(T, [357.5291092*p, 35999.0502909*p,
-0.0001535*p, p/24490000]), 2*Math.PI);
var M_ = A.Math.pMod(A.Math.horner(T, [134.9633964*p, 477198.8675055*p,
0.0087414*p, p/69699, -p/14712000]), 2*Math.PI);
var F = A.Math.pMod(A.Math.horner(T, [93.272095*p, 483202.0175233*p,
-0.0036539*p, -p/3526000, p/863310000]), 2*Math.PI);
var A1 = 119.75*p + 131.849*p*T;
var A2 = 53.09*p + 479264.29*p*T;
var A3 = 313.45*p + 481266.484*p*T;
var E = A.Math.horner(T, [1, -0.002516, -0.0000074]);
var E2 = E * E;
var suml = 3958*Math.sin(A1) + 1962*Math.sin(L_-F) + 318*Math.sin(A2);
var sumr = 0;
var sumb = -2235*Math.sin(L_) + 382*Math.sin(A3) + 175*Math.sin(A1-F) +
175*Math.sin(A1+F) + 127*Math.sin(L_-M_) - 115*Math.sin(L_+M_);
var i, r;
for (i = 0; i < A.Moon.ta.length; i++) {
// 0:D, 1:M, 2:M_, 3:F, 4:suml, 5:sumr
r = A.Moon.ta[i];
var a = D*r[0] + M*r[1] + M_*r[2] + F*r[3];
var sa = Math.sin(a);
var ca = Math.cos(a);
switch (r[1]) { // M
case 0:
suml += r[4] * sa;
sumr += r[5] * ca;
break;
case 1:
case -1:
suml += r[4] * sa * E;
sumr += r[5] * ca * E;
break;
case 2:
case -2:
suml += r[4] * sa * E2;
sumr += r[5] * ca * E2;
break;
default:
throw "error";
}
}
for (i = 0; i < A.Moon.tb.length; i++) {
// 0:D, 1:M, 2:M_, 3:F, 4:sumb
r = A.Moon.tb[i];
var b = D*r[0] + M*r[1] + M_*r[2] + F*r[3];
var sb = Math.sin(b);
switch (r[1]) { // M
case 0:
sumb += r[4] * sb;
break;
case 1:
case -1:
sumb += r[4] * sb * E;
break;
case 2:
case -2:
sumb += r[4] * sb * E2;
break;
default:
throw "error";
}
}
return {
lng: A.Math.pMod(L_, 2*Math.PI) + suml*1e-6*p,
lat: sumb * 1e-6 * p,
delta: 385000.56 + sumr*1e-3
};
},
/**
* 0:D, 1:M, 2:Mʹ, 3:F, 4:suml, 5:sumr
*
* @const {Array} ta
* @static
*/
ta: [
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[]
],
// 0:D, 1:M, 2:Mʹ, 3:F, 4:sumb
tb: [
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[]
]
};