Skip to content
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
2 changes: 2 additions & 0 deletions docs/sphinx/source/whatsnew/v0.11.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Documentation
page. (:issue:`2202`, :pull:`2226`)
* Updated :py:func:`~pvlib.irradiance.reindl` to include definitions of terms
and a new "notes" section (:issue:`2183`, :pull:`2193`)
* Clarified the error message in :py:func:`~pvlib.clearsky.detect_clearsky` when
windows contain fewer than three data points (:issue:`2005`, :pull:`2281`)
* Added a new :ref:`nomenclature` page, in place of the Variables and Symbols
page, using the sphinx glossary directive. (:issue:`1421`, :pull:`2234`)
* Explained how to write docstrings for new functions in :ref:`example-docstring`
Expand Down
49 changes: 31 additions & 18 deletions pvlib/clearsky.py
Original file line number Diff line number Diff line change
Expand Up @@ -683,22 +683,26 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
var_diff=0.005, slope_dev=8, max_iterations=20,
return_components=False):
"""
Detects clear sky times according to the algorithm developed by Reno
and Hansen for GHI measurements. The algorithm [1]_ was designed and
validated for analyzing GHI time series only. Users may attempt to
apply it to other types of time series data using different filter
settings, but should be skeptical of the results.
Detects clear sky times using the algorithm developed by Reno
and Hansen.

The algorithm detects clear sky times by comparing statistics for a
The algorithm [1]_ was designed and
validated for analyzing GHI time series. Jordan and Hansen [2]_ extended
the algorithm to plane-of-array (POA) irradiance measurements.

The algorithm [1]_ detects clear sky times by comparing statistics for a
measured time series and an expected clearsky time series.
Statistics are calculated using a sliding time window (e.g., 10
minutes). An iterative algorithm identifies clear periods, uses the
identified periods to estimate bias in the clearsky data, scales the
clearsky data and repeats.

Clear times are identified by meeting 5 criteria. Default values for
Clear times are identified by meeting five criteria. Default values for
these thresholds are appropriate for 10 minute windows of 1 minute
GHI data.
GHI data. For data at longer intervals, it is recommended
to set ``infer_limits=True`` to use the thresholds from [2]_.

For POA data, ``clearsky`` must be on the same plane as ``measured``.

Parameters
----------
Expand All @@ -713,8 +717,8 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
If True, does not use passed in kwargs (or defaults), but instead
interpolates these values from Table 1 in [2]_.
window_length : int, default 10
Length of sliding time window in minutes. Must be greater than 2
periods.
Length of sliding time window in minutes. Each window must contain at
least three data points.
mean_diff : float, default 75
Threshold value for agreement between mean values of measured
and clearsky in each interval, see Eq. 6 in [1]. [W/m2]
Expand All @@ -723,8 +727,6 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
clearsky values in each interval, see Eq. 7 in [1]. [W/m2]
lower_line_length : float, default -5
Lower limit of line length criterion from Eq. 8 in [1].
Criterion satisfied when lower_line_length < line length difference
< upper_line_length.
upper_line_length : float, default 10
Upper limit of line length criterion from Eq. 8 in [1].
var_diff : float, default 0.005
Expand All @@ -736,7 +738,7 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
change in successive values, see Eqs. 12 through 14 in [1].
max_iterations : int, default 20
Maximum number of times to apply a different scaling factor to
the clearsky and redetermine clear_samples. Must be 1 or larger.
the clearsky and redetermine ``clear_samples``. Must be 1 or larger.
return_components : bool, default False
Controls if additional output should be returned. See below.

Expand All @@ -748,19 +750,23 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,

components : OrderedDict, optional
Dict of arrays of whether or not the given time window is clear
for each condition. Only provided if return_components is True.
for each condition. Only provided if ``return_components`` is True.

alpha : scalar, optional
Scaling factor applied to the clearsky_ghi to obtain the
detected clear_samples. Only provided if return_components is
Scaling factor applied to ``clearsky`` to obtain the
detected ``clear_samples``. Only provided if ``return_components`` is
True.

Raises
------
ValueError
If measured is not a Series and times is not provided
If ``measured`` is not a Series and times is not provided.
ValueError
If a window contains less than three data points.
ValueError
If the measured data is not sufficient to fill a window.
NotImplementedError
If timestamps are not equally spaced
If timestamps are not equally spaced.

References
----------
Expand Down Expand Up @@ -812,6 +818,13 @@ def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
sample_interval, samples_per_window = \
tools._get_sample_intervals(times, window_length)

if samples_per_window < 3:
raise ValueError(f"Samples per window of {samples_per_window}"
" found. Each window must contain at least 3 data"
" points."
f" Window length of {window_length} found; increase"
f" window length to {3*sample_interval} or longer.")

# if infer_limits, find threshold values using the sample interval
if infer_limits:
window_length, mean_diff, max_diff, lower_line_length, \
Expand Down
8 changes: 7 additions & 1 deletion pvlib/tests/test_clearsky.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,10 +674,16 @@ def test_detect_clearsky_missing_index(detect_clearsky_data):

def test_detect_clearsky_not_enough_data(detect_clearsky_data):
expected, cs = detect_clearsky_data
with pytest.raises(ValueError, match='have at least'):
with pytest.raises(ValueError, match='times has only'):
clearsky.detect_clearsky(expected['GHI'], cs['ghi'], window_length=60)


def test_detect_clearsky_window_too_short(detect_clearsky_data):
expected, cs = detect_clearsky_data
with pytest.raises(ValueError, match="Samples per window of "):
clearsky.detect_clearsky(expected['GHI'], cs['ghi'], window_length=2)


@pytest.mark.parametrize("window_length", [5, 10, 15, 20, 25])
def test_detect_clearsky_optimizer_not_failed(
detect_clearsky_data, window_length
Expand Down
Loading