feat: 扩展天文计算能力
- 新增日食、月食、本地可见性、中心线、半影区域、SVG 图示与沙罗周期信息 - 新增行星冲合、留、方照、物理星历、视直径、相位、亮肢角、轨道节点等计算 - 新增木星伽利略卫星位置、现象与接触事件计算 - 新增恒星星表、星座判定、自行修正与观测辅助能力 - 新增 coord、formula、orbit、sundial、lite/sun、lite/moon 等扩展包 - 完善农历年号、月相英文别名、视差角、大气质量、折射、日晷与双星计算 - 增加 NASA、JPL Horizons、IMCCE 等回归测试数据与基线测试 - 重构基础算法文件组织,补充大量公开 API 注释和语义回归测试 - 更新中文和英文 README,补充示例、精度说明、SVG 配图
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package basic
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "b612.me/astro/tools"
|
||||
)
|
||||
|
||||
func TestMoonTopocentricPhysicalMatchesCorrectionMethod(t *testing.T) {
|
||||
jd := TD2UT(Date2JDE(testTime(2026, 4, 28, 9, 30, 45)), true)
|
||||
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", TD2UT(Date2JDE(testTime(2026, 4, 28, 9, 30, 45)), true), 121.4737, 31.2304, 4},
|
||||
{"chicago", TD2UT(Date2JDE(testTime(2024, 3, 25, 7, 0, 0)), true), -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(TD2UT(jd, false), 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)
|
||||
}
|
||||
Reference in New Issue
Block a user