Example #1
0
func ExampleEccentricity() {
	// Example 25.a, p. 165.
	T := base.J2000Century(julian.CalendarGregorianToJD(1992, 10, 13))
	fmt.Printf("%.9f\n", solar.Eccentricity(T))
	// Output:
	// 0.016711668
}
Example #2
0
func ExampleMeanAnomaly() {
	// Example 25.a, p. 165.
	T := base.J2000Century(julian.CalendarGregorianToJD(1992, 10, 13))
	fmt.Printf("%.5f\n", solar.MeanAnomaly(T)*180/math.Pi)
	// Output:
	// -2241.00603
}
Example #3
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
}
Example #4
0
func ExampleRadius() {
	// Example 25.a, p. 165.
	T := base.J2000Century(julian.CalendarGregorianToJD(1992, 10, 13))
	fmt.Printf("%.5f AU\n", solar.Radius(T))
	// Output:
	// 0.99766 AU
}
Example #5
0
func ExampleApparentLongitude() {
	// Example 25.a, p. 165.
	T := base.J2000Century(julian.CalendarGregorianToJD(1992, 10, 13))
	fmt.Println("λ:", sexa.NewFmtAngle(solar.ApparentLongitude(T)))
	// Output:
	// λ: 199°54′32″
}
Example #6
0
// AberrationRonVondrak uses the Ron-Vondrák expression to compute corrections
// due to aberration for equatorial coordinates of an object.
func AberrationRonVondrak(α, δ, jd float64) (Δα, Δδ float64) {
	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α := math.Sincos(α)
	sδ, cδ := math.Sincos(δ)
	// (23.4) p. 156
	return (Yp*cα - Xp*sα) / (c * cδ), -((Xp*cα+Yp*sα)*sδ - Zp*cδ) / c
}
Example #7
0
// 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
}
Example #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))
}
Example #9
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.
//
// 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))
}
Example #10
0
// Mean computes some intermediate values for a mean planetary configuration
// given a year and a row of coefficients from Table 36.A, p. 250.
func mean(y float64, a *ca) (J, M, T float64) {
	// (36.1) p. 250
	k := math.Floor((365.2425*y+1721060-a.A)/a.B + .5)
	J = a.A + k*a.B
	M = unit.PMod(a.M0+k*a.M1, 360) * math.Pi / 180
	T = base.J2000Century(J)
	return
}
Example #11
0
// 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λ)
}
Example #12
0
// TrueNode returns longitude of the true ascending node.
//
// That is, the node of the instantaneous lunar orbit.
//
// Result in radians.
func TrueNode(jde float64) float64 {
	D, M, Mʹ, F := dmf(base.J2000Century(jde))
	return Node(jde) +
		-1.4979*p*math.Sin(2*(D-F)) +
		-.15*p*math.Sin(M) +
		-.1226*p*math.Sin(2*D) +
		.1176*p*math.Sin(2*F) +
		-.0801*p*math.Sin(2*(Mʹ-F))
}
Example #13
0
// TrueNode returns longitude of the true ascending node.
//
// That is, the node of the instantaneous lunar orbit.
func TrueNode(jde float64) unit.Angle {
	D, M, Mʹ, F := dmf(base.J2000Century(jde))
	return Node(jde) + unit.AngleFromDeg(
		-1.4979*math.Sin(2*(D-F))+
			-.15*math.Sin(M)+
			-.1226*math.Sin(2*D)+
			.1176*math.Sin(2*F)+
			-.0801*math.Sin(2*(Mʹ-F)))
}
Example #14
0
// cl splits the work into two closures.
func cl(jde float64, earth, saturn *pp.V87Planet) (f1 func() (ΔU, B float64),
	f2 func() (Bʹ, P, aEdge, bEdge float64)) {
	const p = math.Pi / 180
	var i, Ω float64
	var l0, b0, R float64
	Δ := 9.
	var λ, β float64
	var si, ci, sβ, cβ, sB float64
	var sbʹ, cbʹ, slʹΩ, clʹΩ float64
	f1 = func() (ΔU, B float64) {
		// (45.1), p. 318
		T := base.J2000Century(jde)
		i = base.Horner(T, 28.075216*p, -.012998*p, .000004*p)
		Ω = base.Horner(T, 169.50847*p, 1.394681*p, .000412*p)
		// Step 2.
		l0, b0, R = earth.Position(jde)
		l0, b0 = pp.ToFK5(l0, b0, jde)
		sl0, cl0 := math.Sincos(l0)
		sb0 := math.Sin(b0)
		// Steps 3, 4.
		var l, b, r, x, y, z float64
		f := func() {
			τ := base.LightTime(Δ)
			l, b, r = saturn.Position(jde - τ)
			l, b = pp.ToFK5(l, b, jde)
			sl, cl := math.Sincos(l)
			sb, cb := math.Sincos(b)
			x = r*cb*cl - R*cl0
			y = r*cb*sl - R*sl0
			z = r*sb - R*sb0
			Δ = math.Sqrt(x*x + y*y + z*z)
		}
		f()
		f()
		// Step 5.
		λ = math.Atan2(y, x)
		β = math.Atan(z / math.Hypot(x, y))
		// First part of step 6.
		si, ci = math.Sincos(i)
		sβ, cβ = math.Sincos(β)
		sB = si*cβ*math.Sin(λ-Ω) - ci*sβ
		B = math.Asin(sB) // return value
		// Step 7.
		N := 113.6655*p + .8771*p*T
		lʹ := l - .01759*p/r
		bʹ := b - .000764*p*math.Cos(l-N)/r
		// Setup for steps 8, 9.
		sbʹ, cbʹ = math.Sincos(bʹ)
		slʹΩ, clʹΩ = math.Sincos(lʹ - Ω)
		// Step 9.
		sλΩ, cλΩ := math.Sincos(λ - Ω)
		U1 := math.Atan2(si*sbʹ+ci*cbʹ*slʹΩ, cbʹ*clʹΩ)
		U2 := math.Atan2(si*sβ+ci*cβ*sλΩ, cβ*cλΩ)
		ΔU = math.Abs(U1 - U2) // return value
		return
	}
Example #15
0
// 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
}
Example #16
0
// Mean returns mean orbital elements for a planet
//
// Argument p must be a planet const as defined above, argument e is
// a result parameter.  A valid non-nil pointer to an Elements struct
// must be passed in.
//
// Results are referenced to mean dynamical ecliptic and equinox of date.
//
// Semimajor axis is in AU, angular elements are in radians.
func Mean(p int, jde float64, e *Elements) {
	T := base.J2000Century(jde)
	c := &cMean[p]
	e.Lon = unit.AngleFromDeg(base.Horner(T, c.L...)).Mod1()
	e.Axis = base.Horner(T, c.a...)
	e.Ecc = base.Horner(T, c.e...)
	e.Inc = unit.AngleFromDeg(base.Horner(T, c.i...))
	e.Node = unit.AngleFromDeg(base.Horner(T, c.Ω...))
	e.Peri = unit.AngleFromDeg(base.Horner(T, c.ϖ...))
}
Example #17
0
// Mean returns mean orbital elements for a planet
//
// Argument p must be a planet const as defined above, argument e is
// a result parameter.  A valid non-nil pointer to an Elements struct
// must be passed in.
//
// Results are referenced to mean dynamical ecliptic and equinox of date.
//
// Semimajor axis is in AU, angular elements are in radians.
func Mean(p int, jde float64, e *Elements) {
	T := base.J2000Century(jde)
	c := &cMean[p]
	e.Lon = base.PMod(base.Horner(T, c.L...)*math.Pi/180, 2*math.Pi)
	e.Axis = base.Horner(T, c.a...)
	e.Ecc = base.Horner(T, c.e...)
	e.Inc = base.Horner(T, c.i...) * math.Pi / 180
	e.Node = base.Horner(T, c.Ω...) * math.Pi / 180
	e.Peri = base.Horner(T, c.ϖ...) * math.Pi / 180
}
Example #18
0
// FractionVenus computes an approximation of the illumanted fraction of Venus.
func FractionVenus(jde float64) float64 {
	T := base.J2000Century(jde)
	V := 261.51*p + 22518.443*p*T
	M := 177.53*p + 35999.05*p*T
	N := 50.42*p + 58517.811*p*T
	W := V + 1.91*p*math.Sin(M) + .78*p*math.Sin(N)
	Δ := math.Sqrt(1.52321 + 1.44666*math.Cos(W))
	s := .72333 + Δ
	return (s*s - 1) / 2.89332 / Δ
}
Example #19
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 in radians
//	β: ecliptic latitude in radians
//	R: range in AU
func TrueVSOP87(e *pp.V87Planet, jde float64) (s, β, R float64) {
	l, b, r := e.Position(jde)
	s = l + math.Pi
	// FK5 correction.
	λp := base.Horner(base.J2000Century(jde),
		s, -1.397*math.Pi/180, -.00031*math.Pi/180)
	sλp, cλp := math.Sincos(λp)
	Δβ := .03916 / 3600 * math.Pi / 180 * (cλp - sλp)
	// (25.9) p. 166
	return base.PMod(s-.09033/3600*math.Pi/180, 2*math.Pi), Δβ - b, r
}
Example #20
0
// ToFK5 converts ecliptic longitude and latitude from dynamical frame to FK5.
func ToFK5(L, B, jde float64) (L5, B5 float64) {
	// formula 32.3, p. 219.
	T := base.J2000Century(jde)
	Lp := L - 1.397*math.Pi/180*T - .00031*math.Pi/180*T*T
	sLp, cLp := math.Sincos(Lp)
	// (32.3) p. 219
	L5 = L + -.09033/3600*math.Pi/180 +
		.03916/3600*math.Pi/180*(cLp+sLp)*math.Tan(B)
	B5 = B + .03916/3600*math.Pi/180*(cLp-sLp)
	return
}
Example #21
0
func TestPhaseAngleEcl2(t *testing.T) {
	j := julian.CalendarGregorianToJD(1992, 4, 12)
	λ, β, _ := moonposition.Position(j)
	λ0 := solar.ApparentLongitude(base.J2000Century(j))
	i := moonillum.PhaseAngleEcl2(λ, β, λ0)
	k := base.Illuminated(i)
	ref := .6775
	if math.Abs(k-ref) > 1e-4 {
		t.Errorf("k = %.4f", k)
	}
}
Example #22
0
func eq(y int, c []float64) float64 {
	J0 := base.Horner(float64(y)*.001, c...)
	T := base.J2000Century(J0)
	W := 35999.373*math.Pi/180*T - 2.47*math.Pi/180
	Δλ := 1 + .0334*math.Cos(W) + .0007*math.Cos(2*W)
	S := 0.
	for i := len(terms) - 1; i >= 0; i-- {
		t := &terms[i]
		S += t.a * math.Cos((t.b+t.c*T)*math.Pi/180)
	}
	return J0 + .00001*S/Δλ
}
Example #23
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
}
Example #24
0
func TestPhaseAngleEcl(t *testing.T) {
	j := julian.CalendarGregorianToJD(1992, 4, 12)
	λ, β, Δ := moonposition.Position(j)
	T := base.J2000Century(j)
	λ0 := solar.ApparentLongitude(T)
	R := solar.Radius(T) * base.AU
	i := moonillum.PhaseAngleEcl(λ, β, Δ, λ0, R)
	ref := 69.0756 * math.Pi / 180
	if math.Abs((i-ref)/ref) > 1e-4 {
		t.Errorf("i = %.4f", i*180/math.Pi)
	}
}
Example #25
0
// 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
}
Example #26
0
// 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()
	sπλ, cπλ := (π - λ).Sincos()
	// (23.2) p. 151
	Δλ = κ.Mul((e*cπλ - csλ) / cβ)
	Δβ = -κ.Mul(sβ * (ssλ - e*sπλ))
	return
}
Example #27
0
func ExampleTrue() {
	// Example 25.a, p. 165.
	jd := julian.CalendarGregorianToJD(1992, 10, 13)
	fmt.Printf("JDE: %.1f\n", jd)
	T := base.J2000Century(jd)
	fmt.Printf("T:   %.9f\n", T)
	s, _ := solar.True(T)
	fmt.Printf("☉:   %.5f\n", (s * 180 / math.Pi))
	// Output:
	// JDE: 2448908.5
	// T:   -0.072183436
	// ☉:   199.90987
}
Example #28
0
// EclipticAberration returns corrections due to aberration for ecliptic
// coordinates of an object.
func EclipticAberration(λ, β, jd float64) (Δλ, Δβ float64) {
	T := base.J2000Century(jd)
	s, _ := solar.True(T)
	e := solar.Eccentricity(T)
	π := perihelion(T)
	sβ, cβ := math.Sincos(β)
	ssλ, csλ := math.Sincos(s - λ)
	sπλ, cπλ := math.Sincos(π - λ)
	// (23.2) p. 151
	Δλ = κ * (e*cπλ - csλ) / cβ
	Δβ = -κ * sβ * (ssλ - e*sπλ)
	return
}
Example #29
0
// 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)
}
Example #30
0
// 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())
}