Files
astro/doc/manual/orbit.md
T
b612 16c62a97d5 feat: 完善时标与天象几何计算并扩展输出接口
- 新增时标、ΔT 模型、质心时间与 UT1 支持
- 改进日月食、月掩、行星事件及路径边界计算
- 完善恒星三维自行与动态距离传播
- 扩展 SVG、GeoJSON、KML 输出与底层距离换算工具
- 整理中英文手册、示例资源及回归测试
2026-09-23 18:55:12 +08:00

442 lines
22 KiB
Markdown
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.
# 通用小天体轨道
[English](en/orbit.md) | [返回 README](../../README.md)
`orbit` 包用于按日心二体轨道根数传播天体位置,支持小行星、彗星、矮行星和自定义假想轨道。七大行星仍由各行星包使用内置 VSOP87 解析项计算。
`orbit.Elements` 支持两种常见写法:
- 经典椭圆根数:`A/E/I/Omega/W/M0`
- 近日点形式:`Q/E/I/Omega/W/TpJD`,适合彗星和高偏心率轨道
`orbit.Elements` 的参考系固定为 J2000 平黄道/平春分点。
站心与升落接口的经度东正西负、纬度北正南负、椭球高单位米;位置与站心量也能与[恒星](star.md#恒星)、[坐标工具](coord.md#坐标工具)手册里的接口配合使用。
## 目录
- [用轨道根数计算谷神星位置](#用轨道根数计算谷神星位置)
- [API 参考](#api-参考)
- [轨道根数](#轨道根数)
- [位置](#位置)
- [几何量](#几何量)
- [升落与中天](#升落与中天)
- [测光](#测光)
- [视双星](#视双星)
- [常用场景](#常用场景)
- [按位置层次取小行星坐标](#按位置层次取小行星坐标)
- [今晚会不会升起、现在多高](#今晚会不会升起现在多高)
- [距日距地、相位角与 H-G 视星等](#距日距地相位角与-h-g-视星等)
- [轨道类型与位置层次](#轨道类型与位置层次)
- [参数与返回值约定](#参数与返回值约定)
- [位置层次](#位置层次)
- [单位与坐标口径](#单位与坐标口径)
- [时标与输入格式](#时标与输入格式)
- [零值与越界](#零值与越界)
- [精度与适用范围](#精度与适用范围)
- [常见误用](#常见误用)
- [相关手册](#相关手册)
## 用轨道根数计算谷神星位置
```go
package main
import (
"fmt"
"log"
"time"
"b612.me/astro/orbit"
)
func main() {
cst := time.FixedZone("CST", 8*3600)
when := time.Date(2025, 11, 21, 20, 0, 0, 0, cst)
ceres := orbit.Elements{
EpochJD: 2461000.5, A: 2.765615651508659, E: 0.07957631994408416,
I: 10.58788658206854, Omega: 80.24963090816965,
W: 73.29975464616518, M0: 231.5397330043706,
}
pos := orbit.ApparentGeocentricEquatorial(when, ceres)
fmt.Printf("RA=%.6f Dec=%.6f deg distance=%.6f AU\n", pos.RA, pos.Dec, pos.Distance)
rise, err := orbit.RiseTime(when, ceres, 121.4737, 31.2304, 20, true)
if err != nil {
log.Fatal(err)
}
fmt.Println(rise.Format(time.RFC3339))
}
```
根数使用 J2000 平黄道参考系,历元为 TT/TDB 儒略日。这里是日心二体传播;长时间跨度或近距离掠过行星时,摄动误差需要另外评估。
## API 参考
### 轨道根数
| 名称 | 用途 | 单位与口径 |
| --- | --- | --- |
| `Elements` | 日心二体圆锥曲线根数 | `EpochJD`/`TpJD` 为 TT/TDB 儒略日;`A`/`Q` 为 AU,`I`/`Omega`/`W`/`M0` 为度,`E` 无量纲;`ADot`…`MDot` 为每天变化量,只作用于经典椭圆形式 |
| `MeanMotion` | 平均角速度 | 度/日;抛物线与双曲线返回 `NaN`;`MDot` 非零时直接取它 |
| `MeanAnomaly` | 平近点角 | 度(`[0,360)`);抛物线与双曲线返回 `NaN` |
| `TrueAnomaly` | 真近点角 | 度(`[0,360)`);椭圆、抛物、双曲线都有解,根数非法时返回 `NaN` |
平近点角与真近点角按同一组根数求解,`MDot` 可以替代默认平均角速度:
```go
fmt.Println(orbit.MeanMotion(ceres), orbit.MeanAnomaly(when, ceres), orbit.TrueAnomaly(when, ceres))
// 抛物线与双曲线只能走近日点形式,平均角速度与平近点角没有定义。
parabolic := orbit.Elements{Q: 0.9, E: 1, I: 30, Omega: 40, W: 50, TpJD: 2461000.5}
hyperbolic := orbit.Elements{Q: 1.2, E: 1.05, I: 30, Omega: 40, W: 50, TpJD: 2461000.5}
fmt.Println(orbit.MeanMotion(parabolic), orbit.MeanAnomaly(when, parabolic))
fmt.Println(orbit.TrueAnomaly(when, parabolic), orbit.TrueAnomaly(when, hyperbolic))
```
完整示例同时给出椭圆根数与近日点根数两条链路:
```go
package main
import (
"fmt"
"time"
"b612.me/astro/orbit"
)
func main() {
// 1 Ceres 的一组经典椭圆根数,参考系为 J2000 平黄道/平春分点。
ceres := orbit.Elements{
EpochJD: 2461000.5,
A: 2.765615651508659,
E: 0.07957631994408416,
I: 10.58788658206854,
Omega: 80.24963090816965,
W: 73.29975464616518,
M0: 231.5397330043706,
}
ceresPos := orbit.ApparentGeocentricEquatorial(
time.Date(2025, 11, 12, 0, 0, 0, 0, time.UTC),
ceres,
)
fmt.Printf("ceres ra=%.6f dec=%.6f distance=%.6f\n", ceresPos.RA, ceresPos.Dec, ceresPos.Distance)
// 哈雷彗星示例:用近日点距离 Q 和近日点通过时刻 TpJD 描述。
halley := orbit.Elements{
Q: 0.5870992,
E: 0.9671429,
I: 162.26269,
Omega: 58.42008,
W: 111.33249,
TpJD: 2446467.395,
}
halleyPos := orbit.ApparentGeocentricEquatorial(
time.Date(1986, 2, 9, 0, 0, 0, 0, time.UTC),
halley,
)
fmt.Printf("halley ra=%.6f dec=%.6f distance=%.6f\n", halleyPos.RA, halleyPos.Dec, halleyPos.Distance)
}
```
输出结果:
```text
ceres ra=7.739532 dec=-10.625981 distance=2.164391
halley ra=312.112360 dec=-11.826451 distance=1.533936
```
轨道根数本身有历元,离历元越远,静态根数误差越明显。若数据源提供 `ADot/EDot/IDot/OmegaDot/WDot/MDot` 这类长期线性变化率,也可以填入 `Elements`,用于减轻中长期漂移。
### 位置
| 名称 | 用途 | 单位与口径 |
| --- | --- | --- |
| `EclipticPosition` | 黄道球坐标返回值 | `Lon`/`Lat` 度,`Distance` AU |
| `EquatorialPosition` | 赤道球坐标返回值 | `RA`/`Dec` 度,`Distance` AU |
| `HeliocentricEclipticJ2000` | 日心 J2000 平黄道 | 几何量,不加光行时 |
| `HeliocentricEcliptic` | 日心历元黄道 | 几何量,参考系为当日平分点 |
| `GeocentricEclipticJ2000` | 地心 J2000 平黄道 | 几何量,地球与目标同取该时刻位置 |
| `GeocentricEcliptic` | 地心历元黄道 | 几何量,参考系为当日平分点 |
| `GeocentricEquatorialJ2000` | 地心 J2000 平赤道 | 几何量,黄赤交角用 J2000 值 |
| `GeocentricEquatorial` | 地心历元平赤道 | 几何量,黄赤交角取当日值 |
| `AstrometricGeocentricEquatorialJ2000` | 地心测算 J2000 赤道 | 在几何量上加光行时,可与 J2000 星表直接比对 |
| `ApparentGeocentricEcliptic` | 地心视黄道 | 光行时 + 章动,不含完整光行差 |
| `ApparentGeocentricEquatorial` | 地心视赤道 | 光行时 + 章动,不含完整光行差 |
| `ApparentTopocentricEquatorial` | 站心视赤道 | 在视赤道上再叠加站心视差修正 |
同一时刻沿"几何 → 光行时 → 章动 → 站心"逐层加码:
```go
h := orbit.HeliocentricEcliptic(when, ceres) // 日心历元黄道,几何量
g := orbit.GeocentricEquatorialJ2000(when, ceres) // 地心 J2000 平赤道
a := orbit.ApparentGeocentricEquatorial(when, ceres) // 地心视赤道
t := orbit.ApparentTopocentricEquatorial(when, ceres, 121.4737, 31.2304, 20)
e := orbit.ApparentGeocentricEcliptic(when, ceres)
fmt.Printf("h=%.6f %.6f %.6f\n", h.Lon, h.Lat, h.Distance)
fmt.Printf("g=%.6f %.6f %.6f\n", g.RA, g.Dec, g.Distance)
fmt.Printf("a=%.6f %.6f t=%.6f %.6f e=%.6f\n", a.RA, a.Dec, t.RA, t.Dec, e.Lon)
```
`...J2000` 与不带后缀的历元量是两套参考系:前者固定到 J2000 平黄道/平春分点,适合与星表比对和长期存档;后者使用当日平黄道/平春分点,适合表达“当天天空”。地心量里的 `Distance` 在几何接口上是该时刻的瞬时距离,在 `Astrometric...` 上是光行时收敛后的距离,两者相差约光行时对应的位移。
### 几何量
| 名称 | 用途 | 单位与口径 |
| --- | --- | --- |
| `SunDistance` | 日心距离 | AU,几何量 |
| `EarthDistance` | 地心距离 | AU,几何量 |
| `Elongation` | 日距角 | 度,地心视方向上的角距 |
| `PhaseAngle` | 相位角 | 度,0° 为全亮面朝向观测者 |
| `IlluminatedFraction` | 被照亮比例 | 无量纲,通常落在 `[0,1]` |
| `Phase` | 被照亮比例别名 | 与 `IlluminatedFraction` 同义 |
| `ParallacticAngle` | 视差角(天顶方向角) | 度,时角与赤纬取自同一次站心求解 |
`orbit` 也提供了常见观测几何量和轻量测光接口:
```go
r := orbit.SunDistance(when, ceres) // 日心距离
delta := orbit.EarthDistance(when, ceres) // 地心距离
elong := orbit.Elongation(when, ceres) // 日距角
phase := orbit.PhaseAngle(when, ceres) // 相位角
k := orbit.IlluminatedFraction(when, ceres) // 被照亮比例
mag := orbit.AsteroidMagnitudeHG(when, ceres, 3.34, 0.12) // H-G 视星等
q := orbit.ParallacticAngle(when, ceres, 121.4737, 31.2304, 20) // 站心视差角
fmt.Printf("r=%.6f delta=%.6f elong=%.6f phase=%.6f k=%.6f mag=%.3f q=%.6f\n",
r, delta, elong, phase, k, mag, q)
```
日距角接近 180° 时相位角接近 0°,`IlluminatedFraction` 接近 1;这三个量都由同一组地心几何推出。
`ParallacticAngle` 不另求赤纬,它和 `HourAngle` 复用同一次站心求解,避免时角与赤纬来自两条相差约 1 ULP 的儒略日路径而引入亚纳度漂移。几何量都只依赖 `date` 的绝对时刻,不含观测者参数;含站心参数的只有 `ParallacticAngle` 一个。
### 升落与中天
| 名称 | 用途 | 单位与口径 |
| --- | --- | --- |
| `Altitude` | 视高度角 | 度,站心视位置与观测者当地民用时刻 |
| `Zenith` | 天顶距 | 度,等于 `90 - Altitude` |
| `Azimuth` | 视方位角 | 度,正北 0°、向东增加 |
| `HourAngle` | 站心视时角 | 度 |
| `CulminationTime` | 中天时刻 | `time.Time`,保持输入 `date` 的时区 |
| `RiseTime` | 升起时刻 | `(time.Time, error)`,第二返回值为哨兵错误 |
| `SetTime` | 落下时刻 | `(time.Time, error)`,第二返回值为哨兵错误 |
| `ERR_ORBIT_NEVER_RISE` | 目标当日永不升起的哨兵错误 | 由 `RiseTime` 返回 |
| `ERR_ORBIT_NEVER_SET` | 目标当日永不落下的哨兵错误 | 由 `SetTime` 返回 |
```go
fmt.Println(orbit.Zenith(when, ceres, 121.4737, 31.2304, 20))
fmt.Println(orbit.HourAngle(when, ceres, 121.4737, 31.2304, 20))
fmt.Println(orbit.CulminationTime(when, ceres, 121.4737, 31.2304, 20).Format(time.RFC3339))
day := time.Date(2025, 11, 21, 0, 0, 0, 0, site)
set, err := orbit.SetTime(day, ceres, 121.4737, 31.2304, 20, true)
if errors.Is(err, orbit.ERR_ORBIT_NEVER_SET) {
fmt.Println("当日不落", set)
}
```
已有轨道根数时,也可以把它当作一个“可观测目标”来求站心观测量:
```go
site := time.FixedZone("CST", 8*3600)
when := time.Date(2025, 11, 21, 20, 0, 0, 0, site)
alt := orbit.Altitude(when, ceres, 121.4737, 31.2304, 20) // 视高度角
az := orbit.Azimuth(when, ceres, 121.4737, 31.2304, 20) // 视方位角
rise, _ := orbit.RiseTime(time.Date(2025, 11, 21, 0, 0, 0, 0, site), ceres, 121.4737, 31.2304, 20, true) // 升起时刻
fmt.Printf("alt=%.6f az=%.6f rise=%s\n", alt, az, rise.Format(time.RFC3339))
```
这些观测接口基于站心视坐标计算,适合直接拿去做小行星、彗星或自定义二体目标的升落和指向辅助。
`aero` 为假时判据是几何地平线,为真时把目标高度取到 `-0.5667°` 并叠加依椭球高、纬度算出的地平俯角。`RiseTime`/`SetTime` 的第二个返回值是真正的错误:只有当日确实没有升/落才映射成 `ERR_ORBIT_NEVER_RISE` / `ERR_ORBIT_NEVER_SET`,其余失败原样透传。
### 测光
| 名称 | 用途 | 单位与口径 |
| --- | --- | --- |
| `AsteroidMagnitudeHG` | 小行星 H-G 模型视星等 | `absoluteMagnitude` 为绝对星等 H,`slopeParameter` 为斜率参数 G;无单位 |
```go
fmt.Printf("H-G magnitude=%.3f\n", orbit.AsteroidMagnitudeHG(when, ceres, 3.34, 0.12))
fmt.Printf("r=%.6f delta=%.6f elong=%.6f\n",
orbit.SunDistance(when, ceres), orbit.EarthDistance(when, ceres), orbit.Elongation(when, ceres))
fmt.Printf("phase=%.6f k=%.6f k2=%.6f\n",
orbit.PhaseAngle(when, ceres), orbit.IlluminatedFraction(when, ceres), orbit.Phase(when, ceres))
```
H-G 模型只用日心距、地心距和相位角,不引入目标的半径、反照率或自转;`G` 的取值由外部星表给出,本包不做默认值填充。
### 视双星
| 名称 | 用途 | 单位与口径 |
| --- | --- | --- |
| `VisualBinaryElements` | 视双星轨道要素 | `PeriodYears` 平太阳年,`PeriastronYear` 带小数的年,`SemiMajorAxis` 角秒,`Inclination`/`AscendingNode`/`PeriastronArgument` 度,`Eccentricity` 无量纲 |
| `VisualBinaryPosition` | 视双星计算结果 | `MeanAnomaly`/`EccentricAnomaly`/`TrueAnomaly`/`PositionAngle` 度,`Radius`/`Separation` 角秒 |
| `VisualBinary` | 按时刻求视双星位置 | 先把时刻换算为 UTC 小数年,再套经典视轨道公式 |
| `VisualBinaryByYear` | 按小数年求视双星位置 | 直接给小数年,跳过时刻换算 |
```go
gammaVir := orbit.VisualBinaryElements{
PeriodYears: 171.37, PeriastronYear: 1836.433, Eccentricity: 0.8808,
SemiMajorAxis: 3.746, Inclination: 146.05, AscendingNode: 31.78, PeriastronArgument: 252.88,
}
vb := orbit.VisualBinaryByYear(2026.0, gammaVir)
fmt.Printf("theta=%.6f rho=%.6f M=%.6f\n", vb.PositionAngle, vb.Separation, vb.MeanAnomaly)
```
`orbit` 里还带了一个视双星求解器,直接按《天文算法》第 55 章的经典表观轨道公式输出位置角和角距:
```go
gammaVir := orbit.VisualBinaryElements{
PeriodYears: 171.37,
PeriastronYear: 1836.433,
Eccentricity: 0.8808,
SemiMajorAxis: 3.746,
Inclination: 146.05,
AscendingNode: 31.78,
PeriastronArgument: 252.88,
}
vb := orbit.VisualBinary(time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC), gammaVir)
fmt.Printf("theta=%.6f rho=%.6f\n", vb.PositionAngle, vb.Separation) // 位置角与角距
```
位置角按北为 0°、东为 90° 度量,角距离与径矢 `Radius` 的单位都是角秒。
## 常用场景
### 按位置层次取小行星坐标
```go
helio := orbit.HeliocentricEcliptic(when, ceres)
geo := orbit.GeocentricEclipticJ2000(when, ceres)
ast := orbit.AstrometricGeocentricEquatorialJ2000(when, ceres)
app := orbit.ApparentGeocentricEquatorial(when, ceres)
fmt.Println(helio.Lon, helio.Lat, helio.Distance)
fmt.Println(geo.Lon, geo.Lat, geo.Distance)
fmt.Println(ast.RA, ast.Dec)
fmt.Println(app.RA, app.Dec, app.Distance)
```
```text
19.251489 -9.315340 2.912174
2.147652 -12.026350 2.262445
6.795211 -10.172420
7.125008 -10.028726 2.262489
```
四个层次含义不同:`Heliocentric*` 是相对太阳的位置(第一个数就是日心距),`Geocentric*J2000` 是 J2000 口径的地心位置,`Astrometric*J2000` 去掉光行时、适合与星表对表,`Apparent*` 是当日视位置、观测与出图用它。需要站心视位置用 `ApparentTopocentricEquatorial(when, ceres, lon, lat, height)`。
### 今晚会不会升起、现在多高
```go
fmt.Println(orbit.RiseTime(when, ceres, 121.4737, 31.2304, 20, true))
fmt.Println(orbit.CulminationTime(when, ceres, 121.4737, 31.2304, 20))
fmt.Println(orbit.Altitude(when, ceres, 121.4737, 31.2304, 20),
orbit.Azimuth(when, ceres, 121.4737, 31.2304, 20))
```
```text
2025-11-21 14:41:48.913 CST <nil>
2025-11-21 20:19:34 CST
48.472628 172.699168
```
- `aero = true` 用蒙气差与视半径修正后的地平;`height` 是椭球高(米);经度东正西负。
- 环极或极区目标没有升落:`RiseTime`/`SetTime` 返回 `orbit.ERR_ORBIT_NEVER_RISE` / `ERR_ORBIT_NEVER_SET` 哨兵错误,用 `errors.Is` 判定。
### 距日距地、相位角与 H-G 视星等
```go
fmt.Println(orbit.SunDistance(when, ceres), orbit.EarthDistance(when, ceres))
fmt.Println(orbit.Elongation(when, ceres), orbit.PhaseAngle(when, ceres))
fmt.Println(orbit.IlluminatedFraction(when, ceres), orbit.AsteroidMagnitudeHG(when, ceres, 3.34, 0.12))
```
```text
2.912174 2.262445
122.264630 16.670089
0.978986 8.360
```
- `PhaseAngle` 是太阳-天体-地球夹角(度),`IlluminatedFraction` 是照明比例;`Phase` 只是 `IlluminatedFraction` 的别名,别把它当成相位角。
- H-G 视星等要传绝对星等 `H` 与斜率参数 `G`(示例用谷神星的 `3.34` 与 `0.12`)。
### 轨道类型与位置层次
```go
parabolic := orbit.Elements{Q: 0.9, E: 1, I: 30, Omega: 40, W: 50, TpJD: 2461000.5}
hyperbolic := orbit.Elements{Q: 1.2, E: 1.05, I: 30, Omega: 40, W: 50, TpJD: 2461000.5}
fmt.Println(orbit.MeanMotion(parabolic), orbit.MeanAnomaly(when, parabolic))
fmt.Println(orbit.TrueAnomaly(when, parabolic), orbit.TrueAnomaly(when, hyperbolic))
fmt.Println(orbit.MeanMotion(ceres))
```
```text
NaN NaN
0.817533 0.537610
0.21429712142765137
```
- 抛物线与双曲线只能走近日点形式(`Q` + `TpJD`):平均角速度与平近点角没有定义、返回 `NaN`,真近点角三种轨道都有解。
- 与外部星历对表时先统一位置层次与参考系(`Elements` 固定为 J2000 平黄道/平春分点);`ADot…WDot` 只作用于经典椭圆形式,`MDot` 非零时可直接替代默认平均角速度。
## 参数与返回值约定
### 位置层次
| 层次 | 代表接口 | 包含的改正 |
| --- | --- | --- |
| 日心几何 | `HeliocentricEcliptic` / `HeliocentricEclipticJ2000` | 无 |
| 地心几何 | `GeocentricEcliptic` / `GeocentricEclipticJ2000` / `GeocentricEquatorial` / `GeocentricEquatorialJ2000` | 减去地球日心位置 |
| 地心测算 | `AstrometricGeocentricEquatorialJ2000` | 光行时 |
| 地心视 | `ApparentGeocentricEcliptic` / `ApparentGeocentricEquatorial` | 光行时 + 章动 |
| 站心视 | `ApparentTopocentricEquatorial` 及全部升落接口 | 光行时 + 章动 + 站心视差 |
### 单位与坐标口径
- 角度一律用度,距离用 AU,站心与升落接口的椭球高用米,时间用 `time.Time`。
- `Elements` 的参考系是 J2000 平黄道/平春分点;`...J2000` 结尾的接口保持该参考系,其余 `HeliocentricEcliptic`/`GeocentricEcliptic`/`GeocentricEquatorial` 是历元(of date)量,换参考系时不要混用。
- 位置分三层:`Heliocentric*`/`Geocentric*` 是几何量,`AstrometricGeocentricEquatorialJ2000` 在几何量上加光行时(按距离迭代求解,上限 8 次、`1e-12` 天收敛),`Apparent*` 在光行时之上再加章动。仓库的行星口径就是“光行时 + 章动、不含完整外部光行差模型”,所以 `Apparent*` 与行星包同级,不应把它当成全项视位置。
- `MeanMotion`/`MeanAnomaly`/`TrueAnomaly` 输出度;`MeanMotion` 与 `MeanAnomaly` 对抛物线和双曲线没有定义。
### 时标与输入格式
- `EpochJD` 与 `TpJD` 都是 TT/TDB 儒略日;坐标、几何量与测光接口把 `date` 当绝对时刻处理(`date.UTC()` 后经 `UTC2TT` 换成 TT/TDB)。`UTC2TT` 在 1972-01-01 之前把民用时刻按 UT1 处理,窗口内使用内置闰秒表,闰秒表可用 `astro.SetTTMinusUTC` 覆盖。
- 瞬时站心量将 `date` 的当地字段与 `date.Zone()` 偏移一起换回绝对时刻。同一时刻用 UTC 或当地时区表示,所得位置相同。升落搜索还按当地日期选事件,因此应选择观测日历所用的时区。
- `CulminationTime`、`RiseTime`、`SetTime` 的结果保持输入 `date` 的时区,是民用时刻;三者内部在 `date.Hour() > 12` 时先回退 12 小时,以保持搜索锚点在所选日期内。
- 公开 API 的含 `time.Time` 输出一律是民用时刻(UTC 标签);UT1 与 TT 只出现在内部换算里,需要显式换算时用根包的 `astro.UT1FromUTC` / `astro.TTFromUTC`。
### 零值与越界
- `Elements` 零值不是合法轨道。经典椭圆形式要求 `A` 有限且为正、`E` 落在 `[0,1)`、`EpochJD` 与 `M0` 有限;`E >= 1` 的抛物线与双曲线只能走近日点形式,此时要求 `Q` 有限且为正、`TpJD` 有限、`E >= 0`,三个角度 `I`/`Omega`/`W` 都必须有限。
- `Q > 0` 且 `TpJD` 有限时优先按近日点形式解释,`A`/`M0`/`EpochJD` 被忽略;此时 `ADot`/`EDot`/`IDot`/`OmegaDot`/`WDot` 都不生效,只有 `MDot` 非零时会被当作平均角速度使用。
- 根数非法时 `MeanMotion`、`MeanAnomaly` 返回 `NaN`,位置接口返回三个 `NaN`;`AsteroidMagnitudeHG` 在输入非有限或日心距、地心距、相位角非正时返回 `NaN`,H-G 相位混合项为零时返回 `+Inf`。
- `RiseTime` 与 `SetTime` 在给定当地日内找不到升/落时返回哨兵错误 `ERR_ORBIT_NEVER_RISE` / `ERR_ORBIT_NEVER_SET`,其它失败原样透传;成功时第二个返回值为 `nil`。
- `VisualBinary` 与 `VisualBinaryByYear` 在 `PeriodYears <= 0`、`SemiMajorAxis <= 0`、`Eccentricity` 不落在 `[0,1)` 或任一要素非有限时,把 `VisualBinaryPosition` 的全部数值字段填成 `NaN`。
### 精度与适用范围
- `orbit` 是二体圆锥曲线传播:只含所给根数,不含行星摄动、非引力项与相对论改正;离历元越远,静态根数的误差越大,`ADot`…`WDot` 只能缓解线性漂移,不能替代重新拟合或数值积分。
- `Apparent*` 与站心量的差别只在几何与章动,不含大气折射;升落接口的 `aero=true` 才把地平折射算进判据(目标高度取 `-0.5667°`,再叠加依椭球高与纬度算出的地平俯角)。
- `RiseTime`/`SetTime` 内部用 `round(observerLon/15)` 的标称时区迭代升落几何,因此观测点经度最好落在时区中心附近;只调用一次求根,极区或拱极目标的边界情况以哨兵错误为准。
- 视双星求解器用的是《天文算法》第 55 章的经典视轨道公式,`Eccentricity >= 1` 时不适用;它只做几何投影,不含质量、光度或摄动信息。
### 常见误用
- 把 `HeliocentricEcliptic` 的返回值当作地心坐标:日心量的原点是太阳,地心量已经减掉了地球的日心位置。
- 把 `Apparent*` 当作含大气折射的视位置:折射只出现在升落判据与观测类接口里,坐标接口不含折射。
- 用零值 `Elements` 探路:`MeanMotion` 与位置接口会安静地返回 `NaN`,不会报错。
- 在近日点形式里期待 `ADot`…`WDot` 生效:这些变化率只在经典椭圆形式下参与传播。
## 相关手册
- 恒星与星表:[恒星](star.md#恒星)
- 坐标系换算与站心量:[坐标工具](coord.md#坐标工具)
- 日出日落、月出月落的同类接口:[太阳与月亮](sun-moon.md#日出日落月出月落)
> 需要把这里的黄道/赤道坐标接到恒星表或站心量上时,参见[恒星](star.md#恒星)与[坐标工具](coord.md#坐标工具)。