astro/basic/moon_physical.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

169 lines
6.0 KiB
Go

package basic
import (
"math"
. "b612.me/astro/tools"
)
const moonPhysicalInclinationDeg = 1.54242
const moonPhysicalAstronomicalUnitKM = 149597870.7
// MoonPhysicalInfo 月球物理观测参数 / physical observing parameters of the Moon.
type MoonPhysicalInfo struct {
// OpticalLongitude 光学经度天平动,单位度 / optical libration in longitude, degrees.
OpticalLongitude float64
// OpticalLatitude 光学纬度天平动,单位度 / optical libration in latitude, degrees.
OpticalLatitude float64
// PhysicalLongitude 物理经度天平动,单位度 / physical libration in longitude, degrees.
PhysicalLongitude float64
// PhysicalLatitude 物理纬度天平动,单位度 / physical libration in latitude, degrees.
PhysicalLatitude float64
// LibrationLongitude 总经度天平动,单位度 / total libration in longitude, degrees.
LibrationLongitude float64
// LibrationLatitude 总纬度天平动,单位度 / total libration in latitude, degrees.
LibrationLatitude float64
// PositionAngle 月球自转轴位置角,单位度 / position angle of the lunar rotation axis, degrees.
PositionAngle float64
}
// MoonPhysical 月球物理观测参数 / physical observing parameters of the Moon.
func MoonPhysical(jd float64) MoonPhysicalInfo {
return MoonPhysicalN(jd, -1)
}
// MoonPhysicalN 月球物理观测参数(截断版) / truncated physical observing parameters of the Moon.
func MoonPhysicalN(jd float64, n int) MoonPhysicalInfo {
return moonPhysicalNFromCoordinates(jd, n, HMoonApparentLoN(jd, n), HMoonTrueBoN(jd, n), HMoonTrueRaN(jd, n))
}
// MoonTopocentricPhysical 月球站心物理观测参数 / topocentric physical observing parameters of the Moon.
func MoonTopocentricPhysical(jd, observerLon, observerLat, height float64) MoonPhysicalInfo {
return MoonTopocentricPhysicalN(jd, observerLon, observerLat, height, -1)
}
// MoonTopocentricPhysicalN 月球站心物理观测参数(截断版) / truncated topocentric physical observing parameters of the Moon.
func MoonTopocentricPhysicalN(jd, observerLon, observerLat, height float64, n int) MoonPhysicalInfo {
lambda, beta, alpha := moonTopocentricPhysicalCoordinatesN(jd, observerLon, observerLat, height, n)
return moonPhysicalNFromCoordinates(jd, n, lambda, beta, alpha)
}
func moonPhysicalNFromCoordinates(jd float64, n int, lambda, beta, alpha float64) MoonPhysicalInfo {
t := (jd - 2451545.0) / 36525.0
epsilon := TrueObliquity(jd)
deltaPsi := Nutation2000Bi(jd)
D := Limit360(SunMoonAngle(jd))
sunMeanAnomaly := Limit360(SunM(jd))
moonMeanAnomaly := Limit360(MoonM(jd))
F := Limit360(MoonLonX(jd))
omega := moonPhysicalMeanAscendingNode(t)
E := 1 - 0.002516*t - 0.0000074*t*t
K1 := 119.75 + 131.849*t
K2 := 72.56 + 20.186*t
W := Limit360(lambda - deltaPsi - omega)
A := ArcTan2(Sin(W)*Cos(beta)*Cos(moonPhysicalInclinationDeg)-Sin(beta)*Sin(moonPhysicalInclinationDeg), Cos(W)*Cos(beta))
opticalLongitude := wrapSignedAngle180(A - F)
opticalLatitude := ArcSin(-Sin(W)*Cos(beta)*Sin(moonPhysicalInclinationDeg) - Sin(beta)*Cos(moonPhysicalInclinationDeg))
rho, sigma, tau := moonPhysicalLibrationSeries(D, sunMeanAnomaly, moonMeanAnomaly, F, omega, E, K1, K2)
physicalLongitude := -tau + (rho*Cos(A)+sigma*Sin(A))*Tan(opticalLatitude)
physicalLatitude := sigma*Cos(A) - rho*Sin(A)
librationLongitude := wrapSignedAngle180(opticalLongitude + physicalLongitude)
librationLatitude := opticalLatitude + physicalLatitude
V := Limit360(omega + deltaPsi + sigma/Sin(moonPhysicalInclinationDeg))
X := Sin(moonPhysicalInclinationDeg+rho) * Sin(V)
Y := Sin(moonPhysicalInclinationDeg+rho)*Cos(V)*Cos(epsilon) - Cos(moonPhysicalInclinationDeg+rho)*Sin(epsilon)
littleOmega := ArcTan2(X, Y)
positionAngle := ArcSin(clampUnit((sqrtXY(X, Y) * Cos(alpha-littleOmega)) / Cos(librationLatitude)))
return MoonPhysicalInfo{
OpticalLongitude: opticalLongitude,
OpticalLatitude: opticalLatitude,
PhysicalLongitude: physicalLongitude,
PhysicalLatitude: physicalLatitude,
LibrationLongitude: librationLongitude,
LibrationLatitude: librationLatitude,
PositionAngle: positionAngle,
}
}
func moonTopocentricPhysicalCoordinatesN(jd, observerLon, observerLat, height float64, n int) (lambda, beta, alpha float64) {
geocentricRA := HMoonTrueRaN(jd, n)
geocentricDec := HMoonTrueDecN(jd, n)
distanceAU := HMoonAwayN(jd, n) / moonPhysicalAstronomicalUnitKM
utJD := TD2UT(jd, false)
var topocentricDec float64
alpha, topocentricDec = TopocentricRaDec(geocentricRA, geocentricDec, observerLat, observerLon, utJD, distanceAU, height)
lambda, beta = RaDecToLoBo(jd, alpha, topocentricDec)
return
}
func moonPhysicalLibrationSeries(D, M, MP, F, omega, E, K1, K2 float64) (rho, sigma, tau float64) {
rho = -0.02752*Cos(MP) -
0.02245*Sin(F) +
0.00684*Cos(MP-2*F) -
0.00293*Cos(2*F) -
0.00085*Cos(2*F-2*D) -
0.00054*Cos(MP-2*D) -
0.00020*Sin(MP+F) -
0.00020*Cos(MP+2*F) -
0.00020*Cos(MP-F) +
0.00014*Cos(MP+2*F-2*D)
sigma = -0.02816*Sin(MP) +
0.02244*Cos(F) -
0.00682*Sin(MP-2*F) -
0.00279*Sin(2*F) -
0.00083*Sin(2*F-2*D) +
0.00069*Sin(MP-2*D) +
0.00040*Cos(MP+F) -
0.00025*Sin(2*MP) -
0.00023*Sin(MP+2*F) +
0.00020*Cos(MP-F) +
0.00019*Sin(MP-F) +
0.00013*Sin(MP+2*F-2*D) -
0.00010*Cos(MP-3*F)
tau = 0.02520*E*Sin(M) +
0.00473*Sin(2*MP-2*F) -
0.00467*Sin(MP) +
0.00396*Sin(K1) +
0.00276*Sin(2*MP-2*D) +
0.00196*Sin(omega) -
0.00183*Cos(MP-F) +
0.00115*Sin(MP-2*D) -
0.00096*Sin(MP-D) +
0.00046*Sin(2*F-2*D) -
0.00039*Sin(MP-F) -
0.00032*Sin(MP-M-D) +
0.00027*Sin(2*MP-M-2*D) +
0.00023*Sin(K2) -
0.00014*Sin(2*D) +
0.00014*Cos(2*MP-2*F) -
0.00012*Sin(MP-2*F) -
0.00012*Sin(2*MP) +
0.00011*Sin(2*MP-2*M-2*D)
return
}
func moonPhysicalMeanAscendingNode(t float64) float64 {
return Limit360(125.04452222222222 - 1934.136261111111*t + 0.0020708333333333334*t*t + 0.0000022222222222222222*t*t*t)
}
func wrapSignedAngle180(angle float64) float64 {
angle = Limit360(angle)
if angle > 180 {
angle -= 360
}
return angle
}
func sqrtXY(x, y float64) float64 {
return math.Sqrt(x*x + y*y)
}