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,175 @@
|
||||
package astro_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"b612.me/astro/basic"
|
||||
"b612.me/astro/planet"
|
||||
)
|
||||
|
||||
type lowPrecisionSunSnapshot struct {
|
||||
LoBits uint64 `json:"lo_bits"`
|
||||
MBits uint64 `json:"m_bits"`
|
||||
EccBits uint64 `json:"ecc_bits"`
|
||||
PeriBits uint64 `json:"peri_bits"`
|
||||
MidBits uint64 `json:"mid_bits"`
|
||||
TrueLoBits uint64 `json:"true_lo_bits"`
|
||||
ApparentLoBits uint64 `json:"apparent_lo_bits"`
|
||||
ApparentRaBits uint64 `json:"apparent_ra_bits"`
|
||||
ApparentDecBits uint64 `json:"apparent_dec_bits"`
|
||||
TrueRaBits uint64 `json:"true_ra_bits"`
|
||||
TrueDecBits uint64 `json:"true_dec_bits"`
|
||||
DistanceBits uint64 `json:"distance_bits"`
|
||||
}
|
||||
|
||||
type lowPrecisionMoonSnapshot struct {
|
||||
LoBits uint64 `json:"lo_bits"`
|
||||
SunAngleBits uint64 `json:"sun_angle_bits"`
|
||||
MBits uint64 `json:"m_bits"`
|
||||
LonXBits uint64 `json:"lonx_bits"`
|
||||
IBits uint64 `json:"i_bits"`
|
||||
RBits uint64 `json:"r_bits"`
|
||||
BBits uint64 `json:"b_bits"`
|
||||
TrueLoBits uint64 `json:"true_lo_bits"`
|
||||
TrueBoBits uint64 `json:"true_bo_bits"`
|
||||
AwayBits uint64 `json:"away_bits"`
|
||||
ApparentLoBits uint64 `json:"apparent_lo_bits"`
|
||||
TrueRaBits uint64 `json:"true_ra_bits"`
|
||||
TrueDecBits uint64 `json:"true_dec_bits"`
|
||||
}
|
||||
|
||||
type lowPrecisionSample struct {
|
||||
UTC string `json:"utc"`
|
||||
TTJD float64 `json:"tt_jd"`
|
||||
Sun lowPrecisionSunSnapshot `json:"sun"`
|
||||
Moon lowPrecisionMoonSnapshot `json:"moon"`
|
||||
}
|
||||
|
||||
func loadLowPrecisionSamples(t *testing.T) []lowPrecisionSample {
|
||||
t.Helper()
|
||||
|
||||
data, err := os.ReadFile("testdata/low_precision_sun_moon_baseline.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var samples []lowPrecisionSample
|
||||
if err := json.Unmarshal(data, &samples); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(samples) == 0 {
|
||||
t.Fatal("empty low precision baseline samples")
|
||||
}
|
||||
return samples
|
||||
}
|
||||
|
||||
func TestLowPrecisionSunMoonBaselineRegression(t *testing.T) {
|
||||
samples := loadLowPrecisionSamples(t)
|
||||
|
||||
assertBits := func(t *testing.T, name, utc string, got float64, want uint64) {
|
||||
t.Helper()
|
||||
if math.Float64bits(got) != want {
|
||||
t.Fatalf("%s regression at %s", name, utc)
|
||||
}
|
||||
}
|
||||
|
||||
for _, sample := range samples {
|
||||
jd := sample.TTJD
|
||||
|
||||
assertBits(t, "planet.SunLo", sample.UTC, planet.SunLo(jd), sample.Sun.LoBits)
|
||||
assertBits(t, "basic.SunLo", sample.UTC, basic.SunLo(jd), sample.Sun.LoBits)
|
||||
assertBits(t, "planet.SunM", sample.UTC, planet.SunM(jd), sample.Sun.MBits)
|
||||
assertBits(t, "basic.SunM", sample.UTC, basic.SunM(jd), sample.Sun.MBits)
|
||||
assertBits(t, "planet.Earthe", sample.UTC, planet.Earthe(jd), sample.Sun.EccBits)
|
||||
assertBits(t, "basic.Earthe", sample.UTC, basic.Earthe(jd), sample.Sun.EccBits)
|
||||
assertBits(t, "planet.EarthPI", sample.UTC, planet.EarthPI(jd), sample.Sun.PeriBits)
|
||||
assertBits(t, "basic.EarthPI", sample.UTC, basic.EarthPI(jd), sample.Sun.PeriBits)
|
||||
assertBits(t, "planet.SunMidFun", sample.UTC, planet.SunMidFun(jd), sample.Sun.MidBits)
|
||||
assertBits(t, "basic.SunMidFun", sample.UTC, basic.SunMidFun(jd), sample.Sun.MidBits)
|
||||
assertBits(t, "planet.SunTrueLo", sample.UTC, planet.SunTrueLo(jd), sample.Sun.TrueLoBits)
|
||||
assertBits(t, "basic.SunTrueLo", sample.UTC, basic.SunTrueLo(jd), sample.Sun.TrueLoBits)
|
||||
assertBits(t, "planet.SunApparentLo", sample.UTC, planet.SunApparentLo(jd), sample.Sun.ApparentLoBits)
|
||||
assertBits(t, "basic.SunApparentLo", sample.UTC, basic.SunApparentLo(jd), sample.Sun.ApparentLoBits)
|
||||
assertBits(t, "basic.SunApparentRa", sample.UTC, basic.SunApparentRa(jd), sample.Sun.ApparentRaBits)
|
||||
assertBits(t, "basic.SunApparentDec", sample.UTC, basic.SunApparentDec(jd), sample.Sun.ApparentDecBits)
|
||||
assertBits(t, "basic.SunTrueRa", sample.UTC, basic.SunTrueRa(jd), sample.Sun.TrueRaBits)
|
||||
assertBits(t, "basic.SunTrueDec", sample.UTC, basic.SunTrueDec(jd), sample.Sun.TrueDecBits)
|
||||
assertBits(t, "planet.Distance", sample.UTC, planet.Distance(jd), sample.Sun.DistanceBits)
|
||||
assertBits(t, "basic.Distance", sample.UTC, basic.Distance(jd), sample.Sun.DistanceBits)
|
||||
assertBits(t, "planet.MoonLo", sample.UTC, planet.MoonLo(jd), sample.Moon.LoBits)
|
||||
assertBits(t, "basic.MoonLo", sample.UTC, basic.MoonLo(jd), sample.Moon.LoBits)
|
||||
assertBits(t, "planet.SunMoonAngle", sample.UTC, planet.SunMoonAngle(jd), sample.Moon.SunAngleBits)
|
||||
assertBits(t, "basic.SunMoonAngle", sample.UTC, basic.SunMoonAngle(jd), sample.Moon.SunAngleBits)
|
||||
assertBits(t, "planet.MoonM", sample.UTC, planet.MoonM(jd), sample.Moon.MBits)
|
||||
assertBits(t, "basic.MoonM", sample.UTC, basic.MoonM(jd), sample.Moon.MBits)
|
||||
assertBits(t, "planet.MoonLonX", sample.UTC, planet.MoonLonX(jd), sample.Moon.LonXBits)
|
||||
assertBits(t, "basic.MoonLonX", sample.UTC, basic.MoonLonX(jd), sample.Moon.LonXBits)
|
||||
assertBits(t, "planet.MoonI", sample.UTC, planet.MoonI(jd), sample.Moon.IBits)
|
||||
assertBits(t, "basic.MoonI", sample.UTC, basic.MoonI(jd), sample.Moon.IBits)
|
||||
assertBits(t, "planet.MoonR", sample.UTC, planet.MoonR(jd), sample.Moon.RBits)
|
||||
assertBits(t, "basic.MoonR", sample.UTC, basic.MoonR(jd), sample.Moon.RBits)
|
||||
assertBits(t, "planet.MoonB", sample.UTC, planet.MoonB(jd), sample.Moon.BBits)
|
||||
assertBits(t, "basic.MoonB", sample.UTC, basic.MoonB(jd), sample.Moon.BBits)
|
||||
assertBits(t, "planet.MoonTrueLo", sample.UTC, planet.MoonTrueLo(jd), sample.Moon.TrueLoBits)
|
||||
assertBits(t, "basic.MoonTrueLo", sample.UTC, basic.MoonTrueLo(jd), sample.Moon.TrueLoBits)
|
||||
assertBits(t, "planet.MoonTrueBo", sample.UTC, planet.MoonTrueBo(jd), sample.Moon.TrueBoBits)
|
||||
assertBits(t, "basic.MoonTrueBo", sample.UTC, basic.MoonTrueBo(jd), sample.Moon.TrueBoBits)
|
||||
assertBits(t, "planet.MoonAway", sample.UTC, planet.MoonAway(jd), sample.Moon.AwayBits)
|
||||
assertBits(t, "basic.MoonAway", sample.UTC, basic.MoonAway(jd), sample.Moon.AwayBits)
|
||||
assertBits(t, "basic.MoonApparentLo", sample.UTC, basic.MoonApparentLo(jd), sample.Moon.ApparentLoBits)
|
||||
assertBits(t, "basic.MoonTrueRa", sample.UTC, basic.MoonTrueRa(jd), sample.Moon.TrueRaBits)
|
||||
assertBits(t, "basic.MoonTrueDec", sample.UTC, basic.MoonTrueDec(jd), sample.Moon.TrueDecBits)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDerivedHighPrecisionTruncationFullMatchesDefault(t *testing.T) {
|
||||
jd := 2469808.7654321
|
||||
lon := 116.391
|
||||
lat := 39.907
|
||||
tz := 8.0
|
||||
|
||||
assertSame := func(name string, got, want float64) {
|
||||
t.Helper()
|
||||
if math.Float64bits(got) != math.Float64bits(want) {
|
||||
t.Fatalf("%s full-n mismatch", name)
|
||||
}
|
||||
}
|
||||
assertSamePair := func(name string, got1, got2, want1, want2 float64) {
|
||||
t.Helper()
|
||||
assertSame(name+".1", got1, want1)
|
||||
assertSame(name+".2", got2, want2)
|
||||
}
|
||||
|
||||
assertSame("HSunTrueLo", basic.HSunTrueLo(jd), basic.HSunTrueLoN(jd, -1))
|
||||
assertSame("HSunTrueBo", basic.HSunTrueBo(jd), basic.HSunTrueBoN(jd, -1))
|
||||
assertSame("HSunApparentLo", basic.HSunApparentLo(jd), basic.HSunApparentLoN(jd, -1))
|
||||
assertSame("SunLoGXC", basic.SunLoGXC(jd), basic.SunLoGXCN(jd, -1))
|
||||
assertSame("EarthAway", basic.EarthAway(jd), basic.EarthAwayN(jd, -1))
|
||||
assertSame("HSunApparentRa", basic.HSunApparentRa(jd), basic.HSunApparentRaN(jd, -1))
|
||||
assertSame("HSunTrueRa", basic.HSunTrueRa(jd), basic.HSunTrueRaN(jd, -1))
|
||||
assertSame("HSunApparentDec", basic.HSunApparentDec(jd), basic.HSunApparentDecN(jd, -1))
|
||||
assertSame("HSunTrueDec", basic.HSunTrueDec(jd), basic.HSunTrueDecN(jd, -1))
|
||||
ra1, dec1 := basic.HSunApparentRaDec(jd)
|
||||
ra2, dec2 := basic.HSunApparentRaDecN(jd, -1)
|
||||
assertSamePair("HSunApparentRaDec", ra1, dec1, ra2, dec2)
|
||||
|
||||
assertSame("HMoonTrueLo", basic.HMoonTrueLo(jd), basic.HMoonTrueLoN(jd, -1))
|
||||
assertSame("HMoonTrueBo", basic.HMoonTrueBo(jd), basic.HMoonTrueBoN(jd, -1))
|
||||
assertSame("HMoonAway", basic.HMoonAway(jd), basic.HMoonAwayN(jd, -1))
|
||||
assertSame("HMoonApparentLo", basic.HMoonApparentLo(jd), basic.HMoonApparentLoN(jd, -1))
|
||||
assertSame("HMoonTrueRa", basic.HMoonTrueRa(jd), basic.HMoonTrueRaN(jd, -1))
|
||||
assertSame("HMoonTrueDec", basic.HMoonTrueDec(jd), basic.HMoonTrueDecN(jd, -1))
|
||||
ra1, dec1 = basic.HMoonTrueRaDec(jd)
|
||||
ra2, dec2 = basic.HMoonTrueRaDecN(jd, -1)
|
||||
assertSamePair("HMoonTrueRaDec", ra1, dec1, ra2, dec2)
|
||||
ra1, dec1 = basic.HMoonApparentRaDec(jd, lon, lat, tz)
|
||||
ra2, dec2 = basic.HMoonApparentRaDecN(jd, lon, lat, tz, -1)
|
||||
assertSamePair("HMoonApparentRaDec", ra1, dec1, ra2, dec2)
|
||||
assertSame("HMoonApparentRa", basic.HMoonApparentRa(jd, lon, lat, tz), basic.HMoonApparentRaN(jd, lon, lat, tz, -1))
|
||||
assertSame("HMoonApparentDec", basic.HMoonApparentDec(jd, lon, lat, tz), basic.HMoonApparentDecN(jd, lon, lat, tz, -1))
|
||||
assertSame("HMoonAzimuth", basic.HMoonAzimuth(jd, lon, lat, tz), basic.HMoonAzimuthN(jd, lon, lat, tz, -1))
|
||||
assertSame("HMoonHeight", basic.HMoonHeight(jd, lon, lat, tz), basic.HMoonHeightN(jd, lon, lat, tz, -1))
|
||||
}
|
||||
Reference in New Issue
Block a user