astro-algo 0.0.1
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.
- data/README +23 -0
- data/bin/equinox +19 -0
- data/bin/lunarcalendar +38 -0
- data/bin/moon_clock.rb +184 -0
- data/bin/moons +31 -0
- data/lib/astro-algo.rb +846 -0
- data/lib/lunaryear.rb +91 -0
- metadata +65 -0
data/README
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
= Astronomical Algorithms
|
|
2
|
+
|
|
3
|
+
This library implements algorithms from Jean Meeus, <i>Astronomical Algorithms</i>,
|
|
4
|
+
2nd English Edition, Willmann-Bell, Inc., Richmond, Virginia, 1999, with corrections
|
|
5
|
+
as of June 15, 2005.
|
|
6
|
+
|
|
7
|
+
Gem astro-algo provides two modules:
|
|
8
|
+
|
|
9
|
+
* Astro which implements algorithms from the book. (require 'astro-algo')
|
|
10
|
+
* LunarYear which implements helper routines for calculating lunar years. (require 'lunaryear')
|
|
11
|
+
|
|
12
|
+
This gem also comes with several command line scripts.
|
|
13
|
+
equinox:: prints the date and time of the vernal equinox for the given year.
|
|
14
|
+
lunarcalendar:: prints a conversion chart between the customary Gregarian
|
|
15
|
+
calendar and a lunar year beginning with the full moon on or before
|
|
16
|
+
the vernal equinox.
|
|
17
|
+
moon_clock.rb:: a Tk GUI application which displays information about the current
|
|
18
|
+
lunation.
|
|
19
|
+
moons:: prints the phases of the moon for the given year.
|
|
20
|
+
|
|
21
|
+
This is a work in progress. Only the algorithms from <i>Astronomical Algorithms</i>
|
|
22
|
+
needed to support my hobby in the LunarYear have been implemented. I will add more
|
|
23
|
+
algorithms from the book in time.
|
data/bin/equinox
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# equinox.rb
|
|
3
|
+
|
|
4
|
+
# Compute the date of the vernal equinox for a given year (default current year).
|
|
5
|
+
#
|
|
6
|
+
# Example: compute the date and time of the vernal equinox for 2008.
|
|
7
|
+
# $ equinox 2008 => Thu Mar 20 05:48:18 2008
|
|
8
|
+
|
|
9
|
+
require File.join(File.dirname(__FILE__), '../lib/astro-algo')
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if ARGV.length == 0
|
|
13
|
+
year = Time.now.year
|
|
14
|
+
else
|
|
15
|
+
year = ARGV[0].to_i
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
puts Astro.date_of_vernal_equinox(year).to_utc.asctime
|
|
19
|
+
|
data/bin/lunarcalendar
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# lunarcalendar.rb
|
|
3
|
+
|
|
4
|
+
# Print a lunar calendar for the given year (default current year).
|
|
5
|
+
|
|
6
|
+
require File.join(File.dirname(__FILE__), '../lib/lunaryear')
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
if ARGV.length == 0
|
|
11
|
+
year = Time.now.year
|
|
12
|
+
else
|
|
13
|
+
year = ARGV[0].to_i
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
lunation = LunarYear.new_moon_before_vernal_equinox(year)
|
|
19
|
+
next_years_lunation = LunarYear.new_moon_before_vernal_equinox(year + 1)
|
|
20
|
+
vernal_equinox = Astro.date_of_vernal_equinox(year).to_utc
|
|
21
|
+
vemonth = vernal_equinox.month
|
|
22
|
+
veday = vernal_equinox.day
|
|
23
|
+
|
|
24
|
+
moonth = 0
|
|
25
|
+
while lunation < next_years_lunation
|
|
26
|
+
moon_date = Astro.date_of_moon(lunation, Astro::PhaseNew).to_utc
|
|
27
|
+
next_moon = Astro.date_of_moon(lunation + 1, Astro::PhaseNew).to_utc
|
|
28
|
+
moon_day = 0
|
|
29
|
+
until moon_date.month == next_moon.month && moon_date.day == next_moon.day
|
|
30
|
+
ve = vemonth == moon_date.month && veday == moon_date.day ? '*' : ' '
|
|
31
|
+
puts '%2d-%02d %s%s' % [moonth, moon_day, moon_date.strftime('%b %d'), ve]
|
|
32
|
+
moon_day += 1
|
|
33
|
+
moon_date += 1
|
|
34
|
+
end
|
|
35
|
+
puts '--------------'
|
|
36
|
+
lunation += 1
|
|
37
|
+
moonth += 1
|
|
38
|
+
end
|
data/bin/moon_clock.rb
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# moon_clock.rb
|
|
3
|
+
#
|
|
4
|
+
# A clock application which displays the current local time,
|
|
5
|
+
# Universal time, time since the previous new and full moons,
|
|
6
|
+
# and time until the next new and full moons.
|
|
7
|
+
#
|
|
8
|
+
# Copyright (c) 2007 John Powers
|
|
9
|
+
|
|
10
|
+
require 'tk'
|
|
11
|
+
require File.join(File.dirname(__FILE__), '../lib/lunaryear')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
DateTimeFormat = '%Y-%m-%d %H:%M:%S'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Format number of days.
|
|
18
|
+
# +days+ is a rational number of days.
|
|
19
|
+
# Return days formatted like 28d 14:59:11
|
|
20
|
+
def format_days(days)
|
|
21
|
+
d, r = days.divmod(1)
|
|
22
|
+
h, r = (24*r).divmod(1)
|
|
23
|
+
m, r = (60*r).divmod(1)
|
|
24
|
+
s = (60*r).floor
|
|
25
|
+
'%dd %d:%02d:%02d' % [d, h, m, s] # 28d 14:59:11
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Set local and universal clocks to current time.
|
|
30
|
+
def set_clocks
|
|
31
|
+
now = DateTime.now
|
|
32
|
+
$current_time.value = now.strftime(DateTimeFormat)
|
|
33
|
+
$universal_time.value = now.new_offset.strftime(DateTimeFormat)
|
|
34
|
+
$lunar_date.value = '%4d\'%02d\'%02d' % LunarYear.lunar_date(now.to_date)
|
|
35
|
+
now
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Update moon times
|
|
40
|
+
$tnew0 = DateTime.jd(1)
|
|
41
|
+
$tnew1 = DateTime.jd(1)
|
|
42
|
+
$tfull0 = DateTime.jd(1)
|
|
43
|
+
$tfull1 = DateTime.jd(1)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Set all moon clocks relative to the current time -- the
|
|
47
|
+
# number of days since the last moon or until the next moon.
|
|
48
|
+
def set_moon_clocks
|
|
49
|
+
now = set_clocks
|
|
50
|
+
|
|
51
|
+
# Has new or full moon expired?
|
|
52
|
+
if now > $tnew1 || now > $tfull1
|
|
53
|
+
$tnew0, $tnew1, $tfull0, $tfull1 = LunarYear.date_of_moons(now)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
$last_new_moon.value = format_days(now - $tnew0)
|
|
57
|
+
$next_new_moon.value = format_days($tnew1 - now)
|
|
58
|
+
$last_full_moon.value = format_days(now - $tfull0)
|
|
59
|
+
$next_full_moon.value = format_days($tfull1 - now)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# Periodically update moon clocks. Reschedules itself to run
|
|
64
|
+
# again in 1000 milliseconds.
|
|
65
|
+
def update
|
|
66
|
+
set_moon_clocks
|
|
67
|
+
Tk.after(1000) {update}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
$root = TkRoot.new { title 'Moon Clock' }
|
|
74
|
+
top = TkFrame.new($root)
|
|
75
|
+
|
|
76
|
+
# Local time
|
|
77
|
+
$current_time = TkVariable.new
|
|
78
|
+
TkLabel.new(top) {
|
|
79
|
+
font 'Courier 48 bold'
|
|
80
|
+
textvariable $current_time
|
|
81
|
+
grid(:row => 0, :column => 0, :columnspan => 2, :sticky => 'ew')
|
|
82
|
+
}
|
|
83
|
+
TkLabel.new(top) {
|
|
84
|
+
font 'Palatino 18 italic'
|
|
85
|
+
text 'Local Time'
|
|
86
|
+
grid(:row => 1, :column => 0, :columnspan => 2, :sticky => 'ew')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# Universal time
|
|
91
|
+
$universal_time = TkVariable.new
|
|
92
|
+
TkLabel.new(top) {
|
|
93
|
+
font 'Courier 36 bold'
|
|
94
|
+
textvariable $universal_time
|
|
95
|
+
grid(:row => 2, :column => 0, :columnspan => 2, :sticky => 'ew')
|
|
96
|
+
}
|
|
97
|
+
TkLabel.new(top) {
|
|
98
|
+
font 'Palatino 18 italic'
|
|
99
|
+
text 'Universal Time'
|
|
100
|
+
grid(:row => 3, :column => 0, :columnspan => 2, :sticky => 'ew')
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# Lunar date
|
|
105
|
+
$lunar_date = TkVariable.new
|
|
106
|
+
TkLabel.new(top) {
|
|
107
|
+
font 'Courier 36 bold'
|
|
108
|
+
textvariable $lunar_date
|
|
109
|
+
grid(:row => 4, :column => 0, :columnspan => 2, :sticky => 'ew')
|
|
110
|
+
}
|
|
111
|
+
TkLabel.new(top) {
|
|
112
|
+
font 'Palatino 18 italic'
|
|
113
|
+
text 'Lunar Date'
|
|
114
|
+
grid(:row => 5, :column => 0, :columnspan => 2, :sticky => 'ew')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# Time since last new moon
|
|
119
|
+
$last_new_moon = TkVariable.new
|
|
120
|
+
TkLabel.new(top) {
|
|
121
|
+
font 'Courier 36 bold'
|
|
122
|
+
textvariable $last_new_moon
|
|
123
|
+
grid(:row => 6, :column => 0, :sticky => 'e')
|
|
124
|
+
}
|
|
125
|
+
TkLabel.new(top) {
|
|
126
|
+
font 'Palatino 18 italic'
|
|
127
|
+
text 'Last New Moon'
|
|
128
|
+
grid(:row => 7, :column => 0)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
# Time until next new moon
|
|
132
|
+
$next_new_moon = TkVariable.new
|
|
133
|
+
TkLabel.new(top) {
|
|
134
|
+
font 'Courier 36 bold'
|
|
135
|
+
textvariable $next_new_moon
|
|
136
|
+
grid(:row => 6, :column => 1, :sticky => 'e')
|
|
137
|
+
}
|
|
138
|
+
TkLabel.new(top) {
|
|
139
|
+
font 'Palatino 18 italic'
|
|
140
|
+
text 'Next New Moon'
|
|
141
|
+
grid(:row => 7, :column => 1)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# Time since last full moon
|
|
145
|
+
$last_full_moon = TkVariable.new
|
|
146
|
+
TkLabel.new(top) {
|
|
147
|
+
font 'Courier 36 bold'
|
|
148
|
+
textvariable $last_full_moon
|
|
149
|
+
grid(:row => 8, :column => 0, :sticky => 'e')
|
|
150
|
+
}
|
|
151
|
+
TkLabel.new(top) {
|
|
152
|
+
font 'Palatino 18 italic'
|
|
153
|
+
text 'Last Full Moon'
|
|
154
|
+
grid(:row => 9, :column => 0)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# Time until next full moon
|
|
158
|
+
$next_full_moon = TkVariable.new
|
|
159
|
+
TkLabel.new(top) {
|
|
160
|
+
font 'Courier 36 bold'
|
|
161
|
+
textvariable $next_full_moon
|
|
162
|
+
grid(:row => 8, :column => 1, :sticky => 'e')
|
|
163
|
+
}
|
|
164
|
+
TkLabel.new(top) {
|
|
165
|
+
font 'Palatino 18 italic'
|
|
166
|
+
text 'Next Full Moon'
|
|
167
|
+
grid(:row => 9, :column => 1)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
TkButton.new(top) {
|
|
172
|
+
text ' Quit '
|
|
173
|
+
command {exit}
|
|
174
|
+
grid(:row => 10, :column => 1)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
top.pack(:fill => 'both')
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
# Start clock display
|
|
182
|
+
update
|
|
183
|
+
|
|
184
|
+
Tk.mainloop
|
data/bin/moons
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# moons
|
|
3
|
+
|
|
4
|
+
# Print a list of dates and times for phases of the moon for given
|
|
5
|
+
# year (default current year).
|
|
6
|
+
|
|
7
|
+
require File.join(File.dirname(__FILE__), '../lib/astro-algo')
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if ARGV.length == 0
|
|
12
|
+
year = DateTime.now.year
|
|
13
|
+
else
|
|
14
|
+
year = ARGV[0].to_i
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
DateFormat = '%Y-%m-%d %H:%M:%S '
|
|
18
|
+
|
|
19
|
+
#puts ' ' + date.year.to_s
|
|
20
|
+
lunation = Astro.first_lunation_of_year(year)
|
|
21
|
+
next_year = DateTime.new(year + 1, 1, 1)
|
|
22
|
+
|
|
23
|
+
loop do
|
|
24
|
+
new_moon = Astro.date_of_moon(lunation, Astro::PhaseNew).to_utc
|
|
25
|
+
break if new_moon >= next_year
|
|
26
|
+
print new_moon.strftime(DateFormat)
|
|
27
|
+
print Astro.date_of_moon(lunation, Astro::PhaseFirstQuarter).to_utc.strftime(DateFormat)
|
|
28
|
+
print Astro.date_of_moon(lunation, Astro::PhaseFull).to_utc.strftime(DateFormat)
|
|
29
|
+
puts Astro.date_of_moon(lunation, Astro::PhaseLastQuarter).to_utc.strftime(DateFormat)
|
|
30
|
+
lunation += 1
|
|
31
|
+
end
|
data/lib/astro-algo.rb
ADDED
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
# astro.rb
|
|
2
|
+
# Implementation of astronomical calculations from
|
|
3
|
+
# Jean Meuss, <i>Astronomical Algorithms</i>, 2nd English Edition,
|
|
4
|
+
# Willmann-Bell, Inc., Richmond, Virginia, 1999, with corrections as of June 15, 2005.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
require 'date'
|
|
8
|
+
|
|
9
|
+
# Augment several classes with new methods.
|
|
10
|
+
|
|
11
|
+
class Numeric
|
|
12
|
+
|
|
13
|
+
# Convert from degrees to radians.
|
|
14
|
+
def to_rad
|
|
15
|
+
self * Math::PI / 180.0
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Convert from radians to degrees.
|
|
19
|
+
def to_deg
|
|
20
|
+
self * 180.0 / Math::PI
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Float
|
|
27
|
+
|
|
28
|
+
# Convert Float to Rational.
|
|
29
|
+
# Algorithm from Dave Burt: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/142199
|
|
30
|
+
def to_r
|
|
31
|
+
return Rational(0, 1) if self == 0.0
|
|
32
|
+
x = self
|
|
33
|
+
negative = false
|
|
34
|
+
if x < 0.0
|
|
35
|
+
x = -x
|
|
36
|
+
negative = true
|
|
37
|
+
end
|
|
38
|
+
f, e = Math.frexp(x)
|
|
39
|
+
# raise unless 0.5 <= f and f < 1.0
|
|
40
|
+
# x = f * 2**e exactly
|
|
41
|
+
|
|
42
|
+
# Suck up _chunk_ bits at a time; 28 is enough so that we suck
|
|
43
|
+
# up all bits in 2 iterations for all known binary double-
|
|
44
|
+
# precision formats, and small enough to fit in an int.
|
|
45
|
+
chunk = 28
|
|
46
|
+
top = 0
|
|
47
|
+
# invariant: x = (top + f) * 2**e exactly
|
|
48
|
+
while f > 0.0
|
|
49
|
+
f = Math.ldexp(f, chunk)
|
|
50
|
+
digit = f.to_i
|
|
51
|
+
raise unless digit >> chunk == 0
|
|
52
|
+
top = (top << chunk) | digit
|
|
53
|
+
f -= digit
|
|
54
|
+
# raise unless 0.0 <= f and f < 1.0
|
|
55
|
+
e -= chunk
|
|
56
|
+
end
|
|
57
|
+
# raise if top == 0
|
|
58
|
+
|
|
59
|
+
# now x = top * 2**e exactly; fold in 2**e
|
|
60
|
+
r = Rational(top, 1)
|
|
61
|
+
if e > 0
|
|
62
|
+
r *= 2**e
|
|
63
|
+
else
|
|
64
|
+
r /= 2**-e
|
|
65
|
+
end
|
|
66
|
+
negative ? -r : r
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class Array
|
|
72
|
+
|
|
73
|
+
# Evaluate polynomial using Horner's method.
|
|
74
|
+
# Array consists of coefficients of a polynomial, the
|
|
75
|
+
# coefficient of the highest order term first, the
|
|
76
|
+
# constant coefficient last.
|
|
77
|
+
# Returns evaluation of polynomial at +x+.
|
|
78
|
+
#
|
|
79
|
+
# Example: evaluate the polynomial x**2 - 0.5*x + 3.0 where x = 2.0
|
|
80
|
+
# [1.0, -0.5, 3.0].poly_eval(2.0) # => 6.0
|
|
81
|
+
def poly_eval(x)
|
|
82
|
+
self.inject(0.0) {|p, a| p*x + a}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class DateTime
|
|
89
|
+
|
|
90
|
+
# Adjust dynamical time to UTC.
|
|
91
|
+
# Returns rational number of seconds.
|
|
92
|
+
def to_utc
|
|
93
|
+
self - Astro.delta_T(self).to_r / 86400 # convert from seconds to days
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Truncate date/time to date.
|
|
97
|
+
# Returns a Date object for the given DateTime.
|
|
98
|
+
def to_date
|
|
99
|
+
Date.new(year, month, day)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
module Astro
|
|
106
|
+
|
|
107
|
+
VERSION = '0.0.1'
|
|
108
|
+
|
|
109
|
+
# Compute difference between dynamical time and UTC in seconds.
|
|
110
|
+
# See http://sunearth.gsfc.nasa.gov/eclipse/SEcat5/deltatpoly.html.
|
|
111
|
+
# Good from -1999 to +3000.
|
|
112
|
+
#
|
|
113
|
+
# Example: compute the difference between dynamical time and UTC for January 1, 2007.
|
|
114
|
+
# Astro.delta_T(DateTime.new(2007, 1, 1)) # => 65.465744703125
|
|
115
|
+
def Astro.delta_T(date)
|
|
116
|
+
|
|
117
|
+
year = date.year.to_f
|
|
118
|
+
y = year + (date.month.to_f - 0.5) / 12.0
|
|
119
|
+
|
|
120
|
+
case
|
|
121
|
+
when year < -500.0
|
|
122
|
+
u = (year - 1820.0) / 100.0
|
|
123
|
+
-20.0 + 32.0*u*u
|
|
124
|
+
when year < 500.0
|
|
125
|
+
u = y / 100.0
|
|
126
|
+
[0.0090316521, 0.022174192, -0.1798452, -5.952053, 33.78311, -1014.41, 10583.6].poly_eval(u)
|
|
127
|
+
when year < 1600.0
|
|
128
|
+
u = (y - 1000.0) / 100.0
|
|
129
|
+
[0.0083572073, -0.005050998, -0.8503463, 0.319781, 71.23472, -556.01, 1574.2].poly_eval(u)
|
|
130
|
+
when year < 1700.0
|
|
131
|
+
t = y - 1600.0
|
|
132
|
+
[1.0/7129.0, -0.01532, -0.9808, 120.0].poly_eval(t)
|
|
133
|
+
when year < 1800.0
|
|
134
|
+
t = y - 1700.0
|
|
135
|
+
[-1.0/1174000.0, 0.00013336, -0.0059285, 0.1603, 8.83].poly_eval(t)
|
|
136
|
+
when year < 1860.0
|
|
137
|
+
t = y - 1800.0
|
|
138
|
+
[0.000000000875, -0.0000001699, 0.0000121272, -0.00037436, 0.0041116, 0.0068612, -0.332447, 13.72].poly_eval(t)
|
|
139
|
+
when year < 1900.0
|
|
140
|
+
t = y - 1860.0
|
|
141
|
+
[1.0/233174.0, -0.0004473624, 0.01680668, -0.251754, 0.5737, 7.62].poly_eval(t)
|
|
142
|
+
when year < 1920.0
|
|
143
|
+
t = y - 1900.0
|
|
144
|
+
[-0.000197, 0.0061966, -0.0598939, 1.494119, -2.79].poly_eval(t)
|
|
145
|
+
when year < 1941.0
|
|
146
|
+
t = y - 1920.0
|
|
147
|
+
[0.0020936, -0.076100, 0.84493, 21.20].poly_eval(t)
|
|
148
|
+
when year < 1961.0
|
|
149
|
+
t = y - 1950.0
|
|
150
|
+
[1.0/2547.0, -1.0/233.0, 0.407, 29.07].poly_eval(t)
|
|
151
|
+
when year < 1986.0
|
|
152
|
+
t = y - 1975.0
|
|
153
|
+
[-1.0/718.0, -1.0/260.0, 1.067, 45.45].poly_eval(t)
|
|
154
|
+
when year < 2005.0
|
|
155
|
+
t = y - 2000.0
|
|
156
|
+
[0.00002373599, 0.000651814, 0.0017275, -0.060374, 0.3345, 63.86].poly_eval(t)
|
|
157
|
+
when year < 2050.0
|
|
158
|
+
t = y - 2000.0
|
|
159
|
+
[0.005589, 0.32217, 62.92].poly_eval(t)
|
|
160
|
+
when year < 2150.0
|
|
161
|
+
-20.0 + 32.0*((y - 1820.0)/100.0)**2 - 0.5628*(2150.0 - y)
|
|
162
|
+
else
|
|
163
|
+
u = (year - 1820.0) / 100.0
|
|
164
|
+
-20.0 + 32*u*u
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# =Phases of the Moon
|
|
169
|
+
|
|
170
|
+
# :stopdoc:
|
|
171
|
+
# New and Old Moon
|
|
172
|
+
Table_49B = [ # page 351
|
|
173
|
+
# new moon full moon E F M M' O
|
|
174
|
+
[ 0.00002, 0.00002, 0, 0.0, 0.0, 4.0, 0.0],
|
|
175
|
+
[-0.00002, -0.00002, 0, 0.0, 1.0, 3.0, 0.0],
|
|
176
|
+
[-0.00002, -0.00002, 0, -2.0, -1.0, 1.0, 0.0],
|
|
177
|
+
[ 0.00003, 0.00003, 0, 2.0, -1.0, 1.0, 0.0],
|
|
178
|
+
[-0.00003, -0.00003, 0, 2.0, 1.0, 1.0, 0.0],
|
|
179
|
+
[ 0.00003, 0.00003, 0, 2.0, 0.0, 2.0, 0.0],
|
|
180
|
+
[ 0.00003, 0.00003, 0, -2.0, 1.0, 1.0, 0.0],
|
|
181
|
+
[ 0.00004, 0.00004, 0, 0.0, 3.0, 0.0, 0.0],
|
|
182
|
+
[ 0.00004, 0.00004, 0, -2.0, 0.0, 2.0, 0.0],
|
|
183
|
+
[-0.00007, -0.00007, 0, 0.0, 2.0, 1.0, 0.0],
|
|
184
|
+
[-0.00017, -0.00017, 0, 0.0, 0.0, 0.0, 1.0],
|
|
185
|
+
[-0.00024, -0.00024, 1, 0.0, -1.0, 2.0, 0.0],
|
|
186
|
+
[ 0.00038, 0.00038, 1, -2.0, 1.0, 0.0, 0.0],
|
|
187
|
+
[ 0.00042, 0.00042, 1, 2.0, 1.0, 0.0, 0.0],
|
|
188
|
+
[-0.00042, -0.00042, 0, 0.0, 0.0, 3.0, 0.0],
|
|
189
|
+
[ 0.00056, 0.00056, 1, 0.0, 1.0, 2.0, 0.0],
|
|
190
|
+
[-0.00057, -0.00057, 0, 2.0, 0.0, 1.0, 0.0],
|
|
191
|
+
[-0.00111, -0.00111, 0, -2.0, 0.0, 1.0, 0.0],
|
|
192
|
+
[ 0.00208, 0.00209, 2, 0.0, 2.0, 0.0, 0.0],
|
|
193
|
+
[-0.00514, -0.00515, 1, 0.0, 1.0, 1.0, 0.0],
|
|
194
|
+
[ 0.00739, 0.00734, 1, 0.0, -1.0, 1.0, 0.0],
|
|
195
|
+
[ 0.01039, 0.01043, 0, 2.0, 0.0, 0.0, 0.0],
|
|
196
|
+
[ 0.01608, 0.01614, 0, 0.0, 0.0, 2.0, 0.0],
|
|
197
|
+
[ 0.17241, 0.17302, 1, 0.0, 1.0, 0.0, 0.0],
|
|
198
|
+
[-0.40720, -0.40614, 0, 0.0, 0.0, 1.0, 0.0]
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
# Planetary arguments
|
|
202
|
+
Table_49A = [ # page 351
|
|
203
|
+
# k T^2
|
|
204
|
+
[299.77, 0.107408, 0.000325, -0.009173],
|
|
205
|
+
[251.88, 0.016321, 0.000165, 0.0 ],
|
|
206
|
+
[251.83, 26.651886, 0.000164, 0.0 ],
|
|
207
|
+
[349.42, 36.412478, 0.000126, 0.0 ],
|
|
208
|
+
[ 84.66, 18.206239, 0.000110, 0.0 ],
|
|
209
|
+
[141.74, 53.303771, 0.000062, 0.0 ],
|
|
210
|
+
[207.14, 2.453732, 0.000060, 0.0 ],
|
|
211
|
+
[154.84, 7.306860, 0.000056, 0.0 ],
|
|
212
|
+
[ 34.52, 27.261239, 0.000047, 0.0 ],
|
|
213
|
+
[207.19, 0.121824, 0.000042, 0.0 ],
|
|
214
|
+
[291.34, 1.844379, 0.000040, 0.0 ],
|
|
215
|
+
[161.72, 24.198154, 0.000037, 0.0 ],
|
|
216
|
+
[239.56, 25.513099, 0.000035, 0.0 ],
|
|
217
|
+
[331.55, 3.592518, 0.000023, 0.0 ]
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
# First and last quarter
|
|
221
|
+
Table_49C = [ # page 352
|
|
222
|
+
# E F M M' O
|
|
223
|
+
[-0.00002, 0, 0.0, 1.0, 3.0, 0.0],
|
|
224
|
+
[ 0.00002, 0, 2.0, -1.0, 1.0, 0.0],
|
|
225
|
+
[ 0.00002, 0, -2.0, 0.0, 2.0, 0.0],
|
|
226
|
+
[ 0.00003, 0, 0.0, 3.0, 0.0, 0.0],
|
|
227
|
+
[ 0.00003, 0, -2.0, 1.0, 1.0, 0.0],
|
|
228
|
+
[ 0.00004, 0, 0.0, -2.0, 1.0, 0.0],
|
|
229
|
+
[-0.00004, 0, 2.0, 1.0, 1.0, 0.0],
|
|
230
|
+
[ 0.00004, 0, 2.0, 0.0, 2.0, 0.0],
|
|
231
|
+
[-0.00005, 0, -2.0, -1.0, 1.0, 0.0],
|
|
232
|
+
[-0.00017, 0, 0.0, 0.0, 0.0, 1.0],
|
|
233
|
+
[ 0.00027, 1, 0.0, 1.0, 2.0, 0.0],
|
|
234
|
+
[-0.00028, 2, 0.0, 2.0, 1.0, 0.0],
|
|
235
|
+
[ 0.00032, 1, -2.0, 1.0, 0.0, 0.0],
|
|
236
|
+
[ 0.00032, 1, 2.0, 1.0, 0.0, 0.0],
|
|
237
|
+
[-0.00034, 1, 0.0, -1.0, 2.0, 0.0],
|
|
238
|
+
[-0.00040, 0, 0.0, 0.0, 3.0, 0.0],
|
|
239
|
+
[-0.00070, 0, 2.0, 0.0, 1.0, 0.0],
|
|
240
|
+
[-0.00180, 0, -2.0, 0.0, 1.0, 0.0],
|
|
241
|
+
[ 0.00204, 2, 0.0, 2.0, 0.0, 0.0],
|
|
242
|
+
[ 0.00454, 1, 0.0, -1.0, 1.0, 0.0],
|
|
243
|
+
[ 0.00804, 0, 2.0, 0.0, 0.0, 0.0],
|
|
244
|
+
[ 0.00862, 0, 0.0, 0.0, 2.0, 0.0],
|
|
245
|
+
[-0.01183, 1, 0.0, 1.0, 1.0, 0.0],
|
|
246
|
+
[ 0.17172, 1, 0.0, 1.0, 0.0, 0.0],
|
|
247
|
+
[-0.62801, 0, 0.0, 0.0, 1.0, 0.0]
|
|
248
|
+
]
|
|
249
|
+
# :startdoc:
|
|
250
|
+
|
|
251
|
+
PhaseNew = 0
|
|
252
|
+
PhaseFirstQuarter = 1
|
|
253
|
+
PhaseFull = 2
|
|
254
|
+
PhaseLastQuarter = 3
|
|
255
|
+
|
|
256
|
+
# Returns DateTime for phase of Moon.
|
|
257
|
+
# Implementation of algorithm in chapter 49.
|
|
258
|
+
# k:: number of Moon. k = 0 is first New Moon in the year 2000.
|
|
259
|
+
# phase:: Astro::PhaseNew, Astro::PhaseFirstQuarter, Astro::PhaseFull, Astro::PhaseLastQuarter
|
|
260
|
+
#
|
|
261
|
+
# Example: compute the date and time of New Moon #87 (first lunation in 2007).
|
|
262
|
+
# Astro.date_of_moon(87, Astro::PhaseNew).asctime # => "Fri Jan 19 04:01:45 2007"
|
|
263
|
+
def Astro.date_of_moon(k, phase)
|
|
264
|
+
|
|
265
|
+
k += phase / 4.0
|
|
266
|
+
|
|
267
|
+
# t = Julian centuries
|
|
268
|
+
t = k / 1236.85
|
|
269
|
+
|
|
270
|
+
# Julian Ephemeris Days
|
|
271
|
+
jde = 2_451_550.097_66 +
|
|
272
|
+
29.530_588_861 * k +
|
|
273
|
+
[0.000_000_000_73, -0.000_000_150, 0.000_154_37, 0.0, 0.0].poly_eval(t)
|
|
274
|
+
|
|
275
|
+
# Eccentricity of Earth's orbit
|
|
276
|
+
e = [-0.000_0074, -0.002_516, 1.0].poly_eval(t)
|
|
277
|
+
|
|
278
|
+
# Sun's mean anomaly
|
|
279
|
+
m = 2.5534 +
|
|
280
|
+
29.105_356_70 * k +
|
|
281
|
+
[-0.000_000_11, -0.000_0014, 0.0, 0.0].poly_eval(t)
|
|
282
|
+
|
|
283
|
+
# Moon's mean anomaly
|
|
284
|
+
m_lun = 201.5643 +
|
|
285
|
+
385.816_935_28 * k +
|
|
286
|
+
[-0.000_000_058, 0.000_012_38, 0.010_7582, 0.0, 0.0].poly_eval(t)
|
|
287
|
+
|
|
288
|
+
# Moon's argument of latitude
|
|
289
|
+
f = 160.7108 +
|
|
290
|
+
390.670_502_84 * k +
|
|
291
|
+
[0.000_000_011, -0.000_002_27, -0.001_6118, 0.0, 0.0].poly_eval(t)
|
|
292
|
+
|
|
293
|
+
# omega = longitude of the ascending node of the lunar orbit
|
|
294
|
+
o = 124.7746 -
|
|
295
|
+
1.563_755_88 * k +
|
|
296
|
+
[0.000_002_15, 0.002_0672, 0.0, 0.0].poly_eval(t)
|
|
297
|
+
|
|
298
|
+
if phase == PhaseNew || phase == PhaseFull # new moon or full moon
|
|
299
|
+
|
|
300
|
+
col = phase == PhaseNew ? 0 : 1 # choose column of coefficient
|
|
301
|
+
corr1 = 0.0
|
|
302
|
+
for term in Table_49B do
|
|
303
|
+
t1 = term[col]
|
|
304
|
+
term[2].times {t1 *= e}
|
|
305
|
+
t2 = term[3] * f
|
|
306
|
+
t2 += term[4] * m
|
|
307
|
+
t2 += term[5] * m_lun
|
|
308
|
+
t2 += term[6] * o
|
|
309
|
+
t2 = Math.sin((t2 % 360.0).to_rad)
|
|
310
|
+
corr1 += t1 * t2
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
jde += corr1
|
|
314
|
+
|
|
315
|
+
else # first or last quarter
|
|
316
|
+
corr1 = 0.0
|
|
317
|
+
for term in Table_49C do
|
|
318
|
+
t1 = term[0]
|
|
319
|
+
term[1].times {t1 *= e}
|
|
320
|
+
t2 = term[2] * f
|
|
321
|
+
t2 += term[3] * m
|
|
322
|
+
t2 += term[4] * m_lun
|
|
323
|
+
t2 += term[5] * o
|
|
324
|
+
t2 = Math.sin((t2 % 360.0).to_rad)
|
|
325
|
+
corr1 += t1 * t2
|
|
326
|
+
end
|
|
327
|
+
jde += corr1
|
|
328
|
+
|
|
329
|
+
w = 0.00002 * Math.cos((2.0*f).to_rad) +
|
|
330
|
+
0.00002 * Math.cos((m_lun + m).to_rad) -
|
|
331
|
+
0.00002 * Math.cos((m_lun - m).to_rad) +
|
|
332
|
+
0.00026 * Math.cos(m_lun.to_rad) -
|
|
333
|
+
0.00038 * e * Math.cos(m.to_rad) +
|
|
334
|
+
0.00306
|
|
335
|
+
|
|
336
|
+
if phase == PhaseFirstQuarter
|
|
337
|
+
jde += w # first quarter
|
|
338
|
+
else
|
|
339
|
+
jde -= w # last quarter
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# correction for all phases
|
|
344
|
+
corr2 = 0.0
|
|
345
|
+
t2 = t*t
|
|
346
|
+
for term in Table_49A do
|
|
347
|
+
a = term[0]
|
|
348
|
+
a += term[1] * k
|
|
349
|
+
a += term[3] * t2
|
|
350
|
+
corr2 += Math.sin((a % 360.0).to_rad) * term[2]
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
DateTime.jd((jde + corr2).to_r, 12)
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# Find number of first lunation (New Moon) for a given year.
|
|
357
|
+
# Lunation 0 is the first New Moon in the year 2000.
|
|
358
|
+
# Returns an integer lunation number.
|
|
359
|
+
#
|
|
360
|
+
# Example: find first lunation of 1776.
|
|
361
|
+
# Astro.first_lunation_of_year(1776) # => -2770
|
|
362
|
+
def Astro.first_lunation_of_year(year)
|
|
363
|
+
k = ((year - 2000)*12.3685).floor
|
|
364
|
+
k += 1 while date_of_moon(k, PhaseNew).year < year
|
|
365
|
+
k
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
# :stopdoc:
|
|
370
|
+
# Vernal Equinox
|
|
371
|
+
Table_27C = [ # page 179
|
|
372
|
+
# sum(A cos (B + C*t))
|
|
373
|
+
# A B C
|
|
374
|
+
[ 8.0, 15.45, 16_859.074],
|
|
375
|
+
[ 9.0, 227.73, 1_222.114],
|
|
376
|
+
[ 12.0, 320.81, 34_777.259],
|
|
377
|
+
[ 12.0, 287.11, 31_931.756],
|
|
378
|
+
[ 12.0, 95.39, 14_577.848],
|
|
379
|
+
[ 14.0, 199.76, 31_436.921],
|
|
380
|
+
[ 16.0, 198.04, 62_894.029],
|
|
381
|
+
[ 17.0, 288.79, 4_562.452],
|
|
382
|
+
[ 18.0, 155.12, 67_555.328],
|
|
383
|
+
[ 29.0, 60.93, 4_443.417],
|
|
384
|
+
[ 44.0, 325.15, 31_555.956],
|
|
385
|
+
[ 45.0, 247.54, 29_929.562],
|
|
386
|
+
[ 50.0, 21.02, 2_281.226],
|
|
387
|
+
[ 52.0, 297.17, 150.678],
|
|
388
|
+
[ 58.0, 119.81, 33_718.147],
|
|
389
|
+
[ 70.0, 243.58, 9_037.513],
|
|
390
|
+
[ 74.0, 296.72, 3_034.906],
|
|
391
|
+
[ 77.0, 222.54, 65_928.934],
|
|
392
|
+
[136.0, 171.52, 22_518.443],
|
|
393
|
+
[156.0, 73.14, 45_036.886],
|
|
394
|
+
[182.0, 27.85, 445_267.112],
|
|
395
|
+
[199.0, 342.08, 20.186],
|
|
396
|
+
[203.0, 337.23, 32_964.467],
|
|
397
|
+
[485.0, 324.96, 1_934.136]
|
|
398
|
+
]
|
|
399
|
+
# :startdoc:
|
|
400
|
+
|
|
401
|
+
# Compute date and time of Vernal Equinox for given year.
|
|
402
|
+
# Implementation of low accuracy algorithm in chapter 27.
|
|
403
|
+
# Good from about -1000 to +3000.
|
|
404
|
+
# Returns DateTime of Vernal Equinox.
|
|
405
|
+
#
|
|
406
|
+
# Example: date of Vernal Equinox of 1999.
|
|
407
|
+
# Astro.date_of_vernal_equinox_low_accuracy(1999).asctime # => "Sun Mar 21 01:46:59 1999"
|
|
408
|
+
def Astro.date_of_vernal_equinox_low_accuracy(year)
|
|
409
|
+
if year >= 1000 # +1000 to +3000
|
|
410
|
+
y = (year - 2000.0) / 1000.0
|
|
411
|
+
|
|
412
|
+
# Julian day of March mean equinox
|
|
413
|
+
jdme = [-0.000_57, -0.004_11, 0.051_69, 365_242.374_04, 2_451_623.809_84].poly_eval(y)
|
|
414
|
+
|
|
415
|
+
else # -1000 to +1000
|
|
416
|
+
y = year/1000.0
|
|
417
|
+
|
|
418
|
+
# Julian day of March mean equinox
|
|
419
|
+
jdme = [-0.000_71, 0.001_11, 0.061_34, 365_242.137_40, 1_721_139.291_89].poly_eval(y)
|
|
420
|
+
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
# Julian centuries from 2000
|
|
424
|
+
t = (jdme - 2_451_545.0) / 36525.0
|
|
425
|
+
|
|
426
|
+
w = (35_999.373 * t - 2.47).to_rad
|
|
427
|
+
lambda = 1.0 + 0.0334*Math.cos(w) + 0.0007 * Math.cos(2.0 * w)
|
|
428
|
+
s = Table_27C.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos((b + c*t).to_rad)}
|
|
429
|
+
|
|
430
|
+
ve = jdme + 0.000_01 * s / lambda
|
|
431
|
+
|
|
432
|
+
DateTime.jd(ve.to_r, 12)
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
# Compute date and time of Vernal Equinox for given year.
|
|
436
|
+
# Implementation of higher accuracy algorithm in chapter 27.
|
|
437
|
+
# Returns DateTime of Vernal Equinox.
|
|
438
|
+
#
|
|
439
|
+
# Example: date of Vernal Equinox of 1999.
|
|
440
|
+
# Astro.date_of_vernal_equinox(1999).asctime # => "Sun Mar 21 01:46:56 1999"
|
|
441
|
+
def Astro.date_of_vernal_equinox(year)
|
|
442
|
+
est_date = date_of_vernal_equinox_low_accuracy(year)
|
|
443
|
+
|
|
444
|
+
5.times do |i|
|
|
445
|
+
sol_long = solar_longitude(est_date)
|
|
446
|
+
sol_long -= 360.0 if sol_long > 180.0
|
|
447
|
+
break if sol_long.abs < 0.000001
|
|
448
|
+
est_date += (58 * Math.sin(-sol_long.to_rad)).to_r
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
est_date
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
# :stopdoc:
|
|
456
|
+
# Solar Coordinates
|
|
457
|
+
Table_22A = [
|
|
458
|
+
# D M M' F omega coef of sin
|
|
459
|
+
[ 2, -1, 0, 2, 2, -3, 0],
|
|
460
|
+
[ 0, 0, 3, 2, 2, -3, 0],
|
|
461
|
+
[ 2, -1, -1, 2, 2, -3, 0],
|
|
462
|
+
[ 0, -1, 1, 2, 2, -3, 0],
|
|
463
|
+
[ 0, 1, 1, 0, 0, -3, 0],
|
|
464
|
+
[-1, -1, 1, 0, 0, -3, 0],
|
|
465
|
+
[ 0, 0, -2, 2, 2, -3, 0],
|
|
466
|
+
[ 0, 0, 1, 2, 0, 3, 0],
|
|
467
|
+
[ 1, 0, 0, 0, 0, -4, 0],
|
|
468
|
+
[-2, 1, 0, 0, 0, -4, 0],
|
|
469
|
+
[-1, 0, 1, 0, 0, -4, 0],
|
|
470
|
+
[ 0, 0, 1, -2, 0, 4, 0],
|
|
471
|
+
[-2, 1, 0, 2, 1, 4, 0],
|
|
472
|
+
[-2, 0, 2, 0, 1, 4, 0],
|
|
473
|
+
[ 0, 0, 2, 2, 1, -5, 0],
|
|
474
|
+
[-2, 0, 0, 0, 1, -5, 0],
|
|
475
|
+
[-2, -1, 0, 2, 1, -5, 0],
|
|
476
|
+
[ 0, -1, 1, 0, 0, 5, 0],
|
|
477
|
+
[ 2, 0, 0, 0, 1, -6, 0],
|
|
478
|
+
[ 2, 0, -2, 0, 1, -6, 0],
|
|
479
|
+
[-2, 0, 1, 2, 1, 6, 0],
|
|
480
|
+
[-2, 0, 2, 2, 2, 6, 0],
|
|
481
|
+
[ 2, 0, 1, 0, 0, 6, 0],
|
|
482
|
+
[ 2, 0, 0, 2, 1, -7, 0],
|
|
483
|
+
[ 0, -1, 0, 2, 2, -7, 0],
|
|
484
|
+
[-2, 1, 1, 0, 0, -7, 0],
|
|
485
|
+
[ 0, 1, 0, 2, 2, 7, 0],
|
|
486
|
+
[ 2, 0, 1, 2, 2, -8, 0],
|
|
487
|
+
[ 2, 0, -1, 2, 1, -10, 0],
|
|
488
|
+
[ 0, 0, 2, -2, 0, 11, 0],
|
|
489
|
+
[ 0, -1, 0, 0, 1, -12, 0],
|
|
490
|
+
[-2, 0, 1, 0, 1, -13, 0],
|
|
491
|
+
[ 0, 1, 0, 0, 1, -15, 0],
|
|
492
|
+
[-2, 2, 0, 2, 2, -16, 0.1],
|
|
493
|
+
[ 2, 0, -1, 0, 1, 16, 0],
|
|
494
|
+
[ 0, 2, 0, 0, 0, 17, -0.1],
|
|
495
|
+
[ 0, 0, -1, 2, 1, 21, 0],
|
|
496
|
+
[-2, 0, 0, 2, 0, -22, 0],
|
|
497
|
+
[ 0, 0, 0, 2, 0, 26, 0],
|
|
498
|
+
[-2, 0, 1, 2, 2, 29, 0],
|
|
499
|
+
[ 0, 0, 2, 0, 0, 29, 0],
|
|
500
|
+
[ 0, 0, 2, 2, 2, -31, 0],
|
|
501
|
+
[ 2, 0, 0, 2, 2, -38, 0],
|
|
502
|
+
[ 0, 0, -2, 2, 1, 46, 0],
|
|
503
|
+
[-2, 0, 2, 0, 0, 48, 0],
|
|
504
|
+
[ 0, 0, 1, 2, 1, -51, 0],
|
|
505
|
+
[ 0, 0, -1, 0, 1, -58, -0.1],
|
|
506
|
+
[ 2, 0, -1, 2, 2, -59, 0],
|
|
507
|
+
[ 0, 0, 1, 0, 1, 63, 0.1],
|
|
508
|
+
[ 2, 0, 0, 0, 0, 63, 0],
|
|
509
|
+
[ 0, 0, -1, 2, 2, 123, 0],
|
|
510
|
+
[-2, 0, 0, 2, 1, 129, 0.1],
|
|
511
|
+
[-2, 0, 1, 0, 0, -158, 0],
|
|
512
|
+
[-2, -1, 0, 2, 2, 217, -0.5],
|
|
513
|
+
[ 0, 0, 1, 2, 2, -301, 0],
|
|
514
|
+
[ 0, 0, 0, 2, 1, -386, -0.4],
|
|
515
|
+
[-2, 1, 0, 2, 2, -517, 1.2],
|
|
516
|
+
[ 0, 0, 1, 0, 0, 712, 0.1],
|
|
517
|
+
[ 0, 1, 0, 0, 0, 1426, -3.4],
|
|
518
|
+
[ 0, 0, 0, 0, 2, 2062, 0.2],
|
|
519
|
+
[ 0, 0, 0, 2, 2, -2274, -0.2],
|
|
520
|
+
[-2, 0, 0, 2, 2, -13187, -1.6],
|
|
521
|
+
[ 0, 0, 0, 0, 1, -171996, -174.2]
|
|
522
|
+
]
|
|
523
|
+
# :startdoc:
|
|
524
|
+
|
|
525
|
+
# Compute nutation in longitude of Earth's pole for the given DateTime.
|
|
526
|
+
# Implementation of algorithm in chapter 22.
|
|
527
|
+
# Returns nutation in degrees.
|
|
528
|
+
def Astro.nutation_in_longitude(date)
|
|
529
|
+
|
|
530
|
+
# Julian centuries from the epoch J2000.0
|
|
531
|
+
t = (date.ajd.to_f - 2451545.0)/36525.0
|
|
532
|
+
|
|
533
|
+
# Mean elongation of the Moon from the Sun
|
|
534
|
+
d = [1.0/189_474.0, -0.001_9142, 445_267.111_480, 297.85036].poly_eval(t) % 360.0
|
|
535
|
+
|
|
536
|
+
# Mean anomaly of the Sun (Earth)
|
|
537
|
+
m = [-1.0/300_000.0, -0.000_1603, 35_999.050_340, 357.52772].poly_eval(t) % 360.0
|
|
538
|
+
|
|
539
|
+
# Mean anomaly of the Moon
|
|
540
|
+
m_lun = [1.0/56_250.0, 0.008_6972, 477_198.867_398, 134.96298].poly_eval(t) %360.0
|
|
541
|
+
|
|
542
|
+
# Moon's argument of latitude
|
|
543
|
+
f = [1.0/327_270.0, -0.003_6825, 483_202.017_538, 93.27191].poly_eval(t) % 360.0
|
|
544
|
+
|
|
545
|
+
# Longitude of the ascending node of the Moon's mean orbit on the ecliptic
|
|
546
|
+
omega = [1.0/450_000.0, 0.002_0708, -1934.136_261, 125.04452].poly_eval(t) % 360.0
|
|
547
|
+
|
|
548
|
+
nutation = 0.0
|
|
549
|
+
for term in Table_22A do
|
|
550
|
+
nutation += (term[5] + term[6]*t) *
|
|
551
|
+
Math.sin((term[0]*d + term[1]*m + term[2]*m_lun + term[3]*f + term[4]*omega).to_rad) / 36_000_000.0
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
nutation
|
|
555
|
+
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
# Compute longitude of the Sun for the given DateTime.
|
|
559
|
+
# Implementation of low accuracy algorithm in chapter 25.
|
|
560
|
+
# Returns longitude in degrees.
|
|
561
|
+
def Astro.solar_longitude_low_accuracy(date)
|
|
562
|
+
|
|
563
|
+
# t = Julian centuries from the epoch J2000.0 (2000 January 1.5 TD)
|
|
564
|
+
t = (date.ajd.to_f - 2451545.0)/36525.0
|
|
565
|
+
|
|
566
|
+
# Mean longitude of the Sun
|
|
567
|
+
mean_long = [0.000_3032, 36_000.769_83, 280.46646].poly_eval(t) % 360.0
|
|
568
|
+
|
|
569
|
+
# Mean anomaly of the Sun
|
|
570
|
+
mean_anomaly = [-0.000_1537, 35_999.050_29, 357.52911].poly_eval(t) % 360.0
|
|
571
|
+
|
|
572
|
+
# Center of the sun
|
|
573
|
+
m_rad = mean_anomaly.to_rad
|
|
574
|
+
c = [-0.000_014, -0.004_817, 1.914_602].poly_eval(t) * Math.sin(m_rad) +
|
|
575
|
+
[-0.000_101, 0.019_993].poly_eval(t) * Math.sin(2.0 * m_rad) +
|
|
576
|
+
0.000_289 * Math.sin(3.0 * m_rad)
|
|
577
|
+
|
|
578
|
+
# True longitude
|
|
579
|
+
true_long = (mean_long + c) % 360.0
|
|
580
|
+
|
|
581
|
+
# Longitude corrected for nutation and the aberration
|
|
582
|
+
omega = (125.04 - 1934.136*t) % 360.0
|
|
583
|
+
apparent_long = (true_long - 0.00569 - 0.00478 * Math.sin(omega.to_rad)) % 360.0
|
|
584
|
+
apparent_long
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
# :stopdoc:
|
|
589
|
+
# Helio-centric coordinates of Earth
|
|
590
|
+
EarthL0 = [
|
|
591
|
+
# A B C
|
|
592
|
+
[ 25.0, 3.16, 4_690.48 ],
|
|
593
|
+
[ 30.0, 2.74, 1_349.87 ],
|
|
594
|
+
[ 30.0, 0.44, 83_996.85 ],
|
|
595
|
+
[ 33.0, 0.59, 17_789.85 ],
|
|
596
|
+
[ 36.0, 1.78, 6_812.77 ],
|
|
597
|
+
[ 36.0, 1.71, 2_352.87 ],
|
|
598
|
+
[ 37.0, 2.57, 1_059.38 ],
|
|
599
|
+
[ 37.0, 6.04, 10_213.29 ],
|
|
600
|
+
[ 39.0, 6.17, 10_447.39 ],
|
|
601
|
+
[ 41.0, 2.40, 19_651.05 ],
|
|
602
|
+
[ 41.0, 5.37, 8_429.24 ],
|
|
603
|
+
[ 49.0, 0.49, 1_194.45 ],
|
|
604
|
+
[ 51.0, 0.28, 5_856.48 ],
|
|
605
|
+
[ 52.0, 1.33, 1_748.02 ],
|
|
606
|
+
[ 52.0, 0.19, 12_139.55 ],
|
|
607
|
+
[ 56.0, 3.47, 6_279.55 ],
|
|
608
|
+
[ 56.0, 4.39, 14_143.50 ],
|
|
609
|
+
[ 57.0, 2.78, 6_286.60 ],
|
|
610
|
+
[ 61.0, 1.82, 7_084.90 ],
|
|
611
|
+
[ 62.0, 3.98, 8_827.39 ],
|
|
612
|
+
[ 70.0, 0.83, 9_437.76 ],
|
|
613
|
+
[ 74.0, 4.68, 801.82 ],
|
|
614
|
+
[ 74.0, 3.50, 3_154.69 ],
|
|
615
|
+
[ 75.0, 1.76, 5_088.63 ],
|
|
616
|
+
[ 79.0, 3.04, 12_036.46 ],
|
|
617
|
+
[ 80.0, 1.81, 17_260.15 ],
|
|
618
|
+
[ 85.0, 3.67, 71_430.70 ],
|
|
619
|
+
[ 85.0, 1.30, 6_275.96 ],
|
|
620
|
+
[ 86.0, 5.98, 161_000.69 ],
|
|
621
|
+
[ 98.0, 0.68, 155.42 ],
|
|
622
|
+
[ 99.0, 6.21, 2_146.17 ],
|
|
623
|
+
[ 102.0, 4.267, 7.114 ],
|
|
624
|
+
[ 102.0, 0.976, 15_720.839 ],
|
|
625
|
+
[ 103.0, 0.636, 4_694.003 ],
|
|
626
|
+
[ 115.0, 0.645, 0.980 ],
|
|
627
|
+
[ 126.0, 1.083, 20.775 ],
|
|
628
|
+
[ 132.0, 3.411, 2_942.463 ],
|
|
629
|
+
[ 156.0, 0.833, 213.299 ],
|
|
630
|
+
[ 202.0, 2.458, 6_069.777 ],
|
|
631
|
+
[ 205.0, 1.869, 5_573.143 ],
|
|
632
|
+
[ 206.0, 4.806, 2_544.314 ],
|
|
633
|
+
[ 243.0, 0.345, 5_486.778 ],
|
|
634
|
+
[ 271.0, 0.315, 10_977.079 ],
|
|
635
|
+
[ 284.0, 1.899, 796.298 ],
|
|
636
|
+
[ 317.0, 5.849, 11_790.629 ],
|
|
637
|
+
[ 357.0, 2.920, 0.067 ],
|
|
638
|
+
[ 492.0, 4.205, 775.523 ],
|
|
639
|
+
[ 505.0, 4.583, 18_849.228 ],
|
|
640
|
+
[ 753.0, 2.533, 5_507.553 ],
|
|
641
|
+
[ 780.0, 1.179, 5_223.694 ],
|
|
642
|
+
[ 857.0, 3.508, 398.149 ],
|
|
643
|
+
[ 902.0, 2.045, 26.298 ],
|
|
644
|
+
[ 990.0, 5.233, 5_884.927 ],
|
|
645
|
+
[ 1_199.0, 1.109_6, 1_577.343_5 ],
|
|
646
|
+
[ 1_273.0, 2.037_1, 529.691_0 ],
|
|
647
|
+
[ 1_324.0, 0.742_5, 11_506.769_8 ],
|
|
648
|
+
[ 2_343.0, 6.135_2, 3_930.209_7 ],
|
|
649
|
+
[ 2_676.0, 4.418_1, 7_860.419_4 ],
|
|
650
|
+
[ 3_136.0, 3.627_7, 77_713.771_5 ],
|
|
651
|
+
[ 3_418.0, 2.828_9, 3.523_1 ],
|
|
652
|
+
[ 3_497.0, 2.744_1, 5_753.384_9 ],
|
|
653
|
+
[ 34_894.0, 4.626_10, 12_566.151_70 ],
|
|
654
|
+
[ 3_341_656.0, 4.669_256_8, 6_283.075_850_0 ],
|
|
655
|
+
[175_347_046.0, 0.0, 0.0 ]
|
|
656
|
+
]
|
|
657
|
+
|
|
658
|
+
EarthL1 = [
|
|
659
|
+
[ 6.0, 4.67, 4_690.48 ],
|
|
660
|
+
[ 6.0, 2.65, 9_437.76 ],
|
|
661
|
+
[ 8.0, 5.30, 2_352.87 ],
|
|
662
|
+
[ 9.0, 5.64, 951.72 ],
|
|
663
|
+
[ 9.0, 2.70, 242.73 ],
|
|
664
|
+
[ 10.0, 4.24, 1_349.87 ],
|
|
665
|
+
[ 10.0, 1.30, 6_286.60 ],
|
|
666
|
+
[ 11.0, 0.77, 553.57 ],
|
|
667
|
+
[ 12.0, 2.08, 4_694.00 ],
|
|
668
|
+
[ 12.0, 5.27, 1_194.45 ],
|
|
669
|
+
[ 12.0, 3.26, 5_088.63 ],
|
|
670
|
+
[ 12.0, 2.83, 1_748.02 ],
|
|
671
|
+
[ 15.0, 1.21, 10_977.08 ],
|
|
672
|
+
[ 16.0, 1.43, 2_146.17 ],
|
|
673
|
+
[ 16.0, 0.03, 2_544.31 ],
|
|
674
|
+
[ 17.0, 2.99, 6_275.96 ],
|
|
675
|
+
[ 19.0, 4.97, 213.30 ],
|
|
676
|
+
[ 19.0, 1.85, 5_486.78 ],
|
|
677
|
+
[ 21.0, 5.34, 0.98 ],
|
|
678
|
+
[ 29.0, 2.65, 7.11 ],
|
|
679
|
+
[ 36.0, 0.47, 775.52 ],
|
|
680
|
+
[ 45.0, 0.40, 796.30 ],
|
|
681
|
+
[ 56.0, 2.17, 155.42 ],
|
|
682
|
+
[ 59.0, 2.89, 5_223.69 ],
|
|
683
|
+
[ 67.0, 4.41, 5_507.55 ],
|
|
684
|
+
[ 68.0, 1.87, 398.15 ],
|
|
685
|
+
[ 72.0, 1.14, 529.69 ],
|
|
686
|
+
[ 93.0, 2.59, 18_849.23 ],
|
|
687
|
+
[ 109.0, 2.966, 1_577.344 ],
|
|
688
|
+
[ 119.0, 5.796, 26.298 ],
|
|
689
|
+
[ 425.0, 1.590, 3.523 ],
|
|
690
|
+
[ 4_303.0, 2.635_1, 12_566.151_7 ],
|
|
691
|
+
[ 206_059.0, 2.678_235, 6_283.075_850],
|
|
692
|
+
[628_331_966_747.0, 0.0, 0.0 ]
|
|
693
|
+
]
|
|
694
|
+
|
|
695
|
+
EarthL2 = [
|
|
696
|
+
[ 2.0, 3.75, 0.98 ],
|
|
697
|
+
[ 2.0, 4.38, 5_233.69 ],
|
|
698
|
+
[ 3.0, 2.28, 553.57 ],
|
|
699
|
+
[ 3.0, 0.31, 398.15 ],
|
|
700
|
+
[ 3.0, 6.12, 529.69 ],
|
|
701
|
+
[ 3.0, 1.19, 242.73 ],
|
|
702
|
+
[ 3.0, 6.05, 5_507.55 ],
|
|
703
|
+
[ 3.0, 5.14, 796.30 ],
|
|
704
|
+
[ 4.0, 3.44, 5_573.14 ],
|
|
705
|
+
[ 4.0, 1.03, 7.11 ],
|
|
706
|
+
[ 5.0, 4.66, 1_577.34 ],
|
|
707
|
+
[ 7.0, 0.83, 775.52 ],
|
|
708
|
+
[ 9.0, 2.06, 77_713.77 ],
|
|
709
|
+
[ 10.0, 0.76, 18_849.23 ],
|
|
710
|
+
[ 16.0, 3.68, 155.42 ],
|
|
711
|
+
[ 16.0, 5.19, 26.30 ],
|
|
712
|
+
[ 27.0, 0.05, 3.52 ],
|
|
713
|
+
[ 309.0, 0.867, 12_566.152 ],
|
|
714
|
+
[ 8_720.0, 1.072_1, 6_283.075_8],
|
|
715
|
+
[52_919.0, 0.0, 0.0 ]
|
|
716
|
+
]
|
|
717
|
+
|
|
718
|
+
EarthL3 = [
|
|
719
|
+
[ 1.0, 5.97, 242.73 ],
|
|
720
|
+
[ 1.0, 5.30, 18_849.23 ],
|
|
721
|
+
[ 1.0, 4.72, 3.52 ],
|
|
722
|
+
[ 3.0, 5.20, 155.42 ],
|
|
723
|
+
[ 17.0, 5.49, 12_566.15 ],
|
|
724
|
+
[ 35.0, 0.0, 0.0 ],
|
|
725
|
+
[289.0, 5.844, 6_283.076]
|
|
726
|
+
]
|
|
727
|
+
|
|
728
|
+
EarthL4 = [
|
|
729
|
+
[ 1.0, 3.84, 12_566.15],
|
|
730
|
+
[ 8.0, 4.13, 6_283.08],
|
|
731
|
+
[114.0, 3.142, 0.0 ]
|
|
732
|
+
]
|
|
733
|
+
|
|
734
|
+
EarthL5 = [
|
|
735
|
+
[ 1.0, 3.14, 0.0]
|
|
736
|
+
]
|
|
737
|
+
|
|
738
|
+
EarthR0 = [
|
|
739
|
+
[ 26, 4.59, 10_447.39 ],
|
|
740
|
+
[ 28, 1.90, 6_279.55 ],
|
|
741
|
+
[ 28, 1.21, 6_286.60 ],
|
|
742
|
+
[ 32, 1.78, 398.15 ],
|
|
743
|
+
[ 32, 0.18, 5_088.63 ],
|
|
744
|
+
[ 33, 0.24, 7_084.90 ],
|
|
745
|
+
[ 35, 1.84, 2_942.46 ],
|
|
746
|
+
[ 36, 1.67, 12_036.46 ],
|
|
747
|
+
[ 37, 4.90, 12_139.55 ],
|
|
748
|
+
[ 37, 0.83, 19_651.05 ],
|
|
749
|
+
[ 38, 2.39, 8_827.39 ],
|
|
750
|
+
[ 39, 5.36, 4_694.00 ],
|
|
751
|
+
[ 43, 6.01, 6_275.96 ],
|
|
752
|
+
[ 45, 5.54, 9_437.76 ],
|
|
753
|
+
[ 47, 2.58, 775.52 ],
|
|
754
|
+
[ 49, 3.25, 2_544.31 ],
|
|
755
|
+
[ 56, 5.24, 71_430.70 ],
|
|
756
|
+
[ 57, 2.01, 83_996.85 ],
|
|
757
|
+
[ 63, 0.92, 529.69 ],
|
|
758
|
+
[ 65, 0.27, 17_260.15 ],
|
|
759
|
+
[ 86, 1.27, 161_000.69 ],
|
|
760
|
+
[ 86, 5.69, 15_720.84 ],
|
|
761
|
+
[ 98, 0.89, 6_069.78 ],
|
|
762
|
+
[ 110, 5.055, 5_486.778 ],
|
|
763
|
+
[ 175, 3.012, 18_849.228 ],
|
|
764
|
+
[ 186, 5.022, 10_977.079 ],
|
|
765
|
+
[ 212, 5.847, 1_577.344 ],
|
|
766
|
+
[ 243, 4.273, 11_790.629 ],
|
|
767
|
+
[ 307, 0.299, 5_573.143 ],
|
|
768
|
+
[ 329, 5.900, 5_223.694 ],
|
|
769
|
+
[ 346, 0.964, 5_507.553 ],
|
|
770
|
+
[ 472, 3.661, 5_884.927 ],
|
|
771
|
+
[ 542, 4.564, 3_930.210 ],
|
|
772
|
+
[ 925, 5.453, 11_506.770 ],
|
|
773
|
+
[ 1_576, 2.846_9, 7_860.419_4 ],
|
|
774
|
+
[ 1_628, 1.173_9, 5_753.384_9 ],
|
|
775
|
+
[ 3_084, 5.198_5, 77_713.771_5 ],
|
|
776
|
+
[ 13_956, 3.055_25, 12_566.151_70 ],
|
|
777
|
+
[ 1_670_700, 3.098_463_5, 6_283.075_850_0],
|
|
778
|
+
[100_013_989, 0, 0 ]
|
|
779
|
+
]
|
|
780
|
+
|
|
781
|
+
EarthR1 = [
|
|
782
|
+
[ 9, 0.27, 5_486.78 ],
|
|
783
|
+
[ 9, 1.42, 6_275.96 ],
|
|
784
|
+
[ 10, 5.91, 10_977.08 ],
|
|
785
|
+
[ 18, 1.42, 1_577.34 ],
|
|
786
|
+
[ 25, 1.32, 5_223.69 ],
|
|
787
|
+
[ 31, 2.84, 5_507.55 ],
|
|
788
|
+
[ 32, 1.02, 18_849.23 ],
|
|
789
|
+
[ 702, 3.142, 0 ],
|
|
790
|
+
[ 1_721, 1.064_4, 12_566.151_7 ],
|
|
791
|
+
[103_019, 1.107_490, 6_283.075_850]
|
|
792
|
+
]
|
|
793
|
+
|
|
794
|
+
EarthR2 = [
|
|
795
|
+
[ 3, 5.47, 18_849.23 ],
|
|
796
|
+
[ 6, 1.87, 5_573.14 ],
|
|
797
|
+
[ 9, 3.63, 77_713.77 ],
|
|
798
|
+
[ 12, 3.14, 0 ],
|
|
799
|
+
[ 124, 5.579, 12_566.152 ],
|
|
800
|
+
[4_359, 5.784_6, 6_283.075_8]
|
|
801
|
+
]
|
|
802
|
+
|
|
803
|
+
EarthR3 = [
|
|
804
|
+
[ 7, 3.92, 12_566.15 ],
|
|
805
|
+
[145, 4.273, 6_283.076]
|
|
806
|
+
]
|
|
807
|
+
|
|
808
|
+
EarthR4 = [
|
|
809
|
+
[4, 2.56, 6_283.08]
|
|
810
|
+
]
|
|
811
|
+
# :startdoc:
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
# Compute longitude of Sun for given DateTime.
|
|
815
|
+
# Implementation of higher accuracy algorithm in chapter 25.
|
|
816
|
+
# Accurate to within 1" between the years -2000 and +6000.
|
|
817
|
+
# Returns longitude in degrees.
|
|
818
|
+
def Astro.solar_longitude(date)
|
|
819
|
+
|
|
820
|
+
# t = Julian millennia from the epoch J2000.0 (2000 January 1.5 TD)
|
|
821
|
+
t = (date.ajd.to_f - 2451545.0)/365250.0
|
|
822
|
+
|
|
823
|
+
l0 = EarthL0.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos(b + c*t)}
|
|
824
|
+
l1 = EarthL1.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos(b + c*t)}
|
|
825
|
+
l2 = EarthL2.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos(b + c*t)}
|
|
826
|
+
l3 = EarthL3.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos(b + c*t)}
|
|
827
|
+
l4 = EarthL4.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos(b + c*t)}
|
|
828
|
+
l5 = EarthL5.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos(b + c*t)}
|
|
829
|
+
long = (([l5, l4, l3, l2, l1, l0].poly_eval(t) * 1e-8).to_deg) % 360.0
|
|
830
|
+
|
|
831
|
+
r0 = EarthR0.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos(b + c*t)}
|
|
832
|
+
r1 = EarthR1.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos(b + c*t)}
|
|
833
|
+
r2 = EarthR2.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos(b + c*t)}
|
|
834
|
+
r3 = EarthR3.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos(b + c*t)}
|
|
835
|
+
r4 = EarthR4.inject(0.0) {|accum, (a, b, c)| accum + a * Math.cos(b + c*t)}
|
|
836
|
+
radius = [r4, r3, r2, r1, r0].poly_eval(t) * 1e-8
|
|
837
|
+
aberration = -0.0056916111/radius
|
|
838
|
+
|
|
839
|
+
long -= 180.0 # switch to Earth's perspective
|
|
840
|
+
long += -2.509167e-5 # convert to FK5 system
|
|
841
|
+
long += nutation_in_longitude(date)
|
|
842
|
+
long += aberration # correct for aberration
|
|
843
|
+
long % 360.0
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
end
|
data/lib/lunaryear.rb
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# lunaryear.rb
|
|
2
|
+
# Lunar calendar library.
|
|
3
|
+
#
|
|
4
|
+
# Lunar months (or moonths) begin on the day of the New Moon in Coordinated
|
|
5
|
+
# Universal Time.
|
|
6
|
+
#
|
|
7
|
+
# The lunar year begins at the beginning of the moonth during which the
|
|
8
|
+
# Vernal Equinox occurs, usually March 20 or 21. Twelve moonths fall short
|
|
9
|
+
# of the Solar year by about 10 or 11 days, so an additional thirteenth
|
|
10
|
+
# moonth occurs every two or three years.
|
|
11
|
+
|
|
12
|
+
require File.join(File.dirname(__FILE__), 'astro-algo')
|
|
13
|
+
|
|
14
|
+
module LunarYear
|
|
15
|
+
|
|
16
|
+
# Calculate the lunar calendar date for the given DateTime.
|
|
17
|
+
# Returns [year, moonth, day].
|
|
18
|
+
def LunarYear.lunar_date(date)
|
|
19
|
+
year = date.year
|
|
20
|
+
lun0 = LunarYear.new_moon_before_vernal_equinox(year) # Year begins at Vernal Equinox
|
|
21
|
+
if date < Astro.date_of_moon(lun0, Astro::PhaseNew).to_date
|
|
22
|
+
year -= 1
|
|
23
|
+
lun0 = new_moon_before_vernal_equinox(year)
|
|
24
|
+
end
|
|
25
|
+
prev_moon = Astro.date_of_moon(lun0, Astro::PhaseNew).to_date
|
|
26
|
+
lun = lun0
|
|
27
|
+
loop do
|
|
28
|
+
lun += 1
|
|
29
|
+
new_moon = Astro.date_of_moon(lun, Astro::PhaseNew).to_date
|
|
30
|
+
break if new_moon > date
|
|
31
|
+
prev_moon = new_moon
|
|
32
|
+
end
|
|
33
|
+
moonth = lun - lun0 - 1
|
|
34
|
+
day = (date - prev_moon).to_i
|
|
35
|
+
[year, moonth, day]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Find number of lunation (New Moon) just before Vernal Equinox for a given year.
|
|
40
|
+
# Lunation 0 is the first New Moon in the year 2000.
|
|
41
|
+
# Returns an integer lunation number.
|
|
42
|
+
#
|
|
43
|
+
# Example: first lunation before Vernal Equinox of the year 1984.
|
|
44
|
+
# LunarYear.new_moon_before_vernal_equinox(1984) # => -196
|
|
45
|
+
def LunarYear.new_moon_before_vernal_equinox(year)
|
|
46
|
+
equ = Astro.date_of_vernal_equinox(year)
|
|
47
|
+
lunation = Astro.first_lunation_of_year(year)
|
|
48
|
+
new_moon = Astro.date_of_moon(lunation, Astro::PhaseNew)
|
|
49
|
+
loop do
|
|
50
|
+
previous_new_moon = new_moon
|
|
51
|
+
lunation += 1
|
|
52
|
+
new_moon = Astro.date_of_moon(lunation, Astro::PhaseNew)
|
|
53
|
+
return lunation-1 if new_moon > equ
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Calculate the DateTime of the previous New and Full Moons
|
|
59
|
+
# and the DateTime of the next New and Full moons.
|
|
60
|
+
# Returns [previous New Moon, next New Moon, previous Full Moon, next Full Moon]
|
|
61
|
+
#
|
|
62
|
+
# Example: For November 18, 2007, calculate the date and time of the previous New Moon,
|
|
63
|
+
# the next New Moon, the previous Full Moon, and the next Full Moon.
|
|
64
|
+
# LunarYear.date_of_moons(DateTime.civil(2007, 11, 18)).collect {|d| d.asctime}
|
|
65
|
+
# #=> ["Fri Nov 9 23:03:07 2007", "Sun Dec 9 17:40:21 2007", "Fri Oct 26 04:51:33 2007", "Sat Nov 24 14:29:47 2007"]
|
|
66
|
+
def LunarYear.date_of_moons(date)
|
|
67
|
+
next_new_moon = nil
|
|
68
|
+
next_full_moon = nil
|
|
69
|
+
|
|
70
|
+
k = ((date.year - 2000)*12.3685).floor - 1
|
|
71
|
+
prev_new_moon = Astro.date_of_moon(k, Astro::PhaseNew).to_utc
|
|
72
|
+
lun = k
|
|
73
|
+
loop do
|
|
74
|
+
lun += 1
|
|
75
|
+
next_new_moon = Astro.date_of_moon(lun, Astro::PhaseNew).to_utc
|
|
76
|
+
break if next_new_moon > date
|
|
77
|
+
prev_new_moon = next_new_moon
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
lun = k
|
|
81
|
+
prev_full_moon = Astro.date_of_moon(k, Astro::PhaseFull).to_utc
|
|
82
|
+
loop do
|
|
83
|
+
lun += 1
|
|
84
|
+
next_full_moon = Astro.date_of_moon(lun, Astro::PhaseFull).to_utc
|
|
85
|
+
break if next_full_moon > date
|
|
86
|
+
prev_full_moon = next_full_moon
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
[prev_new_moon, next_new_moon, prev_full_moon, next_full_moon]
|
|
90
|
+
end
|
|
91
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: astro-algo
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ""
|
|
6
|
+
authors:
|
|
7
|
+
- John P. Powers
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
|
|
12
|
+
date: 2007-11-27 00:00:00 -06:00
|
|
13
|
+
default_executable:
|
|
14
|
+
dependencies: []
|
|
15
|
+
|
|
16
|
+
description: This library implements algorithms from Jean Meeus, Astronomical Algorithms, 2nd English Edition, Willmann-Bell, Inc., Richmond, Virginia, 1999, with corrections as of June 15, 2005.
|
|
17
|
+
email: john@jppowers.net
|
|
18
|
+
executables:
|
|
19
|
+
- equinox
|
|
20
|
+
- lunarcalendar
|
|
21
|
+
- moon_clock.rb
|
|
22
|
+
- moons
|
|
23
|
+
extensions: []
|
|
24
|
+
|
|
25
|
+
extra_rdoc_files: []
|
|
26
|
+
|
|
27
|
+
files:
|
|
28
|
+
- bin/moon_clock.rb
|
|
29
|
+
- lib/astro-algo.rb
|
|
30
|
+
- lib/lunaryear.rb
|
|
31
|
+
- README
|
|
32
|
+
- bin/equinox
|
|
33
|
+
- bin/lunarcalendar
|
|
34
|
+
- bin/moons
|
|
35
|
+
has_rdoc: true
|
|
36
|
+
homepage: http://astro-algo.rubyforge.org/astro-algo
|
|
37
|
+
post_install_message:
|
|
38
|
+
rdoc_options:
|
|
39
|
+
- --title
|
|
40
|
+
- Astro API documentation
|
|
41
|
+
- --main
|
|
42
|
+
- README
|
|
43
|
+
require_paths:
|
|
44
|
+
- lib
|
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: "0"
|
|
50
|
+
version:
|
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: "0"
|
|
56
|
+
version:
|
|
57
|
+
requirements: []
|
|
58
|
+
|
|
59
|
+
rubyforge_project: astro-algo
|
|
60
|
+
rubygems_version: 0.9.5
|
|
61
|
+
signing_key:
|
|
62
|
+
specification_version: 2
|
|
63
|
+
summary: Implementation of algorithms in _Astronomical Algorithms_. Useful for computing phases of the moon.
|
|
64
|
+
test_files: []
|
|
65
|
+
|