astronomia
Version:
An astronomical library
393 lines (371 loc) • 12.7 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var base = require('./base.cjs');
var coord = require('./coord.cjs');
var elementequinox = require('./elementequinox.cjs');
var nutation = require('./nutation.cjs');
var sexagesimal = require('./sexagesimal.cjs');
/**
* @copyright 2013 Sonia Keys
* @copyright 2016 commenthol
* @license MIT
* @module precess
*/
/**
* approxAnnualPrecession returns approximate annual precision in right
* ascension and declination.
*
* The two epochs should be within a few hundred years.
* The declinations should not be too close to the poles.
*
* @param {Equatorial} eqFrom
* @param {Number} epochFrom - use `base.JDEToJulianYear(year)` to get epoch
* @param {Number} epochTo - use `base.JDEToJulianYear(year)` to get epoch
* @returns {Object}
* {sexa.HourAngle} seconds of right ascension
* {sexa.Angle} seconds of Declination
*/
function approxAnnualPrecession (eqFrom, epochFrom, epochTo) {
const [m, na, nd] = mn(epochFrom, epochTo);
const [sa, ca] = base["default"].sincos(eqFrom.ra);
// (21.1) p. 132
const Δαs = m + na * sa * Math.tan(eqFrom.dec); // seconds of RA
const Δδs = nd * ca; // seconds of Dec
const ra = new sexagesimal.HourAngle(false, 0, 0, Δαs).rad();
const dec = new sexagesimal.Angle(false, 0, 0, Δδs).rad();
return { ra, dec }
}
/**
* @param {Number} epochFrom - use `base.JDEToJulianYear(year)` to get epoch
* @param {Number} epochTo - use `base.JDEToJulianYear(year)` to get epoch
* @returns {Number[]}
*/
function mn (epochFrom, epochTo) {
const T = (epochTo - epochFrom) * 0.01;
const m = 3.07496 + 0.00186 * T;
const na = 1.33621 - 0.00057 * T;
const nd = 20.0431 - 0.0085 * T;
return [m, na, nd]
}
/**
* ApproxPosition uses ApproxAnnualPrecession to compute a simple and quick
* precession while still considering proper motion.
*
* @param {Equatorial} eqFrom
* @param {Number} epochFrom
* @param {Number} epochTo
* @param {Number} mα - in radians
* @param {Number} mδ - in radians
* @returns {Equatorial} eqTo
*/
function approxPosition (eqFrom, epochFrom, epochTo, mα, mδ) {
const { ra, dec } = approxAnnualPrecession(eqFrom, epochFrom, epochTo);
const dy = epochTo - epochFrom;
const eqTo = new coord.Equatorial();
eqTo.ra = eqFrom.ra + (ra + mα) * dy;
eqTo.dec = eqFrom.dec + (dec + mδ) * dy;
return eqTo
}
// constants
const d = Math.PI / 180;
const s = d / 3600;
// coefficients from (21.2) p. 134
const ζT = [2306.2181 * s, 1.39656 * s, -0.000139 * s];
const zT = [2306.2181 * s, 1.39656 * s, -0.000139 * s];
const θT = [2004.3109 * s, -0.8533 * s, -0.000217 * s];
// coefficients from (21.3) p. 134
const ζt = [2306.2181 * s, 0.30188 * s, 0.017998 * s];
const zt = [2306.2181 * s, 1.09468 * s, 0.018203 * s];
const θt = [2004.3109 * s, -0.42665 * s, -0.041833 * s];
/**
* Precessor represents precession from one epoch to another.
*
* Construct with NewPrecessor, then call method Precess.
* After construction, Precess may be called multiple times to precess
* different coordinates with the same initial and final epochs.
*/
class Precessor {
/**
* constructs a Precessor object and initializes it to precess
* coordinates from epochFrom to epochTo.
* @param {Number} epochFrom
* @param {Number} epochTo
*/
constructor (epochFrom, epochTo) {
// (21.2) p. 134
let ζCoeff = ζt;
let zCoeff = zt;
let θCoeff = θt;
if (epochFrom !== 2000) {
const T = (epochFrom - 2000) * 0.01;
ζCoeff = [
base["default"].horner(T, ...ζT),
0.30188 * s - 0.000344 * s * T,
0.017998 * s
];
zCoeff = [
base["default"].horner(T, ...zT),
1.09468 * s + 0.000066 * s * T,
0.018203 * s
];
θCoeff = [
base["default"].horner(T, ...θT),
-0.42665 * s - 0.000217 * s * T,
-0.041833 * s
];
}
const t = (epochTo - epochFrom) * 0.01;
this.ζ = base["default"].horner(t, ...ζCoeff) * t;
this.z = base["default"].horner(t, ...zCoeff) * t;
const θ = base["default"].horner(t, ...θCoeff) * t;
this.sθ = Math.sin(θ);
this.cθ = Math.cos(θ);
}
/**
* Precess precesses coordinates eqFrom, leaving result in eqTo.
*
* @param {Equatorial} eqFrom
* @returns {Equatorial} eqTo
*/
precess (eqFrom) {
// (21.4) p. 134
const [sδ, cδ] = base["default"].sincos(eqFrom.dec);
const [sαζ, cαζ] = base["default"].sincos(eqFrom.ra + this.ζ);
const A = cδ * sαζ;
const B = this.cθ * cδ * cαζ - this.sθ * sδ;
const C = this.sθ * cδ * cαζ + this.cθ * sδ;
const eqTo = new coord.Equatorial();
eqTo.ra = Math.atan2(A, B) + this.z;
if (C < base["default"].CosSmallAngle) {
eqTo.dec = Math.asin(C);
} else {
eqTo.dec = Math.acos(Math.hypot(A, B)); // near pole
}
return eqTo
}
}
/**
* Position precesses equatorial coordinates from one epoch to another,
* including proper motions.
*
* If proper motions are not to be considered or are not applicable, pass 0, 0
* for mα, mδ
*
* Both eqFrom and eqTo must be non-nil, although they may point to the same
* struct. EqTo is returned for convenience.
* @param {Equatorial} eqFrom
* @param {Number} epochFrom
* @param {Number} epochTo
* @param {Number} mα - in radians
* @param {Number} mδ - in radians
* @returns {Equatorial} [eqTo]
*/
function position (eqFrom, epochFrom, epochTo, mα, mδ) {
const p = new Precessor(epochFrom, epochTo);
const t = epochTo - epochFrom;
const eqTo = new coord.Equatorial();
eqTo.ra = eqFrom.ra + mα * t;
eqTo.dec = eqFrom.dec + mδ * t;
return p.precess(eqTo)
}
// coefficients from (21.5) p. 136
const ηT = [47.0029 * s, -0.06603 * s, 0.000598 * s];
const πT = [174.876384 * d, 3289.4789 * s, 0.60622 * s];
const pT = [5029.0966 * s, 2.22226 * s, -0.000042 * s];
const ηt = [47.0029 * s, -0.03302 * s, 0.000060 * s];
const πt = [174.876384 * d, -869.8089 * s, 0.03536 * s];
const pt = [5029.0966 * s, 1.11113 * s, -0.000006 * s];
/**
* EclipticPrecessor represents precession from one epoch to another.
*
* Construct with NewEclipticPrecessor, then call method Precess.
* After construction, Precess may be called multiple times to precess
* different coordinates with the same initial and final epochs.
*/
class EclipticPrecessor {
/**
* constructs an EclipticPrecessor object and initializes
* it to precess coordinates from epochFrom to epochTo.
* @param {Number} epochFrom
* @param {Number} epochTo
*/
constructor (epochFrom, epochTo) {
// (21.5) p. 136
let ηCoeff = ηt;
let πCoeff = πt;
let pCoeff = pt;
if (epochFrom !== 2000) {
const T = (epochFrom - 2000) * 0.01;
ηCoeff = [
base["default"].horner(T, ...ηT),
-0.03302 * s + 0.000598 * s * T,
0.000060 * s
];
πCoeff = [
base["default"].horner(T, ...πT),
-869.8089 * s - 0.50491 * s * T,
0.03536 * s
];
pCoeff = [
base["default"].horner(T, ...pT),
1.11113 * s - 0.000042 * s * T,
-0.000006 * s
];
}
const t = (epochTo - epochFrom) * 0.01;
this.π = base["default"].horner(t, ...πCoeff);
this.p = base["default"].horner(t, ...pCoeff) * t;
const η = base["default"].horner(t, ...ηCoeff) * t;
this.sη = Math.sin(η);
this.cη = Math.cos(η);
}
/**
* EclipticPrecess precesses coordinates eclFrom, leaving result in eclTo.
*
* The same struct may be used for eclFrom and eclTo.
* EclTo is returned for convenience.
* @param {Ecliptic} eclFrom
* @returns {Ecliptic} [eclTo]
*/
precess (eclFrom) {
// (21.7) p. 137
const [sβ, cβ] = base["default"].sincos(eclFrom.lat);
const [sd, cd] = base["default"].sincos(this.π - eclFrom.lon);
const A = this.cη * cβ * sd - this.sη * sβ;
const B = cβ * cd;
const C = this.cη * sβ + this.sη * cβ * sd;
const eclTo = new coord.Ecliptic(this.p + this.π - Math.atan2(A, B));
if (C < base["default"].CosSmallAngle) {
eclTo.lat = Math.asin(C);
} else {
eclTo.lat = Math.acos(Math.hypot(A, B)); // near pole
}
return eclTo
}
/**
* ReduceElements reduces orbital elements of a solar system body from one
* equinox to another.
*
* This function is described in chapter 24, but is located in this
* package so it can be a method of EclipticPrecessor.
*
* @param {Elements} eFrom
* @returns {Elements} eTo
*/
reduceElements (eFrom) {
const ψ = this.π + this.p;
const [si, ci] = base["default"].sincos(eFrom.inc);
const [snp, cnp] = base["default"].sincos(eFrom.node - this.π);
const eTo = new elementequinox.Elements();
// (24.1) p. 159
eTo.inc = Math.acos(ci * this.cη + si * this.sη * cnp);
// (24.2) p. 159
eTo.node = Math.atan2(si * snp, this.cη * si * cnp - this.sη * ci) + ψ;
// (24.3) p. 159
eTo.peri = Math.atan2(-this.sη * snp, si * this.cη - ci * this.sη * cnp) + eFrom.peri;
return eTo
}
}
/**
* eclipticPosition precesses ecliptic coordinates from one epoch to another,
* including proper motions.
* While eclFrom is given as ecliptic coordinates, proper motions mα, mδ are
* still expected to be equatorial. If proper motions are not to be considered
* or are not applicable, pass 0, 0.
* Both eclFrom and eclTo must be non-nil, although they may point to the same
* struct. EclTo is returned for convenience.
*
* @param {Ecliptic} eclFrom,
* @param {Number} epochFrom
* @param {HourAngle} [mα]
* @param {Angle} [mδ]
* @returns {Ecliptic} eclTo
*/
function eclipticPosition (eclFrom, epochFrom, epochTo, mα, mδ) {
const p = new EclipticPrecessor(epochFrom, epochTo);
if (mα && mδ && (mα.rad() !== 0 || mδ.rad() !== 0)) {
const { lon, lat } = properMotion(mα.rad(), mδ.rad(), epochFrom, eclFrom);
const t = epochTo - epochFrom;
eclFrom.lon += lon * t;
eclFrom.lat += lat * t;
}
return p.precess(eclFrom)
}
/**
* @param {Number} mα - anual proper motion (ra)
* @param {Number} mδ - anual proper motion (dec)
* @param {Number} epoch
* @param {Ecliptic} ecl
* @returns {Ecliptic} {lon, lat}
*/
function properMotion (mα, mδ, epoch, ecl) {
const ε = nutation["default"].meanObliquity(base["default"].JulianYearToJDE(epoch));
const [εsin, εcos] = base["default"].sincos(ε);
const { ra, dec } = ecl.toEquatorial(ε);
const [sα, cα] = base["default"].sincos(ra);
const [sδ, cδ] = base["default"].sincos(dec);
const cβ = Math.cos(ecl.lat);
const lon = (mδ * εsin * cα + mα * cδ * (εcos * cδ + εsin * sδ * sα)) / (cβ * cβ);
const lat = (mδ * (εcos * cδ + εsin * sδ * sα) - mα * εsin * cα * cδ) / cβ;
return new coord.Ecliptic(lon, lat)
}
/**
* ProperMotion3D takes the 3D equatorial coordinates of an object
* at one epoch and computes its coordinates at a new epoch, considering
* proper motion and radial velocity.
*
* Radial distance (r) must be in parsecs, radial velocitiy (mr) in
* parsecs per year.
*
* Both eqFrom and eqTo must be non-nil, although they may point to the same
* struct. EqTo is returned for convenience.
*
* @param {Equatorial} eqFrom,
* @param {Number} epochFrom
* @param {Number} r
* @param {Number} mr
* @param {HourAngle} mα
* @param {Angle} mδ
* @returns {Equatorial} eqTo
*/
function properMotion3D (eqFrom, epochFrom, epochTo, r, mr, mα, mδ) {
const [sα, cα] = base["default"].sincos(eqFrom.ra);
const [sδ, cδ] = base["default"].sincos(eqFrom.dec);
const x = r * cδ * cα;
const y = r * cδ * sα;
const z = r * sδ;
const mrr = mr / r;
const zmδ = z * mδ.rad();
const mx = x * mrr - zmδ * cα - y * mα.rad();
const my = y * mrr - zmδ * sα + x * mα.rad();
const mz = z * mrr + r * mδ.rad() * cδ;
const t = epochTo - epochFrom;
const xp = x + t * mx;
const yp = y + t * my;
const zp = z + t * mz;
const eqTo = new coord.Equatorial();
eqTo.ra = Math.atan2(yp, xp);
eqTo.dec = Math.atan2(zp, Math.hypot(xp, yp));
return eqTo
}
var precess = {
approxAnnualPrecession,
mn,
approxPosition,
Precessor,
position,
EclipticPrecessor,
eclipticPosition,
properMotion,
properMotion3D
};
exports.EclipticPrecessor = EclipticPrecessor;
exports.Precessor = Precessor;
exports.approxAnnualPrecession = approxAnnualPrecession;
exports.approxPosition = approxPosition;
exports["default"] = precess;
exports.eclipticPosition = eclipticPosition;
exports.mn = mn;
exports.position = position;
exports.properMotion = properMotion;
exports.properMotion3D = properMotion3D;