Ejemplo n.º 1
0
 def time_get_total_irradiance(self):
     irradiance.get_total_irradiance(self.tilt, self.azimuth,
                                     self.solar_position.apparent_zenith,
                                     self.solar_position.azimuth,
                                     self.clearsky_irradiance.dni,
                                     self.clearsky_irradiance.ghi,
                                     self.clearsky_irradiance.dhi)
Ejemplo n.º 2
0
def test_get_total_irradiance_missing_dni_extra():
    msg = 'dni_extra is required'
    with pytest.raises(ValueError, match=msg):
        irradiance.get_total_irradiance(32,
                                        180,
                                        10,
                                        180,
                                        dni=1000,
                                        ghi=1100,
                                        dhi=100,
                                        model='haydavies')
Ejemplo n.º 3
0
def system_power(request, system_location, naive_times):
    tilt = request.param[0]
    azimuth = request.param[1]
    local_time = naive_times.tz_localize(system_location.tz)
    clearsky = system_location.get_clearsky(local_time,
                                            model='simplified_solis')
    solar_position = system_location.get_solarposition(local_time)
    poa = irradiance.get_total_irradiance(tilt, azimuth,
                                          solar_position['zenith'],
                                          solar_position['azimuth'],
                                          **clearsky)
    temp_cell = pvlib.temperature.sapm_cell(
        poa['poa_global'], 25, 0,
        **pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS['sapm']
        ['open_rack_glass_glass'])
    pdc = pvsystem.pvwatts_dc(poa['poa_global'], temp_cell, 100, -0.002)
    pac = pvsystem.inverter.pvwatts(pdc, 120)
    return {
        'location': system_location,
        'tilt': tilt,
        'azimuth': azimuth,
        'clearsky': clearsky,
        'solar_position': solar_position,
        'ac': pac
    }
Ejemplo n.º 4
0
    def get_irradiance(self, date, tilt, surface_azimuth):
        # Creates one day's worth of x min intervals
        times = pd.date_range(date,
                              freq='1min',
                              periods=60 * 24,
                              tz=self.site.tz)

        # Generate clearsky data using the Ineichen model, which is the default
        # The get_clearsky method returns a dataframe with values for GHI, DNI,
        # and DHI
        clearsky = self.site.get_clearsky(times)
        # Get solar azimuth and zenith to pass to the transposition function
        solar_position = self.site.get_solarposition(times=times)
        # Use the get_total_irradiance function to transpose the GHI to POA
        POA_irradiance = irradiance.get_total_irradiance(
            surface_tilt=tilt,
            surface_azimuth=surface_azimuth,
            dni=clearsky['dni'],
            ghi=clearsky['ghi'],
            dhi=clearsky['dhi'],
            solar_zenith=solar_position['apparent_zenith'],
            solar_azimuth=solar_position['azimuth'])
        # Return DataFrame with only GHI and POA
        return pd.DataFrame({
            'GHI': clearsky['ghi'],
            'POA': POA_irradiance['poa_global']
        })
Ejemplo n.º 5
0
def _calculate_poa(tmy, PV):
    """
    Input:      tmy irradiance data
    Output:     PV.poa -- plane of array

    Remember, PV GIS (C) defines the folowing:
    G(h): Global irradiance on the horizontal plane (W/m2)                        === GHI
    Gb(n): Beam/direct irradiance on a plane always normal to sun rays (W/m2)     === DNI
    Gd(h): Diffuse irradiance on the horizontal plane (W/m2)                      === DHI
    """
    # define site location for getting solar positions
    tmy.site = location.Location(tmy.lat, tmy.lon, tmy.tz)
    # Get solar azimuth and zenith to pass to the transposition function
    solar_position = tmy.site.get_solarposition(times=tmy.index)
    # Use get_total_irradiance to transpose, based on solar position
    POA_irradiance = irradiance.get_total_irradiance(
        surface_tilt=PV.tilt,
        surface_azimuth=PV.azimuth,
        dni=tmy["Gb(n)"],
        ghi=tmy["G(h)"],
        dhi=tmy["Gd(h)"],
        solar_zenith=solar_position["apparent_zenith"],
        solar_azimuth=solar_position["azimuth"],
    )
    # Return DataFrame
    PV.poa = POA_irradiance["poa_global"]
    return
Ejemplo n.º 6
0
def get_irradiance(site_location, tilt, surface_azimuth, times):
    clearsky = site_location.get_clearsky(times)
    solar_position = site_location.get_solarposition(times)
    POA_irradiance = irradiance.get_total_irradiance(
        surface_tilt=tilt,
        surface_azimuth=surface_azimuth,
        dni=clearsky['dni'],
        ghi=clearsky['ghi'],
        dhi=clearsky['dhi'],
        solar_zenith=solar_position['apparent_zenith'],
        solar_azimuth=solar_position['azimuth'])
    return pd.DataFrame(POA_irradiance['poa_global'])
def calculate_poa(tmy, solar_position, surface_tilt, surface_azimuth):
    # Use the get_total_irradiance function to transpose the irradiance
    # components to POA irradiance
    poa = irradiance.get_total_irradiance(
        surface_tilt=surface_tilt,
        surface_azimuth=surface_azimuth,
        dni=tmy['DNI'],
        ghi=tmy['GHI'],
        dhi=tmy['DHI'],
        solar_zenith=solar_position['apparent_zenith'],
        solar_azimuth=solar_position['azimuth'],
        model='isotropic')
    return poa['poa_global']  # just return the total in-plane irradiance
Ejemplo n.º 8
0
def test_get_total_irradiance_missing_airmass():
    total = irradiance.get_total_irradiance(32,
                                            180,
                                            10,
                                            180,
                                            dni=1000,
                                            ghi=1100,
                                            dhi=100,
                                            dni_extra=1400,
                                            model='perez')
    assert list(total.keys()) == [
        'poa_global', 'poa_direct', 'poa_diffuse', 'poa_sky_diffuse',
        'poa_ground_diffuse'
    ]
Ejemplo n.º 9
0
def test_get_total_irradiance_scalars(model):
    total = irradiance.get_total_irradiance(
        32, 180,
        10, 180,
        dni=1000, ghi=1100,
        dhi=100,
        dni_extra=1400, airmass=1,
        model=model,
        surface_type='urban')

    assert list(total.keys()) == ['poa_global', 'poa_direct',
                                  'poa_diffuse', 'poa_sky_diffuse',
                                  'poa_ground_diffuse']
    # test that none of the values are nan
    assert np.isnan(np.array(list(total.values()))).sum() == 0
Ejemplo n.º 10
0
def test_get_total_irradiance_scalars(model):
    total = irradiance.get_total_irradiance(
        32, 180,
        10, 180,
        dni=1000, ghi=1100,
        dhi=100,
        dni_extra=1400, airmass=1,
        model=model,
        surface_type='urban')

    assert list(total.keys()) == ['poa_global', 'poa_direct',
                                  'poa_diffuse', 'poa_sky_diffuse',
                                  'poa_ground_diffuse']
    # test that none of the values are nan
    assert np.isnan(np.array(list(total.values()))).sum() == 0
Ejemplo n.º 11
0
def test_get_total_irradiance(irrad_data, ephem_data, dni_et, relative_airmass):
    models = ['isotropic', 'klucher',
              'haydavies', 'reindl', 'king', 'perez']

    for model in models:
        total = irradiance.get_total_irradiance(
            32, 180,
            ephem_data['apparent_zenith'], ephem_data['azimuth'],
            dni=irrad_data['dni'], ghi=irrad_data['ghi'],
            dhi=irrad_data['dhi'],
            dni_extra=dni_et, airmass=relative_airmass,
            model=model,
            surface_type='urban')

        assert total.columns.tolist() == ['poa_global', 'poa_direct',
                                          'poa_diffuse', 'poa_sky_diffuse',
                                          'poa_ground_diffuse']
Ejemplo n.º 12
0
def test_stuck_tracker_profile(solarposition, clearsky):
    """Test POA irradiance at a awkward orientation (high tilt and
    oriented West)."""
    poa = irradiance.get_total_irradiance(
        surface_tilt=45,
        surface_azimuth=270,
        **clearsky,
        solar_zenith=solarposition['apparent_zenith'],
        solar_azimuth=solarposition['azimuth'])
    assert not orientation.tracking_nrel(
        poa['poa_global'],
        solarposition['zenith'] < 87,
    ).any()
    # by restricting the data to the middle of the day (lower zenith
    # angles) we should classify the system as fixed
    assert orientation.fixed_nrel(poa['poa_global'],
                                  solarposition['zenith'] < 70).all()
Ejemplo n.º 13
0
def test_get_total_irradiance(irrad_data, ephem_data, dni_et, relative_airmass):
    models = ['isotropic', 'klucher',
              'haydavies', 'reindl', 'king', 'perez']

    for model in models:
        total = irradiance.get_total_irradiance(
            32, 180,
            ephem_data['apparent_zenith'], ephem_data['azimuth'],
            dni=irrad_data['dni'], ghi=irrad_data['ghi'],
            dhi=irrad_data['dhi'],
            dni_extra=dni_et, airmass=relative_airmass,
            model=model,
            surface_type='urban')

        assert total.columns.tolist() == ['poa_global', 'poa_direct',
                                          'poa_diffuse', 'poa_sky_diffuse',
                                          'poa_ground_diffuse']
Ejemplo n.º 14
0
def test_orientation_fit_pvwatts_missing_data(naive_times):
    tilt = 30
    azimuth = 100
    system_location = location.Location(35, -106)
    local_time = naive_times.tz_localize('MST')
    clearsky = system_location.get_clearsky(local_time,
                                            model='simplified_solis')
    clearsky.loc['3/1/2020':'3/15/2020'] = np.nan
    solar_position = system_location.get_solarposition(clearsky.index)
    solar_position.loc['3/1/2020':'3/15/2020'] = np.nan
    poa = irradiance.get_total_irradiance(tilt, azimuth,
                                          solar_position['zenith'],
                                          solar_position['azimuth'],
                                          **clearsky)
    temp_cell = pvlib.temperature.sapm_cell(
        poa['poa_global'], 25, 0,
        **pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS['sapm']
        ['open_rack_glass_glass'])
    pdc = pvsystem.pvwatts_dc(poa['poa_global'], temp_cell, 100, -0.002)
    pac = pvsystem.inverter.pvwatts(pdc, 120)
    solar_position.dropna(inplace=True)
    with pytest.raises(ValueError,
                       match=".* must not contain undefined values"):
        system.infer_orientation_fit_pvwatts(
            pac,
            solar_zenith=solar_position['zenith'],
            solar_azimuth=solar_position['azimuth'],
            **clearsky)
    pac.dropna(inplace=True)
    with pytest.raises(ValueError,
                       match=".* must not contain undefined values"):
        system.infer_orientation_fit_pvwatts(
            pac,
            solar_zenith=solar_position['zenith'],
            solar_azimuth=solar_position['azimuth'],
            **clearsky)
    clearsky.dropna(inplace=True)
    tilt_out, azimuth_out, rsquared = system.infer_orientation_fit_pvwatts(
        pac,
        solar_zenith=solar_position['zenith'],
        solar_azimuth=solar_position['azimuth'],
        **clearsky)
    assert rsquared > 0.9
    assert tilt_out == pytest.approx(tilt, abs=10)
    assert azimuth_out == pytest.approx(azimuth, abs=10)
Ejemplo n.º 15
0
def test_orientation_with_gaps(clearsky_year, solarposition_year):
    poa = irradiance.get_total_irradiance(
        surface_tilt=15,
        surface_azimuth=180,
        **clearsky_year,
        solar_zenith=solarposition_year['apparent_zenith'],
        solar_azimuth=solarposition_year['azimuth'])
    poa.loc['2020-07-19':'2020-07-23'] = np.nan
    azimuth, tilt = system.infer_orientation_daily_peak(
        poa['poa_global'].dropna(),
        tilts=[15],
        azimuths=[180],
        solar_zenith=solarposition_year['apparent_zenith'],
        solar_azimuth=solarposition_year['azimuth'],
        sunny=solarposition_year['apparent_zenith'] < 87,
        **clearsky_year)
    assert azimuth == 180
    assert tilt == 15
Ejemplo n.º 16
0
def test_simple_poa_orientation(clearsky_year, solarposition_year,
                                fine_clearsky, fine_solarposition):
    poa = irradiance.get_total_irradiance(
        surface_tilt=15,
        surface_azimuth=180,
        **clearsky_year,
        solar_zenith=solarposition_year['apparent_zenith'],
        solar_azimuth=solarposition_year['azimuth'])
    azimuth, tilt = system.infer_orientation_daily_peak(
        poa['poa_global'],
        tilts=[15, 30],
        azimuths=[110, 180, 220],
        solar_zenith=fine_solarposition['apparent_zenith'],
        solar_azimuth=fine_solarposition['azimuth'],
        sunny=solarposition_year['apparent_zenith'] < 87,
        **fine_clearsky)
    assert azimuth == 180
    assert tilt == 15
Ejemplo n.º 17
0
def power_pvwatts(request, clearsky_july, solarposition_july):
    pdc0 = 100
    pdc0_inverter = 110
    tilt = 30
    azimuth = 180
    pdc0_marker = request.node.get_closest_marker("pdc0_inverter")
    if pdc0_marker is not None:
        pdc0_inverter = pdc0_marker.args[0]
    poa = irradiance.get_total_irradiance(
        tilt, azimuth,
        solarposition_july['zenith'], solarposition_july['azimuth'],
        **clearsky_july
    )
    cell_temp = temperature.sapm_cell(
        poa['poa_global'], 25, 0,
        **TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']
    )
    dc = pvsystem.pvwatts_dc(poa['poa_global'], cell_temp, pdc0, -0.004)
    return inverter.pvwatts(dc, pdc0_inverter)
Ejemplo n.º 18
0
def test_azimuth_different_index(clearsky_year, solarposition_year,
                                 fine_clearsky, fine_solarposition):
    """Can use solar position and clearsky with finer time-resolution to
    get an accurate estimate of tilt and azimuth."""
    poa = irradiance.get_total_irradiance(
        surface_tilt=40,
        surface_azimuth=120,
        **clearsky_year,
        solar_zenith=solarposition_year['apparent_zenith'],
        solar_azimuth=solarposition_year['azimuth'])
    azimuth, tilt = system.infer_orientation_daily_peak(
        poa['poa_global'],
        sunny=solarposition_year['apparent_zenith'] < 87,
        tilts=[40],
        azimuths=[100, 120, 150],
        solar_azimuth=fine_solarposition['azimuth'],
        solar_zenith=fine_solarposition['apparent_zenith'],
        **fine_clearsky,
    )
    assert azimuth == 120
Ejemplo n.º 19
0
def calculate_overcast_spectrl2():
    """
    This example will loop over a range of cloud covers and latitudes
    (at longitude=0) for a specific date and calculate the spectral
    irradiance with and without accounting for clouds. Clouds are accounted for
    by applying the cloud opacity factor defined in [1]. Several steps
    are required:
    1. Calculate the atmospheric and solar conditions for the
    location and time
    2. Calculate the spectral irradiance using `pvlib.spectrum.spectrl2`
    for clear sky conditions
    3. Calculate the dni, dhi, and ghi for cloudy conditions using
    `pvlib.irradiance.campbell_norman`
    4. Determine total in-plane irradiance and its beam,
    sky diffuse and ground
    reflected components for cloudy conditions -
    `pvlib.irradiance.get_total_irradiance`
    5. Calculate the dni, dhi, and ghi for clear sky conditions
    using `pvlib.irradiance.campbell_norman`
    6. Determine total in-plane irradiance and its beam,
    sky diffuse and ground
    reflected components for clear sky conditions -
    `pvlib.irradiance.get_total_irradiance`
    7. Calculate the cloud opacity factor [1] and scale the
    spectral results from step 4 - func cloud_opacity_factor
    8. Plot the results  - func plot_spectral_irradiance
    """
    month = 2
    hour_of_day = 12
    altitude = 0.0
    longitude = 0.0
    latitudes = [10, 40]

    # cloud cover in fraction units
    cloud_covers = [0.2, 0.5]
    water_vapor_content = 0.5
    tau500 = 0.1
    ground_albedo = 0.06
    ozone = 0.3
    surface_tilt = 0.0

    ctime, pv_system = setup_pv_system(month, hour_of_day)

    for cloud_cover in cloud_covers:
        for latitude in latitudes:
            sol = get_solarposition(ctime, latitude, longitude)
            az = sol['apparent_zenith'].to_numpy()
            airmass_relative = get_relative_airmass(az,
                                                    model='kastenyoung1989')
            pressure = pvlib.atmosphere.alt2pres(altitude)
            az = sol['apparent_zenith'].to_numpy()
            azimuth = sol['azimuth'].to_numpy()
            surface_azimuth = pv_system['surface_azimuth']

            transmittance = (1.0 - cloud_cover) * 0.75
            calc_aoi = aoi(surface_tilt, surface_azimuth, az, azimuth)

            # day of year is an int64index array so access first item
            day_of_year = ctime.dayofyear[0]

            spectra = pvlib.spectrum.spectrl2(
                apparent_zenith=az,
                aoi=calc_aoi,
                surface_tilt=surface_tilt,
                ground_albedo=ground_albedo,
                surface_pressure=pressure,
                relative_airmass=airmass_relative,
                precipitable_water=water_vapor_content,
                ozone=ozone,
                aerosol_turbidity_500nm=tau500,
                dayofyear=day_of_year)

            irrads_clouds = campbell_norman(sol['zenith'].to_numpy(),
                                            transmittance)

            # Convert the irradiance to a plane with tilt zero
            # horizontal to the earth. This is done applying
            #  tilt=0 to POA calculations using the output from
            # `campbell_norman`. The POA calculations include
            # calculating sky and ground diffuse light where
            # specific models can be selected (we use default).
            poa_irr_clouds = get_total_irradiance(
                surface_tilt=surface_tilt,
                surface_azimuth=pv_system['surface_azimuth'],
                dni=irrads_clouds['dni'],
                ghi=irrads_clouds['ghi'],
                dhi=irrads_clouds['dhi'],
                solar_zenith=sol['apparent_zenith'],
                solar_azimuth=sol['azimuth'])

            show_info(latitude, poa_irr_clouds)
            zen = sol['zenith'].to_numpy()
            irr_clearsky = campbell_norman(zen, transmittance=0.75)

            poa_irr_clearsky = get_total_irradiance(
                surface_tilt=surface_tilt,
                surface_azimuth=pv_system['surface_azimuth'],
                dni=irr_clearsky['dni'],
                ghi=irr_clearsky['ghi'],
                dhi=irr_clearsky['dhi'],
                solar_zenith=sol['apparent_zenith'],
                solar_azimuth=sol['azimuth'])

            show_info(latitude, poa_irr_clearsky)
            poa_dr = poa_irr_clouds['poa_direct'].values
            poa_diff = poa_irr_clouds['poa_diffuse'].values
            poa_global = poa_irr_clouds['poa_global'].values
            f_dir, f_diff = cloud_opacity_factor(poa_dr, poa_diff, poa_global,
                                                 spectra)

            plot_spectral_irr(spectra,
                              f_dir,
                              f_diff,
                              lat=latitude,
                              doy=day_of_year,
                              year=ctime.year[0],
                              clouds=cloud_cover)
Ejemplo n.º 20
0
    def get_irradiance(self, surface_tilt, surface_azimuth,
                       solar_zenith, solar_azimuth, dni, ghi, dhi,
                       dni_extra=None, airmass=None, model='haydavies',
                       **kwargs):
        """
        Uses the :func:`irradiance.get_total_irradiance` function to
        calculate the plane of array irradiance components on a tilted
        surface defined by the input data and ``self.albedo``.

        For a given set of solar zenith and azimuth angles, the
        surface tilt and azimuth parameters are typically determined
        by :py:meth:`~SingleAxisTracker.singleaxis`.

        Parameters
        ----------
        surface_tilt : numeric
            Panel tilt from horizontal.
        surface_azimuth : numeric
            Panel azimuth from north
        solar_zenith : numeric
            Solar zenith angle.
        solar_azimuth : numeric
            Solar azimuth angle.
        dni : float or Series
            Direct Normal Irradiance
        ghi : float or Series
            Global horizontal irradiance
        dhi : float or Series
            Diffuse horizontal irradiance
        dni_extra : float or Series, default None
            Extraterrestrial direct normal irradiance
        airmass : float or Series, default None
            Airmass
        model : String, default 'haydavies'
            Irradiance model.

        **kwargs
            Passed to :func:`irradiance.total_irrad`.

        Returns
        -------
        poa_irradiance : DataFrame
            Column names are: ``total, beam, sky, ground``.
        """

        # not needed for all models, but this is easier
        if dni_extra is None:
            dni_extra = irradiance.get_extra_radiation(solar_zenith.index)

        if airmass is None:
            airmass = atmosphere.get_relative_airmass(solar_zenith)

        return irradiance.get_total_irradiance(surface_tilt,
                                               surface_azimuth,
                                               solar_zenith,
                                               solar_azimuth,
                                               dni, ghi, dhi,
                                               dni_extra=dni_extra,
                                               airmass=airmass,
                                               model=model,
                                               albedo=self.albedo,
                                               **kwargs)
Ejemplo n.º 21
0
    def get_irradiance(self,
                       surface_tilt,
                       surface_azimuth,
                       solar_zenith,
                       solar_azimuth,
                       dni,
                       ghi,
                       dhi,
                       dni_extra=None,
                       airmass=None,
                       model='haydavies',
                       **kwargs):
        """
        Uses the :func:`irradiance.get_total_irradiance` function to
        calculate the plane of array irradiance components on a tilted
        surface defined by the input data and ``self.albedo``.

        For a given set of solar zenith and azimuth angles, the
        surface tilt and azimuth parameters are typically determined
        by :py:meth:`~SingleAxisTracker.singleaxis`.

        Parameters
        ----------
        surface_tilt : numeric
            Panel tilt from horizontal.
        surface_azimuth : numeric
            Panel azimuth from north
        solar_zenith : numeric
            Solar zenith angle.
        solar_azimuth : numeric
            Solar azimuth angle.
        dni : float or Series
            Direct Normal Irradiance
        ghi : float or Series
            Global horizontal irradiance
        dhi : float or Series
            Diffuse horizontal irradiance
        dni_extra : float or Series, default None
            Extraterrestrial direct normal irradiance
        airmass : float or Series, default None
            Airmass
        model : String, default 'haydavies'
            Irradiance model.

        **kwargs
            Passed to :func:`irradiance.total_irrad`.

        Returns
        -------
        poa_irradiance : DataFrame
            Column names are: ``total, beam, sky, ground``.
        """

        # not needed for all models, but this is easier
        if dni_extra is None:
            dni_extra = irradiance.get_extra_radiation(solar_zenith.index)

        if airmass is None:
            airmass = atmosphere.get_relative_airmass(solar_zenith)

        return irradiance.get_total_irradiance(surface_tilt,
                                               surface_azimuth,
                                               solar_zenith,
                                               solar_azimuth,
                                               dni,
                                               ghi,
                                               dhi,
                                               dni_extra=dni_extra,
                                               airmass=airmass,
                                               model=model,
                                               albedo=self.albedo,
                                               **kwargs)
Ejemplo n.º 22
0
    def get_irradiance(self,
                       surface_tilt,
                       surface_azimuth,
                       solar_zenith,
                       solar_azimuth,
                       dni,
                       ghi,
                       dhi,
                       dni_extra=None,
                       airmass=None,
                       model='haydavies',
                       **kwargs):
        """
        Uses the :func:`irradiance.get_total_irradiance` function to
        calculate the plane of array irradiance components on a tilted
        surface defined by the input data and ``self.albedo``.

        For a given set of solar zenith and azimuth angles, the
        surface tilt and azimuth parameters are typically determined
        by :py:meth:`~SingleAxisTracker.singleaxis`.

        Parameters
        ----------
        surface_tilt : numeric
            Panel tilt from horizontal.
        surface_azimuth : numeric
            Panel azimuth from north
        solar_zenith : numeric
            Solar zenith angle.
        solar_azimuth : numeric
            Solar azimuth angle.
        dni : float or Series
            Direct Normal Irradiance
        ghi : float or Series
            Global horizontal irradiance
        dhi : float or Series
            Diffuse horizontal irradiance
        dni_extra : float or Series, default None
            Extraterrestrial direct normal irradiance
        airmass : float or Series, default None
            Airmass
        model : String, default 'haydavies'
            Irradiance model.

        **kwargs
            Passed to :func:`irradiance.get_total_irradiance`.

        Returns
        -------
        poa_irradiance : DataFrame
            Column names are: ``total, beam, sky, ground``.
        """

        # not needed for all models, but this is easier
        if dni_extra is None:
            dni_extra = irradiance.get_extra_radiation(solar_zenith.index)

        if airmass is None:
            airmass = atmosphere.get_relative_airmass(solar_zenith)

        # SingleAxisTracker only supports a single Array, but we need the
        # validate/iterate machinery so that single length tuple input/output
        # is handled the same as PVSystem.get_irradiance. GH 1159
        dni = self._validate_per_array(dni, system_wide=True)
        ghi = self._validate_per_array(ghi, system_wide=True)
        dhi = self._validate_per_array(dhi, system_wide=True)

        return tuple(
            irradiance.get_total_irradiance(surface_tilt,
                                            surface_azimuth,
                                            solar_zenith,
                                            solar_azimuth,
                                            dni,
                                            ghi,
                                            dhi,
                                            dni_extra=dni_extra,
                                            airmass=airmass,
                                            model=model,
                                            albedo=self.arrays[0].albedo,
                                            **kwargs)
            for array, dni, ghi, dhi in zip(self.arrays, dni, ghi, dhi))
Ejemplo n.º 23
0
    def fit(self, timestamps, DNI, DHI, solar_zenith, solar_azimuth,
            surface_tilt, surface_azimuth, rho_front, rho_back, albedo,
            GHI=None):
        """Use vectorization to calculate values used for the isotropic
        irradiance model.

        Parameters
        ----------
        timestamps : array-like
            List of timestamps of the simulation.
        DNI : array-like
            Direct normal irradiance values [W/m2]
        DHI : array-like
            Diffuse horizontal irradiance values [W/m2]
        solar_zenith : array-like
            Solar zenith angles [deg]
        solar_azimuth : array-like
            Solar azimuth angles [deg]
        surface_tilt : array-like
            Surface tilt angles, from 0 to 180 [deg]
        surface_azimuth : array-like
            Surface azimuth angles [deg]
        rho_front : float
            Reflectivity of the front side of the PV rows
        rho_back : float
            Reflectivity of the back side of the PV rows
        albedo : array-like
            Albedo values (or ground reflectivity)
        GHI : array-like, optional
            Global horizontal irradiance [W/m2], if not provided, will be
            calculated from DNI and DHI (Default = None)
        """
        # Make sure getting array-like values
        if np.isscalar(DNI):
            timestamps = [timestamps]
            DNI = np.array([DNI])
            DHI = np.array([DHI])
            solar_zenith = np.array([solar_zenith])
            solar_azimuth = np.array([solar_azimuth])
            surface_tilt = np.array([surface_tilt])
            surface_azimuth = np.array([surface_azimuth])
            if GHI is not None:
                GHI = np.array([GHI])
        # Length of arrays
        n = len(DNI)
        # Make sure that albedo is a vector
        if np.isscalar(albedo):
            albedo = albedo * np.ones(n)

        # Save and calculate total POA values from Perez model
        if GHI is None:
            # Calculate GHI if not specified
            GHI = DNI * cosd(solar_zenith) + DHI
        self.GHI = GHI
        self.DHI = DHI
        perez_front_pvrow = get_total_irradiance(
            surface_tilt, surface_azimuth, solar_zenith, solar_azimuth,
            DNI, GHI, DHI, albedo=albedo)

        # Save diffuse light
        self.isotropic_luminance = DHI
        self.rho_front = rho_front
        self.rho_back = rho_back
        self.albedo = albedo

        # DNI seen by ground illuminated surfaces
        self.direct['ground'] = DNI * cosd(solar_zenith)

        # Calculate AOI on front pvrow using pvlib implementation
        aoi_front_pvrow = aoi_function(
            surface_tilt, surface_azimuth, solar_zenith, solar_azimuth)
        aoi_back_pvrow = 180. - aoi_front_pvrow

        # DNI seen by pvrow illuminated surfaces
        front_is_illum = aoi_front_pvrow <= 90
        self.direct['front_pvrow'] = np.where(
            front_is_illum, DNI * cosd(aoi_front_pvrow), 0.)
        self.direct['back_pvrow'] = np.where(
            ~front_is_illum, DNI * cosd(aoi_back_pvrow), 0.)
        self.total_perez['front_pvrow'] = perez_front_pvrow['poa_global']
Ejemplo n.º 24
0
    def fit(self,
            timestamps,
            DNI,
            DHI,
            solar_zenith,
            solar_azimuth,
            surface_tilt,
            surface_azimuth,
            albedo,
            ghi=None):
        """Use vectorization to calculate values used for the hybrid Perez
        irradiance model.

        Parameters
        ----------
        timestamps : array-like
            List of timestamps of the simulation.
        DNI : array-like
            Direct normal irradiance values [W/m2]
        DHI : array-like
            Diffuse horizontal irradiance values [W/m2]
        solar_zenith : array-like
            Solar zenith angles [deg]
        solar_azimuth : array-like
            Solar azimuth angles [deg]
        surface_tilt : array-like
            Surface tilt angles, from 0 to 180 [deg]
        surface_azimuth : array-like
            Surface azimuth angles [deg]
        albedo : array-like
            Albedo values (or ground reflectivity)
        ghi : array-like, optional
            Global horizontal irradiance [W/m2], if not provided, will be
            calculated from DNI and DHI (Default = None)
        """
        # Make sure getting array-like values
        if np.isscalar(DNI):
            timestamps = [timestamps]
            DNI = np.array([DNI])
            DHI = np.array([DHI])
            solar_zenith = np.array([solar_zenith])
            solar_azimuth = np.array([solar_azimuth])
            surface_tilt = np.array([surface_tilt])
            surface_azimuth = np.array([surface_azimuth])
            ghi = None if ghi is None else np.array([ghi])
        # Length of arrays
        n = len(DNI)
        # Make sure that albedo is a vector
        albedo = albedo * np.ones(n) if np.isscalar(albedo) else albedo

        # Calculate terms from Perez model
        luminance_isotropic, luminance_circumsolar, poa_horizon, \
            poa_circumsolar_front, poa_circumsolar_back, \
            aoi_front_pvrow, aoi_back_pvrow = \
            self._calculate_luminance_poa_components(
                timestamps, DNI, DHI, solar_zenith, solar_azimuth,
                surface_tilt, surface_azimuth)

        # Save and calculate total POA values from Perez model
        ghi = DNI * cosd(solar_zenith) + DHI if ghi is None else ghi
        self.GHI = ghi
        self.DHI = DHI
        self.n_steps = n
        perez_front_pvrow = get_total_irradiance(surface_tilt,
                                                 surface_azimuth,
                                                 solar_zenith,
                                                 solar_azimuth,
                                                 DNI,
                                                 ghi,
                                                 DHI,
                                                 albedo=albedo)
        total_perez_front_pvrow = perez_front_pvrow['poa_global']

        # Save isotropic luminance
        self.isotropic_luminance = luminance_isotropic
        self.albedo = albedo

        # Ground surfaces
        self.direct['ground_illum'] = DNI * cosd(solar_zenith)
        self.direct['ground_shaded'] = (
            # Direct light through PV modules spacing
            self.direct['ground_illum'] * self.module_spacing_ratio
            # Direct light through PV modules, by transparency
            + self.direct['ground_illum'] *
            (1. - self.module_spacing_ratio) * self.module_transparency)
        self.circumsolar['ground_illum'] = luminance_circumsolar
        self.circumsolar['ground_shaded'] = (
            # Circumsolar light through PV modules spacing
            self.circumsolar['ground_illum'] * self.module_spacing_ratio
            # Circumsolar light through PV modules, by transparency
            + self.circumsolar['ground_illum'] *
            (1. - self.module_spacing_ratio) * self.module_transparency)
        self.horizon['ground'] = np.zeros(n)

        # PV row surfaces
        front_is_illum = aoi_front_pvrow <= 90
        # direct
        self.direct['front_illum_pvrow'] = np.where(
            front_is_illum, DNI * cosd(aoi_front_pvrow), 0.)
        self.direct['front_shaded_pvrow'] = (
            # Direct light through PV modules spacing
            self.direct['front_illum_pvrow'] * self.module_spacing_ratio
            # Direct light through PV modules, by transparency
            + self.direct['front_illum_pvrow'] *
            (1. - self.module_spacing_ratio) * self.module_transparency)
        self.direct['back_illum_pvrow'] = np.where(~front_is_illum,
                                                   DNI * cosd(aoi_back_pvrow),
                                                   0.)
        self.direct['back_shaded_pvrow'] = (
            # Direct light through PV modules spacing
            self.direct['back_illum_pvrow'] * self.module_spacing_ratio
            # Direct light through PV modules, by transparency
            + self.direct['back_illum_pvrow'] *
            (1. - self.module_spacing_ratio) * self.module_transparency)
        # circumsolar
        self.circumsolar['front_illum_pvrow'] = np.where(
            front_is_illum, poa_circumsolar_front, 0.)
        self.circumsolar['front_shaded_pvrow'] = (
            # Direct light through PV modules spacing
            self.circumsolar['front_illum_pvrow'] * self.module_spacing_ratio
            # Direct light through PV modules, by transparency
            + self.circumsolar['front_illum_pvrow'] *
            (1. - self.module_spacing_ratio) * self.module_transparency)
        self.circumsolar['back_illum_pvrow'] = np.where(
            ~front_is_illum, poa_circumsolar_back, 0.)
        self.circumsolar['back_shaded_pvrow'] = (
            # Direct light through PV modules spacing
            self.circumsolar['back_illum_pvrow'] * self.module_spacing_ratio
            # Direct light through PV modules, by transparency
            + self.circumsolar['back_illum_pvrow'] *
            (1. - self.module_spacing_ratio) * self.module_transparency)
        # horizon
        self.horizon['front_pvrow'] = poa_horizon
        self.horizon['back_pvrow'] = poa_horizon
        # perez
        self.total_perez['front_illum_pvrow'] = total_perez_front_pvrow
        self.total_perez['front_shaded_pvrow'] = (
            total_perez_front_pvrow - self.direct['front_illum_pvrow'] -
            self.circumsolar['front_illum_pvrow'] +
            self.direct['front_shaded_pvrow'] +
            self.circumsolar['front_shaded_pvrow'])
        self.total_perez['ground_shaded'] = (
            DHI - self.circumsolar['ground_illum'] +
            self.circumsolar['ground_shaded'] + self.direct['ground_shaded'])
        self.total_perez['ground_illum'] = ghi
        self.total_perez['sky'] = luminance_isotropic
Ejemplo n.º 25
0
    def fit(self,
            timestamps,
            DNI,
            DHI,
            solar_zenith,
            solar_azimuth,
            surface_tilt,
            surface_azimuth,
            albedo,
            ghi=None):
        """Use vectorization to calculate values used for the isotropic
        irradiance model.

        Parameters
        ----------
        timestamps : array-like
            List of timestamps of the simulation.
        DNI : array-like
            Direct normal irradiance values [W/m2]
        DHI : array-like
            Diffuse horizontal irradiance values [W/m2]
        solar_zenith : array-like
            Solar zenith angles [deg]
        solar_azimuth : array-like
            Solar azimuth angles [deg]
        surface_tilt : array-like
            Surface tilt angles, from 0 to 180 [deg]
        surface_azimuth : array-like
            Surface azimuth angles [deg]
        albedo : array-like
            Albedo values (or ground reflectivity)
        ghi : array-like, optional
            Global horizontal irradiance [W/m2], if not provided, will be
            calculated from DNI and DHI (Default = None)
        """
        # Make sure getting array-like values
        if np.isscalar(DNI):
            timestamps = [timestamps]
            DNI = np.array([DNI])
            DHI = np.array([DHI])
            solar_zenith = np.array([solar_zenith])
            solar_azimuth = np.array([solar_azimuth])
            surface_tilt = np.array([surface_tilt])
            surface_azimuth = np.array([surface_azimuth])
            ghi = None if ghi is None else np.array([ghi])
        # Length of arrays
        n = len(DNI)
        # Make sure that albedo is a vector
        albedo = albedo * np.ones(n) if np.isscalar(albedo) else albedo

        # Save and calculate total POA values from Perez model
        ghi = DNI * cosd(solar_zenith) + DHI if ghi is None else ghi
        self.GHI = ghi
        self.DHI = DHI
        self.n_steps = n
        perez_front_pvrow = get_total_irradiance(surface_tilt,
                                                 surface_azimuth,
                                                 solar_zenith,
                                                 solar_azimuth,
                                                 DNI,
                                                 ghi,
                                                 DHI,
                                                 albedo=albedo)

        # Save diffuse light
        self.isotropic_luminance = DHI
        self.albedo = albedo

        # DNI seen by ground illuminated surfaces
        self.direct['ground_illum'] = DNI * cosd(solar_zenith)
        self.direct['ground_shaded'] = (
            # Direct light through PV modules spacing
            self.direct['ground_illum'] * self.module_spacing_ratio
            # Direct light through PV modules, by transparency
            + self.direct['ground_illum'] *
            (1. - self.module_spacing_ratio) * self.module_transparency)

        # Calculate AOI on front pvrow using pvlib implementation
        aoi_front_pvrow = aoi_function(surface_tilt, surface_azimuth,
                                       solar_zenith, solar_azimuth)
        aoi_back_pvrow = 180. - aoi_front_pvrow

        # DNI seen by pvrow illuminated surfaces
        front_is_illum = aoi_front_pvrow <= 90
        # direct
        self.direct['front_illum_pvrow'] = np.where(
            front_is_illum, DNI * cosd(aoi_front_pvrow), 0.)
        self.direct['front_shaded_pvrow'] = (
            # Direct light through PV modules spacing
            self.direct['front_illum_pvrow'] * self.module_spacing_ratio
            # Direct light through PV modules, by transparency
            + self.direct['front_illum_pvrow'] *
            (1. - self.module_spacing_ratio) * self.module_transparency)
        self.direct['back_illum_pvrow'] = np.where(~front_is_illum,
                                                   DNI * cosd(aoi_back_pvrow),
                                                   0.)
        self.direct['back_shaded_pvrow'] = (
            # Direct light through PV modules spacing
            self.direct['back_illum_pvrow'] * self.module_spacing_ratio
            # Direct light through PV modules, by transparency
            + self.direct['back_illum_pvrow'] *
            (1. - self.module_spacing_ratio) * self.module_transparency)
        # perez
        self.total_perez['front_illum_pvrow'] = perez_front_pvrow['poa_global']
        self.total_perez['front_shaded_pvrow'] = (
            self.total_perez['front_illum_pvrow'] -
            self.direct['front_illum_pvrow'])
        self.total_perez['ground_shaded'] = (self.DHI +
                                             self.direct['ground_shaded'])
Ejemplo n.º 26
0
def test_orientation_fit_pvwatts_temp_wind_as_series(naive_times):
    tilt = 30
    azimuth = 100
    system_location = location.Location(35, -106)
    local_time = naive_times.tz_localize('MST')
    clearsky = system_location.get_clearsky(local_time,
                                            model='simplified_solis')
    solar_position = system_location.get_solarposition(clearsky.index)
    poa = irradiance.get_total_irradiance(tilt, azimuth,
                                          solar_position['zenith'],
                                          solar_position['azimuth'],
                                          **clearsky)
    temp_cell = pvlib.temperature.sapm_cell(
        poa['poa_global'], 25, 1,
        **pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS['sapm']
        ['open_rack_glass_glass'])
    temperature = pd.Series(25, index=clearsky.index)
    wind_speed = pd.Series(1, index=clearsky.index)
    temperature_missing = temperature.copy()
    temperature_missing.loc['4/5/2020':'4/10/2020'] = np.nan
    wind_speed_missing = wind_speed.copy()
    wind_speed_missing.loc['5/5/2020':'5/15/2020'] = np.nan
    pdc = pvsystem.pvwatts_dc(poa['poa_global'], temp_cell, 100, -0.002)
    pac = pvsystem.inverter.pvwatts(pdc, 120)
    with pytest.raises(ValueError,
                       match=".* must not contain undefined values"):
        system.infer_orientation_fit_pvwatts(
            pac,
            solar_zenith=solar_position['zenith'],
            solar_azimuth=solar_position['azimuth'],
            temperature=temperature_missing,
            wind_speed=wind_speed_missing,
            **clearsky)
    with pytest.raises(ValueError,
                       match="temperature must not contain undefined values"):
        system.infer_orientation_fit_pvwatts(
            pac,
            solar_zenith=solar_position['zenith'],
            solar_azimuth=solar_position['azimuth'],
            temperature=temperature_missing,
            wind_speed=wind_speed,
            **clearsky)
    with pytest.raises(ValueError,
                       match="wind_speed must not contain undefined values"):
        system.infer_orientation_fit_pvwatts(
            pac,
            solar_zenith=solar_position['zenith'],
            solar_azimuth=solar_position['azimuth'],
            temperature=temperature,
            wind_speed=wind_speed_missing,
            **clearsky)
    # ValueError if indices don't match
    with pytest.raises(ValueError):
        system.infer_orientation_fit_pvwatts(
            pac,
            solar_zenith=solar_position['zenith'],
            solar_azimuth=solar_position['azimuth'],
            temperature=temperature_missing.dropna(),
            wind_speed=wind_speed_missing.dropna(),
            **clearsky)
    tilt_out, azimuth_out, rsquared = system.infer_orientation_fit_pvwatts(
        pac,
        solar_zenith=solar_position['zenith'],
        solar_azimuth=solar_position['azimuth'],
        **clearsky)
    assert rsquared > 0.9
    assert tilt_out == pytest.approx(tilt, abs=10)
    assert azimuth_out == pytest.approx(azimuth, abs=10)
Ejemplo n.º 27
0
    def get_irradiance(self,
                       solar_zenith,
                       solar_azimuth,
                       dni,
                       ghi,
                       dhi,
                       dni_extra=None,
                       airmass=None,
                       model='haydavies',
                       **kwargs):
        """
        Uses the :py:func:`irradiance.get_total_irradiance` function to
        calculate the plane of array irradiance components on a Fixed panel.

        Parameters
        ----------
        solar_zenith : float or Series.
            Solar zenith angle.
        solar_azimuth : float or Series.
            Solar azimuth angle.
        dni : float or Series
            Direct Normal Irradiance
        ghi : float or Series
            Global horizontal irradiance
        dhi : float or Series
            Diffuse horizontal irradiance
        dni_extra : None, float or Series, default None
            Extraterrestrial direct normal irradiance
        airmass : None, float or Series, default None
            Airmass
        model : String, default 'haydavies'
            Irradiance model.

        **kwargs
            Passed to :func:`irradiance.total_irrad`.

        Returns
        -------
        poa_irradiance : DataFrame
            Column names are: ``total, beam, sky, ground``.
        """

        # not needed for all models, but this is easier
        if dni_extra is None:
            dni_extra = irradiance.get_extra_radiation(solar_zenith.index)

        if airmass is None:
            airmass = atmosphere.get_relative_airmass(solar_zenith)

        return irradiance.get_total_irradiance(self.surface_tilt,
                                               self.surface_azimuth,
                                               solar_zenith,
                                               solar_azimuth,
                                               dni,
                                               ghi,
                                               dhi,
                                               dni_extra=dni_extra,
                                               airmass=airmass,
                                               model=model,
                                               albedo=self.albedo,
                                               **kwargs)
Ejemplo n.º 28
0
def find_clearsky_poa(df,
                      lat,
                      lon,
                      irradiance_poa_key='irradiance_poa_o_###',
                      mounting='fixed',
                      tilt=0,
                      azimuth=180,
                      altitude=0):
    loc = Location(lat, lon, altitude=altitude)

    CS = loc.get_clearsky(df.index)

    df['csghi'] = CS.ghi
    df['csdhi'] = CS.dhi
    df['csdni'] = CS.dni

    if mounting.lower() == "fixed":
        sun = get_solarposition(df.index, lat, lon)

        fixedpoa = get_total_irradiance(tilt, azimuth, sun.zenith, sun.azimuth,
                                        CS.dni, CS.ghi, CS.dhi)

        df['cspoa'] = fixedpoa.poa_global

    if mounting.lower() == "tracking":
        sun = get_solarposition(df.index, lat, lon)

        # default to axis_tilt=0 and axis_azimuth=180

        tracker_data = singleaxis(sun.apparent_zenith,
                                  sun.azimuth,
                                  axis_tilt=tilt,
                                  axis_azimuth=azimuth,
                                  max_angle=50,
                                  backtrack=True,
                                  gcr=0.35)

        track = get_total_irradiance(tracker_data['surface_tilt'],
                                     tracker_data['surface_azimuth'],
                                     sun.zenith, sun.azimuth, CS.dni, CS.ghi,
                                     CS.dhi)

        df['cspoa'] = track.poa_global

    # the following code is assuming clear sky poa has been generated per pvlib, aligned in the same
    # datetime index, and daylight savings or any time shifts were previously corrected
    # the inputs below were tuned for POA at a 15 minute frequency
    # note that detect_clearsky has a scaling factor but I still got slightly different results when I scaled measured poa first

    df['poa'] = df[irradiance_poa_key] / df[irradiance_poa_key].quantile(
        0.98) * df.cspoa.quantile(0.98)

    # inputs for detect_clearsky

    measured = df.poa.copy()
    clear = df.cspoa.copy()
    dur = 60
    lower_line_length = -41.416
    upper_line_length = 77.789
    var_diff = .00745
    mean_diff = 80
    max_diff = 90
    slope_dev = 3

    is_clear_results = detect_clearsky(measured.values,
                                       clear.values,
                                       df.index,
                                       dur,
                                       mean_diff,
                                       max_diff,
                                       lower_line_length,
                                       upper_line_length,
                                       var_diff,
                                       slope_dev,
                                       return_components=True)

    clearSeries = pd.Series(index=df.index, data=is_clear_results[0])

    clearSeries = clearSeries.reindex(index=df.index, method='ffill', limit=3)

    return clearSeries