equationoftime 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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