00001 00004 #include "complex.h" 00005 #include "solar_angles.h" 00006 00007 00008 00009 SolarAngles::SolarAngles() 00010 { 00011 } 00012 00013 SolarAngles::~SolarAngles() 00014 { 00015 } 00016 00017 00018 00019 /******************function eq_time****************************/ 00020 // PURPOSE: Compute equation of time (a measure of the earth's 00021 // "wobble" thoughout the year). 00022 // EXPECTS: Day of year from Jan 1. 00023 // RETURNS: Equation of time in hours. 00024 // SOURCE: Prof. Bill Murphy, Texas A&M U. 00025 // 00026 double SolarAngles::eq_time(short day_of_yr) 00027 { 00028 double rad = (2.0 * PI * day_of_yr) / 365.0; 00029 return( 00030 ( 0.5501*cos(rad) - 3.0195*cos(2*rad) - 0.0771*cos(3*rad) 00031 -7.3403*sin(rad) - 9.4583*sin(2*rad) - 0.3284*sin(3*rad) ) / 60.0 00032 ); 00033 } 00034 00035 /******************function solar_time*************************/ 00036 // PURPOSE: Compute apparent solar time given local standard (not 00037 // daylight savings) time and location. 00038 // EXPECTS: Local standard time, day of year, local standard 00039 // meridian, and local longitude. 00040 // RETURNS: Local solar time in hours (military time) 00041 // SOURCE: Duffie & Beckman. 00042 // 00043 double SolarAngles::solar_time( 00044 double std_time, // Local standard time in decimal hours (e.g., 7:30 is 7.5) 00045 short day_of_yr, // Day of year from Jan 1 00046 double std_meridian, // Standard meridian (longitude) of local time zone (radians---e.g., Pacific timezone is 120 degrees times pi/180) 00047 double longitude // Local longitude (radians west) 00048 ) 00049 { 00050 return std_time + eq_time(day_of_yr) + HR_PER_RADIAN * (std_meridian-longitude); 00051 } 00052 00053 00054 /*****************function local_time*************************/ 00055 // PURPOSE: Compute local standard (not daylight savings) time from 00056 // apparent solar time and location. 00057 // EXPECTS: Apparent solar time, day of year, local standard 00058 // meridian, and local longitude. 00059 // RETURNS: Local solar time in decimal hours. 00060 // SOURCE: Duffie & Beckman. 00061 // 00062 double SolarAngles::local_time( 00063 double sol_time, // Local solar time (decimal hours--7:30 is 7.5) 00064 short day_of_yr, // Day of year from Jan 1 00065 double std_meridian, // Standard meridian (longitude) of local time zone (radians---e.g., Pacific timezone is 120 times pi/180) 00066 double longitude // Local longitude (radians west) 00067 ) 00068 { 00069 return sol_time - eq_time(day_of_yr) - HR_PER_RADIAN * (std_meridian-longitude); 00070 } 00071 00072 00073 /*****************function declination***********************/ 00074 // PURPOSE: Compute the solar declination angle (radians) 00075 // EXPECTS: Day of year from Jan 1. 00076 // RETURNS: Declination angle in radians. 00077 // SOURCE: Duffie & Beckman. 00078 // 00079 double SolarAngles::declination(short day_of_yr) 00080 { 00081 return( 0.409280*sin(2.0*PI*(284+day_of_yr)/365) ); 00082 } 00083 00084 00085 /******************function cos_incident******************/ 00086 // PURPOSE: Compute cosine of angle of incidence of solar beam radiation 00087 // on a surface 00088 // EXPECTS: latitude, surface slope, 00089 // surface azimuth angle, solar time, day of year. 00090 // RETURNS: Cosine of angle of incidence (angle between solar beam and 00091 // surface normal) 00092 // !!! Note that this function is ignorant of the presence !!! 00093 // !!! of the horizon. !!! 00094 // SOURCE: Duffie & Beckman. 00095 // 00096 double SolarAngles::cos_incident( 00097 double latitude, // Latitude (radians north) 00098 double slope, // Slope of surface relative to horizontal (radians) 00099 double az, // Azimuth angle of surface rel. to South (E+, W-) (radians) 00100 double sol_time, // Solar time (decimal hours) 00101 short day_of_yr // Day of year from Jan 1 00102 ) 00103 { 00104 double sindecl,cosdecl,sinlat,coslat,sinslope,cosslope,sinaz,cosaz,sinhr,coshr; // For efficiency 00105 00106 double hr_ang = -(15.0 * PI_OVER_180)*(sol_time-12.0); // morning +, afternoon - 00107 00108 double decl = declination(day_of_yr); 00109 00110 // Precalculate 00111 sindecl = sin(decl); cosdecl = cos(decl); 00112 sinlat = sin(latitude); coslat = cos(latitude); 00113 sinslope = sin(slope); cosslope = cos(slope); 00114 sinaz = sin(az); cosaz = cos(az); 00115 sinhr = sin(hr_ang); coshr = cos(hr_ang); 00116 00117 // The answer... 00118 double answer = sindecl*sinlat*cosslope 00119 -sindecl*coslat*sinslope*cosaz 00120 +cosdecl*coslat*cosslope*coshr 00121 +cosdecl*sinlat*sinslope*cosaz*coshr 00122 +cosdecl*sinslope*sinaz*sinhr; 00123 00124 // Deal with the sun being below the horizon... 00125 return(answer<0.0 ? (double)0.0 : answer); 00126 } 00127 00128 00129 00130 /******************function incident******************/ 00131 // PURPOSE: Compute the angle of incidence of solar 00132 // beam radiation on a surface. 00133 // EXPECTS: latitude, surface slope, 00134 // surface azimuth angle, solar time, day of year. 00135 // RETURNS: Angle of incidence (angle between solar beam and 00136 // surface normal) in radians. 00137 // SOURCE: Duffie & Beckman. 00138 // 00139 double SolarAngles::incident( 00140 double latitude, // Latitude (radians) 00141 double slope, // Slope of surface relative to horizontal (radians) 00142 double az, // Azimuth angle of surface rel. to South (radians, E+, W-) 00143 double sol_time, // Solar time (decimal hours) 00144 short day_of_yr // Day of year from Jan 1 00145 ) 00146 { 00147 return acos(cos_incident(latitude, slope, az, sol_time, day_of_yr)); 00148 } 00149 00150 00151 /*****************function zenith*****************************/ 00152 // PURPOSE: Compute the solar zenith angle (radians, the angle between solar beam 00153 // and the veritical. This could be calculated as the incident 00154 // angle on a horizontal surface, but is more efficient with 00155 // this dedicated function. 00156 // EXPECTS: Day of year, latitude, solar time. 00157 // RETURNS: Zenith angle in radians. 00158 // SOURCE: Duffy & Beckman. 00159 // 00160 double SolarAngles::zenith( 00161 short day_of_yr, // day of year from Jan 1 00162 double latitude, // latitude (radians) 00163 double sol_time // solar time (decimal hours) 00164 ) 00165 { 00166 double hr_ang = -(15.0 * PI_OVER_180)*(sol_time-12.0); // morning +, afternoon - 00167 00168 double decl = declination(day_of_yr); 00169 00170 return acos(sin(decl)*sin(latitude) + cos(decl)*cos(latitude)*cos(hr_ang)); 00171 } 00172 00173 00174 00175 /*****************function altitude*****************************/ 00176 // PURPOSE: Compute the solar altitude angle (radians, angle between solar beam 00177 // and the veritical. This could be calculated as the incident 00178 // angle on a vertical surface, but is more efficient with 00179 // this dedicated function. 00180 // EXPECTS: Day of year, latitude, solar time. 00181 // RETURNS: Altitude angle (angle above horizon) in radians. 00182 // SOURCE: Duffy & Beckman. 00183 // 00184 double SolarAngles::altitude( 00185 short day_of_yr, // day of year from Jan 1 00186 double latitude, // latitude (radians) 00187 double sol_time // solar time (hours) 00188 ) 00189 { 00190 return (90.0 * PI_OVER_180) - zenith(day_of_yr,latitude,sol_time); 00191 } 00192 00193 00194 00195 /*****************function hr_sunrise*****************************/ 00196 // PURPOSE: Compute the hour of sunrise. 00197 // EXPECTS: Declination angle, latitude. 00198 // RETURNS: Solar hour of sunrise. 00199 // SOURCE: Duffy & Beckman. 00200 // 00201 double SolarAngles::hr_sunrise( 00202 short day_of_yr, // solar declination angle (radians) 00203 double latitude // latitude (radians) 00204 ) 00205 { 00206 // Calculate hour angle of sunrise (converted to degrees) 00207 double hr_ang = acos( -tan(latitude)*tan(declination(day_of_yr)) ) / PI_OVER_180; 00208 00209 // Convert hour angle to solar time 00210 return( (-hr_ang/15.0) + 12.0 ); 00211 } 00212 00213 00214 00215 /*****************function day_len********************************/ 00216 // PURPOSE: Compute the length of a given day. 00217 // EXPECTS: Day of year, latitude. 00218 // RETURNS: Day length (hours). 00219 // SOURCE: Duffy & Beckman. 00220 // 00221 double SolarAngles::day_len( 00222 short day_of_yr, // Day of year from Jan 1 00223 double latitude // latitude (radians) 00224 ) 00225 { 00226 return 2.0 * acos( -tan(latitude)*tan(declination(day_of_yr)) ) / (15.0 * PI_OVER_180); 00227 } 00228 00229 00230 00231 /*****************function day_of_yr********************************/ 00232 // PURPOSE: Compute julian day of year. 00233 // EXPECTS: Month, day, year, all as integers. 00234 // RETURNS: Day length (hours). 00235 // 00236 // This ignores leap years but that's okay...the other functions always 00237 // assume a year has only 365 days. 00238 // 00239 short SolarAngles::day_of_yr( 00240 short month, // Month of year (1-12) 00241 short day // Day of month (1-31) 00242 ) 00243 { 00244 00245 // TODO: Error checking on the 1-12 and 1-31... 00246 00247 return days_thru_month[month-1] + day; 00248 }