// AberrationRonVondrak uses the Ron-Vondrák expression to compute corrections // due to aberration for equatorial coordinates of an object. func AberrationRonVondrak(α unit.RA, δ unit.Angle, jd float64) (Δα unit.HourAngle, Δδ unit.Angle) { T := base.J2000Century(jd) r := &rv{ T: T, L2: 3.1761467 + 1021.3285546*T, L3: 1.7534703 + 628.3075849*T, L4: 6.2034809 + 334.0612431*T, L5: 0.5995465 + 52.9690965*T, L6: 0.8740168 + 21.3299095*T, L7: 5.4812939 + 7.4781599*T, L8: 5.3118863 + 3.8133036*T, Lp: 3.8103444 + 8399.6847337*T, D: 5.1984667 + 7771.3771486*T, Mp: 2.3555559 + 8328.6914289*T, F: 1.6279052 + 8433.4661601*T, } var Xp, Yp, Zp float64 // sum smaller terms first for i := 35; i >= 0; i-- { x, y, z := rvTerm[i](r) Xp += x Yp += y Zp += z } sα, cα := α.Sincos() sδ, cδ := δ.Sincos() // (23.4) p. 156 Δα = unit.HourAngle((Yp*cα - Xp*sα) / (c * cδ)) Δδ = unit.Angle(-((Xp*cα+Yp*sα)*sδ - Zp*cδ) / c) return }
// Topocentric2 returns topocentric corrections including parallax. // // This function implements the "non-rigorous" method descripted in the text. // // Note that results are corrections, not corrected coordinates. func Topocentric2(α unit.RA, δ unit.Angle, Δ, ρsφʹ, ρcφʹ float64, L unit.Angle, jde float64) (Δα unit.HourAngle, Δδ unit.Angle) { π := Horizontal(Δ) θ0 := sidereal.Apparent(jde) H := (θ0.Angle() - L - unit.Angle(α)).Mod1() sH, cH := H.Sincos() sδ, cδ := δ.Sincos() Δα = unit.HourAngle(-π.Mul(ρcφʹ * sH / cδ)) // (40.4) p. 280 Δδ = -π.Mul(ρsφʹ*cδ - ρcφʹ*cH*sδ) // (40.5) p. 280 return }
// Nutation returns corrections due to nutation for equatorial coordinates // of an object. // // Results are invalid for objects very near the celestial poles. func Nutation(α unit.RA, δ unit.Angle, jd float64) (Δα1 unit.HourAngle, Δδ1 unit.Angle) { ε := nutation.MeanObliquity(jd) sε, cε := ε.Sincos() Δψ, Δε := nutation.Nutation(jd) sα, cα := α.Sincos() tδ := δ.Tan() // (23.1) p. 151 Δα1 = unit.HourAngle((cε+sε*sα*tδ)*Δψ.Rad() - cα*tδ*Δε.Rad()) Δδ1 = Δψ.Mul(sε*cα) + Δε.Mul(sα) return }
// Topocentric returns topocentric positions including parallax. // // Arguments α, δ are geocentric right ascension and declination in radians. // Δ is distance to the observed object in AU. ρsφʹ, ρcφʹ are parallax // constants (see package globe.) L is geographic longitude of the observer, // jde is time of observation. // // Results are observed topocentric ra and dec in radians. func Topocentric(α unit.RA, δ unit.Angle, Δ, ρsφʹ, ρcφʹ float64, L unit.Angle, jde float64) (αʹ unit.RA, δʹ unit.Angle) { π := Horizontal(Δ) θ0 := sidereal.Apparent(jde) H := (θ0.Angle() - L - unit.Angle(α)).Mod1() sπ := π.Sin() sH, cH := H.Sincos() sδ, cδ := δ.Sincos() // (40.2) p. 279 Δα := unit.HourAngle(math.Atan2(-ρcφʹ*sπ*sH, cδ-ρcφʹ*sπ*cH)) αʹ = α.Add(Δα) // (40.3) p. 279 δʹ = unit.Angle(math.Atan2((sδ-ρsφʹ*sπ)*Δα.Cos(), cδ-ρcφʹ*sπ*cH)) return }
// ESmart computes the "equation of time" for the given JDE. // // Result is equation of time as an hour angle. // // Result is less accurate that E() but the function has the advantage // of not requiring the V87Planet object. func ESmart(jde float64) unit.HourAngle { ε := nutation.MeanObliquity(jde) t := ε.Mul(.5).Tan() y := t * t T := base.J2000Century(jde) L0 := l0(T * .1) e := solar.Eccentricity(T) M := solar.MeanAnomaly(T) s2L0, c2L0 := L0.Mul(2).Sincos() sM := M.Sin() // (28.3) p. 185, with double angle identity return unit.HourAngle(y*s2L0 - 2*e*sM + 4*e*y*sM*c2L0 - y*y*s2L0*c2L0 - 1.25*e*e*M.Mul(2).Sin()) }
// Topocentric3 returns topocentric hour angle and declination including parallax. // // This function implements the "alternative" method described in the text. // The method should be similarly rigorous to that of Topocentric() and results // should be virtually consistent. func Topocentric3(α unit.RA, δ unit.Angle, Δ, ρsφʹ, ρcφʹ float64, L unit.Angle, jde float64) (Hʹ unit.HourAngle, δʹ unit.Angle) { π := Horizontal(Δ) θ0 := sidereal.Apparent(jde) H := (θ0.Angle() - L - unit.Angle(α)).Mod1() sπ := π.Sin() sH, cH := H.Sincos() sδ, cδ := δ.Sincos() A := cδ * sH B := cδ*cH - ρcφʹ*sπ C := sδ - ρsφʹ*sπ q := math.Sqrt(A*A + B*B + C*C) Hʹ = unit.HourAngle(math.Atan2(A, B)) δʹ = unit.Angle(math.Asin(C / q)) return }
// E computes the "equation of time" for the given JDE. // // Parameter e must be a planetposition.V87Planet object for Earth obtained // with planetposition.LoadPlanet. // // Result is equation of time as an hour angle. func E(jde float64, e *pp.V87Planet) unit.HourAngle { τ := base.J2000Century(jde) * .1 L0 := l0(τ) // code duplicated from solar.ApparentEquatorialVSOP87 so that // we can keep Δψ and cε s, β, R := solar.TrueVSOP87(e, jde) Δψ, Δε := nutation.Nutation(jde) a := unit.AngleFromSec(-20.4898).Div(R) λ := s + Δψ + a ε := nutation.MeanObliquity(jde) + Δε sε, cε := ε.Sincos() α, _ := coord.EclToEq(λ, β, sε, cε) // (28.1) p. 183 E := L0 - unit.AngleFromDeg(.0057183) - unit.Angle(α) + Δψ.Mul(cε) return unit.HourAngle((E + math.Pi).Mod1() - math.Pi) }
// Aberration returns corrections due to aberration for equatorial // coordinates of an object. func Aberration(α unit.RA, δ unit.Angle, jd float64) (Δα2 unit.HourAngle, Δδ2 unit.Angle) { ε := nutation.MeanObliquity(jd) T := base.J2000Century(jd) s, _ := solar.True(T) e := solar.Eccentricity(T) π := perihelion(T) sα, cα := α.Sincos() sδ, cδ := δ.Sincos() ss, cs := s.Sincos() sπ, cπ := π.Sincos() cε := ε.Cos() tε := ε.Tan() q1 := cα * cε // (23.3) p. 152 Δα2 = unit.HourAngle(κ.Rad() * (e*(q1*cπ+sα*sπ) - (q1*cs + sα*ss)) / cδ) q2 := cε * (tε*cδ - sα*sδ) q3 := cα * sδ Δδ2 = κ.Mul(e*(cπ*q2+sπ*q3) - (cs*q2 + ss*q3)) return }
// NutationInRA returns "nutation in right ascension" or "equation of the // equinoxes." func NutationInRA(jde float64) unit.HourAngle { // ch 12, p.88 Δψ, Δε := Nutation(jde) ε0 := MeanObliquity(jde) return unit.HourAngle(Δψ.Rad() * math.Cos((ε0 + Δε).Rad())) }