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
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Astronoby
|
4
|
+
class RiseTransitSetEvent
|
5
|
+
attr_reader :rising_time, :transit_time, :setting_time
|
6
|
+
|
7
|
+
def initialize(rising, transit, setting)
|
8
|
+
@rising_time = rising
|
9
|
+
@transit_time = transit
|
10
|
+
@setting_time = setting
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Astronoby
|
4
|
+
class RiseTransitSetEvents
|
5
|
+
attr_reader :rising_times, :transit_times, :setting_times
|
6
|
+
|
7
|
+
def initialize(risings, transits, settings)
|
8
|
+
@rising_times = risings
|
9
|
+
@transit_times = transits
|
10
|
+
@setting_times = settings
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Astronoby
|
4
|
+
class TwilightCalculator
|
5
|
+
TWILIGHTS = [
|
6
|
+
CIVIL = :civil,
|
7
|
+
NAUTICAL = :nautical,
|
8
|
+
ASTRONOMICAL = :astronomical
|
9
|
+
].freeze
|
10
|
+
|
11
|
+
TWILIGHT_ANGLES = {
|
12
|
+
CIVIL => Angle.from_degrees(96),
|
13
|
+
NAUTICAL => Angle.from_degrees(102),
|
14
|
+
ASTRONOMICAL => Angle.from_degrees(108)
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
PERIODS_OF_THE_DAY = [
|
18
|
+
MORNING = :morning,
|
19
|
+
EVENING = :evening
|
20
|
+
].freeze
|
21
|
+
|
22
|
+
def initialize(observer:, ephem:)
|
23
|
+
@observer = observer
|
24
|
+
@ephem = ephem
|
25
|
+
end
|
26
|
+
|
27
|
+
def event_on(date)
|
28
|
+
observation_events = get_observation_events(date)
|
29
|
+
midday_instant = create_midday_instant(date)
|
30
|
+
sun_at_midday = Sun.new(instant: midday_instant, ephem: @ephem)
|
31
|
+
equatorial_coordinates = sun_at_midday.apparent.equatorial
|
32
|
+
|
33
|
+
morning_civil = compute_twilight_time(
|
34
|
+
MORNING,
|
35
|
+
TWILIGHT_ANGLES[CIVIL],
|
36
|
+
observation_events,
|
37
|
+
equatorial_coordinates
|
38
|
+
)
|
39
|
+
|
40
|
+
evening_civil = compute_twilight_time(
|
41
|
+
EVENING,
|
42
|
+
TWILIGHT_ANGLES[CIVIL],
|
43
|
+
observation_events,
|
44
|
+
equatorial_coordinates
|
45
|
+
)
|
46
|
+
|
47
|
+
morning_nautical = compute_twilight_time(
|
48
|
+
MORNING,
|
49
|
+
TWILIGHT_ANGLES[NAUTICAL],
|
50
|
+
observation_events,
|
51
|
+
equatorial_coordinates
|
52
|
+
)
|
53
|
+
|
54
|
+
evening_nautical = compute_twilight_time(
|
55
|
+
EVENING,
|
56
|
+
TWILIGHT_ANGLES[NAUTICAL],
|
57
|
+
observation_events,
|
58
|
+
equatorial_coordinates
|
59
|
+
)
|
60
|
+
|
61
|
+
morning_astronomical = compute_twilight_time(
|
62
|
+
MORNING,
|
63
|
+
TWILIGHT_ANGLES[ASTRONOMICAL],
|
64
|
+
observation_events,
|
65
|
+
equatorial_coordinates
|
66
|
+
)
|
67
|
+
|
68
|
+
evening_astronomical = compute_twilight_time(
|
69
|
+
EVENING,
|
70
|
+
TWILIGHT_ANGLES[ASTRONOMICAL],
|
71
|
+
observation_events,
|
72
|
+
equatorial_coordinates
|
73
|
+
)
|
74
|
+
|
75
|
+
TwilightEvent.new(
|
76
|
+
morning_civil_twilight_time: morning_civil,
|
77
|
+
evening_civil_twilight_time: evening_civil,
|
78
|
+
morning_nautical_twilight_time: morning_nautical,
|
79
|
+
evening_nautical_twilight_time: evening_nautical,
|
80
|
+
morning_astronomical_twilight_time: morning_astronomical,
|
81
|
+
evening_astronomical_twilight_time: evening_astronomical
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def time_for_zenith_angle(date:, period_of_the_day:, zenith_angle:)
|
86
|
+
unless PERIODS_OF_THE_DAY.include?(period_of_the_day)
|
87
|
+
raise IncompatibleArgumentsError,
|
88
|
+
"Only #{PERIODS_OF_THE_DAY.join(" or ")} are allowed as period_of_the_day, got #{period_of_the_day}"
|
89
|
+
end
|
90
|
+
|
91
|
+
observation_events = get_observation_events(date)
|
92
|
+
midday_instant = create_midday_instant(date)
|
93
|
+
sun_at_midday = Sun.new(instant: midday_instant, ephem: @ephem)
|
94
|
+
equatorial_coordinates = sun_at_midday.apparent.equatorial
|
95
|
+
|
96
|
+
compute_twilight_time(
|
97
|
+
period_of_the_day,
|
98
|
+
zenith_angle,
|
99
|
+
observation_events,
|
100
|
+
equatorial_coordinates
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def create_midday_instant(date)
|
107
|
+
time = Time.utc(date.year, date.month, date.day, 12)
|
108
|
+
Instant.from_time(time)
|
109
|
+
end
|
110
|
+
|
111
|
+
def get_observation_events(date)
|
112
|
+
Astronoby::RiseTransitSetCalculator.new(
|
113
|
+
body: Sun,
|
114
|
+
observer: @observer,
|
115
|
+
ephem: @ephem
|
116
|
+
).event_on(date)
|
117
|
+
end
|
118
|
+
|
119
|
+
def compute_twilight_time(
|
120
|
+
period_of_the_day,
|
121
|
+
zenith_angle,
|
122
|
+
observation_events,
|
123
|
+
equatorial_coordinates
|
124
|
+
)
|
125
|
+
period_time = if period_of_the_day == MORNING
|
126
|
+
observation_events.rising_time
|
127
|
+
else
|
128
|
+
observation_events.setting_time
|
129
|
+
end
|
130
|
+
|
131
|
+
# If the sun doesn't rise or set on this day, we can't calculate
|
132
|
+
# twilight
|
133
|
+
return nil unless period_time
|
134
|
+
|
135
|
+
hour_angle_at_period = equatorial_coordinates
|
136
|
+
.compute_hour_angle(time: period_time, longitude: @observer.longitude)
|
137
|
+
|
138
|
+
term1 = zenith_angle.cos -
|
139
|
+
@observer.latitude.sin * equatorial_coordinates.declination.sin
|
140
|
+
term2 = @observer.latitude.cos * equatorial_coordinates.declination.cos
|
141
|
+
hour_angle_ratio_at_twilight = term1 / term2
|
142
|
+
|
143
|
+
# Check if twilight occurs at this location and date
|
144
|
+
return nil unless hour_angle_ratio_at_twilight.between?(-1, 1)
|
145
|
+
|
146
|
+
hour_angle_at_twilight = Angle.acos(hour_angle_ratio_at_twilight)
|
147
|
+
time_sign = -1
|
148
|
+
|
149
|
+
if period_of_the_day == MORNING
|
150
|
+
hour_angle_at_twilight = Angle.from_degrees(
|
151
|
+
Constants::DEGREES_PER_CIRCLE - hour_angle_at_twilight.degrees
|
152
|
+
)
|
153
|
+
time_sign = 1
|
154
|
+
end
|
155
|
+
|
156
|
+
twilight_in_hours =
|
157
|
+
time_sign * (hour_angle_at_twilight - hour_angle_at_period).hours *
|
158
|
+
GreenwichSiderealTime::SIDEREAL_MINUTE_IN_UT_MINUTE
|
159
|
+
twilight_in_seconds = time_sign *
|
160
|
+
twilight_in_hours *
|
161
|
+
Constants::SECONDS_PER_HOUR
|
162
|
+
|
163
|
+
(period_time + twilight_in_seconds).round
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Astronoby
|
4
|
+
class TwilightEvent
|
5
|
+
attr_reader :morning_civil_twilight_time,
|
6
|
+
:evening_civil_twilight_time,
|
7
|
+
:morning_nautical_twilight_time,
|
8
|
+
:evening_nautical_twilight_time,
|
9
|
+
:morning_astronomical_twilight_time,
|
10
|
+
:evening_astronomical_twilight_time
|
11
|
+
|
12
|
+
def initialize(
|
13
|
+
morning_civil_twilight_time: nil,
|
14
|
+
evening_civil_twilight_time: nil,
|
15
|
+
morning_nautical_twilight_time: nil,
|
16
|
+
evening_nautical_twilight_time: nil,
|
17
|
+
morning_astronomical_twilight_time: nil,
|
18
|
+
evening_astronomical_twilight_time: nil
|
19
|
+
)
|
20
|
+
@morning_civil_twilight_time = morning_civil_twilight_time
|
21
|
+
@evening_civil_twilight_time = evening_civil_twilight_time
|
22
|
+
@morning_nautical_twilight_time = morning_nautical_twilight_time
|
23
|
+
@evening_nautical_twilight_time = evening_nautical_twilight_time
|
24
|
+
@morning_astronomical_twilight_time = morning_astronomical_twilight_time
|
25
|
+
@evening_astronomical_twilight_time = evening_astronomical_twilight_time
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
|
5
|
+
module Astronoby
|
6
|
+
# Represents a specific instant in time using Terrestrial Time (TT) as its
|
7
|
+
# internal representation. This class provides conversions between different
|
8
|
+
# time scales commonly used in astronomy:
|
9
|
+
# - Terrestrial Time (TT)
|
10
|
+
# - International Atomic Time (TAI)
|
11
|
+
# - Universal Time Coordinated (UTC)
|
12
|
+
# - Greenwich Mean Sidereal Time (GMST)
|
13
|
+
#
|
14
|
+
# @example Create an instant from the current time
|
15
|
+
# instant = Astronoby::Instant.from_time(Time.now)
|
16
|
+
# instant.tai # Get International Atomic Time
|
17
|
+
#
|
18
|
+
# @example Create an instant from Terrestrial Time
|
19
|
+
# instant = Astronoby::Instant.from_terrestrial_time(2460000.5)
|
20
|
+
#
|
21
|
+
class Instant
|
22
|
+
include Comparable
|
23
|
+
|
24
|
+
JULIAN_DAY_NUMBER_OFFSET = 0.5
|
25
|
+
|
26
|
+
class << self
|
27
|
+
# Creates a new Instant from a Terrestrial Time value
|
28
|
+
#
|
29
|
+
# @param terrestrial_time [Numeric] the Terrestrial Time as a Julian Date
|
30
|
+
# @return [Astronoby::Instant] a new Instant object
|
31
|
+
# @raise [Astronoby::UnsupportedFormatError] if terrestrial_time is not
|
32
|
+
# numeric
|
33
|
+
def from_terrestrial_time(terrestrial_time)
|
34
|
+
new(terrestrial_time)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Creates a new Instant from a Time object
|
38
|
+
#
|
39
|
+
# @param time [Time] a Time object to convert
|
40
|
+
# @return [Astronoby::Instant] a new Instant object
|
41
|
+
def from_time(time)
|
42
|
+
delta_t = Util::Time.terrestrial_universal_time_delta(time)
|
43
|
+
terrestrial_time = time.utc.to_datetime.ajd +
|
44
|
+
Rational(delta_t, Constants::SECONDS_PER_DAY)
|
45
|
+
from_terrestrial_time(terrestrial_time)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Creates a new Instant from a Julian Date in UTC
|
49
|
+
#
|
50
|
+
# @param julian_date [Numeric] the Julian Date in UTC
|
51
|
+
# @return [Astronoby::Instant] a new Instant object
|
52
|
+
def from_utc_julian_date(julian_date)
|
53
|
+
delta_t = Util::Time.terrestrial_universal_time_delta(julian_date)
|
54
|
+
terrestrial_time = julian_date +
|
55
|
+
Rational(delta_t, Constants::SECONDS_PER_DAY)
|
56
|
+
from_terrestrial_time(terrestrial_time)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_reader :terrestrial_time
|
61
|
+
alias_method :tt, :terrestrial_time
|
62
|
+
alias_method :julian_date, :terrestrial_time
|
63
|
+
|
64
|
+
# Initialize a new Instant
|
65
|
+
#
|
66
|
+
# @param terrestrial_time [Numeric] the Terrestrial Time as Julian Date
|
67
|
+
# @raise [Astronoby::UnsupportedFormatError] if terrestrial_time is not
|
68
|
+
# numeric
|
69
|
+
def initialize(terrestrial_time)
|
70
|
+
unless terrestrial_time.is_a?(Numeric)
|
71
|
+
raise UnsupportedFormatError, "terrestrial_time must be a Numeric"
|
72
|
+
end
|
73
|
+
|
74
|
+
@terrestrial_time = terrestrial_time
|
75
|
+
freeze
|
76
|
+
end
|
77
|
+
|
78
|
+
# Calculate the time difference between two Instant objects
|
79
|
+
#
|
80
|
+
# @param other [Astronoby::Instant] another Instant to compare with
|
81
|
+
# @return [Numeric] the difference in days
|
82
|
+
def diff(other)
|
83
|
+
@terrestrial_time - other.terrestrial_time
|
84
|
+
end
|
85
|
+
|
86
|
+
# Convert to DateTime (UTC)
|
87
|
+
#
|
88
|
+
# @return [DateTime] the UTC time as DateTime
|
89
|
+
def to_datetime
|
90
|
+
DateTime.jd(
|
91
|
+
@terrestrial_time -
|
92
|
+
Rational(delta_t / Constants::SECONDS_PER_DAY) +
|
93
|
+
JULIAN_DAY_NUMBER_OFFSET
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Convert to Date (UTC)
|
98
|
+
#
|
99
|
+
# @return [Date] the UTC date
|
100
|
+
def to_date
|
101
|
+
to_datetime.to_date
|
102
|
+
end
|
103
|
+
|
104
|
+
# Convert to Time (UTC)
|
105
|
+
#
|
106
|
+
# @return [Time] the UTC time
|
107
|
+
def to_time
|
108
|
+
to_datetime.to_time.utc
|
109
|
+
end
|
110
|
+
|
111
|
+
# Get the ΔT (Delta T) value for this instant
|
112
|
+
# ΔT is the difference between TT and UT1
|
113
|
+
#
|
114
|
+
# @return [Numeric] Delta T in seconds
|
115
|
+
def delta_t
|
116
|
+
Util::Time.terrestrial_universal_time_delta(@terrestrial_time)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Get the Greenwich Mean Sidereal Time
|
120
|
+
#
|
121
|
+
# @return [Numeric] the sidereal time in radians
|
122
|
+
def gmst
|
123
|
+
GreenwichSiderealTime.from_utc(to_time).time
|
124
|
+
end
|
125
|
+
|
126
|
+
# Get the International Atomic Time (TAI)
|
127
|
+
#
|
128
|
+
# @return [Numeric] TAI as Julian Date
|
129
|
+
def tai
|
130
|
+
@terrestrial_time -
|
131
|
+
Rational(Constants::TAI_TT_OFFSET, Constants::SECONDS_PER_DAY)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Get the Barycentric Dynamical Time (TDB)
|
135
|
+
# Note: Currently approximated as equal to TT
|
136
|
+
#
|
137
|
+
# @return [Numeric] TDB as Julian Date
|
138
|
+
def tdb
|
139
|
+
# This is technically false, there is a slight difference between TT and
|
140
|
+
# TDB. However, this difference is so small that currenly Astronoby
|
141
|
+
# doesn't support it and consider they are the same value.
|
142
|
+
@terrestrial_time
|
143
|
+
end
|
144
|
+
|
145
|
+
# Get the offset between TT and UTC for this instant
|
146
|
+
#
|
147
|
+
# @return [Numeric] the offset in days
|
148
|
+
def utc_offset
|
149
|
+
@terrestrial_time - to_time.utc.to_datetime.ajd
|
150
|
+
end
|
151
|
+
|
152
|
+
# Calculate hash value for the instant
|
153
|
+
#
|
154
|
+
# @return [Integer] hash value
|
155
|
+
def hash
|
156
|
+
[@terrestrial_time, self.class].hash
|
157
|
+
end
|
158
|
+
|
159
|
+
# Compare this instant with another
|
160
|
+
#
|
161
|
+
# @param other [Astronoby::Instant] another instant to compare with
|
162
|
+
# @return [Integer, nil] -1, 0, 1 for less than, equal to, greater than;
|
163
|
+
# nil if other is not an Instant
|
164
|
+
def <=>(other)
|
165
|
+
return unless other.is_a?(self.class)
|
166
|
+
|
167
|
+
@terrestrial_time <=> other.terrestrial_time
|
168
|
+
end
|
169
|
+
alias_method :eql?, :==
|
170
|
+
end
|
171
|
+
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
# TODO: This needs to be improved by receiving an instant instead of an Epoch
|
4
|
+
# as these coefficients work with TT (Terrestrial Time).
|
4
5
|
|
5
6
|
module Astronoby
|
6
7
|
class MeanObliquity
|
7
8
|
# Source:
|
8
9
|
# IAU resolution in 2006 in favor of the P03 astronomical model
|
9
|
-
#
|
10
|
+
# https://syrte.obspm.fr/iau2006/aa03_412_P03.pdf
|
10
11
|
|
11
12
|
EPOCH_OF_REFERENCE = Epoch::DEFAULT_EPOCH
|
12
13
|
OBLIQUITY_OF_REFERENCE = 23.4392794
|
@@ -14,19 +15,31 @@ module Astronoby
|
|
14
15
|
def self.for_epoch(epoch)
|
15
16
|
return obliquity_of_reference if epoch == EPOCH_OF_REFERENCE
|
16
17
|
|
17
|
-
t = (
|
18
|
+
t = Rational(
|
19
|
+
(epoch - EPOCH_OF_REFERENCE),
|
20
|
+
Constants::DAYS_PER_JULIAN_CENTURY
|
21
|
+
)
|
22
|
+
|
23
|
+
epsilon0 = obliquity_of_reference_in_milliarcseconds
|
24
|
+
c1 = -46.836769
|
25
|
+
c2 = -0.0001831
|
26
|
+
c3 = 0.00200340
|
27
|
+
c4 = -0.000000576
|
28
|
+
c5 = -0.0000000434
|
18
29
|
|
19
|
-
Angle.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
0.00181 * t * t * t
|
24
|
-
) / Constants::SECONDS_PER_DEGREE
|
30
|
+
Angle.from_dms(
|
31
|
+
0,
|
32
|
+
0,
|
33
|
+
epsilon0 + t * (c1 + t * (c2 + t * (c3 + t * (c4 + t * c5))))
|
25
34
|
)
|
26
35
|
end
|
27
36
|
|
28
37
|
def self.obliquity_of_reference
|
29
|
-
Angle.from_dms(
|
38
|
+
Angle.from_dms(0, 0, obliquity_of_reference_in_milliarcseconds)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.obliquity_of_reference_in_milliarcseconds
|
42
|
+
84381.406
|
30
43
|
end
|
31
44
|
end
|
32
45
|
end
|