astro/coord/research.go
starainrt c8dd777a7b
docs: 统一公开 API 的中英双语注释
- 补齐公开接口说明段的英文描述,保持签名注释和详细说明均为中英双语结构
- 规范农历、坐标、公式、轨道、日晷、太阳、恒星及行星事件等 API 的注释口径
2026-05-27 16:08:11 +08:00

237 lines
8.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package coord
import "math"
// Galactic 银道坐标 / galactic coordinates.
type Galactic struct {
Lon float64 // 银经,单位度 / galactic longitude in degrees.
Lat float64 // 银纬,单位度 / galactic latitude in degrees.
}
// SOFA ICRS2G/G2ICRS fixed rotation matrix.
// Source: IAU SOFA 2023-10-11, iauIcrs2g/iauG2icrs.
var icrsToGalacticMatrix = [3][3]float64{
{-0.054875560416215368492398900454, -0.873437090234885048760383168409, -0.483835015548713226831774175116},
{+0.494109427875583673525222371358, -0.444829629960011178146614061616, +0.746982244497218890527388004556},
{-0.867666149019004701181616534570, -0.198076373431201528180486091412, +0.455983776175066922272100478348},
}
// EclipticToEquatorialByObliquity 黄道转赤道坐标(指定黄赤交角) / ecliptic to equatorial by obliquity.
//
// lon: 黄经,单位度
// lat: 黄纬,单位度
// obliquity: 黄赤交角,单位度
//
// 返回:
//
// 赤经 RA单位度赤纬 Dec单位度
//
// Returns right ascension and declination in degrees for the supplied ecliptic longitude, latitude, and obliquity.
func EclipticToEquatorialByObliquity(lon, lat, obliquity float64) Equatorial {
sinLon, cosLon := sinCosDeg(lon)
sinLat, cosLat := sinCosDeg(lat)
sinObliquity, cosObliquity := sinCosDeg(obliquity)
ra := normalize360(math.Atan2(sinLon*cosObliquity-math.Tan(lat*math.Pi/180)*sinObliquity, cosLon) * 180 / math.Pi)
dec := math.Asin(clampUnit(sinLat*cosObliquity+cosLat*sinObliquity*sinLon)) * 180 / math.Pi
return Equatorial{RA: ra, Dec: dec}
}
// EquatorialToEclipticByObliquity 赤道转黄道坐标(指定黄赤交角) / equatorial to ecliptic by obliquity.
//
// ra: 赤经,单位度
// dec: 赤纬,单位度
// obliquity: 黄赤交角,单位度
//
// 返回:
//
// 黄经 Lon单位度黄纬 Lat单位度
//
// Returns ecliptic longitude and latitude in degrees for the supplied right ascension, declination, and obliquity.
func EquatorialToEclipticByObliquity(ra, dec, obliquity float64) Ecliptic {
sinRA, cosRA := sinCosDeg(ra)
sinDec, cosDec := sinCosDeg(dec)
sinObliquity, cosObliquity := sinCosDeg(obliquity)
lon := normalize360(math.Atan2(sinRA*cosObliquity+math.Tan(dec*math.Pi/180)*sinObliquity, cosRA) * 180 / math.Pi)
lat := math.Asin(clampUnit(sinDec*cosObliquity-cosDec*sinObliquity*sinRA)) * 180 / math.Pi
return Ecliptic{Lon: lon, Lat: lat}
}
// HourAngleDeclinationToHorizontal 时角赤纬转地平坐标 / horizontal coordinates from hour angle and declination.
//
// hourAngle: 时角,单位度
// declination: 赤纬,单位度
// latitude: 观测者地理纬度,单位度,北正南负
//
// 返回:
//
// 方位角 Azimuth正北为0顺时针增加、高度角 Altitude、天顶距 Zenith均为度
//
// Returns azimuth, altitude, and zenith distance in degrees from the supplied hour angle, declination, and site latitude.
func HourAngleDeclinationToHorizontal(hourAngle, declination, latitude float64) Horizontal {
sinLatitude, cosLatitude := sinCosDeg(latitude)
sinDeclination, cosDeclination := sinCosDeg(declination)
sinHourAngle, cosHourAngle := sinCosDeg(hourAngle)
altitude := math.Asin(clampUnit(sinLatitude*sinDeclination+cosLatitude*cosDeclination*cosHourAngle)) * 180 / math.Pi
azimuth := normalize360(math.Atan2(-cosDeclination*sinHourAngle, cosLatitude*sinDeclination-sinLatitude*cosDeclination*cosHourAngle) * 180 / math.Pi)
return Horizontal{
Azimuth: azimuth,
Altitude: altitude,
Zenith: 90 - altitude,
HourAngle: normalize360(hourAngle),
}
}
// HorizontalToHourAngleDeclination 地平坐标转时角赤纬 / hour angle and declination from horizontal coordinates.
//
// azimuth: 方位角单位度正北为0顺时针增加
// altitude: 高度角,单位度
// latitude: 观测者地理纬度,单位度,北正南负
//
// 返回:
//
// 时角 HourAngle单位度赤纬 Declination单位度
//
// Returns hour angle and declination in degrees from the supplied horizontal coordinates and site latitude.
func HorizontalToHourAngleDeclination(azimuth, altitude, latitude float64) (hourAngle, declination float64) {
sinLatitude, cosLatitude := sinCosDeg(latitude)
sinAltitude, cosAltitude := sinCosDeg(altitude)
sinAzimuth, cosAzimuth := sinCosDeg(azimuth)
declination = math.Asin(clampUnit(sinLatitude*sinAltitude+cosLatitude*cosAltitude*cosAzimuth)) * 180 / math.Pi
sinHourAngle := -cosAltitude * sinAzimuth
cosHourAngle := sinAltitude*cosLatitude - cosAltitude*sinLatitude*cosAzimuth
hourAngle = normalize360(math.Atan2(sinHourAngle, cosHourAngle) * 180 / math.Pi)
return hourAngle, declination
}
// EquatorialToHorizontalByLocalSiderealTime 赤道转地平坐标(指定地方恒星时) / equatorial to horizontal by local sidereal time.
//
// localSiderealTimeHours: 站点本地恒星时,单位小时
// ra: 赤经,单位度
// dec: 赤纬,单位度
// latitude: 观测者地理纬度,单位度,北正南负
//
// 返回:
//
// 方位角 Azimuth正北为0顺时针增加、高度角 Altitude、天顶距 Zenith均为度
// 附带返回对应的时角 HourAngle单位度
//
// Returns horizontal coordinates in degrees from local sidereal time, right ascension, declination, and site latitude.
//
// 例:
//
// hz := coord.EquatorialToHorizontalByLocalSiderealTime(10.5, 83.6331, 22.0145, 31.2)
func EquatorialToHorizontalByLocalSiderealTime(localSiderealTimeHours, ra, dec, latitude float64) Horizontal {
hourAngle := normalize360(localSiderealTimeHours*15 - ra)
return HourAngleDeclinationToHorizontal(hourAngle, dec, latitude)
}
// HorizontalToEquatorialByLocalSiderealTime 地平转赤道坐标(指定地方恒星时) / horizontal to equatorial by local sidereal time.
//
// localSiderealTimeHours: 站点本地恒星时,单位小时
// azimuth: 方位角单位度正北为0顺时针增加
// altitude: 高度角,单位度
// latitude: 观测者地理纬度,单位度,北正南负
//
// 返回:
//
// 赤经 RA单位度赤纬 Dec单位度
//
// Returns right ascension and declination in degrees from local sidereal time and the supplied horizontal coordinates.
//
// 例:
//
// eq := coord.HorizontalToEquatorialByLocalSiderealTime(10.5, 128.2, 37.6, 31.2)
func HorizontalToEquatorialByLocalSiderealTime(localSiderealTimeHours, azimuth, altitude, latitude float64) Equatorial {
hourAngle, declination := HorizontalToHourAngleDeclination(azimuth, altitude, latitude)
ra := normalize360(localSiderealTimeHours*15 - hourAngle)
return Equatorial{RA: ra, Dec: declination}
}
// EquatorialToGalactic 赤道转银道坐标 / equatorial to galactic coordinates.
//
// ra: ICRS 赤经,单位度
// dec: ICRS 赤纬,单位度
//
// 返回:
//
// 银经 Lon单位度银纬 Lat单位度
//
// Returns galactic longitude and latitude in degrees from ICRS right ascension and declination.
func EquatorialToGalactic(ra, dec float64) Galactic {
vector := sphericalToVector(ra, dec)
rotated := matrixVectorMul(icrsToGalacticMatrix, vector)
lon, lat := vectorToSpherical(rotated)
return Galactic{Lon: lon, Lat: lat}
}
// GalacticToEquatorial 银道转赤道坐标 / galactic to equatorial coordinates.
//
// lon: 银经,单位度
// lat: 银纬,单位度
//
// 返回:
//
// ICRS 赤经 RA单位度ICRS 赤纬 Dec单位度
//
// Returns ICRS right ascension and declination in degrees from galactic longitude and latitude.
func GalacticToEquatorial(lon, lat float64) Equatorial {
vector := sphericalToVector(lon, lat)
rotated := matrixTransposeVectorMul(icrsToGalacticMatrix, vector)
ra, dec := vectorToSpherical(rotated)
return Equatorial{RA: ra, Dec: dec}
}
func sinCosDeg(angle float64) (sinValue, cosValue float64) {
return math.Sincos(angle * math.Pi / 180)
}
func normalize360(angle float64) float64 {
angle = math.Mod(angle, 360)
if angle < 0 {
angle += 360
}
return angle
}
func clampUnit(value float64) float64 {
if value > 1 {
return 1
}
if value < -1 {
return -1
}
return value
}
func sphericalToVector(lon, lat float64) [3]float64 {
sinLon, cosLon := sinCosDeg(lon)
sinLat, cosLat := sinCosDeg(lat)
return [3]float64{cosLat * cosLon, cosLat * sinLon, sinLat}
}
func vectorToSpherical(vector [3]float64) (lon, lat float64) {
lon = normalize360(math.Atan2(vector[1], vector[0]) * 180 / math.Pi)
lat = math.Asin(clampUnit(vector[2])) * 180 / math.Pi
return lon, lat
}
func matrixVectorMul(matrix [3][3]float64, vector [3]float64) [3]float64 {
return [3]float64{
matrix[0][0]*vector[0] + matrix[0][1]*vector[1] + matrix[0][2]*vector[2],
matrix[1][0]*vector[0] + matrix[1][1]*vector[1] + matrix[1][2]*vector[2],
matrix[2][0]*vector[0] + matrix[2][1]*vector[1] + matrix[2][2]*vector[2],
}
}
func matrixTransposeVectorMul(matrix [3][3]float64, vector [3]float64) [3]float64 {
return [3]float64{
matrix[0][0]*vector[0] + matrix[1][0]*vector[1] + matrix[2][0]*vector[2],
matrix[0][1]*vector[0] + matrix[1][1]*vector[1] + matrix[2][1]*vector[2],
matrix[0][2]*vector[0] + matrix[1][2]*vector[1] + matrix[2][2]*vector[2],
}
}