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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +235 -0
- data/README.md +19 -1
- data/UPGRADING.md +270 -0
- data/docs/README.md +105 -16
- data/docs/altitude_crossings.md +92 -0
- data/docs/angles.md +1 -0
- data/docs/configuration.md +28 -17
- data/docs/coordinates.md +72 -12
- data/docs/deep_sky_bodies.md +46 -1
- data/docs/ephem.md +5 -2
- data/docs/equinoxes_solstices_times.md +4 -3
- data/docs/glossary.md +99 -1
- data/docs/iers.md +40 -0
- data/docs/instant.md +33 -21
- data/docs/lunar_eclipses.md +208 -0
- data/docs/lunar_observation.md +87 -0
- data/docs/moon_phases.md +4 -1
- data/docs/observer.md +20 -6
- data/docs/planetary_phenomena.md +78 -0
- data/docs/reference_frames.md +192 -34
- data/docs/rise_transit_set_times.md +6 -4
- data/docs/solar_system_bodies.md +26 -4
- data/docs/twilight_times.md +43 -24
- data/lib/astronoby/angle.rb +63 -2
- data/lib/astronoby/angles/dms.rb +18 -1
- data/lib/astronoby/angles/hms.rb +14 -1
- data/lib/astronoby/angular_velocity.rb +21 -0
- data/lib/astronoby/bodies/deep_sky_object.rb +6 -1
- data/lib/astronoby/bodies/deep_sky_object_position.rb +35 -38
- data/lib/astronoby/bodies/earth.rb +7 -44
- data/lib/astronoby/bodies/jupiter.rb +10 -0
- data/lib/astronoby/bodies/mars.rb +10 -0
- data/lib/astronoby/bodies/mercury.rb +10 -0
- data/lib/astronoby/bodies/moon.rb +158 -32
- data/lib/astronoby/bodies/neptune.rb +10 -0
- data/lib/astronoby/bodies/saturn.rb +10 -0
- data/lib/astronoby/bodies/solar_system_body.rb +240 -61
- data/lib/astronoby/bodies/sun.rb +79 -4
- data/lib/astronoby/bodies/uranus.rb +10 -0
- data/lib/astronoby/bodies/venus.rb +10 -0
- data/lib/astronoby/body.rb +6 -0
- data/lib/astronoby/cache.rb +13 -0
- data/lib/astronoby/center.rb +84 -0
- data/lib/astronoby/constants.rb +1 -2
- data/lib/astronoby/constellation.rb +9 -1
- data/lib/astronoby/constellations/data.rb +1 -1
- data/lib/astronoby/coordinates/ecliptic.rb +10 -1
- data/lib/astronoby/coordinates/equatorial.rb +79 -13
- data/lib/astronoby/coordinates/geodetic.rb +102 -0
- data/lib/astronoby/coordinates/horizontal.rb +13 -1
- data/lib/astronoby/delta_t.rb +44 -0
- data/lib/astronoby/distance.rb +35 -0
- data/lib/astronoby/duration.rb +116 -0
- data/lib/astronoby/earth_rotation.rb +70 -0
- data/lib/astronoby/equinox_solstice.rb +31 -8
- data/lib/astronoby/errors.rb +11 -0
- data/lib/astronoby/events/altitude_crossing.rb +29 -0
- data/lib/astronoby/events/altitude_crossing_calculator.rb +511 -0
- data/lib/astronoby/events/altitude_extreme.rb +31 -0
- data/lib/astronoby/events/conjunction.rb +51 -0
- data/lib/astronoby/events/conjunction_opposition_calculator.rb +84 -0
- data/lib/astronoby/events/extremum_calculator.rb +23 -176
- data/lib/astronoby/events/greatest_elongation.rb +58 -0
- data/lib/astronoby/events/greatest_elongation_calculator.rb +56 -0
- data/lib/astronoby/events/lunar_eclipse.rb +111 -0
- data/lib/astronoby/events/lunar_eclipse_calculator.rb +397 -0
- data/lib/astronoby/events/lunar_eclipse_geometry.rb +115 -0
- data/lib/astronoby/events/lunar_eclipse_phase.rb +45 -0
- data/lib/astronoby/events/lunar_eclipse_visibility.rb +296 -0
- data/lib/astronoby/events/opposition.rb +19 -0
- data/lib/astronoby/events/rise_transit_set_calculator.rb +9 -13
- data/lib/astronoby/events/rise_transit_set_event.rb +12 -1
- data/lib/astronoby/events/rise_transit_set_events.rb +12 -1
- data/lib/astronoby/events/twilight_calculator.rb +37 -147
- data/lib/astronoby/events/twilight_event.rb +24 -6
- data/lib/astronoby/events/twilight_events.rb +26 -6
- data/lib/astronoby/extremum_finder.rb +148 -0
- data/lib/astronoby/horizon.rb +40 -0
- data/lib/astronoby/horizontal_transformation.rb +112 -0
- data/lib/astronoby/instant.rb +56 -16
- data/lib/astronoby/libration.rb +25 -0
- data/lib/astronoby/mean_obliquity.rb +8 -0
- data/lib/astronoby/moon_orientation_ephemeris.rb +69 -0
- data/lib/astronoby/moon_physical_ephemeris.rb +263 -0
- data/lib/astronoby/nutation.rb +10 -20
- data/lib/astronoby/observer.rb +67 -49
- data/lib/astronoby/orientation.rb +107 -0
- data/lib/astronoby/position.rb +16 -0
- data/lib/astronoby/precession.rb +62 -61
- data/lib/astronoby/reference_frame.rb +80 -9
- data/lib/astronoby/reference_frames/apparent.rb +43 -12
- data/lib/astronoby/reference_frames/astrometric.rb +14 -1
- data/lib/astronoby/reference_frames/geometric.rb +7 -1
- data/lib/astronoby/reference_frames/mean_of_date.rb +19 -1
- data/lib/astronoby/reference_frames/teme.rb +159 -0
- data/lib/astronoby/reference_frames/topocentric.rb +36 -4
- data/lib/astronoby/refraction.rb +26 -5
- data/lib/astronoby/root_finder.rb +90 -0
- data/lib/astronoby/rotation.rb +49 -0
- data/lib/astronoby/time/greenwich_apparent_sidereal_time.rb +19 -8
- data/lib/astronoby/time/greenwich_mean_sidereal_time.rb +44 -5
- data/lib/astronoby/time/greenwich_sidereal_time.rb +21 -0
- data/lib/astronoby/time/local_apparent_sidereal_time.rb +21 -0
- data/lib/astronoby/time/local_mean_sidereal_time.rb +21 -0
- data/lib/astronoby/time/local_sidereal_time.rb +24 -0
- data/lib/astronoby/time/sidereal_time.rb +23 -1
- data/lib/astronoby/true_obliquity.rb +4 -0
- data/lib/astronoby/util/maths.rb +8 -0
- data/lib/astronoby/util/time.rb +0 -497
- data/lib/astronoby/vector.rb +10 -0
- data/lib/astronoby/velocity.rb +39 -0
- data/lib/astronoby/version.rb +1 -1
- data/lib/astronoby.rb +30 -0
- metadata +80 -5
data/docs/README.md
CHANGED
|
@@ -62,10 +62,10 @@ You can learn more about reference frames and positions on the
|
|
|
62
62
|
|
|
63
63
|
```rb
|
|
64
64
|
topocentric.horizontal.azimuth.str(:dms)
|
|
65
|
-
# => "+175° 34′
|
|
65
|
+
# => "+175° 34′ 33.2353″"
|
|
66
66
|
|
|
67
67
|
topocentric.horizontal.altitude.str(:dms)
|
|
68
|
-
# => "+64° 22′ 58.
|
|
68
|
+
# => "+64° 22′ 58.229″"
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
You can learn more about coordinates on the [Coordinates page].
|
|
@@ -108,26 +108,47 @@ calculator = Astronoby::TwilightCalculator.new(
|
|
|
108
108
|
event = calculator.event_on(Date.new(2025, 5, 1))
|
|
109
109
|
|
|
110
110
|
event.morning_astronomical_twilight_time
|
|
111
|
-
# => 2025-05-01 02:17:
|
|
111
|
+
# => 2025-05-01 02:17:02 UTC
|
|
112
112
|
|
|
113
113
|
event.morning_nautical_twilight_time
|
|
114
|
-
# => 2025-05-01 03:
|
|
114
|
+
# => 2025-05-01 03:09:39 UTC
|
|
115
115
|
|
|
116
116
|
event.morning_civil_twilight_time
|
|
117
|
-
# => 2025-05-01 03:
|
|
117
|
+
# => 2025-05-01 03:54:36 UTC
|
|
118
118
|
|
|
119
119
|
event.evening_civil_twilight_time
|
|
120
|
-
# => 2025-05-01 19:
|
|
120
|
+
# => 2025-05-01 19:41:58 UTC
|
|
121
121
|
|
|
122
122
|
event.evening_nautical_twilight_time
|
|
123
|
-
# => 2025-05-01 20:
|
|
123
|
+
# => 2025-05-01 20:27:15 UTC
|
|
124
124
|
|
|
125
125
|
event.evening_astronomical_twilight_time
|
|
126
|
-
# => 2025-05-01 21:
|
|
126
|
+
# => 2025-05-01 21:20:32 UTC
|
|
127
127
|
```
|
|
128
128
|
|
|
129
129
|
You can learn more about this calculator on the [Twilight times page].
|
|
130
130
|
|
|
131
|
+
## Find when a body reaches any altitude
|
|
132
|
+
|
|
133
|
+
```rb
|
|
134
|
+
calculator = Astronoby::AltitudeCrossingCalculator.new(
|
|
135
|
+
body: Astronoby::Sun,
|
|
136
|
+
observer: observer,
|
|
137
|
+
ephem: ephem
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
crossing = calculator.crossings_between(
|
|
141
|
+
Time.utc(2025, 5, 1),
|
|
142
|
+
Time.utc(2025, 5, 2),
|
|
143
|
+
altitude: Astronoby::Angle.from_degrees(30)
|
|
144
|
+
).first
|
|
145
|
+
|
|
146
|
+
crossing.direction
|
|
147
|
+
# => :rising
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
You can learn more about this calculator on the [Altitude crossings page].
|
|
151
|
+
|
|
131
152
|
## Moon phases
|
|
132
153
|
|
|
133
154
|
You can either get all the major Moon phases that will happen in a month, or get
|
|
@@ -141,7 +162,7 @@ may_2024_phases.each { puts "#{_1.phase}: #{_1.time}" }
|
|
|
141
162
|
# new_moon: 2024-05-08 03:21:56 UTC
|
|
142
163
|
# first_quarter: 2024-05-15 11:48:02 UTC
|
|
143
164
|
# full_moon: 2024-05-23 13:53:12 UTC
|
|
144
|
-
# last_quarter: 2024-05-30 17:12:
|
|
165
|
+
# last_quarter: 2024-05-30 17:12:42 UTC
|
|
145
166
|
```
|
|
146
167
|
|
|
147
168
|
```rb
|
|
@@ -150,14 +171,53 @@ instant = Astronoby::Instant.from_time(time)
|
|
|
150
171
|
moon = Astronoby::Moon.new(ephem: ephem, instant: instant)
|
|
151
172
|
|
|
152
173
|
moon.illuminated_fraction.round(2)
|
|
153
|
-
# => 0.
|
|
174
|
+
# => 0.95
|
|
154
175
|
|
|
155
176
|
moon.current_phase_fraction.round(2)
|
|
156
|
-
# => 0.
|
|
177
|
+
# => 0.59
|
|
157
178
|
```
|
|
158
179
|
|
|
159
180
|
You can learn more about phases on the [Moon phases page].
|
|
160
181
|
|
|
182
|
+
## Lunar observation
|
|
183
|
+
|
|
184
|
+
```rb
|
|
185
|
+
time = Time.utc(2025, 3, 1)
|
|
186
|
+
instant = Astronoby::Instant.from_time(time)
|
|
187
|
+
moon = Astronoby::Moon.new(ephem: ephem, instant: instant)
|
|
188
|
+
|
|
189
|
+
moon.libration.longitude.str(:dms)
|
|
190
|
+
# => "-2° 5′ 4.4219″"
|
|
191
|
+
|
|
192
|
+
moon.libration.latitude.str(:dms)
|
|
193
|
+
# => "+0° 28′ 45.9616″"
|
|
194
|
+
|
|
195
|
+
moon.position_angle_of_axis.str(:dms)
|
|
196
|
+
# => "-21° 48′ 46.657″"
|
|
197
|
+
|
|
198
|
+
moon.bright_limb_position_angle.str(:dms)
|
|
199
|
+
# => "+248° 1′ 57.9467″"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
You can learn more about libration, axis and limb angles on the
|
|
203
|
+
[Lunar observation page].
|
|
204
|
+
|
|
205
|
+
## Lunar eclipses
|
|
206
|
+
|
|
207
|
+
```rb
|
|
208
|
+
eclipses = Astronoby::Moon.eclipse_events(
|
|
209
|
+
ephem: ephem,
|
|
210
|
+
start_time: Time.utc(2025, 1, 1),
|
|
211
|
+
end_time: Time.utc(2026, 1, 1)
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
eclipses.map { |eclipse| [eclipse.instant.to_time, eclipse.kind] }
|
|
215
|
+
# => [[2025-03-14 06:58:46 UTC, :total], [2025-09-07 18:11:49 UTC, :total]]
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
You can learn more about umbral and penumbral magnitudes, phases and contact
|
|
219
|
+
times on the [Lunar eclipses page].
|
|
220
|
+
|
|
161
221
|
## Equinox and solstice times
|
|
162
222
|
|
|
163
223
|
```rb
|
|
@@ -166,18 +226,39 @@ Astronoby::EquinoxSolstice.march_equinox(2025, ephem)
|
|
|
166
226
|
# => 2025-03-20 09:01:29 UTC
|
|
167
227
|
|
|
168
228
|
Astronoby::EquinoxSolstice.june_solstice(2025, ephem)
|
|
169
|
-
# => 2025-06-21 02:42:
|
|
229
|
+
# => 2025-06-21 02:42:16 UTC
|
|
170
230
|
|
|
171
231
|
Astronoby::EquinoxSolstice.september_equinox(2025, ephem)
|
|
172
|
-
# => 2025-09-22 18:19:
|
|
232
|
+
# => 2025-09-22 18:19:21 UTC
|
|
173
233
|
|
|
174
234
|
Astronoby::EquinoxSolstice.december_solstice(2025, ephem)
|
|
175
|
-
# => 2025-12-21 15:03:
|
|
235
|
+
# => 2025-12-21 15:03:05 UTC
|
|
176
236
|
```
|
|
177
237
|
|
|
178
238
|
You can learn more about equinoxes and solstices on the
|
|
179
239
|
[Equinoxes and solstices times page].
|
|
180
240
|
|
|
241
|
+
## Planetary phenomena
|
|
242
|
+
|
|
243
|
+
```rb
|
|
244
|
+
Astronoby::Mars.opposition_events(
|
|
245
|
+
ephem: ephem,
|
|
246
|
+
start_time: Time.utc(2025, 1, 1),
|
|
247
|
+
end_time: Time.utc(2026, 1, 1)
|
|
248
|
+
).first.instant.to_time
|
|
249
|
+
# => 2025-01-16 02:38:35 UTC
|
|
250
|
+
|
|
251
|
+
Astronoby::Venus.greatest_elongation_events(
|
|
252
|
+
ephem: ephem,
|
|
253
|
+
start_time: Time.utc(2025, 1, 1),
|
|
254
|
+
end_time: Time.utc(2026, 1, 1)
|
|
255
|
+
).first.angle.degrees.round(1)
|
|
256
|
+
# => 47.2
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
You can learn more about conjunctions, oppositions and greatest elongations on
|
|
260
|
+
the [Planetary phenomena page].
|
|
261
|
+
|
|
181
262
|
## Deep-sky objects
|
|
182
263
|
|
|
183
264
|
It is possible to manipulate any deep-sky possible, given equatorial coordinates
|
|
@@ -200,13 +281,17 @@ vega = Astronoby::DeepSkyObject.new(equatorial_coordinates: vega_j2000)
|
|
|
200
281
|
vega_position = vega.at(instant)
|
|
201
282
|
|
|
202
283
|
vega_position.apparent.equatorial.right_ascension.str(:hms)
|
|
203
|
-
# => "18h
|
|
284
|
+
# => "18h 37m 48.2804s"
|
|
204
285
|
```
|
|
205
286
|
|
|
206
|
-
You can learn more about deep-sky objects
|
|
287
|
+
You can learn more about deep-sky objects, and about converting many points to
|
|
288
|
+
horizontal coordinates at once with `HorizontalTransformation`, on the
|
|
289
|
+
[Deep-sky Bodies page].
|
|
207
290
|
|
|
208
291
|
## See also
|
|
292
|
+
|
|
209
293
|
- [Glossary](glossary.md) - for astronomical and technical terms
|
|
294
|
+
- [IERS Data](iers.md) - for Delta T and GMST data management
|
|
210
295
|
- [Configuration](configuration.md) - for performance tuning
|
|
211
296
|
- [Performance Benchmarks](../benchmarks/README.md) - for testing improvements
|
|
212
297
|
|
|
@@ -219,6 +304,10 @@ You can learn more about deep-sky objects on the [Deep-sky Bodies page].
|
|
|
219
304
|
[Coordinates page]: coordinates.md
|
|
220
305
|
[Rise, transit and setting times page]: rise_transit_set_times.md
|
|
221
306
|
[Twilight times page]: twilight_times.md
|
|
307
|
+
[Altitude crossings page]: altitude_crossings.md
|
|
222
308
|
[Moon phases page]: moon_phases.md
|
|
309
|
+
[Lunar observation page]: lunar_observation.md
|
|
310
|
+
[Lunar eclipses page]: lunar_eclipses.md
|
|
223
311
|
[Equinoxes and solstices times page]: equinoxes_solstices_times.md
|
|
312
|
+
[Planetary phenomena page]: planetary_phenomena.md
|
|
224
313
|
[Deep-sky Bodies page]: deep_sky_bodies.md
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Altitude crossings
|
|
2
|
+
|
|
3
|
+
`Astronoby::AltitudeCrossingCalculator` finds when a body reaches any altitude above the observer's horizon, positive or negative, with instants that are not rounded. [Twilight times](twilight_times.md) are built on it.
|
|
4
|
+
|
|
5
|
+
## Initialization
|
|
6
|
+
|
|
7
|
+
It takes as key arguments:
|
|
8
|
+
|
|
9
|
+
- `body`: the body to track, for example `Astronoby::Sun`
|
|
10
|
+
- `observer` (`Astronoby::Observer`): location on Earth of the observer
|
|
11
|
+
- `ephem`: ephemeris to provide the initial raw data
|
|
12
|
+
- `refraction` (optional, `false` by default): whether atmospheric refraction is applied to the altitude, `false` being the twilight convention
|
|
13
|
+
- `reference` (optional, `:center` by default): which point of the body reaches the altitude, `:center`, `:upper_limb` or `:lower_limb`. The limbs use the body's true semi-diameter and need a solar system body.
|
|
14
|
+
|
|
15
|
+
```rb
|
|
16
|
+
calculator = Astronoby::AltitudeCrossingCalculator.new(
|
|
17
|
+
body: Astronoby::Sun,
|
|
18
|
+
observer: observer,
|
|
19
|
+
ephem: ephem
|
|
20
|
+
)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## `#crossings_between`
|
|
24
|
+
|
|
25
|
+
It returns the `Astronoby::AltitudeCrossing` objects in a time range, sorted by time.
|
|
26
|
+
|
|
27
|
+
```rb
|
|
28
|
+
crossings = calculator.crossings_between(
|
|
29
|
+
Time.utc(2026, 10, 23),
|
|
30
|
+
Time.utc(2026, 10, 24),
|
|
31
|
+
altitude: Astronoby::Angle.from_degrees(-17.5)
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
crossing = crossings.first
|
|
35
|
+
|
|
36
|
+
crossing.instant # => Astronoby::Instant, unrounded
|
|
37
|
+
crossing.direction # => :rising or :setting
|
|
38
|
+
crossing.grazing? # => true when the body only just reaches the altitude
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
A crossing is `:rising` when the altitude increases through the target. It is `grazing?` when the target is within 0.05° of the body's highest or lowest altitude, where the instant is sensitive to small errors.
|
|
42
|
+
|
|
43
|
+
## `#multiple_crossings_between`
|
|
44
|
+
|
|
45
|
+
It does the same for several altitudes at once and returns one array of crossings per altitude, in the order given. The culminations and the computed positions are shared between the altitudes, which makes it much cheaper than one call per altitude.
|
|
46
|
+
|
|
47
|
+
```rb
|
|
48
|
+
civil, nautical = calculator.multiple_crossings_between(
|
|
49
|
+
start_time,
|
|
50
|
+
end_time,
|
|
51
|
+
altitudes: [Astronoby::Angle.from_degrees(-6), Astronoby::Angle.from_degrees(-12)]
|
|
52
|
+
)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## `#crossing_on`
|
|
56
|
+
|
|
57
|
+
It returns the first crossing of a given direction on a local day, or `nil`.
|
|
58
|
+
|
|
59
|
+
```rb
|
|
60
|
+
calculator.crossing_on(
|
|
61
|
+
Date.new(2026, 10, 23),
|
|
62
|
+
altitude: Astronoby::Angle.from_degrees(-17.5),
|
|
63
|
+
direction: :setting,
|
|
64
|
+
utc_offset: "+02:00"
|
|
65
|
+
)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## `#extremes_between`
|
|
69
|
+
|
|
70
|
+
It returns the upper and lower culminations in a time range, as `Astronoby::AltitudeExtreme` objects with `#kind`, `#instant` and `#altitude`. They are useful to explain why a crossing is absent: the body never got as high as, or as low as, the target.
|
|
71
|
+
|
|
72
|
+
```rb
|
|
73
|
+
calculator.extremes_between(start_time, end_time)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Accuracy
|
|
77
|
+
|
|
78
|
+
The altitude at the returned instant is within 10⁻⁵° of the target, and crossings agree with independent tools. The Sun's centre, without refraction, was compared on 2026-10-23 in Paris, 2026-03-20 in Makkah and 2026-12-21 at 60° N 10° E and 75° N 10° E, at -6°, -12° and -18° (22 crossings, observer at sea level):
|
|
79
|
+
|
|
80
|
+
| Tool | Resolution | Largest difference with Astronoby |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| [IMCCE OPALE](https://opale.imcce.fr) | 1 s | 0.6 s |
|
|
83
|
+
| [JPL Horizons](https://ssd.jpl.nasa.gov/horizons/) | 1 min table, interpolated | 0.10 s |
|
|
84
|
+
| [Skyfield](https://rhodesmills.github.io/skyfield/) on the same DE440s excerpt | 1 ms | 0.19 s |
|
|
85
|
+
| [USNO](https://aa.usno.navy.mil/data/api) | 1 min, civil twilight only | within its rounding |
|
|
86
|
+
|
|
87
|
+
The Skyfield differences are a time-scale effect rather than a geometric one: they are 0.00 s in March, 0.14 s in October and 0.18 s in December, which is the difference between Skyfield's built-in ΔT prediction and the IERS value Astronoby uses on those days. The remaining differences with Horizons and IMCCE come from the ephemerides (DE441 and INPOP19A against DE440s). The comparison also includes the polar night at 75° N, where the Sun does not rise but reaches -12° and -18°, and where the Sun never reaches -6°, as every tool agrees.
|
|
88
|
+
|
|
89
|
+
## See also
|
|
90
|
+
|
|
91
|
+
- [Twilight Times](twilight_times.md)
|
|
92
|
+
- [Rise, Transit and Set Times](rise_transit_set_times.md)
|
data/docs/angles.md
CHANGED
|
@@ -131,6 +131,7 @@ angle1.negative? # => false
|
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
## See also
|
|
134
|
+
|
|
134
135
|
- [Coordinates](coordinates.md) - for using angles in coordinate systems
|
|
135
136
|
- [Observer](observer.md) - for latitude and longitude
|
|
136
137
|
- [Reference Frames](reference_frames.md) - for position calculations
|
data/docs/configuration.md
CHANGED
|
@@ -20,11 +20,20 @@ Astronoby.configuration.cache_enabled = true
|
|
|
20
20
|
|
|
21
21
|
Once caching is enabled, it will be used for the following parts of the library
|
|
22
22
|
with default precision values:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
|
|
24
|
+
- [Geometric positions]
|
|
25
|
+
- [Topocentric positions] when computing rising/transit/setting times
|
|
26
|
+
- [Moon phases]
|
|
27
|
+
- Nutation
|
|
28
|
+
- Precession
|
|
29
|
+
- Greenwich mean and apparent sidereal times, which also cover the local
|
|
30
|
+
apparent sidereal time
|
|
31
|
+
|
|
32
|
+
Sidereal times are cached for the exact UTC time, with no rounding. The cache
|
|
33
|
+
helps when the same instant is used many times, for example when converting
|
|
34
|
+
many points to horizontal coordinates for one observer. Calling
|
|
35
|
+
`DeepSkyObject#at(instant).observed_by(observer).horizontal` repeatedly at one
|
|
36
|
+
instant is about 2.5 times faster with the cache enabled.
|
|
28
37
|
|
|
29
38
|
## Cache precision
|
|
30
39
|
|
|
@@ -35,10 +44,11 @@ However, users may want to improve performance even more at the cost of some
|
|
|
35
44
|
precision.
|
|
36
45
|
|
|
37
46
|
It is possible to change the precision value for the following:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
|
|
48
|
+
- Geometric position, default: `9`
|
|
49
|
+
- Topocentric position, default: `5`
|
|
50
|
+
- Nutation, default: `2`
|
|
51
|
+
- Precession, default: `2`
|
|
42
52
|
|
|
43
53
|
### Precision value
|
|
44
54
|
|
|
@@ -49,14 +59,14 @@ Let's take the example of `1`. Rounding a Julian Day with only one digit means
|
|
|
49
59
|
that all times within 8640 seconds will be rounded to the same instant, which
|
|
50
60
|
means a maximum rounding of 2.4 hours.
|
|
51
61
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
- `1`: 2.4 hours
|
|
63
|
+
- `2`: 14.4 minutes
|
|
64
|
+
- `3`: 86.4 seconds
|
|
65
|
+
- `4`: 8.6 seconds
|
|
66
|
+
- `5`: 0.86 seconds
|
|
67
|
+
- `6`: 0.086 seconds
|
|
68
|
+
- `7`: 0.0086 seconds
|
|
69
|
+
- ...
|
|
60
70
|
|
|
61
71
|
### Setting custom precision
|
|
62
72
|
|
|
@@ -92,6 +102,7 @@ Astronoby.cache.max_size
|
|
|
92
102
|
[Julian Day]: https://en.wikipedia.org/wiki/Julian_day
|
|
93
103
|
|
|
94
104
|
## See also
|
|
105
|
+
|
|
95
106
|
- [Reference Frames](reference_frames.md) - for understanding position calculations
|
|
96
107
|
- [Ephemerides](ephem.md) - for data sources
|
|
97
108
|
- [Performance Benchmarks](benchmarks/README.md) - for testing improvements
|
data/docs/coordinates.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# Coordinates
|
|
2
2
|
|
|
3
|
-
Astronoby provides
|
|
3
|
+
Astronoby provides four types of coordinates:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
- Equatorial
|
|
6
|
+
- Ecliptic
|
|
7
|
+
- Horizontal
|
|
8
|
+
- Geodetic
|
|
8
9
|
|
|
9
10
|
Equatorial and ecliptic coordinates are available for each [reference frame],
|
|
10
|
-
|
|
11
|
+
horizontal coordinates are only available for a topocentric position, and
|
|
12
|
+
geodetic coordinates are used for Earth-surface positions (ECEF ↔ WGS-84).
|
|
11
13
|
|
|
12
14
|
## Equatorial
|
|
13
15
|
|
|
@@ -36,7 +38,7 @@ saturn = Astronoby::Saturn.new(ephem: ephem, instant: instant)
|
|
|
36
38
|
equatorial = saturn.apparent.equatorial
|
|
37
39
|
|
|
38
40
|
equatorial.right_ascension.str(:hms)
|
|
39
|
-
# => "20h 45m 2.
|
|
41
|
+
# => "20h 45m 2.6681s"
|
|
40
42
|
```
|
|
41
43
|
|
|
42
44
|
You can learn more about angles on the [Angle page].
|
|
@@ -49,7 +51,7 @@ is at -90°.
|
|
|
49
51
|
|
|
50
52
|
```rb
|
|
51
53
|
equatorial.declination.str(:dms)
|
|
52
|
-
# => "-18° 46′ 16.
|
|
54
|
+
# => "-18° 46′ 16.0931″"
|
|
53
55
|
```
|
|
54
56
|
|
|
55
57
|
### Hour angle
|
|
@@ -63,7 +65,7 @@ time. By convention, the hour angle is usually displayed in hours.
|
|
|
63
65
|
longitude = Astronoby::Angle.from_degrees(2)
|
|
64
66
|
|
|
65
67
|
equatorial.compute_hour_angle(longitude: longitude, time: time).str(:hms)
|
|
66
|
-
# => "23h 27m 54.
|
|
68
|
+
# => "23h 27m 54.1924s"
|
|
67
69
|
```
|
|
68
70
|
|
|
69
71
|
## Ecliptic
|
|
@@ -101,7 +103,7 @@ saturn = Astronoby::Saturn.new(ephem: ephem, instant: instant)
|
|
|
101
103
|
ecliptic = saturn.apparent.ecliptic
|
|
102
104
|
|
|
103
105
|
ecliptic.latitude.str(:dms)
|
|
104
|
-
# => "-0° 41′ 27.
|
|
106
|
+
# => "-0° 41′ 27.5077″"
|
|
105
107
|
```
|
|
106
108
|
|
|
107
109
|
### Longitude
|
|
@@ -111,7 +113,7 @@ ecliptic towards the north (positive) or south (negative) ecliptic pole.
|
|
|
111
113
|
|
|
112
114
|
```rb
|
|
113
115
|
ecliptic.longitude.str(:dms)
|
|
114
|
-
# => "+308° 38′ 33.
|
|
116
|
+
# => "+308° 38′ 33.1535″"
|
|
115
117
|
```
|
|
116
118
|
|
|
117
119
|
## Horizontal
|
|
@@ -142,7 +144,7 @@ saturn = Astronoby::Saturn.new(ephem: ephem, instant: instant)
|
|
|
142
144
|
horizontal = saturn.observed_by(observer).horizontal
|
|
143
145
|
|
|
144
146
|
horizontal.altitude.str(:dms)
|
|
145
|
-
# => "+28° 46′
|
|
147
|
+
# => "+28° 46′ 38.3398″"
|
|
146
148
|
```
|
|
147
149
|
|
|
148
150
|
### Azimuth
|
|
@@ -152,15 +154,73 @@ eastward.
|
|
|
152
154
|
|
|
153
155
|
```rb
|
|
154
156
|
horizontal.azimuth.str(:dms)
|
|
155
|
-
# => "+171° 19′
|
|
157
|
+
# => "+171° 19′ 38.2567″"
|
|
156
158
|
```
|
|
157
159
|
|
|
160
|
+
## Geodetic
|
|
161
|
+
|
|
162
|
+
Geodetic coordinates describe a position on or above the Earth's surface using
|
|
163
|
+
the [WGS-84] reference ellipsoid, the same system used by GPS. They have three
|
|
164
|
+
attributes:
|
|
165
|
+
|
|
166
|
+
### Latitude
|
|
167
|
+
|
|
168
|
+
The angle from the equator to the point on the ellipsoid surface, from +90°
|
|
169
|
+
(North Pole) to -90° (South Pole).
|
|
170
|
+
|
|
171
|
+
### Longitude
|
|
172
|
+
|
|
173
|
+
The angle from the Greenwich meridian, from +180° to -180°, with positive
|
|
174
|
+
angles eastward.
|
|
175
|
+
|
|
176
|
+
### Elevation
|
|
177
|
+
|
|
178
|
+
The distance above (or below) the WGS-84 ellipsoid surface.
|
|
179
|
+
|
|
180
|
+
### From ECEF
|
|
181
|
+
|
|
182
|
+
Geodetic coordinates can be derived from Earth-Centered Earth-Fixed (ECEF)
|
|
183
|
+
Cartesian coordinates using `Astronoby::Coordinates::Geodetic.from_ecef`. This
|
|
184
|
+
is particularly useful for satellite tracking, where a propagator produces ECEF
|
|
185
|
+
positions via `Astronoby::Teme#to_ecef`:
|
|
186
|
+
|
|
187
|
+
```rb
|
|
188
|
+
teme = Astronoby::Teme.new(
|
|
189
|
+
position: Astronoby::Distance.vector_from_meters(
|
|
190
|
+
[5_094_180.16, 6_127_644.66, 6_380_344.53]
|
|
191
|
+
),
|
|
192
|
+
velocity: Astronoby::Velocity.vector_from_mps(
|
|
193
|
+
[-4746.13, 785.82, 5531.93]
|
|
194
|
+
),
|
|
195
|
+
instant: instant
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
geodetic = teme.to_ecef.geodetic
|
|
199
|
+
|
|
200
|
+
geodetic.latitude.str(:dms)
|
|
201
|
+
# => "+38° 48′ 3.3038″"
|
|
202
|
+
|
|
203
|
+
geodetic.longitude.str(:dms)
|
|
204
|
+
# => "+97° 27′ 6.7374″"
|
|
205
|
+
|
|
206
|
+
geodetic.elevation.km.round
|
|
207
|
+
# => 3838
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The conversion uses Bowring's iterative method, which converges in 2-3
|
|
211
|
+
iterations for typical satellite altitudes.
|
|
212
|
+
|
|
213
|
+
The forward direction (geodetic → ECEF) is handled by
|
|
214
|
+
[`Astronoby::Observer#geocentric_position`][Observer page].
|
|
215
|
+
|
|
216
|
+
[WGS-84]: https://en.wikipedia.org/wiki/World_Geodetic_System
|
|
158
217
|
[reference frame]: reference_frames.md
|
|
159
218
|
[Wikipedia]: https://en.wikipedia.org/wiki/Equatorial_coordinate_system
|
|
160
219
|
[Angle page]: angles.md
|
|
161
220
|
[topocentric position]: reference_frames.md#topocentric
|
|
162
221
|
|
|
163
222
|
## See also
|
|
223
|
+
|
|
164
224
|
- [Reference Frames](reference_frames.md) - for coordinate system details
|
|
165
225
|
- [Angles](angles.md) - for working with angular measurements
|
|
166
226
|
- [Observer](observer.md) - for location setup
|
data/docs/deep_sky_bodies.md
CHANGED
|
@@ -63,7 +63,7 @@ vega_with_proper_motion
|
|
|
63
63
|
.equatorial
|
|
64
64
|
.right_ascension
|
|
65
65
|
.str(:hms)
|
|
66
|
-
# => "18h 37m 48.
|
|
66
|
+
# => "18h 37m 48.706s"
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
You can learn more about [ephemerides] and [reference frames].
|
|
@@ -96,6 +96,51 @@ event.rising_time
|
|
|
96
96
|
# => 2025-10-01 01:31:25 UTC
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
+
## Many points at once
|
|
100
|
+
|
|
101
|
+
Getting the horizontal coordinates of a single object goes through the whole
|
|
102
|
+
chain of reference frames. Doing so for thousands of points at the same instant
|
|
103
|
+
for the same observer, like the stars of a catalogue for a sky chart, repeats
|
|
104
|
+
the same work for each of them: the rotation from the ICRS to the true equator
|
|
105
|
+
and equinox of date, and the sidereal time only depend on the observer and the
|
|
106
|
+
instant.
|
|
107
|
+
|
|
108
|
+
`Astronoby::HorizontalTransformation` computes them once, and then converts
|
|
109
|
+
any equatorial coordinates at J2000 epoch into horizontal coordinates. It is
|
|
110
|
+
about 70 times faster per point than going through
|
|
111
|
+
`DeepSkyObject#at(instant).observed_by(observer).horizontal`.
|
|
112
|
+
|
|
113
|
+
```rb
|
|
114
|
+
observer = Astronoby::Observer.new(
|
|
115
|
+
latitude: Astronoby::Angle.from_degrees(51.5072),
|
|
116
|
+
longitude: Astronoby::Angle.from_degrees(-0.1276)
|
|
117
|
+
)
|
|
118
|
+
instant = Astronoby::Instant.from_time(Time.utc(2025, 10, 1, 3))
|
|
119
|
+
|
|
120
|
+
sirius = Astronoby::Coordinates::Equatorial.new(
|
|
121
|
+
right_ascension: Astronoby::Angle.from_hms(6, 45, 8.917),
|
|
122
|
+
declination: Astronoby::Angle.from_dms(-16, 42, 58.02)
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
transformation = Astronoby::HorizontalTransformation.new(
|
|
126
|
+
observer: observer,
|
|
127
|
+
instant: instant
|
|
128
|
+
)
|
|
129
|
+
horizontal = transformation.apply(sirius)
|
|
130
|
+
|
|
131
|
+
horizontal.altitude.str(:dms, precision: 0)
|
|
132
|
+
# => "+10° 36′ 27″"
|
|
133
|
+
horizontal.azimuth.str(:dms, precision: 0)
|
|
134
|
+
# => "+134° 56′ 25″"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The result is the same as the one of a `DeepSkyObject` without an ephemeris,
|
|
138
|
+
which means the points are treated as fixed directions: there is no aberration,
|
|
139
|
+
no proper motion and no parallax. Atmospheric refraction is not applied by
|
|
140
|
+
default, and can be requested with `transformation.apply(sirius, refraction:
|
|
141
|
+
true)`. The coordinates must be at J2000 epoch, otherwise an
|
|
142
|
+
`Astronoby::IncompatibleArgumentsError` is raised.
|
|
143
|
+
|
|
99
144
|
[ephemerides]: ephem.md
|
|
100
145
|
[reference frames]: reference_frames.md
|
|
101
146
|
[SIMBAD Astronomical Database]: https://simbad.u-strasbg.fr/simbad/
|
data/docs/ephem.md
CHANGED
|
@@ -17,8 +17,9 @@ providing the filename.
|
|
|
17
17
|
### Manually
|
|
18
18
|
|
|
19
19
|
Ephemerides are available for download from:
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
|
|
21
|
+
- the JPL public FTP interface: https://ssd.jpl.nasa.gov/ftp/eph/planets/bsp/
|
|
22
|
+
- the INPOP releases page of the IMCCE: https://www.imcce.fr/inpop
|
|
22
23
|
|
|
23
24
|
You can download any `.bsp` file. For the moment, Astronoby only supports the
|
|
24
25
|
planets of the Solar System, and the Sun and the Moon, so you need to
|
|
@@ -48,6 +49,7 @@ ephem = Astronoby::Ephem.load("tmp/de421.bsp")
|
|
|
48
49
|
|
|
49
50
|
JPL produces many different kernels over the years, with different accuracy and
|
|
50
51
|
ranges of supported years. Here are some that we recommend to begin with:
|
|
52
|
+
|
|
51
53
|
- `de421.bsp`: from 1900 to 2050, 17 MB
|
|
52
54
|
- `de440s.bsp`: from 1849 to 2150, 32 MB
|
|
53
55
|
- `inpop19a.bsp`: from 1900 to 2100, 22 MB
|
|
@@ -79,6 +81,7 @@ the target `399`.
|
|
|
79
81
|
[IMCCE]: https://www.imcce.fr
|
|
80
82
|
|
|
81
83
|
## See also
|
|
84
|
+
|
|
82
85
|
- [Solar System Bodies](solar_system_bodies.md) - for using ephemeris data
|
|
83
86
|
- [Reference Frames](reference_frames.md) - for coordinate calculations
|
|
84
87
|
- [Observer](observer.md) - for location-based calculations
|
|
@@ -15,16 +15,17 @@ Astronoby::EquinoxSolstice.march_equinox(2025, ephem)
|
|
|
15
15
|
# => 2025-03-20 09:01:29 UTC
|
|
16
16
|
|
|
17
17
|
Astronoby::EquinoxSolstice.june_solstice(2025, ephem)
|
|
18
|
-
# => 2025-06-21 02:42:
|
|
18
|
+
# => 2025-06-21 02:42:16 UTC
|
|
19
19
|
|
|
20
20
|
Astronoby::EquinoxSolstice.september_equinox(2025, ephem)
|
|
21
|
-
# => 2025-09-22 18:19:
|
|
21
|
+
# => 2025-09-22 18:19:21 UTC
|
|
22
22
|
|
|
23
23
|
Astronoby::EquinoxSolstice.december_solstice(2025, ephem)
|
|
24
|
-
# => 2025-12-21 15:03:
|
|
24
|
+
# => 2025-12-21 15:03:05 UTC
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
## See also
|
|
28
|
+
|
|
28
29
|
- [Twilight Times](twilight_times.md) - for seasonal sun events
|
|
29
30
|
- [Moon Phases](moon_phases.md) - for lunar events
|
|
30
31
|
- [Ephemerides](ephem.md) - for data sources
|