|
| 1 | +""" |
| 2 | +Simple irradiance adjustment for horizon shading |
| 3 | +================================================ |
| 4 | +
|
| 5 | +Example of applying horizon shading to dni and global poa. Using |
| 6 | +horizon profile data, this example interpolates it to time-series |
| 7 | +solar-position data, and adjust DNI and POA-global irradiance. |
| 8 | +""" |
| 9 | + |
| 10 | +# %% |
| 11 | +# This example shows how to use horizon elevation angles with |
| 12 | +# corresponding horizon azimuth angles for simple horizon shading adjustments. |
| 13 | +# |
| 14 | +# After location information and a date range is established, solar position |
| 15 | +# data is calculated using :py:func:`pvlib.solarposition.get_solarposition`. |
| 16 | +# Horizon data is assigned, and interpolated to the solar azimuth time |
| 17 | +# series data. Finally, in times when solar elevation is greater than the |
| 18 | +# interpolated horizon elevation angle, DNI is set to 0. |
| 19 | + |
| 20 | +import numpy as np |
| 21 | +import pandas as pd |
| 22 | +import pvlib |
| 23 | + |
| 24 | +# Golden, CO |
| 25 | +latitude, longitude = 39.76, -105.22 |
| 26 | +tz = 'MST' |
| 27 | + |
| 28 | +# Set times in the morning of the December solstice. |
| 29 | +times = pd.date_range( |
| 30 | + '2020-12-20 6:30', '2020-12-20 9:00', freq='1T', tz=tz |
| 31 | +) |
| 32 | + |
| 33 | +# Create location object, and get solar position and clearsky irradiance data. |
| 34 | +location = pvlib.location.Location(latitude, longitude, tz) |
| 35 | +solar_position = location.get_solarposition(times) |
| 36 | +clearsky = location.get_clearsky(times) |
| 37 | + |
| 38 | +# Assign variable names for easier reading. |
| 39 | +surface_tilt = 30 |
| 40 | +surface_azimuth = 180 |
| 41 | +solar_azimuth = solar_position.azimuth |
| 42 | +solar_zenith = solar_position.apparent_zenith |
| 43 | +solar_elevation = solar_position.apparent_elevation |
| 44 | +dni = clearsky.dni |
| 45 | +ghi = clearsky.ghi |
| 46 | +dhi = clearsky.dhi |
| 47 | + |
| 48 | +# %% |
| 49 | +# With basic inputs in place, let's perform the adjustment for horizon shading: |
| 50 | + |
| 51 | +# Use hard-coded horizon profile data from location object above. |
| 52 | +horizon_profile = pd.Series([ |
| 53 | + 10.7, 11.8, 11.5, 10.3, 8.0, 6.5, 3.8, 2.3, 2.3, 2.3, 4.6, 8.0, 10.3, 11.1, |
| 54 | + 10.7, 10.3, 9.2, 6.1, 5.3, 2.3, 3.1, 1.9, 1.9, 2.7, 3.8, 5.3, 6.5, 8.4, |
| 55 | + 8.8, 8.4, 8.4, 8.4, 6.5, 6.1, 6.5, 6.1, 7.3, 9.2, 8.4, 8.0, 5.7, 5.3, 5.3, |
| 56 | + 4.2, 4.2, 4.2, 7.3, 9.5 |
| 57 | +], index=np.arange(0, 360, 7.5)) |
| 58 | + |
| 59 | +ax = horizon_profile.plot(xlim=(0, 360), ylim=(0, None), figsize=(6, 2.5)) |
| 60 | +ax.set_title('Horizon profile') |
| 61 | +ax.set_xticks([0, 90, 180, 270, 360]) |
| 62 | +ax.set_xlabel('Azimuth [°]') |
| 63 | +ax.set_ylabel('Horizon angle [°]') |
| 64 | + |
| 65 | +# %% |
| 66 | +# .. admonition:: Horizon data from PVGIS |
| 67 | +# |
| 68 | +# Example of how to get the above horizon data from PVGIS |
| 69 | +# |
| 70 | +# horizon_profile, horizon_metadata = pvlib.iotools.get_pvgis_horizon( |
| 71 | +# latitutde, longitude) |
| 72 | +# |
| 73 | + |
| 74 | +# Interpolate the horizon elevation data to the solar azimuth, and keep as a |
| 75 | +# numpy array. |
| 76 | +horizon_elevation_data = np.interp( |
| 77 | + solar_azimuth, horizon_profile.index, horizon_profile |
| 78 | +) |
| 79 | + |
| 80 | +# Convert to Pandas Series for easier usage. |
| 81 | +horizon_elevation_data = pd.Series(horizon_elevation_data, times) |
| 82 | + |
| 83 | +# Adjust DNI based on data - note this is returned as numpy array |
| 84 | +dni_adjusted = np.where(solar_elevation > horizon_elevation_data, dni, 0) |
| 85 | + |
| 86 | +# Adjust GHI and set it to DHI for time-periods where 'dni_adjusted' is 0. |
| 87 | +# Note this is returned as numpy array |
| 88 | +ghi_adjusted = np.where(dni_adjusted == 0, dhi, ghi) |
| 89 | + |
| 90 | +# Transposition using the original and adjusted irradiance components. |
| 91 | +irrad_pre_adj = pvlib.irradiance.get_total_irradiance( |
| 92 | + surface_tilt, surface_azimuth, solar_zenith, solar_azimuth, dni, ghi, dhi |
| 93 | +) |
| 94 | + |
| 95 | +irrad_post_adj = pvlib.irradiance.get_total_irradiance( |
| 96 | + surface_tilt, surface_azimuth, solar_zenith, solar_azimuth, dni_adjusted, |
| 97 | + ghi_adjusted, dhi |
| 98 | +) |
| 99 | + |
| 100 | +# Create and plot result DataFrames. |
| 101 | +poa_global_comparison = pd.DataFrame({ |
| 102 | + 'poa_global_pre-adjustment': irrad_pre_adj.poa_global, |
| 103 | + 'poa_global_post-adjustment': irrad_post_adj.poa_global |
| 104 | +}) |
| 105 | + |
| 106 | +dni_comparison = pd.DataFrame({ |
| 107 | + 'dni_pre-adjustment': dni, |
| 108 | + 'dni_post-adjustment': dni_adjusted |
| 109 | +}) |
| 110 | + |
| 111 | +# Plot results |
| 112 | +poa_global_comparison.plot( |
| 113 | + title='POA-Global: Before and after Horizon Adjustment', |
| 114 | + ylabel='Irradiance' |
| 115 | +) |
| 116 | +dni_comparison.plot( |
| 117 | + title='DNI: Before and after Horizon Adjustment', ylabel='Irradiance' |
| 118 | +) |
0 commit comments