Пример #1
0
// 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.
//
// 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 of day and are in the range [0,86400).
func Times(p globe.Coord, ΔT unit.Time, h0 unit.Angle, Th0 unit.Time, α3 []unit.RA, δ3 []unit.Angle) (tRise, tTransit, tSet unit.Time, err error) {
	tRise, tTransit, tSet, err = ApproxTimes(p, h0, Th0, α3[1], δ3[1])
	if err != nil {
		return
	}
	αf := make([]float64, 3)
	for i, α := range α3 {
		αf[i] = α.Rad()
	}
	δf := make([]float64, 3)
	for i, δ := range δ3 {
		δf[i] = δ.Rad()
	}
	var d3α, d3δ *interp.Len3
	d3α, err = interp.NewLen3(-86400, 86400, αf)
	if err != nil {
		return
	}
	d3δ, err = interp.NewLen3(-86400, 86400, δf)
	if err != nil {
		return
	}
	// adjust tTransit
	{
		th0 := (Th0 + tTransit.Mul(360.985647/360)).Mod1()
		α := d3α.InterpolateX((tTransit + ΔT).Sec())
		// local hour angle as Time
		H := th0 - unit.TimeFromRad(p.Lon.Rad()+α)
		tTransit -= H
	}
	// adjust tRise, tSet
	sLat, cLat := p.Lat.Sincos()
	adjustRS := func(m unit.Time) (unit.Time, error) {
		th0 := (Th0 + m.Mul(360.985647/360)).Mod1()
		ut := (m + ΔT).Sec()
		α := d3α.InterpolateX(ut)
		δ := d3δ.InterpolateX(ut)
		Hrad := th0.Rad() - p.Lon.Rad() - α
		sδ, cδ := math.Sincos(δ)
		sH, cH := math.Sincos(Hrad)
		h := math.Asin(sLat*sδ + cLat*cδ*cH)
		md := (unit.TimeFromRad(h) - h0.Time()).Div(cδ * cLat * sH)
		return m + md, nil
	}
	tRise, err = adjustRS(tRise)
	if err != nil {
		return
	}
	tSet, err = adjustRS(tSet)
	return
}
Пример #2
0
// MinSepRect returns the minimum separation between two moving objects.
//
// Like MinSep, but using a method of rectangular coordinates that gives
// accurate results even for close approaches.
func MinSepRect(jd1, jd3 float64, r1, d1, r2, d2 []float64) (float64, error) {
	if len(r1) != 3 || len(d1) != 3 || len(r2) != 3 || len(d2) != 3 {
		return 0, interp.ErrorNot3
	}
	uv := func(r1, d1, r2, d2 float64) (u, v float64) {
		sd1, cd1 := math.Sincos(d1)
		Δr := r2 - r1
		tΔr := math.Tan(Δr)
		thΔr := math.Tan(Δr / 2)
		K := 1 / (1 + sd1*sd1*tΔr*thΔr)
		sΔd := math.Sin(d2 - d1)
		u = -K * (1 - (sd1/cd1)*sΔd) * cd1 * tΔr
		v = K * (sΔd + sd1*cd1*tΔr*thΔr)
		return
	}
	us := make([]float64, 3, 6)
	vs := us[3:6]
	for x, r := range r1 {
		us[x], vs[x] = uv(r, d1[x], r2[x], d2[x])
	}
	u3, err := interp.NewLen3(-1, 1, us)
	if err != nil {
		panic(err) // bug not caller's fault.
	}
	v3, err := interp.NewLen3(-1, 1, vs)
	if err != nil {
		panic(err) // bug not caller's fault.
	}
	up0 := (us[2] - us[0]) / 2
	vp0 := (vs[2] - vs[0]) / 2
	up1 := us[0] + us[2] - 2*us[1]
	vp1 := vs[0] + vs[2] - 2*vs[1]
	up := up0
	vp := vp0
	dn := -(us[1]*up + vs[1]*vp) / (up*up + vp*vp)
	n := dn
	var u, v float64
	for limit := 0; limit < 10; limit++ {
		u = u3.InterpolateN(n)
		v = v3.InterpolateN(n)
		if math.Abs(dn) < 1e-5 {
			return math.Hypot(u, v), nil // success
		}
		up := up0 + n*up1
		vp := vp0 + n*vp1
		dn = -(u*up + v*vp) / (up*up + vp*vp)
		n += dn
	}
	return 0, errors.New("MinSepRect: failure to converge")
}
Пример #3
0
func ExampleLen3_Zero() {
	// Example 3.c, p. 26.
	x1 := 26.
	x3 := 28.
	// the y unit doesn't matter.  working in degrees is fine
	yTable := []float64{
		base.DMSToDeg(true, 0, 28, 13.4),
		base.DMSToDeg(false, 0, 6, 46.3),
		base.DMSToDeg(false, 0, 38, 23.2),
	}
	d3, err := interp.NewLen3(x1, x3, yTable)
	if err != nil {
		fmt.Println(err)
		return
	}
	x, err := d3.Zero(false)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("February %.5f\n", x)
	i, frac := math.Modf(x)
	fmt.Printf("February %d, at %.62s TD",
		int(i), base.NewFmtTime(frac*24*3600))
	// Output:
	// February 26.79873
	// February 26, at 19ʰ10ᵐ TD
}
Пример #4
0
func ExampleLen3_Zero() {
	// Example 3.c, p. 26.
	x1 := 26.
	x3 := 28.
	// the y unit doesn't matter.  working in degrees is fine
	yTable := []float64{
		unit.FromSexa('-', 0, 28, 13.4),
		unit.FromSexa(' ', 0, 6, 46.3),
		unit.FromSexa(' ', 0, 38, 23.2),
	}
	d3, err := interp.NewLen3(x1, x3, yTable)
	if err != nil {
		fmt.Println(err)
		return
	}
	x, err := d3.Zero(false)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("February %.5f\n", x)
	i, frac := math.Modf(x)
	fmt.Printf("February %d, at %m TD",
		int(i), sexa.FmtTime(unit.TimeFromDay(frac)))
	// Output:
	// February 26.79873
	// February 26, at 19ʰ10ᵐ TD
}
Пример #5
0
func ExampleLen3_Extremum() {
	// Example 3.b, p. 26.
	d3, err := interp.NewLen3(12, 20, []float64{
		1.3814294,
		1.3812213,
		1.3812453,
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	x, y, err := d3.Extremum()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("distance:  %.7f AU\n", y)
	fmt.Printf("date:     %.4f\n", x)
	i, frac := math.Modf(x)
	fmt.Printf("1992 May %d, at %.64s TD",
		int(i), base.NewFmtTime(frac*24*3600))
	// Output:
	// distance:  1.3812030 AU
	// date:     17.5864
	// 1992 May 17, at 14ʰ TD
}
Пример #6
0
// 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
}
Пример #7
0
func ap2a(j1, d float64, a bool, v *pp.V87Planet) (jde, r float64) {
	// Meeus doesn't give a complete algorithm for finding accurate answers.
	// The algorithm here starts with the approximate result algorithm
	// then crawls along the curve at resultion d until three points
	// are found containing the desired extremum.  It's slow if the starting
	// point is far away (the case of Neptune) or if high accuracy is
	// demanded.  1 day accuracy is generally quick.
	j0 := j1 - d
	j2 := j1 + d
	rr := make([]float64, 3)
	_, _, rr[0] = v.Position2000(j0)
	_, _, rr[1] = v.Position2000(j1)
	_, _, rr[2] = v.Position2000(j2)
	for {
		if a {
			if rr[1] > rr[0] && rr[1] > rr[2] {
				break
			}
		} else {
			if rr[1] < rr[0] && rr[1] < rr[2] {
				break
			}
		}
		if rr[0] < rr[2] == a {
			j0 = j1
			j1 = j2
			j2 += d
			rr[0] = rr[1]
			rr[1] = rr[2]
			_, _, rr[2] = v.Position2000(j2)
		} else {
			j2 = j1
			j1 = j0
			j0 -= d
			rr[2] = rr[1]
			rr[1] = rr[0]
			_, _, rr[0] = v.Position2000(j0)
		}
	}
	l, err := interp.NewLen3(j0, j2, rr)
	if err != nil {
		panic(err) // unexpected.
	}
	jde, r, err = l.Extremum()
	if err != nil {
		panic(err) // unexpected.
	}
	return
}
Пример #8
0
// MinSep returns the minimum separation between two moving objects.
//
// The motion is represented as an ephemeris of three rows, equally spaced
// in time.  Jd1, jd3 are julian day times of the first and last rows.
// R1, d1, r2, d2 are coordinates at the three times.  They must each be
// slices of length 3.
//
// Result is obtained by computing separation at each of the three times
// and interpolating a minimum.  This may be invalid for sufficiently close
// approaches.
func MinSep(jd1, jd3 float64, r1, d1, r2, d2 []float64) (float64, error) {
	if len(r1) != 3 || len(d1) != 3 || len(r2) != 3 || len(d2) != 3 {
		return 0, interp.ErrorNot3
	}
	y := make([]float64, 3)
	for x, r := range r1 {
		y[x] = Sep(r, d1[x], r2[x], d2[x])
	}
	d3, err := interp.NewLen3(jd1, jd3, y)
	if err != nil {
		return 0, err
	}
	_, dMin, err := d3.Extremum()
	return dMin, err
}
Пример #9
0
func ExampleLen3_InterpolateX() {
	// Example 3.a, p. 25.
	d3, err := interp.NewLen3(7, 9, []float64{
		.884226,
		.877366,
		.870531,
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	x := 8 + base.NewTime(false, 4, 21, 0).Day() // 8th day at 4:21
	y := d3.InterpolateX(x)
	fmt.Printf("%.6f\n", y)
	// Output:
	// 0.876125
}
Пример #10
0
func ExampleLen5_Zero() {
	// Exercise, p. 30.
	x1 := 25.
	x5 := 29.
	yTable := []float64{
		base.DMSToDeg(true, 1, 11, 21.23),
		base.DMSToDeg(true, 0, 28, 12.31),
		base.DMSToDeg(false, 0, 16, 07.02),
		base.DMSToDeg(false, 1, 01, 00.13),
		base.DMSToDeg(false, 1, 45, 46.33),
	}
	d5, err := interp.NewLen5(x1, x5, yTable)
	if err != nil {
		fmt.Println(err)
		return
	}
	z, err := d5.Zero(false)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("1988 January %.6f\n", z)
	zInt, zFrac := math.Modf(z)
	fmt.Printf("1988 January %d at %.62s TD\n", int(zInt),
		base.NewFmtTime(zFrac*24*3600))

	// compare result to that from just three central values
	d3, err := interp.NewLen3(26, 28, yTable[1:4])
	if err != nil {
		fmt.Println(err)
		return
	}
	z3, err := d3.Zero(false)
	if err != nil {
		fmt.Println(err)
		return
	}
	dz := z - z3
	fmt.Printf("%.6f day\n", dz)
	fmt.Printf("%.1f minute\n", dz*24*60)
	// Output:
	// 1988 January 26.638587
	// 1988 January 26 at 15ʰ20ᵐ TD
	// 0.000753 day
	// 1.1 minute
}
Пример #11
0
func ExampleLen3_InterpolateN() {
	// Example 3.a, p. 25.
	d3, err := interp.NewLen3(7, 9, []float64{
		.884226,
		.877366,
		.870531,
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	n := 4.35 / 24
	y := d3.InterpolateN(n)
	fmt.Printf("%.6f\n", y)
	// Output:
	// 0.876125
}
Пример #12
0
func ExampleLen3_Zero_strong() {
	// Example 3.d, p. 27.
	x1 := -1.
	x3 := 1.
	yTable := []float64{-2, 3, 2}
	d3, err := interp.NewLen3(x1, x3, yTable)
	if err != nil {
		fmt.Println(err)
		return
	}
	x, err := d3.Zero(true)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%.12f\n", x)
	// Output:
	// -0.720759220056
}
Пример #13
0
func ap2a(j1, d float64, a bool, v *pp.V87Planet) (jde, r float64) {
	j0 := j1 - d
	j2 := j1 + d
	rr := make([]float64, 3)
	_, _, rr[0] = v.Position2000(j0)
	_, _, rr[1] = v.Position2000(j1)
	_, _, rr[2] = v.Position2000(j2)
	for {
		if a {
			if rr[1] > rr[0] && rr[1] > rr[2] {
				break
			}
		} else {
			if rr[1] < rr[0] && rr[1] < rr[2] {
				break
			}
		}
		if rr[0] < rr[2] == a {
			j0 = j1
			j1 = j2
			j2 += d
			rr[0] = rr[1]
			rr[1] = rr[2]
			_, _, rr[2] = v.Position2000(j2)
		} else {
			j2 = j1
			j1 = j0
			j0 -= d
			rr[2] = rr[1]
			rr[1] = rr[0]
			_, _, rr[0] = v.Position2000(j0)
		}
	}
	l, err := interp.NewLen3(j0, j2, rr)
	if err != nil {
		panic(err) // unexpected.
	}
	jde, r, err = l.Extremum()
	if err != nil {
		panic(err) // unexpected.
	}
	return
}
Пример #14
0
func ExampleLen3_InterpolateN() {
	// Example 3.a, p. 25.
	d3, err := interp.NewLen3(7, 9, []float64{
		.884226,
		.877366,
		.870531,
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	h := unit.FromSexa(0, 4, 21, 0)
	fmt.Println(h, "hours")
	n := h / 24
	y := d3.InterpolateN(n)
	fmt.Printf("%.6f\n", y)
	// Output:
	// 4.35 hours
	// 0.876125
}