func TestPrecessor_Precess(t *testing.T) { // Exercise, p. 136. eqFrom := &coord.Equatorial{ RA: base.NewRA(2, 31, 48.704).Rad(), Dec: base.NewAngle(false, 89, 15, 50.72).Rad(), } mα := base.NewHourAngle(false, 0, 0, .19877) mδ := base.NewAngle(false, 0, 0, -.0152) epochs := []float64{ base.JDEToJulianYear(base.B1900), 2050, 2100, } answer := []string{ "α = 1ʰ22ᵐ33ˢ.90 δ = +88°46′26″.18", "α = 3ʰ48ᵐ16ˢ.43 δ = +89°27′15″.38", "α = 5ʰ53ᵐ29ˢ.17 δ = +89°32′22″.18", } eqTo := &coord.Equatorial{} for i, epochTo := range epochs { precess.Position(eqFrom, eqTo, 2000, epochTo, mα, mδ) if answer[i] != fmt.Sprintf("α = %0.2d δ = %+0.2d", base.NewFmtRA(eqTo.RA), base.NewFmtAngle(eqTo.Dec)) { t.Fatal(i) } } }
func ExampleProperMotion3D() { // Example 21.d, p. 141. eqFrom := &coord.Equatorial{ RA: base.NewRA(6, 45, 8.871).Rad(), Dec: base.NewAngle(true, 16, 42, 57.99).Rad(), } mra := base.NewHourAngle(false, 0, 0, -0.03847) mdec := base.NewAngle(false, 0, 0, -1.2053) r := 2.64 // given in correct unit mr := -7.6 / 977792 // magic conversion factor eqTo := &coord.Equatorial{} fmt.Printf("Δr = %.9f, Δα = %.10f, Δδ = %.10f\n", mr, mra, mdec) for _, epoch := range []float64{1000, 0, -1000, -2000, -10000} { precess.ProperMotion3D(eqFrom, eqTo, 2000, epoch, r, mr, mra, mdec) fmt.Printf("%8.1f %0.2d %-0.1d\n", epoch, base.NewFmtRA(eqTo.RA), base.NewFmtAngle(eqTo.Dec)) } // Output: // Δr = -0.000007773, Δα = -0.0000027976, Δδ = -0.0000058435 // 1000.0 6ʰ45ᵐ47ˢ.16 -16°22′56″.0 // 0.0 6ʰ46ᵐ25ˢ.09 -16°03′00″.8 // -1000.0 6ʰ47ᵐ02ˢ.67 -15°43′12″.3 // -2000.0 6ʰ47ᵐ39ˢ.91 -15°23′30″.6 // -10000.0 6ʰ52ᵐ25ˢ.72 -12°50′06″.7 }
// Exercise, p. 136. func TestPosition(t *testing.T) { eqFrom := &coord.Equatorial{ base.NewRA(2, 31, 48.704).Rad(), base.NewAngle(false, 89, 15, 50.72).Rad(), } eqTo := &coord.Equatorial{} mα := base.NewHourAngle(false, 0, 0, 0.19877) mδ := base.NewAngle(true, 0, 0, 0.0152) for _, tc := range []struct { α, δ string jde float64 }{ {"1 22 33.90", "88 46 26.18", base.BesselianYearToJDE(1900)}, {"3 48 16.43", "89 27 15.38", base.JulianYearToJDE(2050)}, {"5 53 29.17", "89 32 22.18", base.JulianYearToJDE(2100)}, } { epochTo := base.JDEToJulianYear(tc.jde) precess.Position(eqFrom, eqTo, 2000.0, epochTo, mα, mδ) αStr := fmt.Sprintf("%.2x", base.NewFmtRA(eqTo.RA)) δStr := fmt.Sprintf("%.2x", base.NewFmtAngle(eqTo.Dec)) if αStr != tc.α { t.Fatal("got:", αStr, "want:", tc.α) } if δStr != tc.δ { t.Fatal(δStr) } } }
func ExampleApproxTimes() { // Example 15.a, p. 103. jd := julian.CalendarGregorianToJD(1988, 3, 20) p := globe.Coord{ Lon: base.NewAngle(false, 71, 5, 0).Rad(), Lat: base.NewAngle(false, 42, 20, 0).Rad(), } // Meeus gives us the value of 11h 50m 58.1s but we have a package // function for this: Th0 := sidereal.Apparent0UT(jd) α := base.NewRA(2, 46, 55.51).Rad() δ := base.NewAngle(false, 18, 26, 27.3).Rad() h0 := rise.Stdh0Stellar rise, transit, set, err := rise.ApproxTimes(p, h0, Th0, α, δ) if err != nil { fmt.Println(err) return } // Units for approximate values given near top of p. 104 are circles. fmt.Printf("rising: %+.5f\n", rise/86400) fmt.Printf("transit: %+.5f\n", transit/86400) fmt.Printf("seting: %+.5f\n", set/86400) // Output: // rising: +0.51816 // transit: +0.81965 // seting: +0.12113 }
func ExampleNewAngle() { // Example negative values, p. 9. a := base.NewAngle(true, 13, 47, 22) fmt.Println(base.NewFmtAngle(a.Rad())) a = base.NewAngle(true, 0, 32, 41) // use # flag to force output of all three components fmt.Printf("%#s\n", base.NewFmtAngle(a.Rad())) // Output: // -13°47′22″ // -0°32′41″ }
// First exercise, p. 110. func TestSep(t *testing.T) { r1 := base.NewRA(4, 35, 55.2).Rad() d1 := base.NewAngle(false, 16, 30, 33).Rad() r2 := base.NewRA(16, 29, 24).Rad() d2 := base.NewAngle(true, 26, 25, 55).Rad() d := angle.Sep(r1, d1, r2, d2) answer := base.NewAngle(false, 169, 58, 0).Rad() if math.Abs(d-answer) > 1e-4 { t.Fatal(base.NewFmtAngle(d)) } }
func ExampleSep() { // Example 17.a, p. 110. r1 := base.NewRA(14, 15, 39.7).Rad() d1 := base.NewAngle(false, 19, 10, 57).Rad() r2 := base.NewRA(13, 25, 11.6).Rad() d2 := base.NewAngle(true, 11, 9, 41).Rad() d := angle.Sep(r1, d1, r2, d2) fmt.Println(base.NewFmtAngle(d)) // Output: // 32°47′35″ }
func TestSepHav(t *testing.T) { // Example 17.a, p. 110. r1 := base.NewRA(14, 15, 39.7).Rad() d1 := base.NewAngle(false, 19, 10, 57).Rad() r2 := base.NewRA(13, 25, 11.6).Rad() d2 := base.NewAngle(true, 11, 9, 41).Rad() d := angle.SepHav(r1, d1, r2, d2) s := fmt.Sprint(base.NewFmtAngle(d)) if s != "32°47′35″" { t.Fatal(s) } }
func ExampleAngleError() { // Example p. 125. rδ := base.NewRA(5, 32, 0.40).Rad() dδ := base.NewAngle(true, 0, 17, 56.9).Rad() rε := base.NewRA(5, 36, 12.81).Rad() dε := base.NewAngle(true, 1, 12, 7.0).Rad() rζ := base.NewRA(5, 40, 45.52).Rad() dζ := base.NewAngle(true, 1, 56, 33.3).Rad() n, ω := line.AngleError(rδ, dδ, rε, dε, rζ, dζ) fmt.Printf("%.62s\n", base.NewFmtAngle(n)) fmt.Println(base.NewFmtAngle(ω)) // Output: // 7°31′ // -5′24″ }
// p. 83 func TestLatDiff(t *testing.T) { φ0 := base.NewAngle(false, 45, 5, 46.36).Rad() diff := base.NewFmtAngle(globe.GeocentricLatitudeDifference(φ0)) if f := fmt.Sprintf("%.2d", diff); f != "11′32″.73" { t.Fatal(f) } }
func ExamplePositionRonVondrak() { // Example 23.b, p. 156 jd := julian.CalendarGregorianToJD(2028, 11, 13.19) eq := &coord.Equatorial{ RA: base.NewRA(2, 44, 11.986).Rad(), Dec: base.NewAngle(false, 49, 13, 42.48).Rad(), } apparent.PositionRonVondrak(eq, eq, base.JDEToJulianYear(jd), base.NewHourAngle(false, 0, 0, 0.03425), base.NewAngle(true, 0, 0, 0.0895)) fmt.Printf("α = %0.3d\n", base.NewFmtRA(eq.RA)) fmt.Printf("δ = %0.2d\n", base.NewFmtAngle(eq.Dec)) // Output: // α = 2ʰ46ᵐ14ˢ.392 // δ = 49°21′07″.45 }
func ExampleAngle() { // Example p. 123. rδ := base.NewRA(5, 32, 0.40).Rad() dδ := base.NewAngle(true, 0, 17, 56.9).Rad() rε := base.NewRA(5, 36, 12.81).Rad() dε := base.NewAngle(true, 1, 12, 7.0).Rad() rζ := base.NewRA(5, 40, 45.52).Rad() dζ := base.NewAngle(true, 1, 56, 33.3).Rad() n := line.Angle(rδ, dδ, rε, dε, rζ, dζ) fmt.Printf("%.4f degrees\n", n*180/math.Pi) fmt.Printf("%.62s\n", base.NewFmtAngle(n)) // Output: // 172.4830 degrees // 172°29′ }
func ExampleApproxPosition() { // Example 21.a, p. 132. eq := &coord.Equatorial{ base.NewRA(10, 8, 22.3).Rad(), base.NewAngle(false, 11, 58, 2).Rad(), } epochFrom := 2000.0 epochTo := 1978.0 mα := base.NewHourAngle(true, 0, 0, 0.0169) mδ := base.NewAngle(false, 0, 0, 0.006) precess.ApproxPosition(eq, eq, epochFrom, epochTo, mα, mδ) fmt.Printf("%0.1d\n", base.NewFmtRA(eq.RA)) fmt.Printf("%+0d\n", base.NewFmtAngle(eq.Dec)) // Output: // 10ʰ07ᵐ12ˢ.1 // +12°04′32″ }
// 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. func ApproxAnnualPrecession(eq *coord.Equatorial, epochFrom, epochTo float64) (Δα base.HourAngle, Δδ base.Angle) { m, na, nd := mn(epochFrom, epochTo) sa, ca := math.Sincos(eq.RA) // (21.1) p. 132 Δαs := m + na*sa*math.Tan(eq.Dec) // seconds of RA Δδs := nd * ca // seconds of Dec return base.NewHourAngle(false, 0, 0, Δαs), base.NewAngle(false, 0, 0, Δδs) }
// MeanObliquity returns mean obliquity (ε₀) following the IAU 1980 // polynomial. // // Accuracy is 1″ over the range 1000 to 3000 years and 10″ over the range // 0 to 4000 years. // // Result unit is radians. func MeanObliquity(jde float64) float64 { // (22.2) p. 147 return base.Horner(base.J2000Century(jde), base.NewAngle(false, 23, 26, 21.448).Rad(), -46.815/3600*(math.Pi/180), -0.00059/3600*(math.Pi/180), 0.001813/3600*(math.Pi/180)) }
func ExamplePosition() { // Example 21.b, p. 135. eq := &coord.Equatorial{ base.NewRA(2, 44, 11.986).Rad(), base.NewAngle(false, 49, 13, 42.48).Rad(), } epochFrom := 2000.0 jdTo := julian.CalendarGregorianToJD(2028, 11, 13.19) epochTo := base.JDEToJulianYear(jdTo) precess.Position(eq, eq, epochFrom, epochTo, base.NewHourAngle(false, 0, 0, 0.03425), base.NewAngle(true, 0, 0, 0.0895)) fmt.Printf("%0.3d\n", base.NewFmtRA(eq.RA)) fmt.Printf("%+0.2d\n", base.NewFmtAngle(eq.Dec)) // Output: // 2ʰ46ᵐ11ˢ.331 // +49°20′54″.54 }
func ExampleError() { // Example p. 124. rδ := base.NewRA(5, 32, 0.40).Rad() dδ := base.NewAngle(true, 0, 17, 56.9).Rad() rε := base.NewRA(5, 36, 12.81).Rad() dε := base.NewAngle(true, 1, 12, 7.0).Rad() rζ := base.NewRA(5, 40, 45.52).Rad() dζ := base.NewAngle(true, 1, 56, 33.3).Rad() ω := line.Error(rζ, dζ, rδ, dδ, rε, dε) fmt.Println(base.DecSymAdd(fmt.Sprintf("%.6f", ω*180/math.Pi), '°')) fmt.Printf("%.0f″\n", ω*3600*180/math.Pi) fmt.Println(base.NewFmtAngle(ω)) // Output: // 0°.089876 // 324″ // 5′24″ }
func ExampleSmallest_b() { // Exercise, p. 128. r1 := base.NewRA(9, 5, 41.44).Rad() r2 := base.NewRA(9, 9, 29).Rad() r3 := base.NewRA(8, 59, 47.14).Rad() d1 := base.NewAngle(false, 18, 30, 30).Rad() d2 := base.NewAngle(false, 17, 43, 56.7).Rad() d3 := base.NewAngle(false, 17, 49, 36.8).Rad() d, t := circle.Smallest(r1, d1, r2, d2, r3, d3) fmt.Printf("Δ = %.62s\n", base.NewFmtAngle(d)) if t { fmt.Println("type I") } else { fmt.Println("type II") } // Output: // Δ = 2°19′ // type I }
func ExampleNutation() { // Example 23.a, p. 152 α := base.NewRA(2, 46, 11.331).Rad() δ := base.NewAngle(false, 49, 20, 54.54).Rad() jd := julian.CalendarGregorianToJD(2028, 11, 13.19) Δα1, Δδ1 := apparent.Nutation(α, δ, jd) fmt.Printf("%.3s %.3s\n", base.NewFmtAngle(Δα1), base.NewFmtAngle(Δδ1)) // Output: // 15.843″ 6.217″ }
func ExampleAberration() { // Example 23.a, p. 152 α := base.NewRA(2, 46, 11.331).Rad() δ := base.NewAngle(false, 49, 20, 54.54).Rad() jd := julian.CalendarGregorianToJD(2028, 11, 13.19) Δα2, Δδ2 := apparent.Aberration(α, δ, jd) fmt.Printf("%.3s %.3s\n", base.NewFmtAngle(Δα2), base.NewFmtAngle(Δδ2)) // Output: // 30.045″ 6.697″ }
func ExampleEllipsoid_Parallax() { // Example 11.a, p 82. // phi = geographic latitude of Palomar φ := base.NewAngle(false, 33, 21, 22).Rad() s, c := globe.Earth76.ParallaxConstants(φ, 1706) fmt.Printf("ρ sin φ′ = %+.6f\n", s) fmt.Printf("ρ cos φ′ = %+.6f\n", c) // Output: // ρ sin φ′ = +0.546861 // ρ cos φ′ = +0.836339 }
// 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. base.NewHourAngle(true, 0, 0, 0.0169).Rad(), base.NewAngle(false, 0, 0, 0.006).Rad(), 2000.0, // eq coordinates from p. 132. new(coord.Ecliptic).EqToEcl(&coord.Equatorial{ RA: base.NewRA(10, 8, 22.3).Rad(), Dec: base.NewAngle(false, 11, 58, 2).Rad(), }, ε)) d := math.Abs((mλ - base.NewAngle(true, 0, 0, .2348).Rad()) / mλ) if d*169 > 1 { // 169 = significant digits of given lon t.Fatal("mλ") } d = math.Abs((mβ - base.NewAngle(true, 0, 0, 0.0813).Rad()) / mβ) if d*6 > 1 { // 6 = significant digit of given lat t.Fatal("mβ") } }
func ExampleHorizontal_EqToHz() { // Example 13.b, p. 95. eq := &coord.Equatorial{ RA: base.NewRA(23, 9, 16.641).Rad(), Dec: base.NewAngle(true, 6, 43, 11.61).Rad(), } g := &globe.Coord{ Lat: base.NewAngle(false, 38, 55, 17).Rad(), Lon: base.NewAngle(false, 77, 3, 56).Rad(), } jd := julian.TimeToJD(time.Date(1987, 4, 10, 19, 21, 0, 0, time.UTC)) st := sidereal.Apparent(jd) hz := new(coord.Horizontal).EqToHz(eq, g, st) AStr := base.DecSymAdd(fmt.Sprintf("%+.3f", hz.Az*180/math.Pi), '°') hStr := base.DecSymAdd(fmt.Sprintf("%+.3f", hz.Alt*180/math.Pi), '°') fmt.Println("A =", AStr) fmt.Println("h =", hStr) // Output: // A = +68°.034 // h = +15°.125 }
func TestEqToGal(t *testing.T) { g := new(coord.Galactic).EqToGal(&coord.Equatorial{ RA: base.NewRA(17, 48, 59.74).Rad(), Dec: base.NewAngle(true, 14, 43, 8.2).Rad(), }) if s := fmt.Sprintf("%.4f", g.Lon*180/math.Pi); s != "12.9593" { t.Fatal("lon:", s) } if s := fmt.Sprintf("%+.4f", g.Lat*180/math.Pi); s != "+6.0463" { t.Fatal("lat:", s) } }
func ExampleSmallest_a() { // Example 20.a, p. 128. r1 := base.NewRA(12, 41, 8.64).Rad() r2 := base.NewRA(12, 52, 5.21).Rad() r3 := base.NewRA(12, 39, 28.11).Rad() d1 := base.NewAngle(true, 5, 37, 54.2).Rad() d2 := base.NewAngle(true, 4, 22, 26.2).Rad() d3 := base.NewAngle(true, 1, 50, 3.7).Rad() d, t := circle.Smallest(r1, d1, r2, d2, r3, d3) fmt.Printf("Δ = %s = %.62s\n", base.DecSymAdd(fmt.Sprintf("%.5f", d*180/math.Pi), '°'), base.NewFmtAngle(d)) if t { fmt.Println("type I") } else { fmt.Println("type II") } // Output: // Δ = 4°.26363 = 4°16′ // type II }
func ExampleAberrationRonVondrak() { // Example 23.b, p. 156 α := base.NewRA(2, 44, 12.9747).Rad() δ := base.NewAngle(false, 49, 13, 39.896).Rad() jd := julian.CalendarGregorianToJD(2028, 11, 13.19) Δα, Δδ := apparent.AberrationRonVondrak(α, δ, jd) fmt.Printf("Δα = %+.9f radian\n", Δα) fmt.Printf("Δδ = %+.9f radian\n", Δδ) // Output: // Δα = +0.000145252 radian // Δδ = +0.000032723 radian }
func ExampleEllipsoid_Distance() { // Example 11.c p 85. c1 := globe.Coord{ base.NewAngle(false, 48, 50, 11).Rad(), // geographic latitude base.NewAngle(true, 2, 20, 14).Rad(), // geographic longitude } c2 := globe.Coord{ base.NewAngle(false, 38, 55, 17).Rad(), base.NewAngle(false, 77, 3, 56).Rad(), } fmt.Printf("%.2f km\n", globe.Earth76.Distance(c1, c2)) cos := globe.ApproxAngularDistance(c1, c2) fmt.Printf("cos d = %.6f\n", cos) d := math.Acos(cos) fmt.Println(" d =", base.DecSymAdd(fmt.Sprintf("%.5f", d*180/math.Pi), '°')) fmt.Printf(" s = %.0f km\n", globe.ApproxLinearDistance(d)) // Output: // 6181.63 km // cos d = 0.567146 // d = 55°.44855 // s = 6166 km }
func TestDiurnalPathAtHorizon(t *testing.T) { φ := 40 * math.Pi / 180 ε := 23.44 * math.Pi / 180 J := parallactic.DiurnalPathAtHorizon(0, φ) Jexp := math.Pi/2 - φ if math.Abs((J-Jexp)/Jexp) > 1e-15 { t.Fatal("0 dec:", base.NewFmtAngle(J)) } J = parallactic.DiurnalPathAtHorizon(ε, φ) Jexp = base.NewAngle(false, 45, 31, 0).Rad() if math.Abs((J-Jexp)/Jexp) > 1e-3 { t.Fatal("solstace:", base.NewFmtAngle(J)) } }
func TestTopocentricEcliptical(t *testing.T) { // exercise, p. 282 λʹ, βʹ, sʹ := parallax.TopocentricEcliptical(base.NewAngle(false, 181, 46, 22.5).Rad(), base.NewAngle(false, 2, 17, 26.2).Rad(), base.NewAngle(false, 0, 16, 15.5).Rad(), base.NewAngle(false, 50, 5, 7.8).Rad(), 0, base.NewAngle(false, 23, 28, 0.8).Rad(), base.NewAngle(false, 209, 46, 7.9).Rad(), base.NewAngle(false, 0, 59, 27.7).Rad()) λʹa := base.NewAngle(false, 181, 48, 5).Rad() βʹa := base.NewAngle(false, 1, 29, 7.1).Rad() sʹa := base.NewAngle(false, 0, 16, 25.5).Rad() if math.Abs(λʹ-λʹa) > .1/60/60*math.Pi/180 { t.Fatal(λʹ, λʹa) } if math.Abs(βʹ-βʹa) > .1/60/60*math.Pi/180 { t.Fatal(βʹ, βʹa) } if math.Abs(sʹ-sʹa) > .1/60/60*math.Pi/180 { t.Fatal(sʹ, sʹa) } }
func ExampleTimes() { // Example 15.a, p. 103. jd := julian.CalendarGregorianToJD(1988, 3, 20) p := globe.Coord{ Lon: base.NewAngle(false, 71, 5, 0).Rad(), Lat: base.NewAngle(false, 42, 20, 0).Rad(), } // Meeus gives us the value of 11h 50m 58.1s but we have a package // function for this: Th0 := sidereal.Apparent0UT(jd) α3 := []float64{ base.NewRA(2, 42, 43.25).Rad(), base.NewRA(2, 46, 55.51).Rad(), base.NewRA(2, 51, 07.69).Rad(), } δ3 := []float64{ base.NewAngle(false, 18, 02, 51.4).Rad(), base.NewAngle(false, 18, 26, 27.3).Rad(), base.NewAngle(false, 18, 49, 38.7).Rad(), } h0 := rise.Stdh0Stellar // Similarly as with Th0, Meeus gives us the value of 56 for ΔT but // let's use our package function. ΔT := deltat.Interp10A(jd) rise, transit, set, err := rise.Times(p, ΔT, h0, Th0, α3, δ3) if err != nil { fmt.Println(err) return } fmt.Println("rising: ", base.NewFmtTime(rise)) fmt.Println("transit:", base.NewFmtTime(transit)) fmt.Println("seting: ", base.NewFmtTime(set)) // Output: // rising: 12ʰ26ᵐ9ˢ // transit: 19ʰ40ᵐ30ˢ // seting: 2ʰ54ᵐ26ˢ }