astro/basic/orbit_elements.go

97 lines
3.1 KiB
Go
Raw Normal View History

package basic
import "math"
const (
orbitReferenceJD = 2451545.0
gaussianGravitationalConstant = 0.01720209895 // rad/day
lightTimeDaysPerAU = 0.0057755183
orbitParabolicTolerance = 1e-12
)
// OrbitElements 日心二体圆锥曲线根数,参考系为 J2000 平黄道/平春分点。
// EpochJD 与 TpJD 使用 TT/TDB 对应的儒略日。
//
// 两种输入形式:
// 1. 椭圆经典根数A/E/I/Omega/W/M0原有形式
// 2. 近日点形式Q/E/I/Omega/W/TpJD用于高偏心、抛物或双曲轨道
//
// 线性 rates 仅作用于经典根数形式,单位均为“每天变化量”。
type OrbitElements struct {
EpochJD float64
A float64 // 半长径 / semi-major axis in AU.
E float64 // 离心率 / eccentricity.
I float64 // 轨道倾角 / inclination in degrees.
Omega float64 // 升交点黄经 / longitude of ascending node in degrees.
W float64 // 近日点幅角 / argument of perihelion in degrees.
M0 float64 // 历元平近点角 / mean anomaly at epoch in degrees.
Q float64 // 近日点距离 / perihelion distance in AU.
TpJD float64 // 近日点通过时刻 / perihelion passage TT/TDB Julian day.
ADot float64 // 半长径日变化 / daily rate of A in AU/day.
EDot float64 // 离心率日变化 / daily rate of E per day.
IDot float64 // 倾角日变化 / daily rate of I in deg/day.
OmegaDot float64 // 升交点黄经日变化 / daily rate of Omega in deg/day.
WDot float64 // 近日点幅角日变化 / daily rate of W in deg/day.
MDot float64 // 平近点角日变化 / daily rate of M in deg/day.
}
func (elements OrbitElements) usesPerihelionForm() bool {
return isFinitePositive(elements.Q) && isFinite(elements.TpJD)
}
func (elements OrbitElements) validOrientation() bool {
angles := [...]float64{elements.I, elements.Omega, elements.W}
for _, angle := range angles {
if !isFinite(angle) {
return false
}
}
return true
}
func (elements OrbitElements) validEllipticClassical() bool {
if !isFinite(elements.EpochJD) || !isFinitePositive(elements.A) {
return false
}
if !isFinite(elements.E) || elements.E < 0 || elements.E >= 1 {
return false
}
if !isFinite(elements.M0) {
return false
}
return elements.validOrientation()
}
func (elements OrbitElements) validPerihelionForm() bool {
if !elements.usesPerihelionForm() {
return false
}
if !isFinite(elements.E) || elements.E < 0 {
return false
}
return elements.validOrientation()
}
func orbitElementsAt(jd float64, elements OrbitElements) OrbitElements {
if elements.usesPerihelionForm() || !isFinite(jd) || !isFinite(elements.EpochJD) {
return elements
}
deltaDays := jd - elements.EpochJD
updated := elements
updated.A += updated.ADot * deltaDays
updated.E += updated.EDot * deltaDays
updated.I += updated.IDot * deltaDays
updated.Omega += updated.OmegaDot * deltaDays
updated.W += updated.WDot * deltaDays
return updated
}
func isFinite(value float64) bool {
return !(math.IsNaN(value) || math.IsInf(value, 0))
}
func isFinitePositive(value float64) bool {
return isFinite(value) && value > 0
}