Skip to content

WIP: PVSystem attributes as iterables #1068

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/sphinx/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,10 @@ PV temperature models
temperature.pvsyst_cell
temperature.faiman
temperature.fuentes
temperature.ross
pvsystem.PVSystem.sapm_celltemp
pvsystem.PVSystem.pvsyst_celltemp
pvsystem.PVSystem.faiman_celltemp

Temperature Model Parameters
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 4 additions & 0 deletions docs/sphinx/source/whatsnew/v0.8.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Deprecations

Enhancements
~~~~~~~~~~~~
* Added :py:func:`pvlib.temperature.ross` for cell temperature modeling using
only NOCT. (:pull:`1045`)


Bug fixes
Expand All @@ -35,3 +37,5 @@ Requirements
Contributors
~~~~~~~~~~~~
* Kevin Anderson (:ghuser:`kanderso-nrel`)
* Will Holmgren (:ghuser:`wholmgren`)
* Cliff Hansen (:ghuser:`cwhanse`)
64 changes: 42 additions & 22 deletions pvlib/pvsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,9 +245,16 @@ def get_aoi(self, solar_zenith, solar_azimuth):
The angle of incidence
"""

aoi = irradiance.aoi(self.surface_tilt, self.surface_azimuth,
solar_zenith, solar_azimuth)
return aoi
try:
aoi = [irradiance.aoi(t, a, solar_zenith, solar_azimuth)
for t, a in zip(self.surface_tilt, self.surface_azimuth)]
if isinstance(self.surface_tilt, np.ndarray):
aoi = np.asarray(aoi)
return aoi
except TypeError:
return irradiance.aoi(self.surface_tilt, self.surface_azimuth,
solar_zenith, solar_azimuth)


def get_irradiance(self, solar_zenith, solar_azimuth, dni, ghi, dhi,
dni_extra=None, airmass=None, model='haydavies',
Expand Down Expand Up @@ -293,15 +300,20 @@ def get_irradiance(self, solar_zenith, solar_azimuth, dni, ghi, dhi,
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)
try:
poa = [irradiance.get_total_irradiance(
t, a, solar_zenith, solar_azimuth, dni, ghi, dhi,
dni_extra=dni_extra, airmass=airmass, model=model,
albedo=self.albedo, **kwargs)
for t, a in zip(self.surface_tilt, self.surface_azimuth)]
if isinstance(self.surface_tilt, np.ndarray):
poa = np.asarray(poa)
return poa
except TypeError:
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)

def get_iam(self, aoi, iam_model='physical'):
"""
Expand Down Expand Up @@ -370,7 +382,9 @@ def calcparams_desoto(self, effective_irradiance, temp_cell, **kwargs):
'R_s', 'alpha_sc', 'EgRef', 'dEgdT',
'irrad_ref', 'temp_ref'],
self.module_parameters)

if isinstance(effective_irradiance, list):
return [calcparams_desoto(ee, tc, **kwargs)
for ee, tc in zip(effective_irradiance, temp_cell)]
return calcparams_desoto(effective_irradiance, temp_cell, **kwargs)

def calcparams_cec(self, effective_irradiance, temp_cell, **kwargs):
Expand Down Expand Up @@ -524,7 +538,7 @@ def sapm_spectral_loss(self, airmass_absolute):
"""
return sapm_spectral_loss(airmass_absolute, self.module_parameters)

def sapm_effective_irradiance(self, poa_direct, poa_diffuse,
def sapm_effective_irradiance(self, total_irrad,
airmass_absolute, aoi,
reference_irradiance=1000):
"""
Expand All @@ -534,11 +548,10 @@ def sapm_effective_irradiance(self, poa_direct, poa_diffuse,

Parameters
----------
poa_direct : numeric
The direct irradiance incident upon the module. [W/m2]

poa_diffuse : numeric
The diffuse irradiance incident on module. [W/m2]
total_irrad : Dataframe
Contains 'poa_direct', the direct irradiance incident upon the
module [W/m2], and 'poa_diffuse', the diffuse irradiance incident
on the module [W/m2].

airmass_absolute : numeric
Absolute airmass. [unitless]
Expand All @@ -551,9 +564,16 @@ def sapm_effective_irradiance(self, poa_direct, poa_diffuse,
effective_irradiance : numeric
The SAPM effective irradiance. [W/m2]
"""
return sapm_effective_irradiance(
poa_direct, poa_diffuse, airmass_absolute, aoi,
self.module_parameters)
try:
ee = [sapm_effective_irradiance(
df['poa_direct'], df['poa_diffuse'], airmass_absolute, aoi,
self.module_parameters)
for df, aoi in zip(total_irrad, aoi)]
return ee
except TypeError:
return sapm_effective_irradiance(
total_irrad['poa_direct'], total_irrad['poa_diffuse'],
airmass_absolute, aoi, self.module_parameters)

def pvsyst_celltemp(self, poa_global, temp_air, wind_speed=1.0):
"""Uses :py:func:`temperature.pvsyst_cell` to calculate cell
Expand Down
54 changes: 51 additions & 3 deletions pvlib/temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,9 +377,10 @@ def pvsyst_cell(poa_global, temp_air, wind_speed=1.0, u_c=29.0, u_v=0.0,

def faiman(poa_global, temp_air, wind_speed=1.0, u0=25.0, u1=6.84):
r'''
Calculate cell or module temperature using the Faiman model. The Faiman
model uses an empirical heat loss factor model [1]_ and is adopted in the
IEC 61853 standards [2]_ and [3]_.
Calculate cell or module temperature using the Faiman model.

The Faiman model uses an empirical heat loss factor model [1]_ and is
adopted in the IEC 61853 standards [2]_ and [3]_.

Usage of this model in the IEC 61853 standard does not distinguish
between cell and module temperature.
Expand Down Expand Up @@ -443,6 +444,53 @@ def faiman(poa_global, temp_air, wind_speed=1.0, u0=25.0, u1=6.84):
return temp_air + temp_difference


def ross(poa_global, temp_air, noct):
r'''
Calculate cell temperature using the Ross model.

The Ross model [1]_ assumes the difference between cell temperature
and ambient temperature is proportional to the plane of array irradiance,
and ignores the effects of wind. The model implicitly assumes steady or
slowly changing irradiance conditions.

Parameters
----------
poa_global : numeric
Total incident irradiance. [W/m^2]

temp_air : numeric
Ambient dry bulb temperature. [C]

noct : numeric
Nominal operating cell temperature [C], determined at conditions of
800 W/m^2 irradiance, 20 C ambient air temperature and 1 m/s wind.

Returns
-------
cell_temperature : numeric
Cell temperature. [C]

Notes
-----
The Ross model for cell temperature :math:`T_{C}` is given in [1]_ as

.. math::

T_{C} = T_{a} + \frac{NOCT - 20}{80} S

where :math:`S` is the plane of array irradiance in :math:`mW/{cm}^2`.
This function expects irradiance in :math:`W/m^2`.

References
----------
.. [1] Ross, R. G. Jr., (1981). "Design Techniques for Flat-Plate
Photovoltaic Arrays". 15th IEEE Photovoltaic Specialist Conference,
Orlando, FL.
'''
# factor of 0.1 converts irradiance from W/m2 to mW/cm2
return temp_air + (noct - 20.) / 80. * poa_global * 0.1


def _fuentes_hconv(tave, windmod, tinoct, temp_delta, xlen, tilt,
check_reynold):
# Calculate the convective coefficient as in Fuentes 1987 -- a mixture of
Expand Down
8 changes: 8 additions & 0 deletions pvlib/tests/test_temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ def test_faiman_ndarray():
assert_allclose(expected, result, 3)


def test_ross():
result = temperature.ross(np.array([1000., 600., 1000.]),
np.array([20., 40., 60.]),
np.array([40., 100., 20.]))
expected = np.array([45., 100., 60.])
assert_allclose(expected, result)


def test_faiman_series():
times = pd.date_range(start="2015-01-01", end="2015-01-02", freq="12H")
temps = pd.Series([0, 10, 5], index=times)
Expand Down