Search code examples
pythonpvlib

How to get clear sky irradiance with horizon in PVLib?


Is there a way to take into account the horizon in PVLib ?

I have PV systems in the mountains, so with high neigbouring montains affecting the horizon. I have simulated the clearsky irradiance with PVLib, PVGis with and without horizon (see next figure). We see that the difference is significant.

  • Is it possible to consider the horizon of the Location when calling the Location.get_clearsky() function ?
  • If not, is there another way to consider the impact of the horizon with PVLib?
  • If not, it is possible to run a ModelChain (that use the pvwatts AC and DC models) only with the clearsky GHI+Horizon comming from PVGIS, even if no DNI and DHI are provided ?

Clear Sky Irradiance comparison between PVGIS and PVLib (in a valley, in January)


PS: This is my code to get the clearsky irradiance and the PV system AC Power:

# Location
locationValley = Location(latitude=46.179, longitude=7.602, altitude=1431, tz='Europe/Zurich', name='Valley')

# Weather
datetime = pd.date_range(start='2022-01-01', end='2022-01-02', freq='5min', tz=locationValley.tz, inclusive='left')
csPowerValley = locationValley.get_clearsky(datetime)  # ineichen with climatology table by default

# ModelChain
array1 = Array(
        mount=FixedMount(surface_tilt=30, surface_azimuth=241, racking_model = 'open_rack'),
        module_parameters={'pdc0': 55, 'gamma_pdc' : -0.004},
        module_type = 'glass_polymer',
        modules_per_string = 445, # 445 modules for 1 string or 89 modules for 5 strings is the same
        strings = 1,
        temperature_model_parameters=pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_polymer'],
    )
system = PVSystem(arrays=[array1], inverter_parameters={'pdc0': 24475, 'eta_inv_nom': 0.96})
modelChain = ModelChain(system, locationValley, clearsky_model = 'ineichen', aoi_model='no_loss', spectral_model="no_loss")

modelChain.run_model(csPowerValley)

Solution

  • To account for the horizon when calculating clear sky irradiance using PVLib, you can follow the approach demonstrated in the PVLib documentation example. This method involves using horizon profile data to adjust the Direct Normal Irradiance (DNI) and Plane of Array (POA) global irradiance based on the horizon elevation angles.

    Here's a concise implementation:

    1. Import necessary libraries and define location/time:
    import numpy as np
    import pandas as pd
    import pvlib
    
    # Define location (Golden, CO) and time range
    latitude, longitude = 39.76, -105.22
    tz = 'MST'
    times = pd.date_range('2020-12-20 6:30', '2020-12-20 9:00', freq='1T', tz=tz)
    location = pvlib.location.Location(latitude, longitude, tz)
    
    # Get solar position and clearsky data
    solar_position = location.get_solarposition(times)
    clearsky = location.get_clearsky(times)
    
    1. Define the horizon profile and interpolate:
    # Example horizon profile (azimuth: 0° to 360° in 7.5° increments)
    horizon_profile = pd.Series([
        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,
        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,
        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,
        4.2, 4.2, 4.2, 7.3, 9.5
    ], index=np.arange(0, 360, 7.5))
    
    # Interpolate horizon elevation data to the solar azimuth
    horizon_elevation_data = np.interp(
        solar_position.azimuth, horizon_profile.index, horizon_profile
    )
    
    1. Adjust DNI and GHI based on the horizon:
    # Adjust DNI based on horizon data
    dni_adjusted = np.where(solar_position.apparent_elevation > horizon_elevation_data, clearsky.dni, 0)
    ghi_adjusted = np.where(dni_adjusted == 0, clearsky.dhi, clearsky.ghi)
    
    # Calculate irradiance before and after adjustment
    surface_tilt, surface_azimuth = 30, 180
    irrad_pre_adj = pvlib.irradiance.get_total_irradiance(
        surface_tilt, surface_azimuth, solar_position.apparent_zenith, solar_position.azimuth,
        clearsky.dni, clearsky.ghi, clearsky.dhi
    )
    
    irrad_post_adj = pvlib.irradiance.get_total_irradiance(
        surface_tilt, surface_azimuth, solar_position.apparent_zenith, solar_position.azimuth,
        dni_adjusted, ghi_adjusted, clearsky.dhi
    )
    

    By following this approach, you can adjust the clear sky irradiance values to account for the horizon profile, providing more accurate irradiance data for locations with significant surrounding terrain.