astronoby 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CHANGELOG.md +235 -0
  4. data/README.md +19 -1
  5. data/UPGRADING.md +270 -0
  6. data/docs/README.md +105 -16
  7. data/docs/altitude_crossings.md +92 -0
  8. data/docs/angles.md +1 -0
  9. data/docs/configuration.md +28 -17
  10. data/docs/coordinates.md +72 -12
  11. data/docs/deep_sky_bodies.md +46 -1
  12. data/docs/ephem.md +5 -2
  13. data/docs/equinoxes_solstices_times.md +4 -3
  14. data/docs/glossary.md +99 -1
  15. data/docs/iers.md +40 -0
  16. data/docs/instant.md +33 -21
  17. data/docs/lunar_eclipses.md +208 -0
  18. data/docs/lunar_observation.md +87 -0
  19. data/docs/moon_phases.md +4 -1
  20. data/docs/observer.md +20 -6
  21. data/docs/planetary_phenomena.md +78 -0
  22. data/docs/reference_frames.md +192 -34
  23. data/docs/rise_transit_set_times.md +6 -4
  24. data/docs/solar_system_bodies.md +26 -4
  25. data/docs/twilight_times.md +43 -24
  26. data/lib/astronoby/angle.rb +63 -2
  27. data/lib/astronoby/angles/dms.rb +18 -1
  28. data/lib/astronoby/angles/hms.rb +14 -1
  29. data/lib/astronoby/angular_velocity.rb +21 -0
  30. data/lib/astronoby/bodies/deep_sky_object.rb +6 -1
  31. data/lib/astronoby/bodies/deep_sky_object_position.rb +35 -38
  32. data/lib/astronoby/bodies/earth.rb +7 -44
  33. data/lib/astronoby/bodies/jupiter.rb +10 -0
  34. data/lib/astronoby/bodies/mars.rb +10 -0
  35. data/lib/astronoby/bodies/mercury.rb +10 -0
  36. data/lib/astronoby/bodies/moon.rb +158 -32
  37. data/lib/astronoby/bodies/neptune.rb +10 -0
  38. data/lib/astronoby/bodies/saturn.rb +10 -0
  39. data/lib/astronoby/bodies/solar_system_body.rb +240 -61
  40. data/lib/astronoby/bodies/sun.rb +79 -4
  41. data/lib/astronoby/bodies/uranus.rb +10 -0
  42. data/lib/astronoby/bodies/venus.rb +10 -0
  43. data/lib/astronoby/body.rb +6 -0
  44. data/lib/astronoby/cache.rb +13 -0
  45. data/lib/astronoby/center.rb +84 -0
  46. data/lib/astronoby/constants.rb +1 -2
  47. data/lib/astronoby/constellation.rb +9 -1
  48. data/lib/astronoby/constellations/data.rb +1 -1
  49. data/lib/astronoby/coordinates/ecliptic.rb +10 -1
  50. data/lib/astronoby/coordinates/equatorial.rb +79 -13
  51. data/lib/astronoby/coordinates/geodetic.rb +102 -0
  52. data/lib/astronoby/coordinates/horizontal.rb +13 -1
  53. data/lib/astronoby/delta_t.rb +44 -0
  54. data/lib/astronoby/distance.rb +35 -0
  55. data/lib/astronoby/duration.rb +116 -0
  56. data/lib/astronoby/earth_rotation.rb +70 -0
  57. data/lib/astronoby/equinox_solstice.rb +31 -8
  58. data/lib/astronoby/errors.rb +11 -0
  59. data/lib/astronoby/events/altitude_crossing.rb +29 -0
  60. data/lib/astronoby/events/altitude_crossing_calculator.rb +511 -0
  61. data/lib/astronoby/events/altitude_extreme.rb +31 -0
  62. data/lib/astronoby/events/conjunction.rb +51 -0
  63. data/lib/astronoby/events/conjunction_opposition_calculator.rb +84 -0
  64. data/lib/astronoby/events/extremum_calculator.rb +23 -176
  65. data/lib/astronoby/events/greatest_elongation.rb +58 -0
  66. data/lib/astronoby/events/greatest_elongation_calculator.rb +56 -0
  67. data/lib/astronoby/events/lunar_eclipse.rb +111 -0
  68. data/lib/astronoby/events/lunar_eclipse_calculator.rb +397 -0
  69. data/lib/astronoby/events/lunar_eclipse_geometry.rb +115 -0
  70. data/lib/astronoby/events/lunar_eclipse_phase.rb +45 -0
  71. data/lib/astronoby/events/lunar_eclipse_visibility.rb +296 -0
  72. data/lib/astronoby/events/opposition.rb +19 -0
  73. data/lib/astronoby/events/rise_transit_set_calculator.rb +9 -13
  74. data/lib/astronoby/events/rise_transit_set_event.rb +12 -1
  75. data/lib/astronoby/events/rise_transit_set_events.rb +12 -1
  76. data/lib/astronoby/events/twilight_calculator.rb +37 -147
  77. data/lib/astronoby/events/twilight_event.rb +24 -6
  78. data/lib/astronoby/events/twilight_events.rb +26 -6
  79. data/lib/astronoby/extremum_finder.rb +148 -0
  80. data/lib/astronoby/horizon.rb +40 -0
  81. data/lib/astronoby/horizontal_transformation.rb +112 -0
  82. data/lib/astronoby/instant.rb +56 -16
  83. data/lib/astronoby/libration.rb +25 -0
  84. data/lib/astronoby/mean_obliquity.rb +8 -0
  85. data/lib/astronoby/moon_orientation_ephemeris.rb +69 -0
  86. data/lib/astronoby/moon_physical_ephemeris.rb +263 -0
  87. data/lib/astronoby/nutation.rb +10 -20
  88. data/lib/astronoby/observer.rb +67 -49
  89. data/lib/astronoby/orientation.rb +107 -0
  90. data/lib/astronoby/position.rb +16 -0
  91. data/lib/astronoby/precession.rb +62 -61
  92. data/lib/astronoby/reference_frame.rb +80 -9
  93. data/lib/astronoby/reference_frames/apparent.rb +43 -12
  94. data/lib/astronoby/reference_frames/astrometric.rb +14 -1
  95. data/lib/astronoby/reference_frames/geometric.rb +7 -1
  96. data/lib/astronoby/reference_frames/mean_of_date.rb +19 -1
  97. data/lib/astronoby/reference_frames/teme.rb +159 -0
  98. data/lib/astronoby/reference_frames/topocentric.rb +36 -4
  99. data/lib/astronoby/refraction.rb +26 -5
  100. data/lib/astronoby/root_finder.rb +90 -0
  101. data/lib/astronoby/rotation.rb +49 -0
  102. data/lib/astronoby/time/greenwich_apparent_sidereal_time.rb +19 -8
  103. data/lib/astronoby/time/greenwich_mean_sidereal_time.rb +44 -5
  104. data/lib/astronoby/time/greenwich_sidereal_time.rb +21 -0
  105. data/lib/astronoby/time/local_apparent_sidereal_time.rb +21 -0
  106. data/lib/astronoby/time/local_mean_sidereal_time.rb +21 -0
  107. data/lib/astronoby/time/local_sidereal_time.rb +24 -0
  108. data/lib/astronoby/time/sidereal_time.rb +23 -1
  109. data/lib/astronoby/true_obliquity.rb +4 -0
  110. data/lib/astronoby/util/maths.rb +8 -0
  111. data/lib/astronoby/util/time.rb +0 -497
  112. data/lib/astronoby/vector.rb +10 -0
  113. data/lib/astronoby/velocity.rb +39 -0
  114. data/lib/astronoby/version.rb +1 -1
  115. data/lib/astronoby.rb +30 -0
  116. metadata +80 -5
data/docs/glossary.md CHANGED
@@ -5,130 +5,223 @@ This glossary defines key astronomical and technical terms used throughout the A
5
5
  ## Astronomical Terms
6
6
 
7
7
  ### **Aberration**
8
+
8
9
  The apparent displacement of a celestial object due to the finite speed of light and the motion of the observer. In Astronoby, this is automatically corrected in apparent reference frames.
9
10
 
10
11
  ### **Altitude**
12
+
11
13
  The angular distance of a celestial object above the observer's local horizon, measured in degrees from 0° (horizon) to 90° (zenith).
12
14
 
13
15
  ### **Apparent Position**
16
+
14
17
  The position of a celestial object as it appears in the sky, corrected for light-time, aberration, and other effects. This is what you actually see when looking through a telescope.
15
18
 
16
19
  ### **Arc Second**
20
+
17
21
  A unit of angular measurement equal to 1/3600th of a degree. Often used to describe the precision of astronomical calculations.
18
22
 
19
23
  ### **Azimuth**
24
+
20
25
  The angular distance around the horizon from north, measured clockwise in degrees. North is 0°, east is 90°, south is 180°, and west is 270°.
21
26
 
22
27
  ### **Barycentre**
28
+
23
29
  The centre of mass of a system of bodies. In the Solar System, this is the point around which all planets orbit, which is usually close to but not exactly at the Sun's centre.
24
30
 
25
31
  ### **Celestial Equator**
32
+
26
33
  The projection of Earth's equator onto the celestial sphere. It's the reference plane for equatorial coordinates.
27
34
 
28
35
  ### **Celestial Sphere**
36
+
29
37
  An imaginary sphere surrounding Earth, on which all celestial objects appear to be located. Used as a reference system for astronomical coordinates.
30
38
 
31
39
  ### **Constellation**
40
+
32
41
  A region of the sky containing a group of stars that form a recognizable pattern. Astronoby can determine which constellation a celestial body appears to be in.
33
42
 
34
43
  ### **Declination**
44
+
35
45
  The angular distance north or south of the celestial equator, measured in degrees. Positive values are north, negative values are south.
36
46
 
37
47
  ### **Ecliptic**
48
+
38
49
  The apparent path of the Sun across the celestial sphere throughout the year. It's the plane of Earth's orbit around the Sun.
39
50
 
40
51
  ### **Ephemeris**
52
+
41
53
  A table or file containing the calculated positions of celestial objects at specific times. Astronoby uses ephemeris files from JPL and IMCCE for high-precision calculations.
42
54
 
43
55
  ### **Equinox**
56
+
44
57
  The two times each year when the Sun crosses the celestial equator, making day and night approximately equal in length. The March (vernal) and September (autumnal) equinoxes.
45
58
 
46
59
  ### **Geocentric**
60
+
47
61
  As seen from the centre of Earth. Geocentric coordinates are useful for calculations but don't account for an observer's specific location.
48
62
 
49
63
  ### **Horizon**
64
+
50
65
  The apparent boundary between Earth and sky as seen by an observer. The local horizon depends on the observer's location and elevation.
51
66
 
52
67
  ### **Illuminated Fraction**
68
+
53
69
  The portion of a celestial body's disk that appears illuminated as seen from Earth. For the Moon, this varies from 0 (new moon) to 1 (full moon).
54
70
 
55
71
  ### **Julian Date**
72
+
56
73
  A continuous count of days since January 1, 4713 BCE. Used in astronomy for precise time measurements and calculations.
57
74
 
58
75
  ### **Light-Time Correction**
76
+
59
77
  The adjustment made to account for the time it takes light to travel from a celestial object to Earth. Important for accurate position calculations.
60
78
 
61
79
  ### **Magnitude**
80
+
62
81
  A measure of a celestial object's brightness. Lower numbers indicate brighter objects (e.g., -4 is brighter than +2). Apparent magnitude is as seen from Earth, absolute magnitude is intrinsic brightness.
63
82
 
64
83
  ### **Meridian**
84
+
65
85
  An imaginary line passing through the observer's zenith and the north and south celestial poles. Objects transit (cross) the meridian when they reach their highest point in the sky.
66
86
 
67
87
  ### **Nutation**
88
+
68
89
  Small periodic variations in the orientation of Earth's rotation axis, caused by gravitational forces from the Sun and Moon.
69
90
 
70
91
  ### **Obliquity**
92
+
71
93
  The angle between Earth's equatorial plane and the ecliptic plane. Currently about 23.4° and slowly decreasing.
72
94
 
73
95
  ### **Parallax**
96
+
74
97
  The apparent shift in position of a nearby object when viewed from different locations. Important for calculating distances to nearby stars.
75
98
 
76
99
  ### **Phase Angle**
100
+
77
101
  The angle between the Sun, a celestial object, and Earth. For planets, this determines how much of the disk is illuminated.
78
102
 
79
103
  ### **Precession**
104
+
80
105
  The slow, continuous change in the orientation of Earth's rotation axis, causing the positions of the equinoxes to shift over time.
81
106
 
82
107
  ### **Refraction**
108
+
83
109
  The bending of light as it passes through Earth's atmosphere, causing celestial objects to appear slightly higher in the sky than they actually are.
84
110
 
85
111
  ### **Right Ascension**
112
+
86
113
  The angular distance eastward along the celestial equator from the vernal equinox, measured in hours (0-24h) or degrees (0-360°).
87
114
 
88
115
  ### **Solstice**
116
+
89
117
  The two times each year when the Sun reaches its northernmost (June) or southernmost (December) position relative to the celestial equator.
90
118
 
91
119
  ### **Topocentric**
120
+
92
121
  As seen from a specific location on Earth's surface. Topocentric positions account for the observer's latitude, longitude, and elevation.
93
122
 
123
+ ### **TEME (True Equator, Mean Equinox)**
124
+
125
+ The reference frame used by the SGP4/SDP4 satellite orbit propagators. It shares the true equator with the apparent frame but uses the mean equinox (tracked by GMST) instead of the true equinox (tracked by GAST).
126
+
94
127
  ### **Transit**
128
+
95
129
  The moment when a celestial object crosses the observer's meridian, reaching its highest point in the sky for that day.
96
130
 
97
131
  ### **Twilight**
132
+
98
133
  The period before sunrise and after sunset when the sky is partially illuminated by scattered sunlight. Civil, nautical, and astronomical twilight have different definitions based on the Sun's position below the horizon.
99
134
 
100
135
  ### **Zenith**
136
+
101
137
  The point directly above an observer on Earth, at an altitude of 90°.
102
138
 
103
139
  ## Technical Terms
104
140
 
105
141
  ### **API (Application Programming Interface)**
142
+
106
143
  The set of methods and classes that programmers use to interact with the Astronoby library.
107
144
 
145
+ ### **Body**
146
+
147
+ A catalog definition that can position itself at an instant, returning a Position. Solar system bodies (the classes themselves, e.g. `Astronoby::Saturn`) and deep-sky objects (`Astronoby::DeepSkyObject` instances) both fulfil this role.
148
+
108
149
  ### **Cache**
150
+
109
151
  A temporary storage system that stores frequently used calculation results to improve performance.
110
152
 
153
+ ### **Centre**
154
+
155
+ The point a reference frame is relative to, modelled by the `Astronoby::Center` value object: barycentric (Solar System barycentre), geocentric (Earth's centre), or topocentric (a specific observer's location).
156
+
111
157
  ### **Coordinate System**
158
+
112
159
  A system for specifying the position of objects in space. Astronoby supports equatorial, ecliptic, and horizontal coordinate systems.
113
160
 
114
161
  ### **Ephemeris File**
162
+
115
163
  A binary file (usually with .bsp extension) containing orbital data for Solar System bodies. These files are produced by JPL and IMCCE.
116
164
 
117
165
  ### **Floating-Point Precision**
166
+
118
167
  The accuracy of decimal number calculations. Higher precision values in Astronoby provide more accurate results but may be slower.
119
168
 
169
+ ### **BCRS (Barycentric Celestial Reference System)**
170
+
171
+ A coordinate system centered on the Solar System barycentre with axes aligned to the ICRS. In Astronoby, this corresponds to the geometric reference frame.
172
+
173
+ ### **ECEF (Earth-Centered Earth-Fixed)**
174
+
175
+ A Cartesian coordinate system that rotates with the Earth. Equivalent to ITRS. In Astronoby, observer positions are expressed in ECEF.
176
+
177
+ ### **Equation of the Equinoxes**
178
+
179
+ The difference between Greenwich Apparent Sidereal Time (GAST) and Greenwich Mean Sidereal Time (GMST), equal to the nutation in longitude projected onto the equator (Δψ cos ε₀). It defines the angular offset between the mean and true equinoxes.
180
+
181
+ ### **GAST (Greenwich Apparent Sidereal Time)**
182
+
183
+ The hour angle of the true vernal equinox at the Greenwich meridian. Equal to GMST plus the equation of the equinoxes. Used to rotate observer positions from ECEF into the true-equinox celestial frame.
184
+
185
+ ### **GCRS (Geocentric Celestial Reference System)**
186
+
187
+ A coordinate system centered on the Earth's centre with axes aligned to the ICRS. In Astronoby, this corresponds to the astrometric reference frame.
188
+
189
+ ### **GMST (Greenwich Mean Sidereal Time)**
190
+
191
+ The hour angle of the mean vernal equinox at the Greenwich meridian. It measures Earth's rotation relative to the mean equinox, without nutation corrections. Used in the TEME ↔ ECEF conversion.
192
+
193
+ ### **ICRS (International Celestial Reference System)**
194
+
195
+ The standard celestial reference system adopted by the IAU. Its axes are defined by the positions of extragalactic radio sources and are practically fixed in space. JPL ephemeris data is given in ICRS-aligned coordinates.
196
+
197
+ ### **ITRS (International Terrestrial Reference System)**
198
+
199
+ The standard Earth-fixed reference system, also known as ECEF (Earth-Centered Earth-Fixed). Observer positions in Astronoby are expressed in ITRS before being rotated into the celestial frame.
200
+
201
+ ### **Position**
202
+
203
+ A target resolved at a specific instant, exposing the reference frame chain (astrometric, apparent, topocentric, ...) for a Body. Solar system body instances and `Astronoby::DeepSkyObjectPosition` instances fulfil this role.
204
+
120
205
  ### **Reference Frame**
121
- A coordinate system used to specify positions. Astronoby provides geometric, astrometric, mean of date, apparent, and topocentric reference frames.
206
+
207
+ A coordinate system used to specify positions. Astronoby provides geometric, astrometric, mean of date, apparent, and topocentric reference frames for celestial bodies, plus TEME for satellite tracking. See [Reference Frames](reference_frames.md) for how they map to IAU/IERS standard systems.
208
+
209
+ ### **WGS-84 (World Geodetic System 1984)**
210
+
211
+ The geodetic reference system used by GPS and Astronoby for specifying observer latitude, longitude, and elevation. Observer coordinates are converted from WGS-84 geodetic to ITRS geocentric Cartesian internally.
122
212
 
123
213
  ### **SPICE**
214
+
124
215
  A NASA toolkit for computing positions and orientations of Solar System bodies. Astronoby uses SPICE binary kernels (.bsp files) for ephemeris data.
125
216
 
126
217
  ### **UTC (Coordinated Universal Time)**
218
+
127
219
  The primary time standard used worldwide. All astronomical calculations in Astronoby are based on UTC.
128
220
 
129
221
  ## Units and Measurements
130
222
 
131
223
  ### **Angular Units**
224
+
132
225
  - **Degree (°)**: 1/360th of a circle
133
226
  - **Arc Minute (′)**: 1/60th of a degree
134
227
  - **Arc Second (″)**: 1/60th of an arc minute
@@ -136,16 +229,21 @@ The primary time standard used worldwide. All astronomical calculations in Astro
136
229
  - **Radian**: 180/π degrees (≈57.3°)
137
230
 
138
231
  ### **Distance Units**
232
+
139
233
  - **Astronomical Unit (AU)**: The average distance between Earth and Sun (≈149.6 million km)
140
234
  - **Kilometre (km)**: Standard metric unit for distances
141
235
  - **Metre (m)**: Standard metric unit for elevations
142
236
 
143
237
  ### **Time Units**
238
+
144
239
  - **Julian Day**: Continuous day count since 4713 BCE
145
240
  - **Terrestrial Time (TT)**: Astronomical time scale used for calculations
241
+ - **International Atomic Time (TAI)**: The atomic time scale TT is defined against, 32.184 seconds behind it
242
+ - **Barycentric Dynamical Time (TDB)**: Time at the Solar System barycentre, within about 1.7 milliseconds of TT
146
243
  - **UTC**: Coordinated Universal Time, the standard for civil time
147
244
 
148
245
  ## See also
246
+
149
247
  - [Quick Start Guide](README.md) - for getting started
150
248
  - [Coordinates](coordinates.md) - for coordinate systems
151
249
  - [Reference Frames](reference_frames.md) - for position calculations
data/docs/iers.md ADDED
@@ -0,0 +1,40 @@
1
+ # IERS Data
2
+
3
+ Astronoby relies on the [`iers`](https://github.com/rhannequin/iers) gem for
4
+ access to data published by the [International Earth Rotation and Reference
5
+ Systems Service (IERS)][IERS]. This data is used for:
6
+
7
+ - **Delta T (TT - UT1)**: the difference between Terrestrial Time and Universal
8
+ Time, used when converting between UTC and the internal TT time scale (see
9
+ [Instant](instant.md))
10
+ - **Greenwich Mean Sidereal Time (GMST)**: computed via the Earth Rotation Angle
11
+ (ERA) based expression from the [IERS Conventions (2010)]
12
+
13
+ ## Data coverage
14
+
15
+ The `iers` gem ships with bundled IERS data files that work out of the box
16
+ with no network access required. The bundled data covers dates roughly from
17
+ 1800 to early 2027.
18
+
19
+ - **Before 1800**: Delta T is not available; Astronoby returns 0.
20
+ - **After the end of bundled data**: Astronoby uses the last known Delta T
21
+ value, which remains a reasonable approximation for dates in the near future.
22
+
23
+ ## Updating data
24
+
25
+ The bundled data can be refreshed to extend coverage into the future:
26
+
27
+ ```rb
28
+ IERS::Data.update!
29
+ ```
30
+
31
+ This downloads the latest IERS finals data and stores it in the gem's cache
32
+ directory. Updated data is used automatically on subsequent calculations.
33
+
34
+ ## See also
35
+
36
+ - [Instant](instant.md) - for time scales and Delta T
37
+ - [Configuration](configuration.md) - for performance settings
38
+
39
+ [IERS]: https://www.iers.org
40
+ [IERS Conventions (2010)]: https://www.iers.org/IERS/EN/Publications/TechnicalNotes/tn36.html
data/docs/instant.md CHANGED
@@ -14,7 +14,9 @@ from the irregularities in the rotation of Earth and the irregularly fluctuating
14
14
  mean solar time.
15
15
 
16
16
  Astronoby handles this situation by implementing an `Astronoby::Instant` class,
17
- used in most calculations instead of `Time`.
17
+ used in most calculations instead of `Time`. Converting between UTC and
18
+ Terrestrial Time requires knowing [Delta T (TT - UT1)][Delta T], which
19
+ Astronoby obtains from [IERS data](iers.md).
18
20
 
19
21
  `Astronoby::Instant` is a value object that stores an instant in time on Earth
20
22
  in [Terrestrial Time], an astronomical time standard defined by the
@@ -23,14 +25,18 @@ International Astronomical Union, as a [Julian Date].
23
25
  From this instant in <abbr title="Terrestrial Time">TT</abbr>, other time
24
26
  standards can be expressed, such as the
25
27
  <abbr title="International Atomic Time">TAI</abbr> or the
26
- <abbr title="Barycentric Dynamic Time">TDB</abbr>.
28
+ <abbr title="Barycentric Dynamical Time">TDB</abbr>. Those two are computed by
29
+ the [horologium] gem, which owns the time scales that convert by definition or
30
+ by model. UT1 is not one of them: it follows the actual rotation of the Earth,
31
+ so it stays in Astronoby, backed by [IERS data](iers.md).
27
32
 
28
33
  ## Initialization
29
34
 
30
35
  An `Astronoby::Instant` object can be instantiated from:
31
- * Terrestrial time (`Numeric`): `.from_terrestrial_time`
32
- * Ruby `Time` object: `.from_time`
33
- * UTC Julian date (`Numeric`): `.from_utc_julian_date`
36
+
37
+ - Terrestrial time (`Numeric`): `.from_terrestrial_time`
38
+ - Ruby `Time` object: `.from_time`
39
+ - UTC Julian date (`Numeric`): `.from_utc_julian_date`
34
40
 
35
41
  ```rb
36
42
  Astronoby::Instant.from_terrestrial_time(2460796)
@@ -48,7 +54,7 @@ Astronoby::Instant.from_utc_julian_date(2460796)
48
54
 
49
55
  From the same instant, it is possible to extract different time standards.
50
56
 
51
- * Gregorian `Date`
57
+ - Gregorian `Date`
52
58
 
53
59
  ```rb
54
60
  instant = Astronoby::Instant.from_terrestrial_time(2460796)
@@ -57,62 +63,65 @@ instant.to_date
57
63
  # => #<Date: 2025-04-30 ((2460796j,0s,0n),+0s,2299161j)>
58
64
  ```
59
65
 
60
- * UTC `DateTime`
66
+ - UTC `DateTime`
61
67
 
62
68
  ```rb
63
69
  instant = Astronoby::Instant.from_terrestrial_time(2460796)
64
70
 
65
71
  instant.to_datetime
66
- # => #<DateTime: 2025-04-30T11:58:51+00:00 ((2460796j,43131s,12159n),+0s,2299161j)>
72
+ # => #<DateTime: 2025-04-30T11:58:50+00:00 ((2460796j,43130s,845637619n),+0s,2299161j)>
67
73
  ```
68
74
 
69
- * UTC `Time`
75
+ - UTC `Time`
70
76
 
71
77
  ```rb
72
78
  instant = Astronoby::Instant.from_terrestrial_time(2460796)
73
79
 
74
80
  instant.to_datetime
75
- # => 2025-04-30 11:58:51.000012159 UTC
81
+ # => 2025-04-30T11:58:50+00:00 UTC
76
82
  ```
77
83
 
78
- * Greenwich Sidereal Time
84
+ - Greenwich Sidereal Time
79
85
 
80
86
  ```rb
81
87
  instant = Astronoby::Instant.from_terrestrial_time(2460796)
82
88
 
83
89
  instant.gmst
84
- # => 2.5597425440141457
90
+ # => 2.5597070126923764
85
91
  ```
86
92
 
87
- * International Atomic Time
93
+ - International Atomic Time
88
94
 
89
95
  ```rb
90
96
  instant = Astronoby::Instant.from_terrestrial_time(2460796)
91
97
 
92
98
  instant.tai.to_f
93
- # => 2460795.9996275003
99
+ # => 2460795.9996275
94
100
  ```
95
101
 
96
- * UTC offset (difference with UTC in days)
102
+ - UTC offset (difference with UTC in days)
97
103
 
98
104
  ```rb
99
105
  instant = Astronoby::Instant.from_terrestrial_time(2460796)
100
106
 
101
107
  instant.utc_offset.to_f
102
- # => 0.0007986109703819444
108
+ # => 0.0008003974106626159
103
109
  ```
104
110
 
105
- * Barycentric Dynamic Time
111
+ - Barycentric Dynamical Time
106
112
 
107
113
  ```rb
108
- # This is not handled for now, and returns TT
109
-
110
114
  instant = Astronoby::Instant.from_terrestrial_time(2460796)
111
115
 
112
- instant.tdb
113
- # => 2460796
116
+ instant.tdb.to_f
117
+ # => 2460796.000000017
114
118
  ```
115
119
 
120
+ `tai` and `tdb` are read as a `Rational`. A Julian Date is around 2.46
121
+ million, so a single `Float` rounds to about 47 microseconds of the day, which
122
+ is more than the whole TDB - TT correction. Call `to_f` when a `Float` is what
123
+ you want.
124
+
116
125
  ## Value Equality
117
126
 
118
127
  As a value object, it is possible to compare different instants.
@@ -128,11 +137,14 @@ instant1 < instant2
128
137
  # => true
129
138
  ```
130
139
 
140
+ [horologium]: https://github.com/rhannequin/horologium
131
141
  [Gregorian calendar]: https://en.wikipedia.org/wiki/Gregorian_calendar
132
142
  [Terrestrial Time]: https://en.wikipedia.org/wiki/Terrestrial_Time
133
143
  [Julian Date]: https://en.wikipedia.org/wiki/Julian_day
144
+ [Delta T]: https://en.wikipedia.org/wiki/ΔT_(timekeeping)
134
145
 
135
146
  ## See also
147
+
136
148
  - [Ephemerides](ephem.md) - for time-based calculations
137
149
  - [Solar System Bodies](solar_system_bodies.md) - for object positions
138
150
  - [Reference Frames](reference_frames.md) - for coordinate systems
@@ -0,0 +1,208 @@
1
+ # Lunar Eclipses
2
+
3
+ Astronoby computes lunar eclipses: the passages of the Moon through Earth's shadow. A lunar eclipse is a geocentric event, the same for every observer who can see the Moon, so finding one takes no observer. What one place sees of it depends only on whether the Moon is above its horizon, which is covered in [Local circumstances](#local-circumstances) below. The geometry is built from the apparent geocentric positions of the Sun and Moon, which matches the standard reduction used by [NASA's Five Millennium Canon of Lunar Eclipses] and by IMCCE.
4
+
5
+ There are three kinds of lunar eclipses. A penumbral eclipse is when the Moon only enters Earth's penumbra, the outer, partial shadow. A partial eclipse is when part of the Moon enters the umbra, the inner, total shadow. A total eclipse is when the whole Moon enters the umbra.
6
+
7
+ ## Finding eclipses
8
+
9
+ `Astronoby::Moon.eclipse_events` takes an ephemeris and a time range, and returns the lunar eclipses whose greatest instant falls in that range, sorted by time.
10
+
11
+ ```rb
12
+ ephem = Astronoby::Ephem.load("inpop19a.bsp")
13
+
14
+ eclipses = Astronoby::Moon.eclipse_events(
15
+ ephem: ephem,
16
+ start_time: Time.utc(2025, 1, 1),
17
+ end_time: Time.utc(2026, 1, 1)
18
+ )
19
+
20
+ eclipses.map { |eclipse| [eclipse.instant.to_time, eclipse.kind] }
21
+ # => [[2025-03-14 06:58:46 UTC, :total], [2025-09-07 18:11:49 UTC, :total]]
22
+ ```
23
+
24
+ ## An eclipse
25
+
26
+ Each eclipse is an `Astronoby::LunarEclipse`. Its `#instant` (also available as `#greatest_eclipse_instant`) is the moment of greatest eclipse, when the Moon's centre is least distant from the axis of Earth's shadow.
27
+
28
+ ```rb
29
+ eclipse = eclipses.first
30
+
31
+ eclipse.kind # => :total
32
+ eclipse.total? # => true
33
+ eclipse.instant.to_time # => 2025-03-14 06:58:46 UTC
34
+ eclipse.greatest_eclipse_instant # => same as #instant
35
+ ```
36
+
37
+ The umbral and penumbral magnitudes are the fractions of the Moon's diameter immersed in the umbra and the penumbra at greatest eclipse. The umbral magnitude is negative for a penumbral eclipse (the Moon misses the umbra), between 0 and 1 for a partial eclipse, and 1 or more for a total eclipse.
38
+
39
+ ```rb
40
+ eclipse.umbral_magnitude # => 1.179
41
+ eclipse.penumbral_magnitude # => 2.26
42
+ ```
43
+
44
+ `#gamma` is the least distance of the Moon's centre from the axis of Earth's shadow at greatest eclipse, in Earth radii, positive when the Moon passes north of the axis and negative when it passes south. It is the standard, dimensionless eclipse parameter used by IMCCE and NASA. The same quantity is also available as an `Astronoby::Distance` through `#shadow_axis_distance`, and the side of the axis it takes its sign from is on the geometry as `#north_of_axis?`.
45
+
46
+ ```rb
47
+ eclipse.gamma # => 0.348
48
+ eclipse.shadow_axis_distance.km # => 2222.37
49
+ ```
50
+
51
+ ## Phases
52
+
53
+ An eclipse exposes its phases as `Astronoby::LunarEclipsePhase` objects, each with a `#starting_instant`, an `#ending_instant`, and a `#duration` (an `Astronoby::Duration`). The penumbral phase is always present. The partial phase is present for partial and total eclipses, and the total phase (totality) only for total eclipses. A phase that does not occur is `nil`.
54
+
55
+ ```rb
56
+ eclipse.penumbral.starting_instant.to_time # => 2025-03-14 03:57:28 UTC (P1)
57
+ eclipse.partial.starting_instant.to_time # => 2025-03-14 05:09:36 UTC (U1)
58
+ eclipse.total.starting_instant.to_time # => 2025-03-14 06:26:02 UTC (U2)
59
+ eclipse.total.ending_instant.to_time # => 2025-03-14 07:31:29 UTC (U3)
60
+ eclipse.partial.ending_instant.to_time # => 2025-03-14 08:47:55 UTC (U4)
61
+ eclipse.penumbral.ending_instant.to_time # => 2025-03-14 10:00:08 UTC (P4)
62
+
63
+ eclipse.total.duration.seconds # => 3927.11 (seconds of totality)
64
+ ```
65
+
66
+ For a penumbral eclipse, `#partial` and `#total` are `nil`. For a partial eclipse, `#total` is `nil`.
67
+
68
+ ## Shadow geometry
69
+
70
+ `Astronoby::LunarEclipseGeometry` describes Earth's shadow and the Moon's place in it at one instant. The eclipse carries the geometry at greatest eclipse, and each phase carries the geometry at its two contacts, so all six contacts of a total eclipse are reachable as well as greatest eclipse. It gives the size of the two shadow cones, how far the Moon's centre is from the shadow axis, and where on the Moon's limb the shadow bites.
71
+
72
+ ```rb
73
+ geometry = eclipse.geometry
74
+
75
+ geometry.umbra_angular_radius.degrees * 60 # => 39.23 (arcminutes)
76
+ geometry.penumbra_angular_radius.degrees * 60 # => 71.39
77
+ geometry.angular_axis_distance.degrees * 60 # => 19.03
78
+ geometry.position_angle.degrees # => 29.07
79
+ ```
80
+
81
+ The cone radii are measured in the plane perpendicular to the shadow axis at the Moon's distance, which is where they are published. They are available as an `Astronoby::Distance` through `#umbra_radius` and `#penumbra_radius`, and as an `Astronoby::Angle` through `#umbra_angular_radius` and `#penumbra_angular_radius`. `#moon_distance` is the geocentric distance of the Moon, the distance of that plane.
82
+
83
+ `#position_angle` is the position angle of the contact point on the Moon's limb, seen from the Moon's centre, from celestial north through east. This is the quantity IMCCE and NASA publish. At greatest eclipse, where there is no contact point, it is the direction from the shadow axis to the Moon, which is what they report there too.
84
+
85
+ `#umbral_magnitude` and `#penumbral_magnitude` are available at any of these instants, not only at greatest eclipse. Each one is 0 at the contacts that define it, so the penumbral magnitude at P1 and P4 and the umbral magnitude at U1 and U4. The umbral magnitude is 1 at U2 and U3, where the Moon is wholly inside the umbra. The penumbral magnitude is well past 1 by then, since the Moon is far deeper into the penumbra than into the umbra.
86
+
87
+ ```rb
88
+ eclipse.penumbral.starting_geometry.penumbral_magnitude # => 0.0 (P1)
89
+ eclipse.partial.starting_geometry.umbral_magnitude # => 0.0 (U1)
90
+ eclipse.total.starting_geometry.umbral_magnitude # => 1.0 (U2)
91
+ ```
92
+
93
+ ```rb
94
+ eclipse.penumbral.starting_geometry.position_angle.degrees # => 131.8 (P1)
95
+ eclipse.total.starting_geometry.position_angle.degrees # => 350.46 (U2)
96
+ ```
97
+
98
+ Note that IMCCE labels the end of the penumbral phase `P2`, where this documentation uses `P4`.
99
+
100
+ ```rb
101
+ penumbral_eclipse = Astronoby::Moon.eclipse_events(
102
+ ephem: ephem,
103
+ start_time: Time.utc(2024, 3, 1),
104
+ end_time: Time.utc(2024, 4, 1)
105
+ ).first
106
+
107
+ penumbral_eclipse.kind # => :penumbral
108
+ penumbral_eclipse.partial # => nil
109
+ penumbral_eclipse.total # => nil
110
+ ```
111
+
112
+ ## Local circumstances
113
+
114
+ The eclipse is the same everywhere, so there is no path of visibility to compute. All that changes from place to place is whether the Moon is above the horizon, and visibility is the intersection of the eclipse with the time the Moon spends up. Half the Earth sees an eclipse; the other half is in daylight, with the Moon below the horizon.
115
+
116
+ `LunarEclipse#visibility_from` takes an `Astronoby::Observer` and returns an `Astronoby::LunarEclipseVisibility`. No ephemeris is involved: the Moon's place at every contact is already carried by the geometry, so an eclipse can be observed from as many places as wanted, including after a round trip through a cache.
117
+
118
+ ```rb
119
+ paris = Astronoby::Observer.new(
120
+ latitude: Astronoby::Angle.from_degrees(48.8566),
121
+ longitude: Astronoby::Angle.from_degrees(2.3522)
122
+ )
123
+
124
+ visibility = eclipse.visibility_from(paris)
125
+
126
+ visibility.visible? # => true
127
+ visibility.entirely_visible? # => false
128
+ visibility.circumstance # => :ends_after_moonset
129
+ ```
130
+
131
+ `#circumstance` sums up what the place gets of the eclipse:
132
+
133
+ - `:not_visible`, the Moon is below the horizon for the whole eclipse
134
+ - `:entirely_visible`, the Moon is up from the first to the last penumbral contact
135
+ - `:begins_before_moonrise`, the eclipse is already under way when the Moon rises
136
+ - `:ends_after_moonset`, the eclipse is still under way when the Moon sets
137
+ - `:partially_visible`, anything else, which at high latitudes can be the Moon rising and setting within the eclipse
138
+
139
+ `#coverage` takes a phase and answers how much of it happens with the Moon up, in the same three words `#circumstance` uses of the whole eclipse: `:entirely_visible`, `:partially_visible`, `:not_visible`, or `nil` when the eclipse has no such phase. In the example, in Paris, the Moon sets during the partial phase, before totality begins.
140
+
141
+ ```rb
142
+ visibility.coverage(:penumbral) # => :partially_visible
143
+ visibility.coverage(:partial) # => :partially_visible
144
+ visibility.coverage(:total) # => :not_visible
145
+ ```
146
+
147
+ `#horizon_crossings` are the instants of the eclipse at which the Moon rises or sets, and `#observable_windows` are the stretches of the eclipse spent with the Moon up. There is one window for an eclipse seen whole or in part, none for one not seen at all, and more than one only where the Moon crosses the horizon repeatedly.
148
+
149
+ ```rb
150
+ visibility.horizon_crossings.map { |instant| instant.to_time }
151
+ # => [2025-03-14 06:11:41 UTC]
152
+
153
+ visibility.observable_windows.map { |window| [window.first.to_time, window.last.to_time] }
154
+ # => [[2025-03-14 03:57:28 UTC, 2025-03-14 06:11:41 UTC]]
155
+ ```
156
+
157
+ From Mexico City the same eclipse runs from end to end with the Moon high in the sky.
158
+
159
+ ```rb
160
+ mexico_city = Astronoby::Observer.new(
161
+ latitude: Astronoby::Angle.from_degrees(19.4326),
162
+ longitude: Astronoby::Angle.from_degrees(-99.1332)
163
+ )
164
+
165
+ visibility = eclipse.visibility_from(mexico_city)
166
+
167
+ visibility.circumstance # => :entirely_visible
168
+ visibility.coverage(:total) # => :entirely_visible
169
+ visibility.horizon_crossings # => []
170
+ ```
171
+
172
+ `#above_horizon_at?` answers whether the Moon is up at an instant of the eclipse, and raises outside it.
173
+
174
+ ```rb
175
+ visibility.above_horizon_at?(eclipse.total.starting_instant) # => true
176
+ ```
177
+
178
+ Visibility answers whether the Moon is up, not how high it is. The Moon's place at each contact is interpolated from what the eclipse carries, which is what lets an eclipse be observed from anywhere without an ephemeris, and that is accurate well past what the horizon convention can resolve. For the altitude itself, ask the Moon, which computes it from the ephemeris with no interpolation at all.
179
+
180
+ ```rb
181
+ Astronoby::Moon
182
+ .new(ephem: ephem, instant: eclipse.total.starting_instant)
183
+ .observed_by(mexico_city)
184
+ .horizontal
185
+ .altitude
186
+ .degrees # => 72.45
187
+ ```
188
+
189
+ The Moon counts as up once its upper limb clears the refracted horizon, which is the convention Astronoby uses for moonrise and moonset, through `Astronoby::Horizon`.
190
+
191
+ ## Precision
192
+
193
+ Two conventions shape the result. Earth's shadow is enlarged by its atmosphere, so Astronoby adds a 64 km shell to Earth's radius before building the shadow cones. And eclipse contacts are reduced with the IAU eclipse constant k, which puts the Moon's radius at 1738.09 km, slightly above its physical equatorial radius. Both are calibrated against IMCCE.
194
+
195
+ Validated against IMCCE, the eclipse kind and the magnitudes match, and the contacts agree to within a couple of seconds. The shadow radii and the distance from the shadow axis match to well under an arcsecond, and position angles to 0.03 degrees.
196
+
197
+ The local circumstances are reduced without the ephemeris, from the Moon's place at the contacts and the sidereal rate. The altitudes agree with the topocentric places computed from the ephemeris to under an arcminute, and the horizon crossings put the Moon on the horizon to a few arcseconds, which is well inside the uncertainty of the fixed refraction the convention assumes.
198
+
199
+ ## See also
200
+
201
+ - [Moon Phases](moon_phases.md) - for lunar phases
202
+ - [Lunar Observation](lunar_observation.md) - for libration, axis and limb angles
203
+ - [Planetary Phenomena](planetary_phenomena.md) - for conjunctions, oppositions and elongations
204
+ - [Solar System Bodies](solar_system_bodies.md) - for moon object details
205
+ - [Ephemerides](ephem.md) - for data sources
206
+
207
+ [NASA's Five Millennium Canon of Lunar Eclipses]: https://eclipse.gsfc.nasa.gov/SEpubs/5MCLE.html
208
+ [IMCCE]: https://www.imcce.fr/