Skip to content

Implement IEC 61853 module temperature model #834

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

Merged
merged 4 commits into from
Dec 13, 2019
Merged
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
1 change: 1 addition & 0 deletions docs/sphinx/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ PV temperature models
temperature.sapm_cell
temperature.sapm_module
temperature.pvsyst_cell
temperature.faiman

Single diode models
-------------------
Expand Down
6 changes: 4 additions & 2 deletions docs/sphinx/source/whatsnew/v0.7.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,12 @@ Other API Changes

Enhancements
~~~~~~~~~~~~
* Created one new temperature model function:
:py:func:`pvlib.temperature.faiman`. (:issue:`750`)
* Created two new incidence angle modifier (IAM) functions:
:py:func:`pvlib.iam.martin_ruiz` and :py:func:`pvlib.iam.interp`. (:issue:`751`)
* Created one new incidence angle modifier (IAM) function for diffuse irradiance:
:py:func:`pvlib.iam.martin_ruiz_diffuse`. (:issue:`751`)
* Add the `martin_ruiz` IAM function as an option for `ModelChain.aoi_model`.
* Updated the file for module parameters for the CEC model, from the SAM file
dated 2017-6-5 to the SAM file dated 2019-03-05. (:issue:`761`)
Expand All @@ -138,8 +142,6 @@ Enhancements
* Add `timeout` to :py:func:`pvlib.iotools.get_psm3`.
* Add :py:func:`~pvlib.scaling.wvm`, a port of the wavelet variability model for
computing reductions in variability due to a spatially distributed plant.
* Created one new incidence angle modifier (IAM) function for diffuse irradiance:
:py:func:`pvlib.iam.martin_ruiz_diffuse`. (:issue:`751`)
* Add :py:meth:`~pvlib.location.Location.from_epw`, a method to create a Location
object from epw metadata, typically coming from `pvlib.iotools.epw.read_epw`.

Expand Down
66 changes: 66 additions & 0 deletions pvlib/temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,3 +269,69 @@ def pvsyst_cell(poa_global, temp_air, wind_speed=1.0, u_c=29.0, u_v=0.0,
heat_input = poa_global * alpha_absorption * (1 - eta_m)
temp_difference = heat_input / total_loss_factor
return temp_air + temp_difference


def faiman(poa_global, temp_air, wind_speed=1.0, u0=25.0, u1=6.84):
'''
Calculate cell or module temperature using an empirical heat loss factor
model as proposed by Faiman [1] and 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.

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

temp_air : numeric
Ambient dry bulb temperature [C].

wind_speed : numeric, default 1.0
Wind speed in m/s measured at the same height for which the wind loss
factor was determined. The default value 1.0 m/s is the wind
speed at module height used to determine NOCT. [m/s]

u0 : numeric, default 25.0
Combined heat loss factor coefficient. The default value is one
determined by Faiman for 7 silicon modules. [W/(m^2 C)].

u1 : numeric, default 6.84
Combined heat loss factor influenced by wind. The default value is one
determined by Faiman for 7 silicon modules. [(W/m^2 C)(m/s)].

Returns
-------
numeric, values in degrees Celsius

Notes
-----
All arguments may be scalars or vectors. If multiple arguments
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Note doesn't hurt but I don't think it's needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also considered about using array-like, but that depends on the conclusion and transition plan for #765. (Only one definition of 'array-like' should apply at one time.)

are vectors they must be the same length.

References
----------
[1] Faiman, D. (2008). "Assessing the outdoor operating temperature of
photovoltaic modules." Progress in Photovoltaics 16(4): 307-315.

[2] "IEC 61853-2 Photovoltaic (PV) module performance testing and energy
rating - Part 2: Spectral responsivity, incidence angle and module
operating temperature measurements". IEC, Geneva, 2018.

[3] "IEC 61853-3 Photovoltaic (PV) module performance testing and energy
rating - Part 3: Energy rating of PV modules". IEC, Geneva, 2018.

'''
# Contributed by Anton Driesse (@adriesse), PV Performance Labs. Dec., 2019

# The following lines may seem odd since u0 & u1 are probably scalar,
# but it serves an indirect and easy way of allowing lists and
# tuples for the other function arguments.
u0 = np.asanyarray(u0)
u1 = np.asanyarray(u1)

total_loss_factor = u0 + u1 * wind_speed
heat_input = poa_global
temp_difference = heat_input / total_loss_factor
return temp_air + temp_difference
39 changes: 39 additions & 0 deletions pvlib/test/test_temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,45 @@ def test_pvsyst_cell_series():
assert_series_equal(expected, result)


def test_faiman_default():
result = temperature.faiman(900, 20, 5)
assert_allclose(result, 35.203, 0.001)


def test_faiman_kwargs():
result = temperature.faiman(900, 20, wind_speed=5.0, u0=22.0, u1=6.)
assert_allclose(result, 37.308, 0.001)


def test_faiman_list():
temps = [0, 10, 5]
irrads = [0, 500, 0]
winds = [10, 5, 0]
result = temperature.faiman(irrads, temps, wind_speed=winds)
expected = np.array([0.0, 18.446, 5.0])
assert_allclose(expected, result, 3)


def test_faiman_ndarray():
temps = np.array([0, 10, 5])
irrads = np.array([0, 500, 0])
winds = np.array([10, 5, 0])
result = temperature.faiman(irrads, temps, wind_speed=winds)
expected = np.array([0.0, 18.446, 5.0])
assert_allclose(expected, result, 3)


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)
irrads = pd.Series([0, 500, 0], index=times)
winds = pd.Series([10, 5, 0], index=times)

result = temperature.faiman(irrads, temps, wind_speed=winds)
expected = pd.Series([0.0, 18.446, 5.0], index=times)
assert_series_equal(expected, result)


def test__temperature_model_params():
params = temperature._temperature_model_params('sapm',
'open_rack_glass_glass')
Expand Down