module

Kozai::Sun

Where the Sun is.

Two questions need it, and only two: whether a satellite is in the Earth's shadow (Illumination), and whether the sky over the station is dark enough to see one that is not. Both are answered by a direction, and neither is sensitive to the last arcsecond of it.

NOTE: this is the low-precision solar ephemeris, on purpose.

The series here is the one given in the Astronomical Almanac and reproduced as Vallado algorithm 29: mean longitude, mean anomaly, a two-term equation of the centre, the obliquity of the ecliptic. It is documented as good to about 0.01 degrees in direction over 1950–2050, and that is what this library asserts against Skyfield in spec/sun_spec.cr — against the published bound, not against a tolerance chosen to pass.

What 0.01 degrees is worth, in the two places the answer is used:

  • On the shadow boundary, at a lever arm of 7000 km, it is 1.2 km — about 0.16 seconds of flight for a satellite in a low orbit. The umbra cone itself is worth twenty times that (see Illumination), so improving the ephemeris would change nothing that can be measured.
  • On the Sun's elevation at the station it is 0.01 degrees, which moves the moment of civil twilight by about two and a half seconds.

A full VSOP-class series would be hundreds of terms for neither.

NOTE: the frame. This formula produces a direction referred to the true equator and equinox of date; the propagator's output, and therefore everything downstream of it, is TEME. The two differ by the equation of the equinoxes, at most about 1.1 arcseconds — thirty times smaller than the error the series already carries. The rotation is deliberately not applied, and this note exists so that its absence reads as a decision rather than an oversight.

Constants

ASTRONOMICAL_UNIT_KM = 1.495978707e8

Astronomical unit in kilometres, IAU 2012.

RADIUS_KM = 695700.0

Radius of the Sun's photosphere in kilometres, IAU 2015 nominal value.

Used by Illumination for the shadow cones, which is the only place the Sun's size matters: a point source would cast no penumbra at all.

Class methods

elevation(observer : Observer, time : Time) : Float64

How high the Sun is above observer's horizon, in degrees.

Negative in twilight and at night: −6 is the civil threshold, −12 the nautical one, −18 the astronomical one.

Source
elevation_at(observer : Observer, julian_date : Float64) : Float64

How high the Sun is above observer's horizon, in degrees.

Negative in twilight and at night: −6 is the civil threshold, −12 the nautical one, −18 the astronomical one.

Source
look_angles(observer : Observer, time : Time) : Frames::LookAngles

Where the Sun is in observer's sky.

NOTE: geometric, and of the centre of the disc.

No refraction — the station's own Observer#refraction? setting is not consulted, because it exists to make satellite elevations comparable with tools that apply refraction, and applying it here would move a twilight threshold that is defined without it. No correction for the Sun's semidiameter either, for the same reason: sunrise is conventionally the upper limb at the apparent horizon, but civil twilight — the threshold this software actually uses — is defined on the centre of the disc at a geometric −6 degrees. Reporting the centre geometrically is the quantity every definition downstream is written against.

Source
look_angles_at(observer : Observer, julian_date : Float64) : Frames::LookAngles

Where the Sun is in observer's sky.

NOTE: geometric, and of the centre of the disc.

No refraction — the station's own Observer#refraction? setting is not consulted, because it exists to make satellite elevations comparable with tools that apply refraction, and applying it here would move a twilight threshold that is defined without it. No correction for the Sun's semidiameter either, for the same reason: sunrise is conventionally the upper limb at the apparent horizon, but civil twilight — the threshold this software actually uses — is defined on the centre of the disc at a geometric −6 degrees. Reporting the centre geometrically is the quantity every definition downstream is written against.

Source
position(time : Time) : Vector3

Geocentric position of the Sun in kilometres, in TEME.

position = Kozai::Sun.position(Time.utc(2026, 8, 7, 12, 0, 0))
position.magnitude # => about 1.51e8 in August, aphelion being in July
Source
position_at(julian_date : Float64) : Vector3

Geocentric position of the Sun in kilometres, in TEME, at a Julian date.

Takes the Julian date directly for the benefit of callers that already have one — the pass search and the shadow scan both walk time in minutes from an element set epoch and would otherwise convert back to a Time and forward again on every step.

Source
position_ecef(julian_date : Float64, gmst : Float64) : Vector3

The Sun's position in the earth-fixed frame, kilometres.

gmst is Greenwich sidereal time at the same instant, in radians. This is the form Illumination works in: the shadow is a body fixed to the Earth, and the station's position is already earth-fixed and precomputed.

Source
subsolar_point(time : Time) : Frames::Geodetic

The point on the ground the Sun is directly overhead.

Its latitude is the Sun's declination, so it runs between the tropics over a year; its longitude moves west at a quarter of a degree a minute. The web interface draws the day–night terminator from it.

Source