astronoby 0.5.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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/.standard.yml +1 -0
  4. data/CHANGELOG.md +162 -0
  5. data/Gemfile.lock +54 -34
  6. data/README.md +42 -272
  7. data/UPGRADING.md +238 -0
  8. data/benchmark/README.md +131 -0
  9. data/benchmark/benchmark.rb +259 -0
  10. data/benchmark/data/imcce.csv.zip +0 -0
  11. data/benchmark/data/sun_calc.csv.zip +0 -0
  12. data/lib/astronoby/aberration.rb +56 -31
  13. data/lib/astronoby/angle.rb +20 -16
  14. data/lib/astronoby/angles/dms.rb +2 -2
  15. data/lib/astronoby/angles/hms.rb +2 -2
  16. data/lib/astronoby/bodies/earth.rb +56 -0
  17. data/lib/astronoby/bodies/jupiter.rb +11 -0
  18. data/lib/astronoby/bodies/mars.rb +11 -0
  19. data/lib/astronoby/bodies/mercury.rb +11 -0
  20. data/lib/astronoby/bodies/moon.rb +50 -285
  21. data/lib/astronoby/bodies/neptune.rb +11 -0
  22. data/lib/astronoby/bodies/saturn.rb +11 -0
  23. data/lib/astronoby/bodies/solar_system_body.rb +122 -0
  24. data/lib/astronoby/bodies/sun.rb +16 -220
  25. data/lib/astronoby/bodies/uranus.rb +11 -0
  26. data/lib/astronoby/bodies/venus.rb +11 -0
  27. data/lib/astronoby/constants.rb +13 -1
  28. data/lib/astronoby/coordinates/ecliptic.rb +2 -37
  29. data/lib/astronoby/coordinates/equatorial.rb +25 -7
  30. data/lib/astronoby/coordinates/horizontal.rb +0 -46
  31. data/lib/astronoby/corrections/light_time_delay.rb +90 -0
  32. data/lib/astronoby/deflection.rb +187 -0
  33. data/lib/astronoby/distance.rb +9 -0
  34. data/lib/astronoby/ephem.rb +39 -0
  35. data/lib/astronoby/equinox_solstice.rb +21 -18
  36. data/lib/astronoby/errors.rb +4 -0
  37. data/lib/astronoby/events/moon_phases.rb +2 -1
  38. data/lib/astronoby/events/rise_transit_set_calculator.rb +352 -0
  39. data/lib/astronoby/events/rise_transit_set_event.rb +13 -0
  40. data/lib/astronoby/events/rise_transit_set_events.rb +13 -0
  41. data/lib/astronoby/events/twilight_calculator.rb +166 -0
  42. data/lib/astronoby/events/twilight_event.rb +28 -0
  43. data/lib/astronoby/instant.rb +171 -0
  44. data/lib/astronoby/mean_obliquity.rb +23 -10
  45. data/lib/astronoby/nutation.rb +227 -42
  46. data/lib/astronoby/observer.rb +66 -1
  47. data/lib/astronoby/precession.rb +91 -17
  48. data/lib/astronoby/reference_frame.rb +49 -0
  49. data/lib/astronoby/reference_frames/apparent.rb +60 -0
  50. data/lib/astronoby/reference_frames/astrometric.rb +21 -0
  51. data/lib/astronoby/reference_frames/geometric.rb +20 -0
  52. data/lib/astronoby/reference_frames/mean_of_date.rb +38 -0
  53. data/lib/astronoby/reference_frames/topocentric.rb +82 -0
  54. data/lib/astronoby/time/greenwich_sidereal_time.rb +1 -1
  55. data/lib/astronoby/true_obliquity.rb +2 -1
  56. data/lib/astronoby/util/maths.rb +68 -49
  57. data/lib/astronoby/util/time.rb +466 -32
  58. data/lib/astronoby/vector.rb +36 -0
  59. data/lib/astronoby/velocity.rb +116 -0
  60. data/lib/astronoby/version.rb +1 -1
  61. data/lib/astronoby.rb +26 -5
  62. metadata +81 -18
  63. data/.tool-versions +0 -1
  64. data/lib/astronoby/astronomical_models/ephemeride_lunaire_parisienne.rb +0 -143
  65. data/lib/astronoby/events/observation_events.rb +0 -259
  66. data/lib/astronoby/events/rise_transit_set_iteration.rb +0 -215
  67. data/lib/astronoby/events/twilight_events.rb +0 -121
  68. data/lib/astronoby/util/astrodynamics.rb +0 -60
@@ -1,47 +1,72 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Astronoby
4
+ # Applies relativistic aberration corrections to an astrometric position based
5
+ # on observer velocity.
4
6
  class Aberration
5
- MAXIMUM_SHIFT = Angle.from_degrees(20.5)
7
+ # Source:
8
+ # Title: Explanatory Supplement to the Astronomical Almanac
9
+ # Authors: Sean E. Urban and P. Kenneth Seidelmann
10
+ # Edition: University Science Books
11
+ # Chapter: 7.2.3 - Aberration
6
12
 
7
- def self.for_ecliptic_coordinates(coordinates:, epoch:)
8
- new(coordinates, epoch).apply
9
- end
13
+ LIGHT_SPEED = Astronoby::Velocity.light_speed.mps
10
14
 
11
- def initialize(coordinates, epoch)
12
- @coordinates = coordinates
13
- @epoch = epoch
15
+ # Initializes the aberration correction with position and observer velocity.
16
+ #
17
+ # @param astrometric_position [Astronoby::Vector<Astronoby::Distance>] The
18
+ # astrometric position vector.
19
+ # @param observer_velocity [Astronoby::Vector<Astronoby::Velocity>] The
20
+ # velocity vector of the observer.
21
+ def initialize(astrometric_position:, observer_velocity:)
22
+ @position = astrometric_position
23
+ @velocity = observer_velocity
24
+ @distance_meters = @position.norm.m
25
+ @observer_speed = @velocity.norm.mps
14
26
  end
15
27
 
16
- # Source:
17
- # Title: Practical Astronomy with your Calculator or Spreadsheet
18
- # Authors: Peter Duffett-Smith and Jonathan Zwart
19
- # Edition: Cambridge University Press
20
- # Chapter: 36 - Aberration
21
- def apply
22
- delta_longitude = Angle.from_degrees(
23
- -MAXIMUM_SHIFT.degrees * (
24
- sun_longitude - @coordinates.longitude
25
- ).cos / @coordinates.latitude.cos / Constants::SECONDS_PER_DEGREE
26
- )
28
+ # Computes the aberration-corrected position.
29
+ #
30
+ # @return [Astronoby::Vector<Astronoby::Distance>] The corrected position
31
+ # vector.
32
+ def corrected_position
33
+ beta = @observer_speed / LIGHT_SPEED
34
+ projected_velocity = beta * aberration_angle_cos
35
+ lorentz_factor_inv = lorentz_factor_inverse(beta)
27
36
 
28
- delta_latitude = Angle.from_degrees(
29
- -MAXIMUM_SHIFT.degrees *
30
- (sun_longitude - @coordinates.longitude).sin *
31
- @coordinates.latitude.sin / Constants::SECONDS_PER_DEGREE
32
- )
37
+ velocity_correction =
38
+ velocity_correction_factor(projected_velocity) * velocity_mps
39
+ normalization_factor = 1.0 + projected_velocity
40
+ position_scaled = position_meters * lorentz_factor_inv
33
41
 
34
- Coordinates::Ecliptic.new(
35
- latitude: @coordinates.latitude + delta_latitude,
36
- longitude: @coordinates.longitude + delta_longitude
42
+ Distance.vector_from_meters(
43
+ (position_scaled + velocity_correction) / normalization_factor
37
44
  )
38
45
  end
39
46
 
40
- def sun_longitude
41
- @_sun_longitude ||= Sun
42
- .new(time: Epoch.to_utc(@epoch))
43
- .true_ecliptic_coordinates
44
- .longitude
47
+ private
48
+
49
+ def aberration_angle_cos
50
+ denominator = [@distance_meters * @observer_speed, 1e-20].max
51
+ Util::Maths.dot_product(position_meters, velocity_mps) / denominator
52
+ end
53
+
54
+ def position_meters
55
+ @position.map(&:meters)
56
+ end
57
+
58
+ def velocity_mps
59
+ @velocity.map(&:mps)
60
+ end
61
+
62
+ def lorentz_factor_inverse(beta)
63
+ Math.sqrt(1.0 - beta**2)
64
+ end
65
+
66
+ def velocity_correction_factor(projected_velocity)
67
+ lorentz_inv = lorentz_factor_inverse(projected_velocity)
68
+ (1.0 + projected_velocity / (1.0 + lorentz_inv)) *
69
+ (@distance_meters / LIGHT_SPEED)
45
70
  end
46
71
  end
47
72
  end
@@ -22,6 +22,10 @@ module Astronoby
22
22
  from_radians(radians)
23
23
  end
24
24
 
25
+ def from_degree_arcseconds(arcseconds)
26
+ from_dms(0, 0, arcseconds)
27
+ end
28
+
25
29
  def from_hours(hours)
26
30
  radians = hours * Constants::RADIAN_PER_HOUR
27
31
  from_radians(radians)
@@ -120,10 +124,10 @@ module Astronoby
120
124
  end
121
125
  alias_method :eql?, :==
122
126
 
123
- def str(format)
127
+ def str(format, precision: 4)
124
128
  case format
125
- when :dms then to_dms(degrees).format
126
- when :hms then to_hms(hours).format
129
+ when :dms then to_dms.format(precision: precision)
130
+ when :hms then to_hms.format(precision: precision)
127
131
  else
128
132
  raise UnsupportedFormatError.new(
129
133
  "Expected a format between #{FORMATS.join(", ")}, got #{format}"
@@ -131,36 +135,36 @@ module Astronoby
131
135
  end
132
136
  end
133
137
 
134
- def to_dms(deg)
135
- sign = deg.negative? ? "-" : "+"
136
- absolute_degrees = deg.abs
137
- degrees = absolute_degrees.floor
138
+ def to_dms
139
+ sign = degrees.negative? ? "-" : "+"
140
+ absolute_degrees = degrees.abs
141
+ deg = absolute_degrees.floor
138
142
  decimal_minutes = Constants::MINUTES_PER_DEGREE *
139
- (absolute_degrees - degrees)
143
+ (absolute_degrees - deg)
140
144
  absolute_decimal_minutes = (
141
- Constants::MINUTES_PER_DEGREE * (absolute_degrees - degrees)
145
+ Constants::MINUTES_PER_DEGREE * (absolute_degrees - deg)
142
146
  ).abs
143
147
  minutes = decimal_minutes.floor
144
148
  seconds = Constants::SECONDS_PER_MINUTE * (
145
149
  absolute_decimal_minutes - absolute_decimal_minutes.floor
146
150
  )
147
151
 
148
- Dms.new(sign, degrees, minutes, seconds.floor(4))
152
+ Dms.new(sign, deg, minutes, seconds)
149
153
  end
150
154
 
151
- def to_hms(hrs)
152
- absolute_hours = hrs.abs
153
- hours = absolute_hours.floor
154
- decimal_minutes = Constants::MINUTES_PER_HOUR * (absolute_hours - hours)
155
+ def to_hms
156
+ absolute_hours = hours.abs
157
+ hrs = absolute_hours.floor
158
+ decimal_minutes = Constants::MINUTES_PER_HOUR * (absolute_hours - hrs)
155
159
  absolute_decimal_minutes = (
156
- Constants::MINUTES_PER_HOUR * (absolute_hours - hours)
160
+ Constants::MINUTES_PER_HOUR * (absolute_hours - hrs)
157
161
  ).abs
158
162
  minutes = decimal_minutes.floor
159
163
  seconds = Constants::SECONDS_PER_MINUTE * (
160
164
  absolute_decimal_minutes - absolute_decimal_minutes.floor
161
165
  )
162
166
 
163
- Hms.new(hours, minutes, seconds.floor(4))
167
+ Hms.new(hrs, minutes, seconds)
164
168
  end
165
169
  end
166
170
  end
@@ -11,8 +11,8 @@ module Astronoby
11
11
  @seconds = seconds
12
12
  end
13
13
 
14
- def format
15
- "#{sign}#{degrees}° #{minutes}′ #{seconds}″"
14
+ def format(precision: 4)
15
+ "#{sign}#{degrees}° #{minutes}′ #{seconds.floor(precision)}″"
16
16
  end
17
17
  end
18
18
  end
@@ -10,8 +10,8 @@ module Astronoby
10
10
  @seconds = seconds
11
11
  end
12
12
 
13
- def format
14
- "#{hours}h #{minutes}m #{seconds}s"
13
+ def format(precision: 4)
14
+ "#{hours}h #{minutes}m #{seconds.floor(precision)}s"
15
15
  end
16
16
  end
17
17
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ class Earth < SolarSystemBody
5
+ def self.ephemeris_segments(ephem_source)
6
+ if ephem_source == ::Ephem::SPK::JPL_DE
7
+ [
8
+ [SOLAR_SYSTEM_BARYCENTER, EARTH_MOON_BARYCENTER],
9
+ [EARTH_MOON_BARYCENTER, EARTH]
10
+ ]
11
+ elsif ephem_source == ::Ephem::SPK::INPOP
12
+ [
13
+ [SOLAR_SYSTEM_BARYCENTER, EARTH]
14
+ ]
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def compute_astrometric(ephem)
21
+ Astrometric.new(
22
+ position: Vector[
23
+ Distance.zero,
24
+ Distance.zero,
25
+ Distance.zero
26
+ ],
27
+ velocity: Vector[
28
+ Velocity.zero,
29
+ Velocity.zero,
30
+ Velocity.zero
31
+ ],
32
+ instant: @instant,
33
+ center_identifier: EARTH,
34
+ target_body: self.class
35
+ )
36
+ end
37
+
38
+ def compute_mean_of_date(ephem)
39
+ MeanOfDate.new(
40
+ position: Vector[
41
+ Distance.zero,
42
+ Distance.zero,
43
+ Distance.zero
44
+ ],
45
+ velocity: Vector[
46
+ Velocity.zero,
47
+ Velocity.zero,
48
+ Velocity.zero
49
+ ],
50
+ instant: @instant,
51
+ center_identifier: EARTH,
52
+ target_body: self.class
53
+ )
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ class Jupiter < SolarSystemBody
5
+ EQUATORIAL_RADIUS = Distance.from_meters(71_492_000)
6
+
7
+ def self.ephemeris_segments(_ephem_source)
8
+ [[SOLAR_SYSTEM_BARYCENTER, JUPITER_BARYCENTER]]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ class Mars < SolarSystemBody
5
+ EQUATORIAL_RADIUS = Distance.from_meters(3_396_200)
6
+
7
+ def self.ephemeris_segments(_ephem_source)
8
+ [[SOLAR_SYSTEM_BARYCENTER, MARS_BARYCENTER]]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ class Mercury < SolarSystemBody
5
+ EQUATORIAL_RADIUS = Distance.from_meters(2_439_700)
6
+
7
+ def self.ephemeris_segments(_ephem_source)
8
+ [[SOLAR_SYSTEM_BARYCENTER, MERCURY_BARYCENTER]]
9
+ end
10
+ end
11
+ end
@@ -1,9 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Astronoby
4
- class Moon
4
+ class Moon < SolarSystemBody
5
5
  SEMIDIAMETER_VARIATION = 0.7275
6
- MEAN_GEOCENTRIC_DISTANCE = Astronoby::Distance.from_meters(385_000_560)
6
+ EQUATORIAL_RADIUS = Distance.from_meters(1_737_400)
7
+
8
+ def self.ephemeris_segments(ephem_source)
9
+ if ephem_source == ::Ephem::SPK::JPL_DE
10
+ [
11
+ [SOLAR_SYSTEM_BARYCENTER, EARTH_MOON_BARYCENTER],
12
+ [EARTH_MOON_BARYCENTER, MOON]
13
+ ]
14
+ elsif ephem_source == ::Ephem::SPK::INPOP
15
+ [
16
+ [SOLAR_SYSTEM_BARYCENTER, EARTH],
17
+ [EARTH, MOON]
18
+ ]
19
+ end
20
+ end
7
21
 
8
22
  # Source:
9
23
  # Title: Astronomical Algorithms
@@ -18,117 +32,24 @@ module Astronoby
18
32
  Events::MoonPhases.phases_for(year: year, month: month)
19
33
  end
20
34
 
21
- def initialize(time:)
22
- @time = time
23
- end
24
-
25
- # @return [Astronoby::Coordinates::Ecliptic] Apparent ecliptic coordinates
26
- # of the Moon
27
- def apparent_ecliptic_coordinates
28
- @ecliptic_coordinates ||= begin
29
- latitude = Astronoby::Angle.from_degrees(
30
- (latitude_terms + additive_latitude_terms) *
31
- EphemerideLunaireParisienne::DEGREES_UNIT
32
- )
33
-
34
- longitude = mean_longitude + Astronoby::Angle.from_degrees(
35
- (longitude_terms + additive_longitude_terms) *
36
- EphemerideLunaireParisienne::DEGREES_UNIT
37
- ) + nutation
38
-
39
- Coordinates::Ecliptic.new(
40
- latitude: latitude,
41
- longitude: longitude
42
- )
43
- end
44
- end
45
-
46
- # Source:
47
- # Title: Astronomical Algorithms
48
- # Author: Jean Meeus
49
- # Edition: 2nd edition
50
- # Chapter: 47 - Position of the Moon
51
-
52
- # @return [Astronoby::Coordinates::Equatorial] Apparent geocentric
53
- # equatorial coordinates of the Moon
54
- def apparent_equatorial_coordinates
55
- @apparent_equatorial_coordinates ||=
56
- apparent_ecliptic_coordinates
57
- .to_apparent_equatorial(epoch: Epoch.from_time(@time))
58
- end
59
-
60
- def horizontal_coordinates(observer:)
61
- apparent_topocentric_equatorial_coordinates =
62
- Astronoby::GeocentricParallax.for_equatorial_coordinates(
63
- observer: observer,
64
- time: @time,
65
- coordinates: apparent_equatorial_coordinates,
66
- distance: distance
67
- )
68
-
69
- apparent_topocentric_equatorial_coordinates.to_horizontal(
70
- observer: observer,
71
- time: @time
72
- )
73
- end
74
-
75
- # @return [Astronoby::Distance] Distance between the Earth and the Moon centers
76
- def distance
77
- @distance ||= Astronoby::Distance.from_meters(
78
- (MEAN_GEOCENTRIC_DISTANCE.meters + distance_terms).round
79
- )
80
- end
35
+ attr_reader :phase_angle
81
36
 
82
- # @return [Angle] Moon's mean longitude
83
- def mean_longitude
84
- @mean_longitude ||= Angle.from_degrees(
85
- (
86
- 218.3164477 +
87
- 481267.88123421 * elapsed_centuries -
88
- 0.0015786 * elapsed_centuries**2 +
89
- elapsed_centuries**3 / 538841 -
90
- elapsed_centuries**4 / 65194000
91
- ) % 360
92
- )
37
+ def initialize(instant:, ephem:)
38
+ super
39
+ @phase_angle = compute_phase_angle(ephem)
93
40
  end
94
41
 
95
- # @return [Angle] Moon's mean elongation
96
- def mean_elongation
97
- @mean_elongation ||= Angle.from_degrees(
98
- (
99
- 297.8501921 +
100
- 445267.1114034 * elapsed_centuries -
101
- 0.0018819 * elapsed_centuries**2 +
102
- elapsed_centuries**3 / 545868 -
103
- elapsed_centuries**4 / 113065000
104
- ) % 360
105
- )
42
+ # @return [Float] Moon's illuminated fraction
43
+ def illuminated_fraction
44
+ @illuminated_fraction ||= (1 + phase_angle.cos) / 2.0
106
45
  end
107
46
 
108
- # @return [Angle] Moon's mean anomaly
109
- def mean_anomaly
110
- @mean_anomaly ||= Angle.from_degrees(
111
- (
112
- 134.9633964 +
113
- 477198.8675055 * elapsed_centuries +
114
- 0.0087414 * elapsed_centuries**2 +
115
- elapsed_centuries**3 / 69699 -
116
- elapsed_centuries**4 / 14712000
117
- ) % 360
118
- )
47
+ # @return [Float] Phase fraction, from 0 to 1
48
+ def current_phase_fraction
49
+ mean_elongation.degrees / Constants::DEGREES_PER_CIRCLE
119
50
  end
120
51
 
121
- # @return [Angle] Moon's argument of latitude
122
- def argument_of_latitude
123
- @argument_of_latitude ||= Angle.from_degrees(
124
- (
125
- 93.2720950 +
126
- 483202.0175233 * elapsed_centuries -
127
- 0.0036539 * elapsed_centuries**2 -
128
- elapsed_centuries**3 / 3526000
129
- ) % 360
130
- )
131
- end
52
+ private
132
53
 
133
54
  # Source:
134
55
  # Title: Astronomical Algorithms
@@ -137,199 +58,43 @@ module Astronoby
137
58
  # Chapter: 48 - Illuminated Fraction of the Moon's Disk
138
59
 
139
60
  # @return [Angle] Moon's phase angle
140
- def phase_angle
61
+ def compute_phase_angle(ephem)
141
62
  @phase_angle ||= begin
142
- sun_apparent_equatorial_coordinates = sun
143
- .apparent_ecliptic_coordinates
144
- .to_apparent_equatorial(epoch: Epoch.from_time(@time))
145
- moon_apparent_equatorial_coordinates = apparent_equatorial_coordinates
63
+ sun = Sun.new(instant: @instant, ephem: ephem)
146
64
  geocentric_elongation = Angle.acos(
147
- sun_apparent_equatorial_coordinates.declination.sin *
148
- moon_apparent_equatorial_coordinates.declination.sin +
149
- sun_apparent_equatorial_coordinates.declination.cos *
150
- moon_apparent_equatorial_coordinates.declination.cos *
151
- (
152
- sun_apparent_equatorial_coordinates.right_ascension -
153
- moon_apparent_equatorial_coordinates.right_ascension
154
- ).cos
65
+ sun.apparent.equatorial.declination.sin *
66
+ apparent.equatorial.declination.sin +
67
+ sun.apparent.equatorial.declination.cos *
68
+ apparent.equatorial.declination.cos *
69
+ (
70
+ sun.apparent.equatorial.right_ascension -
71
+ apparent.equatorial.right_ascension
72
+ ).cos
155
73
  )
156
74
 
157
- term1 = sun.earth_distance.km * geocentric_elongation.sin
158
- term2 = distance.km - sun.earth_distance.km * geocentric_elongation.cos
75
+ term1 = sun.astrometric.distance.km * geocentric_elongation.sin
76
+ term2 = astrometric.distance.km -
77
+ sun.astrometric.distance.km * geocentric_elongation.cos
159
78
  angle = Angle.atan(term1 / term2)
160
79
  Astronoby::Util::Trigonometry
161
80
  .adjustement_for_arctangent(term1, term2, angle)
162
81
  end
163
82
  end
164
83
 
165
- # @return [Float] Moon's illuminated fraction
166
- def illuminated_fraction
167
- @illuminated_fraction ||= (1 + phase_angle.cos) / 2
168
- end
169
-
170
- # @param observer [Astronoby::Observer] Observer of the event
171
- # @return [Astronoby::Events::ObservationEvents] Moon's observation events
172
- def observation_events(observer:)
173
- today = @time.to_date
174
- leap_seconds = Util::Time.terrestrial_universal_time_delta(today)
175
- yesterday = today.prev_day
176
- yesterday_midnight_terrestrial_time =
177
- Time.utc(yesterday.year, yesterday.month, yesterday.day) - leap_seconds
178
- today_midnight_terrestrial_time =
179
- Time.utc(today.year, today.month, today.day) - leap_seconds
180
- tomorrow = today.next_day
181
- tomorrow_midnight_terrestrial_time =
182
- Time.utc(tomorrow.year, tomorrow.month, tomorrow.day) - leap_seconds
183
-
184
- coordinates_of_the_previous_day = self.class
185
- .new(time: yesterday_midnight_terrestrial_time)
186
- .apparent_equatorial_coordinates
187
- coordinates_of_the_day = self.class
188
- .new(time: today_midnight_terrestrial_time)
189
- .apparent_equatorial_coordinates
190
- coordinates_of_the_next_day = self.class
191
- .new(time: tomorrow_midnight_terrestrial_time)
192
- .apparent_equatorial_coordinates
193
- additional_altitude = -Angle.from_degrees(
194
- SEMIDIAMETER_VARIATION *
195
- GeocentricParallax.angle(distance: distance).degrees
196
- )
197
-
198
- Events::ObservationEvents.new(
199
- observer: observer,
200
- date: today,
201
- coordinates_of_the_previous_day: coordinates_of_the_previous_day,
202
- coordinates_of_the_day: coordinates_of_the_day,
203
- coordinates_of_the_next_day: coordinates_of_the_next_day,
204
- additional_altitude: additional_altitude
84
+ def mean_elongation
85
+ @mean_elongation ||= Angle.from_degrees(
86
+ (
87
+ 297.8501921 +
88
+ 445267.1114034 * elapsed_centuries -
89
+ 0.0018819 * elapsed_centuries**2 +
90
+ elapsed_centuries**3 / 545868 -
91
+ elapsed_centuries**4 / 113065000
92
+ ) % 360
205
93
  )
206
94
  end
207
95
 
208
- private
209
-
210
- def terrestrial_time
211
- @terrestrial_time ||= begin
212
- delta = Util::Time.terrestrial_universal_time_delta(@time)
213
- @time + delta
214
- end
215
- end
216
-
217
- def julian_date
218
- Epoch.from_time(terrestrial_time)
219
- end
220
-
221
96
  def elapsed_centuries
222
- (julian_date - Epoch::DEFAULT_EPOCH) / Constants::DAYS_PER_JULIAN_CENTURY
223
- end
224
-
225
- def sun
226
- @sun ||= Sun.new(time: @time)
227
- end
228
-
229
- def sun_mean_anomaly
230
- @sun_mean_anomaly ||= sun.mean_anomaly
231
- end
232
-
233
- def a1
234
- @a1 ||= Angle.from_degrees(
235
- (119.75 + 131.849 * elapsed_centuries) % 360
236
- )
237
- end
238
-
239
- def a2
240
- @a2 ||= Angle.from_degrees(
241
- (53.09 + 479264.290 * elapsed_centuries) % 360
242
- )
243
- end
244
-
245
- def a3
246
- @a3 ||= Angle.from_degrees(
247
- (313.45 + 481266.484 * elapsed_centuries) % 360
248
- )
249
- end
250
-
251
- def eccentricity_correction
252
- @eccentricity_correction ||=
253
- 1 - 0.002516 * elapsed_centuries - 0.0000074 * elapsed_centuries**2
254
- end
255
-
256
- def latitude_terms
257
- @latitude_terms ||=
258
- Astronoby::EphemerideLunaireParisienne
259
- .periodic_terms_for_moon_latitude
260
- .inject(0) do |sum, terms|
261
- value = terms[4] * Math.sin(
262
- terms[0] * mean_elongation.radians +
263
- terms[1] * sun_mean_anomaly.radians +
264
- terms[2] * mean_anomaly.radians +
265
- terms[3] * argument_of_latitude.radians
266
- )
267
-
268
- value *= eccentricity_correction if terms[1].abs == 1
269
- value *= eccentricity_correction**2 if terms[1].abs == 2
270
-
271
- sum + value
272
- end
273
- end
274
-
275
- def additive_latitude_terms
276
- @additive_latitude_terms ||=
277
- -2235 * mean_longitude.sin +
278
- 382 * a3.sin +
279
- 175 * (a1 - argument_of_latitude).sin +
280
- 175 * (a1 + argument_of_latitude).sin +
281
- 127 * (mean_longitude - mean_anomaly).sin -
282
- 115 * (mean_longitude + mean_anomaly).sin
283
- end
284
-
285
- def longitude_terms
286
- @longitude_terms ||=
287
- Astronoby::EphemerideLunaireParisienne
288
- .periodic_terms_for_moon_longitude_and_distance
289
- .inject(0) do |sum, terms|
290
- value = terms[4] * Math.sin(
291
- terms[0] * mean_elongation.radians +
292
- terms[1] * sun_mean_anomaly.radians +
293
- terms[2] * mean_anomaly.radians +
294
- terms[3] * argument_of_latitude.radians
295
- )
296
-
297
- value *= eccentricity_correction if terms[1].abs == 1
298
- value *= eccentricity_correction**2 if terms[1].abs == 2
299
-
300
- sum + value
301
- end
302
- end
303
-
304
- def additive_longitude_terms
305
- @additive_longitude_terms ||=
306
- 3958 * a1.sin +
307
- 1962 * (mean_longitude - argument_of_latitude).sin +
308
- 318 * a2.sin
309
- end
310
-
311
- def distance_terms
312
- @distance_terms ||=
313
- EphemerideLunaireParisienne
314
- .periodic_terms_for_moon_longitude_and_distance
315
- .inject(0) do |sum, terms|
316
- value = terms[5] * Math.cos(
317
- terms[0] * mean_elongation.radians +
318
- terms[1] * sun_mean_anomaly.radians +
319
- terms[2] * mean_anomaly.radians +
320
- terms[3] * argument_of_latitude.radians
321
- )
322
-
323
- value *= eccentricity_correction if terms[1].abs == 1
324
- value *= eccentricity_correction**2 if terms[1].abs == 2
325
-
326
- sum + value
327
- end
328
- end
329
-
330
- def nutation
331
- @nutation ||=
332
- Astronoby::Nutation.for_ecliptic_longitude(epoch: julian_date)
97
+ (@instant.tt - Epoch::DEFAULT_EPOCH) / Constants::DAYS_PER_JULIAN_CENTURY
333
98
  end
334
99
  end
335
100
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Astronoby
4
+ class Neptune < SolarSystemBody
5
+ EQUATORIAL_RADIUS = Distance.from_meters(24_764_000)
6
+
7
+ def self.ephemeris_segments(_ephem_source)
8
+ [[SOLAR_SYSTEM_BARYCENTER, NEPTUNE_BARYCENTER]]
9
+ end
10
+ end
11
+ end