def aoi_projection(surf_tilt, surf_az, sun_zen, sun_az): """ Calculates the dot product of the solar vector and the surface normal. Input all angles in degrees. Parameters ========== surf_tilt : float or Series. Panel tilt from horizontal. surf_az : float or Series. Panel azimuth from north. sun_zen : float or Series. Solar zenith angle. sun_az : float or Series. Solar azimuth angle. Returns ======= float or Series. Dot product of panel normal and solar angle. """ projection = pvl_tools.cosd(surf_tilt)*pvl_tools.cosd(sun_zen) + pvl_tools.sind(surf_tilt)*pvl_tools.sind(sun_zen)*pvl_tools.cosd(sun_az - surf_az) try: projection.name = 'aoi_projection' except AttributeError: pass return projection
def poa_horizontal_ratio(surf_tilt, surf_az, sun_zen, sun_az): """ Calculates the ratio of the beam components of the plane of array irradiance and the horizontal irradiance. Input all angles in degrees. :param surf_tilt: float or Series. Panel tilt from horizontal. :param surf_az: float or Series. Panel azimuth from north. :param sun_zen: float or Series. Solar zenith angle. :param sun_az: float or Series. Solar azimuth angle. :returns: float or Series. Ratio of the plane of array irradiance to the horizontal plane irradiance """ cos_poa_zen = aoi_projection(surf_tilt, surf_az, sun_zen, sun_az) cos_sun_zen = pvl_tools.cosd(sun_zen) # ratio of titled and horizontal beam irradiance ratio = cos_poa_zen / cos_sun_zen try: ratio.name = 'poa_ratio' except AttributeError: pass return ratio
def king(surf_tilt, DHI, GHI, sun_zen): ''' Determine diffuse irradiance from the sky on a tilted surface using the King model King's model determines the diffuse irradiance from the sky (ground reflected irradiance is not included in this algorithm) on a tilted surface using the surface tilt angle, diffuse horizontal irradiance, global horizontal irradiance, and sun zenith angle. Note that this model is not well documented and has not been published in any fashion (as of January 2012). Parameters ---------- surf_tilt : float or Series Surface tilt angles in decimal degrees. The tilt angle is defined as degrees from horizontal (e.g. surface facing up = 0, surface facing horizon = 90) DHI : float or Series diffuse horizontal irradiance in W/m^2. GHI : float or Series global horizontal irradiance in W/m^2. sun_zen : float or Series apparent (refraction-corrected) zenith angles in decimal degrees. Returns -------- SkyDiffuse : float or Series the diffuse component of the solar radiation on an arbitrarily tilted surface as given by a model developed by David L. King at Sandia National Laboratories. See Also -------- pvl_ephemeris pvl_extraradiation pvl_isotropicsky pvl_haydavies1980 pvl_perez pvl_klucher1979 pvl_reindl1990 ''' pvl_logger.debug('diffuse_sky.king()') sky_diffuse = DHI * ((1 + pvl_tools.cosd(surf_tilt))) / 2 + GHI*((0.012 * sun_zen - 0.04))*((1 - pvl_tools.cosd(surf_tilt))) / 2 sky_diffuse[sky_diffuse < 0] = 0 return sky_diffuse
def haurwitz(ApparentZenith): ''' Determine clear sky GHI from Haurwitz model Implements the Haurwitz clear sky model for global horizontal irradiance (GHI) as presented in [1, 2]. A report on clear sky models found the Haurwitz model to have the best performance of models which require only zenith angle [3]. Extreme care should be taken in the interpretation of this result! Parameters ---------- ApparentZenith : DataFrame The apparent (refraction corrected) sun zenith angle in degrees. Returns ------- ClearSkyGHI : DataFrame the modeled global horizonal irradiance in W/m^2 provided by the Haurwitz clear-sky model. Initial implementation of this algorithm by Matthew Reno. References ---------- [1] B. Haurwitz, "Insolation in Relation to Cloudiness and Cloud Density," Journal of Meteorology, vol. 2, pp. 154-166, 1945. [2] B. Haurwitz, "Insolation in Relation to Cloud Type," Journal of Meteorology, vol. 3, pp. 123-124, 1946. [3] M. Reno, C. Hansen, and J. Stein, "Global Horizontal Irradiance Clear Sky Models: Implementation and Analysis", Sandia National Laboratories, SAND2012-2389, 2012. See Also --------- pvl_maketimestruct pvl_makelocationstruct pvl_ephemeris pvl_spa pvl_ineichen ''' cos_zenith = pvl_tools.cosd(ApparentZenith) clearsky_GHI = 1098.0 * cos_zenith * np.exp(-0.059/cos_zenith) clearsky_GHI[clearsky_GHI < 0] = 0 df_out = pd.DataFrame({'GHI':clearsky_GHI}) return df_out
def perez(surf_tilt, surf_az, DHI, DNI, DNI_ET, sun_zen, sun_az, AM, modelt='allsitescomposite1990'): ''' Determine diffuse irradiance from the sky on a tilted surface using one of the Perez models Perez models determine the diffuse irradiance from the sky (ground reflected irradiance is not included in this algorithm) on a tilted surface using the surface tilt angle, surface azimuth angle, diffuse horizontal irradiance, direct normal irradiance, extraterrestrial irradiance, sun zenith angle, sun azimuth angle, and relative (not pressure-corrected) airmass. Optionally a selector may be used to use any of Perez's model coefficient sets. Parameters ---------- surf_tilt : float or Series Surface tilt angles in decimal degrees. surf_tilt must be >=0 and <=180. The tilt angle is defined as degrees from horizontal (e.g. surface facing up = 0, surface facing horizon = 90) surf_az : float or Series Surface azimuth angles in decimal degrees. surf_az must be >=0 and <=360. The Azimuth convention is defined as degrees east of north (e.g. North = 0, South=180 East = 90, West = 270). DHI : float or Series diffuse horizontal irradiance in W/m^2. DHI must be >=0. DNI : float or Series direct normal irradiance in W/m^2. DNI must be >=0. DNI_ET : float or Series extraterrestrial normal irradiance in W/m^2. DNI_ET must be >=0. sun_zen : float or Series apparent (refraction-corrected) zenith angles in decimal degrees. sun_zen must be >=0 and <=180. sun_az : float or Series Sun azimuth angles in decimal degrees. sun_az must be >=0 and <=360. The Azimuth convention is defined as degrees east of north (e.g. North = 0, East = 90, West = 270). AM : float or Series relative (not pressure-corrected) airmass values. If AM is a DataFrame it must be of the same size as all other DataFrame inputs. AM must be >=0 (careful using the 1/sec(z) model of AM generation) Other Parameters ---------------- model : string (optional, default='allsitescomposite1990') a character string which selects the desired set of Perez coefficients. If model is not provided as an input, the default, '1990' will be used. All possible model selections are: * '1990' * 'allsitescomposite1990' (same as '1990') * 'allsitescomposite1988' * 'sandiacomposite1988' * 'usacomposite1988' * 'france1988' * 'phoenix1988' * 'elmonte1988' * 'osage1988' * 'albuquerque1988' * 'capecanaveral1988' * 'albany1988' Returns -------- float or Series the diffuse component of the solar radiation on an arbitrarily tilted surface defined by the Perez model as given in reference [3]. SkyDiffuse is the diffuse component ONLY and does not include the ground reflected irradiance or the irradiance due to the beam. References ---------- [1] Loutzenhiser P.G. et. al. "Empirical validation of models to compute solar irradiance on inclined surfaces for building energy simulation" 2007, Solar Energy vol. 81. pp. 254-267 [2] Perez, R., Seals, R., Ineichen, P., Stewart, R., Menicucci, D., 1987. A new simplified version of the Perez diffuse irradiance model for tilted surfaces. Solar Energy 39(3), 221-232. [3] Perez, R., Ineichen, P., Seals, R., Michalsky, J., Stewart, R., 1990. Modeling daylight availability and irradiance components from direct and global irradiance. Solar Energy 44 (5), 271-289. [4] Perez, R. et. al 1988. "The Development and Verification of the Perez Diffuse Radiation Model". SAND88-7030 See also -------- pvl_ephemeris pvl_extraradiation pvl_isotropicsky pvl_haydavies1980 pvl_reindl1990 pvl_klucher1979 pvl_kingdiffuse pvl_relativeairmass ''' pvl_logger.debug('diffuse_sky.perez()') kappa = 1.041 #for sun_zen in radians z = np.radians(sun_zen) # convert to radians # epsilon is the sky's "clearness" eps = ( (DHI + DNI)/DHI + kappa*(z**3) ) / ( 1 + kappa*(z**3) ) # Perez et al define clearness bins according to the following rules. # 1 = overcast ... 8 = clear # (these names really only make sense for small zenith angles, but...) # these values will eventually be used as indicies for coeffecient look ups ebin = eps.copy() ebin[(eps<1.065)] = 1 ebin[(eps>=1.065) & (eps<1.23)] = 2 ebin[(eps>=1.23) & (eps<1.5)] = 3 ebin[(eps>=1.5) & (eps<1.95)] = 4 ebin[(eps>=1.95) & (eps<2.8)] = 5 ebin[(eps>=2.8) & (eps<4.5)] = 6 ebin[(eps>=4.5) & (eps<6.2)] = 7 ebin[eps>=6.2] = 8 ebin = ebin - 1 #correct for 0 indexing in coeffecient lookup # remove night time values ebin = ebin.dropna().astype(int) # This is added because in cases where the sun is below the horizon # (var.sun_zen > 90) but there is still diffuse horizontal light (var.DHI>0), it is # possible that the airmass (var.AM) could be NaN, which messes up later # calculations. Instead, if the sun is down, and there is still var.DHI, we set # the airmass to the airmass value on the horizon (approximately 37-38). #var.AM(var.sun_zen >=90 & var.DHI >0) = 37; #var.DNI_ET[var.DNI_ET==0] = .00000001 #very hacky, fix this # delta is the sky's "brightness" delta = DHI * AM / DNI_ET # keep only valid times delta = delta[ebin.index] z = z[ebin.index] # The various possible sets of Perez coefficients are contained # in a subfunction to clean up the code. F1c, F2c = _get_perez_coefficients(modelt) F1 = F1c[ebin,0] + F1c[ebin,1]*delta + F1c[ebin,2]*z F1[F1 < 0] = 0; F1 = F1.astype(float) F2 = F2c[ebin,0] + F2c[ebin,1]*delta + F2c[ebin,2]*z F2[F2 < 0] = 0 F2 = F2.astype(float) A = aoi_projection(surf_tilt, surf_az, sun_zen, sun_az) A[A < 0] = 0 B = pvl_tools.cosd(sun_zen); B[B < pvl_tools.cosd(85)] = pvl_tools.cosd(85) #Calculate Diffuse POA from sky dome term1 = 0.5 * (1 - F1) * (1 + pvl_tools.cosd(surf_tilt)) term2 = F1 * A[ebin.index] / B[ebin.index] term3 = F2*pvl_tools.sind(surf_tilt) sky_diffuse = DHI[ebin.index] * (term1 + term2 + term3) sky_diffuse[sky_diffuse < 0] = 0 return sky_diffuse
def reindl(surf_tilt, surf_az, DHI, DNI, GHI, DNI_ET, sun_zen, sun_az): ''' Determine diffuse irradiance from the sky on a tilted surface using Reindl's 1990 model .. math:: I_{d} = DHI (A R_b + (1 - A) (\frac{1 + \cos\beta}{2}) (1 + \sqrt{\frac{I_{hb}}{I_h}} \sin^3(\beta/2)) ) Reindl's 1990 model determines the diffuse irradiance from the sky (ground reflected irradiance is not included in this algorithm) on a tilted surface using the surface tilt angle, surface azimuth angle, diffuse horizontal irradiance, direct normal irradiance, global horizontal irradiance, extraterrestrial irradiance, sun zenith angle, and sun azimuth angle. Parameters ---------- surf_tilt : float or Series. Surface tilt angles in decimal degrees. The tilt angle is defined as degrees from horizontal (e.g. surface facing up = 0, surface facing horizon = 90) surf_az : float or Series. Surface azimuth angles in decimal degrees. The Azimuth convention is defined as degrees east of north (e.g. North = 0, South=180 East = 90, West = 270). DHI : float or Series. diffuse horizontal irradiance in W/m^2. DNI : float or Series. direct normal irradiance in W/m^2. GHI: float or Series. Global irradiance in W/m^2. DNI_ET : float or Series. extraterrestrial normal irradiance in W/m^2. sun_zen : float or Series. apparent (refraction-corrected) zenith angles in decimal degrees. sun_az : float or Series. Sun azimuth angles in decimal degrees. The Azimuth convention is defined as degrees east of north (e.g. North = 0, East = 90, West = 270). Returns ------- SkyDiffuse : float or Series. the diffuse component of the solar radiation on an arbitrarily tilted surface defined by the Reindl model as given in Loutzenhiser et. al (2007) equation 8. SkyDiffuse is the diffuse component ONLY and does not include the ground reflected irradiance or the irradiance due to the beam. SkyDiffuse is a column vector vector with a number of elements equal to the input vector(s). Notes ----- The POAskydiffuse calculation is generated from the Loutzenhiser et al. (2007) paper, equation 8. Note that I have removed the beam and ground reflectance portion of the equation and this generates ONLY the diffuse radiation from the sky and circumsolar, so the form of the equation varies slightly from equation 8. References ---------- [1] Loutzenhiser P.G. et. al. "Empirical validation of models to compute solar irradiance on inclined surfaces for building energy simulation" 2007, Solar Energy vol. 81. pp. 254-267 [2] Reindl, D.T., Beckmann, W.A., Duffie, J.A., 1990a. Diffuse fraction correlations. Solar Energy 45(1), 1-7. [3] Reindl, D.T., Beckmann, W.A., Duffie, J.A., 1990b. Evaluation of hourly tilted surface radiation models. Solar Energy 45(1), 9-17. See Also --------- pvl_ephemeris pvl_extraradiation pvl_isotropicsky pvl_haydavies1980 pvl_perez pvl_klucher1979 pvl_kingdiffuse ''' pvl_logger.debug('diffuse_sky.reindl()') cos_tt = aoi_projection(surf_tilt, surf_az, sun_zen, sun_az) cos_sun_zen = pvl_tools.cosd(sun_zen) # ratio of titled and horizontal beam irradiance Rb = cos_tt / cos_sun_zen # Anisotropy Index AI = DNI / DNI_ET # DNI projected onto horizontal HB = DNI * cos_sun_zen HB[HB < 0] = 0 # these are actually the () and [] sub-terms of the second term of eqn 8 term1 = 1 - AI term2 = 0.5 * (1 + pvl_tools.cosd(surf_tilt)) term3 = 1 + np.sqrt(HB / GHI) * (pvl_tools.sind(0.5*surf_tilt) ** 3) sky_diffuse = DHI * ( AI*Rb + term1 * term2 * term3 ) sky_diffuse[sky_diffuse < 0] = 0 return sky_diffuse
def haydavies(surf_tilt, surf_az, DHI, DNI, DNI_ET, sun_zen, sun_az): ''' Determine diffuse irradiance from the sky on a tilted surface using Hay & Davies' 1980 model .. math:: I_{d} = DHI ( A R_b + (1 - A) (\frac{1 + \cos\beta}{2}) ) Hay and Davies' 1980 model determines the diffuse irradiance from the sky (ground reflected irradiance is not included in this algorithm) on a tilted surface using the surface tilt angle, surface azimuth angle, diffuse horizontal irradiance, direct normal irradiance, extraterrestrial irradiance, sun zenith angle, and sun azimuth angle. Parameters ---------- surf_tilt : float or Series Surface tilt angles in decimal degrees. The tilt angle is defined as degrees from horizontal (e.g. surface facing up = 0, surface facing horizon = 90) surf_az : float or Series Surface azimuth angles in decimal degrees. The Azimuth convention is defined as degrees east of north (e.g. North = 0, South=180 East = 90, West = 270). DHI : float or Series diffuse horizontal irradiance in W/m^2. DNI : float or Series direct normal irradiance in W/m^2. DNI_ET : float or Series extraterrestrial normal irradiance in W/m^2. sun_zen : float or Series apparent (refraction-corrected) zenith angles in decimal degrees. sun_az : float or Series Sun azimuth angles in decimal degrees. The Azimuth convention is defined as degrees east of north (e.g. North = 0, East = 90, West = 270). Returns -------- SkyDiffuse : float or Series the diffuse component of the solar radiation on an arbitrarily tilted surface defined by the Perez model as given in reference [3]. SkyDiffuse is the diffuse component ONLY and does not include the ground reflected irradiance or the irradiance due to the beam. References ----------- [1] Loutzenhiser P.G. et. al. "Empirical validation of models to compute solar irradiance on inclined surfaces for building energy simulation" 2007, Solar Energy vol. 81. pp. 254-267 [2] Hay, J.E., Davies, J.A., 1980. Calculations of the solar radiation incident on an inclined surface. In: Hay, J.E., Won, T.K. (Eds.), Proc. of First Canadian Solar Radiation Data Workshop, 59. Ministry of Supply and Services, Canada. See Also -------- pvl_ephemeris pvl_extraradiation pvl_isotropicsky pvl_reindl1990 pvl_perez pvl_klucher1979 pvl_kingdiffuse pvl_spa ''' pvl_logger.debug('diffuse_sky.haydavies()') cos_tt = aoi_projection(surf_tilt, surf_az, sun_zen, sun_az) cos_sun_zen = pvl_tools.cosd(sun_zen) # ratio of titled and horizontal beam irradiance Rb = cos_tt / cos_sun_zen # Anisotropy Index AI = DNI / DNI_ET # these are actually the () and [] sub-terms of the second term of eqn 7 term1 = 1 - AI term2 = 0.5 * (1 + pvl_tools.cosd(surf_tilt)) sky_diffuse = DHI * ( AI*Rb + term1 * term2 ) sky_diffuse[sky_diffuse < 0] = 0 return sky_diffuse
def klucher(surf_tilt, surf_az, DHI, GHI, sun_zen, sun_az): ''' Determine diffuse irradiance from the sky on a tilted surface using Klucher's 1979 model .. math:: I_{d} = DHI \frac{1 + \cos\beta}{2} (1 + F' \sin^3(\beta/2)) (1 + F' \cos^2\theta\sin^3\theta_z) where .. math:: F' = 1 - (I_{d0} / GHI) Klucher's 1979 model determines the diffuse irradiance from the sky (ground reflected irradiance is not included in this algorithm) on a tilted surface using the surface tilt angle, surface azimuth angle, diffuse horizontal irradiance, direct normal irradiance, global horizontal irradiance, extraterrestrial irradiance, sun zenith angle, and sun azimuth angle. Parameters ---------- surf_tilt : float or Series Surface tilt angles in decimal degrees. surf_tilt must be >=0 and <=180. The tilt angle is defined as degrees from horizontal (e.g. surface facing up = 0, surface facing horizon = 90) surf_az : float or Series Surface azimuth angles in decimal degrees. surf_az must be >=0 and <=360. The Azimuth convention is defined as degrees east of north (e.g. North = 0, South=180 East = 90, West = 270). DHI : float or Series diffuse horizontal irradiance in W/m^2. DHI must be >=0. GHI : float or Series Global irradiance in W/m^2. DNI must be >=0. sun_zen : float or Series apparent (refraction-corrected) zenith angles in decimal degrees. sun_zen must be >=0 and <=180. sun_az : float or Series Sun azimuth angles in decimal degrees. sun_az must be >=0 and <=360. The Azimuth convention is defined as degrees east of north (e.g. North = 0, East = 90, West = 270). Returns ------- float or Series the diffuse component of the solar radiation on an arbitrarily tilted surface defined by the Klucher model as given in Loutzenhiser et. al (2007) equation 4. SkyDiffuse is the diffuse component ONLY and does not include the ground reflected irradiance or the irradiance due to the beam. SkyDiffuse is a column vector vector with a number of elements equal to the input vector(s). References ---------- [1] Loutzenhiser P.G. et. al. "Empirical validation of models to compute solar irradiance on inclined surfaces for building energy simulation" 2007, Solar Energy vol. 81. pp. 254-267 [2] Klucher, T.M., 1979. Evaluation of models to predict insolation on tilted surfaces. Solar Energy 23 (2), 111-114. See also -------- pvl_ephemeris pvl_extraradiation pvl_isotropicsky pvl_haydavies1980 pvl_perez pvl_reindl1990 pvl_kingdiffuse ''' pvl_logger.debug('diffuse_sky.klucher()') # zenith angle with respect to panel normal. cos_tt = aoi_projection(surf_tilt, surf_az, sun_zen, sun_az) F = 1 - ((DHI / GHI) ** 2) try: # fails with single point input F.fillna(0, inplace=True) except AttributeError: F = 0 term1 = 0.5 * (1 + pvl_tools.cosd(surf_tilt)) term2 = 1 + F * (pvl_tools.sind(0.5*surf_tilt) ** 3) term3 = 1 + F * (cos_tt ** 2) * (pvl_tools.sind(sun_zen) ** 3) sky_diffuse = DHI * term1 * term2 * term3 return sky_diffuse
def isotropic(surf_tilt, DHI): ''' Determine diffuse irradiance from the sky on a tilted surface using the isotropic sky model. .. math:: I_{d} = DHI \frac{1 + \cos\beta}{2} Hottel and Woertz's model treats the sky as a uniform source of diffuse irradiance. Thus the diffuse irradiance from the sky (ground reflected irradiance is not included in this algorithm) on a tilted surface can be found from the diffuse horizontal irradiance and the tilt angle of the surface. Parameters ---------- surf_tilt : float or Series Surface tilt angle in decimal degrees. surf_tilt must be >=0 and <=180. The tilt angle is defined as degrees from horizontal (e.g. surface facing up = 0, surface facing horizon = 90) DHI : float or Series Diffuse horizontal irradiance in W/m^2. DHI must be >=0. Returns ------- float or Series The diffuse component of the solar radiation on an arbitrarily tilted surface defined by the isotropic sky model as given in Loutzenhiser et. al (2007) equation 3. SkyDiffuse is the diffuse component ONLY and does not include the ground reflected irradiance or the irradiance due to the beam. SkyDiffuse is a column vector vector with a number of elements equal to the input vector(s). References ---------- [1] Loutzenhiser P.G. et. al. "Empirical validation of models to compute solar irradiance on inclined surfaces for building energy simulation" 2007, Solar Energy vol. 81. pp. 254-267 [2] Hottel, H.C., Woertz, B.B., 1942. Evaluation of flat-plate solar heat collector. Trans. ASME 64, 91. See also -------- pvl_reindl1990 pvl_haydavies1980 pvl_perez pvl_klucher1979 pvl_kingdiffuse ''' pvl_logger.debug('diffuse_sky.isotropic()') sky_diffuse = DHI * (1 + pvl_tools.cosd(surf_tilt)) * 0.5 return sky_diffuse
def physicaliam(K,L,n,theta): ''' Determine the incidence angle modifier using refractive index, glazing thickness, and extinction coefficient pvl_physicaliam calculates the incidence angle modifier as described in De Soto et al. "Improvement and validation of a model for photovoltaic array performance", section 3. The calculation is based upon a physical model of absorbtion and transmission through a cover. Required information includes, incident angle, cover extinction coefficient, cover thickness Note: The authors of this function believe that eqn. 14 in [1] is incorrect. This function uses the following equation in its place: theta_r = arcsin(1/n * sin(theta)) Parameters ---------- K : float The glazing extinction coefficient in units of 1/meters. Reference [1] indicates that a value of 4 is reasonable for "water white" glass. K must be a numeric scalar or vector with all values >=0. If K is a vector, it must be the same size as all other input vectors. L : float The glazing thickness in units of meters. Reference [1] indicates that 0.002 meters (2 mm) is reasonable for most glass-covered PV panels. L must be a numeric scalar or vector with all values >=0. If L is a vector, it must be the same size as all other input vectors. n : float The effective index of refraction (unitless). Reference [1] indicates that a value of 1.526 is acceptable for glass. n must be a numeric scalar or vector with all values >=0. If n is a vector, it must be the same size as all other input vectors. theta :float The angle of incidence between the module normal vector and the sun-beam vector in degrees. Theta must be a numeric scalar or vector. For any values of theta where abs(theta)>90, IAM is set to 0. For any values of theta where -90 < theta < 0, theta is set to abs(theta) and evaluated. A warning will be generated if any(theta<0 or theta>90). Returns ------- IAM : float The incident angle modifier as specified in eqns. 14-16 of [1]. IAM is a column vector with the same number of elements as the largest input vector. References ---------- [1] W. De Soto et al., "Improvement and validation of a model for photovoltaic array performance", Solar Energy, vol 80, pp. 78-88, 2006. [2] Duffie, John A. & Beckman, William A.. (2006). Solar Engineering of Thermal Processes, third edition. [Books24x7 version] Available from http://common.books24x7.com/toc.aspx?bookid=17160. See Also -------- pvl_getaoi pvl_ephemeris pvl_spa pvl_ashraeiam ''' Vars=locals() Expect={'K':'x >= 0', 'L':'x >= 0', 'n':'x >= 0', 'theta':'num'} var=pvl_tools.Parse(Vars,Expect) if any((var.theta < 0) | (var.theta >= 90)): print('Input incident angles <0 or >=90 detected For input angles with absolute value greater than 90, the ' + 'modifier is set to 0. For input angles between -90 and 0, the ' + 'angle is changed to its absolute value and evaluated.') var.theta[(var.theta < 0) | (var.theta >= 90)]=abs((var.theta < 0) | (var.theta >= 90)) thetar_deg=pvl_tools.asind(1.0 / n*(pvl_tools.sind(theta))) tau=np.exp(- 1.0 * (K*(L) / pvl_tools.cosd(thetar_deg)))*((1 - 0.5*((((pvl_tools.sind(thetar_deg - theta)) ** 2) / ((pvl_tools.sind(thetar_deg + theta)) ** 2) + ((pvl_tools.tand(thetar_deg - theta)) ** 2) / ((pvl_tools.tand(thetar_deg + theta)) ** 2))))) zeroang=1e-06 thetar_deg0=pvl_tools.asind(1.0 / n*(pvl_tools.sind(zeroang))) tau0=np.exp(- 1.0 * (K*(L) / pvl_tools.cosd(thetar_deg0)))*((1 - 0.5*((((pvl_tools.sind(thetar_deg0 - zeroang)) ** 2) / ((pvl_tools.sind(thetar_deg0 + zeroang)) ** 2) + ((pvl_tools.tand(thetar_deg0 - zeroang)) ** 2) / ((pvl_tools.tand(thetar_deg0 + zeroang)) ** 2))))) IAM=tau / tau0 IAM[theta == 0]=1 IAM[abs(theta) > 90 | (IAM < 0)]=0 return IAM
def ineichen(time, location, linke_turbidity=None, solarposition_method='pyephem', zenith_data=None, airmass_model='young1994', airmass_data=None, interp_turbidity=True): ''' Determine clear sky GHI, DNI, and DHI from Ineichen/Perez model Implements the Ineichen and Perez clear sky model for global horizontal irradiance (GHI), direct normal irradiance (DNI), and calculates the clear-sky diffuse horizontal (DHI) component as the difference between GHI and DNI*cos(zenith) as presented in [1, 2]. A report on clear sky models found the Ineichen/Perez model to have excellent performance with a minimal input data set [3]. Default values for Linke turbidity provided by SoDa [4, 5]. Parameters ----------- time : pandas.DatetimeIndex location : pvlib.Location linke_turbidity : None or float solarposition_method : string See pvlib.solarposition.get_solarposition() zenith_data : None or pandas.Series If None, ephemeris data will be calculated using ``solarposition_method``. airmass_model : string See pvlib.airmass.relativeairmass(). airmass_data : None or pandas.Series If None, absolute air mass data will be calculated using ``airmass_model`` and location.alitude. Returns -------- ClearSkyGHI : Dataframe the modeled global horizonal irradiance in W/m^2 provided by the Ineichen clear-sky model. ClearSkyDNI : Dataframe the modeled direct normal irradiance in W/m^2 provided by the Ineichen clear-sky model. ClearSkyDHI : Dataframe the calculated diffuse horizonal irradiance in W/m^2 provided by the Ineichen clear-sky model. Notes ----- If you are using this function in a loop, it may be faster to load LinkeTurbidities.mat outside of the loop and feed it in as a variable, rather than having the function open the file each time it is called. References ---------- [1] P. Ineichen and R. Perez, "A New airmass independent formulation for the Linke turbidity coefficient", Solar Energy, vol 73, pp. 151-157, 2002. [2] R. Perez et. al., "A New Operational Model for Satellite-Derived Irradiances: Description and Validation", Solar Energy, vol 73, pp. 307-317, 2002. [3] M. Reno, C. Hansen, and J. Stein, "Global Horizontal Irradiance Clear Sky Models: Implementation and Analysis", Sandia National Laboratories, SAND2012-2389, 2012. [4] http://www.soda-is.com/eng/services/climat_free_eng.php#c5 (obtained July 17, 2012). [5] J. Remund, et. al., "Worldwide Linke Turbidity Information", Proc. ISES Solar World Congress, June 2003. Goteborg, Sweden. ''' # Initial implementation of this algorithm by Matthew Reno. # Ported to python by Rob Andrews # Added functionality by Will Holmgren I0 = irradiance.extraradiation(time.dayofyear) if zenith_data is None: ephem_data = solarposition.get_solarposition(time, location, method=solarposition_method) time = ephem_data.index # fixes issue with time possibly not being tz-aware try: ApparentZenith = ephem_data['apparent_zenith'] except KeyError: ApparentZenith = ephem_data['zenith'] pvl_logger.warning('could not find apparent_zenith. using zenith') else: ApparentZenith = zenith_data #ApparentZenith[ApparentZenith >= 90] = 90 # can cause problems in edge cases if linke_turbidity is None: # The .mat file 'LinkeTurbidities.mat' contains a single 2160 x 4320 x 12 # matrix of type uint8 called 'LinkeTurbidity'. The rows represent global # latitudes from 90 to -90 degrees; the columns represent global longitudes # from -180 to 180; and the depth (third dimension) represents months of # the year from January (1) to December (12). To determine the Linke # turbidity for a position on the Earth's surface for a given month do the # following: LT = LinkeTurbidity(LatitudeIndex, LongitudeIndex, month). # Note that the numbers within the matrix are 20 * Linke Turbidity, # so divide the number from the file by 20 to get the # turbidity. # consider putting this code at module level this_path = os.path.dirname(os.path.abspath(__file__)) pvl_logger.debug('this_path={}'.format(this_path)) mat = scipy.io.loadmat(os.path.join(this_path, 'data', 'LinkeTurbidities.mat')) linke_turbidity = mat['LinkeTurbidity'] LatitudeIndex = np.round_(_linearly_scale(location.latitude,90,- 90,1,2160)) LongitudeIndex = np.round_(_linearly_scale(location.longitude,- 180,180,1,4320)) g = linke_turbidity[LatitudeIndex][LongitudeIndex] if interp_turbidity: pvl_logger.info('interpolating turbidity to the day') g2 = np.concatenate([[g[-1]], g, [g[0]]]) # wrap ends around days = np.linspace(-15, 380, num=14) # map day of year onto month (approximate) LT = pd.Series(np.interp(time.dayofyear, days, g2), index=time) else: pvl_logger.info('using monthly turbidity') ApplyMonth = lambda x:g[x[0]-1] LT = pd.DataFrame(time.month, index=time) LT = LT.apply(ApplyMonth, axis=1) TL = LT / 20. pvl_logger.info('using TL=\n{}'.format(TL)) else: TL = linke_turbidity # Get the absolute airmass assuming standard local pressure (per # pvl_alt2pres) using Kasten and Young's 1989 formula for airmass. if airmass_data is None: AMabsolute = atmosphere.absoluteairmass(AMrelative=atmosphere.relativeairmass(ApparentZenith, airmass_model), pressure=atmosphere.alt2pres(location.altitude)) else: AMabsolute = airmass_data fh1 = np.exp(-location.altitude/8000.) fh2 = np.exp(-location.altitude/1250.) cg1 = 5.09e-05 * location.altitude + 0.868 cg2 = 3.92e-05 * location.altitude + 0.0387 pvl_logger.debug('fh1={}, fh2={}, cg1={}, cg2={}'.format(fh1, fh2, cg1, cg2)) # Dan's note on the TL correction: By my reading of the publication on # pages 151-157, Ineichen and Perez introduce (among other things) three # things. 1) Beam model in eqn. 8, 2) new turbidity factor in eqn 9 and # appendix A, and 3) Global horizontal model in eqn. 11. They do NOT appear # to use the new turbidity factor (item 2 above) in either the beam or GHI # models. The phrasing of appendix A seems as if there are two separate # corrections, the first correction is used to correct the beam/GHI models, # and the second correction is used to correct the revised turibidity # factor. In my estimation, there is no need to correct the turbidity # factor used in the beam/GHI models. # Create the corrected TL for TL < 2 # TLcorr = TL; # TLcorr(TL < 2) = TLcorr(TL < 2) - 0.25 .* (2-TLcorr(TL < 2)) .^ (0.5); # This equation is found in Solar Energy 73, pg 311. # Full ref: Perez et. al., Vol. 73, pp. 307-317 (2002). # It is slightly different than the equation given in Solar Energy 73, pg 156. # We used the equation from pg 311 because of the existence of known typos # in the pg 156 publication (notably the fh2-(TL-1) should be fh2 * (TL-1)). cos_zenith = pvl_tools.cosd(ApparentZenith) clearsky_GHI = cg1 * I0 * cos_zenith * np.exp(-cg2*AMabsolute*(fh1 + fh2*(TL - 1))) * np.exp(0.01*AMabsolute**1.8) clearsky_GHI[clearsky_GHI < 0] = 0 # BncI == "normal beam clear sky radiation" b = 0.664 + 0.163/fh1 BncI = b * I0 * np.exp( -0.09 * AMabsolute * (TL - 1) ) pvl_logger.debug('b={}'.format(b)) # "empirical correction" SE 73, 157 & SE 73, 312. BncI_2 = clearsky_GHI * ( 1 - (0.1 - 0.2*np.exp(-TL))/(0.1 + 0.882/fh1) ) / cos_zenith #return BncI, BncI_2 clearsky_DNI = np.minimum(BncI, BncI_2) # Will H: use np.minimum explicitly clearsky_DHI = clearsky_GHI - clearsky_DNI*cos_zenith df_out = pd.DataFrame({'GHI':clearsky_GHI, 'DNI':clearsky_DNI, 'DHI':clearsky_DHI}) df_out.fillna(0, inplace=True) #df_out['BncI'] = BncI #df_out['BncI_2'] = BncI return df_out