// Position returns observed equatorial coordinates of a planet at a given time. // // Argument p must be a valid V87Planet object for the observed planet. // Argument earth must be a valid V87Planet object for Earth. // // Results are right ascension and declination, α and δ in radians. func Position(p, earth *pp.V87Planet, jde float64) (α, δ float64) { L0, B0, R0 := earth.Position(jde) L, B, R := p.Position(jde) sB0, cB0 := math.Sincos(B0) sL0, cL0 := math.Sincos(L0) sB, cB := math.Sincos(B) sL, cL := math.Sincos(L) x := R*cB*cL - R0*cB0*cL0 y := R*cB*sL - R0*cB0*sL0 z := R*sB - R0*sB0 { Δ := math.Sqrt(x*x + y*y + z*z) // (33.4) p. 224 τ := base.LightTime(Δ) // repeating with jde-τ L, B, R = p.Position(jde - τ) sB, cB = math.Sincos(B) sL, cL = math.Sincos(L) x = R*cB*cL - R0*cB0*cL0 y = R*cB*sL - R0*cB0*sL0 z = R*sB - R0*sB0 } λ := math.Atan2(y, x) // (33.1) p. 223 β := math.Atan2(z, math.Hypot(x, y)) // (33.2) p. 223 Δλ, Δβ := apparent.EclipticAberration(λ, β, jde) λ, β = pp.ToFK5(λ+Δλ, β+Δβ, jde) Δψ, Δε := nutation.Nutation(jde) λ += Δψ sε, cε := math.Sincos(nutation.MeanObliquity(jde) + Δε) return coord.EclToEq(λ, β, sε, cε) // Meeus gives a formula for elongation but doesn't spell out how to // obtaion term λ0 and doesn't give an example solution. }
func eqProperMotionToEcl(mα, mδ, epoch float64, pos *coord.Ecliptic) (mλ, mβ float64) { ε := nutation.MeanObliquity(base.JulianYearToJDE(epoch)) sε, cε := math.Sincos(ε) α, δ := coord.EclToEq(pos.Lon, pos.Lat, sε, cε) sα, cα := math.Sincos(α) sδ, cδ := math.Sincos(δ) cβ := math.Cos(pos.Lat) mλ = (mδ*sε*cα + mα*cδ*(cε*cδ+sε*sδ*sα)) / (cβ * cβ) mβ = (mδ*(cε*cδ+sε*sδ*sα) - mα*sε*cα*cδ) / cβ return }
func eqProperMotionToEcl(mα unit.HourAngle, mδ unit.Angle, epoch float64, pos *coord.Ecliptic) (mλ, mβ unit.Angle) { ε := nutation.MeanObliquity(base.JulianYearToJDE(epoch)) sε, cε := ε.Sincos() α, δ := coord.EclToEq(pos.Lon, pos.Lat, sε, cε) sα, cα := α.Sincos() sδ, cδ := δ.Sincos() cβ := pos.Lat.Cos() mλ = (mδ.Mul(sε*cα) + unit.Angle(mα).Mul(cδ*(cε*cδ+sε*sδ*sα))).Div(cβ * cβ) mβ = (mδ.Mul(cε*cδ+sε*sδ*sα) - unit.Angle(mα).Mul(sε*cα*cδ)).Div(cβ) return }
// ApparentEquatorialVSOP87 returns the apparent position of the sun as equatorial coordinates. // // Result computed by VSOP87, at equator and equinox of date in the FK5 frame, // and includes effects of nutation and aberration. // // α: right ascension in radians // δ: declination in radians // R: range in AU func ApparentEquatorialVSOP87(e *pp.V87Planet, jde float64) (α, δ, R float64) { // note: duplicate code from ApparentVSOP87 so we can keep Δε. // see also duplicate code in time.E(). s, β, R := TrueVSOP87(e, jde) Δψ, Δε := nutation.Nutation(jde) a := aberration(R) λ := s + Δψ + a ε := nutation.MeanObliquity(jde) + Δε sε, cε := math.Sincos(ε) α, δ = coord.EclToEq(λ, β, sε, cε) return }
func (m *moon) pa(λ, β, b unit.Angle) unit.Angle { V := m.Ω + m.Δψ + m.σ.Div(sI) sV, cV := V.Sincos() sIρ, cIρ := (_I + m.ρ).Sincos() X := sIρ * sV Y := sIρ*cV*m.cε - cIρ*m.sε ω := math.Atan2(X, Y) α, _ := coord.EclToEq(λ+m.Δψ, β, m.sε, m.cε) P := unit.Angle(math.Asin(math.Hypot(X, Y) * math.Cos(α.Rad()-ω) / b.Cos())) if P < 0 { P += 2 * math.Pi } return P }
func (m *moon) pa(λ, β, b float64) float64 { V := m.Ω + m.Δψ + m.σ/sI sV, cV := math.Sincos(V) sIρ, cIρ := math.Sincos(_I + m.ρ) X := sIρ * sV Y := sIρ*cV*m.cε - cIρ*m.sε ω := math.Atan2(X, Y) α, _ := coord.EclToEq(λ+m.Δψ, β, m.sε, m.cε) P := math.Asin(math.Hypot(X, Y) * math.Cos(α-ω) / math.Cos(b)) if P < 0 { P += 2 * math.Pi } return P }
// 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) }
// 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 in radians. func E(jde float64, e *pp.V87Planet) float64 { τ := 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 := -20.4898 / 3600 * math.Pi / 180 / R λ := s + Δψ + a ε := nutation.MeanObliquity(jde) + Δε sε, cε := math.Sincos(ε) α, _ := coord.EclToEq(λ, β, sε, cε) // (28.1) p. 183 E := L0 - .0057183*math.Pi/180 - α + Δψ*cε return base.PMod(E+math.Pi, 2*math.Pi) - math.Pi }
// Physical computes quantities for physical observations of Mars. // // Results: // DE planetocentric declination of the Earth. // DS planetocentric declination of the Sun. // ω Areographic longitude of the central meridian, as seen from Earth. // P Geocentric position angle of Mars' northern rotation pole. // Q Position angle of greatest defect of illumination. // d Apparent diameter of Mars. // q Greatest defect of illumination. // k Illuminated fraction of the disk. func Physical(jde float64, earth, mars *pp.V87Planet) (DE, DS, ω, P, Q, d, q unit.Angle, k float64) { // Step 1. T := base.J2000Century(jde) const p = math.Pi / 180 // (42.1) p. 288 λ0 := 352.9065*p + 1.1733*p*T β0 := 63.2818*p - .00394*p*T // Step 2. l0, b0, R := earth.Position(jde) l0, b0 = pp.ToFK5(l0, b0, jde) // Steps 3, 4. sl0, cl0 := l0.Sincos() sb0 := b0.Sin() Δ := .5 // surely better than 0. τ := base.LightTime(Δ) var l, b unit.Angle var r, x, y, z float64 f := func() { l, b, r = mars.Position(jde - τ) l, b = pp.ToFK5(l, b, jde) sb, cb := b.Sincos() sl, cl := l.Sincos() // (42.2) p. 289 x = r*cb*cl - R*cl0 y = r*cb*sl - R*sl0 z = r*sb - R*sb0 // (42.3) p. 289 Δ = math.Sqrt(x*x + y*y + z*z) τ = base.LightTime(Δ) } f() f() // Step 5. λ := math.Atan2(y, x) β := math.Atan(z / math.Hypot(x, y)) // Step 6. sβ0, cβ0 := math.Sincos(β0) sβ, cβ := math.Sincos(β) DE = unit.Angle(math.Asin(-sβ0*sβ - cβ0*cβ*math.Cos(λ0-λ))) // Step 7. N := 49.5581*p + .7721*p*T lʹ := l.Rad() - .00697*p/r bʹ := b.Rad() - .000225*p*math.Cos(l.Rad()-N)/r // Step 8. sbʹ, cbʹ := math.Sincos(bʹ) DS = unit.Angle(math.Asin(-sβ0*sbʹ - cβ0*cbʹ*math.Cos(λ0-lʹ))) // Step 9. W := 11.504*p + 350.89200025*p*(jde-τ-2433282.5) // Step 10. ε0 := nutation.MeanObliquity(jde) sε0, cε0 := ε0.Sincos() α0, δ0 := coord.EclToEq(unit.Angle(λ0), unit.Angle(β0), sε0, cε0) // Step 11. u := y*cε0 - z*sε0 v := y*sε0 + z*cε0 α := math.Atan2(u, x) δ := math.Atan(v / math.Hypot(x, u)) sδ, cδ := math.Sincos(δ) sδ0, cδ0 := δ0.Sincos() sα0α, cα0α := math.Sincos(α0.Rad() - α) ζ := math.Atan2(sδ0*cδ*cα0α-sδ*cδ0, cδ*sα0α) // Step 12. ω = unit.Angle(W - ζ).Mod1() // Step 13. Δψ, Δε := nutation.Nutation(jde) // Step 14. sl0λ, cl0λ := math.Sincos(l0.Rad() - λ) λ += .005693 * p * cl0λ / cβ β += .005693 * p * sl0λ * sβ // Step 15. λ0 += Δψ.Rad() λ += Δψ.Rad() ε := ε0 + Δε // Step 16. sε, cε := ε.Sincos() α0ʹ, δ0ʹ := coord.EclToEq(unit.Angle(λ0), unit.Angle(β0), sε, cε) αʹ, δʹ := coord.EclToEq(unit.Angle(λ), unit.Angle(β), sε, cε) // Step 17. sδ0ʹ, cδ0ʹ := δ0ʹ.Sincos() sδʹ, cδʹ := δʹ.Sincos() sα0ʹαʹ, cα0ʹαʹ := (α0ʹ - αʹ).Sincos() // (42.4) p. 290 P = unit.Angle(math.Atan2(cδ0ʹ*sα0ʹαʹ, sδ0ʹ*cδʹ-cδ0ʹ*sδʹ*cα0ʹαʹ)) if P < 0 { P += 2 * math.Pi } // Step 18. s := l0 + math.Pi ss, cs := s.Sincos() αs := math.Atan2(cε*ss, cs) δs := math.Asin(sε * ss) sδs, cδs := math.Sincos(δs) sαsα, cαsα := math.Sincos(αs - α) χ := math.Atan2(cδs*sαsα, sδs*cδ-cδs*sδ*cαsα) Q = unit.Angle(χ) + math.Pi // Step 19. d = unit.AngleFromSec(9.36) / unit.Angle(Δ) k = illum.Fraction(r, Δ, R) q = d.Mul(1 - k) return }