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