Ejemplo n.º 1
0
// Section "Trigonometric functions of large angles":
//
// Meeus makes his point, but an example with integer values is a bit unfair
// when trigonometric functions inherently work on floating point numbers.
func ExamplePMod_integer() {
	const large = 36000030

	// The direct function call loses precition as expected.
	fmt.Println("Direct:    ", math.Sin(large*math.Pi/180))

	// When the value is manually reduced to the integer 30, the Go constant
	// evaluaton does a good job of delivering a radian value to math.Sin that
	// evaluates to .5 exactly.
	fmt.Println("Integer 30:", math.Sin(30*math.Pi/180))

	// Math.Mod takes float64s and returns float64s.  The integer constants
	// here however can be represented exactly as float64s, and the returned
	// result is exact as well.
	fmt.Println("Math.Mod:  ", math.Mod(large, 360))

	// But when math.Mod is substituted into the Sin function, float64s
	// are multiplied instead of the high precision constants, and the result
	// comes back slightly inexact.
	fmt.Println("Sin Mod:   ", math.Sin(math.Mod(large, 360)*math.Pi/180))

	// Use of PMod on integer constants produces results identical to above.
	fmt.Println("PMod int:  ", math.Sin(base.PMod(large, 360)*math.Pi/180))

	// As soon as the large integer is scaled to a non-integer value though,
	// precision is lost and PMod is of no help recovering at this point.
	fmt.Println("PMod float:", math.Sin(base.PMod(large*math.Pi/180, 2*math.Pi)))
	// Output:
	// Direct:     0.49999999995724154
	// Integer 30: 0.5
	// Math.Mod:   30
	// Sin Mod:    0.49999999999999994
	// PMod int:   0.49999999999999994
	// PMod float: 0.49999999997845307
}
Ejemplo n.º 2
0
// True returns true geometric longitude and anomaly of the sun referenced to the mean equinox of date.
//
// Argument T is the number of Julian centuries since J2000.
// See base.J2000Century.
//
// Results:
//	s = true geometric longitude, ☉, in radians
//	ν = true anomaly in radians
func True(T float64) (s, ν float64) {
	// (25.2) p. 163
	L0 := base.Horner(T, 280.46646, 36000.76983, 0.0003032) *
		math.Pi / 180
	M := MeanAnomaly(T)
	C := (base.Horner(T, 1.914602, -0.004817, -.000014)*
		math.Sin(M) +
		(0.019993-.000101*T)*math.Sin(2*M) +
		0.000289*math.Sin(3*M)) * math.Pi / 180
	return base.PMod(L0+C, 2*math.Pi), base.PMod(M+C, 2*math.Pi)
}
Ejemplo n.º 3
0
// ReduceB1950ToJ2000 reduces orbital elements of a solar system body from
// equinox B1950 to J2000.
func ReduceB1950ToJ2000(eFrom, eTo *Elements) *Elements {
	// (24.4) p. 161
	const S = .0001139788
	const C = .9999999935
	W := eFrom.Node - 174.298782*math.Pi/180
	si, ci := math.Sincos(eFrom.Inc)
	sW, cW := math.Sincos(W)
	A := si * sW
	B := C*si*cW - S*ci
	eTo.Inc = math.Asin(math.Hypot(A, B))
	eTo.Node = base.PMod(174.997194*math.Pi/180+math.Atan2(A, B),
		2*math.Pi)
	eTo.Peri = base.PMod(eFrom.Peri+math.Atan2(-S*sW, C*si-S*ci*cW),
		2*math.Pi)
	return eTo
}
Ejemplo n.º 4
0
func TestNode0(t *testing.T) {
	for i, j := range n0 {
		if e := math.Abs(base.PMod(moon.Node(j)+1, 2*math.Pi) - 1); e > 1e-3 {
			t.Error(i, e)
		}
	}
}
Ejemplo n.º 5
0
// ReduceB1950ToJ2000 reduces orbital elements of a solar system body from
// equinox B1950 in the FK4 system to equinox J2000 in the FK5 system.
func ReduceB1950FK4ToJ2000FK5(eFrom, eTo *Elements) *Elements {
	const (
		Lp = 4.50001688 * math.Pi / 180
		L  = 5.19856209 * math.Pi / 180
		J  = .00651966 * math.Pi / 180
	)
	W := L + eFrom.Node
	si, ci := math.Sincos(eFrom.Inc)
	sJ, cJ := math.Sincos(J)
	sW, cW := math.Sincos(W)
	eTo.Inc = math.Acos(ci*cJ - si*sJ*cW)
	eTo.Node = base.PMod(math.Atan2(si*sW, ci*sJ+si*cJ*cW)-Lp,
		2*math.Pi)
	eTo.Peri = base.PMod(eFrom.Peri+math.Atan2(sJ*sW, si*cJ+ci*sJ*cW),
		2*math.Pi)
	return eTo
}
Ejemplo n.º 6
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 = base.PMod(a.M0+k*a.M1, 360) * math.Pi / 180
	T = base.J2000Century(J)
	return
}
Ejemplo n.º 7
0
// Apparent0UT returns apparent sidereal time at Greenwich at 0h UT
// on the given JD.
//
// The result is in seconds of time and is in the range [0,86400).
func Apparent0UT(jd float64) float64 {
	j0, f := math.Modf(jd + .5)
	cen := (j0 - .5 - base.J2000) / 36525
	s := base.Horner(cen, iau82...) + f*1.00273790935*86400
	n := nutation.NutationInRA(j0)      // angle (radians) of RA
	ns := n * 3600 * 180 / math.Pi / 15 // convert RA to time in seconds
	return base.PMod(s+ns, 86400)
}
Ejemplo n.º 8
0
// GalToEq converts galactic coordinates to equatorial coordinates.
//
// Resulting equatorial coordinates will be referred to the standard equinox of
// B1950.0.  For subsequent conversion to other epochs, see package precess and
// utility functions in package meeus.
func GalToEq(l, b float64) (α, δ float64) {
	sdLon, cdLon := math.Sincos(l - galacticLon0)
	sgδ, cgδ := math.Sincos(galacticNorth.Dec)
	sb, cb := math.Sincos(b)
	y := math.Atan2(sdLon, cdLon*sgδ-(sb/cb)*cgδ)
	α = base.PMod(y+galacticNorth.RA, 2*math.Pi)
	δ = math.Asin(sb*sgδ + cb*cgδ*cdLon)
	return
}
Ejemplo n.º 9
0
// HzToEq transforms horizontal coordinates to equatorial coordinates.
//
//	A: azimuth
//	h: elevation
//	φ: latitude of observer on Earth
//	ψ: longitude of observer on Earth
//	st: sidereal time at Greenwich at time of observation.
//
// Sidereal time must be consistent with the equatorial coordinates.
// If coordinates are apparent, sidereal time must be apparent as well.
//
// Results:
//
//	α: right ascension
//	δ: declination
func HzToEq(A, h, φ, ψ, st float64) (α, δ float64) {
	sA, cA := math.Sincos(A)
	sh, ch := math.Sincos(h)
	sφ, cφ := math.Sincos(φ)
	H := math.Atan2(sA, cA*sφ+sh/ch*cφ)
	α = base.PMod(sexa.Time(st).Rad()-ψ-H, 2*math.Pi)
	δ = math.Asin(sφ*sh - cφ*ch*cA)
	return
}
Ejemplo n.º 10
0
// GalToEq converts galactic coordinates to equatorial coordinates.
//
// Resulting equatorial coordinates will be referred to the standard equinox of
// B1950.0.  For subsequent conversion to other epochs, see package precess and
// utility functions in package meeus.
func (eq *Equatorial) GalToEq(g *Galactic) *Equatorial {
	sdLon, cdLon := math.Sincos(g.Lon - galacticLon0)
	sgδ, cgδ := math.Sincos(galacticNorth.Dec)
	sb, cb := math.Sincos(g.Lat)
	y := math.Atan2(sdLon, cdLon*sgδ-(sb/cb)*cgδ)
	eq.RA = base.PMod(y+galacticNorth.RA, 2*math.Pi)
	eq.Dec = math.Asin(sb*sgδ + cb*cgδ*cdLon)
	return eq
}
Ejemplo n.º 11
0
// HzToEq transforms horizontal coordinates to equatorial coordinates.
//
// Sidereal time must be consistent with the equatorial coordinates.
// If coordinates are apparent, sidereal time must be apparent as well.
func (eq *Equatorial) HzToEq(hz *Horizontal, g globe.Coord, st float64) *Equatorial {
	sA, cA := math.Sincos(hz.Az)
	sh, ch := math.Sincos(hz.Alt)
	sφ, cφ := math.Sincos(g.Lat)
	H := math.Atan2(sA, cA*sφ+sh/ch*cφ)
	eq.RA = base.PMod(sexa.Time(st).Rad()-g.Lon-H, 2*math.Pi)
	eq.Dec = math.Asin(sφ*sh - cφ*ch*cA)
	return eq
}
Ejemplo n.º 12
0
// Topocentric2 returns topocentric corrections including parallax.
//
// This function implements the "non-rigorous" method descripted in the text.
//
// Note that results are corrections, not corrected coordinates.
func Topocentric2(α, δ, Δ, ρsφʹ, ρcφʹ, L, jde float64) (Δα, Δδ float64) {
	π := Horizontal(Δ)
	θ0 := base.Time(sidereal.Apparent(jde)).Rad()
	H := base.PMod(θ0-L-α, 2*math.Pi)
	sH, cH := math.Sincos(H)
	sδ, cδ := math.Sincos(δ)
	Δα = -π * ρcφʹ * sH / cδ         // (40.4) p. 280
	Δδ = -π * (ρsφʹ*cδ - ρcφʹ*cH*sδ) // (40.5) p. 280
	return
}
Ejemplo n.º 13
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
}
Ejemplo n.º 14
0
func (m *moon) optical(λ, β float64) (lʹ, bʹ, A float64) {
	// (53.1) p. 372
	W := λ - m.Ω // (λ without nutation)
	sW, cW := math.Sincos(W)
	sβ, cβ := math.Sincos(β)
	A = math.Atan2(sW*cβ*cI-sβ*sI, cW*cβ)
	lʹ = base.PMod(A-m.F, 2*math.Pi)
	bʹ = math.Asin(-sW*cβ*sI - sβ*cI)
	return
}
Ejemplo n.º 15
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
}
Ejemplo n.º 16
0
// Topocentric returns topocentric positions including parallax.
//
// Arguments α, δ are geocentric right ascension and declination in radians.
// Δ is distance to the observed object in AU.  ρsφʹ, ρcφʹ are parallax
// constants (see package globe.) L is geographic longitude of the observer,
// jde is time of observation.
//
// Results are observed topocentric ra and dec in radians.
func Topocentric(α, δ, Δ, ρsφʹ, ρcφʹ, L, jde float64) (αʹ, δʹ float64) {
	π := Horizontal(Δ)
	θ0 := base.Time(sidereal.Apparent(jde)).Rad()
	H := base.PMod(θ0-L-α, 2*math.Pi)
	sπ := math.Sin(π)
	sH, cH := math.Sincos(H)
	sδ, cδ := math.Sincos(δ)
	Δα := math.Atan2(-ρcφʹ*sπ*sH, cδ-ρcφʹ*sπ*cH) // (40.2) p. 279
	αʹ = α + Δα
	δʹ = math.Atan2((sδ-ρsφʹ*sπ)*math.Cos(Δα), cδ-ρcφʹ*sπ*cH) // (40.3) p. 279
	return
}
Ejemplo n.º 17
0
Archivo: rise.go Proyecto: pjh59/meeus
// Times computes UT rise, transit and set times for a celestial object on
// a day of interest.
//
// The function argurments do not actually include the day, but do include
// a number of values computed from the day.
//
//	p is geographic coordinates of observer.
//	ΔT is delta T.
//	h0 is "standard altitude" of the body.
//	Th0 is apparent sidereal time at 0h UT at Greenwich.
//	α3, δ3 are slices of three right ascensions and declinations.
//
// ΔT unit is seconds.  See package deltat.
//
// h0 unit is radians.
//
// Th0 must be the time on the day of interest, in seconds.
// See sidereal.Apparent0UT.
//
// α3, δ3 must be values at 0h dynamical time for the day before, the day of,
// and the day after the day of interest.  Units are radians.
//
// Result units are seconds and are in the range [0,86400)
func Times(p globe.Coord, ΔT, h0, Th0 float64, α3, δ3 []float64) (mRise, mTransit, mSet float64, err error) {
	mRise, mTransit, mSet, err = ApproxTimes(p, h0, Th0, α3[1], δ3[1])
	if err != nil {
		return
	}
	var d3α, d3δ *interp.Len3
	d3α, err = interp.NewLen3(-86400, 86400, α3)
	if err != nil {
		return
	}
	d3δ, err = interp.NewLen3(-86400, 86400, δ3)
	if err != nil {
		return
	}
	// adjust mTransit
	{
		th0 := base.PMod(Th0+mTransit*360.985647/360, 86400)
		α := d3α.InterpolateX(mTransit + ΔT)
		H := th0 - (p.Lon+α)*43200/math.Pi
		mTransit -= H
	}
	// adjust mRise, mSet
	sLat, cLat := math.Sincos(p.Lat)
	adjustRS := func(m float64) (float64, error) {
		th0 := base.PMod(Th0+m*360.985647/360, 86400)
		ut := m + ΔT
		α := d3α.InterpolateX(ut)
		δ := d3δ.InterpolateX(ut)
		H := th0 - (p.Lon+α)*43200/math.Pi
		sδ, cδ := math.Sincos(δ)
		h := sLat*sδ + cLat*cδ*math.Cos(H)
		return m + (h-h0)/cδ*cLat*math.Sin(H), nil
	}
	mRise, err = adjustRS(mRise)
	if err != nil {
		return
	}
	mSet, err = adjustRS(mSet)
	return
}
Ejemplo n.º 18
0
Archivo: rise.go Proyecto: pjh59/meeus
// ApproxTimes computes approximate UT rise, transit and set times for
// a celestial object on a day of interest.
//
// The function argurments do not actually include the day, but do include
// values computed from the day.
//
//	p is geographic coordinates of observer.
//	h0 is "standard altitude" of the body.
//	Th0 is apparent sidereal time at 0h UT at Greenwich.
//	α, δ are right ascension and declination of the body.
//
// h0 unit is radians.
//
// Th0 must be the time on the day of interest, in seconds.
// See sidereal.Apparent0UT.
//
// α, δ must be values at 0h dynamical time for the day of interest.
// Units are radians.
//
// Result units are seconds and are in the range [0,86400)
func ApproxTimes(p globe.Coord, h0, Th0 float64, α, δ float64) (mRise, mTransit, mSet float64, err error) {
	// Meeus works in a crazy mix of units.
	// This function and Times work with seconds of time as much as possible.

	// approximate local hour angle
	sLat, cLat := math.Sincos(p.Lat)
	sδ1, cδ1 := math.Sincos(δ)
	cH0 := (math.Sin(h0) - sLat*sδ1) / (cLat * cδ1) // (15.1) p. 102
	if cH0 < -1 || cH0 > 1 {
		err = ErrorCircumpolar
		return
	}
	H0 := math.Acos(cH0) * 43200 / math.Pi

	// approximate transit, rise, set times.
	// (15.2) p. 102.
	mt := (α+p.Lon)*43200/math.Pi - Th0
	mTransit = base.PMod(mt, 86400)
	mRise = base.PMod(mt-H0, 86400)
	mSet = base.PMod(mt+H0, 86400)
	return
}
Ejemplo n.º 19
0
// Section "Trigonometric functions of large angles":
//
// A non integer example better illustrates that reduction to a range
// does not rescue precision.
func ExamplePMod_mars() {
	// Angle W from step 9 of example 42.a, as suggested.
	const W = 5492522.4593
	const reduced = 2.4593

	// Direct function call.  It's a number.  How correct is it?
	fmt.Println("Direct:  ", math.Sin(W*math.Pi/180))

	// Manually reduced to range 0-360.  This is presumably the "correct"
	// answer, but note that the reduced number has a reduced number of
	// significat digits.  The answer cannot have any more significant digits.
	fmt.Println("Reduced: ", math.Sin(reduced*math.Pi/180))

	// Accordingly, PMod cannot rescue any precision, whether done on degrees
	// or radians.
	fmt.Println("PMod deg:", math.Sin(base.PMod(W, 360)*math.Pi/180))
	fmt.Println("PMod rad:", math.Sin(base.PMod(W*math.Pi/180, 2*math.Pi)))
	// Output:
	// Direct:   0.04290970350270464
	// Reduced:  0.04290970350923273
	// PMod deg: 0.04290970351307828
	// PMod rad: 0.04290970350643808
}
Ejemplo n.º 20
0
// Physical2 computes quantities for physical observations of Jupiter.
//
// Results are less accurate than with Physical().
//
// 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.
//
// All angular results in radians.
func Physical2(jde float64) (DS, DE, ω1, ω2 float64) {
	d := jde - base.J2000
	const p = math.Pi / 180
	V := 172.74*p + .00111588*p*d
	M := 357.529*p + .9856003*p*d
	sV := math.Sin(V)
	N := 20.02*p + .0830853*p*d + .329*p*sV
	J := 66.115*p + .9025179*p*d - .329*p*sV
	sM, cM := math.Sincos(M)
	sN, cN := math.Sincos(N)
	s2M, c2M := math.Sincos(2 * M)
	s2N, c2N := math.Sincos(2 * N)
	A := 1.915*p*sM + .02*p*s2M
	B := 5.555*p*sN + .168*p*s2N
	K := J + A - B
	R := 1.00014 - .01671*cM - .00014*c2M
	r := 5.20872 - .25208*cN - .00611*c2N
	sK, cK := math.Sincos(K)
	Δ := math.Sqrt(r*r + R*R - 2*r*R*cK)
	ψ := math.Asin(R / Δ * sK)
	dd := d - Δ/173
	ω1 = 210.98*p + 877.8169088*p*dd + ψ - B
	ω2 = 187.23*p + 870.1869088*p*dd + ψ - B
	C := math.Sin(ψ / 2)
	C *= C
	if sK > 0 {
		C = -C
	}
	ω1 = base.PMod(ω1+C, 2*math.Pi)
	ω2 = base.PMod(ω2+C, 2*math.Pi)
	λ := 34.35*p + .083091*p*d + .329*p*sV + B
	DS = 3.12 * p * math.Sin(λ+42.8*p)
	DE = DS - 2.22*p*math.Sin(ψ)*math.Cos(λ+22*p) -
		1.3*p*(r-Δ)/Δ*math.Sin(λ-100.5*p)
	return
}
Ejemplo n.º 21
0
// Topocentric3 returns topocentric hour angle and declination including parallax.
//
// This function implements the "alternative" method described in the text.
// The method should be similarly rigorous to that of Topocentric() and results
// should be virtually consistent.
func Topocentric3(α, δ, Δ, ρsφʹ, ρcφʹ, L, jde float64) (Hʹ, δʹ float64) {
	π := Horizontal(Δ)
	θ0 := base.Time(sidereal.Apparent(jde)).Rad()
	H := base.PMod(θ0-L-α, 2*math.Pi)
	sπ := math.Sin(π)
	sH, cH := math.Sincos(H)
	sδ, cδ := math.Sincos(δ)
	A := cδ * sH
	B := cδ*cH - ρcφʹ*sπ
	C := sδ - ρsφʹ*sπ
	q := math.Sqrt(A*A + B*B + C*C)
	Hʹ = math.Atan2(A, B)
	δʹ = math.Asin(C / q)
	return
}
Ejemplo n.º 22
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 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
}
Ejemplo n.º 23
0
// PhaseAngle3 computes the phase angle of the Moon given a julian day.
//
// Less accurate than PhaseAngle functions taking coordinates.
//
// Result in radians.
func PhaseAngle3(jde float64) float64 {
	T := base.J2000Century(jde)
	const p = math.Pi / 180
	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)
	return math.Pi - base.PMod(D, 2*math.Pi) +
		-6.289*p*math.Sin(Mʹ) +
		2.1*p*math.Sin(M) +
		-1.274*p*math.Sin(2*D-Mʹ) +
		-.658*p*math.Sin(2*D) +
		-.214*p*math.Sin(2*Mʹ) +
		-.11*p*math.Sin(D)
}
Ejemplo n.º 24
0
// Position returns geocentric location of the Moon.
//
// Results are referenced to mean equinox of date and do not include
// the effect of nutation.
//
//	λ  Geocentric longitude, in radians.
//	β  Geocentric latidude, in radians.
//	Δ  Distance between centers of the Earth and Moon, in km.
func Position(jde float64) (λ, β, Δ float64) {
	T := base.J2000Century(jde)
	Lʹ := base.Horner(T, 218.3164477*p, 481267.88123421*p,
		-.0015786*p, p/538841, -p/65194000)
	D, M, Mʹ, F := dmf(T)
	A1 := 119.75*p + 131.849*p*T
	A2 := 53.09*p + 479264.29*p*T
	A3 := 313.45*p + 481266.484*p*T
	E := base.Horner(T, 1, -.002516, -.0000074)
	E2 := E * E
	Σl := 3958*math.Sin(A1) + 1962*math.Sin(Lʹ-F) + 318*math.Sin(A2)
	Σr := 0.
	Σb := -2235*math.Sin(Lʹ) + 382*math.Sin(A3) + 175*math.Sin(A1-F) +
		175*math.Sin(A1+F) + 127*math.Sin(Lʹ-Mʹ) - 115*math.Sin(Lʹ+Mʹ)
	for i := range ta {
		r := &ta[i]
		sa, ca := math.Sincos(D*r.D + M*r.M + Mʹ*r.Mʹ + F*r.F)
		switch r.M {
		case 0:
			Σl += r.Σl * sa
			Σr += r.Σr * ca
		case 1, -1:
			Σl += r.Σl * sa * E
			Σr += r.Σr * ca * E
		case 2, -2:
			Σl += r.Σl * sa * E2
			Σr += r.Σr * ca * E2
		}
	}
	for i := range tb {
		r := &tb[i]
		sb := math.Sin(D*r.D + M*r.M + Mʹ*r.Mʹ + F*r.F)
		switch r.M {
		case 0:
			Σb += r.Σb * sb
		case 1, -1:
			Σb += r.Σb * sb * E
		case 2, -2:
			Σb += r.Σb * sb * E2
		}
	}
	λ = base.PMod(Lʹ, 2*math.Pi) + Σl*1e-6*p
	β = Σb * 1e-6 * p
	Δ = 385000.56 + Σr*1e-3
	return
}
Ejemplo n.º 25
0
// Position2000 returns ecliptic position of planets by full VSOP87 theory.
//
// Argument jde is the date for which positions are desired.
//
// Results are for the dynamical equinox and ecliptic J2000.
//
//	L is heliocentric longitude in radians.
//	B is heliocentric latitude in radians.
//	R is heliocentric range in AU.
func (vt *V87Planet) Position2000(jde float64) (L, B, R float64) {
	T := base.J2000Century(jde)
	τ := T * .1
	cf := make([]float64, 6)
	sum := func(series coeff) float64 {
		for x, terms := range series {
			cf[x] = 0
			// sum terms in reverse order to preserve accuracy
			for y := len(terms) - 1; y >= 0; y-- {
				term := &terms[y]
				cf[x] += term.a * math.Cos(term.b+term.c*τ)
			}
		}
		return base.Horner(τ, cf[:len(series)]...)
	}
	L = base.PMod(sum(vt.l), 2*math.Pi)
	B = sum(vt.b)
	R = sum(vt.r)
	return
}
Ejemplo n.º 26
0
func TestTopocentric3(t *testing.T) {
	// same test case as example 40.a, p. 280
	α := 339.530208 * math.Pi / 180
	δ := -15.771083 * math.Pi / 180
	Δ := .37276
	ρsφʹ := .546861
	ρcφʹ := .836339
	L := base.NewHourAngle(false, 7, 47, 27).Rad()
	jde := julian.CalendarGregorianToJD(2003, 8, 28+(3+17./60)/24)
	// reference result
	αʹ, δʹ1 := parallax.Topocentric(α, δ, Δ, ρsφʹ, ρcφʹ, L, jde)
	// result to test
	Hʹ, δʹ3 := parallax.Topocentric3(α, δ, Δ, ρsφʹ, ρcφʹ, L, jde)
	// test
	θ0 := base.Time(sidereal.Apparent(jde)).Rad()
	if math.Abs(base.PMod(Hʹ-(θ0-L-αʹ)+1, 2*math.Pi)-1) > 1e-15 {
		t.Fatal(Hʹ, θ0-L-αʹ)
	}
	if math.Abs(δʹ3-δʹ1) > 1e-15 {
		t.Fatal(δʹ3, δʹ1)
	}
}
Ejemplo n.º 27
0
// Kepler3 solves Kepler's equation by binary search.
//
// Argument e is eccentricity, M is mean anomoly in radians.
//
// Result E is eccentric anomaly in radians.
func Kepler3(e, M float64) (E float64) {
	// adapted from BASIC, p. 206
	M = base.PMod(M, 2*math.Pi)
	f := 1
	if M > math.Pi {
		f = -1
		M = 2*math.Pi - M
	}
	E0 := math.Pi * .5
	d := math.Pi * .25
	for i := 0; i < 53; i++ {
		M1 := E0 - e*math.Sin(E0)
		if M-M1 < 0 {
			E0 -= d
		} else {
			E0 += d
		}
		d *= .5
	}
	if f < 0 {
		return -E0
	}
	return E0
}
Ejemplo n.º 28
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.
//
// 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
}
Ejemplo n.º 29
0
// Apparent returns apparent sidereal time at Greenwich for the given JD.
//
// Apparent is mean plus the nutation in right ascension.
//
// The result is in seconds of time and is in the range [0,86400).
func Apparent(jd float64) float64 {
	s := mean(jd)                       // seconds of time
	n := nutation.NutationInRA(jd)      // angle (radians) of RA
	ns := n * 3600 * 180 / math.Pi / 15 // convert RA to time in seconds
	return base.PMod(s+ns, 86400)
}
Ejemplo n.º 30
0
// Mean0UT returns mean sidereal time at Greenwich at 0h UT on the given JD.
//
// The result is in seconds of time and is in the range [0,86400).
func Mean0UT(jd float64) float64 {
	s, _ := mean0UT(jd)
	return base.PMod(s, 86400)
}