Skip to content

Commit

Permalink
Add JRC spectral factor correction (#2088)
Browse files Browse the repository at this point in the history
* create spectral_factor_jrc

* Update mismatch.py

* Update mismatch.py

* Update pvlib/spectrum/mismatch.py

Co-authored-by: Echedey Luis <[email protected]>

* Update pvlib/spectrum/mismatch.py

Co-authored-by: Echedey Luis <[email protected]>

* Update mismatch.py

* Update mismatch.py

* Update mismatch.py

* Update v0.11.0.rst

* normalise coefficients

* normalisation calc, test tolerance

include normalisation calculation for built in coeff inside the function
adjust tests --- additional calculation seems to affect this(?)

* Update mismatch.py

* Update mismatch.py

* Update pvlib/spectrum/mismatch.py

Co-authored-by: Cliff Hansen <[email protected]>

* Update mismatch.py

line length

* Update v0.11.0.rst

* Update mismatch.py

* Update pvlib/spectrum/mismatch.py

Co-authored-by: Echedey Luis <[email protected]>

* Update mismatch.py

* Update mismatch.py

---------

Co-authored-by: Echedey Luis <[email protected]>
Co-authored-by: Cliff Hansen <[email protected]>
  • Loading branch information
3 people authored Jun 20, 2024
1 parent 229a187 commit 3f2daab
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ Spectrum
spectrum.spectral_factor_firstsolar
spectrum.spectral_factor_sapm
spectrum.spectral_factor_pvspec
spectrum.spectral_factor_jrc
spectrum.sr_to_qe
spectrum.qe_to_sr
11 changes: 8 additions & 3 deletions docs/sphinx/source/whatsnew/v0.11.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,14 @@ Enhancements
efficiency ([unitless]) and vice versa. The conversion functions are
:py:func:`pvlib.spectrum.sr_to_qe` and :py:func:`pvlib.spectrum.qe_to_sr`
respectively. (:issue:`2040`, :pull:`2041`)
* Add function :py:func:`pvlib.spectrum.spectral_factor_pvspec`, which calculates the
spectral mismatch factor as a function of absolute airmass and clearsky index
using the PVSPEC model. (:issue:`1950`, :issue:`2065`, :pull:`2072`)
* Add function :py:func:`pvlib.spectrum.spectral_factor_pvspec`, which
calculates the spectral mismatch factor as a function of absolute airmass and
clearsky index using the PVSPEC model.
(:issue:`1950`, :issue:`2065`, :pull:`2072`)
* Add function :py:func:`pvlib.spectrum.spectral_factor_jrc`, which calculates
the spectral mismatch factor as a function of airmass and clearsky
index using the JRC model.
(:issue:`1950`, :issue:`2065`, :issue:`2087`, :pull:`2088`)
* Added extraterrestrial and direct spectra of the ASTM G173-03 standard with
the new function :py:func:`pvlib.spectrum.get_reference_spectra`.
(:issue:`1963`, :pull:`2039`)
Expand Down
1 change: 1 addition & 0 deletions pvlib/spectrum/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
spectral_factor_firstsolar,
spectral_factor_sapm,
spectral_factor_pvspec,
spectral_factor_jrc,
sr_to_qe,
qe_to_sr
)
110 changes: 110 additions & 0 deletions pvlib/spectrum/mismatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,116 @@ def spectral_factor_pvspec(airmass_absolute, clearsky_index,
return mismatch


def spectral_factor_jrc(airmass, clearsky_index, module_type=None,
coefficients=None):
r"""
Estimate a technology-specific spectral mismatch modifier from
airmass and clear sky index using the JRC model.
The JRC spectral mismatch model includes the effects of cloud cover on
the irradiance spectrum. Model coefficients are derived using measurements
of irradiance and module performance at the Joint Research Centre (JRC) in
Ispra, Italy (45.80N, 8.62E). Coefficients for two module types are
available via the ``module_type`` parameter. More details on the model can
be found in [1]_.
Parameters
----------
airmass : numeric
relative airmass. [unitless]
clearsky_index: numeric
clear sky index. [unitless]
module_type : str, optional
One of the following PV technology strings from [1]_:
* ``'cdte'`` - anonymous CdTe module.
* ``'multisi'`` - anonymous multicrystalline Si module.
coefficients : array-like, optional
user-defined coefficients, if not using one of the default coefficient
sets via the ``module_type`` parameter.
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 JRC model parameterises the spectral mismatch factor as a function
of air mass and the clear sky index as follows:
.. math::
M = 1 + a_1(e^{-k_c}-e^{-1}) + a_2(k_c-1)+a_3(AM-1.5),
where :math:`M` is the spectral mismatch factor, :math:`k_c` is the clear
sky index, :math:`AM` is the air mass, :math:`e` is Euler's number, and
:math:`a_1, a_2, a_3` are module-specific coefficients. The :math:`a_n`
coefficients available via the ``coefficients`` parameter differ from the
:math:`k_n` coefficients documented in [1]_ in that they are normalised by
the specific short-circuit current value, :math:`I_{sc0}^*`, which is the
expected short-circuit current at standard test conditions indoors. The
model used to estimate the air mass (denoted as :math:`AM`) is not stated
in the original publication. The authors of [1]_ used the ESRA model [2]_
to estimate the clear sky GHI for the clear sky index, which is the ratio
of GHI to clear sky GHI. Also, prior to the calculation of :math:`k_c`, the
irradiance measurements were corrected for angle of incidence using the
Martin and Ruiz model [3]_.
References
----------
.. [1] Huld, T., Sample, T., and Dunlop, E., 2009. A simple model
for estimating the influence of spectrum variations on PV performance.
In Proceedings of the 24th European Photovoltaic Solar Energy
Conference, Hamburg, Germany pp. 3385-3389. 2009. Accessed at:
https://www.researchgate.net/publication/256080247
.. [2] Rigollier, C., Bauer, O., and Wald, L., 2000. On the clear sky model
of the ESRA—European Solar Radiation Atlas—with respect to the Heliosat
method. Solar energy, 68(1), pp.33-48.
:doi:`10.1016/S0038-092X(99)00055-9`
.. [3] Martin, N. and Ruiz, J. M., 2001. Calculation of the PV modules
angular losses under field conditions by means of an analytical model.
Solar Energy Materials and Solar Cells, 70(1), 25-38.
:doi:`10.1016/S0927-0248(00)00408-6`
"""

_coefficients = {}
_coefficients['multisi'] = (0.00172, 0.000508, 0.00000357)
_coefficients['cdte'] = (0.000643, 0.000130, 0.0000108)
# normalise coefficients by I*sc0, see [1]
_coefficients = {
'multisi': tuple(x / 0.00348 for x in _coefficients['multisi']),
'cdte': tuple(x / 0.001150 for x in _coefficients['cdte'])
}
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
mismatch = (
1
+ coeff[0] * (np.exp(-clearsky_index) - np.exp(-1))
+ coeff[1] * (clearsky_index - 1)
+ coeff[2] * (airmass - 1.5)
)
return mismatch


def sr_to_qe(sr, wavelength=None, normalize=False):
"""
Convert spectral responsivities to quantum efficiencies.
Expand Down
48 changes: 48 additions & 0 deletions pvlib/tests/test_spectrum.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,54 @@ def test_spectral_factor_pvspec_supplied_ambiguous():
coefficients=None)


@pytest.mark.parametrize("module_type,expected", [
('multisi', np.array([1.06129, 1.03098, 1.01155, 0.99849])),
('cdte', np.array([1.09657, 1.05594, 1.02763, 0.97740])),
])
def test_spectral_factor_jrc(module_type, expected):
ams = np.array([1.0, 1.5, 2.0, 1.5])
kcs = np.array([0.4, 0.6, 0.8, 1.4])
out = spectrum.spectral_factor_jrc(ams, kcs,
module_type=module_type)
assert np.allclose(expected, out, atol=1e-4)


@pytest.mark.parametrize("module_type,expected", [
('multisi', np.array([1.06129, 1.03098, 1.01155, 0.99849])),
('cdte', np.array([1.09657, 1.05594, 1.02763, 0.97740])),
])
def test_spectral_factor_jrc_series(module_type, expected):
ams = pd.Series([1.0, 1.5, 2.0, 1.5])
kcs = pd.Series([0.4, 0.6, 0.8, 1.4])
out = spectrum.spectral_factor_jrc(ams, kcs,
module_type=module_type)
assert isinstance(out, pd.Series)
assert np.allclose(expected, out, atol=1e-4)


def test_spectral_factor_jrc_supplied():
# use the multisi coeffs
coeffs = (0.494, 0.146, 0.00103)
out = spectrum.spectral_factor_jrc(1.0, 0.8, coefficients=coeffs)
expected = 1.01052106
assert_allclose(out, expected, atol=1e-4)


def test_spectral_factor_jrc_supplied_redundant():
# Error when specifying both module_type and coefficients
coeffs = (0.494, 0.146, 0.00103)
with pytest.raises(ValueError, match='supply only one of'):
spectrum.spectral_factor_jrc(1.0, 0.8, module_type='multisi',
coefficients=coeffs)


def test_spectral_factor_jrc_supplied_ambiguous():
# Error when specifying neither module_type nor coefficients
with pytest.raises(ValueError, match='No valid input provided'):
spectrum.spectral_factor_jrc(1.0, 0.8, module_type=None,
coefficients=None)


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

0 comments on commit 3f2daab

Please sign in to comment.