Files
astro/doc/manual/phenomena.md
T
b612 044f2f4381 feat: 引入可切换星历模型并扩展天象观测链路
- 新增半解析、旧模型、自定义与多源堆叠星历实例,提供 Context、Instance、SPK 读取及状态与视位置计算
- 统一太阳、月球和行星实例接口,扩展黄经穿越、留、相位、最近角距、偕日可见、任意高度升落、轨道节点及凌日等天象查询
- 完善日月食、月掩与凌日的月缘剖面、有限盘面接触、站心修正、局地可见性、全球路径和地图输出
- 新增 SVG、GeoJSON、KML 天象输出及凌日、月掩和月缘地形相关缓存与几何求解
- 新增恒星星表导入与查询,支持 CSV、Hipparcos、BSC5、Stellarium 等格式及名称、交叉标识、锥面检索和星等过滤
- 补充 IAU 2006、地球定向、折射消光、大气观测、轨道传播及半解析行星/月球数据支持
- 将默认未来民用时标切换为 TimeScaleLeapHour,更新 2027–2400 农历速查表、中文日期解析和时区边界处理
- 增加事件基线、跨模型回归、几何边界、月缘地形和输出契约测试,完善中英文手册、示例资源、NOTICE 与忽略规则
2026-10-15 23:54:15 +08:00

244 lines
10 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/phenomena.md) | [返回 README](../../README.md)
`phenomena` 包按地心视黄经、视黄纬搜索任意两天体的事件,计算行星与恒星的晨昏始见、末见,另外提供任意高度升落和近日点、远日点、过交点。包级入口使用进程当前的星历模型,也可以用 `ctx.Phenomena()` 固定星历实例;只有恒星的任意高度升落按传入的视坐标计算,不读星历。
## 目录
- [快速示例](#快速示例)
- [天体对事件](#天体对事件)
- [恒星坐标](#恒星坐标)
- [偕日可见](#偕日可见)
- [任意高度升落](#任意高度升落)
- [近日点、远日点与过交点](#近日点远日点与过交点)
- [API 参考](#api-参考)
- [参数与返回值约定](#参数与返回值约定)
## 快速示例
```go
start := time.Date(2020, 10, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2021, 3, 1, 0, 0, 0, 0, time.UTC)
events := phenomena.ClosestApproaches(phenomena.Jupiter, phenomena.Saturn, 1, start, end)
fmt.Println(events[0].Time.UTC().Format("2006-01-02 15:04"), fmt.Sprintf("%.4f", events[0].Value))
```
```text
2020-12-21 18:21 0.1018
```
`ClosestApproaches` 返回窗口内两天体角距的**局部极小**,`Value` 是当时的角距(度)。窗口内没有小于 `maxSeparation` 的极小值时返回空切片。
固定星历实例时换成模块方法:
```go
ctx, err := astro.NewContext(astro.ModelLegacy)
if err != nil {
panic(err)
}
events = ctx.Phenomena().ClosestApproaches(phenomena.Jupiter, phenomena.Saturn, 1, start, end)
```
## 天体对事件
| 入口 | 事件 | `Event.Value` |
| --- | --- | --- |
| `LongitudeCrossings(body, lon, start, end)` | 视黄经经过 `lon` | 事件时刻的视黄经(度) |
| `Stations(body, start, end)` | 视黄经的留(行星) | 留时的视黄经(度) |
| `AspectCrossings(a, b, angle, start, end)` | `lon(a) − lon(b) = angle`;`0` 为黄经合,`180` 为冲 | 实际的黄经差(度) |
| `ClosestApproaches(a, b, max, start, end)` | 两天体角距的局部极小 | 角距(度) |
| `StarApproaches(body, star, max, start, end)` | 天体与恒星角距的局部极小 | 角距(度) |
各入口只接受上表列出的参数,结果按时间升序返回。各行星包里按赤经定义的留与这里按黄经定义的留口径不同,时刻可差数小时。
```go
// 2026 年前两次水星留
stations := phenomena.Stations(phenomena.Mercury,
time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC), time.Date(2026, 4, 1, 0, 0, 0, 0, time.UTC))
for _, e := range stations {
fmt.Println(e.Time.UTC().Format("01-02 15:04"), fmt.Sprintf("%.3f", e.Value))
}
```
```text
02-26 06:48 352.565
03-20 19:32 338.491
```
```go
// 太阳视黄经经过 0°(春分)
crossings := phenomena.LongitudeCrossings(phenomena.Sun, 0,
time.Date(2026, 3, 18, 0, 0, 0, 0, time.UTC), time.Date(2026, 3, 24, 0, 0, 0, 0, time.UTC))
fmt.Println(crossings[0].Time.UTC().Format("2006-01-02 15:04"))
```
```text
2026-03-20 14:45
```
## 恒星坐标
行星与恒星的角距、恒星偕日可见都要传入 `StarCoordinate`,内嵌 9100 星表可以直接查:
| 入口 | 输入 |
| --- | --- |
| `StarCoordinateByName(name)` | 星表中文名,例如 `"天狼星"` |
| `StarCoordinateByHR(hr)` | HR 编号 |
| `StarCoordinateFromStarData(star)` | `star.StarDataByHR` 等取到的星表记录 |
```go
star, err := phenomena.StarCoordinateByName("天狼星")
fmt.Println(err, star.ID, fmt.Sprintf("%.6f %.6f %.2f %.2f", star.RA, star.Dec,
star.ProperMotionRACosDecMasPerYear, star.ProperMotionDecMasPerYear))
```
```text
<nil> 天狼 101.287083 -16.716111 -553.00 -1205.00
```
`RA`、`Dec` 为度,`Epoch` 与 `Frame` 必填;自行字段(`ProperMotionRACosDecMasPerYear` 等)按星表常见的 `dRA·cos(Dec)` 约定,单位毫角秒/年。`ParallaxMas`(或等价的 `DistanceLightYear`)给出距离,`RadialVelocityKmPerSecond` 给出视向速度;距离缺失时按二维自行传播,有距离时才计入视向速度。
## 偕日可见
`PlanetHeliacalEvents(body, start, end, lon, lat, options)` 与 `StarHeliacalEvents(star, magnitude, start, end, lon, lat, options)` 逐日扫描太阳高度 −18° 到 0° 的晨昏时段,按天光亮度模型求肉眼极限星等,再与目标视星等比较(行星用 Mallama & Hilton 2018 星等),返回四类事件:
| 常量 | 含义 |
| --- | --- |
| `HeliacalMorningFirst` | 晨始见(偕日升) |
| `HeliacalMorningLast` | 晨末见 |
| `HeliacalEveningFirst` | 昏始见 |
| `HeliacalEveningLast` | 昏末见(偕日落) |
`HeliacalEvent` 中 `Time` 是当次晨昏的最佳可见时刻,`TargetAltitude`、`SunAltitude` 是当时目标与太阳的几何高度(度),`Margin` 是极限星等减目标星等。
| `HeliacalOptions` | 默认 | 说明 |
| --- | --- | --- |
| `ExtinctionCoefficient` | `0.25` | 大气消光,星等/大气质量 |
| `MinTargetAltitude` | `0.5` | 目标最低几何高度(度) |
| `Moonlight` | `false` | 计入月光散射(Krisciunas–Schaefer) |
```go
events := phenomena.PlanetHeliacalEvents(phenomena.Venus,
time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC), time.Date(2025, 12, 31, 0, 0, 0, 0, time.UTC),
31.23, 30.04, phenomena.HeliacalOptions{})
for _, e := range events {
fmt.Println(e.Kind, e.Time.UTC().Format("2006-01-02"), fmt.Sprintf("margin=%.2f", e.Margin))
}
```
```text
3 2025-03-18 margin=0.10
0 2025-03-25 margin=0.58
1 2025-12-01 margin=0.10
```
`Kind` 打印出来是常量序号,判断时用常量本身比较。`LimitingMagnitude(targetAltitude, sunAltitude, separation, extinction)` 单独给出某一时刻无月夜的极限星等,与事件判定同源:
```go
fmt.Println(fmt.Sprintf("%.3f", phenomena.LimitingMagnitude(20, -12, 60, 0.25)))
```
```text
3.408
```
结果对消光系数敏感,可见日期差一两天属正常。
## 任意高度升落
`AltitudeCrossing(body, date, lon, lat, height, altitude, options)` 求日、月或行星在 `date` 所在**当地民用日**内首次穿过视高度 `altitude` 的升、落时刻。`StarAltitudeCrossing(date, ra, dec, lon, lat, altitude, options)` 对恒星视坐标做同样计算,它不读星历,也没有模块方法。
| `AltitudeOptions` | 默认 | 说明 |
| --- | --- | --- |
| `Limb` | `LimbUpper` | 日月取上缘,也可取 `LimbCenter`、`LimbLower`;行星与恒星忽略 |
| `PressureHPa` / `TemperatureC` | 标准大气(`0` 值) | 指定实测气象 |
| `NoRefraction` | `false` | 为 `true` 时按几何高度比较 |
| `AltitudeCrossingResult` | 说明 |
| --- | --- |
| `Rise`、`Set` | 升、落时刻,没有事件时为零值 |
| `HasRise`、`HasSet` | 当天是否存在升、落 |
| `State` | `AltitudeCrosses`、`AltitudeAlwaysAbove`、`AltitudeAlwaysBelow` 或 `AltitudeTangent`(极值与目标高度相差不足 `1″`) |
| `MinResidual`、`MaxResidual` | 当天高度与目标高度之差的最小、最大值(度) |
```go
cst := time.FixedZone("CST", 8*3600)
r, err := phenomena.AltitudeCrossing(phenomena.Sun, time.Date(2026, 3, 21, 12, 0, 0, 0, cst),
116.4, 39.9, 0, -18, phenomena.AltitudeOptions{})
fmt.Println(err, r.State, r.Rise.In(cst).Format("15:04:05"), r.Set.In(cst).Format("15:04:05"),
fmt.Sprintf("%.3f %.3f", r.MinResidual, r.MaxResidual))
```
```text
<nil> 0 04:44:54 19:59:16 -31.806 68.602
```
```go
// 北纬 89° 极昼:太阳整天都在 -18° 之上
polar, err := phenomena.AltitudeCrossing(phenomena.Sun, time.Date(2026, 6, 21, 12, 0, 0, 0, time.UTC),
0, 89, 0, -18, phenomena.AltitudeOptions{})
fmt.Println(err, polar.State, polar.HasRise, polar.HasSet, fmt.Sprintf("%.3f", polar.MinResidual))
```
```text
<nil> 1 false false 40.737
```
```go
// 天狼星穿过 -0.833° 的升落
sirius, err := phenomena.StarAltitudeCrossing(time.Date(2026, 1, 1, 12, 0, 0, 0, cst),
star.RA, star.Dec, 116.4, 39.9, -0.833, phenomena.AltitudeOptions{Limb: phenomena.LimbCenter})
fmt.Println(err, sirius.State, sirius.Rise.In(cst).Format("15:04:05"), sirius.Set.In(cst).Format("15:04:05"))
```
```text
<nil> 0 19:04:31 05:27:52
```
`height` 只影响月球视差。需要以下沉地平为基准时,由调用方从 `altitude` 中减去地平俯角。天体不是日、月或行星(例如 `phenomena.Earth`),或恒星视坐标不是有限值时,返回 `basic.ErrInvalidObservationInput`。
## 近日点、远日点与过交点
| 常量 | 事件 |
| --- | --- |
| `Perihelion`、`Aphelion` | 近日点、远日点 |
| `AscendingNode`、`DescendingNode` | 穿过历元平黄道的升交点、降交点 |
`Apsides(body, start, end)` 接受行星或地球(`phenomena.Earth`),`Nodes(body, start, end)` 只接受行星,传地球返回空切片。`OrbitalEvent` 的 `Time` 是事件时刻,`Kind` 是上表常量,`DistanceAU` 是该时刻的日心距(AU)。
```go
apsides := phenomena.Apsides(phenomena.Earth,
time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC), time.Date(2027, 1, 1, 0, 0, 0, 0, time.UTC))
for _, e := range apsides {
fmt.Println(e.Kind, e.Time.UTC().Format("2006-01-02 15:04"), fmt.Sprintf("%.9f AU", e.DistanceAU))
}
nodes := phenomena.Nodes(phenomena.Jupiter,
time.Date(2018, 1, 1, 0, 0, 0, 0, time.UTC), time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC))
for _, e := range nodes {
fmt.Println(e.Kind, e.Time.UTC().Format("2006-01-02 15:04"), fmt.Sprintf("%.6f AU", e.DistanceAU))
}
```
```text
0 2026-01-03 09:15 0.983302049 AU
1 2026-07-06 09:30 1.016643962 AU
3 2020-02-25 18:09 5.207056 AU
2 2025-09-19 11:58 5.174312 AU
```
极值取日心距本身:太阳绕质心的反射运动会让天王星、海王星的日心距在近日点附近出现多个小极值,同一段出现多个极小值时只返回前后各 `0.3` 个轨道周期内日心距最小的一个,与吻切轨道近日点可相差数年。
## API 参考
`ctx.Phenomena()` 的方法与同名包级函数签名一致(`StarAltitudeCrossing` 除外);`NewWithInstance` 用给定星历实例创建模块。各入口的参数与单位见上文各节。
## 参数与返回值约定
- 角度一律为度,`OrbitalEvent.DistanceAU` 为 AU,`StarHeliacalEvents` 的 `magnitude` 为 V 星等。
- 时间参数按绝对时刻解释(读取其 UTC 字段),返回时刻换算到 `start`(升落类为 `date`)所在的时区。
- 事件搜索没有结果时返回空切片,不返回错误;只有任意高度升落在输入非法时返回 `basic.ErrInvalidObservationInput`。
- 事件搜索会用到星历,可以用模块方法固定模型;`StarAltitudeCrossing`、`StarCoordinate*` 与 `LimitingMagnitude` 与星历无关。
- 行星视星等、赤经留等口径差异见[行星手册](planets.md);日月升落与观测角语义见[太阳与月亮](sun-moon.md)。