astronoby 0.7.0 → 0.9.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 +145 -3
- data/README.md +59 -33
- data/UPGRADING.md +75 -21
- data/docs/README.md +224 -0
- data/docs/angles.md +137 -0
- data/docs/configuration.md +98 -0
- data/docs/coordinates.md +167 -0
- data/docs/deep_sky_bodies.md +101 -0
- data/docs/ephem.md +85 -0
- data/docs/equinoxes_solstices_times.md +31 -0
- data/docs/glossary.md +152 -0
- data/docs/instant.md +139 -0
- data/docs/moon_phases.md +79 -0
- data/docs/observer.md +65 -0
- data/docs/reference_frames.md +138 -0
- data/docs/rise_transit_set_times.md +119 -0
- data/docs/solar_system_bodies.md +107 -0
- data/docs/twilight_times.md +123 -0
- data/lib/astronoby/angle.rb +6 -2
- data/lib/astronoby/angular_velocity.rb +76 -0
- data/lib/astronoby/bodies/deep_sky_object.rb +44 -0
- data/lib/astronoby/bodies/deep_sky_object_position.rb +127 -0
- data/lib/astronoby/bodies/earth.rb +12 -2
- data/lib/astronoby/bodies/jupiter.rb +17 -0
- data/lib/astronoby/bodies/mars.rb +17 -0
- data/lib/astronoby/bodies/mercury.rb +21 -0
- data/lib/astronoby/bodies/moon.rb +50 -36
- data/lib/astronoby/bodies/neptune.rb +21 -0
- data/lib/astronoby/bodies/saturn.rb +26 -0
- data/lib/astronoby/bodies/solar_system_body.rb +162 -27
- data/lib/astronoby/bodies/sun.rb +25 -2
- data/lib/astronoby/bodies/uranus.rb +5 -0
- data/lib/astronoby/bodies/venus.rb +25 -0
- data/lib/astronoby/cache.rb +189 -0
- data/lib/astronoby/configuration.rb +92 -0
- data/lib/astronoby/constants.rb +11 -3
- data/lib/astronoby/constellation.rb +12 -0
- data/lib/astronoby/constellations/data.rb +42 -0
- data/lib/astronoby/constellations/finder.rb +35 -0
- data/lib/astronoby/constellations/repository.rb +20 -0
- data/lib/astronoby/coordinates/equatorial.rb +5 -8
- data/lib/astronoby/data/constellations/constellation_names.dat +88 -0
- data/lib/astronoby/data/constellations/indexed_abbreviations.dat +88 -0
- data/lib/astronoby/data/constellations/radec_to_index.dat +238 -0
- data/lib/astronoby/data/constellations/sorted_declinations.dat +202 -0
- data/lib/astronoby/data/constellations/sorted_right_ascensions.dat +237 -0
- data/lib/astronoby/distance.rb +6 -0
- data/lib/astronoby/equinox_solstice.rb +2 -2
- data/lib/astronoby/events/extremum_calculator.rb +233 -0
- data/lib/astronoby/events/extremum_event.rb +15 -0
- data/lib/astronoby/events/moon_phases.rb +15 -14
- data/lib/astronoby/events/rise_transit_set_calculator.rb +39 -12
- data/lib/astronoby/events/twilight_calculator.rb +116 -61
- data/lib/astronoby/events/twilight_events.rb +28 -0
- data/lib/astronoby/instant.rb +34 -6
- data/lib/astronoby/julian_date.rb +78 -0
- data/lib/astronoby/mean_obliquity.rb +8 -10
- data/lib/astronoby/nutation.rb +11 -3
- data/lib/astronoby/observer.rb +1 -1
- data/lib/astronoby/precession.rb +48 -38
- data/lib/astronoby/reference_frame.rb +2 -1
- data/lib/astronoby/reference_frames/apparent.rb +1 -11
- data/lib/astronoby/reference_frames/mean_of_date.rb +1 -1
- data/lib/astronoby/reference_frames/topocentric.rb +2 -12
- data/lib/astronoby/stellar_propagation.rb +162 -0
- data/lib/astronoby/time/greenwich_apparent_sidereal_time.rb +22 -0
- data/lib/astronoby/time/greenwich_mean_sidereal_time.rb +64 -0
- data/lib/astronoby/time/greenwich_sidereal_time.rb +20 -58
- data/lib/astronoby/time/local_apparent_sidereal_time.rb +42 -0
- data/lib/astronoby/time/local_mean_sidereal_time.rb +42 -0
- data/lib/astronoby/time/local_sidereal_time.rb +35 -26
- data/lib/astronoby/time/sidereal_time.rb +42 -0
- data/lib/astronoby/true_obliquity.rb +2 -3
- data/lib/astronoby/util/time.rb +62 -44
- data/lib/astronoby/velocity.rb +5 -0
- data/lib/astronoby/version.rb +1 -1
- data/lib/astronoby.rb +19 -1
- metadata +71 -11
- data/Gemfile +0 -5
- data/Gemfile.lock +0 -102
- data/benchmark/README.md +0 -131
- data/benchmark/benchmark.rb +0 -259
- data/benchmark/data/imcce.csv.zip +0 -0
- data/benchmark/data/sun_calc.csv.zip +0 -0
- data/lib/astronoby/epoch.rb +0 -22
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Astronoby
|
|
4
|
+
class DeepSkyObjectPosition
|
|
5
|
+
DEFAULT_DISTANCE = Distance.from_parsecs(1e9)
|
|
6
|
+
|
|
7
|
+
attr_reader :instant, :apparent
|
|
8
|
+
|
|
9
|
+
# @param instant [Astronoby::Instant] Instant of the observation
|
|
10
|
+
# @param equatorial_coordinates [Astronoby::Coordinates::Equatorial]
|
|
11
|
+
# Equatorial coordinates at epoch J2000.0
|
|
12
|
+
# @param proper_motion_ra [Astronoby::AngularVelocity, nil] Proper motion in
|
|
13
|
+
# right ascension
|
|
14
|
+
# @param proper_motion_dec [Astronoby::AngularVelocity, nil] Proper motion
|
|
15
|
+
# in declination
|
|
16
|
+
# @param parallax [Astronoby::Angle, nil] Parallax angle
|
|
17
|
+
# @param radial_velocity [Astronoby::Velocity, nil] Radial velocity
|
|
18
|
+
def initialize(
|
|
19
|
+
instant:,
|
|
20
|
+
equatorial_coordinates:,
|
|
21
|
+
ephem: nil,
|
|
22
|
+
proper_motion_ra: nil,
|
|
23
|
+
proper_motion_dec: nil,
|
|
24
|
+
parallax: nil,
|
|
25
|
+
radial_velocity: nil
|
|
26
|
+
)
|
|
27
|
+
@instant = instant
|
|
28
|
+
@initial_equatorial_coordinates = equatorial_coordinates
|
|
29
|
+
@proper_motion_ra = proper_motion_ra
|
|
30
|
+
@proper_motion_dec = proper_motion_dec
|
|
31
|
+
@parallax = parallax
|
|
32
|
+
@radial_velocity = radial_velocity
|
|
33
|
+
if ephem
|
|
34
|
+
@earth_geometric = Earth.geometric(ephem: ephem, instant: @instant)
|
|
35
|
+
end
|
|
36
|
+
compute_apparent
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @return [Astronoby::Astrometric] Astrometric position of the object
|
|
40
|
+
def astrometric
|
|
41
|
+
@astrometric ||= Astrometric.new(
|
|
42
|
+
instant: @instant,
|
|
43
|
+
position: astrometric_position,
|
|
44
|
+
velocity: astrometric_velocity,
|
|
45
|
+
center_identifier: SolarSystemBody::EARTH,
|
|
46
|
+
target_body: self
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def observed_by(observer)
|
|
51
|
+
Topocentric.build_from_apparent(
|
|
52
|
+
apparent: @apparent,
|
|
53
|
+
observer: observer,
|
|
54
|
+
instant: @instant,
|
|
55
|
+
target_body: self
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def astrometric_position
|
|
62
|
+
@astrometric_position ||= if use_stellar_propagation?
|
|
63
|
+
stellar_propagation.position
|
|
64
|
+
else
|
|
65
|
+
astronomical_distance = DEFAULT_DISTANCE.meters
|
|
66
|
+
right_ascension = @initial_equatorial_coordinates.right_ascension
|
|
67
|
+
declination = @initial_equatorial_coordinates.declination
|
|
68
|
+
Distance.vector_from_meters([
|
|
69
|
+
declination.cos * right_ascension.cos * astronomical_distance,
|
|
70
|
+
declination.cos * right_ascension.sin * astronomical_distance,
|
|
71
|
+
declination.sin * astronomical_distance
|
|
72
|
+
])
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def astrometric_velocity
|
|
77
|
+
@astrometric_velocity ||= if use_stellar_propagation?
|
|
78
|
+
stellar_propagation.velocity_vector
|
|
79
|
+
else
|
|
80
|
+
Velocity.vector_from_meters_per_second([0.0, 0.0, 0.0])
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def use_stellar_propagation?
|
|
85
|
+
@proper_motion_ra && @proper_motion_dec && @parallax && @radial_velocity
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def stellar_propagation
|
|
89
|
+
@stellar_propagation ||= StellarPropagation.new(
|
|
90
|
+
equatorial_coordinates: @initial_equatorial_coordinates,
|
|
91
|
+
proper_motion_ra: @proper_motion_ra,
|
|
92
|
+
proper_motion_dec: @proper_motion_dec,
|
|
93
|
+
parallax: @parallax,
|
|
94
|
+
radial_velocity: @radial_velocity,
|
|
95
|
+
instant: @instant,
|
|
96
|
+
earth_geometric: @earth_geometric
|
|
97
|
+
)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def compute_apparent
|
|
101
|
+
@apparent = if @earth_geometric
|
|
102
|
+
Apparent.build_from_astrometric(
|
|
103
|
+
instant: @instant,
|
|
104
|
+
target_astrometric: astrometric,
|
|
105
|
+
earth_geometric: @earth_geometric,
|
|
106
|
+
target_body: self
|
|
107
|
+
)
|
|
108
|
+
else
|
|
109
|
+
precession_matrix = Precession.matrix_for(@instant)
|
|
110
|
+
nutation_matrix = Nutation.matrix_for(@instant)
|
|
111
|
+
corrected_position = Distance.vector_from_meters(
|
|
112
|
+
precession_matrix * nutation_matrix * astrometric.position.map(&:m)
|
|
113
|
+
)
|
|
114
|
+
corrected_velocity = Velocity.vector_from_mps(
|
|
115
|
+
precession_matrix * nutation_matrix * astrometric.velocity.map(&:mps)
|
|
116
|
+
)
|
|
117
|
+
Apparent.new(
|
|
118
|
+
position: corrected_position,
|
|
119
|
+
velocity: corrected_velocity,
|
|
120
|
+
instant: @instant,
|
|
121
|
+
center_identifier: SolarSystemBody::EARTH,
|
|
122
|
+
target_body: self
|
|
123
|
+
)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -15,9 +15,19 @@ module Astronoby
|
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
def phase_angle
|
|
19
|
+
nil
|
|
20
|
+
end
|
|
21
|
+
|
|
18
22
|
private
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
# Attributes that require Sun data like phase angle or magnitude are not
|
|
25
|
+
# applicable for Earth.
|
|
26
|
+
def requires_sun_data?
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def compute_astrometric(_ephem)
|
|
21
31
|
Astrometric.new(
|
|
22
32
|
position: Vector[
|
|
23
33
|
Distance.zero,
|
|
@@ -35,7 +45,7 @@ module Astronoby
|
|
|
35
45
|
)
|
|
36
46
|
end
|
|
37
47
|
|
|
38
|
-
def compute_mean_of_date(
|
|
48
|
+
def compute_mean_of_date(_ephem)
|
|
39
49
|
MeanOfDate.new(
|
|
40
50
|
position: Vector[
|
|
41
51
|
Distance.zero,
|
|
@@ -3,9 +3,26 @@
|
|
|
3
3
|
module Astronoby
|
|
4
4
|
class Jupiter < SolarSystemBody
|
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(71_492_000)
|
|
6
|
+
ABSOLUTE_MAGNITUDE = -9.395
|
|
6
7
|
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, JUPITER_BARYCENTER]]
|
|
9
10
|
end
|
|
11
|
+
|
|
12
|
+
def self.absolute_magnitude
|
|
13
|
+
ABSOLUTE_MAGNITUDE
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Source:
|
|
19
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
|
20
|
+
# Almanac (2018)
|
|
21
|
+
# Authors: Anthony Mallama and James L. Hilton
|
|
22
|
+
def magnitude_correction_term
|
|
23
|
+
phase_angle_degrees = phase_angle.degrees
|
|
24
|
+
-3.7 * 10**-4 * phase_angle_degrees +
|
|
25
|
+
6.16 * 10**-4 * phase_angle_degrees * phase_angle_degrees
|
|
26
|
+
end
|
|
10
27
|
end
|
|
11
28
|
end
|
|
@@ -3,9 +3,26 @@
|
|
|
3
3
|
module Astronoby
|
|
4
4
|
class Mars < SolarSystemBody
|
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(3_396_200)
|
|
6
|
+
ABSOLUTE_MAGNITUDE = -1.601
|
|
6
7
|
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, MARS_BARYCENTER]]
|
|
9
10
|
end
|
|
11
|
+
|
|
12
|
+
def self.absolute_magnitude
|
|
13
|
+
ABSOLUTE_MAGNITUDE
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Source:
|
|
19
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
|
20
|
+
# Almanac (2018)
|
|
21
|
+
# Authors: Anthony Mallama and James L. Hilton
|
|
22
|
+
def magnitude_correction_term
|
|
23
|
+
phase_angle_degrees = phase_angle.degrees
|
|
24
|
+
2.267 * 10**-2 * phase_angle_degrees -
|
|
25
|
+
1.302 * 10**-4 * phase_angle_degrees * phase_angle_degrees
|
|
26
|
+
end
|
|
10
27
|
end
|
|
11
28
|
end
|
|
@@ -3,9 +3,30 @@
|
|
|
3
3
|
module Astronoby
|
|
4
4
|
class Mercury < SolarSystemBody
|
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(2_439_700)
|
|
6
|
+
ABSOLUTE_MAGNITUDE = -0.613
|
|
6
7
|
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, MERCURY_BARYCENTER]]
|
|
9
10
|
end
|
|
11
|
+
|
|
12
|
+
def self.absolute_magnitude
|
|
13
|
+
ABSOLUTE_MAGNITUDE
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Source:
|
|
19
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
|
20
|
+
# Almanac (2018)
|
|
21
|
+
# Authors: Anthony Mallama and James L. Hilton
|
|
22
|
+
def magnitude_correction_term
|
|
23
|
+
phase_angle_degrees = phase_angle.degrees
|
|
24
|
+
6.328 * 10**-2 * phase_angle_degrees -
|
|
25
|
+
1.6336 * 10**-3 * phase_angle_degrees * phase_angle_degrees +
|
|
26
|
+
3.3634 * 10**-5 * phase_angle_degrees**3 -
|
|
27
|
+
3.4265 * 10**-7 * phase_angle_degrees**4 +
|
|
28
|
+
1.6893 * 10**-9 * phase_angle_degrees**5 -
|
|
29
|
+
3.0334 * 10**-12 * phase_angle_degrees**6
|
|
30
|
+
end
|
|
10
31
|
end
|
|
11
32
|
end
|
|
@@ -4,6 +4,7 @@ module Astronoby
|
|
|
4
4
|
class Moon < SolarSystemBody
|
|
5
5
|
SEMIDIAMETER_VARIATION = 0.7275
|
|
6
6
|
EQUATORIAL_RADIUS = Distance.from_meters(1_737_400)
|
|
7
|
+
ABSOLUTE_MAGNITUDE = 0.28
|
|
7
8
|
|
|
8
9
|
def self.ephemeris_segments(ephem_source)
|
|
9
10
|
if ephem_source == ::Ephem::SPK::JPL_DE
|
|
@@ -32,16 +33,8 @@ module Astronoby
|
|
|
32
33
|
Events::MoonPhases.phases_for(year: year, month: month)
|
|
33
34
|
end
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def initialize(instant:, ephem:)
|
|
38
|
-
super
|
|
39
|
-
@phase_angle = compute_phase_angle(ephem)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# @return [Float] Moon's illuminated fraction
|
|
43
|
-
def illuminated_fraction
|
|
44
|
-
@illuminated_fraction ||= (1 + phase_angle.cos) / 2.0
|
|
36
|
+
def self.absolute_magnitude
|
|
37
|
+
ABSOLUTE_MAGNITUDE
|
|
45
38
|
end
|
|
46
39
|
|
|
47
40
|
# @return [Float] Phase fraction, from 0 to 1
|
|
@@ -49,6 +42,27 @@ module Astronoby
|
|
|
49
42
|
mean_elongation.degrees / Constants::DEGREES_PER_CIRCLE
|
|
50
43
|
end
|
|
51
44
|
|
|
45
|
+
# @return [Boolean] True if the body is approaching the primary
|
|
46
|
+
# body (Earth), false otherwise.
|
|
47
|
+
def approaching_primary?
|
|
48
|
+
relative_position =
|
|
49
|
+
(geometric.position - @earth_geometric.position).map(&:m)
|
|
50
|
+
relative_velocity =
|
|
51
|
+
(geometric.velocity - @earth_geometric.velocity).map(&:mps)
|
|
52
|
+
radial_velocity_component = Astronoby::Util::Maths
|
|
53
|
+
.dot_product(relative_position, relative_velocity)
|
|
54
|
+
distance = Math.sqrt(
|
|
55
|
+
Astronoby::Util::Maths.dot_product(relative_position, relative_position)
|
|
56
|
+
)
|
|
57
|
+
radial_velocity_component / distance < 0
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [Boolean] True if the body is receding from the primary
|
|
61
|
+
# body (Earth), false otherwise.
|
|
62
|
+
def receding_from_primary?
|
|
63
|
+
!approaching_primary?
|
|
64
|
+
end
|
|
65
|
+
|
|
52
66
|
private
|
|
53
67
|
|
|
54
68
|
# Source:
|
|
@@ -56,31 +70,6 @@ module Astronoby
|
|
|
56
70
|
# Author: Jean Meeus
|
|
57
71
|
# Edition: 2nd edition
|
|
58
72
|
# Chapter: 48 - Illuminated Fraction of the Moon's Disk
|
|
59
|
-
|
|
60
|
-
# @return [Angle] Moon's phase angle
|
|
61
|
-
def compute_phase_angle(ephem)
|
|
62
|
-
@phase_angle ||= begin
|
|
63
|
-
sun = Sun.new(instant: @instant, ephem: ephem)
|
|
64
|
-
geocentric_elongation = Angle.acos(
|
|
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
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
term1 = sun.astrometric.distance.km * geocentric_elongation.sin
|
|
76
|
-
term2 = astrometric.distance.km -
|
|
77
|
-
sun.astrometric.distance.km * geocentric_elongation.cos
|
|
78
|
-
angle = Angle.atan(term1 / term2)
|
|
79
|
-
Astronoby::Util::Trigonometry
|
|
80
|
-
.adjustement_for_arctangent(term1, term2, angle)
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
73
|
def mean_elongation
|
|
85
74
|
@mean_elongation ||= Angle.from_degrees(
|
|
86
75
|
(
|
|
@@ -94,7 +83,32 @@ module Astronoby
|
|
|
94
83
|
end
|
|
95
84
|
|
|
96
85
|
def elapsed_centuries
|
|
97
|
-
(@instant.tt -
|
|
86
|
+
(@instant.tt - JulianDate::DEFAULT_EPOCH) / Constants::DAYS_PER_JULIAN_CENTURY
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
# Source:
|
|
92
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
|
93
|
+
# Almanac (2018)
|
|
94
|
+
# Authors: Anthony Mallama and James L. Hilton
|
|
95
|
+
def magnitude_correction_term
|
|
96
|
+
phase_angle_degrees = phase_angle.degrees
|
|
97
|
+
if phase_angle_degrees <= 150 && current_phase_fraction <= 0.5
|
|
98
|
+
2.9994 * 10**-2 * phase_angle_degrees -
|
|
99
|
+
1.6057 * 10**-4 * phase_angle_degrees**2 +
|
|
100
|
+
3.1543 * 10**-6 * phase_angle_degrees**3 -
|
|
101
|
+
2.0667 * 10**-8 * phase_angle_degrees**4 +
|
|
102
|
+
6.2553 * 10**-11 * phase_angle_degrees**5
|
|
103
|
+
elsif phase_angle_degrees <= 150 && current_phase_fraction > 0.5
|
|
104
|
+
3.3234 * 10**-2 * phase_angle_degrees -
|
|
105
|
+
3.0725 * 10**-4 * phase_angle_degrees**2 +
|
|
106
|
+
6.1575 * 10**-6 * phase_angle_degrees**3 -
|
|
107
|
+
4.7723 * 10**-8 * phase_angle_degrees**4 +
|
|
108
|
+
1.4681 * 10**-10 * phase_angle_degrees**5
|
|
109
|
+
else
|
|
110
|
+
super
|
|
111
|
+
end
|
|
98
112
|
end
|
|
99
113
|
end
|
|
100
114
|
end
|
|
@@ -3,9 +3,30 @@
|
|
|
3
3
|
module Astronoby
|
|
4
4
|
class Neptune < SolarSystemBody
|
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(24_764_000)
|
|
6
|
+
ABSOLUTE_MAGNITUDE = -7.0
|
|
6
7
|
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, NEPTUNE_BARYCENTER]]
|
|
9
10
|
end
|
|
11
|
+
|
|
12
|
+
def self.absolute_magnitude
|
|
13
|
+
ABSOLUTE_MAGNITUDE
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Source:
|
|
19
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
|
20
|
+
# Almanac (2018)
|
|
21
|
+
# Authors: Anthony Mallama and James L. Hilton
|
|
22
|
+
def magnitude_correction_term
|
|
23
|
+
phase_angle_degrees = phase_angle.degrees
|
|
24
|
+
if phase_angle_degrees < 133 && @instant.tt > JulianDate::J2000
|
|
25
|
+
7.944 * 10**-3 * phase_angle_degrees +
|
|
26
|
+
9.617 * 10**-5 * phase_angle_degrees * phase_angle_degrees
|
|
27
|
+
else
|
|
28
|
+
super
|
|
29
|
+
end
|
|
30
|
+
end
|
|
10
31
|
end
|
|
11
32
|
end
|
|
@@ -3,9 +3,35 @@
|
|
|
3
3
|
module Astronoby
|
|
4
4
|
class Saturn < SolarSystemBody
|
|
5
5
|
EQUATORIAL_RADIUS = Distance.from_meters(60_268_000)
|
|
6
|
+
ABSOLUTE_MAGNITUDE = -8.914
|
|
6
7
|
|
|
7
8
|
def self.ephemeris_segments(_ephem_source)
|
|
8
9
|
[[SOLAR_SYSTEM_BARYCENTER, SATURN_BARYCENTER]]
|
|
9
10
|
end
|
|
11
|
+
|
|
12
|
+
def self.absolute_magnitude
|
|
13
|
+
ABSOLUTE_MAGNITUDE
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# Source:
|
|
19
|
+
# Title: Computing Apparent Planetary Magnitudes for The Astronomical
|
|
20
|
+
# Almanac (2018)
|
|
21
|
+
# Authors: Anthony Mallama and James L. Hilton
|
|
22
|
+
def magnitude_correction_term
|
|
23
|
+
phase_angle_degrees = phase_angle.degrees
|
|
24
|
+
if phase_angle_degrees <= 6
|
|
25
|
+
-0.036 -
|
|
26
|
+
3.7 * 10**-4 * phase_angle_degrees +
|
|
27
|
+
6.16 * 10**-4 * phase_angle_degrees * phase_angle_degrees
|
|
28
|
+
else
|
|
29
|
+
0.026 +
|
|
30
|
+
2.446 * 10**-4 * phase_angle_degrees +
|
|
31
|
+
2.672 * 10**-4 * phase_angle_degrees * phase_angle_degrees -
|
|
32
|
+
1.505 * 10**-6 * phase_angle_degrees**3 +
|
|
33
|
+
4.767 * 10**-9 * phase_angle_degrees**4
|
|
34
|
+
end
|
|
35
|
+
end
|
|
10
36
|
end
|
|
11
37
|
end
|
|
@@ -19,6 +19,10 @@ module Astronoby
|
|
|
19
19
|
|
|
20
20
|
attr_reader :geometric, :instant
|
|
21
21
|
|
|
22
|
+
def self.at(instant, ephem:)
|
|
23
|
+
new(ephem: ephem, instant: instant)
|
|
24
|
+
end
|
|
25
|
+
|
|
22
26
|
def self.geometric(ephem:, instant:)
|
|
23
27
|
compute_geometric(ephem: ephem, instant: instant)
|
|
24
28
|
end
|
|
@@ -27,42 +31,49 @@ module Astronoby
|
|
|
27
31
|
segments = ephemeris_segments(ephem.type)
|
|
28
32
|
segment1 = segments[0]
|
|
29
33
|
segment2 = segments[1] if segments.size == 2
|
|
34
|
+
cache_key = CacheKey.generate(:geometric, instant, segment1, segment2)
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
Astronoby.cache.fetch(cache_key) do
|
|
37
|
+
state1 = ephem[*segment1].state_at(instant.tt)
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
if segment2
|
|
40
|
+
state2 = ephem[*segment2].state_at(instant.tt)
|
|
41
|
+
position = state1.position + state2.position
|
|
42
|
+
velocity = state1.velocity + state2.velocity
|
|
43
|
+
else
|
|
44
|
+
position = state1.position
|
|
45
|
+
velocity = state1.velocity
|
|
46
|
+
end
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
48
|
+
position_vector = Vector[
|
|
49
|
+
Distance.from_kilometers(position.x),
|
|
50
|
+
Distance.from_kilometers(position.y),
|
|
51
|
+
Distance.from_kilometers(position.z)
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
velocity_vector = Vector[
|
|
55
|
+
Velocity.from_kilometers_per_day(velocity.x),
|
|
56
|
+
Velocity.from_kilometers_per_day(velocity.y),
|
|
57
|
+
Velocity.from_kilometers_per_day(velocity.z)
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
Geometric.new(
|
|
61
|
+
position: position_vector,
|
|
62
|
+
velocity: velocity_vector,
|
|
63
|
+
instant: instant,
|
|
64
|
+
target_body: self
|
|
65
|
+
)
|
|
66
|
+
end
|
|
60
67
|
end
|
|
61
68
|
|
|
62
69
|
def self.ephemeris_segments(_ephem_source)
|
|
63
70
|
raise NotImplementedError
|
|
64
71
|
end
|
|
65
72
|
|
|
73
|
+
def self.absolute_magnitude
|
|
74
|
+
nil
|
|
75
|
+
end
|
|
76
|
+
|
|
66
77
|
def initialize(ephem:, instant:)
|
|
67
78
|
@instant = instant
|
|
68
79
|
@geometric = compute_geometric(ephem)
|
|
@@ -74,6 +85,7 @@ module Astronoby
|
|
|
74
85
|
target: @geometric,
|
|
75
86
|
ephem: ephem
|
|
76
87
|
)
|
|
88
|
+
compute_sun(ephem) if requires_sun_data?
|
|
77
89
|
end
|
|
78
90
|
|
|
79
91
|
def astrometric
|
|
@@ -113,10 +125,133 @@ module Astronoby
|
|
|
113
125
|
)
|
|
114
126
|
end
|
|
115
127
|
|
|
128
|
+
# Returns the constellation of the body
|
|
129
|
+
# @return [Astronoby::Constellation, nil]
|
|
130
|
+
def constellation
|
|
131
|
+
@constellation ||= Constellations::Finder.find(
|
|
132
|
+
Precession.for_equatorial_coordinates(
|
|
133
|
+
coordinates: astrometric.equatorial,
|
|
134
|
+
epoch: JulianDate::B1875
|
|
135
|
+
)
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Source:
|
|
140
|
+
# Title: Astronomical Algorithms
|
|
141
|
+
# Author: Jean Meeus
|
|
142
|
+
# Edition: 2nd edition
|
|
143
|
+
# Chapter: 48 - Illuminated Fraction of the Moon's Disk
|
|
144
|
+
# @return [Astronoby::Angle, nil] Phase angle of the body
|
|
145
|
+
def phase_angle
|
|
146
|
+
return unless @sun
|
|
147
|
+
|
|
148
|
+
@phase_angle ||= begin
|
|
149
|
+
geocentric_elongation = Angle.acos(
|
|
150
|
+
@sun.apparent.equatorial.declination.sin *
|
|
151
|
+
apparent.equatorial.declination.sin +
|
|
152
|
+
@sun.apparent.equatorial.declination.cos *
|
|
153
|
+
apparent.equatorial.declination.cos *
|
|
154
|
+
(
|
|
155
|
+
@sun.apparent.equatorial.right_ascension -
|
|
156
|
+
apparent.equatorial.right_ascension
|
|
157
|
+
).cos
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
term1 = @sun.astrometric.distance.km * geocentric_elongation.sin
|
|
161
|
+
term2 = astrometric.distance.km -
|
|
162
|
+
@sun.astrometric.distance.km * geocentric_elongation.cos
|
|
163
|
+
angle = Angle.atan(term1 / term2)
|
|
164
|
+
Astronoby::Util::Trigonometry
|
|
165
|
+
.adjustement_for_arctangent(term1, term2, angle)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Fraction between 0 and 1 of the body's disk that is illuminated.
|
|
170
|
+
# @return [Float, nil] Body's illuminated fraction, between 0 and 1.
|
|
171
|
+
def illuminated_fraction
|
|
172
|
+
return unless phase_angle
|
|
173
|
+
|
|
174
|
+
@illuminated_fraction ||= (1 + phase_angle.cos) / 2.0
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Source:
|
|
178
|
+
# Title: Astronomical Algorithms
|
|
179
|
+
# Author: Jean Meeus
|
|
180
|
+
# Edition: 2nd edition
|
|
181
|
+
# Chapter: 48 - Illuminated Fraction of the Moon's Disk
|
|
182
|
+
# Apparent magnitude of the body, as seen from Earth.
|
|
183
|
+
# @return [Float, nil] Apparent magnitude of the body.
|
|
184
|
+
def apparent_magnitude
|
|
185
|
+
return unless self.class.absolute_magnitude
|
|
186
|
+
|
|
187
|
+
@apparent_magnitude ||= begin
|
|
188
|
+
body_sun_distance =
|
|
189
|
+
(astrometric.position - @sun.astrometric.position).magnitude
|
|
190
|
+
self.class.absolute_magnitude +
|
|
191
|
+
5 * Math.log10(body_sun_distance.au * astrometric.distance.au) +
|
|
192
|
+
magnitude_correction_term
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Angular diameter of the body, as seen from Earth. Based on the apparent
|
|
197
|
+
# position of the body.
|
|
198
|
+
# @return [Astronoby::Angle] Angular diameter of the body
|
|
199
|
+
def angular_diameter
|
|
200
|
+
@angular_radius ||= begin
|
|
201
|
+
return if apparent.position.zero?
|
|
202
|
+
|
|
203
|
+
Angle.from_radians(
|
|
204
|
+
Math.asin(self.class::EQUATORIAL_RADIUS.m / apparent.distance.m) * 2
|
|
205
|
+
)
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# @return [Boolean] True if the body is approaching the primary
|
|
210
|
+
# body (Sun), false otherwise.
|
|
211
|
+
def approaching_primary?
|
|
212
|
+
relative_position =
|
|
213
|
+
(geometric.position - @sun.geometric.position).map(&:m)
|
|
214
|
+
relative_velocity =
|
|
215
|
+
(geometric.velocity - @sun.geometric.velocity).map(&:mps)
|
|
216
|
+
radial_velocity_component = Astronoby::Util::Maths
|
|
217
|
+
.dot_product(relative_position, relative_velocity)
|
|
218
|
+
distance = Math.sqrt(
|
|
219
|
+
Astronoby::Util::Maths.dot_product(relative_position, relative_position)
|
|
220
|
+
)
|
|
221
|
+
radial_velocity_component / distance < 0
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# @return [Boolean] True if the body is receding from the primary
|
|
225
|
+
# body (Sun), false otherwise.
|
|
226
|
+
def receding_from_primary?
|
|
227
|
+
!approaching_primary?
|
|
228
|
+
end
|
|
229
|
+
|
|
116
230
|
private
|
|
117
231
|
|
|
232
|
+
# By default, Solar System bodies expose attributes that are dependent on
|
|
233
|
+
# the Sun's position, such as phase angle and illuminated fraction.
|
|
234
|
+
# If a body does not require Sun data, it should override this method to
|
|
235
|
+
# return false.
|
|
236
|
+
def requires_sun_data?
|
|
237
|
+
true
|
|
238
|
+
end
|
|
239
|
+
|
|
118
240
|
def compute_geometric(ephem)
|
|
119
241
|
self.class.compute_geometric(ephem: ephem, instant: @instant)
|
|
120
242
|
end
|
|
243
|
+
|
|
244
|
+
def compute_sun(ephem)
|
|
245
|
+
@sun ||= Sun.new(instant: @instant, ephem: ephem)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Source:
|
|
249
|
+
# Title: Explanatory Supplement to the Astronomical Almanac
|
|
250
|
+
# Authors: Sean E. Urban and P. Kenneth Seidelmann
|
|
251
|
+
# Edition: University Science Books
|
|
252
|
+
# Chapter: 10.3 - Phases and Magnitudes
|
|
253
|
+
def magnitude_correction_term
|
|
254
|
+
-2.5 * Math.log10(illuminated_fraction)
|
|
255
|
+
end
|
|
121
256
|
end
|
|
122
257
|
end
|