Source code for bsrn.qc.tracker
"""
BSRN Level 6 checks - tracker-off detection.
"""
import numpy as np
import pandas as pd
[docs]
def tracker_off_test(ghi, bni, zenith, ghi_extra=None, ghi_clear=None,
dhi_clear=None, bni_clear=None):
"""
Check if the solar tracker is off by comparing measured and clear-sky irradiances [1]_.
Parameters
----------
ghi : numeric or Series
Measured global horizontal irradiance ($G_h$). [W/m^2]
bni : numeric or Series
Measured beam normal irradiance ($B_n$). [W/m^2]
zenith : numeric or Series
Solar zenith angle ($Z$). [degrees]
ghi_extra : numeric or Series, optional
Extraterrestrial horizontal irradiance ($E_0$). [W/m^2]
ghi_clear : numeric or Series, optional
Reference clear-sky global horizontal irradiance ($G_{hc}$). [W/m^2]
dhi_clear : numeric or Series, optional
Reference clear-sky diffuse horizontal irradiance ($D_{hc}$). [W/m^2]
bni_clear : numeric or Series, optional
Reference clear-sky beam normal irradiance ($B_{nc}$). [W/m^2]
Returns
-------
flags : Series or ndarray
Boolean flags (True = Pass). [bool]
Raises
------
ValueError
If ``ghi_clear`` is not provided and ``ghi_extra`` is also missing.
References
----------
.. [1] Forstinger, A., et al. (2021). Expert quality control of solar
radiation ground data sets. In SWC 2021: ISES Solar World Congress.
International Solar Energy Society.
"""
mu0 = np.cos(np.radians(zenith))
# Fallback definitions per Forstinger et al. (2021)
if ghi_clear is None:
if ghi_extra is None:
raise ValueError(
"ghi_extra must be provided if ghi_clear is not supplied."
)
# GHIC ($G_{hc}$) = 0.8 * GHIE ($E_{0}$)
ghi_clear = 0.8 * ghi_extra
if dhi_clear is None:
# DHIC ($D_{hc}$) = 0.165 * GHIC ($G_{hc}$)
dhi_clear = 0.165 * ghi_clear
if bni_clear is None:
# BNIC ($B_{nc}$) = (GHIC - DHIC) / mu0
bni_clear = (ghi_clear - dhi_clear) / np.maximum(mu0, 0.01)
# Tracker-off: GHI near clear-sky but BNI far below reference
# Term 1: (GHIC - GHI) / (GHIC + GHI) < 0.2
term1 = (ghi_clear - ghi) / (ghi_clear + ghi)
# Term 2: (BNIC - BNI) / (BNIC + BNI) > 0.95
term2 = (bni_clear - bni) / (bni_clear + bni)
# Apply when zenith < 85°
tracker_is_off = (term1 < 0.2) & (term2 > 0.95) & (zenith < 85)
if hasattr(tracker_is_off, 'iloc'):
return ~tracker_is_off
else:
return not tracker_is_off