ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/gen/sun.c
Revision: 2.7
Committed: Thu Nov 7 23:15:07 2019 UTC (4 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R3, HEAD
Changes since 2.6: +68 -12 lines
Log Message:
Added more accurate Michalsky solar position calculation and made correction to old IES handbook formula (thanks to Axel Jacobs)

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: sun.c,v 2.6 2013/08/09 16:51:15 greg Exp $";
3 #endif
4 /*
5 * SOLAR CALCULATIONS
6 *
7 * 3/31/87
8 *
9 * Michalsky algorithm added October 2019:
10 * "The Astronomical Almanac's Algorithm for Approximate
11 * Solar Position (1950-2050)" by Joseph J. Michalsky,
12 * published in 1988 in Solar Energy, Vol. 40, No. 3.
13 * Also added correction to sdec() (365 was 368 originally)
14 *
15 */
16
17 #include <math.h>
18 #include "sun.h"
19
20 #ifdef M_PI
21 #define PI M_PI
22 #else
23 #define PI 3.14159265358979323846
24 #endif
25 #undef DEG
26 #define DEG (PI/180.)
27
28
29 double s_latitude = 0.66; /* site latitude (radians north of equator) */
30 double s_longitude = 2.13; /* site longitude (radians west of Greenwich) */
31 double s_meridian = 120.*DEG; /* standard meridian (radians west) */
32
33
34 int
35 jdate( /* Julian date (days into year) */
36 int month,
37 int day
38 )
39 {
40 static short mo_da[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
41
42 return(mo_da[month-1] + day);
43 }
44
45
46 double
47 stadj( /* solar time adjustment from Julian date */
48 int jd
49 )
50 {
51 return( 0.170 * sin( (4.*PI/373.) * (jd - 80) ) -
52 0.129 * sin( (2.*PI/355.) * (jd - 8) ) +
53 (12./PI) * (s_meridian - s_longitude) );
54 }
55
56
57 double
58 sdec( /* solar declination angle from Julian date */
59 int jd
60 )
61 {
62 return( 0.4093 * sin( (2.*PI/365.) * (jd - 81) ) );
63 }
64
65
66 double
67 salt( /* solar altitude from solar declination and solar time */
68 double sd,
69 double st
70 )
71 {
72 return( asin( sin(s_latitude) * sin(sd) -
73 cos(s_latitude) * cos(sd) * cos(st*(PI/12.)) ) );
74 }
75
76
77 double
78 sazi( /* solar azimuth from solar declination and solar time */
79 double sd,
80 double st
81 )
82 {
83 return( -atan2( cos(sd)*sin(st*(PI/12.)),
84 -cos(s_latitude)*sin(sd) -
85 sin(s_latitude)*cos(sd)*cos(st*(PI/12.)) ) );
86 }
87
88
89 /****************** More accurate Michalsky algorithm ****************/
90
91
92 /* circle normalization */
93 static double
94 norm_cir(double r, const double p)
95 {
96 while (r < 0) r += p;
97 while (r >= p) r -= p;
98 return(r);
99 }
100
101
102 /* Almanac Julian date relative to noon UT on Jan 1, 2000 (fractional days) */
103 double
104 mjdate(int year, int month, int day, double hour)
105 {
106 int jd = jdate(month, day);
107 jd += (month > 2) & !(year&3);
108 jd += (year - 1949)*365 + (year - 1949)/4;
109 hour += s_meridian*(12./PI);
110 return(jd + hour*(1./24.) + (2432916.5-2451545.));
111 }
112
113
114 /* Solar declination (and solar time) from Almanac Julian date (fractional) */
115 double
116 msdec(double mjd, double *stp)
117 { /* Ecliptic coordinates (radians) */
118 double L = norm_cir(280.460*DEG + 0.9856474*DEG*mjd, 2.*PI);
119 double g = norm_cir(357.528*DEG + 0.9856003*DEG*mjd, 2.*PI);
120 double l = L + 1.915*DEG*sin(g) + 0.020*DEG*sin(2.*g);
121 double ep = 23.439*DEG - 4e-7*DEG*mjd;
122 double sin_l = sin(l);
123
124 if (stp) { /* solar time requested, also? */
125 double ra = atan2(sin_l*cos(ep), cos(l));
126 double utime = 24.*(mjd - floor(mjd)) + 12.;
127 double gmst = 6.697375 + 0.0657098242*mjd + utime;
128 double lmst = gmst - s_longitude*(12./PI);
129
130 *stp = norm_cir(lmst - ra*(12./PI) + 12., 24.);
131 }
132 return(asin(sin(ep)*sin_l)); /* return solar declination angle */
133 }