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

81 lines
3.3 KiB
Go

package basic
import (
"testing"
"time"
. "b612.me/astro/tools"
)
func TestMoonTopocentricPhysicalMatchesCorrectionMethod(t *testing.T) {
jd := UTC2TT(Date2JD(testTime(2026, 4, 28, 9, 30, 45)))
observerLon := 121.4737
observerLat := 31.2304
got := MoonTopocentricPhysical(jd, observerLon, observerLat, 0)
want := moonTopocentricPhysicalByCorrection(jd, observerLon, observerLat)
assertPlanetPhaseClose(t, "MoonTopocentricPhysical.LibrationLongitude", got.LibrationLongitude, want.LibrationLongitude, 0.1)
assertPlanetPhaseClose(t, "MoonTopocentricPhysical.LibrationLatitude", got.LibrationLatitude, want.LibrationLatitude, 0.1)
assertPlanetPhaseClose(t, "MoonTopocentricPhysical.PositionAngle", got.PositionAngle, want.PositionAngle, 0.1)
}
func TestMoonTopocentricPhysicalSampleSweepFiniteAndInRange(t *testing.T) {
samples := []struct {
name string
jd float64
observerLon float64
observerLat float64
height float64
}{
{"shanghai", UTC2TT(Date2JD(testTime(2026, 4, 28, 9, 30, 45))), 121.4737, 31.2304, 4},
{"chicago", UTC2TT(Date2JD(testTime(2024, 3, 25, 7, 0, 0))), -87.65, 41.85, 180},
}
for _, sample := range samples {
info := MoonTopocentricPhysical(sample.jd, sample.observerLon, sample.observerLat, sample.height)
prefix := sample.name + "."
assertFiniteRange(t, prefix+"OpticalLongitude", info.OpticalLongitude, -180, 180, false)
assertFiniteRange(t, prefix+"OpticalLatitude", info.OpticalLatitude, -90, 90, false)
assertFiniteRange(t, prefix+"PhysicalLongitude", info.PhysicalLongitude, -180, 180, false)
assertFiniteRange(t, prefix+"PhysicalLatitude", info.PhysicalLatitude, -90, 90, false)
assertFiniteRange(t, prefix+"LibrationLongitude", info.LibrationLongitude, -180, 180, false)
assertFiniteRange(t, prefix+"LibrationLatitude", info.LibrationLatitude, -90, 90, false)
assertFiniteRange(t, prefix+"PositionAngle", info.PositionAngle, -90, 90, false)
}
}
func moonTopocentricPhysicalByCorrection(jd, observerLon, observerLat float64) MoonPhysicalInfo {
geocentric := MoonPhysical(jd)
moonRA := HMoonTrueRa(jd)
moonDec := HMoonTrueDec(jd)
hourAngle := StarHourAngle(TT2UTC(jd), moonRA, observerLon, 0)
horizontalParallax := ArcSin(6378.1366 / HMoonAway(jd))
Q := ArcTan2(
Cos(moonDec)*Sin(hourAngle),
Cos(moonDec)*Sin(observerLat)-Sin(moonDec)*Cos(observerLat)*Cos(hourAngle),
)
z := ArcCos(Sin(moonDec)*Sin(observerLat) + Cos(moonDec)*Cos(observerLat)*Cos(hourAngle))
piPrime := horizontalParallax * (Sin(z) + 0.0084*Sin(2*z))
deltaL := -piPrime * Sin(Q-geocentric.PositionAngle) / Cos(geocentric.LibrationLatitude)
deltaB := piPrime * Cos(Q-geocentric.PositionAngle)
deltaP := deltaL*Sin(geocentric.LibrationLatitude+deltaB) - piPrime*Sin(Q)*Tan(moonDec)
return MoonPhysicalInfo{
OpticalLongitude: geocentric.OpticalLongitude,
OpticalLatitude: geocentric.OpticalLatitude,
PhysicalLongitude: geocentric.PhysicalLongitude,
PhysicalLatitude: geocentric.PhysicalLatitude,
LibrationLongitude: wrapSignedAngle180(geocentric.LibrationLongitude + deltaL),
LibrationLatitude: geocentric.LibrationLatitude + deltaB,
PositionAngle: geocentric.PositionAngle + deltaP,
}
}
func testTime(year int, month time.Month, day, hour, minute, second int) time.Time {
return time.Date(year, month, day, hour, minute, second, 0, time.UTC)
}