97 lines
3.1 KiB
Go
97 lines
3.1 KiB
Go
|
|
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
|
|||
|
|
}
|