Advertisement
Guest User

testsunfun

a guest
Aug 26th, 2012
24
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 41.67 KB | None | 0 0
  1. Calculation of local times of sunrise, solar noon, and sunset
  2. based on the calculation procedure by NOAA in the javascript in
  3. http : // www.srrb.noaa.gov/highlights/sunrise/sunrise.html and
  4. http : // www.srrb.noaa.gov/highlights/sunrise/azel.html
  5.  
  6. Five functions are available for use from Excel worksheets :
  7. -sunrise (lat, lon, year, month, day, timezone, dlstime)
  8. -solarnoon (lat, lon, year, month, day, timezone, dlstime)
  9. -sunset (lat, lon, year, month, day, timezone, dlstime)
  10. -solarazimuth (lat, lon, year, month, day, hour, minute, second, timezone, dlstime)
  11. -solarelevation (lat, lon, year, month, day, hour, minute, second, timezone, dlstime)
  12.  
  13. The sign convention for inputs to the functions named sunrise, solarnoon, sunset, solarazimuth, and solarelevationis :
  14. -positive latitude decimal degrees for northern hemisphere
  15. -negative longitude degrees for western hemisphere
  16. -negative time zone hours for western hemisphere
  17.  
  18. The other functions in the VBA module use the original
  19. NOAA sign convention of positive longitude in the western hemisphere. The calculations in the NOAA Sunrise/Sunset and Solar Position
  20. Calculators are based on equations from Astronomical Algorithms, by Jean Meeus.NOAA also included atmospheric refraction effects.
  21. The sunrise and sunset results were reported by NOAA
  22. to be accurate to within + /-1 minute for locations between + /-72 \[Degree]
  23. latitude, and within ten minutes outside of those latitudes. This translation was tested for selected locations
  24. and found to provide results within + /-1 minute of the
  25. original Javascript code. This translation does not include calculation of prior or next
  26. susets for locations above the Arctic Circle and below the
  27. Antarctic Circle, when a sunrise or sunset does not occur. Translated from NOAAs Javascript to Excel VBA by : Greg Pelletier
  28. Department of Ecology
  29. P.O.Box 47600
  30. Olympia, WA 98504 - 7600
  31. email : gpel461@ecy.wa.gov
  32.  
  33.  
  34. Name : calcJD
  35. '*Type : Function
  36. '*Purpose : Julian day from calendar day
  37. '*Arguments : '*year : 4 digit year
  38. '*month : January = 1
  39. '*day : 1 - 31
  40. '*Return value : '*The Julian day corresponding to the date
  41. '*Note : '*Number is returned for start of day.Fractional days should be
  42. '*added later.' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/
  43.  
  44. BeginPackage["Sunpath`"];
  45. dawn::usage =
  46. "dawn[lat_,lon_,year_,month_,day_,timezone_,dlstime_,solardepression_] \
  47. gives the time of the dawn for various solar depressions (6 deg is civil \
  48. dawn, 12 deg is nautical dawn, 18 deg is astronomical dawn). The number \
  49. returned is the time in a single number ranging from 0 to 24; hours, minutes \
  50. and seconds can be derived from this. Lat and long coordinates are in \
  51. degrees, with directions east and north counted positive. Timezone is the \
  52. offset with respect to GMT. dlstime indicates whether daylight savings time \
  53. is in effect (0=false, 1=true).";
  54. sunrise::usage =
  55. "sunrise[lat_,lon_,year_,month_,day_,timezone_,dlstime_] gives the time of \
  56. the sunrise taking into account atmospheric refraction. The number returned \
  57. is the time in days; hours, minutes and seconds can be derived from this. Lat \
  58. and long coordinates are in degrees, with directions east and north counted \
  59. positive. Timezone is the offset with respect to GMT. dlstime indicates \
  60. whether daylight savings time is in effect (0=false, 1=true).";
  61. solarnoon::usage =
  62. "solarnoon[lat_,lon_,year_,month_,day_,timezone_,dlstime_] gives the time \
  63. at which the sun reaches its highest elevation. The number returned is the \
  64. time in days; hours, minutes and seconds can be derived from this. Lat and \
  65. long coordinates are in degrees, with directions east and north counted \
  66. positive. Timezone is the offset with respect to GMT. dlstime indicates \
  67. whether daylight savings time is in effect (0=false, 1=true).";
  68. sunset::usage =
  69. "sunset[lat_,lon_,year_,month_,day_,timezone_,dlstime_] gives the time of \
  70. the sunset taking into account atmospheric refraction. The number returned is \
  71. the time in days; hours, minutes and seconds can be derived from this. Lat \
  72. and long coordinates are in degrees, with directions east and north counted \
  73. positive. Timezone is the offset with respect to GMT. dlstime indicates \
  74. whether daylight savings time is in effect (0=false, 1=true).";
  75. dusk::usage =
  76. "dusk[lat_,lon_,year_,month_,day_,timezone_,dlstime_,solardepression_] \
  77. gives the time of the sunset taking into account atmospheric refraction.The \
  78. number returned is the time in a single number ranging from 0 to 24; hours, \
  79. minutes and seconds can be derived from this. Lat and long coordinates are in \
  80. degrees, with directions east and north counted positive. Timezone is the \
  81. offset with respect to GMT. dlstime indicates whether daylight savings time \
  82. is in effect (0=false, 1=true).";
  83. solarposition::usage =
  84. "solarposition[lat_,lon_,year_,month_,day_,hours_,minutes_,seconds_,\
  85. timezone_,dlstime_] gives the time of the sunset taking into account \
  86. atmospheric refraction. Lat and long coordinates are in degrees, with \
  87. directions east and north counted positive. Timezone is the offset with \
  88. respect to GMT. dlstime indicates whether daylight savings time is in effect \
  89. (0=false, 1=true). The function returns the sumposition as a list consisting \
  90. of the azimuth and elevation is degrees";
  91. Begin["`Private`"]
  92.  
  93.  
  94. calcJD[year0_, month0_, day0_] :=
  95. Module[{year = year0, month = month0, day = day0, A, B},
  96. If [month <= 2, year = year - 1; month = month + 12];
  97. A = Floor[year/100];
  98. B = 2 - A + Floor[A/4];
  99. Floor[365.25*(year + 4716)] + Floor[30.6001*(month + 1)] + day + B - 1524.5
  100. ];
  101.  
  102.  
  103. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***
  104. /'*Name : calcTimeJulianCent
  105. '*Type : Function
  106. '*Purpose : convert Julian Day to centuries since J2000 .0.'*Arguments : '*jd : the Julian Day to convert
  107. '*Return value : '*the T value corresponding to the Julian Day
  108. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim t As Double
  109.  
  110. calcTimeJulianCent[JD_] := (JD - 2451545)/36525;
  111.  
  112. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*
  113. Name : calcJDFromJulianCent
  114. '*Type : Function
  115. '*Purpose : convert centuries since J2000 .0 to Julian Day.'*Arguments : '*t : number of Julian centuries since J2000 .0
  116. '*Return value : '*the Julian Day corresponding to the t value
  117. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim JD As Double
  118.  
  119. calcJDFromJulianCent[t_] := t*36525 + 2451545;
  120.  
  121. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/
  122. '*Name : calGeomMeanLongSun
  123. '*Type : Function
  124. '*Purpose : calculate the Geometric Mean Longitude of the Sun
  125. '*Arguments : '*t : number of Julian centuries since J2000 .0
  126. '*Return value : '*the Geometric Mean Longitude of the Sun in degrees
  127. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim l0 As Double
  128.  
  129. calcGeomMeanLongSun[t_] :=
  130. Mod[280.46646 + t*(36000.76983 + 0.0003032*t), 360];
  131.  
  132. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*
  133. Name : calGeomAnomalySun
  134. '*Type : Function
  135. '*Purpose : calculate the Geometric Mean Anomaly of the Sun
  136. '*Arguments : '*t : number of Julian centuries since J2000 .0
  137. '*Return value : '*the Geometric Mean Anomaly of the Sun in degrees
  138. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim m As Double
  139.  
  140. calcGeomMeanAnomalySun[t_] := 357.52911 + t*(35999.05029 - 0.0001537*t);
  141.  
  142. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'
  143. *Name : calcEccentricityEarthOrbit
  144. '*Type : Function
  145. '*Purpose : calculate the eccentricity of earth' s orbit
  146. '*Arguments : '*t : number of Julian centuries since J2000 .0
  147. '*Return value : '*the unitless eccentricity
  148. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim e As Double
  149.  
  150. calcEccentricityEarthOrbit[t_] :=
  151. 0.016708634 - t*(0.000042037 + 0.0000001267*t);
  152.  
  153. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'
  154. *Name : calcSunEqOfCenter
  155. '*Type : Function
  156. '*Purpose : calculate the equation of center for the sun
  157. '*Arguments : '*t : number of Julian centuries since J2000 .0
  158. '*Return value : '*in degrees
  159. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim m As Double, mrad As Double, sinm As Double, sin2m As Double, sin3m As Double
  160. Dim c As Double
  161.  
  162. calcSunEqOfCenter[t_] :=
  163. Module[{m},
  164. m = calcGeomMeanAnomalySun[t];
  165. Sin[m \[Degree]]*(1.914602 - t*(0.004817 + 0.000014*t)) +
  166. Sin[2 m \[Degree]]*(0.019993 - 0.000101*t) + Sin[3 m \[Degree]]*0.000289
  167. ];
  168.  
  169. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcSunTrueLong
  170. '*Type : Function
  171. '*Purpose : calculate the true longitude of the sun
  172. '*Arguments : '*t : number of Julian centuries since J2000 .0
  173. '*Return value : '*sun' s true longitude in degrees
  174. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim l0 As Double, c As Double, O As Double
  175.  
  176. calcSunTrueLong[t_] := calcGeomMeanLongSun[t] + calcSunEqOfCenter[t];
  177.  
  178. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcSunTrueAnomaly (not used by sunrise, solarnoon, sunset)
  179. '*Type : Function
  180. '*Purpose : calculate the true anamoly of the sun
  181. '*Arguments : '*t : number of Julian centuries since J2000 .0
  182. '*Return value : '*sun' s true anamoly in degrees
  183. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim m As Double, c As Double, v As Double
  184.  
  185. calcSunTrueAnomaly[t_] := calcGeomMeanAnomalySun[t] + calcSunEqOfCenter[t];
  186.  
  187. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcSunRadVector (not used by sunrise, solarnoon, sunset)
  188. '*Type : Function
  189. '*Purpose : calculate the distance to the sun in AU
  190. '*Arguments : '*t : number of Julian centuries since J2000 .0
  191. '*Return value : '*sun radius vector in AUs
  192. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim v As Double, e As Double, R As Double
  193.  
  194. calcSunRadVector[
  195. t_] := (1.000001018*(1 - calcEccentricityEarthOrbit[t]^2))/(1 +
  196. calcEccentricityEarthOrbit[t]*Cos[calcSunTrueAnomaly[t] \[Degree]]);
  197.  
  198. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcSunApparentLong (not used by sunrise, solarnoon, sunset)
  199. '*Type : Function
  200. '*Purpose : calculate the apparent longitude of the sun
  201. '*Arguments : '*t : number of Julian centuries since J2000 .0
  202. '*Return value : '*sun' s apparent longitude in degrees
  203. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim O As Double, omega As Double, lambda As Double
  204.  
  205. calcSunApparentLong[t_] :=
  206. calcSunTrueLong[t] - 0.00569 - 0.00478*Sin[(125.04 - 1934.136*t) \[Degree]];
  207.  
  208. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcMeanObliquityOfEcliptic
  209. '*Type : Function
  210. '*Purpose : calculate the mean obliquity of the ecliptic
  211. '*Arguments : '*t : number of Julian centuries since J2000 .0
  212. '*Return value : '*mean obliquity in degrees
  213. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim seconds As Double, e0 As Double
  214.  
  215. calcMeanObliquityOfEcliptic[t_] :=
  216. Module[{seconds},
  217. seconds = 21.448 - t*(46.815 + t*(0.00059 - t*(0.001813)));
  218. 23 + (26 + (seconds/60))/60
  219. ];
  220.  
  221. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcObliquityCorrection
  222. '*Type : Function
  223. '*Purpose : calculate the corrected obliquity of the ecliptic
  224. '*Arguments : '*t : number of Julian centuries since J2000 .0
  225. '*Return value : '*corrected obliquity in degrees
  226. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim e0 As Double, omega As Double, e As Double
  227.  
  228. calcObliquityCorrection[t_] :=
  229. Module[{e0, omega},
  230. e0 = calcMeanObliquityOfEcliptic[t];
  231. omega = 125.04 - 1934.136*t;
  232. e0 + 0.00256*Cos[omega \[Degree]]
  233. ];
  234.  
  235.  
  236. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcSunRtAscension (not used by sunrise, solarnoon, sunset)
  237. '*Type : Function
  238. '*Purpose : calculate the right ascension of the sun
  239. '*Arguments : '*t : number of Julian centuries since J2000 .0
  240. '*Return value : '*sun' s right ascension in degrees
  241. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim e As Double, lambda As Double, tananum As Double, tanadenom As Double
  242. Dim alpha As Double
  243.  
  244. calcSunRtAscension[t_] :=
  245. Module[{e, lambda, tananum, tanadenom},
  246. e = calcObliquityCorrection[t];
  247. lambda = calcSunApparentLong[t];
  248. tananum = (Cos[e \[Degree]]*Sin[lambda \[Degree]]);
  249. tanadenom = (Cos[lambda \[Degree]]);
  250. ArcTan[tanadenom, tananum]/\[Degree]
  251. ];
  252.  
  253.  
  254. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcSunDeclination
  255. '*Type : Function
  256. '*Purpose : calculate the declination of the sun
  257. '*Arguments : '*t : number of Julian centuries since J2000 .0
  258. '*Return value : '*sun' s declination in degrees
  259. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim e As Double, lambda As Double, sint As Double, theta As Double
  260.  
  261. calcSunDeclination[t_] :=
  262. Module[{e, lambda},
  263. e = calcObliquityCorrection[t];
  264. lambda = calcSunApparentLong[t];
  265. ArcSin[Sin[e \[Degree]]*Sin[lambda \[Degree]]]/\[Degree]
  266. ];
  267.  
  268.  
  269. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcEquationOfTime
  270. '*Type : Function
  271. '*Purpose : calculate the difference between true solar time and mean
  272. '*solar time
  273. '*Arguments : '*t : number of Julian centuries since J2000 .0
  274. '*Return value : '*equation of time in minutes of time
  275. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim epsilon As Double, l0 As Double, e As Double, m As Double
  276. Dim y As Double, sin2l0 As Double, sinm As Double
  277. Dim cos2l0 As Double, sin4l0 As Double, sin2m As Double, Etime As Double
  278.  
  279. calcEquationOfTime[t_] :=
  280. Module[{epsilon, l0, e, m, y, sinm, sin2l0, cos2l0, sin4l0, sin2m, Etime},
  281. epsilon = calcObliquityCorrection[t];
  282. l0 = calcGeomMeanLongSun[t];
  283. e = calcEccentricityEarthOrbit[t];
  284. m = calcGeomMeanAnomalySun[t];
  285. y = Tan[epsilon \[Degree]/2]^2;
  286. sin2l0 = Sin[2*l0 \[Degree]];
  287. sinm = Sin[m \[Degree]];
  288. cos2l0 = Cos[2*l0 \[Degree]];
  289. sin4l0 = Sin[4*l0 \[Degree]];
  290. sin2m = Sin[2*m \[Degree]];
  291. Etime =
  292. y*sin2l0 - 2*e*sinm + 4*e*y*sinm*cos2l0 - 0.5*y*y*sin4l0 - 1.25*e*e*sin2m;
  293. Etime/\[Degree]*4
  294. ];
  295.  
  296.  
  297. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcHourAngleDawn
  298. '*Type : Function
  299. '*Purpose : calculate the hour angle of the sun at dawn for the
  300. '*latitude
  301. '*for user selected solar depression below horizon
  302. '*Arguments : '*lat : latitude of observer in degrees
  303. '*solarDec : declination angle of sun in degrees
  304. '*solardepression : angle of the sun below the horizion in degrees
  305. '*Return value : '*hour angle of dawn in radians
  306. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim latRad As Double, sdRad As Double, HAarg As Double, HA As Double
  307.  
  308. calcHourAngleDawn[lat_, solarDec_, solardepression_] :=
  309. ArcCos[Cos[(90 + solardepression) \[Degree]] /(Cos[lat \[Degree]]*
  310. Cos[solarDec \[Degree]]) - Tan[lat \[Degree]]*Tan[solarDec \[Degree]]];
  311.  
  312. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcHourAngleSunrise
  313. '*Type : Function
  314. '*Purpose : calculate the hour angle of the sun at sunrise for the
  315. '*latitude
  316. '*Arguments : '*lat : latitude of observer in degrees
  317. '*solarDec : declination angle of sun in degrees
  318. '*Return value : '*hour angle of sunrise in radians
  319. '*'*Note : For sunrise and sunset calculations, we assume 0.833 \[Degree] of atmospheric refraction
  320. '*For details about refraction see http : // www.srrb.noaa.gov/highlights/sunrise/calcdetails.html
  321. '*' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim latRad As Double, sdRad As Double, HAarg As Double, HA As Double
  322.  
  323. calcHourAngleSunrise[lat_, solarDec_] :=
  324. ArcCos[Cos[90.833 \[Degree]]/(Cos[lat \[Degree]]*Cos[solarDec \[Degree]]) -
  325. Tan[lat \[Degree]]*Tan[solarDec \[Degree]]];
  326.  
  327.  
  328. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcHourAngleSunset
  329. '*Type : Function
  330. '*Purpose : calculate the hour angle of the sun at sunset for the
  331. '*latitude
  332. '*Arguments : '*lat : latitude of observer in degrees
  333. '*solarDec : declination angle of sun in degrees
  334. '*Return value : '*hour angle of sunset in radians
  335. '*'*Note : For sunrise and sunset calculations, we assume 0.833 \[Degree] of atmospheric refraction
  336. '*For details about refraction see http : // www.srrb.noaa.gov/highlights/sunrise/calcdetails.html
  337. '*' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim latRad As Double, sdRad As Double, HAarg As Double, HA As Double
  338.  
  339. calcHourAngleSunset[lat_,
  340. solarDec_] := -ArcCos[
  341. Cos[90.833 \[Degree]]/(Cos[lat \[Degree]]*Cos[solarDec \[Degree]]) -
  342. Tan[lat \[Degree]]*Tan[solarDec \[Degree]]];
  343.  
  344. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcHourAngleDusk
  345. '*Type : Function
  346. '*Purpose : calculate the hour angle of the sun at dusk for the
  347. '*latitude
  348. '*for user selected solar depression below horizon
  349. '*Arguments : '*lat : latitude of observer in degrees
  350. '*solarDec : declination angle of sun in degrees
  351. '*solardepression : angle of sun below horizon in degrees
  352. '*Return value : '*hour angle of dusk in radians
  353. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim latRad As Double, sdRad As Double, HAarg As Double, HA As Double
  354.  
  355.  
  356. calcHourAngleDusk[lat_, solarDec_,
  357. solardepression_] := -ArcCos[
  358. Cos[(90 + solardepression) \[Degree]]/(Cos[lat \[Degree]]*
  359. Cos[solarDec \[Degree]]) -
  360. Tan[lat \[Degree]]*Tan[solarDec \[Degree]]];
  361.  
  362.  
  363. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcDawnUTC
  364. '*Type : Function
  365. '*Purpose : calculate the Universal Coordinated Time (UTC) of dawn
  366. '*for the given day at the given location on earth
  367. '*for user selected solar depression below horizon
  368. '*Arguments : '*JD : julian day
  369. '*latitude : latitude of observer in degrees
  370. '*longitude : longitude of observer in degrees
  371. '*solardepression : angle of sun below the horizon in degrees
  372. '*Return value : '*time in minutes from zero Z
  373. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim t As Double, eqtime As Double, solarDec As Double, hourangle As Double
  374. Dim delta As Double, timeDiff As Double, timeUTC As Double
  375. Dim newt As Double
  376.  
  377. calcDawnUTC[JD_, latitude_, longitude_, solardepression_] :=
  378. Module[{t, eqtime, solarDec, hourangle, delta, timeDiff, timeUTC, newt},
  379. t = calcTimeJulianCent[JD];
  380.  
  381. (* First pass to approximate sunrise *)
  382. eqtime = calcEquationOfTime[t];
  383. solarDec = calcSunDeclination[t];
  384. hourangle = calcHourAngleSunrise[latitude, solarDec];
  385.  
  386. delta = longitude - hourangle/\[Degree];
  387. timeDiff = 4*delta;
  388. (* in minutes of time *)
  389. timeUTC = 720 + timeDiff - eqtime;
  390. (* in minutes *)
  391.  
  392. (*Second pass includes fractional jday in gamma calc *)
  393.  
  394. newt = calcTimeJulianCent[calcJDFromJulianCent[t] + timeUTC/1440];
  395. eqtime = calcEquationOfTime[newt];
  396. solarDec = calcSunDeclination[newt];
  397. hourangle = calcHourAngleDawn[latitude, solarDec, solardepression];
  398. delta = longitude - hourangle/\[Degree];
  399. timeDiff = 4*delta;
  400. timeUTC = 720 + timeDiff - eqtime(* in minutes *)
  401. ];
  402.  
  403. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcSunriseUTC
  404. '*Type : Function
  405. '*Purpose : calculate the Universal Coordinated Time (UTC) of sunrise
  406. '*for the given day at the given location on earth
  407. '*Arguments : '*JD : julian day
  408. '*latitude : latitude of observer in degrees
  409. '*longitude : longitude of observer in degrees
  410. '*Return value : '*time in minutes from zero Z
  411. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim t As Double, eqtime As Double, solarDec As Double, hourangle As Double
  412. Dim delta As Double, timeDiff As Double, timeUTC As Double
  413. Dim newt As Double
  414.  
  415. calcSunriseUTC[JD_, latitude_, longitude_] :=
  416. Module[{t, eqtime, solarDec, hourangle, delta, timeDiff, timeUTC, newt},
  417. t = calcTimeJulianCent[JD];
  418. (* First pass to approximate sunrise *)
  419. eqtime = calcEquationOfTime[t];
  420. solarDec = calcSunDeclination[t];
  421. hourangle = calcHourAngleSunrise[latitude, solarDec];
  422. delta = longitude - hourangle/\[Degree];
  423. timeDiff = 4*delta;
  424. (* in minutes of time *)
  425. timeUTC = 720 + timeDiff - eqtime;
  426. (* in minutes *)
  427.  
  428. (* Second pass includes fractional jday in gamma calc *)
  429.  
  430. newt = calcTimeJulianCent[calcJDFromJulianCent[t] + timeUTC/1440];
  431. eqtime = calcEquationOfTime[newt];
  432. solarDec = calcSunDeclination[newt];
  433. hourangle = calcHourAngleSunrise[latitude, solarDec];
  434. delta = longitude - hourangle/\[Degree];
  435. timeDiff = 4*delta;
  436. timeUTC = 720 + timeDiff - eqtime
  437. (* in minutes *)
  438. ];
  439.  
  440. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcSolNoonUTC
  441. '*Type : Function
  442. '*Purpose : calculate the Universal Coordinated Time (UTC) of solar
  443. '*noon for the given day at the given location on earth
  444. '*Arguments : '*t : number of Julian centuries since J2000 .0
  445. '*longitude : longitude of observer in degrees
  446. '*Return value : '*time in minutes from zero Z
  447. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim newt As Double, eqtime As Double, solarNoonDec As Double, solNoonUTC As Double
  448.  
  449. calcSolNoonUTC[t_, longitude_] :=
  450. Module[{newt, eqtime, solarNoonDec},
  451. newt = calcTimeJulianCent[calcJDFromJulianCent[t] + 0.5 + longitude/360];
  452. eqtime = calcEquationOfTime[newt];
  453. (*solarNoonDec=calcSunDeclination[newt];*)
  454. 720 + (longitude*4) - eqtime
  455. ];
  456.  
  457.  
  458. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcSunsetUTC
  459. '*Type : Function
  460. '*Purpose : calculate the Universal Coordinated Time (UTC) of sunset
  461. '*for the given day at the given location on earth
  462. '*Arguments : '*JD : julian day
  463. '*latitude : latitude of observer in degrees
  464. '*longitude : longitude of observer in degrees
  465. '*Return value : '*time in minutes from zero Z
  466. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim t As Double, eqtime As Double, solarDec As Double, hourangle As Double
  467. Dim delta As Double, timeDiff As Double, timeUTC As Double
  468. Dim newt As Double
  469.  
  470. calcSunsetUTC[JD_, latitude_, longitude_] :=
  471. Module[{t, eqtime, solarDec, hourangle, delta, timeDiff, timeUTC, newt},
  472. t = calcTimeJulianCent[JD];
  473.  
  474. (*First calculates sunrise and approx length of day*)
  475.  
  476. eqtime = calcEquationOfTime[t];
  477. solarDec = calcSunDeclination[t];
  478. hourangle = calcHourAngleSunset[latitude, solarDec];
  479.  
  480. delta = longitude - hourangle/\[Degree];
  481. timeDiff = 4*delta;
  482. timeUTC = 720 + timeDiff - eqtime;
  483.  
  484. (* first pass used to include fractional day in gamma calc *)
  485.  
  486. newt = calcTimeJulianCent[calcJDFromJulianCent[t] + timeUTC/1440];
  487. eqtime = calcEquationOfTime[newt];
  488. solarDec = calcSunDeclination[newt];
  489. hourangle = calcHourAngleSunset[latitude, solarDec];
  490.  
  491. delta = longitude - hourangle/\[Degree];
  492. timeDiff = 4*delta;
  493. timeUTC = 720 + timeDiff - eqtime
  494. (* in minutes *)
  495. ];
  496.  
  497.  
  498. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : calcDuskUTC
  499. '*Type : Function
  500. '*Purpose : calculate the Universal Coordinated Time (UTC) of dusk
  501. '*for the given day at the given location on earth
  502. '*for user selected solar depression below horizon
  503. '*Arguments : '*JD : julian day
  504. '*latitude : latitude of observer in degrees
  505. '*longitude : longitude of observer in degrees
  506. '*solardepression : angle of sun below horizon
  507. '*Return value : '*time in minutes from zero Z
  508. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim t As Double, eqtime As Double, solarDec As Double, hourangle As Double
  509. Dim delta As Double, timeDiff As Double, timeUTC As Double
  510. Dim newt As Double
  511.  
  512. calcDuskUTC[JD_, latitude_, longitude_, solardepression_] :=
  513. Module[{t, eqtime, solarDec, hourangle, delta, timeDiff, timeUTC, newt},
  514. t = calcTimeJulianCent[JD];
  515.  
  516. (* First calculates sunrise and approx length of day *)
  517.  
  518. eqtime = calcEquationOfTime[t];
  519. solarDec = calcSunDeclination[t];
  520. hourangle = calcHourAngleSunset[latitude, solarDec];
  521.  
  522. delta = longitude - hourangle/\[Degree];
  523. timeDiff = 4*delta;
  524. timeUTC = 720 + timeDiff - eqtime;
  525.  
  526. (*first pass used to include fractional day in gamma calc *)
  527.  
  528. newt = calcTimeJulianCent[calcJDFromJulianCent[t] + timeUTC/1440];
  529. eqtime = calcEquationOfTime[newt];
  530. solarDec = calcSunDeclination[newt];
  531. hourangle = calcHourAngleDusk[latitude, solarDec, solardepression];
  532.  
  533. delta = longitude - hourangle/\[Degree];
  534. timeDiff = 4*delta;
  535. timeUTC = 720 + timeDiff - eqtime
  536. (*in minutes*)
  537. ];
  538.  
  539.  
  540. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : dawn
  541. '*Type : Main Function called by spreadsheet
  542. '*Purpose : calculate time of dawn for the entered date
  543. '*and location.'*For latitudes greater than 72 degrees N and S, calculations are
  544. '*accurate to within 10 minutes.For latitudes less than + /-72 \[Degree]
  545. '*accuracy is approximately one minute.'*Arguments : ' latitude = latitude (decimal degrees)
  546. ' longitude = longitude (decimal degrees)
  547. ' NOTE : longitude is negative for western hemisphere for input cells
  548. ' in the spreadsheet for calls to the functions named
  549. ' sunrise, solarnoon, and sunset.Those functions convert the
  550. ' longitude to positive for the western hemisphere for calls to
  551. ' other functions using the original sign convention
  552. ' from the NOAA javascript code.' year = year
  553. ' month = month
  554. ' day = day
  555. ' timezone = time zone hours relative to GMT/UTC (hours)
  556. ' dlstime = daylight savings time (0 = no, 1 = yes) (hours)
  557. ' solardepression = angle of sun below horizon in degrees
  558. '*Return value : '*dawn time in local time (days)
  559. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim longitude As Double, latitude As Double, JD As Double
  560. Dim riseTimeGMT As Double, riseTimeLST As Double
  561.  
  562. dawn[lat_, lon_, year_, month_, day_, timezone_, dlstime_, solardepression_] :=
  563.  
  564.  
  565. Module[{longitude, latitude, JD, riseTimeGMT, riseTimeLST},
  566. (* change sign convention for longitude from negative to positive in \
  567. western hemisphere *)
  568. longitude = -lon;
  569. latitude = lat;
  570. If [latitude > 89.8, latitude = 89.8];
  571. If [latitude < -89.8, latitude = -89.8];
  572.  
  573. JD = calcJD[year, month, day];
  574.  
  575. (* Calculate sunrise for this date *)
  576. riseTimeGMT = calcDawnUTC[JD, latitude, longitude, solardepression];
  577.  
  578. (* adjust for time zone and daylight savings time in minutes *)
  579. riseTimeLST = riseTimeGMT + (60*timezone) + (dlstime*60);
  580.  
  581. (* convert to days *)
  582. riseTimeLST/1440
  583. ];
  584.  
  585. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : sunrise
  586. '*Type : Main Function called by spreadsheet
  587. '*Purpose : calculate time of sunrise for the entered date
  588. '*and location.'*For latitudes greater than 72 degrees N and S, calculations are
  589. '*accurate to within 10 minutes.For latitudes less than + /-72 \[Degree]
  590. '*accuracy is approximately one minute.'*Arguments : ' latitude = latitude (decimal degrees)
  591. ' longitude = longitude (decimal degrees)
  592. ' NOTE : longitude is negative for western hemisphere for input cells
  593. ' in the spreadsheet for calls to the functions named
  594. ' sunrise, solarnoon, and sunset.Those functions convert the
  595. ' longitude to positive for the western hemisphere for calls to
  596. ' other functions using the original sign convention
  597. ' from the NOAA javascript code.' year = year
  598. ' month = month
  599. ' day = day
  600. ' timezone = time zone hours relative to GMT/UTC (hours)
  601. ' dlstime = daylight savings time (0 = no, 1 = yes) (hours)
  602. '*Return value : '*sunrise time in local time (days)
  603. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim longitude As Double, latitude As Double, JD As Double
  604. Dim riseTimeGMT As Double, riseTimeLST As Double
  605.  
  606. sunrise[lat_, lon_, year_, month_, day_, timezone_, dlstime_] :=
  607. Module[{longitude, latitude, JD, riseTimeGMT, riseTimeLST},
  608. (* change sign convention for longitude from negative to positive in \
  609. western hemisphere *)
  610. longitude = -lon;
  611. latitude = lat;
  612. If [latitude > 89.8, latitude = 89.8];
  613. If [latitude < -89.8, latitude = -89.8];
  614.  
  615. JD = calcJD[year, month, day];
  616.  
  617. (* Calculate sunrise for this date *)
  618. riseTimeGMT = calcSunriseUTC[JD, latitude, longitude];
  619.  
  620. (* adjust for time zone and daylight savings time in minutes *)
  621. riseTimeLST = riseTimeGMT + (60*timezone) + (dlstime*60);
  622.  
  623. (* convert to days *)
  624. riseTimeLST/1440
  625. ];
  626.  
  627.  
  628. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : solarnoon
  629. '*Type : Main Function called by spreadsheet
  630. '*Purpose : calculate the Universal Coordinated Time (UTC) of solar
  631. '*noon for the given day at the given location on earth
  632. '*Arguments : ' year
  633. ' month
  634. ' day
  635. '*longitude : longitude of observer in degrees
  636. ' NOTE : longitude is negative for western hemisphere for input cells
  637. ' in the spreadsheet for calls to the functions named
  638. ' sunrise, solarnoon, and sunset.Those functions convert the
  639. ' longitude to positive for the western hemisphere for calls to
  640. ' other functions using the original sign convention
  641. ' from the NOAA javascript code.'*Return value : '*time of solar noon in local time days
  642. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim longitude As Double, latitude As Double, JD As Double
  643. Dim t As Double, newt As Double, eqtime As Double
  644. Dim solarNoonDec As Double, solNoonUTC As Double
  645.  
  646. solarnoon[lat_, lon_, year_, month_, day_, timezone_, dlstime_] :=
  647. Module[{longitude, latitude, JD, t, newt, eqtime, solarNoonDec, solNoonUTC,
  648. solarnoon},
  649. (* change sign convention for longitude from negative to positive in \
  650. western hemisphere *)
  651. longitude = -lon;
  652. latitude = lat;
  653. If [latitude > 89.8, latitude = 89.8];
  654. If [latitude < -89.8, latitude = -89.8];
  655.  
  656. JD = calcJD[year, month, day];
  657.  
  658. t = calcTimeJulianCent[JD];
  659.  
  660. newt = calcTimeJulianCent[calcJDFromJulianCent[t] + 0.5 + longitude/360];
  661.  
  662. eqtime = calcEquationOfTime[newt];
  663. (* solarNoonDec=calcSunDeclination[newt]; *)
  664. solNoonUTC = 720 + (longitude*4) - eqtime;
  665.  
  666. (* adjust for time zone and daylight savings time in minutes *)
  667. solarnoon = solNoonUTC + (60*timezone) + (dlstime*60);
  668.  
  669. (* convert to days *)
  670. solarnoon/1440
  671. ];
  672.  
  673.  
  674. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : sunset
  675. '*Type : Main Function called by spreadsheet
  676. '*Purpose : calculate time of sunrise and sunset for the entered date
  677. '*and location.'*For latitudes greater than 72 degrees N and S, calculations are
  678. '*accurate to within 10 minutes.For latitudes less than + /-72 \[Degree]
  679. '*accuracy is approximately one minute.'*Arguments : ' latitude = latitude (decimal degrees)
  680. ' longitude = longitude (decimal degrees)
  681. ' NOTE : longitude is negative for western hemisphere for input cells
  682. ' in the spreadsheet for calls to the functions named
  683. ' sunrise, solarnoon, and sunset.Those functions convert the
  684. ' longitude to positive for the western hemisphere for calls to
  685. ' other functions using the original sign convention
  686. ' from the NOAA javascript code.' year = year
  687. ' month = month
  688. ' day = day
  689. ' timezone = time zone hours relative to GMT/UTC (hours)
  690. ' dlstime = daylight savings time (0 = no, 1 = yes) (hours)
  691. '*Return value : '*sunset time in local time (days)
  692. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim longitude As Double, latitude As Double, JD As Double
  693. Dim setTimeGMT As Double, setTimeLST As Double
  694.  
  695. sunset[lat_, lon_, year_, month_, day_, timezone_, dlstime_] :=
  696. Module[{longitude, latitude, JD, setTimeGMT, setTimeLST},
  697. (* change sign convention for longitude from negative to positive in \
  698. western hemisphere *)
  699. longitude = -lon;
  700. latitude = lat;
  701. If [latitude > 89.8, latitude = 89.8];
  702. If [latitude < -89.8, latitude = -89.8];
  703.  
  704. JD = calcJD[year, month, day];
  705.  
  706. (* Calculate sunset for this date *)
  707. setTimeGMT = calcSunsetUTC[JD, latitude, longitude];
  708.  
  709. (* adjust for time zone and daylight savings time in minutes *)
  710. setTimeLST = setTimeGMT + (60*timezone) + (dlstime*60);
  711.  
  712. (* convert to days *)
  713. setTimeLST/1440
  714. ];
  715.  
  716.  
  717. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : dusk
  718. '*Type : Main Function called by spreadsheet
  719. '*Purpose : calculate time of sunrise and sunset for the entered date
  720. '*and location.'*For latitudes greater than 72 degrees N and S, calculations are
  721. '*accurate to within 10 minutes.For latitudes less than + /-72 \[Degree]
  722. '*accuracy is approximately one minute.'*Arguments : ' latitude = latitude (decimal degrees)
  723. ' longitude = longitude (decimal degrees)
  724. ' NOTE : longitude is negative for western hemisphere for input cells
  725. ' in the spreadsheet for calls to the functions named
  726. ' sunrise, solarnoon, and sunset.Those functions convert the
  727. ' longitude to positive for the western hemisphere for calls to
  728. ' other functions using the original sign convention
  729. ' from the NOAA javascript code.' year = year
  730. ' month = month
  731. ' day = day
  732. ' timezone = time zone hours relative to GMT/UTC (hours)
  733. ' dlstime = daylight savings time (0 = no, 1 = yes) (hours)
  734. ' solardepression = angle of sun below horizon in degrees
  735. '*Return value : '*dusk time in local time (days)
  736. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim longitude As Double, latitude As Double, JD As Double
  737. Dim setTimeGMT As Double, setTimeLST As Double
  738.  
  739.  
  740. dusk[lat_, lon_, year_, month_, day_, timezone_, dlstime_, solardepression_] :=
  741.  
  742.  
  743. Module[{longitude, latitude, JD, setTimeGMT, setTimeLST},
  744.  
  745. (* change sign convention for longitude from negative to positive in \
  746. western hemisphere *)
  747. longitude = -lon;
  748. latitude = lat;
  749. If [latitude > 89.8, latitude = 89.8];
  750. If [latitude < -89.8, latitude = -89.8];
  751.  
  752. JD = calcJD[year, month, day];
  753.  
  754. (* Calculate sunset for this date *)
  755. setTimeGMT = calcDuskUTC[JD, latitude, longitude, solardepression];
  756.  
  757. (* adjust for time zone and daylight savings time in minutes *)
  758. setTimeLST = setTimeGMT + (60*timezone) + (dlstime*60);
  759.  
  760. (* convert to days *)
  761. setTimeLST/1440
  762. ];
  763.  
  764. ' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/'*Name : solarazimuth
  765. '*Type : Main Function
  766. '*Purpose : calculate solar azimuth (deg from north) for the entered
  767. '*date, time and location.Returns - 999999 if darker than twilight
  768. '*'*Arguments : '*latitude, longitude, year, month, day, hour, minute, second, '*timezone, daylightsavingstime
  769. '*Return value : '*solar azimuth in degrees from north
  770. '*'*Note : solarelevation and solarazimuth functions are identical
  771. '*and could converted to a VBA subroutine that would return
  772. '*both values.'*' ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ***/Dim longitude As Double, latitude As Double
  773. Dim zone As Double, daySavings As Double
  774. Dim hh As Double, mm As Double, ss As Double, timenow As Double
  775. Dim JD As Double, t As Double, R As Double
  776. Dim alpha As Double, theta As Double, Etime As Double, eqtime As Double
  777. Dim solarDec As Double, earthRadVec As Double, solarTimeFix As Double
  778. Dim trueSolarTime As Double, hourangle As Double, harad As Double
  779. Dim csz As Double, zenith As Double, azDenom As Double, azRad As Double
  780. Dim azimuth As Double, exoatmElevation As Double
  781. Dim step1 As Double, step2 As Double, step3 As Double
  782. Dim refractionCorrection As Double, te As Double, solarzen As Double
  783.  
  784. solarposition[lat_, lon_, year_, month_, day_, hours_, minutes_, seconds_,
  785. timezone_, dlstime_] :=
  786. Module[{longitude, latitude, zone, daySavings, hh, mm, ss, timenow, JD, t,
  787. R, alpha, theta, Etime, eqtime, solarDec, earthRadVec, solarTimeFix,
  788. trueSolarTime, hourangle, harad, csz, zenith, azDenom, azRad, azimuth,
  789. exoatmElevation, refractionCorrection, te, step1, step2, step3, solarzen,
  790. solarazimuth, solarelevation},
  791. (* change sign convention for longitude from negative to positive in \
  792. western hemisphere *)
  793. longitude = -lon;
  794. latitude = lat;
  795. If [latitude > 89.8, latitude = 89.8];
  796. If [latitude < -89.8, latitude = -89.8];
  797.  
  798. (* change time zone to ppositive hours in western hemisphere *)
  799. zone = -timezone;
  800. daySavings = dlstime*60;
  801. hh = hours - (daySavings/60);
  802. mm = minutes;
  803. ss = seconds;
  804.  
  805. (* timenow is GMT time for calculation in hours since 0Z *)
  806. timenow = hh + mm/60 + ss/3600 + zone;
  807.  
  808. JD = calcJD[year, month, day];
  809. t = calcTimeJulianCent[JD + timenow/24];
  810. R = calcSunRadVector[t];
  811. alpha = calcSunRtAscension[t];
  812. theta = calcSunDeclination[t];
  813. Etime = calcEquationOfTime[t];
  814.  
  815. eqtime = Etime;
  816. solarDec = theta; (* in degrees *)
  817. earthRadVec = R;
  818.  
  819. solarTimeFix = eqtime - 4*longitude + 60*zone;
  820. trueSolarTime = hh*60 + mm + ss/60 + solarTimeFix;
  821. (* in minutes *)
  822.  
  823. While [trueSolarTime > 1440, trueSolarTime = trueSolarTime - 1440];
  824.  
  825. hourangle = trueSolarTime/4 - 180;
  826. (* Thanks to Louis Schwarzmayr for the next line: *)
  827. If[ (hourangle < -180) , hourangle = hourangle + 360];
  828.  
  829. harad = hourangle \[Degree];
  830.  
  831. csz = Sin[latitude \[Degree]]*Sin[solarDec \[Degree]] +
  832. Cos[latitude \[Degree]]*Cos[solarDec \[Degree]]*Cos[harad];
  833.  
  834. If[csz > 1 ,
  835. csz = 1,
  836. If [csz < -1 , csz = -1]
  837. ];
  838.  
  839. zenith = ArcCos[csz]/\[Degree];
  840.  
  841. azDenom = Cos[latitude \[Degree]]*Sin[zenith \[Degree]];
  842.  
  843. If [Abs[azDenom] > 0.001,
  844. azRad = (Sin[latitude \[Degree]]*Cos[zenith \[Degree]] -
  845. Sin[solarDec \[Degree]])/azDenom;
  846. If[Abs[azRad] > 1,
  847. If [azRad < 0, azRad = -1, azRad = 1]
  848. ];
  849. azimuth = 180 - ArcCos[azRad]/\[Degree];
  850. If[hourangle > 0, azimuth = -azimuth],
  851. (*else*)
  852. If[latitude > 0, azimuth = 180, azimuth = 0]
  853. ];
  854. If [azimuth < 0, azimuth = azimuth + 360];
  855.  
  856. exoatmElevation = 90 - zenith;
  857.  
  858. (* beginning of simplified expression *)
  859. If [exoatmElevation > 85,
  860. refractionCorrection = 0,
  861. te = Tan[exoatmElevation \[Degree]];
  862. If[exoatmElevation > 5,
  863. refractionCorrection = 58.1/te - 0.07/te^3 + 0.000086/te^5,
  864. (*else*)
  865. If [exoatmElevation > -0.575,
  866. step1 = (-12.79 + exoatmElevation*0.711);
  867. step2 = (103.4 + exoatmElevation*(step1));
  868. step3 = (-518.2 + exoatmElevation*(step2));
  869. refractionCorrection = 1735 + exoatmElevation*(step3),
  870. (*else*)
  871. refractionCorrection = -20.774/te
  872. ]
  873. ];
  874. refractionCorrection = refractionCorrection/3600;
  875. ];
  876. (* end of simplified expression *)
  877.  
  878. solarzen = zenith - refractionCorrection;
  879. solarazimuth = azimuth;
  880. solarelevation = 90 - solarzen;
  881. Return[{solarazimuth, solarelevation}];
  882. ];
  883.  
  884. End[ ]
  885. EndPackage[ ]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement