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