module SunCalc
Constants
- DAY_MS
- E
- HC
- J0
- J1970
- J2000
- RAD
Shortcuts for easier to read equations
- SDIST
- TIMES
- VERSION
Public Class Methods
add_time(angle, rise_name, set_name)
click to toggle source
Sun times configuration (angle, morning name, evening name)
# File lib/suncalc.rb, line 98 def self.add_time(angle, rise_name, set_name) TIMES << [angle, rise_name, set_name] end
altitude(h, phi, dec)
click to toggle source
# File lib/suncalc.rb, line 52 def self.altitude(h, phi, dec) Math::asin(Math::sin(phi) * Math::sin(dec) + Math::cos(phi) * Math::cos(dec) * Math::cos(h)) end
approx_transit(ht, lw, n)
click to toggle source
# File lib/suncalc.rb, line 107 def self.approx_transit(ht, lw, n) J0 + (ht + lw) / (2 * Math::PI) + n end
azimuth(h, phi, dec)
click to toggle source
# File lib/suncalc.rb, line 48 def self.azimuth(h, phi, dec) Math::atan2(Math::sin(h), Math::cos(h) * Math::sin(phi) - Math::tan(dec) * Math::cos(phi)) end
declination(l, b)
click to toggle source
# File lib/suncalc.rb, line 44 def self.declination(l, b) Math::asin(Math::sin(b) * Math::cos(E) + Math::cos(b) * Math::sin(E) * Math::sin(l)) end
ecliptic_longitude(m)
click to toggle source
# File lib/suncalc.rb, line 65 def self.ecliptic_longitude(m) c = RAD * (1.9148 * Math::sin(m) + 0.02 * Math::sin(2 * m) + 0.0003 * Math::sin(3 * m)) p = RAD * 102.9372 m + c + p + Math::PI end
from_julian(j)
click to toggle source
# File lib/suncalc.rb, line 29 def self.from_julian(j) Time.at(((j + 0.5 - J1970) * DAY_MS)/1000).utc end
get_moon_illumination(date)
click to toggle source
Calculations for illumination parameters of the moon
# File lib/suncalc.rb, line 198 def self.get_moon_illumination(date) d = to_days(date) s = sun_coords(d) m = moon_coords(d) phi = Math::acos(Math::sin(s[:dec]) * Math::sin(m[:dec]) + Math::cos(s[:dec]) * Math::cos(m[:dec]) * Math::cos(s[:ra] - m[:ra])) inc = Math::atan2(SDIST * Math::sin(phi), m[:dist] - SDIST * Math::cos(phi)) angle = Math::atan2(Math::cos(s[:dec]) * Math::sin(s[:ra] - m[:ra]), Math::sin(s[:dec]) * Math::cos(m[:dec]) - Math::cos(s[:dec]) * Math::sin(m[:dec]) * Math::cos(s[:ra] - m[:ra])) result = { :fraction => (1 + Math::cos(inc)) / 2, :phase => 0.5 + 0.5 * inc * (angle < 0 ? -1 : 1) / Math::PI, :angle => angle } result end
get_moon_position(date, lat, lng)
click to toggle source
# File lib/suncalc.rb, line 177 def self.get_moon_position(date, lat, lng) lw = RAD * -lng phi = RAD * lat d = to_days(date) c = moon_coords(d) th = sidereal_time(d, lw) - c[:ra] h = altitude(th, phi, c[:dec]) h = h + RAD * 0.017 / Math::tan(h + RAD * 10.26 / (h + RAD * 5.10)) result = { :azimuth => azimuth(th, phi, c[:dec]), :altitude => h, :distance => c[:dist] } result end
get_moon_times(date, lat, lng)
click to toggle source
# File lib/suncalc.rb, line 220 def self.get_moon_times(date, lat, lng) t = Time.new(date.year.to_i, date.month.to_i, date.day.to_i).utc h0 = get_moon_position(t, lat, lng)[:altitude] - HC rise = false set = false ye = 0 (1..24).step(2) do |i| h1 = get_moon_position(hours_later(t, i), lat, lng)[:altitude] - HC h2 = get_moon_position(hours_later(t, i + 1), lat, lng)[:altitude] - HC a = (h0 + h2) / 2 - h1 b = (h2 - h0) / 2 xe = -b / (2 * a) ye = (a * xe + b) * xe + h1 d = b * b - 4 * a * h1 roots = 0 if d >= 0 dx = Math::sqrt(d) / (a.abs * 2) x1 = xe - dx x2 = xe + dx if x1.abs <= 1 roots += 1 end if x2.abs <= 1 roots += 1 end if x1 < -1 x1 = x2 end end if roots === 1 if h0 < 0 rise = i + x1 else set = i + x1 end elsif roots === 2 rise = i + (ye < 0 ? x2 : x1) set = i + (ye < 0 ? x1 : x2) end break if rise and set h0 = h2 end result = {} if rise result[:rise] = hours_later(t, rise) end if set result[:set] = hours_later(t, set) end if not rise and not set result[ye > 0 ? :alwaysUp : :alwaysDown] = true end result end
get_position(date, lat, lng)
click to toggle source
Calculate sun position for a given date and latitude/longitude
# File lib/suncalc.rb, line 84 def self.get_position(date, lat, lng) lw = RAD * -lng phi = RAD * lat d = to_days(date) c = sun_coords(d) h = sidereal_time(d, lw) - c[:ra] { :azimuth => azimuth(h, phi, c[:dec]), :altitude => altitude(h, phi, c[:dec]) } end
get_set_j(h, lw, phi, dec, n, m, l)
click to toggle source
Returns set time for the given sun altitude
# File lib/suncalc.rb, line 120 def self.get_set_j(h, lw, phi, dec, n, m, l) w = hour_angle(h, phi, dec) a = approx_transit(w, lw, n) solar_transit_j(a, m, l) end
get_times(date, lat, lng)
click to toggle source
Calculate sun times for a given date and latitude/longitude
# File lib/suncalc.rb, line 127 def self.get_times(date, lat, lng) lw = RAD * -lng phi = RAD * lat d = to_days(date) n = julian_cycle(d, lw) ds = approx_transit(0, lw, n) m = solar_mean_anomaly(ds) l = ecliptic_longitude(m) dec = declination(l, 0) jnoon = solar_transit_j(ds, m, l) result = { :solar_noon => from_julian(jnoon), :nadir => from_julian(jnoon - 0.5) } TIMES.each do |time| jset = get_set_j(time[0] * RAD, lw, phi, dec, n, m, l) jrise = jnoon - (jset - jnoon) result[time[1]] = from_julian(jrise) result[time[2]] = from_julian(jset) end result end
hour_angle(h, phi, d)
click to toggle source
# File lib/suncalc.rb, line 115 def self.hour_angle(h, phi, d) Math::acos((Math::sin(h) - Math::sin(phi) * Math::sin(d)) / (Math::cos(phi) * Math::cos(d))) end
hours_later(date, h)
click to toggle source
# File lib/suncalc.rb, line 216 def self.hours_later(date, h) Time.at(date.to_f + (h * (DAY_MS/1000)) / 24).utc end
julian_cycle(d, lw)
click to toggle source
Calculations for sun times
# File lib/suncalc.rb, line 103 def self.julian_cycle(d, lw) (d - J0 - lw / (2 * Math::PI)).round end
moon_coords(d)
click to toggle source
Moon calculations
# File lib/suncalc.rb, line 158 def self.moon_coords(d) el = RAD * (218.316 + 13.176396 * d) m = RAD * (134.963 + 13.064993 * d) f = RAD * (93.272 + 13.229350 * d) l = el + RAD * 6.289 * Math::sin(m) b = RAD * 5.128 * Math::sin(f) dt = 385001 - 20905 * Math::cos(m) result = { :ra => right_ascension(l, b), :dec => declination(l, b), :dist => dt } result end
right_ascension(l, b)
click to toggle source
General calculations for position
# File lib/suncalc.rb, line 40 def self.right_ascension(l, b) Math::atan2(Math::sin(l) * Math::cos(E) - Math::tan(b) * Math::sin(E), Math::cos(l)) end
sidereal_time(d, lw)
click to toggle source
# File lib/suncalc.rb, line 56 def self.sidereal_time(d, lw) RAD * (280.16 + 360.9856235 * d) - lw end
solar_mean_anomaly(d)
click to toggle source
General sun calculations
# File lib/suncalc.rb, line 61 def self.solar_mean_anomaly(d) RAD * (357.5291 + 0.98560028 * d) end
solar_transit_j(ds, m, l)
click to toggle source
# File lib/suncalc.rb, line 111 def self.solar_transit_j(ds, m, l) J2000 + ds + 0.0053 * Math::sin(m) - 0.0069 * Math::sin(2 * l) end
sun_coords(d)
click to toggle source
# File lib/suncalc.rb, line 72 def self.sun_coords(d) @result = [] sM = solar_mean_anomaly(d) eL = ecliptic_longitude(sM) { :dec => declination(eL, 0), :ra => right_ascension(eL, 0) } end
to_days(date)
click to toggle source
# File lib/suncalc.rb, line 33 def self.to_days(date) to_julian(date) - J2000 end
to_julian(date)
click to toggle source
Date/time constants and conversions
# File lib/suncalc.rb, line 25 def self.to_julian(date) (date.to_f * 1000) / DAY_MS - 0.5 + J1970 end