// 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. }
// TrueEquatorial returns the true geometric position of the Sun as equatorial coordinates. func TrueEquatorial(jde float64) (α, δ float64) { s, _ := True(base.J2000Century(jde)) ε := nutation.MeanObliquity(jde) ss, cs := math.Sincos(s) sε, cε := math.Sincos(ε) // (25.6, 25.7) p. 165 return math.Atan2(cε*ss, cs), sε * ss }
// ApparentEquatorial returns the apparent position of the Sun as equatorial coordinates. // // α: right ascension in radians // δ: declination in radians func ApparentEquatorial(jde float64) (α, δ float64) { T := base.J2000Century(jde) λ := ApparentLongitude(T) ε := nutation.MeanObliquity(jde) sλ, cλ := math.Sincos(λ) // (25.8) p. 165 sε, cε := math.Sincos(ε + .00256*math.Pi/180*math.Cos(node(T))) return math.Atan2(cε*sλ, cλ), math.Asin(sε * sλ) }
func TestIAUvsLaskar(t *testing.T) { for _, y := range []int{1000, 2000, 3000} { jd := julian.CalendarGregorianToJD(y, 0, 0) i := nutation.MeanObliquity(jd) l := nutation.MeanObliquityLaskar(jd) if math.Abs((i - l).Sec()) > 1 { t.Fatal(y) } } for _, y := range []int{0, 4000} { jd := julian.CalendarGregorianToJD(y, 0, 0) i := nutation.MeanObliquity(jd) l := nutation.MeanObliquityLaskar(jd) if math.Abs((i - l).Sec()) > 10 { t.Fatal(y) } } }
// TrueEquatorial returns the true geometric position of the Sun as equatorial coordinates. func TrueEquatorial(jde float64) (α unit.RA, δ unit.Angle) { s, _ := True(base.J2000Century(jde)) ε := nutation.MeanObliquity(jde) ss, cs := s.Sincos() sε, cε := ε.Sincos() // (25.6, 25.7) p. 165 α = unit.RAFromRad(math.Atan2(cε*ss, cs)) δ = unit.Angle(math.Asin(sε * ss)) return }
// Position returns rectangular coordinates referenced to the mean equinox of date. func Position(e *pp.V87Planet, jde float64) (x, y, z float64) { // (26.1) p. 171 s, β, R := solar.TrueVSOP87(e, jde) sε, cε := math.Sincos(nutation.MeanObliquity(jde)) ss, cs := math.Sincos(s) sβ := math.Sin(β) x = R * cs y = R * (ss*cε - sβ*sε) z = R * (ss*sε + sβ*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 }
// Nutation returns corrections due to nutation for equatorial coordinates // of an object. // // Results are invalid for objects very near the celestial poles. func Nutation(α, δ, jd float64) (Δα1, Δδ1 float64) { ε := nutation.MeanObliquity(jd) sε, cε := math.Sincos(ε) Δψ, Δε := nutation.Nutation(jd) sα, cα := math.Sincos(α) tδ := math.Tan(δ) // (23.1) p. 151 Δα1 = (cε+sε*sα*tδ)*Δψ - cα*tδ*Δε Δδ1 = sε*cα*Δψ + sα*Δε return }
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 }
// 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 }
// 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 }
// ApparentEquatorial returns the apparent position of the Sun as equatorial coordinates. // // α: right ascension in radians // δ: declination in radians func ApparentEquatorial(jde float64) (α unit.RA, δ unit.Angle) { T := base.J2000Century(jde) λ := ApparentLongitude(T) ε := nutation.MeanObliquity(jde) sλ, cλ := λ.Sincos() // (25.8) p. 165 ε += unit.AngleFromDeg(.00256).Mul(node(T).Cos()) sε, cε := ε.Sincos() α = unit.RAFromRad(math.Atan2(cε*sλ, cλ)) δ = unit.Angle(math.Asin(sε * sλ)) 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()) }
// ESmart computes the "equation of time" for the given JDE. // // Result is equation of time as an hour angle in radians. // // Result is less accurate that E() but the function has the advantage // of not requiring the V87Planet object. func ESmart(jde float64) float64 { ε := nutation.MeanObliquity(jde) t := math.Tan(ε * .5) y := t * t T := base.J2000Century(jde) L0 := l0(T * .1) e := solar.Eccentricity(T) M := solar.MeanAnomaly(T) s2L0, c2L0 := math.Sincos(2 * L0) sM := math.Sin(M) // (28.3) p. 185 return y*s2L0 - 2*e*sM + 4*e*y*sM*c2L0 - y*y*s2L0*c2L0 - 1.25*e*e*math.Sin(2*M) }
func ExampleNutation() { // Example 22.a, p. 148. jd := julian.CalendarGregorianToJD(1987, 4, 10) Δψ, Δε := nutation.Nutation(jd) ε0 := nutation.MeanObliquity(jd) ε := ε0 + Δε fmt.Printf("%+.3d\n", sexa.FmtAngle(Δψ)) fmt.Printf("%+.3d\n", sexa.FmtAngle(Δε)) fmt.Printf("%.3d\n", sexa.FmtAngle(ε0)) fmt.Printf("%.3d\n", sexa.FmtAngle(ε)) // Output: // -3″.788 // +9″.443 // 23°26′27″.407 // 23°26′36″.850 }
// 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 }
// 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(α, δ, jd float64) (Δα2, Δδ2 float64) { ε := nutation.MeanObliquity(jd) T := base.J2000Century(jd) s, _ := solar.True(T) e := solar.Eccentricity(T) π := perihelion(T) sα, cα := math.Sincos(α) sδ, cδ := math.Sincos(δ) ss, cs := math.Sincos(s) sπ, cπ := math.Sincos(π) cε := math.Cos(ε) tε := math.Tan(ε) q1 := cα * cε // (23.3) p. 152 Δα2 = κ * (e*(q1*cπ+sα*sπ) - (q1*cs + sα*ss)) / cδ q2 := cε * (tε*cδ - sα*sδ) q3 := cα * sδ Δδ2 = κ * (e*(cπ*q2+sπ*q3) - (cs*q2 + ss*q3)) return }
// 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 }
// Test with proper motion of Regulus, with equatorial motions given // in Example 21.a, p. 132, and ecliptic motions given in table 21.A, // p. 138. func TestEqProperMotionToEcl(t *testing.T) { ε := coord.NewObliquity(nutation.MeanObliquity(base.J2000)) mλ, mβ := eqProperMotionToEcl( // eq motions from p. 132. unit.NewHourAngle('-', 0, 0, 0.0169), unit.NewAngle(' ', 0, 0, 0.006), 2000.0, // eq coordinates from p. 132. new(coord.Ecliptic).EqToEcl(&coord.Equatorial{ RA: unit.NewRA(10, 8, 22.3), Dec: unit.NewAngle(' ', 11, 58, 2), }, ε)) d := math.Abs((mλ - unit.AngleFromSec(-.2348)).Rad() / mλ.Rad()) if d*169 > 1 { // 169 = significant digits of given lon t.Fatal("mλ") } d = math.Abs((mβ - unit.AngleFromSec(-.0813)).Rad() / mβ.Rad()) if d*6 > 1 { // 6 = significant digit of given lat t.Fatal("mβ") } }
// Test with proper motion of Regulus, with equatorial motions given // in Example 21.a, p. 132, and ecliptic motions given in table 21.A, // p. 138. func TestEqProperMotionToEcl(t *testing.T) { ε := coord.NewObliquity(nutation.MeanObliquity(base.J2000)) mλ, mβ := eqProperMotionToEcl( // eq motions from p. 132. sexa.NewHourAngle(true, 0, 0, 0.0169).Rad(), sexa.NewAngle(false, 0, 0, 0.006).Rad(), 2000.0, // eq coordinates from p. 132. new(coord.Ecliptic).EqToEcl(&coord.Equatorial{ RA: sexa.NewRA(10, 8, 22.3).Rad(), Dec: sexa.NewAngle(false, 11, 58, 2).Rad(), }, ε)) d := math.Abs((mλ - sexa.NewAngle(true, 0, 0, .2348).Rad()) / mλ) if d*169 > 1 { // 169 = significant digits of given lon t.Fatal("mλ") } d = math.Abs((mβ - sexa.NewAngle(true, 0, 0, 0.0813).Rad()) / mβ) if d*6 > 1 { // 6 = significant digit of given lat t.Fatal("mβ") } }
// Ephemeris returns the apparent orientation of the sun at the given jd. // // Results: // P: Position angle of the solar north pole. // B0: Heliographic latitude of the center of the solar disk. // L0: Heliographic longitude of the center of the solar disk. // // All results in radians. func Ephemeris(jd float64, e *pp.V87Planet) (P, B0, L0 float64) { θ := (jd - 2398220) * 2 * math.Pi / 25.38 I := 7.25 * math.Pi / 180 K := 73.6667*math.Pi/180 + 1.3958333*math.Pi/180*(jd-2396758)/base.JulianCentury L, _, R := solar.TrueVSOP87(e, jd) Δψ, Δε := nutation.Nutation(jd) ε0 := nutation.MeanObliquity(jd) ε := ε0 + Δε λ := L - 20.4898/3600*math.Pi/180/R λp := λ + Δψ sλK, cλK := math.Sincos(λ - K) sI, cI := math.Sincos(I) tx := -math.Cos(λp) * math.Tan(ε) ty := -cλK * math.Tan(I) P = math.Atan(tx) + math.Atan(ty) B0 = math.Asin(sλK * sI) η := math.Atan2(-sλK*cI, -cλK) L0 = base.PMod(η-θ, 2*math.Pi) return }
// Ephemeris returns the apparent orientation of the sun at the given jd. // // Results: // P: Position angle of the solar north pole. // B0: Heliographic latitude of the center of the solar disk. // L0: Heliographic longitude of the center of the solar disk. func Ephemeris(jd float64, e *pp.V87Planet) (P, B0, L0 unit.Angle) { θ := unit.Angle((jd - 2398220) * 2 * math.Pi / 25.38) I := unit.AngleFromDeg(7.25) K := unit.AngleFromDeg(73.6667) + unit.AngleFromDeg(1.3958333).Mul((jd-2396758)/base.JulianCentury) L, _, R := solar.TrueVSOP87(e, jd) Δψ, Δε := nutation.Nutation(jd) ε0 := nutation.MeanObliquity(jd) ε := ε0 + Δε λ := L - unit.AngleFromSec(20.4898).Div(R) λp := λ + Δψ sλK, cλK := (λ - K).Sincos() sI, cI := I.Sincos() tx := -(λp.Cos() * ε.Tan()) ty := -(cλK * I.Tan()) P = unit.Angle(math.Atan(tx) + math.Atan(ty)) B0 = unit.Angle(math.Asin(sλK * sI)) η := unit.Angle(math.Atan2(-sλK*cI, -cλK)) L0 = (η - θ).Mod1() return }
func newMoon(jde float64) *moon { m := &moon{jde: jde} // Δψ, F, Ω, p. 372. var Δε float64 m.Δψ, Δε = nutation.Nutation(jde) T := base.J2000Century(jde) F := base.Horner(T, 93.272095*p, 483202.0175233*p, -.0036539*p, -p/3526000, p/863310000) m.F = F m.Ω = base.Horner(T, 125.0445479*p, -1934.1362891*p, .0020754*p, p/467441, -p/60616000) // true ecliptic m.sε, m.cε = math.Sincos(nutation.MeanObliquity(jde) + Δε) // ρ, σ, τ, p. 372,373 D := base.Horner(T, 297.8501921*p, 445267.1114034*p, -.0018819*p, p/545868, -p/113065000) M := base.Horner(T, 357.5291092*p, 35999.0502909*p, -.0001535*p, p/24490000) Mʹ := base.Horner(T, 134.9633964*p, 477198.8675055*p, .0087414*p, p/69699, -p/14712000) E := base.Horner(T, 1, -.002516, -.0000074) K1 := 119.75*p + 131.849*p*T K2 := 72.56*p + 20.186*p*T m.ρ = -.02752*p*math.Cos(Mʹ) + -.02245*p*math.Sin(F) + .00684*p*math.Cos(Mʹ-2*F) + -.00293*p*math.Cos(2*F) + -.00085*p*math.Cos(2*(F-D)) + -.00054*p*math.Cos(Mʹ-2*D) + -.0002*p*math.Sin(Mʹ+F) + -.0002*p*math.Cos(Mʹ+2*F) + -.0002*p*math.Cos(Mʹ-F) + .00014*p*math.Cos(Mʹ+2*(F-D)) m.σ = -.02816*p*math.Sin(Mʹ) + .02244*p*math.Cos(F) + -.00682*p*math.Sin(Mʹ-2*F) + -.00279*p*math.Sin(2*F) + -.00083*p*math.Sin(2*(F-D)) + .00069*p*math.Sin(Mʹ-2*D) + .0004*p*math.Cos(Mʹ+F) + -.00025*p*math.Sin(2*Mʹ) + -.00023*p*math.Sin(Mʹ+2*F) + .0002*p*math.Cos(Mʹ-F) + .00019*p*math.Sin(Mʹ-F) + .00013*p*math.Sin(Mʹ+2*(F-D)) + -.0001*p*math.Cos(Mʹ-3*F) m.τ = .0252*p*math.Sin(M)*E + .00473*p*math.Sin(2*(Mʹ-F)) + -.00467*p*math.Sin(Mʹ) + .00396*p*math.Sin(K1) + .00276*p*math.Sin(2*(Mʹ-D)) + .00196*p*math.Sin(m.Ω) + -.00183*p*math.Cos(Mʹ-F) + .00115*p*math.Sin(Mʹ-2*D) + -.00096*p*math.Sin(Mʹ-D) + .00046*p*math.Sin(2*(F-D)) + -.00039*p*math.Sin(Mʹ-F) + -.00032*p*math.Sin(Mʹ-M-D) + .00027*p*math.Sin(2*(Mʹ-D)-M) + .00023*p*math.Sin(K2) + -.00014*p*math.Sin(2*D) + .00014*p*math.Cos(2*(Mʹ-F)) + -.00012*p*math.Sin(Mʹ-2*F) + -.00012*p*math.Sin(2*Mʹ) + .00011*p*math.Sin(2*(Mʹ-M-D)) return m }
// 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 }
// Physical computes quantities for physical observations of Jupiter. // // Results: // DS Planetocentric declination of the Sun. // DE Planetocentric declination of the Earth. // ω1 Longitude of the System I central meridian of the illuminated disk, // as seen from Earth. // ω2 Longitude of the System II central meridian of the illuminated disk, // as seen from Earth. // P Geocentric position angle of Jupiter's northern rotation pole. func Physical(jde float64, earth, jupiter *pp.V87Planet) (DS, DE, ω1, ω2, P unit.Angle) { // Step 1. d := jde - 2433282.5 T1 := d / base.JulianCentury const p = math.Pi / 180 α0 := 268*p + .1061*p*T1 δ0 := 64.5*p - .0164*p*T1 // Step 2. W1 := 17.71*p + 877.90003539*p*d W2 := 16.838*p + 870.27003539*p*d // Step 3. l0, b0, R := earth.Position(jde) l0, b0 = pp.ToFK5(l0, b0, jde) // Steps 4-7. sl0, cl0 := l0.Sincos() sb0 := b0.Sin() Δ := 4. // surely better than 0. var l, b unit.Angle var r, x, y, z float64 f := func() { τ := base.LightTime(Δ) l, b, r = jupiter.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) } f() f() // Step 8. ε0 := nutation.MeanObliquity(jde) // Step 9. sε0, cε0 := ε0.Sincos() sl, cl := l.Sincos() sb, cb := b.Sincos() αs := math.Atan2(cε0*sl-sε0*sb/cb, cl) δs := math.Asin(cε0*sb + sε0*cb*sl) // Step 10. sδs, cδs := math.Sincos(δs) sδ0, cδ0 := math.Sincos(δ0) DS = unit.Angle(math.Asin(-sδ0*sδs - cδ0*cδs*math.Cos(α0-αs))) // 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α := math.Sincos(α0 - α) ζ := math.Atan2(sδ0*cδ*cα0α-sδ*cδ0, cδ*sα0α) // Step 12. DE = unit.Angle(math.Asin(-sδ0*sδ - cδ0*cδ*math.Cos(α0-α))) // Step 13. ω1 = unit.Angle(W1 - ζ - 5.07033*p*Δ) ω2 = unit.Angle(W2 - ζ - 5.02626*p*Δ) // Step 14. C := unit.Angle((2*r*Δ + R*R - r*r - Δ*Δ) / (4 * r * Δ)) if (l - l0).Sin() < 0 { C = -C } ω1 = (ω1 + C).Mod1() ω2 = (ω2 + C).Mod1() // Step 15. Δψ, Δε := nutation.Nutation(jde) ε := ε0 + Δε // Step 16. sε, cε := ε.Sincos() sα, cα := math.Sincos(α) α += .005693 * p * (cα*cl0*cε + sα*sl0) / cδ δ += .005693 * p * (cl0*cε*(sε/cε*cδ-sα*sδ) + cα*sδ*sl0) // Step 17. tδ := sδ / cδ Δα := (cε+sε*sα*tδ)*Δψ.Rad() - cα*tδ*Δε.Rad() Δδ := sε*cα*Δψ.Rad() + sα*Δε.Rad() αʹ := α + Δα δʹ := δ + Δδ sα0, cα0 := math.Sincos(α0) tδ0 := sδ0 / cδ0 Δα0 := (cε+sε*sα0*tδ0)*Δψ.Rad() - cα0*tδ0*Δε.Rad() Δδ0 := sε*cα0*Δψ.Rad() + sα0*Δε.Rad() α0ʹ := α0 + Δα0 δ0ʹ := δ0 + Δδ0 // Step 18. sδʹ, cδʹ := math.Sincos(δʹ) sδ0ʹ, cδ0ʹ := math.Sincos(δ0ʹ) sα0ʹαʹ, cα0ʹαʹ := math.Sincos(α0ʹ - αʹ) // (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 } return }
func newMoon(jde float64) *moon { m := &moon{jde: jde} // Δψ, F, Ω, p. 372. var Δε unit.Angle m.Δψ, Δε = nutation.Nutation(jde) T := base.J2000Century(jde) m.F = unit.AngleFromDeg(base.Horner(T, 93.272095, 483202.0175233, -.0036539, -1/3526000, 1/863310000)) F := m.F.Rad() m.Ω = unit.AngleFromDeg(base.Horner(T, 125.0445479, -1934.1362891, .0020754, 1/467441, -1/60616000)) // true ecliptic m.sε, m.cε = math.Sincos((nutation.MeanObliquity(jde) + Δε).Rad()) // ρ, σ, τ, p. 372,373 D := unit.AngleFromDeg(base.Horner(T, 297.8501921, 445267.1114034, -.0018819, 1/545868, -1/113065000)).Rad() M := unit.AngleFromDeg(base.Horner(T, 357.5291092, 35999.0502909, -.0001535, 1/24490000)).Rad() Mʹ := unit.AngleFromDeg(base.Horner(T, 134.9633964, 477198.8675055, .0087414, 1/69699, -1/14712000)).Rad() E := base.Horner(T, 1, -.002516, -.0000074) K1 := unit.AngleFromDeg(119.75 + 131.849*T).Rad() K2 := unit.AngleFromDeg(72.56 + 20.186*T).Rad() m.ρ = unit.AngleFromDeg(-.02752*math.Cos(Mʹ) + -.02245*math.Sin(F) + .00684*math.Cos(Mʹ-2*F) + -.00293*math.Cos(2*F) + -.00085*math.Cos(2*(F-D)) + -.00054*math.Cos(Mʹ-2*D) + -.0002*math.Sin(Mʹ+F) + -.0002*math.Cos(Mʹ+2*F) + -.0002*math.Cos(Mʹ-F) + .00014*math.Cos(Mʹ+2*(F-D))) m.σ = unit.AngleFromDeg(-.02816*math.Sin(Mʹ) + .02244*math.Cos(F) + -.00682*math.Sin(Mʹ-2*F) + -.00279*math.Sin(2*F) + -.00083*math.Sin(2*(F-D)) + .00069*math.Sin(Mʹ-2*D) + .0004*math.Cos(Mʹ+F) + -.00025*math.Sin(2*Mʹ) + -.00023*math.Sin(Mʹ+2*F) + .0002*math.Cos(Mʹ-F) + .00019*math.Sin(Mʹ-F) + .00013*math.Sin(Mʹ+2*(F-D)) + -.0001*math.Cos(Mʹ-3*F)) m.τ = unit.AngleFromDeg(.0252*math.Sin(M)*E + .00473*math.Sin(2*(Mʹ-F)) + -.00467*math.Sin(Mʹ) + .00396*math.Sin(K1) + .00276*math.Sin(2*(Mʹ-D)) + .00196*math.Sin(m.Ω.Rad()) + -.00183*math.Cos(Mʹ-F) + .00115*math.Sin(Mʹ-2*D) + -.00096*math.Sin(Mʹ-D) + .00046*math.Sin(2*(F-D)) + -.00039*math.Sin(Mʹ-F) + -.00032*math.Sin(Mʹ-M-D) + .00027*math.Sin(2*(Mʹ-D)-M) + .00023*math.Sin(K2) + -.00014*math.Sin(2*D) + .00014*math.Cos(2*(Mʹ-F)) + -.00012*math.Sin(Mʹ-2*F) + -.00012*math.Sin(2*Mʹ) + .00011*math.Sin(2*(Mʹ-M-D))) return m }