Skip to content

Add ape_e spectral factor model #2126

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 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ Spectrum
spectrum.spectral_factor_sapm
spectrum.spectral_factor_pvspec
spectrum.spectral_factor_jrc
spectrum.spectral_factor_daxini
spectrum.sr_to_qe
spectrum.qe_to_sr
1 change: 1 addition & 0 deletions pvlib/spectrum/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
spectral_factor_sapm,
spectral_factor_pvspec,
spectral_factor_jrc,
spectral_factor_daxini,
sr_to_qe,
qe_to_sr
)
126 changes: 126 additions & 0 deletions pvlib/spectrum/mismatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,132 @@ def spectral_factor_pvspec(airmass_absolute, clearsky_index,
return mismatch


def spectral_factor_daxini(ape, band_depth, module_type=None,
coefficients=None):
r"""
Estimate a technology-specific spectral mismatch modifier from the average
photon energy (APE) and the depth of a water absorption band using the
Daxini model.

Parameters
----------
ape : numeric
Average photon energy (APE, :math:`\varphi`) [eV]

band_depth : numeric
Depth of a spectral band, :math:`\varepsilon` [Wm:math:`^{-2}`]
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Depth of a spectral band, :math:`\varepsilon` [Wm:math:`^{-2}`]
Depth of a spectral band, :math:`\varepsilon` [W/m²]


module_type : str, optional
One of the following PV technology strings from [1]_:

* ``asi-t`` - anyonymous triple junction amorphous Si module
* ``'cdte'`` - anyonymous CdTe module.
* ``'multisi'`` - anyonymous multicrystalline Si module

The default is None.

coefficients : array-like, optional
User-defined coefficients, if not using one of the default coefficient
sets via the ``module_type`` parameter. The default is None.
Comment on lines +861 to +865
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we remove "The default is None."?

#1574 , #1828, #2084


Returns
-------
mismatch: numeric
spectral mismatch factor [unitless], which is multiplied
with broadband irradiance reaching a module's cells to estimate
effective irradiance, i.e., the irradiance that is converted to
electrical current.

Notes
-----
The Daxini model parameterises the spectral mismatch factor, :math:`M`, as
a function of the average photon energy, :math:`\varphi`, and the depth of
a water absorption band, :math:`\varepsilon`, as follows:

.. math::

M = a_0 + a_1\varphi + a_2\varepsilon + a_3\varphi^2 + a_4\varepsilon^2
+ a_5\varphi\varepsilon,

where :math:`a_{0-5}` are module-specific coefficients. In [1]_,
:math:`\varphi` is calculated between the limits of 350nm to 1050nm.
While several atmopsheric windows and water absorption bands within the
spectral irradiance range 350nm-1050nm were tested as candidates for
:math:`\varepsilon`, ultimately the 650nm-670nm is recommended for the PV
devices analysed in the study. It should be noted that "depth" here refers
to the area beneath the spectral irradiance curve within the specified
wavelength limits, which in this case are 650nm-670nm. Therefore,
:math:`\varepsilon` is calculated by integrating the spectral irradiance,
with respect to wavelength, between 650nm-670nm. The purpose of this second
index is to distinguish between different spectra that have the same or
similar APE values, the occurance of which reduces the reliability of a
single-variable APE spectral mismatch estimation function.

The model is developed and validated using one year of outdoor
meteorological, PV, and spectral irradiance data measured at the National
Renewable Energy Laboratory in Golden, Colorado, USA. The data used are
publicly available and can be found at [2]_ and [3]_. The primary
publications associated with these data releases are [4]_, and [5]_ and
[6]_, respectively.

References
----------
.. [1] Daxini, R., et al., 2023 "Modelling the spectral influence on
photovoltaic device performance using the average photon energy and
the depth of a water absorption band for improved forecasting."
Energy 284: 129046.
:doi:`10.1016/j.energy.2023.129046`
.. [2] Measurement and Instrumentation Data Center (MIDC)
:doi:`10.5439/1052221`
.. [3] Data for Validating Models for PV Module Performance
:doi:`10.21948/1811521`
.. [4] Stoffel, T., and Andreas, A. NREL Solar Radiation Research
laboratory (SRRL): Baseline measurement system (BMS); Golden,
Colorado (data). No. NREL/DA-5500-56488. National Renewable Energy
Laboratory.(NREL), Golden, CO (United States), 1981.
:doi:`10.5439/1052221`
.. [5] Marion, B., et al. Data for validating models for PV module
performance. EMN-DURMAT (EMN-DuraMAT); National Renewable Energy
Laboratory (NREL), Golden, CO (United States), 2021.
:doi:`10.21948/1811521`
.. [6] Marion, B., et al. User's manual for data for validating models for
PV module performance. No. NREL/TP-5200-61610. National Renewable
Energy Laboratory (NREL), Golden, CO (United States), 2014.
:doi:`10.2172/1130632`
"""

_coefficients = {}
_coefficients['multisi'] = (-0.3998, 1.101, 0.03366, -0.1837,
1.493e-4, -0.02046)
_coefficients['cdte'] = (-0.5313, 0.7208, 0.02232, 0.05321,
1.629e-4, -0.01445)
_coefficients['asi-t'] = (-21.94, 22.62, -0.01393, -5.521,
1.7341e-4, 0.003860)

if module_type is not None and coefficients is None:
coefficients = _coefficients[module_type.lower()]
elif module_type is None and coefficients is not None:
pass
elif module_type is None and coefficients is None:
raise ValueError('No valid input provided, both module_type and ' +
'coefficients are None. module_type can be one of ' +
", ".join(_coefficients.keys()))
else:
raise ValueError('Cannot resolve input, must supply only one of ' +
'module_type and coefficients. module_type can be ' +
'one of' ", ".join(_coefficients.keys()))

coeff = coefficients
e = band_depth

mismatch = (
coeff[0] + coeff[1]*ape + coeff[2]*e + coeff[3]*ape**2
+ coeff[4]*e**2 + coeff[5]*ape*e
)

return mismatch


def spectral_factor_jrc(airmass, clearsky_index, module_type=None,
coefficients=None):
r"""
Expand Down
37 changes: 37 additions & 0 deletions pvlib/tests/test_spectrum.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,43 @@ def test_spectral_factor_jrc_supplied_ambiguous():
coefficients=None)


@pytest.mark.parametrize("module_type,expected", [
('multisi', pd.Series([0.98897, 1.000677, 1.00829])),
('cdte', pd.Series([0.94950, 0.98647, 1.04016])),
('asi-t', pd.Series([0.92752, 1.02894, 1.13527])),
])
def test_spectral_factor_daxini_series(module_type, expected):
apes = pd.Series([1.82, 1.87, 1.95])
bands = pd.Series([2, 4, 8])
out = spectrum.spectral_factor_daxini(apes, bands,
module_type=module_type)
assert isinstance(out, pd.Series)
assert np.allclose(expected, out, atol=1e-5)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
assert np.allclose(expected, out, atol=1e-5)
assert_allclose(out, expected, atol=1e-5)



def test_spectral_factor_daxini_supplied():
# use the cdte coeffs
coeffs = (-0.5313, 0.7208, 0.02232, 0.05321, 1.629e-4, -0.01445)
out = spectrum.spectral_factor_daxini(1.87, 4, coefficients=coeffs)
expected = 0.98647
assert_allclose(out, expected, atol=1e-5)


def test_spectral_factor_daxini_supplied_redundant():
# Error when specifying both module_type and coefficients
coeffs = (-0.5313, 0.7208, 0.02232, 0.05321, 1.629e-4, -0.01445)
with pytest.raises(ValueError, match='supply only one of'):
spectrum.spectral_factor_daxini(1.87, 4, module_type='cdte',
coefficients=coeffs)


def test_spectral_factor_daxini_supplied_ambiguous():
# Error when specifying neither module_type nor coefficients
with pytest.raises(ValueError, match='No valid input provided'):
spectrum.spectral_factor_daxini(1.87, 4, module_type=None,
coefficients=None)


@pytest.fixture
def sr_and_eqe_fixture():
# Just some arbitrary data for testing the conversion functions
Expand Down
Loading