astronoby 0.6.0 → 0.7.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 -0
- data/.standard.yml +1 -0
- data/CHANGELOG.md +116 -0
- data/Gemfile.lock +45 -23
- data/README.md +42 -285
- data/UPGRADING.md +238 -0
- data/lib/astronoby/aberration.rb +56 -31
- data/lib/astronoby/angle.rb +20 -16
- data/lib/astronoby/angles/dms.rb +2 -2
- data/lib/astronoby/angles/hms.rb +2 -2
- data/lib/astronoby/bodies/earth.rb +56 -0
- data/lib/astronoby/bodies/jupiter.rb +11 -0
- data/lib/astronoby/bodies/mars.rb +11 -0
- data/lib/astronoby/bodies/mercury.rb +11 -0
- data/lib/astronoby/bodies/moon.rb +50 -290
- data/lib/astronoby/bodies/neptune.rb +11 -0
- data/lib/astronoby/bodies/saturn.rb +11 -0
- data/lib/astronoby/bodies/solar_system_body.rb +122 -0
- data/lib/astronoby/bodies/sun.rb +16 -220
- data/lib/astronoby/bodies/uranus.rb +11 -0
- data/lib/astronoby/bodies/venus.rb +11 -0
- data/lib/astronoby/constants.rb +13 -1
- data/lib/astronoby/coordinates/ecliptic.rb +2 -37
- data/lib/astronoby/coordinates/equatorial.rb +25 -7
- data/lib/astronoby/coordinates/horizontal.rb +0 -46
- data/lib/astronoby/corrections/light_time_delay.rb +90 -0
- data/lib/astronoby/deflection.rb +187 -0
- data/lib/astronoby/distance.rb +9 -0
- data/lib/astronoby/ephem.rb +39 -0
- data/lib/astronoby/equinox_solstice.rb +21 -18
- data/lib/astronoby/errors.rb +4 -0
- data/lib/astronoby/events/moon_phases.rb +2 -1
- data/lib/astronoby/events/rise_transit_set_calculator.rb +352 -0
- data/lib/astronoby/events/rise_transit_set_event.rb +13 -0
- data/lib/astronoby/events/rise_transit_set_events.rb +13 -0
- data/lib/astronoby/events/twilight_calculator.rb +166 -0
- data/lib/astronoby/events/twilight_event.rb +28 -0
- data/lib/astronoby/instant.rb +171 -0
- data/lib/astronoby/mean_obliquity.rb +23 -10
- data/lib/astronoby/nutation.rb +227 -42
- data/lib/astronoby/observer.rb +55 -0
- data/lib/astronoby/precession.rb +91 -17
- data/lib/astronoby/reference_frame.rb +49 -0
- data/lib/astronoby/reference_frames/apparent.rb +60 -0
- data/lib/astronoby/reference_frames/astrometric.rb +21 -0
- data/lib/astronoby/reference_frames/geometric.rb +20 -0
- data/lib/astronoby/reference_frames/mean_of_date.rb +38 -0
- data/lib/astronoby/reference_frames/topocentric.rb +82 -0
- data/lib/astronoby/true_obliquity.rb +2 -1
- data/lib/astronoby/util/maths.rb +70 -73
- data/lib/astronoby/util/time.rb +454 -31
- data/lib/astronoby/vector.rb +36 -0
- data/lib/astronoby/velocity.rb +116 -0
- data/lib/astronoby/version.rb +1 -1
- data/lib/astronoby.rb +26 -5
- metadata +61 -16
- data/.tool-versions +0 -1
- data/lib/astronoby/astronomical_models/ephemeride_lunaire_parisienne.rb +0 -143
- data/lib/astronoby/events/observation_events.rb +0 -285
- data/lib/astronoby/events/rise_transit_set_iteration.rb +0 -218
- data/lib/astronoby/events/twilight_events.rb +0 -121
- data/lib/astronoby/util/astrodynamics.rb +0 -60
data/lib/astronoby/nutation.rb
CHANGED
@@ -2,72 +2,257 @@
|
|
2
2
|
|
3
3
|
module Astronoby
|
4
4
|
class Nutation
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
# Edition: Cambridge University Press
|
9
|
-
# Chapter: 35 - Nutation
|
5
|
+
# IAU 2000B model corrections (in microarcseconds)
|
6
|
+
IAU2000B_DPSI_CORRECTION = -0.000135e7
|
7
|
+
IAU2000B_DEPS_CORRECTION = 0.000388e7
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
# Nutation terms from IAU 2000B model:
|
10
|
+
# 77 most significant terms from the IAU 2000A model
|
11
|
+
# 0..4: fundamental argument coefficients
|
12
|
+
# 5..7: longitude coefficients
|
13
|
+
# 8..10: obliquity coefficients
|
14
|
+
NUTATION_TERMS = [
|
15
|
+
[0, 0, 0, 0, 1, -172064161, -174666, 33386, 92052331, 9086, 15377],
|
16
|
+
[0, 0, 2, -2, 2, -13170906, -1675, -13696, 5730336, -3015, -4587],
|
17
|
+
[0, 0, 2, 0, 2, -2276413, -234, 2796, 978459, -485, 1374],
|
18
|
+
[0, 0, 0, 0, 2, 2074554, 207, -698, -897492, 470, -291],
|
19
|
+
[0, 1, 0, 0, 0, 1475877, -3633, 11817, 73871, -184, -1924],
|
20
|
+
[0, 1, 2, -2, 2, -516821, 1226, -524, 224386, -677, -174],
|
21
|
+
[1, 0, 0, 0, 0, 711159, 73, -872, -6750, 0, 358],
|
22
|
+
[0, 0, 2, 0, 1, -387298, -367, 380, 200728, 18, 318],
|
23
|
+
[1, 0, 2, 0, 2, -301461, -36, 816, 129025, -63, 367],
|
24
|
+
[0, -1, 2, -2, 2, 215829, -494, 111, -95929, 299, 132],
|
25
|
+
[0, 0, 2, -2, 1, 128227, 137, 181, -68982, -9, 39],
|
26
|
+
[-1, 0, 2, 0, 2, 123457, 11, 19, -53311, 32, -4],
|
27
|
+
[-1, 0, 0, 2, 0, 156994, 10, -168, -1235, 0, 82],
|
28
|
+
[1, 0, 0, 0, 1, 63110, 63, 27, -33228, 0, -9],
|
29
|
+
[-1, 0, 0, 0, 1, -57976, -63, -189, 31429, 0, -75],
|
30
|
+
[-1, 0, 2, 2, 2, -59641, -11, 149, 25543, -11, 66],
|
31
|
+
[1, 0, 2, 0, 1, -51613, -42, 129, 26366, 0, 78],
|
32
|
+
[-2, 0, 2, 0, 1, 45893, 50, 31, -24236, -10, 20],
|
33
|
+
[0, 0, 0, 2, 0, 63384, 11, -150, -1220, 0, 29],
|
34
|
+
[0, 0, 2, 2, 2, -38571, -1, 158, 16452, -11, 68],
|
35
|
+
[0, -2, 2, -2, 2, 32481, 0, 0, -13870, 0, 0],
|
36
|
+
[-2, 0, 0, 2, 0, -47722, 0, -18, 477, 0, -25],
|
37
|
+
[2, 0, 2, 0, 2, -31046, -1, 131, 13238, -11, 59],
|
38
|
+
[1, 0, 2, -2, 2, 28593, 0, -1, -12338, 10, -3],
|
39
|
+
[-1, 0, 2, 0, 1, 20441, 21, 10, -10758, 0, -3],
|
40
|
+
[2, 0, 0, 0, 0, 29243, 0, -74, -609, 0, 13],
|
41
|
+
[0, 0, 2, 0, 0, 25887, 0, -66, -550, 0, 11],
|
42
|
+
[0, 1, 0, 0, 1, -14053, -25, 79, 8551, -2, -45],
|
43
|
+
[-1, 0, 0, 2, 1, 15164, 10, 11, -8001, 0, -1],
|
44
|
+
[0, 2, 2, -2, 2, -15794, 72, -16, 6850, -42, -5],
|
45
|
+
[0, 0, -2, 2, 0, 21783, 0, 13, -167, 0, 13],
|
46
|
+
[1, 0, 0, -2, 1, -12873, -10, -37, 6953, 0, -14],
|
47
|
+
[0, -1, 0, 0, 1, -12654, 11, 63, 6415, 0, 26],
|
48
|
+
[-1, 0, 2, 2, 1, -10204, 0, 25, 5222, 0, 15],
|
49
|
+
[0, 2, 0, 0, 0, 16707, -85, -10, 168, -1, 10],
|
50
|
+
[1, 0, 2, 2, 2, -7691, 0, 44, 3268, 0, 19],
|
51
|
+
[-2, 0, 2, 0, 0, -11024, 0, -14, 104, 0, 2],
|
52
|
+
[0, 1, 2, 0, 2, 7566, -21, -11, -3250, 0, -5],
|
53
|
+
[0, 0, 2, 2, 1, -6637, -11, 25, 3353, 0, 14],
|
54
|
+
[0, -1, 2, 0, 2, -7141, 21, 8, 3070, 0, 4],
|
55
|
+
[0, 0, 0, 2, 1, -6302, -11, 2, 3272, 0, 4],
|
56
|
+
[1, 0, 2, -2, 1, 5800, 10, 2, -3045, 0, -1],
|
57
|
+
[2, 0, 2, -2, 2, 6443, 0, -7, -2768, 0, -4],
|
58
|
+
[-2, 0, 0, 2, 1, -5774, -11, -15, 3041, 0, -5],
|
59
|
+
[2, 0, 2, 0, 1, -5350, 0, 21, 2695, 0, 12],
|
60
|
+
[0, -1, 2, -2, 1, -4752, -11, -3, 2719, 0, -3],
|
61
|
+
[0, 0, 0, -2, 1, -4940, -11, -21, 2720, 0, -9],
|
62
|
+
[-1, -1, 0, 2, 0, 7350, 0, -8, -51, 0, 4],
|
63
|
+
[2, 0, 0, -2, 1, 4065, 0, 6, -2206, 0, 1],
|
64
|
+
[1, 0, 0, 2, 0, 6579, 0, -24, -199, 0, 2],
|
65
|
+
[0, 1, 2, -2, 1, 3579, 0, 5, -1900, 0, 1],
|
66
|
+
[1, -1, 0, 0, 0, 4725, 0, -6, -41, 0, 3],
|
67
|
+
[-2, 0, 2, 0, 2, -3075, 0, -2, 1313, 0, -1],
|
68
|
+
[3, 0, 2, 0, 2, -2904, 0, 15, 1233, 0, 7],
|
69
|
+
[0, -1, 0, 2, 0, 4348, 0, -10, -81, 0, 2],
|
70
|
+
[1, -1, 2, 0, 2, -2878, 0, 8, 1232, 0, 4],
|
71
|
+
[0, 0, 0, 1, 0, -4230, 0, 5, -20, 0, -2],
|
72
|
+
[-1, -1, 2, 2, 2, -2819, 0, 7, 1207, 0, 3],
|
73
|
+
[-1, 0, 2, 0, 0, -4056, 0, 5, 40, 0, -2],
|
74
|
+
[0, -1, 2, 2, 2, -2647, 0, 11, 1129, 0, 5],
|
75
|
+
[-2, 0, 0, 0, 1, -2294, 0, -10, 1266, 0, -4],
|
76
|
+
[1, 1, 2, 0, 2, 2481, 0, -7, -1062, 0, -3],
|
77
|
+
[2, 0, 0, 0, 1, 2179, 0, -2, -1129, 0, -2],
|
78
|
+
[-1, 1, 0, 1, 0, 3276, 0, 1, -9, 0, 0],
|
79
|
+
[1, 1, 0, 0, 0, -3389, 0, 5, 35, 0, -2],
|
80
|
+
[1, 0, 2, 0, 0, 3339, 0, -13, -107, 0, 1],
|
81
|
+
[-1, 0, 2, -2, 1, -1987, 0, -6, 1073, 0, -2],
|
82
|
+
[1, 0, 0, 0, 2, -1981, 0, 0, 854, 0, 0],
|
83
|
+
[-1, 0, 0, 1, 0, 4026, 0, -353, -553, 0, -139],
|
84
|
+
[0, 0, 2, 1, 2, 1660, 0, -5, -710, 0, -2],
|
85
|
+
[-1, 0, 2, 4, 2, -1521, 0, 9, 647, 0, 4],
|
86
|
+
[-1, 1, 0, 1, 1, 1314, 0, 0, -700, 0, 0],
|
87
|
+
[0, -2, 2, -2, 1, -1283, 0, 0, 672, 0, 0],
|
88
|
+
[1, 0, 2, 2, 1, -1331, 0, 8, 663, 0, 4],
|
89
|
+
[-2, 0, 2, 2, 2, 1383, 0, -2, -594, 0, -2],
|
90
|
+
[-1, 0, 0, 0, 2, 1405, 0, 4, -610, 0, 2],
|
91
|
+
[1, 1, 2, -2, 2, 1290, 0, 0, -556, 0, 0]
|
92
|
+
]
|
14
93
|
|
15
|
-
|
16
|
-
|
94
|
+
# @param instant [Astronoby::Instant] The time instant
|
95
|
+
# @return [Matrix] The nutation matrix
|
96
|
+
def self.matrix_for(instant)
|
97
|
+
new(instant: instant).matrix
|
17
98
|
end
|
18
99
|
|
19
|
-
|
20
|
-
|
100
|
+
# @param instant [Astronoby::Instant] The time instant
|
101
|
+
def initialize(instant:)
|
102
|
+
@instant = instant
|
21
103
|
end
|
22
104
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
105
|
+
# @return [Matrix] The nutation matrix
|
106
|
+
def matrix
|
107
|
+
mean_obliquity = MeanObliquity.for_epoch(@instant.tt)
|
108
|
+
true_obliquity = mean_obliquity + nutation_in_obliquity
|
109
|
+
build_nutation_matrix(
|
110
|
+
mean_obliquity: mean_obliquity,
|
111
|
+
true_obliquity: true_obliquity,
|
112
|
+
psi: nutation_in_longitude
|
31
113
|
)
|
32
114
|
end
|
33
115
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
)
|
116
|
+
# @return [Astronoby::Angle] Nutation angle in longitude
|
117
|
+
def nutation_in_longitude
|
118
|
+
iau2000b_angles.first
|
119
|
+
end
|
120
|
+
|
121
|
+
# @return [Astronoby::Angle] Nutation angle in obliquity
|
122
|
+
def nutation_in_obliquity
|
123
|
+
iau2000b_angles.last
|
43
124
|
end
|
44
125
|
|
45
126
|
private
|
46
127
|
|
128
|
+
def iau2000a
|
129
|
+
a = fundamental_arguments
|
130
|
+
|
131
|
+
dpsi = 0.0
|
132
|
+
deps = 0.0
|
133
|
+
|
134
|
+
NUTATION_TERMS.each do |term|
|
135
|
+
# Extract the fundamental argument coefficients
|
136
|
+
arg_coef = term[0..4]
|
137
|
+
|
138
|
+
# Calculate the argument
|
139
|
+
arg = Util::Maths.dot_product(arg_coef, a.map(&:radians))
|
140
|
+
|
141
|
+
sin_arg = Math.sin(arg)
|
142
|
+
cos_arg = Math.cos(arg)
|
143
|
+
|
144
|
+
# Extract longitude coefficients
|
145
|
+
long_coef = term[5..7]
|
146
|
+
|
147
|
+
# Extract obliquity coefficients
|
148
|
+
obl_coef = term[8..10]
|
149
|
+
|
150
|
+
# Update dpsi using longitude coefficients
|
151
|
+
dpsi += long_coef[0] * sin_arg
|
152
|
+
dpsi += long_coef[1] * sin_arg * julian_centuries
|
153
|
+
dpsi += long_coef[2] * cos_arg
|
154
|
+
|
155
|
+
# Update deps using obliquity coefficients
|
156
|
+
deps += obl_coef[0] * cos_arg
|
157
|
+
deps += obl_coef[1] * cos_arg * julian_centuries
|
158
|
+
deps += obl_coef[2] * sin_arg
|
159
|
+
end
|
160
|
+
|
161
|
+
[dpsi, deps] # in microarcseconds
|
162
|
+
end
|
163
|
+
|
164
|
+
def iau2000b
|
165
|
+
dpsi, deps = iau2000a
|
166
|
+
|
167
|
+
# Apply corrections for IAU 2000B model
|
168
|
+
dpsi += IAU2000B_DPSI_CORRECTION
|
169
|
+
deps += IAU2000B_DEPS_CORRECTION
|
170
|
+
|
171
|
+
[dpsi, deps]
|
172
|
+
end
|
173
|
+
|
174
|
+
def iau2000b_angles
|
175
|
+
@iau2000b_angles ||= begin
|
176
|
+
dpsi, deps = iau2000b
|
177
|
+
dpsi = Angle.from_degree_arcseconds(dpsi / 1e7)
|
178
|
+
deps = Angle.from_degree_arcseconds(deps / 1e7)
|
179
|
+
|
180
|
+
[dpsi, deps]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def build_nutation_matrix(mean_obliquity:, true_obliquity:, psi:)
|
185
|
+
cobm = mean_obliquity.cos
|
186
|
+
sobm = mean_obliquity.sin
|
187
|
+
cobt = true_obliquity.cos
|
188
|
+
sobt = true_obliquity.sin
|
189
|
+
cpsi = psi.cos
|
190
|
+
spsi = psi.sin
|
191
|
+
|
192
|
+
Matrix[
|
193
|
+
[cpsi, -spsi * cobm, -spsi * sobm],
|
194
|
+
[
|
195
|
+
spsi * cobt,
|
196
|
+
cpsi * cobm * cobt + sobm * sobt,
|
197
|
+
cpsi * sobm * cobt - cobm * sobt
|
198
|
+
],
|
199
|
+
[
|
200
|
+
spsi * sobt,
|
201
|
+
cpsi * cobm * sobt - sobm * cobt,
|
202
|
+
cpsi * sobm * sobt + cobm * cobt
|
203
|
+
]
|
204
|
+
]
|
205
|
+
end
|
206
|
+
|
47
207
|
def julian_centuries
|
48
|
-
|
208
|
+
@julian_centuries ||=
|
209
|
+
(@instant.tt - Epoch::J2000) / Constants::DAYS_PER_JULIAN_CENTURY
|
49
210
|
end
|
50
211
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
212
|
+
# IAU 2006/2000A formula for the mean anomaly of the Moon
|
213
|
+
def mean_anomaly_moon
|
214
|
+
Angle.from_degree_arcseconds(
|
215
|
+
485868.249036 + 1717915923.2178 * julian_centuries
|
55
216
|
)
|
56
217
|
end
|
57
218
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
219
|
+
# IAU 2006/2000A formula for the mean anomaly of the Sun
|
220
|
+
def mean_anomaly_sun
|
221
|
+
Angle.from_degree_arcseconds(
|
222
|
+
1287104.79305 + 129596581.0481 * julian_centuries
|
62
223
|
)
|
63
224
|
end
|
64
225
|
|
65
|
-
|
66
|
-
|
226
|
+
# IAU 2006/2000A formula for the mean argument of latitude of the Moon
|
227
|
+
def mean_argument_latitude_moon
|
228
|
+
Angle.from_degree_arcseconds(
|
229
|
+
335779.526232 + 1739527262.8478 * julian_centuries
|
230
|
+
)
|
231
|
+
end
|
232
|
+
|
233
|
+
# IAU 2006/2000A formula for the mean elongation of the Moon from the Sun
|
234
|
+
def mean_elongation_moon_sun
|
235
|
+
Angle.from_degree_arcseconds(
|
236
|
+
1072260.70369 + 1602961601.2090 * julian_centuries
|
237
|
+
)
|
67
238
|
end
|
68
239
|
|
69
|
-
|
70
|
-
|
240
|
+
# IAU 2006/2000A formula for the mean longitude of the ascending node of the
|
241
|
+
# Moon
|
242
|
+
def longitude_ascending_node_moon
|
243
|
+
Angle.from_degree_arcseconds(
|
244
|
+
450160.398036 - 6962890.5431 * julian_centuries
|
245
|
+
)
|
246
|
+
end
|
247
|
+
|
248
|
+
def fundamental_arguments
|
249
|
+
l = mean_anomaly_moon
|
250
|
+
lp = mean_anomaly_sun
|
251
|
+
f = mean_argument_latitude_moon
|
252
|
+
d = mean_elongation_moon_sun
|
253
|
+
omega = longitude_ascending_node_moon
|
254
|
+
|
255
|
+
[l, lp, f, d, omega]
|
71
256
|
end
|
72
257
|
end
|
73
258
|
end
|
data/lib/astronoby/observer.rb
CHANGED
@@ -42,6 +42,45 @@ module Astronoby
|
|
42
42
|
@pressure = pressure || compute_pressure
|
43
43
|
end
|
44
44
|
|
45
|
+
def geocentric_position
|
46
|
+
n = earth_prime_vertical_radius_of_curvature
|
47
|
+
x = (n + @elevation.m) * @latitude.cos * @longitude.cos
|
48
|
+
y = (n + @elevation.m) * @latitude.cos * @longitude.sin
|
49
|
+
z = (n * (1 - Constants::WGS84_ECCENTICITY_SQUARED) + @elevation.m) *
|
50
|
+
@latitude.sin
|
51
|
+
Distance.vector_from_meters([x, y, z])
|
52
|
+
end
|
53
|
+
|
54
|
+
def geocentric_velocity
|
55
|
+
r = projected_radius
|
56
|
+
vx = -Constants::EARTH_ANGULAR_VELOCITY_RAD_PER_S * r * @longitude.sin
|
57
|
+
vy = Constants::EARTH_ANGULAR_VELOCITY_RAD_PER_S * r * @longitude.cos
|
58
|
+
vz = 0.0
|
59
|
+
Velocity.vector_from_mps([vx, vy, vz])
|
60
|
+
end
|
61
|
+
|
62
|
+
def earth_fixed_rotation_matrix_for(instant)
|
63
|
+
dpsi = Nutation.new(instant: instant).nutation_in_longitude
|
64
|
+
|
65
|
+
mean_obliquity = MeanObliquity.for_epoch(instant.tt)
|
66
|
+
|
67
|
+
gast = Angle.from_radians(
|
68
|
+
Angle.from_hours(instant.gmst).radians +
|
69
|
+
dpsi.radians * mean_obliquity.cos
|
70
|
+
)
|
71
|
+
|
72
|
+
earth_rotation_matrix = Matrix[
|
73
|
+
[gast.cos, -gast.sin, 0],
|
74
|
+
[gast.sin, gast.cos, 0],
|
75
|
+
[0, 0, 1]
|
76
|
+
]
|
77
|
+
|
78
|
+
nutation_matrix = Nutation.matrix_for(instant)
|
79
|
+
precession_matrix = Precession.matrix_for(instant)
|
80
|
+
|
81
|
+
earth_rotation_matrix * nutation_matrix * precession_matrix
|
82
|
+
end
|
83
|
+
|
45
84
|
def ==(other)
|
46
85
|
return false unless other.is_a?(self.class)
|
47
86
|
|
@@ -84,5 +123,21 @@ module Astronoby
|
|
84
123
|
|
85
124
|
Math.exp(-term1 / term2)
|
86
125
|
end
|
126
|
+
|
127
|
+
def earth_prime_vertical_radius_of_curvature
|
128
|
+
Constants::WGS84_EARTH_EQUATORIAL_RADIUS_IN_METERS./(
|
129
|
+
Math.sqrt(
|
130
|
+
1 -
|
131
|
+
Constants::WGS84_ECCENTICITY_SQUARED * @latitude.sin * @latitude.sin
|
132
|
+
)
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
def projected_radius
|
137
|
+
Math.sqrt(
|
138
|
+
geocentric_position.x.m * geocentric_position.x.m +
|
139
|
+
geocentric_position.y.m * geocentric_position.y.m
|
140
|
+
)
|
141
|
+
end
|
87
142
|
end
|
88
143
|
end
|
data/lib/astronoby/precession.rb
CHANGED
@@ -1,16 +1,74 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "matrix"
|
4
|
-
|
5
3
|
module Astronoby
|
6
4
|
class Precession
|
7
|
-
def self.
|
8
|
-
new(
|
5
|
+
def self.matrix_for(instant)
|
6
|
+
new(instant: instant).matrix
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(instant:)
|
10
|
+
@instant = instant
|
11
|
+
end
|
12
|
+
|
13
|
+
def matrix
|
14
|
+
# Source:
|
15
|
+
# IAU resolution in 2006 in favor of the P03 astronomical model
|
16
|
+
# https://syrte.obspm.fr/iau2006/aa03_412_P03.pdf
|
17
|
+
# P(t) = R3(χA) R1(−ωA) R3(−ψA) R1(ϵ0)
|
18
|
+
|
19
|
+
# Precession in right ascension
|
20
|
+
psi_a = ((((
|
21
|
+
-0.0000000951 * t +
|
22
|
+
+0.000132851) * t +
|
23
|
+
-0.00114045) * t +
|
24
|
+
-1.0790069) * t +
|
25
|
+
+5038.481507) * t
|
26
|
+
|
27
|
+
# Precession in declination
|
28
|
+
omega_a = ((((
|
29
|
+
+0.0000003337 * t +
|
30
|
+
-0.000000467) * t +
|
31
|
+
-0.00772503) * t +
|
32
|
+
+0.0512623) * t +
|
33
|
+
-0.025754) * t +
|
34
|
+
eps0
|
35
|
+
|
36
|
+
# Precession of the ecliptic
|
37
|
+
chi_a = ((((
|
38
|
+
-0.0000000560 * t +
|
39
|
+
+0.000170663) * t +
|
40
|
+
-0.00121197) * t +
|
41
|
+
-2.3814292) * t +
|
42
|
+
+10.556403) * t
|
43
|
+
|
44
|
+
psi_a = Angle.from_degree_arcseconds(psi_a)
|
45
|
+
omega_a = Angle.from_degree_arcseconds(omega_a)
|
46
|
+
chi_a = Angle.from_degree_arcseconds(chi_a)
|
47
|
+
|
48
|
+
r3_psi = rotation_z(-psi_a)
|
49
|
+
r1_omega = rotation_x(-omega_a)
|
50
|
+
r3_chi = rotation_z(chi_a)
|
51
|
+
r1_eps0 = rotation_x(MeanObliquity.obliquity_of_reference)
|
52
|
+
|
53
|
+
r3_chi * r1_omega * r3_psi * r1_eps0
|
9
54
|
end
|
10
55
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
56
|
+
def rotation_x(angle)
|
57
|
+
c, s = angle.cos, angle.sin
|
58
|
+
Matrix[
|
59
|
+
[1, 0, 0],
|
60
|
+
[0, c, s],
|
61
|
+
[0, -s, c]
|
62
|
+
]
|
63
|
+
end
|
64
|
+
|
65
|
+
def rotation_z(angle)
|
66
|
+
c, s = angle.cos, angle.sin
|
67
|
+
Matrix[
|
68
|
+
[c, s, 0],
|
69
|
+
[-s, c, 0],
|
70
|
+
[0, 0, 1]
|
71
|
+
]
|
14
72
|
end
|
15
73
|
|
16
74
|
# Source:
|
@@ -18,14 +76,19 @@ module Astronoby
|
|
18
76
|
# Authors: Peter Duffett-Smith and Jonathan Zwart
|
19
77
|
# Edition: Cambridge University Press
|
20
78
|
# Chapter: 34 - Precession
|
21
|
-
|
22
|
-
|
23
|
-
|
79
|
+
|
80
|
+
def self.for_equatorial_coordinates(coordinates:, epoch:)
|
81
|
+
precess(coordinates, epoch)
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.precess(coordinates, epoch)
|
85
|
+
matrix_a = matrix_for_epoch(coordinates.epoch)
|
86
|
+
matrix_b = matrix_for_epoch(epoch).transpose
|
24
87
|
|
25
88
|
vector = Vector[
|
26
|
-
|
27
|
-
|
28
|
-
|
89
|
+
coordinates.right_ascension.cos * coordinates.declination.cos,
|
90
|
+
coordinates.right_ascension.sin * coordinates.declination.cos,
|
91
|
+
coordinates.declination.sin
|
29
92
|
]
|
30
93
|
|
31
94
|
s = matrix_a * vector
|
@@ -38,13 +101,11 @@ module Astronoby
|
|
38
101
|
Angle.atan(w[1] / w[0])
|
39
102
|
),
|
40
103
|
declination: Angle.asin(w[2]),
|
41
|
-
epoch:
|
104
|
+
epoch: epoch
|
42
105
|
)
|
43
106
|
end
|
44
107
|
|
45
|
-
|
46
|
-
|
47
|
-
def matrix_for_epoch(epoch)
|
108
|
+
def self.matrix_for_epoch(epoch)
|
48
109
|
t = (epoch - Epoch::DEFAULT_EPOCH) / Constants::DAYS_PER_JULIAN_CENTURY
|
49
110
|
|
50
111
|
zeta = Angle.from_degrees(
|
@@ -82,5 +143,18 @@ module Astronoby
|
|
82
143
|
]
|
83
144
|
]
|
84
145
|
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def t
|
150
|
+
@t ||= Rational(
|
151
|
+
@instant.tdb - Epoch::DEFAULT_EPOCH,
|
152
|
+
Constants::DAYS_PER_JULIAN_CENTURY
|
153
|
+
)
|
154
|
+
end
|
155
|
+
|
156
|
+
def eps0
|
157
|
+
@eps0 ||= MeanObliquity.obliquity_of_reference_in_milliarcseconds
|
158
|
+
end
|
85
159
|
end
|
86
160
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Astronoby
|
4
|
+
class ReferenceFrame
|
5
|
+
attr_reader :position,
|
6
|
+
:velocity,
|
7
|
+
:instant,
|
8
|
+
:center_identifier,
|
9
|
+
:target_body
|
10
|
+
|
11
|
+
def initialize(
|
12
|
+
position:,
|
13
|
+
velocity:,
|
14
|
+
instant:,
|
15
|
+
center_identifier:,
|
16
|
+
target_body:
|
17
|
+
)
|
18
|
+
@position = position
|
19
|
+
@velocity = velocity
|
20
|
+
@instant = instant
|
21
|
+
@center_identifier = center_identifier
|
22
|
+
@target_body = target_body
|
23
|
+
end
|
24
|
+
|
25
|
+
def equatorial
|
26
|
+
@equatorial ||= begin
|
27
|
+
return Coordinates::Equatorial.zero if distance.zero?
|
28
|
+
|
29
|
+
Coordinates::Equatorial.from_position_vector(@position)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def ecliptic
|
34
|
+
@ecliptic ||= begin
|
35
|
+
return Coordinates::Ecliptic.zero if distance.zero?
|
36
|
+
|
37
|
+
equatorial.to_ecliptic(epoch: Epoch::J2000)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def distance
|
42
|
+
@distance ||= begin
|
43
|
+
return Distance.zero if @position.zero?
|
44
|
+
|
45
|
+
@position.magnitude
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Astronoby
|
4
|
+
class Apparent < ReferenceFrame
|
5
|
+
def self.build_from_astrometric(
|
6
|
+
instant:,
|
7
|
+
target_astrometric:,
|
8
|
+
earth_geometric:,
|
9
|
+
target_body:
|
10
|
+
)
|
11
|
+
position = target_astrometric.position
|
12
|
+
velocity = target_astrometric.velocity
|
13
|
+
precession_matrix = Precession.matrix_for(instant)
|
14
|
+
nutation_matrix = Nutation.matrix_for(instant)
|
15
|
+
|
16
|
+
corrected_position = Distance.vector_from_meters(
|
17
|
+
precession_matrix * nutation_matrix * position.map(&:m)
|
18
|
+
)
|
19
|
+
corrected_position = Aberration.new(
|
20
|
+
astrometric_position: corrected_position,
|
21
|
+
observer_velocity: earth_geometric.velocity
|
22
|
+
).corrected_position
|
23
|
+
# In theory, here we should also apply light deflection. However, so far
|
24
|
+
# the deflection algorithm hasn't shown any significant changes to the
|
25
|
+
# apparent position. Therefore, for now, we are saving some computation
|
26
|
+
# time by not applying it, and we will investigate if the algorithm is
|
27
|
+
# correct or if the deflection is indeed negligible.
|
28
|
+
|
29
|
+
corrected_velocity = Velocity.vector_from_mps(
|
30
|
+
precession_matrix * nutation_matrix * velocity.map(&:mps)
|
31
|
+
)
|
32
|
+
|
33
|
+
new(
|
34
|
+
position: corrected_position,
|
35
|
+
velocity: corrected_velocity,
|
36
|
+
instant: instant,
|
37
|
+
center_identifier: SolarSystemBody::EARTH,
|
38
|
+
target_body: target_body
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def ecliptic
|
43
|
+
@ecliptic ||= begin
|
44
|
+
return Coordinates::Ecliptic.zero if distance.zero?
|
45
|
+
|
46
|
+
equatorial.to_ecliptic(epoch: @instant.tdb)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def angular_diameter
|
51
|
+
@angular_radius ||= begin
|
52
|
+
return Angle.zero if @position.zero?
|
53
|
+
|
54
|
+
Angle.from_radians(
|
55
|
+
Math.atan(@target_body.class::EQUATORIAL_RADIUS.m / distance.m) * 2
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Astronoby
|
4
|
+
class Astrometric < ReferenceFrame
|
5
|
+
def self.build_from_geometric(
|
6
|
+
instant:,
|
7
|
+
earth_geometric:,
|
8
|
+
light_time_corrected_position:,
|
9
|
+
light_time_corrected_velocity:,
|
10
|
+
target_body:
|
11
|
+
)
|
12
|
+
new(
|
13
|
+
position: light_time_corrected_position - earth_geometric.position,
|
14
|
+
velocity: light_time_corrected_velocity - earth_geometric.velocity,
|
15
|
+
instant: instant,
|
16
|
+
center_identifier: SolarSystemBody::EARTH,
|
17
|
+
target_body: target_body
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Astronoby
|
4
|
+
class Geometric < ReferenceFrame
|
5
|
+
def initialize(
|
6
|
+
position:,
|
7
|
+
velocity:,
|
8
|
+
instant:,
|
9
|
+
target_body:
|
10
|
+
)
|
11
|
+
super(
|
12
|
+
position: position,
|
13
|
+
velocity: velocity,
|
14
|
+
instant: instant,
|
15
|
+
center_identifier: SolarSystemBody::SOLAR_SYSTEM_BARYCENTER,
|
16
|
+
target_body: target_body
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Astronoby
|
4
|
+
class MeanOfDate < ReferenceFrame
|
5
|
+
def self.build_from_geometric(
|
6
|
+
instant:,
|
7
|
+
target_geometric:,
|
8
|
+
earth_geometric:,
|
9
|
+
target_body:
|
10
|
+
)
|
11
|
+
position = target_geometric.position - earth_geometric.position
|
12
|
+
velocity = target_geometric.velocity - earth_geometric.velocity
|
13
|
+
precession_matrix = Precession.matrix_for(instant)
|
14
|
+
corrected_position = Distance.vector_from_m(
|
15
|
+
precession_matrix * position.map(&:m)
|
16
|
+
)
|
17
|
+
corrected_velocity = Velocity.vector_from_mps(
|
18
|
+
precession_matrix * velocity.map(&:mps)
|
19
|
+
)
|
20
|
+
|
21
|
+
new(
|
22
|
+
position: corrected_position,
|
23
|
+
velocity: corrected_velocity,
|
24
|
+
instant: instant,
|
25
|
+
center_identifier: SolarSystemBody::EARTH,
|
26
|
+
target_body: target_body
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def ecliptic
|
31
|
+
@ecliptic ||= begin
|
32
|
+
return Coordinates::Ecliptic.zero if distance.zero?
|
33
|
+
|
34
|
+
equatorial.to_ecliptic(epoch: @instant.tdb)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|