Beispiel #1
0
// Nutation returns nutation in longitude (Δψ) and nutation in obliquity (Δε)
// for a given JDE.
//
// JDE = UT + ΔT, see package deltat.
//
// Computation is by 1980 IAU theory, with terms < .0003″ neglected.
func Nutation(jde float64) (Δψ, Δε unit.Angle) {
	T := base.J2000Century(jde)
	D := base.Horner(T,
		297.85036, 445267.11148, -0.0019142, 1./189474) * math.Pi / 180
	M := base.Horner(T,
		357.52772, 35999.050340, -0.0001603, -1./300000) * math.Pi / 180
	N := base.Horner(T,
		134.96298, 477198.867398, 0.0086972, 1./5620) * math.Pi / 180
	F := base.Horner(T,
		93.27191, 483202.017538, -0.0036825, 1./327270) * math.Pi / 180
	Ω := base.Horner(T,
		125.04452, -1934.136261, 0.0020708, 1./450000) * math.Pi / 180
	// sum in reverse order to accumulate smaller terms first
	var Δψs, Δεs float64
	for i := len(table22A) - 1; i >= 0; i-- {
		row := table22A[i]
		arg := row.d*D + row.m*M + row.n*N + row.f*F + row.ω*Ω
		s, c := math.Sincos(arg)
		Δψs += s * (row.s0 + row.s1*T)
		Δεs += c * (row.c0 + row.c1*T)
	}
	Δψ = unit.AngleFromSec(Δψs * .0001)
	Δε = unit.AngleFromSec(Δεs * .0001)
	return
}
Beispiel #2
0
// TrueVSOP87 returns the true geometric position of the sun as ecliptic coordinates.
//
// Result computed by full VSOP87 theory.  Result is at equator and equinox
// of date in the FK5 frame.  It does not include nutation or aberration.
//
//	s: ecliptic longitude
//	β: ecliptic latitude
//	R: range in AU
func TrueVSOP87(e *pp.V87Planet, jde float64) (s, β unit.Angle, R float64) {
	l, b, r := e.Position(jde)
	s = l + math.Pi
	// FK5 correction.
	λp := base.Horner(base.J2000Century(jde),
		s.Rad(), -1.397*math.Pi/180, -.00031*math.Pi/180)
	sλp, cλp := math.Sincos(λp)
	Δβ := unit.AngleFromSec(.03916).Mul(cλp - sλp)
	// (25.9) p. 166
	s -= unit.AngleFromSec(.09033)
	return s.Mod1(), Δβ - b, r
}
Beispiel #3
0
// ApproxNutation returns a fast approximation of nutation in longitude (Δψ)
// and nutation in obliquity (Δε) for a given JDE.
//
// Accuracy is 0.5″ in Δψ, 0.1″ in Δε.
func ApproxNutation(jde float64) (Δψ, Δε unit.Angle) {
	T := (jde - base.J2000) / 36525
	Ω := (125.04452 - 1934.136261*T) * math.Pi / 180
	L := (280.4665 + 36000.7698*T) * math.Pi / 180
	N := (218.3165 + 481267.8813*T) * math.Pi / 180
	sΩ, cΩ := math.Sincos(Ω)
	s2L, c2L := math.Sincos(2 * L)
	s2N, c2N := math.Sincos(2 * N)
	s2Ω, c2Ω := math.Sincos(2 * Ω)
	Δψ = unit.AngleFromSec(-17.2*sΩ - 1.32*s2L - 0.23*s2N + 0.21*s2Ω)
	Δε = unit.AngleFromSec(9.2*cΩ + 0.57*c2L + 0.1*c2N - 0.09*c2Ω)
	return
}
Beispiel #4
0
// mn as separate function for testing purposes
func mn(epochFrom, epochTo float64) (m, nα unit.HourAngle, nδ unit.Angle) {
	T := (epochTo - epochFrom) * .01
	m = unit.HourAngleFromSec(3.07496 + 0.00186*T)
	nα = unit.HourAngleFromSec(1.33621 - 0.00057*T)
	nδ = unit.AngleFromSec(20.0431 - 0.0085*T)
	return
}
Beispiel #5
0
func ExampleProperMotion3D() {
	// Example 21.d, p. 141.
	eqFrom := &coord.Equatorial{
		RA:  unit.NewRA(6, 45, 8.871),
		Dec: unit.NewAngle('-', 16, 42, 57.99),
	}
	mra := unit.HourAngleFromSec(-0.03847)
	mdec := unit.AngleFromSec(-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,
			sexa.FmtRA(eqTo.RA), sexa.FmtAngle(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
}
Beispiel #6
0
// Exercise, p. 136.
func TestPosition(t *testing.T) {
	eqFrom := &coord.Equatorial{
		unit.NewRA(2, 31, 48.704),
		unit.NewAngle(' ', 89, 15, 50.72),
	}
	eqTo := &coord.Equatorial{}
	mα := unit.HourAngleFromSec(0.19877)
	mδ := unit.AngleFromSec(-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("%.2s", sexa.FmtRA(eqTo.RA))
		δStr := fmt.Sprintf("%.2s", sexa.FmtAngle(eqTo.Dec))
		if αStr != tc.α {
			t.Fatal("got:", αStr, "want:", tc.α)
		}
		if δStr != tc.δ {
			t.Fatal(δStr)
		}
	}
}
Beispiel #7
0
func TestPrecessor_Precess(t *testing.T) {
	// Exercise, p. 136.
	eqFrom := &coord.Equatorial{
		RA:  unit.NewRA(2, 31, 48.704),
		Dec: unit.NewAngle(' ', 89, 15, 50.72),
	}
	mα := unit.HourAngleFromSec(.19877)
	mδ := unit.AngleFromSec(-.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",
			sexa.FmtRA(eqTo.RA), sexa.FmtAngle(eqTo.Dec)) {
			t.Fatal(i)
		}
	}
}
Beispiel #8
0
// 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.
func MeanObliquity(jde float64) unit.Angle {
	// (22.2) p. 147
	return unit.AngleFromSec(base.Horner(base.J2000Century(jde),
		unit.FromSexaSec(' ', 23, 26, 21.448),
		-46.815,
		-0.00059,
		0.001813))
}
Beispiel #9
0
// "rectangular coordinate" solution, p. 113.
func TestMinSepRect(t *testing.T) {
	sep, err := angle.MinSepRect(jd1, jd3, r1, d1, r2, d2)
	if err != nil {
		t.Fatal(err)
	}
	answer := unit.AngleFromSec(224) // on p. 111
	if math.Abs((sep-answer).Rad()/sep.Rad()) > 1e-2 {
		t.Fatal(sep, answer)
	}

}
Beispiel #10
0
// 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β")
	}
}
Beispiel #11
0
// perigee parallax
func (l *la) pp() unit.Angle {
	return unit.AngleFromSec(
		3629.215 +
			63.224*math.Cos(2*l.D) +
			-6.990*math.Cos(4*l.D) +
			(2.834-0.0071*l.T)*math.Cos(2*l.D-l.M) +
			1.927*math.Cos(6*l.D) +
			-1.263*math.Cos(l.D) +
			-0.702*math.Cos(8*l.D) +
			(0.696-0.0017*l.T)*math.Cos(l.M) +
			-0.690*math.Cos(2*l.F) +
			(-0.629+0.0016*l.T)*math.Cos(4*l.D-l.M) +
			-0.392*math.Cos(2*(l.D-l.F)) +
			0.297*math.Cos(10*l.D) +
			0.260*math.Cos(6*l.D-l.M) +
			0.201*math.Cos(3*l.D) +
			-0.161*math.Cos(2*l.D+l.M) +
			0.157*math.Cos(l.D+l.M) +
			-0.138*math.Cos(12*l.D) +
			-0.127*math.Cos(8*l.D-l.M) +
			0.104*math.Cos(2*(l.D+l.F)) +
			0.104*math.Cos(2*(l.D-l.M)) +
			-0.079*math.Cos(5*l.D) +
			0.068*math.Cos(14*l.D) +
			0.067*math.Cos(10*l.D-l.M) +
			0.054*math.Cos(4*l.D+l.M) +
			-0.038*math.Cos(12*l.D-l.M) +
			-0.038*math.Cos(4*l.D-2*l.M) +
			0.037*math.Cos(7*l.D) +
			-0.037*math.Cos(4*l.D+2*l.F) +
			-0.035*math.Cos(16*l.D) +
			-0.030*math.Cos(3*l.D+l.M) +
			0.029*math.Cos(l.D-l.M) +
			-0.025*math.Cos(6*l.D+l.M) +
			0.023*math.Cos(2*l.M) +
			0.023*math.Cos(14*l.D-l.M) +
			-0.023*math.Cos(2*(l.D+l.M)) +
			0.022*math.Cos(6*l.D-2*l.M) +
			-0.021*math.Cos(2*l.D-2*l.F-l.M) +
			-0.020*math.Cos(9*l.D) +
			0.019*math.Cos(18*l.D) +
			0.017*math.Cos(6*l.D+2*l.F) +
			0.014*math.Cos(2*l.F-l.M) +
			-0.014*math.Cos(16*l.D-l.M) +
			0.013*math.Cos(4*l.D-2*l.F) +
			0.012*math.Cos(8*l.D+l.M) +
			0.011*math.Cos(11*l.D) +
			0.010*math.Cos(5*l.D+l.M) +
			-0.010*math.Cos(20*l.D))
}
Beispiel #12
0
// MeanObliquityLaskar returns mean obliquity (ε₀) following the Laskar
// 1986 polynomial.
//
// Accuracy over the range 1000 to 3000 years is .01″.
//
// Accuracy over the valid date range of -8000 to +12000 years is
// "a few seconds."
func MeanObliquityLaskar(jde float64) unit.Angle {
	// (22.3) p. 147
	return unit.AngleFromSec(base.Horner(base.J2000Century(jde)*.01,
		unit.FromSexaSec(' ', 23, 26, 21.448),
		-4680.93,
		-1.55,
		1999.25,
		-51.38,
		-249.67,
		-39.05,
		7.12,
		27.87,
		5.79,
		2.45))
}
Beispiel #13
0
func ExampleStellar() {
	// Exercise, p. 119.
	day1 := 7.
	day5 := 27.
	r2 := []unit.Angle{
		unit.NewRA(15, 3, 51.937).Angle(),
		unit.NewRA(15, 9, 57.327).Angle(),
		unit.NewRA(15, 15, 37.898).Angle(),
		unit.NewRA(15, 20, 50.632).Angle(),
		unit.NewRA(15, 25, 32.695).Angle(),
	}
	d2 := []unit.Angle{
		unit.NewAngle('-', 8, 57, 34.51),
		unit.NewAngle('-', 9, 9, 03.88),
		unit.NewAngle('-', 9, 17, 37.94),
		unit.NewAngle('-', 9, 23, 16.25),
		unit.NewAngle('-', 9, 26, 01.01),
	}
	jd := julian.CalendarGregorianToJD(1996, 2, 17)
	dt := jd - base.J2000
	dy := dt / base.JulianYear
	dc := dy / 100
	fmt.Printf("%.2f years\n", dy)
	fmt.Printf("%.4f century\n", dc)

	pmr := -.649 // sec/cen
	pmd := -1.91 // sec/cen
	r1 := unit.NewRA(15, 17, 0.421) + unit.RAFromSec(pmr*dc)
	d1 := unit.NewAngle('-', 9, 22, 58.54) + unit.AngleFromSec(pmd*dc)
	fmt.Printf("α′ = %.3d, δ′ = %.2d\n", sexa.FmtRA(r1), sexa.FmtAngle(d1))

	day, dd, err := conjunction.Stellar(day1, day5, r1.Angle(), d1, r2, d2)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(sexa.FmtAngle(dd))
	dInt, dFrac := math.Modf(day)
	fmt.Printf("1996 February %d at %s TD\n", int(dInt),
		sexa.FmtTime(unit.TimeFromDay(dFrac)))

	// Output:
	// -3.87 years
	// -0.0387 century
	// α′ = 15ʰ17ᵐ0ˢ.446, δ′ = -9°22′58″.47
	// 3′38″
	// 1996 February 18 at 6ʰ36ᵐ55ˢ TD
}
Beispiel #14
0
// 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)
}
Beispiel #15
0
func ExamplePositionRonVondrak() {
	// Example 23.b, p. 156
	jd := julian.CalendarGregorianToJD(2028, 11, 13.19)
	eq := &coord.Equatorial{
		RA:  unit.NewRA(2, 44, 11.986),
		Dec: unit.NewAngle(' ', 49, 13, 42.48),
	}
	apparent.PositionRonVondrak(eq, eq, base.JDEToJulianYear(jd),
		unit.HourAngleFromSec(.03425),
		unit.AngleFromSec(-.0895))
	fmt.Printf("α = %0.3d\n", sexa.FmtRA(eq.RA))
	fmt.Printf("δ = %0.2d\n", sexa.FmtAngle(eq.Dec))
	// Output:
	// α = 2ʰ46ᵐ14ˢ.392
	// δ = 49°21′07″.45
}
Beispiel #16
0
func ExampleApproxPosition() {
	// Example 21.a, p. 132.
	eq := &coord.Equatorial{
		unit.NewRA(10, 8, 22.3),
		unit.NewAngle(' ', 11, 58, 2),
	}
	epochFrom := 2000.0
	epochTo := 1978.0
	mα := unit.HourAngleFromSec(-0.0169)
	mδ := unit.AngleFromSec(0.006)
	precess.ApproxPosition(eq, eq, epochFrom, epochTo, mα, mδ)
	fmt.Printf("%0.1d\n", sexa.FmtRA(eq.RA))
	fmt.Printf("%+0d\n", sexa.FmtAngle(eq.Dec))
	// Output:
	// 10ʰ07ᵐ12ˢ.1
	// +12°04′32″
}
Beispiel #17
0
func ExamplePosition() {
	// Example 21.b, p. 135.
	eq := &coord.Equatorial{
		unit.NewRA(2, 44, 11.986),
		unit.NewAngle(' ', 49, 13, 42.48),
	}
	epochFrom := 2000.0
	jdTo := julian.CalendarGregorianToJD(2028, 11, 13.19)
	epochTo := base.JDEToJulianYear(jdTo)
	precess.Position(eq, eq, epochFrom, epochTo,
		unit.HourAngleFromSec(0.03425),
		unit.AngleFromSec(-0.0895))
	fmt.Printf("%0.3d\n", sexa.FmtRA(eq.RA))
	fmt.Printf("%+0.2d\n", sexa.FmtAngle(eq.Dec))
	// Output:
	// 2ʰ46ᵐ11ˢ.331
	// +49°20′54″.54
}
Beispiel #18
0
func ExamplePosition() {
	// Example 57.a, p. 398
	M := binary.M(1980, 1934.008, 41.623)
	fmt.Printf("M = %.3f\n", M.Deg())
	E, err := kepler.Kepler1(.2763, M, 4)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("E = %.3f\n", E.Deg())
	θ, ρ := binary.Position(.2763, unit.AngleFromSec(.907),
		unit.AngleFromDeg(59.025), unit.AngleFromDeg(23.717),
		unit.AngleFromDeg(219.907), E)
	fmt.Printf("θ = %.1f\n", θ.Deg())
	fmt.Printf("ρ = %.3f\n", ρ.Sec())
	// Output:
	// M = 37.788
	// E = 49.896
	// θ = 318.4
	// ρ = 0.411
}
Beispiel #19
0
// apogee parallax
func (l *la) ap() unit.Angle {
	return unit.AngleFromSec(
		3245.251 +
			-9.147*math.Cos(2*l.D) +
			-.841*math.Cos(l.D) +
			.697*math.Cos(2*l.F) +
			(-.656+.0016*l.T)*math.Cos(l.M) +
			.355*math.Cos(4*l.D) +
			.159*math.Cos(2*l.D-l.M) +
			.127*math.Cos(l.D+l.M) +
			.065*math.Cos(4*l.D-l.M) +
			.052*math.Cos(6*l.D) +
			.043*math.Cos(2*l.D+l.M) +
			.031*math.Cos(2*(l.D+l.F)) +
			-.023*math.Cos(2*(l.D-l.F)) +
			.022*math.Cos(2*(l.D-l.M)) +
			.019*math.Cos(2*(l.D+l.M)) +
			-.016*math.Cos(2*l.M) +
			.014*math.Cos(6*l.D-l.M) +
			.01*math.Cos(8*l.D))
}
Beispiel #20
0
// 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
}
Beispiel #21
0
// LongitudeJ2000 returns geometric longitude referenced to equinox J2000.
func LongitudeJ2000(e *pp.V87Planet, jde float64) (l unit.Angle) {
	l, _, _ = e.Position2000(jde)
	return (l + math.Pi - unit.AngleFromSec(.09033)).Mod1()
}
Beispiel #22
0
// Copyright 2013 Sonia Keys
// License MIT: http://www.opensource.org/licenses/MIT

// Parallax: Chapter 40, Correction for Parallax.
package parallax

import (
	"math"

	"github.com/soniakeys/meeus/globe"
	"github.com/soniakeys/meeus/sidereal"
	"github.com/soniakeys/unit"
)

// constant for Horizontal.  p. 279.
var hp = unit.AngleFromSec(8.794)

// Horizontal returns equatorial horizontal parallax of a body.
//
// Argument Δ is distance in AU.
//
// Meeus mentions use of this function for the Moon, Sun, planet, or comet.
// That is, for relatively distant objects.  For parallax of the Moon (or
// other relatively close object) see moonposition.Parallax.
func Horizontal(Δ float64) (π unit.Angle) {
	return hp.Div(Δ) // (40.1) p. 279
}

// Topocentric returns topocentric positions including parallax.
//
// Arguments α, δ are geocentric right ascension and declination in radians.
Beispiel #23
0
// GeocentricLatitudeDifference returns geographic latitude - geocentric
// latitude (φ - φ′) given geographic latitude (φ).
func GeocentricLatitudeDifference(φ unit.Angle) unit.Angle {
	// This appears to be an approximation with hard coded magic numbers.
	// No explanation is given in the text. The ellipsoid is not specified.
	// Perhaps the approximation works well enough for all ellipsoids?
	return unit.AngleFromSec(692.73*φ.Mul(2).Sin() - 1.16*φ.Mul(4).Sin())
}
Beispiel #24
0
// Asteroid returns semidiameter of an asteroid with a given diameter
// at given distance.
//
// Argument d is diameter in km, Δ is distance in AU.
//
// Result is semidiameter.
func Asteroid(d, Δ float64) unit.Angle {
	return unit.AngleFromSec(.0013788).Mul(d / Δ)
}
Beispiel #25
0
// License MIT: http://www.opensource.org/licenses/MIT

// Semidiameter: Chapter 55, Semidiameters of the Sun, Moon, and Planets.
package semidiameter

import (
	"math"

	"github.com/soniakeys/meeus/base"
	"github.com/soniakeys/meeus/parallax"
	"github.com/soniakeys/unit"
)

// Standard semidiameters at unit distance of 1 AU.
var (
	Sun               = unit.AngleFromSec(959.63)
	Mercury           = unit.AngleFromSec(3.36)
	VenusSurface      = unit.AngleFromSec(8.34)
	VenusCloud        = unit.AngleFromSec(8.41)
	Mars              = unit.AngleFromSec(4.68)
	JupiterEquatorial = unit.AngleFromSec(98.44)
	JupiterPolar      = unit.AngleFromSec(92.06)
	SaturnEquatorial  = unit.AngleFromSec(82.73)
	SaturnPolar       = unit.AngleFromSec(73.82)
	Uranus            = unit.AngleFromSec(35.02)
	Neptune           = unit.AngleFromSec(33.50)
	Pluto             = unit.AngleFromSec(2.07)
	Moon              = unit.AngleFromSec(358473400 / base.AU)
)

// Semidiameter returns semidiameter at specified distance.
Beispiel #26
0
// License MIT: http://www.opensource.org/licenses/MIT

// Refraction: Chapter 16: Atmospheric Refraction.
//
// Functions here assume atmospheric pressure of 1010 mb, temperature of
// 10°C, and yellow light.
package refraction

import (
	"math"

	"github.com/soniakeys/unit"
)

var (
	gt15true1 = unit.AngleFromSec(58.294)
	gt15true2 = unit.AngleFromSec(.0668)
	gt15app1  = unit.AngleFromSec(58.276)
	gt15app2  = unit.AngleFromSec(.0824)
)

// Gt15True returns refraction for obtaining true altitude when altitude
// is greater than 15 degrees (about .26 radians.)
//
// h0 must be a measured apparent altitude of a celestial body.
//
// Result is refraction to be subtracted from h0 to obtain the true altitude
// of the body.
func Gt15True(h0 unit.Angle) unit.Angle {
	// (16.1) p. 105
	t := (math.Pi/2 - h0).Tan()
Beispiel #27
0
// Low precision formula.  The high precision formula is not implemented
// because the low precision formula already gives position results to the
// accuracy given on p. 165.  The high precision formula the represents lots
// of typing with associated chance of typos, and no way to test the result.
func aberration(R float64) unit.Angle {
	// (25.10) p. 167
	return unit.AngleFromSec(-20.4898).Div(R)
}
Beispiel #28
0
//
// 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
}

// κ is the constnt of aberration in radians.
var κ = unit.AngleFromSec(20.49552)

// longitude of perihelian of Earth's orbit.
func perihelion(T float64) unit.Angle {
	return unit.AngleFromDeg(base.Horner(T, 102.93735, 1.71946, .00046))
}

// EclipticAberration returns corrections due to aberration for ecliptic
// coordinates of an object.
func EclipticAberration(λ, β unit.Angle, jd float64) (Δλ, Δβ unit.Angle) {
	T := base.J2000Century(jd)
	s, _ := solar.True(T)
	e := solar.Eccentricity(T)
	π := perihelion(T)
	sβ, cβ := β.Sincos()
	ssλ, csλ := (s - λ).Sincos()
Beispiel #29
0
// 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
}