UNPKG

3.83 kBJavaScriptView Raw
1import circle from '@robireton/circle'
2import JulianEphemerisDay from './julian-day'
3import calculateNutationAndObliquity from './nutation-obliquity'
4import earthVSOP87D from './vsop87d-earth'
5
6export function positionSun (date, lat, lon) {
7 const JDE = JulianEphemerisDay(date)
8 const heliocentric = positionEarth(JDE)
9
10 // convert heliocentric longitude & latitude to geocentric
11 let Θ = circle.normalizedDegrees(heliocentric.L + 180)
12 let β = -heliocentric.B
13
14 // convert to FK5 reference frame
15 const T = (JDE - 2451545) / 36525 // time in centuries from 2000.0
16 const λ_ = Θ + T * (-1.397 + T * (-0.00031 * T))
17 const ΔΘ = -0.09033 / 3600
18 const Δβ = (0.03916 / 3600) * (Math.cos(circle.DegreesToRadians(λ_)) - Math.sin(circle.DegreesToRadians(λ_)))
19 Θ += ΔΘ
20 β += Δβ
21
22 // correct for nutation and aberration
23 const objNutObl = calculateNutationAndObliquity(JDE)
24 const λ = Θ + objNutObl.Δψ - (20.4898 / 3600) / heliocentric.R
25
26 // convert to right ascension & declination
27 const ε = circle.DegreesToRadians(objNutObl.ε)
28 const α = circle.normalizedDegrees(circle.RadiansToDegrees(Math.atan2(Math.sin(circle.DegreesToRadians(λ)) * Math.cos(ε) - Math.tan(circle.DegreesToRadians(β)) * Math.sin(ε), Math.cos(circle.DegreesToRadians(λ)))))
29 const δ = circle.RadiansToDegrees(Math.asin(Math.sin(circle.DegreesToRadians(β)) * Math.cos(ε) + Math.cos(circle.DegreesToRadians(β)) * Math.sin(ε) * Math.sin(circle.DegreesToRadians(λ))))
30
31 // c.f. Chapter 27 of Astronomical Algorithms by Jean Meeus
32 const τ = T / 10
33 const L0 = circle.normalizedDegrees(280.4664567 + τ * (360007.6982779 + τ * (0.03032028 + τ * (1 / 49931 + τ * (-1 / 15299 - τ / 1988000)))))
34 let E = circle.normalizedDegrees(L0 - 0.0057183 - α + objNutObl.Δψ * Math.cos(ε))
35 if (E > 180) E -= 360
36 E *= 4 // convert degrees of arc to minutes of time
37
38 let A, h
39 if (!isNaN(lat) && !isNaN(lon)) {
40 const θ0 = circle.normalizedDegrees(280.46061837 + 360.98564736629 * (JDE - 2451545.0) + 0.000387933 * T * T + T * T * T / 38710000) + objNutObl.Δψ * Math.cos(ε)
41
42 const L = -lon // Meeus thumbs his nose at the IAU and considers longitude to increase west from Greenwich
43 const φ = lat
44
45 const H = circle.normalizedDegrees(θ0 - L - α)
46
47 A = circle.normalizedDegrees(180 + circle.RadiansToDegrees(Math.atan2(Math.sin(circle.DegreesToRadians(H)), Math.cos(circle.DegreesToRadians(H)) * Math.sin(circle.DegreesToRadians(φ)) - Math.tan(circle.DegreesToRadians(δ)) * Math.cos(circle.DegreesToRadians(φ)))))
48
49 h = circle.RadiansToDegrees(Math.asin(Math.sin(circle.DegreesToRadians(φ)) * Math.sin(circle.DegreesToRadians(δ)) + Math.cos(circle.DegreesToRadians(φ)) * Math.cos(circle.DegreesToRadians(δ)) * Math.cos(circle.DegreesToRadians(H))))
50 }
51
52 return {
53 E: E, // value for the equation of time in minutes
54 A: Math.round(1000000 * A) / 1000000, // azimuth in degrees, measured westward from the South
55 h: Math.round(1000000 * h) / 1000000 // altitude in degrees, positive above the horizon, negative below
56 }
57}
58
59function positionEarth (JDE) {
60 // c.f. Chapter 31 of Astronomical Algorithms by Jean Meeus
61 const τ = (JDE - 2451545) / 365250
62
63 const L = circle.normalizedRadians(computeVSOP87(earthVSOP87D.L, τ))
64 const B = computeVSOP87(earthVSOP87D.B, τ)
65 const R = computeVSOP87(earthVSOP87D.R, τ)
66
67 return {
68 L: circle.RadiansToDegrees(L), // the ecliptical longitude in degrees
69 B: circle.RadiansToDegrees(B), // the ecliptical latitude in degrees
70 R: R // the radius vector (distance to Sun) in AU
71 }
72}
73
74function computeVSOP87 (obj, T) {
75 let X = 0
76 for (const α in obj) {
77 let coeff = 0
78 for (const β of obj[α]) {
79 coeff += β.A * Math.cos(β.B + β.C * T)
80 }
81 X += coeff * Math.pow(T, α)
82 }
83
84 return X
85}