astronomia
Version:
An astronomical library
276 lines (253 loc) • 6.87 kB
JavaScript
/**
* @copyright 2013 Sonia Keys
* @copyright 2016 commenthol
* @license MIT
* @module solstice
*/
/**
* Solstice: Chapter 27: Equinoxes and Solstices.
*/
import base from './base.js'
import solar from './solar.js'
const { abs, cos, sin } = Math
const D2R = Math.PI / 180
// table 27.a - for years from -1000 to +1000
const mc0 = [1721139.29189, 365242.13740, 0.06134, 0.00111, -0.00071]
const jc0 = [1721233.25401, 365241.72562, -0.05323, 0.00907, 0.00025]
const sc0 = [1721325.70455, 365242.49558, -0.11677, -0.00297, 0.00074]
const dc0 = [1721414.39987, 365242.88257, -0.00769, -0.00933, -0.00006]
// table 27.b - for years from +1000 to +3000
const mc2 = [2451623.80984, 365242.37404, 0.05169, -0.00411, -0.00057]
const jc2 = [2451716.56767, 365241.62603, 0.00325, 0.00888, -0.00030]
const sc2 = [2451810.21715, 365242.01767, -0.11575, 0.00337, 0.00078]
const dc2 = [2451900.05952, 365242.74049, -0.06223, -0.00823, 0.00032]
// table 27.c
const terms = (function () {
const term = [
[485, 324.96, 1934.136],
[203, 337.23, 32964.467],
[199, 342.08, 20.186],
[182, 27.85, 445267.112],
[156, 73.14, 45036.886],
[136, 171.52, 22518.443],
[77, 222.54, 65928.934],
[74, 296.72, 3034.906],
[70, 243.58, 9037.513],
[58, 119.81, 33718.147],
[52, 297.17, 150.678],
[50, 21.02, 2281.226],
[45, 247.54, 29929.562],
[44, 325.15, 31555.956],
[29, 60.93, 4443.417],
[18, 155.12, 67555.328],
[17, 288.79, 4562.452],
[16, 198.04, 62894.029],
[14, 199.76, 31436.921],
[12, 95.39, 14577.848],
[12, 287.11, 31931.756],
[12, 320.81, 34777.259],
[9, 227.73, 1222.114],
[8, 15.45, 16859.074]
]
return term.map((t) => {
return {
a: t[0],
b: t[1],
c: t[2]
}
})
})()
/**
* March returns the JDE of the March equinox for the given year.
*
* Results are valid for the years -1000 to +3000.
*
* Accuracy is within one minute of time for the years 1951-2050.
* @param {Number} y - (int) year
* @returns {Number} JDE
*/
export function march (y) {
if (y < 1000) {
return eq(y, mc0)
}
return eq(y - 2000, mc2)
}
/**
* June returns the JDE of the June solstice for the given year.
*
* Results are valid for the years -1000 to +3000.
*
* Accuracy is within one minute of time for the years 1951-2050.
* @param {Number} y - (int) year
* @returns {Number} JDE
*/
export function june (y) {
if (y < 1000) {
return eq(y, jc0)
}
return eq(y - 2000, jc2)
}
/**
* September returns the JDE of the September equinox for the given year.
*
* Results are valid for the years -1000 to +3000.
*
* Accuracy is within one minute of time for the years 1951-2050.
* @param {Number} y - (int) year
* @returns {Number} JDE
*/
export function september (y) {
if (y < 1000) {
return eq(y, sc0)
}
return eq(y - 2000, sc2)
}
/**
* December returns the JDE of the December solstice for a given year.
*
* Results are valid for the years -1000 to +3000.
*
* Accuracy is within one minute of time for the years 1951-2050.
* @param {Number} y - (int) year
* @returns {Number} JDE
*/
export function december (y) {
if (y < 1000) {
return eq(y, dc0)
}
return eq(y - 2000, dc2)
}
/**
* Fast calculation of solstices/ equinoxes
* Accuracy is within one minute of time for the years 1951-2050.
*
* @param {Number} y - (int) year
* @param {Array} c - term from table 27.a / 27.b
* @returns {Number} JDE
*/
function eq (y, c) {
const J0 = base.horner(y * 0.001, c)
const T = base.J2000Century(J0)
const W = 35999.373 * D2R * T - 2.47 * D2R
const Δλ = 1 + 0.0334 * cos(W) + 0.0007 * cos(2 * W)
let S = 0
for (let i = terms.length - 1; i >= 0; i--) {
const t = terms[i]
S += t.a * cos((t.b + t.c * T) * D2R)
}
return J0 + 0.00001 * S / Δλ
}
/**
* March2 returns a more accurate JDE of the March equinox.
*
* Result is accurate to one second of time.
*
* @param {Number} year - (int) year
* @param {planetposition.Planet} planet - must be a V87Planet object representing Earth, obtained with
* the package planetposition
* @returns {Number} JDE
*/
export function march2 (year, planet) {
return longitude(year, planet, 0)
}
/**
* June2 returns a more accurate JDE of the June solstice.
*
* Result is accurate to one second of time.
*
* @param {Number} year - (int) year
* @param {planetposition.Planet} planet - must be a V87Planet object representing Earth, obtained with
* the package planetposition
* @returns {Number} JDE
*/
export function june2 (year, planet) {
return longitude(year, planet, Math.PI / 2)
}
/**
* September2 returns a more accurate JDE of the September equinox.
*
* Result is accurate to one second of time.
*
* @param {Number} year - (int) year
* @param {planetposition.Planet} planet - must be a V87Planet object representing Earth, obtained with
* the package planetposition
* @returns {Number} JDE
*/
export function september2 (year, planet) {
return longitude(year, planet, Math.PI)
}
/**
* December2 returns a more accurate JDE of the December solstice.
*
* Result is accurate to one second of time.
*
* @param {Number} year - (int) year
* @param {planetposition.Planet} planet - must be a V87Planet object representing Earth, obtained with
* the package planetposition
* @returns {Number} JDE
*/
export function december2 (year, planet) {
return longitude(year, planet, Math.PI * 3 / 2)
}
/**
* Longitude returns the JDE for a given `year`, VSOP87 Planet `planet` at a
* given geocentric solar longitude `lon`
* @param {Number} year - (int)
* @param {planetposition.Planet} planet
* @param {Number} lon - geocentric solar longitude in radians
* @returns {Number} JDE
*/
export function longitude (year, planet, lon) {
let c
let ct
if (year < 1000) {
ct = [mc0, jc0, sc0, dc0]
} else {
ct = [mc2, jc2, sc2, dc2]
year -= 2000
}
lon = lon % (Math.PI * 2)
if (lon < Math.PI / 2) {
c = ct[0]
} else if (lon < Math.PI) {
c = ct[1]
} else if (lon < Math.PI * 3 / 2) {
c = ct[2]
} else {
c = ct[3]
}
return eq2(year, planet, lon, c)
}
/**
* Accurate calculation of solstices/ equinoxes
* Result is accurate to one second of time.
*
* @param {Number} year - (int) year
* @param {planetposition.Planet} planet - vsop87 planet
* @param {Number} lon - longitude in radians
* @param {Array} c - term from table 27.a / 27.b
* @returns {Number} JDE
*/
function eq2 (year, planet, lon, c) {
let J0 = base.horner(year * 0.001, c)
for (;;) {
const a = solar.apparentVSOP87(planet, J0)
const c = 58 * sin(lon - a.lon) // (27.1) p. 180
J0 += c
if (abs(c) < 0.000005) {
break
}
}
return J0
}
export default {
march,
june,
september,
december,
march2,
june2,
september2,
december2,
longitude
}