16c62a97d5
- 新增时标、ΔT 模型、质心时间与 UT1 支持 - 改进日月食、月掩、行星事件及路径边界计算 - 完善恒星三维自行与动态距离传播 - 扩展 SVG、GeoJSON、KML 输出与底层距离换算工具 - 整理中英文手册、示例资源及回归测试
928 lines
56 KiB
Markdown
928 lines
56 KiB
Markdown
# Planets
|
|
|
|
[中文](../planets.md) | [Back to README](../../../README.en.md)
|
|
|
|
The seven major planets each have a package of their own: `mercury`, `venus`, `mars`, `jupiter`, `saturn`, `uranus`, and `neptune`.
|
|
|
|
They share the same API shape: a civil instant is passed as `time.Time`, angles and distances come back as `float64`, and event searches return `time.Time` or a struct.
|
|
|
|
The inner planets (Mercury and Venus) add superior/inferior conjunction, greatest elongation, and geocentric transit; the outer planets (Mars through Neptune) add opposition and quadrature; Jupiter alone has the Galilean satellites and Saturn alone has ring parameters. The low-level VSOP87 series and the solar/lunar analytic series live in the `planet` package, shared by these seven packages and by `sun` / `moon`.
|
|
|
|
- The function names of the common capabilities are identical across the seven packages (for example all of them provide `ApparentRa`, `ApparentDec`, and `ApparentRaDec`); only the extra families differ.
|
|
|
|
Always qualify a call with its package name instead of mixing packages.
|
|
- Position functions return a **geocentric apparent place**.
|
|
|
|
Topocentric quantities and horizontal coordinates are separate: `Altitude` / `Azimuth` / `Zenith` / `HourAngle` / `ParallacticAngle`, with formulas under [Coordinate Tools](coord.md).
|
|
- Event-search families come as `Last...` / `Next...` pairs (some also `Closest...`) and always return the nearest event at or before/after the input instant, endpoints included.
|
|
- The planets have no dedicated SVG chart entry point; occultation-related charts (including Saturn-ring occultations) are documented in [Lunar Occultations](occultation.md#lunar-occultation-charts).
|
|
|
|
## Contents
|
|
|
|
- [The position and rise time of Mars](#the-position-and-rise-time-of-mars)
|
|
- [API Reference](#api-reference)
|
|
- [Cross-planet comparison](#cross-planet-comparison)
|
|
- [Common capabilities and units](#common-capabilities-and-units)
|
|
- [The `...N` truncation family](#the-n-truncation-family)
|
|
- [Usage examples](#usage-examples)
|
|
- [Which planet can I see tonight?](#which-planet-can-i-see-tonight)
|
|
- [Oppositions, conjunctions, elongations, stations and retrogrades](#oppositions-conjunctions-elongations-stations-and-retrogrades)
|
|
- [Mercury and Venus transits](#mercury-and-venus-transits)
|
|
- [Phase, diameter, magnitude and nodes](#phase-diameter-magnitude-and-nodes)
|
|
- [Physical ephemerides and the Galilean satellites](#physical-ephemerides-and-the-galilean-satellites)
|
|
- [Comparison conventions](#comparison-conventions)
|
|
- [Basic examples](#basic-examples)
|
|
- [Inner planets](#inner-planets)
|
|
- [Outer planets](#outer-planets)
|
|
- [Topic examples](#topic-examples)
|
|
- [Position and coordinates](#position-and-coordinates)
|
|
- [Rise, set and culmination](#rise-set-and-culmination)
|
|
- [Conjunctions, oppositions, stations and quadratures](#conjunctions-oppositions-stations-and-quadratures)
|
|
- [Greatest elongation and geocentric transits](#greatest-elongation-and-geocentric-transits)
|
|
- [Nodes, phase, magnitude, diameter and parallactic angle](#nodes-phase-magnitude-diameter-and-parallactic-angle)
|
|
- [Division of labour with other manuals](#division-of-labour-with-other-manuals)
|
|
- [Physical ephemerides](#physical-ephemerides)
|
|
- [Galilean satellites of Jupiter](#galilean-satellites-of-jupiter)
|
|
- [Shared types and constants from the `planet` package](#shared-types-and-constants-from-the-planet-package)
|
|
- [Parameter and result conventions](#parameter-and-result-conventions)
|
|
- [Time scale and civil time](#time-scale-and-civil-time)
|
|
- [Units and conventions](#units-and-conventions)
|
|
- [Zero values, out-of-range input and sentinel errors](#zero-values-out-of-range-input-and-sentinel-errors)
|
|
- [Topocentric versus geocentric](#topocentric-versus-geocentric)
|
|
- [Accuracy and scope](#accuracy-and-scope)
|
|
|
|
## The position and rise time of Mars
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"b612.me/astro/mars"
|
|
)
|
|
|
|
func main() {
|
|
cst := time.FixedZone("CST", 8*3600)
|
|
date := time.Date(2020, 1, 1, 8, 8, 8, 0, cst)
|
|
lon, lat, height := 108.93, 34.27, 0.0
|
|
ra, dec := mars.ApparentRaDec(date)
|
|
fmt.Printf("RA=%.6f Dec=%.6f deg\n", ra, dec)
|
|
rise, err := mars.RiseTime(date, lon, lat, height, true)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Println(rise.Format(time.RFC3339))
|
|
}
|
|
```
|
|
|
|
`ApparentRaDec` returns geocentric apparent right ascension and declination in degrees. Rise/set also needs a site and ellipsoidal height, and returns an error when no rise event exists.
|
|
|
|
## API Reference
|
|
|
|
### Cross-planet comparison
|
|
|
|
Rows list capabilities and columns list planetary packages. Qualify each function with its package, for example `mars.NextOpposition`. A slash separates function names; `—` means the package has no corresponding API.
|
|
|
|
| Capability | `mercury` | `venus` | `mars` | `jupiter` | `saturn` | `uranus` | `neptune` |
|
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
| Apparent ecliptic longitude / latitude | `ApparentLo` / `ApparentBo` | `ApparentLo` / `ApparentBo` | `ApparentLo` / `ApparentBo` | `ApparentLo` / `ApparentBo` | `ApparentLo` / `ApparentBo` | `ApparentLo` / `ApparentBo` | `ApparentLo` / `ApparentBo` |
|
|
| Apparent right ascension / declination | `ApparentRa` / `ApparentDec` / `ApparentRaDec` | `ApparentRa` / `ApparentDec` / `ApparentRaDec` | `ApparentRa` / `ApparentDec` / `ApparentRaDec` | `ApparentRa` / `ApparentDec` / `ApparentRaDec` | `ApparentRa` / `ApparentDec` / `ApparentRaDec` | `ApparentRa` / `ApparentDec` / `ApparentRaDec` | `ApparentRa` / `ApparentDec` / `ApparentRaDec` |
|
|
| Apparent magnitude | `ApparentMagnitude` | `ApparentMagnitude` | `ApparentMagnitude` | `ApparentMagnitude` | `ApparentMagnitude` | `ApparentMagnitude` | `ApparentMagnitude` |
|
|
| Geocentric / heliocentric distance | `EarthDistance` / `SunDistance` | `EarthDistance` / `SunDistance` | `EarthDistance` / `SunDistance` | `EarthDistance` / `SunDistance` | `EarthDistance` / `SunDistance` | `EarthDistance` / `SunDistance` | `EarthDistance` / `SunDistance` |
|
|
| Orbital ascending / descending node | `AscendingNode` / `DescendingNode` | `AscendingNode` / `DescendingNode` | `AscendingNode` / `DescendingNode` | `AscendingNode` / `DescendingNode` | `AscendingNode` / `DescendingNode` | `AscendingNode` / `DescendingNode` | `AscendingNode` / `DescendingNode` |
|
|
| Apparent diameter / semidiameter | `Diameter` / `Semidiameter` | `Diameter` / `Semidiameter` | `Diameter` / `Semidiameter` | `Diameter` / `Semidiameter` | `Diameter` / `Semidiameter` | `Diameter` / `Semidiameter` | `Diameter` / `Semidiameter` |
|
|
| Phase angle / illuminated fraction / bright-limb position angle | `PhaseAngle` / `Phase` / `IlluminatedFraction` / `BrightLimbPositionAngle` | `PhaseAngle` / `Phase` / `IlluminatedFraction` / `BrightLimbPositionAngle` | `PhaseAngle` / `Phase` / `IlluminatedFraction` / `BrightLimbPositionAngle` | `PhaseAngle` / `Phase` / `IlluminatedFraction` / `BrightLimbPositionAngle` | `PhaseAngle` / `Phase` / `IlluminatedFraction` / `BrightLimbPositionAngle` | `PhaseAngle` / `Phase` / `IlluminatedFraction` / `BrightLimbPositionAngle` | `PhaseAngle` / `Phase` / `IlluminatedFraction` / `BrightLimbPositionAngle` |
|
|
| Topocentric horizontal quantities | `Altitude` / `Azimuth` / `Zenith` / `HourAngle` / `ParallacticAngle` | `Altitude` / `Azimuth` / `Zenith` / `HourAngle` / `ParallacticAngle` | `Altitude` / `Azimuth` / `Zenith` / `HourAngle` / `ParallacticAngle` | `Altitude` / `Azimuth` / `Zenith` / `HourAngle` / `ParallacticAngle` | `Altitude` / `Azimuth` / `Zenith` / `HourAngle` / `ParallacticAngle` | `Altitude` / `Azimuth` / `Zenith` / `HourAngle` / `ParallacticAngle` | `Altitude` / `Azimuth` / `Zenith` / `HourAngle` / `ParallacticAngle` |
|
|
| Rise / set / culmination | `RiseTime` / `SetTime` / `DownTime` / `CulminationTime` | `RiseTime` / `SetTime` / `DownTime` / `CulminationTime` | `RiseTime` / `SetTime` / `DownTime` / `CulminationTime` | `RiseTime` / `SetTime` / `DownTime` / `CulminationTime` | `RiseTime` / `SetTime` / `DownTime` / `CulminationTime` | `RiseTime` / `SetTime` / `DownTime` / `CulminationTime` | `RiseTime` / `SetTime` / `DownTime` / `CulminationTime` |
|
|
| Physical ephemeris | `Physical` / `PhysicalN` | `Physical` / `PhysicalN` | `Physical` / `PhysicalN` | `Physical` / `PhysicalN` / `CentralMeridians` / `CentralMeridiansN` | `Physical` / `PhysicalN` / `PhysicalSystemIII` / `Ring` | `Physical` / `PhysicalN` / `PhysicalSystemIII` | `Physical` / `PhysicalN` |
|
|
| Conjunction | `LastConjunction` / `NextConjunction` | `LastConjunction` / `NextConjunction` | `LastConjunction` / `NextConjunction` | `LastConjunction` / `NextConjunction` | `LastConjunction` / `NextConjunction` | `LastConjunction` / `NextConjunction` | `LastConjunction` / `NextConjunction` |
|
|
| Superior / inferior conjunction | `LastSuperiorConjunction` / `NextSuperiorConjunction` / `LastInferiorConjunction` / `NextInferiorConjunction` | `LastSuperiorConjunction` / `NextSuperiorConjunction` / `LastInferiorConjunction` / `NextInferiorConjunction` | — | — | — | — | — |
|
|
| Station | `LastProgradeToRetrograde` / `NextProgradeToRetrograde` / `LastRetrogradeToPrograde` / `NextRetrogradeToPrograde`, plus `LastRetrograde` / `NextRetrograde` | `LastProgradeToRetrograde` / `NextProgradeToRetrograde` / `LastRetrogradeToPrograde` / `NextRetrogradeToPrograde`, plus `LastRetrograde` / `NextRetrograde` | `LastProgradeToRetrograde` / `NextProgradeToRetrograde` / `LastRetrogradeToPrograde` / `NextRetrogradeToPrograde` | `LastProgradeToRetrograde` / `NextProgradeToRetrograde` / `LastRetrogradeToPrograde` / `NextRetrogradeToPrograde` | `LastProgradeToRetrograde` / `NextProgradeToRetrograde` / `LastRetrogradeToPrograde` / `NextRetrogradeToPrograde` | `LastProgradeToRetrograde` / `NextProgradeToRetrograde` / `LastRetrogradeToPrograde` / `NextRetrogradeToPrograde` | `LastProgradeToRetrograde` / `NextProgradeToRetrograde` / `LastRetrogradeToPrograde` / `NextRetrogradeToPrograde` |
|
|
| Opposition | — | — | `LastOpposition` / `NextOpposition` | `LastOpposition` / `NextOpposition` | `LastOpposition` / `NextOpposition` | `LastOpposition` / `NextOpposition` | `LastOpposition` / `NextOpposition` |
|
|
| Quadrature | — | — | `LastEasternQuadrature` / `NextEasternQuadrature` / `LastWesternQuadrature` / `NextWesternQuadrature` | `LastEasternQuadrature` / `NextEasternQuadrature` / `LastWesternQuadrature` / `NextWesternQuadrature` | `LastEasternQuadrature` / `NextEasternQuadrature` / `LastWesternQuadrature` / `NextWesternQuadrature` | `LastEasternQuadrature` / `NextEasternQuadrature` / `LastWesternQuadrature` / `NextWesternQuadrature` | `LastEasternQuadrature` / `NextEasternQuadrature` / `LastWesternQuadrature` / `NextWesternQuadrature` |
|
|
| Greatest elongation | `LastGreatestElongation` / `NextGreatestElongation` / `LastGreatestElongationEast` / `NextGreatestElongationEast` / `LastGreatestElongationWest` / `NextGreatestElongationWest` | `LastGreatestElongation` / `NextGreatestElongation` / `LastGreatestElongationEast` / `NextGreatestElongationEast` / `LastGreatestElongationWest` / `NextGreatestElongationWest` | — | — | — | — | — |
|
|
| Geocentric transit | `LastTransit` / `NextTransit` / `ClosestTransit` | `LastTransit` / `NextTransit` / `ClosestTransit` | — | — | — | — | — |
|
|
| Galilean satellites | — | — | — | `Satellites` / `SatellitePhenomena` / `LastGalileanPhenomenonEvent` / `NextGalileanPhenomenonEvent` / `ClosestGalileanPhenomenonEvent` / `LastGalileanPhenomenonContactEvent` / `NextGalileanPhenomenonContactEvent` / `ClosestGalileanPhenomenonContactEvent` | — | — | — |
|
|
| Result types | `PhysicalInfo` / `TransitInfo` | `PhysicalInfo` / `TransitInfo` | `PhysicalInfo` | `PhysicalInfo` / `CentralMeridianInfo` / `GalileanSatellitesInfo` / `GalileanPhenomenaInfo` / `GalileanSatellitePosition` / `GalileanSatellitePhenomenon` / `GalileanPhenomenonEvent` / `GalileanPhenomenonContactEvent` | `PhysicalInfo` / `RingInfo` | `PhysicalInfo` | `PhysicalInfo` |
|
|
|
|
All seven packages spell the **truncation family** the same way: append `N` to any instantaneous evaluation function, where `n < 0` uses the full built-in series and `n >= 0` truncates it.
|
|
|
|
See [the `...N` truncation family](#the-n-truncation-family) for details. Event-search families (`Last...` / `Next...` / `Closest...`) have no `N` variants.
|
|
|
|
### Common capabilities and units
|
|
|
|
| Capability | Purpose | Unit and convention |
|
|
| --- | --- | --- |
|
|
| `ApparentLo` / `ApparentBo` | Geocentric apparent ecliptic longitude and latitude | degrees; true equinox of date, including light time, aberration, and nutation |
|
|
| `ApparentRa` / `ApparentDec` / `ApparentRaDec` | Geocentric apparent right ascension and declination | degrees; true equator of date; `ApparentRaDec` returns both at once |
|
|
| `ApparentMagnitude` | Apparent visual magnitude | magnitudes (dimensionless) |
|
|
| `Altitude` / `Azimuth` / `Zenith` / `HourAngle` | Topocentric horizontal coordinates | degrees; azimuth runs from north toward east, and `Zenith` equals `90 - Altitude` |
|
|
| `RiseTime` / `SetTime` / `DownTime` | Rise and set within the local civil day | `time.Time` keeping the input time zone; `DownTime` is a compatibility alias for `SetTime` |
|
|
| `CulminationTime` | Upper culmination instant | `time.Time` keeping the input time zone |
|
|
| `ParallacticAngle` | Parallactic angle (zenith direction angle) | degrees |
|
|
| `Diameter` / `Semidiameter` | Geocentric apparent diameter and semidiameter | arcseconds |
|
|
| `PhaseAngle` | Sun-planet-Earth angle | degrees |
|
|
| `IlluminatedFraction` / `Phase` | Illuminated fraction | `0-1`; `Phase` is an alias for `IlluminatedFraction` |
|
|
| `BrightLimbPositionAngle` | Position angle of the bright-limb center | degrees |
|
|
| `EarthDistance` / `SunDistance` | Earth distance and Sun distance | AU |
|
|
| `AscendingNode` / `DescendingNode` | Ecliptic longitude of the orbital plane's intersections with the ecliptic | degrees; the two differ by about `180°` at the same instant |
|
|
| `Physical` | Disk orientation, sub-Earth/sub-Solar coordinates, north-pole position angle | degrees; the positive longitude direction follows each body's IAU convention |
|
|
| `planet.WherePlanet` / `planet.WherePlanetN` | VSOP87 longitude, latitude, and heliocentric distance | degrees / AU; out-of-range input returns `NaN` instead of panicking |
|
|
|
|
### The `...N` truncation family
|
|
|
|
Every instantaneous evaluation function has an `...N` variant that trades accuracy for cost: `n < 0` uses the full built-in series and is equivalent to the plain function, while `n >= 0` keeps roughly `n` principal terms and scales the higher orders proportionally.
|
|
|
|
Event-search families (`Last...` / `Next...` / `Closest...`) have no `N` variant.
|
|
|
|
Functions with an `N` variant include `ApparentLoN`, `ApparentBoN`, `ApparentRaN`, `ApparentDecN`, `ApparentRaDecN`, `ApparentMagnitudeN`, `EarthDistanceN`, `SunDistanceN`, `AltitudeN`, `AzimuthN`, `ZenithN`, `HourAngleN`, `CulminationTimeN`, `RiseTimeN`, `SetTimeN`, `DownTimeN`, `ParallacticAngleN`, `DiameterN`, `SemidiameterN`, `PhaseAngleN`, `PhaseN`, `IlluminatedFractionN`, `BrightLimbPositionAngleN`, `AscendingNodeN`, `DescendingNodeN`, and `PhysicalN`, plus `CentralMeridiansN` for Jupiter, `RingN` and `PhysicalSystemIIIN` for Saturn, and `PhysicalSystemIIIN` for Uranus.
|
|
|
|
```go
|
|
fmt.Println(mars.ApparentLo(date), mars.ApparentLoN(date, 8)) // ecliptic longitude: full series / truncated to about 8 terms
|
|
fmt.Println(mars.SunDistance(date), mars.SunDistanceN(date, 8)) // heliocentric distance, AU
|
|
```
|
|
|
|
## Usage examples
|
|
|
|
### Which planet can I see tonight?
|
|
|
|
```go
|
|
fmt.Println(venus.RiseTime(date, lon, lat, height, true)) // Venus rises today
|
|
fmt.Println(jupiter.CulminationTime(date, lon)) // Jupiter's upper culmination
|
|
fmt.Println(mars.Altitude(date, lon, lat), mars.Azimuth(date, lon, lat)) // Mars's altitude and azimuth now
|
|
```
|
|
|
|
```text
|
|
2020-01-01 10:02:34.350145161 +0800 CST <nil>
|
|
2020-01-01 12:32:17.585815787 +0800 CST
|
|
31.194578177219057 152.07031660415714
|
|
```
|
|
|
|
Above the horizon means `Altitude` greater than `0`, and azimuth increases from due north towards the east; `aero = true` lowers the geometric horizon to about `-0.5667°` for standard refraction.
|
|
|
|
Per-parameter conventions and the polar sentinel errors are in [Rise, set and culmination](#rise-set-and-culmination).
|
|
|
|
### Oppositions, conjunctions, elongations, stations and retrogrades
|
|
|
|
```go
|
|
fmt.Println(mars.NextOpposition(date)) // Mars's next opposition
|
|
fmt.Println(jupiter.NextConjunction(date)) // Jupiter's next conjunction
|
|
fmt.Println(saturn.NextProgradeToRetrograde(date)) // Saturn's next prograde-to-retrograde station
|
|
```
|
|
|
|
```text
|
|
2020-10-14 07:25:50.441412627 +0800 CST
|
|
2021-01-29 09:39:33.697994649 +0800 CST
|
|
2020-05-11 17:26:53.961271941 +0800 CST
|
|
```
|
|
|
|
Event searches return the nearest event at or after the input instant and keep its time zone; the paired `Last...` functions and the direction-agnostic `NextRetrograde` are in [Conjunctions, oppositions, stations and quadratures](#conjunctions-oppositions-stations-and-quadratures);
|
|
|
|
Mercury's and Venus's `NextGreatestElongationEast` / `...West` are in [Greatest elongation and geocentric transits](#greatest-elongation-and-geocentric-transits).
|
|
|
|
### Mercury and Venus transits
|
|
|
|
```go
|
|
transit := mercury.NextTransit(date) // next geocentric Mercury transit after 2020
|
|
fmt.Println(transit.Valid, transit.Start, transit.Greatest) // whether one was found, first contact, greatest transit
|
|
fmt.Println(transit.Duration, transit.MinimumSeparationArcsec) // duration and minimum separation at greatest transit
|
|
```
|
|
|
|
```text
|
|
true 2032-11-13 14:41:13.161198198 +0800 CST 2032-11-13 16:54:12.821315824 +0800 CST
|
|
4h26m2.695272267s 572.0643215495325
|
|
```
|
|
|
|
`TransitInfo.Valid` false means no transit inside the search window and every other field is the zero value; a transit is a geocentric geometry test and does not check whether the Sun is above the horizon at a given site.
|
|
|
|
The four contacts, partial transits and the internal-contact fields are in [Greatest elongation and geocentric transits](#greatest-elongation-and-geocentric-transits).
|
|
|
|
### Phase, diameter, magnitude and nodes
|
|
|
|
```go
|
|
fmt.Println(venus.PhaseAngle(date), venus.Phase(date)) // phase angle (degrees) and illuminated fraction
|
|
fmt.Println(venus.Diameter(date), venus.ApparentMagnitude(date)) // apparent diameter (arcseconds) and magnitude
|
|
fmt.Println(mars.AscendingNode(date), mars.DescendingNode(date)) // ascending/descending node longitudes (degrees)
|
|
```
|
|
|
|
```text
|
|
49.98145049145023 0.8215177914415865
|
|
13.059409604614839 -4
|
|
49.71479005849112 229.71479005849113
|
|
```
|
|
|
|
`Phase` is an alias of `IlluminatedFraction` and runs from `0` to `1`; the two nodes are about `180°` apart at any instant.
|
|
|
|
Definitions, aliases and the truncated versions are in [Nodes, phase, magnitude, diameter and parallactic angle](#nodes-phase-magnitude-diameter-and-parallactic-angle).
|
|
|
|
### Physical ephemerides and the Galilean satellites
|
|
|
|
```go
|
|
j := jupiter.Physical(date) // Jupiter's physical ephemeris
|
|
fmt.Println(j.DS, j.DE, j.CentralMeridianSystemIII) // sub-solar/sub-Earth latitude and System III central meridian
|
|
sats := jupiter.Satellites(date) // instantaneous positions of the four Galilean satellites
|
|
fmt.Println(sats.Io.OffsetXJupiterR, sats.Io.InFrontOfJupiter) // Io's offset and whether it is in front of the disk
|
|
```
|
|
|
|
```text
|
|
-56.55778470155335 -2.039966127259664 311.37430665615585
|
|
3.8223302102343975 false
|
|
```
|
|
|
|
Saturn's rings have their own `saturn.Ring` (`EarthLatitude`, `MinorAxis`, and so on; angles in degrees and axes in arcseconds). Disk orientation and the central meridians are covered in [Physical ephemerides](#physical-ephemerides); the Galilean-satellite public entry points are in the `jupiter` package, while `JupiterGalilean*` in `basic` is the low-level entry that takes a Julian day, see [Galilean satellites of Jupiter](#galilean-satellites-of-jupiter).
|
|
|
|
### Comparison conventions
|
|
|
|
```go
|
|
fmt.Println(mars.ApparentLo(date), mars.ApparentLoN(date, 8)) // apparent longitude with every term / truncated to about 8
|
|
_, err := mars.RiseTime(date, 0, 89, 0, true) // an observing site in the polar region
|
|
fmt.Println(errors.Is(err, mars.ERR_MARS_NEVER_RISE), errors.Is(err, mars.ERR_MARS_NEVER_SET))
|
|
```
|
|
|
|
```text
|
|
238.38840227925655 238.39637464888327
|
|
true false
|
|
```
|
|
|
|
`ApparentLo` and friends are geocentric apparent places referred to the **true equinox of date**; bring external J2000 or mean places to the same convention with `coord.Precess` before comparing.
|
|
|
|
In the truncation family `n < 0` uses every built-in term and `n >= 0` truncates.
|
|
|
|
The convention gap between the Galilean contact events and JPL Horizons / IMCCE tables is documented under [External baselines](#external-baselines), and the overall boundaries under [Parameter and result conventions](#parameter-and-result-conventions).
|
|
|
|
## Basic examples
|
|
|
|
The two examples below are the smallest runnable programs and use `date = 2020-01-01 08:08:08 CST` with the Xi'an coordinates.
|
|
|
|
### Inner planets
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"b612.me/astro/mercury"
|
|
"b612.me/astro/venus"
|
|
)
|
|
|
|
func main() {
|
|
// Xi'an, China. Longitude east and latitude north are positive; elevation is 0 m.
|
|
var lon, lat, height float64 = 108.93, 34.27, 0
|
|
cst := time.FixedZone("CST", 8*3600)
|
|
// Instant of observation.
|
|
date := time.Date(2020, 1, 1, 8, 8, 8, 8, cst)
|
|
|
|
// Previous inferior conjunction of Mercury.
|
|
fmt.Println(mercury.LastInferiorConjunction(date))
|
|
// Next superior conjunction of Venus.
|
|
fmt.Println(venus.NextSuperiorConjunction(date))
|
|
// Previous Mercury station from prograde to retrograde.
|
|
fmt.Println(mercury.LastProgradeToRetrograde(date))
|
|
// Next Venus station from retrograde to prograde.
|
|
fmt.Println(venus.NextRetrogradeToPrograde(date))
|
|
// Previous greatest eastern elongation of Mercury.
|
|
fmt.Println(mercury.LastGreatestElongationEast(date))
|
|
// Next greatest western elongation of Venus.
|
|
fmt.Println(venus.NextGreatestElongationWest(date))
|
|
// Venus rise and set times in Xi'an.
|
|
fmt.Println(venus.RiseTime(date, lon, lat, height, true))
|
|
fmt.Println(venus.SetTime(date, lon, lat, height, true))
|
|
// Current apparent magnitude of Venus.
|
|
fmt.Println(venus.ApparentMagnitude(date))
|
|
// Venus phase angle, illuminated fraction, and bright-limb position angle.
|
|
fmt.Println(venus.PhaseAngle(date))
|
|
fmt.Println(venus.Phase(date))
|
|
fmt.Println(venus.BrightLimbPositionAngle(date))
|
|
// Earth-Venus distance.
|
|
fmt.Println(venus.EarthDistance(date))
|
|
// Sun-Venus distance.
|
|
fmt.Println(venus.SunDistance(date))
|
|
}
|
|
```
|
|
|
|
Output:
|
|
|
|
```text
|
|
2019-11-11 23:21:41.971051096 +0800 CST // previous inferior conjunction of Mercury
|
|
2021-03-26 14:57:42.052354216 +0800 CST // next superior conjunction of Venus
|
|
2019-11-01 04:31:49.749019145 +0800 CST // previous Mercury station from prograde to retrograde
|
|
2020-06-25 02:07:41.599749326 +0800 CST // next Venus station from retrograde to prograde
|
|
2019-10-20 12:01:37.740152478 +0800 CST // previous greatest eastern elongation of Mercury
|
|
2020-08-13 08:14:46.304587125 +0800 CST // next greatest western elongation of Venus
|
|
2020-01-01 10:02:34.172435402 +0800 CST <nil> // Venus rise time in Xi'an; no error
|
|
2020-01-01 20:25:37.36411482 +0800 CST <nil> // Venus set time in Xi'an; no error
|
|
-4 // Venus apparent magnitude
|
|
49.98145049145023 // Venus phase angle, degrees
|
|
0.8215177914415865 // illuminated fraction of Venus
|
|
255.63802053541346 // bright-limb position angle of Venus, degrees
|
|
1.2778819631550336 // Earth-Venus distance, AU
|
|
0.7262651056423838 // Sun-Venus distance, AU
|
|
```
|
|
|
|
Inner and outer planets also expose `Diameter` / `Semidiameter` and `N` variants, returning geocentric apparent diameter/semidiameter in arcseconds.
|
|
|
|
Planet apparent diameter and orbital nodes can be queried directly:
|
|
|
|
```go
|
|
fmt.Println(mars.Diameter(date), mars.Semidiameter(date)) // Martian apparent diameter and semidiameter, arcseconds
|
|
fmt.Println(venus.AscendingNode(date), venus.DescendingNode(date)) // Venus ascending-node and descending-node ecliptic longitudes, degrees
|
|
```
|
|
|
|
Ascending node / descending node here means the two intersections of the body's orbital plane with the ecliptic:
|
|
|
|
- `AscendingNode`: ecliptic longitude where the body crosses from south of the ecliptic to north of it
|
|
- `DescendingNode`: ecliptic longitude where the body crosses from north of the ecliptic to south of it
|
|
- return values are degrees; for the same instant, descending node is usually about `180°` from ascending node
|
|
|
|
For `date := 2020-01-01 08:08:08 CST`, the output is:
|
|
|
|
```text
|
|
4.287299886569956 2.143649943284978 // Mars apparent diameter and semidiameter, arcseconds
|
|
76.86008484515058 256.8600848451506 // Venus ascending-node and descending-node longitudes, degrees
|
|
```
|
|
|
|
Mercury and Venus also expose `NextTransit` / `LastTransit` / `ClosestTransit` for geocentric planetary transits. "Geocentric" means the planet disk crosses the solar disk as seen from Earth's center; it does not test whether the Sun is above the horizon at a particular observing site. For observing plans, combine this with local solar altitude and weather.
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"b612.me/astro/mercury"
|
|
"b612.me/astro/venus"
|
|
)
|
|
|
|
func main() {
|
|
// Next geocentric Mercury transit after the beginning of 2019.
|
|
mercuryTransit := mercury.NextTransit(time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC))
|
|
fmt.Println(mercuryTransit.Valid)
|
|
fmt.Println(mercuryTransit.Start)
|
|
fmt.Println(mercuryTransit.InternalStart)
|
|
fmt.Println(mercuryTransit.Greatest)
|
|
fmt.Println(mercuryTransit.InternalEnd)
|
|
fmt.Println(mercuryTransit.End)
|
|
fmt.Println(mercuryTransit.Duration)
|
|
fmt.Println(mercuryTransit.MinimumSeparationArcsec)
|
|
fmt.Println(mercuryTransit.SunSemidiameterArcsec)
|
|
fmt.Println(mercuryTransit.PlanetSemidiameterArcsec)
|
|
|
|
// Next geocentric Venus transit after the beginning of 2012.
|
|
venusTransit := venus.NextTransit(time.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC))
|
|
fmt.Println(venusTransit.Valid)
|
|
fmt.Println(venusTransit.Start)
|
|
fmt.Println(venusTransit.InternalStart)
|
|
fmt.Println(venusTransit.Greatest)
|
|
fmt.Println(venusTransit.InternalEnd)
|
|
fmt.Println(venusTransit.End)
|
|
fmt.Println(venusTransit.Duration)
|
|
}
|
|
```
|
|
|
|
Output:
|
|
|
|
```text
|
|
true // a valid geocentric Mercury transit was found
|
|
2019-11-11 12:35:31.567597389 +0000 UTC // first contact: Mercury externally enters the solar disk
|
|
2019-11-11 12:37:12.817581295 +0000 UTC // second contact: Mercury is fully inside the solar disk
|
|
2019-11-11 15:19:48.36056292 +0000 UTC // greatest transit: Mercury center is closest to the Sun center
|
|
2019-11-11 18:02:29.176982045 +0000 UTC // third contact: Mercury starts leaving the solar disk
|
|
2019-11-11 18:04:10.637948513 +0000 UTC // fourth contact: Mercury externally leaves the solar disk
|
|
5h28m39.070351124s // geocentric transit duration from first to fourth contact
|
|
75.92400059923187 // minimum Mercury-Sun center separation at greatest transit, arcseconds
|
|
968.8881519533047 // solar semidiameter at greatest transit, arcseconds
|
|
4.978442871670873 // Mercury semidiameter at greatest transit, arcseconds
|
|
true // a valid geocentric Venus transit was found
|
|
2012-06-05 22:09:47.466886639 +0000 UTC // first contact: Venus externally enters the solar disk
|
|
2012-06-05 22:27:35.865356326 +0000 UTC // second contact: Venus is fully inside the solar disk
|
|
2012-06-06 01:29:35.572371482 +0000 UTC // greatest transit: Venus center is closest to the Sun center
|
|
2012-06-06 04:31:35.068444311 +0000 UTC // third contact: Venus starts leaving the solar disk
|
|
2012-06-06 04:49:23.25597167 +0000 UTC // fourth contact: Venus externally leaves the solar disk
|
|
6h39m35.789085031s // geocentric transit duration from first to fourth contact
|
|
```
|
|
|
|
### Outer planets
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"b612.me/astro/jupiter"
|
|
"b612.me/astro/mars"
|
|
"b612.me/astro/neptune"
|
|
"b612.me/astro/saturn"
|
|
"b612.me/astro/uranus"
|
|
)
|
|
|
|
func main() {
|
|
// Xi'an, China. Longitude east and latitude north are positive; elevation is 0 m.
|
|
var lon, lat, height float64 = 108.93, 34.27, 0
|
|
cst := time.FixedZone("CST", 8*3600)
|
|
// Instant of observation.
|
|
date := time.Date(2020, 1, 1, 8, 8, 8, 8, cst)
|
|
|
|
// Next opposition of Mars.
|
|
fmt.Println(mars.NextOpposition(date))
|
|
// Next conjunction of Jupiter.
|
|
fmt.Println(jupiter.NextConjunction(date))
|
|
// Previous Saturn station from prograde to retrograde.
|
|
fmt.Println(saturn.LastProgradeToRetrograde(date))
|
|
// Saturn ring observing parameters.
|
|
ring := saturn.Ring(date)
|
|
fmt.Printf("saturn B=%.6f Bp=%.6f P=%.6f dU=%.6f major=%.6f minor=%.6f\n",
|
|
ring.EarthLatitude,
|
|
ring.SunLatitude,
|
|
ring.PositionAngle,
|
|
ring.DeltaU,
|
|
ring.MajorAxis,
|
|
ring.MinorAxis,
|
|
)
|
|
// Next Uranus station from retrograde to prograde.
|
|
fmt.Println(uranus.NextRetrogradeToPrograde(date))
|
|
// Previous eastern quadrature of Neptune.
|
|
fmt.Println(neptune.LastEasternQuadrature(date))
|
|
// Next western quadrature of Mars.
|
|
fmt.Println(mars.NextWesternQuadrature(date))
|
|
// Mars rise and set times in Xi'an.
|
|
fmt.Println(mars.RiseTime(date, lon, lat, height, true))
|
|
fmt.Println(mars.SetTime(date, lon, lat, height, true))
|
|
// Current apparent magnitude of Mars.
|
|
fmt.Println(mars.ApparentMagnitude(date))
|
|
// Earth-Mars distance.
|
|
fmt.Println(mars.EarthDistance(date))
|
|
// Sun-Mars distance.
|
|
fmt.Println(mars.SunDistance(date))
|
|
}
|
|
```
|
|
|
|
Output:
|
|
|
|
```text
|
|
2020-10-14 07:25:50.441412627 +0800 CST // next opposition of Mars
|
|
2021-01-29 09:39:33.697994649 +0800 CST // next conjunction of Jupiter
|
|
2019-04-30 10:28:00.187439918 +0800 CST // previous Saturn station from prograde to retrograde
|
|
saturn B=23.577025 Bp=23.266930 P=6.629811 dU=1.171016 major=34.133852 minor=13.652911 // Saturn ring B, B', P, dU, major axis, minor axis
|
|
2020-01-11 15:23:23.360308706 +0800 CST // next Uranus station from retrograde to prograde
|
|
2019-12-08 17:00:15.517960488 +0800 CST // previous eastern quadrature of Neptune
|
|
2020-06-07 03:11:00.026179254 +0800 CST // next western quadrature of Mars
|
|
2020-01-01 04:41:29.621566236 +0800 CST <nil> // Mars rise time in Xi'an; no error
|
|
2020-01-01 14:55:32.963508367 +0800 CST <nil> // Mars set time in Xi'an; no error
|
|
1.57 // Mars apparent magnitude
|
|
2.1844284956325937 // Earth-Mars distance, AU
|
|
1.5897860004265403 // Sun-Mars distance, AU
|
|
```
|
|
|
|
`saturn.Ring` returns `RingInfo`: `EarthLatitude` is ring opening angle B, `SunLatitude` is B', `PositionAngle` is the position angle of the northern semiminor axis, `DeltaU` is the Saturnicentric longitude difference between the Sun and Earth in the ring plane, and `MajorAxis` / `MinorAxis` are the apparent outer major/minor axes in arcseconds.
|
|
|
|
## Topic examples
|
|
|
|
The snippets below are grouped by topic and all build on the shared variables `date`, `lon`, `lat`, and `height`; complete runnable versions are in the basic examples above.
|
|
|
|
### Position and coordinates
|
|
|
|
`ApparentLo` / `ApparentBo` / `ApparentRa` / `ApparentDec` / `ApparentRaDec` return a **geocentric apparent place**: the geometric geocentric position corrected for light time, aberration, and nutation, then converted to the true equator and equinox of date.
|
|
|
|
These packages do not provide J2000 or mean-place output; for a J2000 frame, use `coord.Precess` for precession and `coord.Nutation2000B` for nutation, and use `coord.TopocentricEquatorial` and `coord.EquatorialToHorizontal` for topocentric quantities. See [Coordinate Tools](coord.md).
|
|
|
|
```go
|
|
// Apparent place of date: ecliptic and equatorial coordinates, degrees.
|
|
lo, bo := venus.ApparentLo(date), venus.ApparentBo(date)
|
|
ra, dec := venus.ApparentRaDec(date)
|
|
fmt.Println(lo, bo, venus.ApparentRa(date), venus.ApparentDec(date), ra, dec)
|
|
|
|
// Earth distance and Sun distance, AU.
|
|
fmt.Println(venus.EarthDistance(date), venus.SunDistance(date))
|
|
```
|
|
|
|
### Rise, set and culmination
|
|
|
|
`RiseTime` / `SetTime` / `DownTime` work on the **local civil day** only: `date` selects the local date and the output time zone (when the local hour is greater than 12 it is first shifted back by 12 hours), `height` is the ellipsoidal height in meters, and `aero == true` adds standard atmospheric refraction (lowering the geometric horizon to about `-0.5667°`).
|
|
|
|
Polar day, polar night, or a day with no crossing returns a [sentinel error](#parameter-and-result-conventions) instead of an instant. `CulminationTime` gives upper culmination; `Altitude` / `Azimuth` / `Zenith` / `HourAngle` / `ParallacticAngle` form the topocentric family, with geometry under [Coordinate Tools](coord.md).
|
|
|
|
```go
|
|
// Rise, set, and culmination on the local civil day in Xi'an; aero=true adds refraction.
|
|
rise, err := mars.RiseTime(date, lon, lat, height, true)
|
|
set, err := mars.SetTime(date, lon, lat, height, true)
|
|
fmt.Println(rise, set, err)
|
|
fmt.Println(mars.CulminationTime(date, lon))
|
|
```
|
|
|
|
```go
|
|
// Topocentric horizontal quantities: east-positive longitude, north-positive latitude, degrees.
|
|
fmt.Println(mars.Altitude(date, lon, lat), mars.Azimuth(date, lon, lat))
|
|
fmt.Println(mars.Zenith(date, lon, lat), mars.HourAngle(date, lon))
|
|
fmt.Println(mars.ParallacticAngle(date, lon, lat))
|
|
```
|
|
|
|
```go
|
|
// DownTime is a compatibility alias for SetTime; the N variant evaluates a truncated series.
|
|
set, err := mars.DownTime(date, lon, lat, height, true)
|
|
fmt.Println(set, err)
|
|
fmt.Println(mars.CulminationTimeN(date, lon, 12))
|
|
```
|
|
|
|
### Conjunctions, oppositions, stations and quadratures
|
|
|
|
Event searches always return the nearest event at or before/after the input instant (endpoints included), in the input time zone. The inner planets use `LastConjunction` / `NextConjunction` plus the superior/inferior conjunction family; the outer planets use `LastConjunction` / `NextConjunction`, `LastOpposition` / `NextOpposition`, and the eastern/western quadrature family.
|
|
|
|
Stations come in two directions: `LastProgradeToRetrograde` / `NextProgradeToRetrograde` (prograde to retrograde) and `LastRetrogradeToPrograde` / `NextRetrogradeToPrograde` (retrograde to prograde); Mercury and Venus additionally have `LastRetrograde` / `NextRetrograde`, which ignore the direction, and the outer planets do not have those two names.
|
|
|
|
For the inner planets a conjunction is simply "on the same side as the Sun"; the outer planets additionally split opposition and quadrature: only the five planets outside Earth's orbit can reach opposition (Sun-Earth-planet in a line) or eastern/western quadrature (about 90° of ecliptic longitude from the Sun).
|
|
|
|
Mercury and Venus stay inside Earth's orbit, so those two families exist only in the outer-planet packages.
|
|
|
|
```go
|
|
// Inner planets: superior/inferior conjunction, and direction-agnostic stations.
|
|
fmt.Println(mercury.LastSuperiorConjunction(date), mercury.NextInferiorConjunction(date))
|
|
fmt.Println(mercury.LastRetrograde(date), mercury.NextRetrograde(date))
|
|
```
|
|
|
|
```go
|
|
// Outer planets: conjunction, opposition, and eastern/western quadrature.
|
|
fmt.Println(jupiter.NextConjunction(date), mars.NextOpposition(date))
|
|
fmt.Println(mars.NextEasternQuadrature(date), neptune.LastWesternQuadrature(date))
|
|
```
|
|
|
|
```go
|
|
// Both station directions have Last/Next forms.
|
|
fmt.Println(saturn.LastProgradeToRetrograde(date), saturn.NextProgradeToRetrograde(date))
|
|
fmt.Println(saturn.LastRetrogradeToPrograde(date), saturn.NextRetrogradeToPrograde(date))
|
|
```
|
|
|
|
### Greatest elongation and geocentric transits
|
|
|
|
Greatest elongation only makes sense for Mercury and Venus: `LastGreatestElongation` / `NextGreatestElongation` ignore the side, while `LastGreatestElongationEast` / `NextGreatestElongationEast` and the `...West` forms distinguish it.
|
|
|
|
The public entry points for geocentric transits are likewise only in `mercury` / `venus`: `LastTransit` / `NextTransit` / `ClosestTransit` return a `TransitInfo`.
|
|
|
|
`Valid == false` means no transit inside the search window and every other field is a zero value; a partial transit has no internal contacts, so `HasInternal` is false and `InternalStart` / `InternalEnd` are zero.
|
|
|
|
A transit is a purely geocentric geometry test and does not check whether the Sun is above the horizon at a given site.
|
|
|
|
```go
|
|
// Greatest elongation: use ...East / ...West to pick a side, or the plain form for either.
|
|
fmt.Println(mercury.NextGreatestElongationEast(date), venus.LastGreatestElongationWest(date))
|
|
fmt.Println(venus.NextGreatestElongation(date))
|
|
```
|
|
|
|
```go
|
|
// Geocentric transit: when Valid is false every other field is a zero value.
|
|
transit := mercury.NextTransit(date)
|
|
if transit.Valid {
|
|
fmt.Println(transit.Start, transit.InternalStart, transit.Greatest, transit.InternalEnd, transit.End)
|
|
fmt.Println(transit.Duration, transit.MinimumSeparationArcsec, transit.SunSemidiameterArcsec)
|
|
}
|
|
```
|
|
|
|
```go
|
|
// Remaining transit fields; InternalDuration is 0 when there are no internal contacts.
|
|
transit := venus.ClosestTransit(date)
|
|
fmt.Println(transit.HasInternal, transit.InternalDuration, transit.MinimumSeparationArcsec)
|
|
fmt.Println(transit.SunSemidiameterArcsec, transit.PlanetSemidiameterArcsec)
|
|
```
|
|
|
|
### Nodes, phase, magnitude, diameter and parallactic angle
|
|
|
|
`AscendingNode` / `DescendingNode` are the ecliptic longitudes of the two intersections of the planet's orbital plane with the ecliptic, in degrees, about `180°` apart at the same instant.
|
|
|
|
`PhaseAngle` is the Sun-planet-Earth angle in degrees; `IlluminatedFraction` (alias `Phase`) is the illuminated fraction from `0` to `1`; `BrightLimbPositionAngle` is the position angle of the bright-limb center in degrees.
|
|
|
|
`Diameter` / `Semidiameter` return the geocentric apparent diameter and semidiameter in arcseconds. `ParallacticAngle` returns the topocentric parallactic angle (zenith direction angle) in degrees; topocentric coordinates are under [Coordinate Tools](coord.md).
|
|
|
|
```go
|
|
fmt.Println(mars.AscendingNode(date), mars.DescendingNode(date)) // node longitudes, degrees
|
|
fmt.Println(mars.PhaseAngle(date), mars.IlluminatedFraction(date), mars.Phase(date)) // phase angle in degrees; illuminated fraction
|
|
fmt.Println(mars.ApparentMagnitude(date), mars.BrightLimbPositionAngle(date)) // apparent magnitude; bright-limb position angle
|
|
```
|
|
|
|
```go
|
|
fmt.Println(mars.Diameter(date), mars.Semidiameter(date)) // apparent diameter and semidiameter, arcseconds
|
|
fmt.Println(mars.ParallacticAngle(date, lon, lat)) // parallactic angle, degrees
|
|
```
|
|
|
|
```go
|
|
// Nodes and apparent diameter also have truncated variants.
|
|
fmt.Println(mars.AscendingNodeN(date, 12), mars.DescendingNodeN(date, 12))
|
|
fmt.Println(mars.DiameterN(date, 12), mars.SemidiameterN(date, 12))
|
|
```
|
|
|
|
### Division of labour with other manuals
|
|
|
|
- Sidereal time, precession and nutation, and topocentric/horizontal conversion are in [Coordinate Tools](coord.md).
|
|
- Sun and Moon positions, phases, rise/set, and syzygies are in the [Sun and Moon manual](sun-moon.md).
|
|
- Planetary occultations, occultation bands, and lunar-disk charts are in [Lunar Occultations](occultation.md#lunar-occultation-charts).
|
|
- Asteroids, comets, and other bodies computed from orbital elements are in [Small-body orbits](orbit.md).
|
|
- Time-scale declarations, UT1 conventions, and GeoJSON output are in [Event Maps and GeoJSON](map-geojson.md); the scale convention itself is in [Time Scale Declaration](map-geojson.md#time-scale-declaration).
|
|
- The authoritative capability list, dependency matrix, and accuracy summary are in the root [README](../../../README.en.md).
|
|
|
|
### Physical ephemerides
|
|
|
|
All seven major planets provide `Physical` / `PhysicalN` for disk orientation, sub-Earth/sub-Sun coordinates, and north-pole position angle. Jupiter additionally exposes System I/II/III central meridians, and Saturn exposes ring parameters.
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"b612.me/astro/jupiter"
|
|
"b612.me/astro/saturn"
|
|
)
|
|
|
|
func main() {
|
|
date := time.Date(2025, 11, 1, 0, 0, 0, 0, time.UTC)
|
|
|
|
// Jupiter: DS and DE are planetocentric declinations of the Sun and Earth relative to Jupiter's equator.
|
|
// CMI/CMII/CMIII are Jupiter System I/II/III central meridians, degrees.
|
|
j := jupiter.Physical(date)
|
|
fmt.Printf("jupiter DS=%.6f DE=%.6f CMI=%.6f CMII=%.6f CMIII=%.6f\n",
|
|
j.DS,
|
|
j.DE,
|
|
j.CentralMeridianSystemI,
|
|
j.CentralMeridianSystemII,
|
|
j.CentralMeridianSystemIII,
|
|
)
|
|
|
|
// Saturn ring: B/B' are ring-plane latitudes seen from Earth and Sun; P is the position angle of the ring minor axis.
|
|
ring := saturn.Ring(date)
|
|
fmt.Printf("saturn B=%.6f Bp=%.6f P=%.6f major=%.6f minor=%.6f\n",
|
|
ring.EarthLatitude,
|
|
ring.SunLatitude,
|
|
ring.PositionAngle,
|
|
ring.MajorAxis,
|
|
ring.MinorAxis,
|
|
)
|
|
}
|
|
```
|
|
|
|
Output:
|
|
|
|
```text
|
|
jupiter DS=54.342153 DE=1.436485 CMI=292.712909 CMII=276.309048 CMIII=147.241811 // Jupiter DS/DE and System I/II/III central meridians, degrees
|
|
saturn B=-0.608048 Bp=-2.675677 P=4.480276 major=42.709920 minor=0.453248 // Saturn ring B, B', minor-axis position angle, outer major/minor axes
|
|
```
|
|
|
|
If only Jupiter central meridians are needed:
|
|
|
|
```go
|
|
cm := jupiter.CentralMeridians(date)
|
|
fmt.Printf("CMI=%.6f CMII=%.6f CMIII=%.6f\n", cm.SystemI, cm.SystemII, cm.SystemIII) // Jupiter System I/II/III central meridians
|
|
```
|
|
|
|
Saturn and Uranus also retain explicit `System III` semantic aliases:
|
|
|
|
```go
|
|
sat3 := saturn.PhysicalSystemIII(date)
|
|
ura3 := uranus.PhysicalSystemIII(date)
|
|
fmt.Printf("saturn systemIII lon=%.6f lat=%.6f P=%.6f\n", sat3.SubEarthLongitude, sat3.SubEarthLatitude, sat3.NorthPolePositionAngle) // Saturn sub-Earth longitude/latitude and north-pole position angle
|
|
fmt.Printf("uranus systemIII lon=%.6f lat=%.6f P=%.6f\n", ura3.SubEarthLongitude, ura3.SubEarthLatitude, ura3.NorthPolePositionAngle) // Uranus sub-Earth longitude/latitude and north-pole position angle
|
|
```
|
|
|
|
All seven packages return their own `PhysicalInfo`, whose fields mirror `basic.PlanetPhysicalInfo` one for one.
|
|
|
|
The positive direction of `SubEarthLongitude` / `SubSolarLongitude` follows each body's current IAU/Horizons cartographic convention: Mercury, Mars, Jupiter, Saturn, and Neptune use west-positive longitudes, while Venus and Uranus use east-positive longitudes.
|
|
|
|
Saturn-ring parameters describe only the disk and band; they take no part in occultation contact geometry, and charts are in [Lunar Occultations](occultation.md#lunar-occultation-charts).
|
|
|
|
```go
|
|
p := uranus.Physical(date) // Uranus sub-Earth/sub-Solar coordinates and north-pole position angle, degrees
|
|
fmt.Println(p.SubEarthLongitude, p.SubEarthLatitude, p.SubSolarLongitude, p.SubSolarLatitude, p.NorthPolePositionAngle)
|
|
```
|
|
|
|
```go
|
|
// Truncated variants of the Saturn ring and the Jupiter central meridians.
|
|
fmt.Println(saturn.RingN(date, 12).MinorAxis, jupiter.CentralMeridiansN(date, 12).SystemIII)
|
|
```
|
|
|
|
### Galilean satellites of Jupiter
|
|
|
|
The public entry points are in the **`jupiter` package** (`jupiter.Satellites`, `jupiter.SatellitePhenomena`, `jupiter.NextGalileanPhenomenonEvent`, and so on); they take a `time.Time` and return Jupiter's own types.
|
|
|
|
The `JupiterGalilean*` functions in `basic` (such as `basic.JupiterGalileanSatelliteObservations` and `basic.NextJupiterGalileanPhenomenonEvent`) are the low-level entries of the same implementation: they take a Julian day and return `basic` types.
|
|
|
|
Applications should use the `jupiter` layer.
|
|
|
|
```go
|
|
// Entry point is in the jupiter package; satellite numbers use jupiter.GalileanSatelliteIo and friends.
|
|
sats := jupiter.Satellites(date)
|
|
fmt.Println(sats.Io.OffsetXJupiterR, sats.Io.OffsetYJupiterR, sats.Io.InFrontOfJupiter)
|
|
```
|
|
|
|
Satellite numbers and phenomenon types have named constants, so there is no need to write raw numbers or strings:
|
|
|
|
- Satellite numbers: `GalileanSatelliteIo`, `GalileanSatelliteEuropa`, `GalileanSatelliteGanymede`, `GalileanSatelliteCallisto`
|
|
- Phenomenon types (`GalileanPhenomenonType`): `GalileanPhenomenonTransit`, `GalileanPhenomenonOccultation`, `GalileanPhenomenonEclipse`, `GalileanPhenomenonShadowTransit`
|
|
- Contact phases (`GalileanPhenomenonContactPhase`): `GalileanPhenomenonContactDisappearance`, `GalileanPhenomenonContactReappearance`
|
|
|
|
```go
|
|
// Satellite numbers and phenomenon types are constants, so no raw numbers or strings are needed.
|
|
event := jupiter.NextGalileanPhenomenonEvent(date, jupiter.GalileanSatelliteCallisto, jupiter.GalileanPhenomenonShadowTransit)
|
|
fmt.Println(event.Type == jupiter.GalileanPhenomenonShadowTransit)
|
|
```
|
|
|
|
The `jupiter` package provides apparent positions, instantaneous phenomena, and event searches for the four Galilean satellites.
|
|
|
|
Common entry points:
|
|
|
|
- `Satellites`: instantaneous apparent positions relative to Jupiter's disk
|
|
- `SatellitePhenomena`: instantaneous transit, occultation, eclipse, and shadow-transit flags
|
|
- `LastGalileanPhenomenonEvent` / `NextGalileanPhenomenonEvent` / `ClosestGalileanPhenomenonEvent`: search whole phenomenon intervals
|
|
- `LastGalileanPhenomenonContactEvent` / `NextGalileanPhenomenonContactEvent` / `ClosestGalileanPhenomenonContactEvent`: search IMCCE-style D/F contact events
|
|
|
|
Two conventions matter:
|
|
|
|
- `GalileanPhenomenonEvent` treats the satellite as a point and checks when its center enters or leaves Jupiter's disk. It is suitable for fast phenomenon search and internal state checks.
|
|
- `GalileanPhenomenonContactEvent` includes the finite disk of the satellite and splits disappearance and reappearance contact windows. It is the better match for IMCCE tables such as `TR.D/TR.F/OC.D/OC.F/EC.D/EC.F/SH.D/SH.F`.
|
|
|
|
The two conventions may differ by up to about 7 minutes in duration. This is a definition difference, not a timing-accuracy failure. Use `GalileanPhenomenonContactEvent` for observing predictions and direct comparison with public almanacs.
|
|
|
|
#### Code example
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"b612.me/astro/jupiter"
|
|
)
|
|
|
|
func main() {
|
|
date := time.Date(2026, 1, 15, 0, 0, 0, 0, time.UTC)
|
|
|
|
// Instantaneous positions of the four satellites relative to Jupiter's center.
|
|
sats := jupiter.Satellites(date)
|
|
fmt.Printf("io x=%.6f y=%.6f front=%v\n", sats.Io.OffsetXJupiterR, sats.Io.OffsetYJupiterR, sats.Io.InFrontOfJupiter)
|
|
fmt.Printf("europa ra=%.6f dec=%.6f\n", sats.Europa.ApparentRA, sats.Europa.ApparentDec)
|
|
|
|
// Instantaneous phenomenon flags.
|
|
ph := jupiter.SatellitePhenomena(date)
|
|
fmt.Printf("io transit=%v occultation=%v eclipse=%v shadow=%v\n", ph.Io.Transit, ph.Io.Occultation, ph.Io.Eclipse, ph.Io.ShadowTransit)
|
|
fmt.Printf("europa transit=%v occultation=%v eclipse=%v shadow=%v\n", ph.Europa.Transit, ph.Europa.Occultation, ph.Europa.Eclipse, ph.Europa.ShadowTransit)
|
|
|
|
// Next full Io transit event.
|
|
event := jupiter.NextGalileanPhenomenonEvent(date, jupiter.GalileanSatelliteIo, jupiter.GalileanPhenomenonTransit)
|
|
fmt.Printf("event valid=%v sat=%d type=%s\n", event.Valid, event.Satellite, event.Type)
|
|
fmt.Println(event.Start)
|
|
fmt.Println(event.Greatest)
|
|
fmt.Println(event.End)
|
|
fmt.Println(event.Duration)
|
|
|
|
// Next IMCCE-style contact window for a Europa occultation.
|
|
contact := jupiter.NextGalileanPhenomenonContactEvent(date, jupiter.GalileanSatelliteEuropa, jupiter.GalileanPhenomenonOccultation)
|
|
fmt.Printf("contact valid=%v sat=%d type=%s\n", contact.Valid, contact.Satellite, contact.Type)
|
|
fmt.Println(contact.Disappearance.Start)
|
|
fmt.Println(contact.Disappearance.ModelCrossing)
|
|
fmt.Println(contact.Disappearance.End)
|
|
fmt.Println(contact.Greatest)
|
|
fmt.Println(contact.Reappearance.Start)
|
|
fmt.Println(contact.Reappearance.ModelCrossing)
|
|
fmt.Println(contact.Reappearance.End)
|
|
}
|
|
```
|
|
|
|
Output:
|
|
|
|
```text
|
|
io x=-0.675026 y=-0.032798 front=true // Io X/Y offset from Jupiter center, in Jupiter radii; in front of Jupiter
|
|
europa ra=110.769133 dec=22.335828 // Europa apparent RA and Dec, degrees
|
|
io transit=true occultation=false eclipse=false shadow=true // Io is transiting, and its shadow is also transiting
|
|
europa transit=false occultation=false eclipse=false shadow=false // Europa has no transit, occultation, eclipse, or shadow transit at this instant
|
|
event valid=true sat=1 type=transit // next valid event is an Io transit
|
|
2026-01-16 16:32:47.552742362 +0000 UTC // Io transit begins
|
|
2026-01-16 17:40:44.189371168 +0000 UTC // midpoint of the Io transit
|
|
2026-01-16 18:48:40.287077128 +0000 UTC // Io transit ends
|
|
2h15m52.734334766s // Io transit duration
|
|
contact valid=true sat=2 type=occultation // next valid contact event is a Europa occultation
|
|
2026-01-17 01:00:34.99533087 +0000 UTC // Europa occultation disappearance starts
|
|
2026-01-17 01:02:31.714070141 +0000 UTC // model center crossing during disappearance
|
|
2026-01-17 01:04:28.432809412 +0000 UTC // disappearance ends
|
|
2026-01-17 02:27:37.807798683 +0000 UTC // deepest occultation
|
|
2026-01-17 03:50:48.120300471 +0000 UTC // reappearance starts
|
|
2026-01-17 03:52:43.901527225 +0000 UTC // model center crossing during reappearance
|
|
2026-01-17 03:54:39.68275398 +0000 UTC // reappearance ends
|
|
```
|
|
|
|
#### External baselines
|
|
|
|
The Galilean-satellite implementation was checked against two external baselines:
|
|
|
|
- **JPL Horizons**: apparent positions of the four satellites relative to Jupiter's center, and shadow-center offsets from Jupiter's disk during shadow transits.
|
|
- **IMCCE 2026 tables**: transits, occultations, Jupiter eclipses, shadow transits, and D/F contact windows.
|
|
|
|
Comparison results:
|
|
|
|
- `Satellites` positions relative to Jupiter center: maximum sample difference against JPL Horizons about `X=0.054"`, `Y=0.048"`.
|
|
- `SatellitePhenomena` shadow-transit shadow-center offsets: maximum sample difference against JPL Horizons about `X=0.051"`, `Y=0.016"`; boolean phenomenon flags match in the samples.
|
|
- `GalileanPhenomenonContactEvent` differs from IMCCE 2026 D/F contact times by at most about `79 s`, and contact durations by about `17 s` in the compared cases.
|
|
- `GalileanPhenomenonEvent` uses a different definition from IMCCE D/F contacts, so start and end times can differ by about `7 min`.
|
|
|
|
### Shared types and constants from the `planet` package
|
|
|
|
The `planet` package is the low-level analytic-series entry point, shared by the seven planet packages and by `sun` / `moon`.
|
|
|
|
It exports functions only and **no types**, so what the planet packages really share is one set of numerical conventions and truncation semantics rather than shared types: each package's `PhysicalInfo` mirrors `basic.PlanetPhysicalInfo` and `TransitInfo` mirrors `basic.PlanetTransitResult`, field for field, while the types themselves still belong to their own packages.
|
|
|
|
| Entry point | Purpose | Unit |
|
|
| --- | --- | --- |
|
|
| `planet.WherePlanet` / `planet.WherePlanetN` | VSOP87 result: `xt` is `1..7` for Mercury through Neptune and `-1` or `0` for Earth, `zn` is `0` longitude, `1` latitude, `2` heliocentric distance; an out-of-range `xt` / `zn` returns `NaN` instead of panicking | degrees / AU |
|
|
| `planet.Distance` | Sun-Earth distance | AU |
|
|
| `planet.SunLo` / `planet.SunM` / `planet.SunMidFun` / `planet.SunTrueLo` / `planet.SunApparentLo` | Solar geometric longitude, mean anomaly, equation of center, true longitude, apparent longitude | degrees |
|
|
| `planet.Earthe` / `planet.EarthPI` | Earth's orbital eccentricity and longitude of perihelion | dimensionless / degrees |
|
|
| `planet.MoonLo` / `planet.MoonM` / `planet.MoonLonX` / `planet.SunMoonAngle` | Lunar mean longitude, mean anomaly, mean argument of latitude, and mean elongation | degrees |
|
|
| `planet.MoonI` / `planet.MoonB` / `planet.MoonR` | Periodic longitude, latitude, and distance terms (truncated ELP2000/82-style series) | `10⁻⁶` degrees / `10⁻⁶` degrees / `10⁻³ km` |
|
|
| `planet.MoonTrueLo` / `planet.MoonTrueBo` / `planet.MoonAway` | Lunar true longitude, true latitude, and Earth distance | degrees / degrees / km |
|
|
|
|
```go
|
|
// xt=1..7 is Mercury..Neptune; zn=0 longitude, 1 latitude, 2 heliocentric distance (AU).
|
|
fmt.Println(planet.WherePlanet(4, 2, 2460000.5)) // Jupiter heliocentric distance, AU
|
|
fmt.Println(planet.WherePlanetN(4, 2, 2460000.5, 12)) // truncated form, about 12 principal terms
|
|
fmt.Println(planet.WherePlanet(8, 0, 2460000.5)) // xt out of range: NaN
|
|
```
|
|
|
|
```go
|
|
// Earth's heliocentric longitude (xt=-1) and a planet's can be compared on the same convention.
|
|
fmt.Println(planet.WherePlanet(-1, 0, 2460000.5), planet.WherePlanet(4, 0, 2460000.5))
|
|
```
|
|
|
|
## Parameter and result conventions
|
|
|
|
The conventions below are shared by all seven packages; per-capability return units are summarised under [Common capabilities and units](#common-capabilities-and-units).
|
|
|
|
### Time scale and civil time
|
|
|
|
Every public API treats its `time.Time` argument as a **civil instant** (a UTC label): position and physical functions take `date.UTC()` and convert to TT internally before evaluating the ephemeris, while rise/set, culmination, and the topocentric horizontal family additionally read `date.Zone()` for local-time computation.
|
|
|
|
UTC had no leap seconds before 1972-01-01; the library treats that span as UT1, so a civil-time label there is equal to UT1.
|
|
|
|
From 1972 on the built-in leap-second table is used, and beyond the exact window the active UTC tracking policy applies. For explicit conversion use `astro.UT1FromUTC`, `astro.TTFromUTC`, and `astro.DUT1` from the root package; time-scale declarations inside figures and captions and the UT1 convention are in [Time Scale Declaration](map-geojson.md#time-scale-declaration).
|
|
|
|
### Units and conventions
|
|
|
|
Angles are always in degrees; apparent diameter and semidiameter are in arcseconds; distances follow the function name -- `EarthDistance` / `SunDistance` and `planet.WherePlanet` with `zn=2` are in AU, while `planet.MoonAway` is in km.
|
|
|
|
`PhaseAngle` is in degrees, `IlluminatedFraction` and its alias `Phase` are `0-1`, and `ApparentMagnitude` is a magnitude (dimensionless); rise/set, culmination, and every event search return `time.Time` in the input time zone.
|
|
|
|
Duration fields inside event structs (`TransitInfo.Duration`, `TransitInfo.InternalDuration`, `GalileanPhenomenonEvent.Duration`, `GalileanPhenomenonContact.Duration`) are Go `time.Duration` values, not Julian days or day counts; the `Start` / `Greatest` / `End` / `InternalStart` / `InternalEnd` fields of `TransitInfo` keep the caller's time zone.
|
|
|
|
Geocentric, topocentric, and distance are three different conventions: `ApparentLo` / `ApparentBo` / `ApparentRa` / `ApparentDec` / `ApparentRaDec` are geocentric apparent places, `Altitude` / `Azimuth` / `Zenith` / `HourAngle` / `ParallacticAngle` are topocentric quantities, and `EarthDistance` / `SunDistance` are geometric geocentric distances.
|
|
|
|
### Zero values, out-of-range input and sentinel errors
|
|
|
|
When an event search finds nothing inside its window it returns zero values or a struct with `Valid == false` (`TransitInfo.Valid`, `GalileanPhenomenonEvent.Valid`, `GalileanPhenomenonContactEvent.Valid`) instead of an error; when `TransitInfo.HasInternal` is false, `InternalStart` / `InternalEnd` are zero values because a partial transit has no internal contacts.
|
|
|
|
`planet.WherePlanet` / `planet.WherePlanetN` return `NaN` instead of panicking when `xt` / `zn` is out of range; in the `...N` truncation family, `n < 0` uses the full built-in series and `n >= 0` truncates it.
|
|
|
|
`RiseTime` / `SetTime` / `DownTime` (including their `N` forms) are the only family that returns an `error`: when the body has no geometric rise or set on that day they return the sentinel error below with a zero instant.
|
|
|
|
Each planet package has its own polar-day/polar-night errors.
|
|
|
|
`NEVER_RISE` in the name means "never rises that day" (polar night), `NEVER_SET` means "never sets that day" (polar day), and `NEVER_DOWN` is a compatibility alias for `NEVER_SET`.
|
|
|
|
| Package | Never rises | Never sets | Set alias |
|
|
| --- | --- | --- | --- |
|
|
| `mercury` | `ERR_MERCURY_NEVER_RISE` | `ERR_MERCURY_NEVER_SET` | `ERR_MERCURY_NEVER_DOWN` |
|
|
| `venus` | `ERR_VENUS_NEVER_RISE` | `ERR_VENUS_NEVER_SET` | `ERR_VENUS_NEVER_DOWN` |
|
|
| `mars` | `ERR_MARS_NEVER_RISE` | `ERR_MARS_NEVER_SET` | `ERR_MARS_NEVER_DOWN` |
|
|
| `jupiter` | `ERR_JUPITER_NEVER_RISE` | `ERR_JUPITER_NEVER_SET` | `ERR_JUPITER_NEVER_DOWN` |
|
|
| `saturn` | `ERR_SATURN_NEVER_RISE` | `ERR_SATURN_NEVER_SET` | `ERR_SATURN_NEVER_DOWN` |
|
|
| `uranus` | `ERR_URANUS_NEVER_RISE` | `ERR_URANUS_NEVER_SET` | `ERR_URANUS_NEVER_DOWN` |
|
|
| `neptune` | `ERR_NEPTUNE_NEVER_RISE` | `ERR_NEPTUNE_NEVER_SET` | `ERR_NEPTUNE_NEVER_DOWN` |
|
|
|
|
```go
|
|
// Polar day/night: the rise/set functions return a sentinel error and a zero time.Time.
|
|
rise, err := mercury.RiseTime(date, lon, lat, height, true)
|
|
switch {
|
|
case errors.Is(err, mercury.ERR_MERCURY_NEVER_RISE):
|
|
fmt.Println("polar night: never rises that day", rise.IsZero())
|
|
case errors.Is(err, mercury.ERR_MERCURY_NEVER_SET):
|
|
fmt.Println("polar day: never sets that day", rise.IsZero())
|
|
}
|
|
```
|
|
|
|
### Topocentric versus geocentric
|
|
|
|
`Altitude` / `Azimuth` / `Zenith` / `HourAngle` / `ParallacticAngle` use `date`'s time zone for local-time computation, with east-positive longitude, north-positive latitude, and `height` as the ellipsoidal height in meters (not orthometric elevation).
|
|
|
|
They are a different convention from the geocentric apparent place of `ApparentRa` / `ApparentDec`; convert through [Coordinate Tools](coord.md) before mixing them.
|
|
|
|
### Accuracy and scope
|
|
|
|
The planet packages use the built-in truncated VSOP87 series, covering about 4000 years around J2000; the truncation magnitudes relative to full VSOP87 are in [Sun and planets](accuracy.md#sun-and-planets) and the overall scope is in [Scope And Accuracy](accuracy.md).
|
|
|
|
The `...N` forms relax that baseline further and suit batch scans or live front-end refreshes.
|
|
|
|
`saturn.Ring` and the physical ephemerides affect only the disk and band rendering: the Saturn ring takes no part in occultation contact geometry and is not drawn as a disk boundary. The planets have no dedicated chart entry point; occultation and Saturn-ring charts are in [Lunar Occultations](occultation.md#lunar-occultation-charts).
|