feat: 扩展天文计算能力

- 新增日食、月食、本地可见性、中心线、半影区域、SVG 图示与沙罗周期信息
- 新增行星冲合、留、方照、物理星历、视直径、相位、亮肢角、轨道节点等计算
- 新增木星伽利略卫星位置、现象与接触事件计算
- 新增恒星星表、星座判定、自行修正与观测辅助能力
- 新增 coord、formula、orbit、sundial、lite/sun、lite/moon 等扩展包
- 完善农历年号、月相英文别名、视差角、大气质量、折射、日晷与双星计算
- 增加 NASA、JPL Horizons、IMCCE 等回归测试数据与基线测试
- 重构基础算法文件组织,补充大量公开 API 注释和语义回归测试
- 更新中文和英文 README,补充示例、精度说明、SVG 配图
This commit is contained in:
2026-05-01 22:38:44 +08:00
parent 98ff574495
commit 3ffdbe0034
365 changed files with 63589 additions and 17508 deletions
+51 -78
View File
@@ -14,10 +14,10 @@ func StarHeight(jde, ra, dec, lon, lat, timezone float64) float64 {
// 计算视恒星时
st := Limit360(ApparentSiderealTime(utcJde)*15 + lon)
// 计算时角
H := Limit360(st - ra)
hourAngle := Limit360(st - ra)
// 高度角、时角与天球座标三角转换公式
// sin(h)=sin(lat)*sin(dec)+cos(dec)*cos(lat)*cos(H)
sinHeight := Sin(lat)*Sin(dec) + Cos(dec)*Cos(lat)*Cos(H)
// sin(h)=sin(lat)*sin(dec)+cos(dec)*cos(lat)*cos(hourAngle)
sinHeight := Sin(lat)*Sin(dec) + Cos(dec)*Cos(lat)*Cos(hourAngle)
return ArcSin(sinHeight)
}
@@ -30,20 +30,20 @@ func StarAzimuth(jde, ra, dec, lon, lat, timezone float64) float64 {
// 计算视恒星时
st := Limit360(ApparentSiderealTime(utcJde)*15 + lon)
// 计算时角
H := Limit360(st - ra)
hourAngle := Limit360(st - ra)
// 三角转换公式
tanAzimuth := Sin(H) / (Cos(H)*Sin(lat) - Tan(dec)*Cos(lat))
Azimuth := ArcTan(tanAzimuth)
if Azimuth < 0 {
if H/15 < 12 {
return Azimuth + 360
tanAzimuth := Sin(hourAngle) / (Cos(hourAngle)*Sin(lat) - Tan(dec)*Cos(lat))
azimuth := ArcTan(tanAzimuth)
if azimuth < 0 {
if hourAngle/15 < 12 {
return azimuth + 360
}
return Azimuth + 180
return azimuth + 180
}
if H/15 < 12 {
return Azimuth + 180
if hourAngle/15 < 12 {
return azimuth + 180
}
return Azimuth
return azimuth
}
// StarHourAngle 星体的时角
@@ -59,25 +59,25 @@ func StarHourAngle(jde, ra, lon, timezone float64) float64 {
}
// MeanSiderealTime 平恒星时
func MeanSiderealTime(JD float64) float64 {
return MeanSiderealTime2006(JD)
func MeanSiderealTime(jd float64) float64 {
return MeanSiderealTime2006(jd)
}
// ApparentSiderealTime 视恒星时,计算章动
func ApparentSiderealTime(JD float64) float64 {
return ApparentSiderealTime2006(JD)
func ApparentSiderealTime(jd float64) float64 {
return ApparentSiderealTime2006(jd)
}
// MeanSiderealTime1982 不含章动下的恒星时
func MeanSiderealTime1982(JD float64) float64 {
T := (JD - 2451545) / 36525
return (Limit360(280.46061837+360.98564736629*(JD-2451545.0)+0.000387933*T*T-T*T*T/38710000) / 15)
func MeanSiderealTime1982(jd float64) float64 {
t := (jd - 2451545) / 36525
return (Limit360(280.46061837+360.98564736629*(jd-2451545.0)+0.000387933*t*t-t*t*t/38710000) / 15)
}
// ApparentSiderealTime1982 视恒星时,计算章动
func ApparentSiderealTime1982(JD float64) float64 {
tmp := MeanSiderealTime1982(JD)
return tmp + Nutation2000Bi(JD)*Cos(Sita(JD))/15
func ApparentSiderealTime1982(jd float64) float64 {
tmp := MeanSiderealTime1982(jd)
return tmp + Nutation2000Bi(jd)*Cos(TrueObliquity(jd))/15
}
// EarthRotationAngle 计算地球自转角 (ERA)
@@ -116,82 +116,55 @@ func MeanSiderealTime2006(jd_ut1 float64) float64 {
}
// ApparentSiderealTime2006 视恒星时,计算章动
func ApparentSiderealTime2006(JD float64) float64 {
tmp := MeanSiderealTime2006(JD)
return tmp + Nutation2000Bi(JD)*Cos(Sita(JD))/15
func ApparentSiderealTime2006(jd float64) float64 {
tmp := MeanSiderealTime2006(jd)
return tmp + Nutation2000Bi(jd)*Cos(TrueObliquity(jd))/15
}
func StarAngle(RA, DEC, JD, Lon, Lat, TZ float64) float64 {
//JD=JD-8/24+TZ/24;
calcjd := JD - TZ/24
st := Limit360(ApparentSiderealTime(calcjd)*15 + Lon)
H := Limit360(st - RA)
tmp2 := Sin(H) / (Cos(H)*Sin(Lat) - Tan(DEC)*Cos(Lat))
Angle := ArcTan(tmp2)
if Angle < 0 {
if H/15 < 12 {
return Angle + 360
} else {
return Angle + 180
}
} else {
if H/15 < 12 {
return Angle + 180
} else {
return Angle
}
}
func StarRiseTime(jde, ra, dec, lon, lat, height, timezone float64, aero bool) (float64, error) {
return StarRiseSetTime(jde, ra, dec, lon, lat, height, timezone, aero, true)
}
func StarRiseTime(jde, ra, dec, lon, lat, height, timezone float64, aero bool) float64 {
return StarRiseDownTime(jde, ra, dec, lon, lat, height, timezone, aero, true)
func StarSetTime(jde, ra, dec, lon, lat, height, timezone float64, aero bool) (float64, error) {
return StarRiseSetTime(jde, ra, dec, lon, lat, height, timezone, aero, false)
}
func StarDownTime(jde, ra, dec, lon, lat, height, timezone float64, aero bool) float64 {
return StarRiseDownTime(jde, ra, dec, lon, lat, height, timezone, aero, false)
}
func StarRiseDownTime(jde, ra, dec, lon, lat, height, timezone float64, aero, isRise bool) float64 {
func StarRiseSetTime(jde, ra, dec, lon, lat, height, timezone float64, aero, isRise bool) (float64, error) {
//jde 世界时,非力学时,当地时区 0时,无需转换力学时
//ra,dec 瞬时天球座标,非J2000等时间天球坐标
jde = math.Floor(jde) + 0.5
var An float64 = 0
if aero {
An = -0.566667
}
An = An - HeightDegreeByLat(height, lat)
targetAltitude := StandardAltitudeStar(aero, height, lat)
sct := StarCulminationTime(jde, ra, lon, timezone)
tmp := (Sin(An) - Sin(dec)*Sin(lat)) / (Cos(dec) * Cos(lat))
tmp := (Sin(targetAltitude) - Sin(dec)*Sin(lat)) / (Cos(dec) * Cos(lat))
if math.Abs(tmp) > 1 {
if StarHeight(sct, ra, dec, lon, lat, timezone) < 0 {
return -2 //极夜
} else {
return -1 //极昼
return 0, ErrNeverRise
}
return 0, ErrNeverSet
}
var JD1 float64
var estimateJD float64
if isRise {
JD1 = sct - ArcCos(tmp)/15.0/24.0
estimateJD = sct - ArcCos(tmp)/15.0/24.0
} else {
JD1 = sct + ArcCos(tmp)/15.0/24.0
estimateJD = sct + ArcCos(tmp)/15.0/24.0
}
for {
JD0 := JD1
stDegree := StarHeight(JD0, ra, dec, lon, lat, timezone) - An
stDegreep := (StarHeight(JD0+0.000005, ra, dec, lon, lat, timezone) - StarHeight(JD0-0.000005, ra, dec, lon, lat, timezone)) / 0.00001
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 0.00001 {
prevJD := estimateJD
stDegree := StarHeight(prevJD, ra, dec, lon, lat, timezone) - targetAltitude
stDegreep := (StarHeight(prevJD+0.000005, ra, dec, lon, lat, timezone) - StarHeight(prevJD-0.000005, ra, dec, lon, lat, timezone)) / 0.00001
estimateJD = prevJD - stDegree/stDegreep
if math.Abs(estimateJD-prevJD) <= 0.00001 {
break
}
}
return JD1
return estimateJD, nil
}
func StarCulminationTime(jde, ra, lon, timezone float64) float64 {
//jde 世界时,非力学时,当地时区 0时,无需转换力学时
//ra,dec 瞬时天球座标,非J2000等时间天球坐标
jde = math.Floor(jde) + 0.5
JD1 := jde + Limit360(360-StarHourAngle(jde, ra, lon, timezone))/15.0/24.0*0.99726851851851851851
estimateJD := jde + Limit360(360-StarHourAngle(jde, ra, lon, timezone))/15.0/24.0*0.99726851851851851851
limitStarHA := func(jde, ra, lon, timezone float64) float64 {
ha := StarHourAngle(jde, ra, lon, timezone)
if ha < 180 {
@@ -200,15 +173,15 @@ func StarCulminationTime(jde, ra, lon, timezone float64) float64 {
return ha
}
for {
JD0 := JD1
stDegree := limitStarHA(JD0, ra, lon, timezone) - 360
stDegreep := (limitStarHA(JD0+0.000005, ra, lon, timezone) - limitStarHA(JD0-0.000005, ra, lon, timezone)) / 0.00001
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 0.00001 {
prevJD := estimateJD
stDegree := limitStarHA(prevJD, ra, lon, timezone) - 360
stDegreep := (limitStarHA(prevJD+0.000005, ra, lon, timezone) - limitStarHA(prevJD-0.000005, ra, lon, timezone)) / 0.00001
estimateJD = prevJD - stDegree/stDegreep
if math.Abs(estimateJD-prevJD) <= 0.00001 {
break
}
}
return JD1
return estimateJD
}
func StarAngularSeparation(ra1, dec1, ra2, dec2 float64) float64 {