equationoftime 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.md +22 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +80 -0
  8. data/README2.txt +70 -0
  9. data/Rakefile +80 -0
  10. data/doc/GeoLatLng.html +770 -0
  11. data/doc/_index.html +123 -0
  12. data/doc/class_list.html +54 -0
  13. data/doc/css/common.css +1 -0
  14. data/doc/css/full_list.css +57 -0
  15. data/doc/css/style.css +339 -0
  16. data/doc/file.README.html +179 -0
  17. data/doc/file_list.html +56 -0
  18. data/doc/frames.html +26 -0
  19. data/doc/index.html +179 -0
  20. data/doc/js/app.js +219 -0
  21. data/doc/js/full_list.js +178 -0
  22. data/doc/js/jquery.js +4 -0
  23. data/doc/method_list.html +611 -0
  24. data/doc/top-level-namespace.html +112 -0
  25. data/equationoftime.gemspec +35 -0
  26. data/examples/Equation_of_Time.jpg +0 -0
  27. data/examples/analemma_data_generator.rb +53 -0
  28. data/examples/check_date_type.rb +57 -0
  29. data/examples/compare_geoc_long_ra.rb +31 -0
  30. data/examples/data_table.rb +26 -0
  31. data/examples/earth_rotation.rb +13 -0
  32. data/examples/eot_methods_list.rb +16 -0
  33. data/examples/eot_plot.r +57 -0
  34. data/examples/eot_suntimes.rb +140 -0
  35. data/examples/equation_of_time.py +186 -0
  36. data/examples/figure_1.jpg +0 -0
  37. data/examples/file_converter.rb +31 -0
  38. data/examples/from_readme.rb +10 -0
  39. data/examples/geo_locator.rb +12 -0
  40. data/examples/getjd.rb +45 -0
  41. data/examples/input_suntimes.rb +21 -0
  42. data/examples/julian_day_formula.rb +29 -0
  43. data/examples/julian_day_formula.txt +12 -0
  44. data/examples/my_time_conversion.rb +21 -0
  45. data/examples/nutation_series.txt +678 -0
  46. data/examples/nutation_series.yaml +14239 -0
  47. data/examples/nutation_table5_3a.txt +682 -0
  48. data/examples/nutation_table5_3a.yaml +9532 -0
  49. data/examples/ptime.rb +162 -0
  50. data/examples/read_nutation_data.rb +399 -0
  51. data/examples/suntimes.rb +28 -0
  52. data/examples/suntimes_test.rb +47 -0
  53. data/examples/test_poly_eval.rb +38 -0
  54. data/examples/time_scales.rb +29 -0
  55. data/examples/usage_example.rb +13 -0
  56. data/examples/use_angles.rb +155 -0
  57. data/lib/eot/angles.rb +337 -0
  58. data/lib/eot/constants.rb +168 -0
  59. data/lib/eot/displays.rb +213 -0
  60. data/lib/eot/geo_lat_lng_smt.rb +80 -0
  61. data/lib/eot/init.rb +93 -0
  62. data/lib/eot/nutation.rb +70 -0
  63. data/lib/eot/nutation_table5_3a.yaml +9532 -0
  64. data/lib/eot/times.rb +130 -0
  65. data/lib/eot/utilities.rb +129 -0
  66. data/lib/eot/version.rb +6 -0
  67. data/lib/eot.rb +11 -0
  68. data/tests/minitest/aliased_angles_spec.rb +287 -0
  69. data/tests/minitest/aliased_displays_spec.rb +106 -0
  70. data/tests/minitest/aliased_times_spec.rb +36 -0
  71. data/tests/minitest/aliased_utilities_spec.rb +49 -0
  72. data/tests/minitest/angles_spec.rb +313 -0
  73. data/tests/minitest/constants_spec.rb +27 -0
  74. data/tests/minitest/delta_epsilon_spec.rb +35 -0
  75. data/tests/minitest/displays_spec.rb +111 -0
  76. data/tests/minitest/geo_spec.rb +36 -0
  77. data/tests/minitest/init_spec.rb +32 -0
  78. data/tests/minitest/nutation_spec.rb +33 -0
  79. data/tests/minitest/times_spec.rb +137 -0
  80. data/tests/minitest/utilities_spec.rb +121 -0
  81. data/tests/spec_config.rb +3 -0
  82. data/wiki.md +46 -0
  83. data/wiki2.md +4 -0
  84. metadata +240 -0
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ https://bitbucket.org/cmcqueen1975/sundials/src/26a0f54a7c18?at=default
4
+ Calculation of "equation of time".
5
+
6
+ References:
7
+ http://en.wikipedia.org/wiki/Equation_of_time
8
+ http://www.sundials.co.uk/equation.htm
9
+
10
+ Calculations have been done according to the Wikipedia reference.
11
+
12
+ Dependencies:
13
+ - Python 2.x
14
+ - NumPy
15
+ - SciPy (only strictly needed for the more accurate calculation)
16
+ - matplotlib to plot the graph
17
+ """
18
+
19
+ import datetime
20
+ from collections import namedtuple
21
+
22
+ import numpy as np
23
+ import scipy # only strictly needed for the more accurate calculation in equation_of_time_accurate()
24
+ import scipy.optimize
25
+
26
+ # Named tuple to hold geographic location
27
+ Location = namedtuple('Location', 'latitude, longitude')
28
+
29
+
30
+ # If a location is given, a longitude correction is calculated and included in the graph.
31
+ # If the sundial itself includes the longitude correction, just use the 0 value here.
32
+ LOCATION = Location(0, 0)
33
+ #LOCATION = Location(51.3809, -2.3603) # Bath, England
34
+ #LOCATION = Location(35.10, 138.86) # Numazu, Japan
35
+ #LOCATION = Location(-37.81, 144.96) # Melbourne, Victoria, Australia
36
+
37
+
38
+ DAYS_PER_TROPICAL_YEAR = 365.242
39
+ SUN_ECCENTRICITY = 0.01671
40
+
41
+ # The angle from the vernal equinox to the periapsis in the plane of the ecliptic.
42
+ SUN_ANGLE_OFFSET = 4.9358
43
+
44
+ # Angle of tilt of earth's axis--about 23.44 degrees
45
+ SUN_OBLIQUITY = 0.40910
46
+
47
+
48
+ # Date range for drawing a graph.
49
+ DATE_START = datetime.date(2009, 1, 1)
50
+ DATE_END = datetime.date(2010, 1, 1)
51
+ # Periapsis occurs on a slightly different date each year--varying by a couple
52
+ # of days. 4th of January is about the average.
53
+ DATE_PERIAPSIS = datetime.date(2009, 1, 4)
54
+
55
+
56
+ def longitude_offset(location):
57
+ """Given a location, return the offset due to longitude, in degrees
58
+ Location's longitude is used. Latitude isn't needed.
59
+ """
60
+ longitude = location.longitude
61
+ longitude_per_hour = (360. / 24)
62
+ longitude_offset = longitude % longitude_per_hour
63
+ if longitude_offset > longitude_per_hour / 2:
64
+ longitude_offset -= longitude_per_hour
65
+ return longitude_offset
66
+
67
+
68
+ def longitude_offset_min(location):
69
+ minute_per_longitude = 24 * 60 / 360.
70
+ return longitude_offset(location) * minute_per_longitude
71
+
72
+
73
+ def mean_anomaly(day_number_n):
74
+ """day_number_n is the number of days from periapsis."""
75
+ return day_number_n * (2 * np.pi / DAYS_PER_TROPICAL_YEAR)
76
+
77
+
78
+ @np.vectorize
79
+ def eccentric_anomaly(mean_anomaly_value):
80
+ local_sun_eccentricity = SUN_ECCENTRICITY
81
+
82
+ def eccentric_anomaly_function(eccentric_anomaly_value):
83
+ return eccentric_anomaly_value - local_sun_eccentricity * np.sin(eccentric_anomaly_value) - mean_anomaly_value
84
+
85
+ # eccentric_anomaly_value = scipy.optimize.brentq(eccentric_anomaly_function, 0 - 0.0001, 2 * np.pi + 0.0001)
86
+ eccentric_anomaly_value = scipy.optimize.fsolve(eccentric_anomaly_function, mean_anomaly_value)
87
+ return eccentric_anomaly_value
88
+
89
+
90
+ def true_anomaly(eccentric_anomaly_value):
91
+ local_sun_eccentricity = SUN_ECCENTRICITY
92
+
93
+ half_eccentric_anomaly = eccentric_anomaly_value / 2
94
+ a_x = np.cos(half_eccentric_anomaly)
95
+ a_y = np.sin(half_eccentric_anomaly)
96
+ a_y *= np.sqrt((1 + local_sun_eccentricity) / (1 - local_sun_eccentricity))
97
+ return 2 * np.arctan2(a_y, a_x)
98
+
99
+
100
+ def right_ascension(sun_angle):
101
+ """sun_angle is the angle from the vernal equinox to the Sun in the plane of the ecliptic.
102
+ It is the true_anomaly value plus the SUN_ANGLE_OFFSET."""
103
+ a_x = np.cos(sun_angle)
104
+ a_y = np.sin(sun_angle)
105
+ return np.arctan2(a_y * np.cos(SUN_OBLIQUITY), a_x)
106
+
107
+
108
+ def equation_of_time_accurate(day_number_n):
109
+ """Calculate the equation of time (in min), given a day number.
110
+
111
+ day_number_n is the number of days from periapsis.
112
+ Returns the difference between solar time and clock time, in minutes.
113
+ This uses a more accurate calculation.
114
+ """
115
+ mean_anomaly_value = mean_anomaly(day_number_n)
116
+ eccentric_anomaly_value = eccentric_anomaly(mean_anomaly_value)
117
+ true_anomaly_value = true_anomaly(eccentric_anomaly_value)
118
+ right_ascension_value = right_ascension(true_anomaly_value + SUN_ANGLE_OFFSET)
119
+ eot = mean_anomaly_value + SUN_ANGLE_OFFSET - right_ascension_value
120
+ # Get the angles into the range we want--that is, -pi to +pi
121
+ eot = (eot + np.pi) % (2 * np.pi) - np.pi
122
+ return eot * (24 * 60 / 2 / np.pi)
123
+
124
+
125
+ def equation_of_time_simple(day_number_n):
126
+ """Calculate the equation of time (in min), given a day number.
127
+
128
+ day_number_n is the number of days from periapsis.
129
+ Returns the difference between solar time and clock time, in minutes.
130
+ This uses a simple, approximate calculation.
131
+ """
132
+ mean_anomaly_value = mean_anomaly(day_number_n)
133
+ return -7.655 * np.sin(mean_anomaly_value) + 9.873 * np.sin(2 * mean_anomaly_value + 3.588)
134
+
135
+
136
+ #equation_of_time = equation_of_time_simple
137
+ equation_of_time = equation_of_time_accurate
138
+
139
+
140
+ def main():
141
+ import matplotlib
142
+ #matplotlib.use('pdf')
143
+ #matplotlib.use('svg')
144
+ from matplotlib import pyplot as plt
145
+
146
+
147
+ date_range = np.arange(matplotlib.dates.date2num(DATE_START), matplotlib.dates.date2num(DATE_END), 0.1)
148
+ day_numbers = date_range - matplotlib.dates.date2num(DATE_PERIAPSIS)
149
+
150
+ # Calculate the accurate and simple calculations of equation of time.
151
+ solar_offset_accurate_min = equation_of_time_accurate(day_numbers) + longitude_offset_min(LOCATION)
152
+ solar_offset_simple_min = equation_of_time_simple(day_numbers) + longitude_offset_min(LOCATION)
153
+
154
+ # Plot the graph, either solar vs clock, or vice-versa.
155
+ if 1:
156
+ # Solar time vs clock time
157
+ plt.plot_date(date_range, solar_offset_accurate_min, '-')
158
+ # plt.plot_date(date_range, solar_offset_simple_min, '--')
159
+ plt.ylabel('solar time - clock time (min)')
160
+ else:
161
+ # Clock time vs solar time
162
+ plt.plot_date(date_range, -solar_offset_accurate_min, '-')
163
+ # plt.plot_date(date_range, -solar_offset_simple_min, '--')
164
+ plt.ylabel('clock time - solar time (min)')
165
+
166
+ # Set month lines
167
+ ax = plt.subplot(111)
168
+ ax.xaxis.set_major_locator(matplotlib.dates.MonthLocator())
169
+ ax.xaxis.set_major_formatter(matplotlib.ticker.NullFormatter())
170
+ # Set month labels centred in the middle (actually on day 15) of each month.
171
+ ax.xaxis.set_minor_locator(matplotlib.dates.MonthLocator(bymonthday=15))
172
+ ax.xaxis.set_minor_formatter(matplotlib.dates.DateFormatter('%b'))
173
+ for tick in ax.xaxis.get_minor_ticks():
174
+ tick.tick1line.set_markersize(0)
175
+ tick.tick2line.set_markersize(0)
176
+
177
+ plt.grid(True)
178
+
179
+ plt.show()
180
+ # plt.savefig('equation_of_time.pdf')
181
+ # plt.savefig('equation_of_time.svg')
182
+ # plt.savefig('equation_of_time.png')
183
+
184
+
185
+ if __name__ == '__main__':
186
+ main()
Binary file
@@ -0,0 +1,31 @@
1
+ # the file this data comes from 'Circular_179.pdf' IAU 2000A Nutation Series
2
+ # the first 678 lines are for lunisolar data
3
+
4
+ require 'safe_yaml'
5
+
6
+ # make array elements from each line of the file
7
+ filename = "nutation_table5_3a.txt"
8
+ temp_array = []
9
+ data = File.readlines(filename)
10
+
11
+ # clean out whitespace and new line breaks
12
+ data.each {|i| temp_array << i.strip}
13
+
14
+ # make new muti-dimensional data array
15
+ data = []
16
+ temp_array.each {|i| data << i.split}
17
+
18
+ # save the array in a yaml file
19
+ File::open( "nutation_table5_3a.yaml", "w" ) do |f|
20
+ YAML.dump( data, f )
21
+ end
22
+
23
+ # show the new data file contents as an array.
24
+ data = []
25
+ File.open( "nutation_table5_3a.yaml" ) do |f|
26
+ YAML.load_documents( f ) do |doc|
27
+ data = doc
28
+ p data
29
+ end
30
+ p f
31
+ end
@@ -0,0 +1,10 @@
1
+ # from_readme.rb
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'eot'
7
+
8
+ eot = Eot.new
9
+
10
+ puts eot.string_eot()
@@ -0,0 +1,12 @@
1
+ # geo_locator.rb
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'eot'
7
+
8
+ geo = GeoLatLng.new
9
+ geo.addr = "8000 South Michigan Ave., Chicago, IL"
10
+ geo.get_coordinates_from_address
11
+ p geo.lat
12
+ p geo.lng
data/examples/getjd.rb ADDED
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'date'
4
+ include Math
5
+
6
+ def calc_time_julian_centurey(t)
7
+ # Julian Day Number j(2000) subtracted
8
+ (t - 2451545.0) / 36525.0
9
+ # Time in fractional centurey
10
+ end
11
+
12
+ # Truncate large angles
13
+ def mod_360(x)
14
+ 360.0 * ( x / 360.0 - Integer( x / 360.0))
15
+ end
16
+
17
+ def calc_mean_long_aries(t)
18
+
19
+ mod_360(280.46061666 + t * 36525.0 * 360.98564736629 + t * (t * 0.000387933 - t * (t / 38710000.0)))
20
+
21
+ end
22
+
23
+ puts "outputs data every 5 seconds"
24
+ loop do
25
+ time = Time.now.utc
26
+ theDate = Date.new(time.year, time.month, time.day)
27
+ # puts time
28
+ # puts theDate
29
+ # puts "#{theDate.ajd} = Astronomical Julian Day"
30
+ # puts "#{theDate.jd - 0.5} = Astronomical Julian Day"
31
+ # puts "#{theDate.jd} = Julian Day"
32
+ t = time
33
+ theDayFraction = (t.usec / (1000000.0 * 3600.0) + t.min / 60.0 + t.hour + t.sec / 3600.0) / 24.0
34
+ # puts "#{theDayFraction} = Day Fraction time now"
35
+
36
+ theTotal = theDate.ajd + theDayFraction
37
+ # puts "#{theTotal} = Astronomical Julian Day + Day Fraction time now"
38
+
39
+ tjc = calc_time_julian_centurey(theTotal)
40
+ gmst = calc_mean_long_aries(tjc)
41
+
42
+ puts "#{gmst.round 3} = (GHA) Mean Hour Angle First Point of Aries (Vernal Equinox)"
43
+ puts "#{(gmst/15.0).round 3} = Mean Greenwich Siderial Time (GMST)"
44
+ sleep 5
45
+ end
@@ -0,0 +1,21 @@
1
+ # input_suntimes.rb
2
+
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'eot'
7
+
8
+ eot = Eot.new
9
+
10
+ @date = Date.today.to_s
11
+ @zone = -5
12
+ puts @date
13
+ eot.date = @date
14
+ geo = GeoLatLng.new
15
+ # note: you will need internet access to get the coordinates next
16
+ geo.addr = "8000 South Michigan Ave., Chicago, IL"
17
+ geo.get_coordinates_from_address
18
+ eot.longitude = geo.lng.to_f
19
+ eot.latitude = geo.lat.to_f
20
+ puts "Sunrise #{eot.sunrise_dt().to_time}"
21
+ puts "Sunset #{eot.sunset_dt().to_time}"
@@ -0,0 +1,29 @@
1
+ # julian_day_formula.rb
2
+
3
+ # 3) Dropping the fractional part of all results of all multiplications and divisions, let
4
+ require 'date'
5
+
6
+ def date_to_ajd date
7
+ year = date.year
8
+ month = date.month
9
+
10
+ if month <= 2
11
+ year = year -1
12
+ month = month +12
13
+ end
14
+
15
+ day = date.day
16
+
17
+ a = (year / 100).floor
18
+ b = (a / 4).floor
19
+ c = 2 - a + b
20
+ e = (365.25 * (year + 4716)).floor
21
+ f = (30.6001 * (month +1)).floor
22
+ c + day + e + f - 1524.5
23
+ end
24
+
25
+ t = Time.now.utc
26
+ date_string = "#{t.year}-#{t.month}-#{t.day}"
27
+ date = Date.parse(date_string)
28
+ puts t
29
+ puts "Todays date is #{date} and the AJD is #{date_to_ajd date}"
@@ -0,0 +1,12 @@
1
+ def date_to_jd date
2
+
3
+ # 3) Dropping the fractional part of all results of all multiplications and divisions,
4
+ # let
5
+ a = year/100
6
+ b = a/4
7
+ c = 2-a+b
8
+ e = 365.25 * (year + 4716)
9
+ f = 30.6001 * (m +1)
10
+ c + d + e + f - 1524.5
11
+ end
12
+
@@ -0,0 +1,21 @@
1
+ # my_time_conversion.rb
2
+
3
+ # This method will convert hours decimal into a Time object and let you see H:M:S format
4
+ def decimal_to_strf(time_in)
5
+ t = Time.now
6
+ year = t.year
7
+ month = t.month
8
+ day = t.day
9
+ hours = Integer(time_in)
10
+ decimal_minutes = (time_in - hours) * 60.0
11
+ minutes = Integer(decimal_minutes)
12
+ decimal_seconds = (decimal_minutes - minutes) * 60.0
13
+ seconds = Integer(decimal_seconds)
14
+ my_time = Time.new(year, month, day, hours, minutes, seconds, "-05:00")
15
+ my_time.strftime("%H:%M:%S")
16
+ end
17
+
18
+ decimal_hours = 4.64
19
+ puts
20
+ puts "#{decimal_hours} = #{decimal_to_strf(decimal_hours)}"
21
+ puts