Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
38 changes: 21 additions & 17 deletions pvlib/temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import pandas as pd
from pvlib.tools import sind
from pvlib._deprecation import warn_deprecated
from pvlib.clearsky import _get_sample_intervals
import scipy
import warnings


TEMPERATURE_MODEL_PARAMETERS = {
Expand Down Expand Up @@ -827,22 +829,22 @@ def noct_sam(poa_global, temp_air, wind_speed, noct, module_efficiency,

def prilliman(temp_cell, wind_speed, unit_mass=11.1, coefficients=None):
"""
Smooth out short-term model transience using the Prilliman model [1]_.
Smooth short-term cell temperature transients using the Prilliman model.

The Prilliman et al. model applies an exponential moving average to
the output of a steady-state cell temperature model to account for a
module's thermal inertia and smooth out the cell temperature's response
to changing weather conditions.
The Prilliman et al. model [1]_ applies a weighted moving average to
the output of a steady-state cell temperature model to account for
a module's thermal inertia by smoothing the cell temperature's
response to changing weather conditions.

.. warning::
This implementation requires the time series inputs to be regularly
sampled in time. Data with irregular time steps should be resampled
prior to using this function.
sampled in time with frequency less than 20 minutes. Data with
irregular time steps should be resampled prior to using this function.

Parameters
----------
temp_cell : pandas Series
Cell temperature modeled with steady-state assumptions [C]
temp_cell : pandas Series with DatetimeIndex
Cell temperature modeled with steady-state assumptions. [C]

wind_speed : pandas Series
Wind speed, adjusted to correspond to array height [m/s]
Expand All @@ -851,7 +853,7 @@ def prilliman(temp_cell, wind_speed, unit_mass=11.1, coefficients=None):
Total mass of module divided by its one-sided surface area [kg/m^2]

coefficients : 4-element list-like, optional
Values for coefficients a_0a_3 from [1]_
Values for coefficients a_0 through a_3, see Eq. 9 of [1]_

Returns
-------
Expand All @@ -861,7 +863,7 @@ def prilliman(temp_cell, wind_speed, unit_mass=11.1, coefficients=None):
Notes
-----
This smoothing model was developed and validated using the SAPM
model for the steady-state input.
cell temperature model for the steady-state input.

References
Copy link
Member

Choose a reason for hiding this comment

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

One more suggestion: explain in Notes how nan in inputs corresponds to nan in output. It makes sense (to me) that output at k is nan if windspeed[k] is nan. As a user, I may be surprised non-nan at position k in output when input temp_cell[k] is nan. But that also makes sense, because the non-nan value can be produced when window of temp_cell prior to k has data.

Output ``temp_cell[k]`` is NaN when input ``wind_speed[k]`` is NaN, or when no non-NaN data are
in the input temperature for the 20 minute window preceding index ``k``.

----------
Expand All @@ -871,15 +873,17 @@ def prilliman(temp_cell, wind_speed, unit_mass=11.1, coefficients=None):
:doi:`10.1109/JPHOTOV.2020.2992351`
"""

# TODO: check inputs to ensure regular spacing?
time_step, window = _get_sample_intervals(temp_cell.index, 20)

time_step = (temp_cell.index[1] - temp_cell.index[0]).total_seconds()
if time_step >= 1200:
if time_step >= 20:
warnings.warn("temperature.prilliman only applies smoothing when "
"the sampling interval is shorter than 20 minutes "
f"(input sampling interval: {time_step} minutes)")
# too coarsely sampled for smoothing to be relevant
Copy link
Member

Choose a reason for hiding this comment

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

I think a warning here would be appropriate

Copy link
Member

Choose a reason for hiding this comment

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

Maybe extend the message to say that the return values are the original temperature?

return temp_cell

window = min(int(1200 / time_step), # time series > 20 minutes
len(temp_cell)) # time series < 20 minutes
window = min(window, # time series > 20 minutes total
len(temp_cell)) # time series < 20 minutes total

# prefix with NaNs so that the rolling window is "full",
# even for the first actual value:
Expand All @@ -900,7 +904,7 @@ def prilliman(temp_cell, wind_speed, unit_mass=11.1, coefficients=None):

wind_speed = wind_speed.values
P = a[0] + a[1]*wind_speed + a[2]*unit_mass + a[3]*wind_speed*unit_mass
timedeltas = np.arange(window, 0, -1) * time_step
timedeltas = np.arange(window, 0, -1) * (time_step*60) # s to min
weights = np.exp(-P[:, np.newaxis] * timedeltas)

# set weights corresponding to the prefix values to zero; otherwise the
Expand Down
11 changes: 9 additions & 2 deletions pvlib/tests/test_temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from pvlib import temperature, tools
from pvlib._deprecation import pvlibDeprecationWarning

import re


@pytest.fixture
def sapm_default():
Expand Down Expand Up @@ -326,11 +328,16 @@ def test_prilliman():


def test_prilliman_coarse():
# if the input series time step is >= 20 min, input is returned unchanged:
# if the input series time step is >= 20 min, input is returned unchanged,
# and a warning is emitted
times = pd.date_range('2019-01-01', freq='30min', periods=3)
cell_temperature = pd.Series([0, 1, 3], index=times)
wind_speed = pd.Series([0, 1, 2])
actual = temperature.prilliman(cell_temperature, wind_speed)
msg = re.escape("temperature.prilliman only applies smoothing when the "
"sampling interval is shorter than 20 minutes (input "
"sampling interval: 30.0 minutes)")
with pytest.warns(UserWarning, match=msg):
actual = temperature.prilliman(cell_temperature, wind_speed)
assert_series_equal(cell_temperature, actual)


Expand Down