feat: 引入可切换星历模型并扩展天象观测链路
- 新增半解析、旧模型、自定义与多源堆叠星历实例,提供 Context、Instance、SPK 读取及状态与视位置计算 - 统一太阳、月球和行星实例接口,扩展黄经穿越、留、相位、最近角距、偕日可见、任意高度升落、轨道节点及凌日等天象查询 - 完善日月食、月掩与凌日的月缘剖面、有限盘面接触、站心修正、局地可见性、全球路径和地图输出 - 新增 SVG、GeoJSON、KML 天象输出及凌日、月掩和月缘地形相关缓存与几何求解 - 新增恒星星表导入与查询,支持 CSV、Hipparcos、BSC5、Stellarium 等格式及名称、交叉标识、锥面检索和星等过滤 - 补充 IAU 2006、地球定向、折射消光、大气观测、轨道传播及半解析行星/月球数据支持 - 将默认未来民用时标切换为 TimeScaleLeapHour,更新 2027–2400 农历速查表、中文日期解析和时区边界处理 - 增加事件基线、跨模型回归、几何边界、月缘地形和输出契约测试,完善中英文手册、示例资源、NOTICE 与忽略规则
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
// Package iau2006 IAU 2006 岁差、IAU 2000A 章动与 ICRS 到真赤道的旋转;系数表单独成包,只有调用时才链接。
|
||||
package iau2006
|
||||
|
||||
import "math"
|
||||
|
||||
// Matrix 3×3 旋转矩阵,按行存放,作用于列向量 / 3×3 rotation matrix, row-major, acting on column vectors.
|
||||
type Matrix [3][3]float64
|
||||
|
||||
const (
|
||||
j2000 = 2451545.0
|
||||
arcsecToRad = math.Pi / 648000
|
||||
arcsecCircle = 1296000.0
|
||||
obliquityJ2K = 84381.406
|
||||
)
|
||||
|
||||
type lunisolarTerm struct {
|
||||
n [5]int8
|
||||
lonSin, lonSinT, lonCos float64
|
||||
oblCos, oblCosT, oblSin float64
|
||||
}
|
||||
|
||||
type planetaryTerm struct {
|
||||
n [14]int8
|
||||
lonSin, lonCos float64
|
||||
oblSin, oblCos float64
|
||||
}
|
||||
|
||||
func centuries(jdeTT float64) float64 { return (jdeTT - j2000) / 36525 }
|
||||
|
||||
// Nutation IAU 2000A 黄经章动 Δψ 与交角章动 Δε(角秒),jdeTT 为 TT 儒略日 / nutation in longitude and obliquity in arcseconds.
|
||||
func Nutation(jdeTT float64) (deltaPsi, deltaEpsilon float64) {
|
||||
t := centuries(jdeTT)
|
||||
var fa [5]float64
|
||||
for i, p := range fundamentalPolynomials {
|
||||
v := (((p[4]*t+p[3])*t+p[2])*t+p[1])*t + p[0]
|
||||
fa[i] = math.Mod(v, arcsecCircle) * arcsecToRad
|
||||
}
|
||||
var dpsi, deps float64
|
||||
for _, term := range lunisolarTerms {
|
||||
arg := 0.0
|
||||
for i, n := range term.n {
|
||||
arg += float64(n) * fa[i]
|
||||
}
|
||||
s, c := math.Sincos(arg)
|
||||
dpsi += s*(term.lonSin+term.lonSinT*t) + c*term.lonCos
|
||||
deps += c*(term.oblCos+term.oblCosT*t) + s*term.oblSin
|
||||
}
|
||||
var pa [14]float64
|
||||
for i, p := range planetaryArguments {
|
||||
pa[i] = p[0] + p[1]*t
|
||||
}
|
||||
pa[13] *= t
|
||||
for _, term := range planetaryTerms {
|
||||
arg := 0.0
|
||||
for i, n := range term.n {
|
||||
if n != 0 {
|
||||
arg += float64(n) * pa[i]
|
||||
}
|
||||
}
|
||||
s, c := math.Sincos(arg)
|
||||
dpsi += s*term.lonSin + c*term.lonCos
|
||||
deps += s*term.oblSin + c*term.oblCos
|
||||
}
|
||||
// 系数单位为 0.1 微角秒。
|
||||
return dpsi * 1e-7, deps * 1e-7
|
||||
}
|
||||
|
||||
// MeanObliquity IAU 2006 平黄赤交角(角秒)/ IAU 2006 mean obliquity in arcseconds.
|
||||
func MeanObliquity(jdeTT float64) float64 {
|
||||
t := centuries(jdeTT)
|
||||
return ((((-0.0000000434*t-0.000000576)*t+0.00200340)*t-0.0001831)*t-46.836769)*t + obliquityJ2K
|
||||
}
|
||||
|
||||
// Precession J2000 平赤道到历元平赤道的 IAU 2006 岁差矩阵 / IAU 2006 precession matrix from J2000 to the mean equator of date.
|
||||
func Precession(jdeTT float64) Matrix {
|
||||
t := centuries(jdeTT)
|
||||
psi := ((((-0.0000000951*t+0.000132851)*t-0.00114045)*t-1.0790069)*t + 5038.481507) * t
|
||||
omega := ((((0.0000003337*t-0.000000467)*t-0.00772503)*t+0.0512623)*t-0.025754)*t + obliquityJ2K
|
||||
chi := ((((-0.0000000560*t+0.000170663)*t-0.00121197)*t-2.3814292)*t + 10.556403) * t
|
||||
// R3(χ) R1(−ω) R3(−ψ) R1(ε0)
|
||||
return multiply(rotZ(chi*arcsecToRad), multiply(rotX(-omega*arcsecToRad), multiply(rotZ(-psi*arcsecToRad), rotX(obliquityJ2K*arcsecToRad))))
|
||||
}
|
||||
|
||||
// NutationMatrix 历元平赤道到真赤道真春分点的章动矩阵 / nutation matrix from mean to true equator of date.
|
||||
func NutationMatrix(jdeTT float64) Matrix {
|
||||
dpsi, deps := Nutation(jdeTT)
|
||||
mean := MeanObliquity(jdeTT) * arcsecToRad
|
||||
// R1(−εA−Δε) R3(−Δψ) R1(εA)
|
||||
return multiply(rotX(-(mean + deps*arcsecToRad)), multiply(rotZ(-dpsi*arcsecToRad), rotX(mean)))
|
||||
}
|
||||
|
||||
// FrameBias ICRS 到 J2000 平赤道的框架偏差矩阵 / frame bias from ICRS to the J2000 mean equator.
|
||||
func FrameBias() Matrix {
|
||||
const (
|
||||
xi0 = -0.0166170 * arcsecToRad
|
||||
eta0 = -0.0068192 * arcsecToRad
|
||||
da0 = -0.01460 * arcsecToRad
|
||||
)
|
||||
return Matrix{
|
||||
{1 - 0.5*(da0*da0+xi0*xi0), da0, -xi0},
|
||||
{-da0, 1 - 0.5*(da0*da0+eta0*eta0), -eta0},
|
||||
{xi0, eta0, 1 - 0.5*(eta0*eta0+xi0*xi0)},
|
||||
}
|
||||
}
|
||||
|
||||
// BiasPrecessionNutation ICRS 到真赤道真春分点的完整旋转 N·P·B / full rotation from ICRS to the true equator and equinox of date.
|
||||
func BiasPrecessionNutation(jdeTT float64) Matrix {
|
||||
return multiply(NutationMatrix(jdeTT), multiply(Precession(jdeTT), FrameBias()))
|
||||
}
|
||||
|
||||
// EquationOfEquinoxes 春分点方程的主项 Δψ·cos εA(角秒),不含补充项 / equation of the equinoxes, principal term only.
|
||||
func EquationOfEquinoxes(jdeTT float64) float64 {
|
||||
dpsi, _ := Nutation(jdeTT)
|
||||
return dpsi * math.Cos(MeanObliquity(jdeTT)*arcsecToRad)
|
||||
}
|
||||
|
||||
// Apply 把矩阵作用于向量 / apply the matrix to a vector.
|
||||
func (m Matrix) Apply(v [3]float64) [3]float64 {
|
||||
var out [3]float64
|
||||
for i := range out {
|
||||
out[i] = m[i][0]*v[0] + m[i][1]*v[1] + m[i][2]*v[2]
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Transpose 逆旋转 / inverse rotation.
|
||||
func (m Matrix) Transpose() Matrix {
|
||||
var out Matrix
|
||||
for i := range out {
|
||||
for j := range out[i] {
|
||||
out[i][j] = m[j][i]
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func rotX(a float64) Matrix {
|
||||
s, c := math.Sincos(a)
|
||||
return Matrix{{1, 0, 0}, {0, c, s}, {0, -s, c}}
|
||||
}
|
||||
|
||||
func rotZ(a float64) Matrix {
|
||||
s, c := math.Sincos(a)
|
||||
return Matrix{{c, s, 0}, {-s, c, 0}, {0, 0, 1}}
|
||||
}
|
||||
|
||||
func multiply(a, b Matrix) Matrix {
|
||||
var out Matrix
|
||||
for i := range out {
|
||||
for j := range out[i] {
|
||||
out[i][j] = a[i][0]*b[0][j] + a[i][1]*b[1][j] + a[i][2]*b[2][j]
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user