astro/basic/orbit_elements.go
starainrt 3ffdbe0034
feat: 扩展天文计算能力
- 新增日食、月食、本地可见性、中心线、半影区域、SVG 图示与沙罗周期信息
- 新增行星冲合、留、方照、物理星历、视直径、相位、亮肢角、轨道节点等计算
- 新增木星伽利略卫星位置、现象与接触事件计算
- 新增恒星星表、星座判定、自行修正与观测辅助能力
- 新增 coord、formula、orbit、sundial、lite/sun、lite/moon 等扩展包
- 完善农历年号、月相英文别名、视差角、大气质量、折射、日晷与双星计算
- 增加 NASA、JPL Horizons、IMCCE 等回归测试数据与基线测试
- 重构基础算法文件组织,补充大量公开 API 注释和语义回归测试
- 更新中文和英文 README,补充示例、精度说明、SVG 配图
2026-05-01 22:38:44 +08:00

97 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}