Skip to content

Commit 3f2daab

Browse files
RDaxiniechedey-lscwhanse
authored
Add JRC spectral factor correction (#2088)
* 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]>
1 parent 229a187 commit 3f2daab

File tree

5 files changed

+168
-3
lines changed

5 files changed

+168
-3
lines changed

docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,6 @@ Spectrum
1515
spectrum.spectral_factor_firstsolar
1616
spectrum.spectral_factor_sapm
1717
spectrum.spectral_factor_pvspec
18+
spectrum.spectral_factor_jrc
1819
spectrum.sr_to_qe
1920
spectrum.qe_to_sr

docs/sphinx/source/whatsnew/v0.11.0.rst

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,14 @@ Enhancements
4646
efficiency ([unitless]) and vice versa. The conversion functions are
4747
:py:func:`pvlib.spectrum.sr_to_qe` and :py:func:`pvlib.spectrum.qe_to_sr`
4848
respectively. (:issue:`2040`, :pull:`2041`)
49-
* Add function :py:func:`pvlib.spectrum.spectral_factor_pvspec`, which calculates the
50-
spectral mismatch factor as a function of absolute airmass and clearsky index
51-
using the PVSPEC model. (:issue:`1950`, :issue:`2065`, :pull:`2072`)
49+
* Add function :py:func:`pvlib.spectrum.spectral_factor_pvspec`, which
50+
calculates the spectral mismatch factor as a function of absolute airmass and
51+
clearsky index using the PVSPEC model.
52+
(:issue:`1950`, :issue:`2065`, :pull:`2072`)
53+
* Add function :py:func:`pvlib.spectrum.spectral_factor_jrc`, which calculates
54+
the spectral mismatch factor as a function of airmass and clearsky
55+
index using the JRC model.
56+
(:issue:`1950`, :issue:`2065`, :issue:`2087`, :pull:`2088`)
5257
* Added extraterrestrial and direct spectra of the ASTM G173-03 standard with
5358
the new function :py:func:`pvlib.spectrum.get_reference_spectra`.
5459
(:issue:`1963`, :pull:`2039`)

pvlib/spectrum/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
spectral_factor_firstsolar,
99
spectral_factor_sapm,
1010
spectral_factor_pvspec,
11+
spectral_factor_jrc,
1112
sr_to_qe,
1213
qe_to_sr
1314
)

pvlib/spectrum/mismatch.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,116 @@ def spectral_factor_pvspec(airmass_absolute, clearsky_index,
794794
return mismatch
795795

796796

797+
def spectral_factor_jrc(airmass, clearsky_index, module_type=None,
798+
coefficients=None):
799+
r"""
800+
Estimate a technology-specific spectral mismatch modifier from
801+
airmass and clear sky index using the JRC model.
802+
803+
The JRC spectral mismatch model includes the effects of cloud cover on
804+
the irradiance spectrum. Model coefficients are derived using measurements
805+
of irradiance and module performance at the Joint Research Centre (JRC) in
806+
Ispra, Italy (45.80N, 8.62E). Coefficients for two module types are
807+
available via the ``module_type`` parameter. More details on the model can
808+
be found in [1]_.
809+
810+
Parameters
811+
----------
812+
airmass : numeric
813+
relative airmass. [unitless]
814+
815+
clearsky_index: numeric
816+
clear sky index. [unitless]
817+
818+
module_type : str, optional
819+
One of the following PV technology strings from [1]_:
820+
821+
* ``'cdte'`` - anonymous CdTe module.
822+
* ``'multisi'`` - anonymous multicrystalline Si module.
823+
824+
coefficients : array-like, optional
825+
user-defined coefficients, if not using one of the default coefficient
826+
sets via the ``module_type`` parameter.
827+
828+
Returns
829+
-------
830+
mismatch: numeric
831+
spectral mismatch factor (unitless) which is multiplied
832+
with broadband irradiance reaching a module's cells to estimate
833+
effective irradiance, i.e., the irradiance that is converted to
834+
electrical current.
835+
836+
Notes
837+
-----
838+
The JRC model parameterises the spectral mismatch factor as a function
839+
of air mass and the clear sky index as follows:
840+
841+
.. math::
842+
843+
M = 1 + a_1(e^{-k_c}-e^{-1}) + a_2(k_c-1)+a_3(AM-1.5),
844+
845+
where :math:`M` is the spectral mismatch factor, :math:`k_c` is the clear
846+
sky index, :math:`AM` is the air mass, :math:`e` is Euler's number, and
847+
:math:`a_1, a_2, a_3` are module-specific coefficients. The :math:`a_n`
848+
coefficients available via the ``coefficients`` parameter differ from the
849+
:math:`k_n` coefficients documented in [1]_ in that they are normalised by
850+
the specific short-circuit current value, :math:`I_{sc0}^*`, which is the
851+
expected short-circuit current at standard test conditions indoors. The
852+
model used to estimate the air mass (denoted as :math:`AM`) is not stated
853+
in the original publication. The authors of [1]_ used the ESRA model [2]_
854+
to estimate the clear sky GHI for the clear sky index, which is the ratio
855+
of GHI to clear sky GHI. Also, prior to the calculation of :math:`k_c`, the
856+
irradiance measurements were corrected for angle of incidence using the
857+
Martin and Ruiz model [3]_.
858+
859+
References
860+
----------
861+
.. [1] Huld, T., Sample, T., and Dunlop, E., 2009. A simple model
862+
for estimating the influence of spectrum variations on PV performance.
863+
In Proceedings of the 24th European Photovoltaic Solar Energy
864+
Conference, Hamburg, Germany pp. 3385-3389. 2009. Accessed at:
865+
https://www.researchgate.net/publication/256080247
866+
.. [2] Rigollier, C., Bauer, O., and Wald, L., 2000. On the clear sky model
867+
of the ESRA—European Solar Radiation Atlas—with respect to the Heliosat
868+
method. Solar energy, 68(1), pp.33-48.
869+
:doi:`10.1016/S0038-092X(99)00055-9`
870+
.. [3] Martin, N. and Ruiz, J. M., 2001. Calculation of the PV modules
871+
angular losses under field conditions by means of an analytical model.
872+
Solar Energy Materials and Solar Cells, 70(1), 25-38.
873+
:doi:`10.1016/S0927-0248(00)00408-6`
874+
"""
875+
876+
_coefficients = {}
877+
_coefficients['multisi'] = (0.00172, 0.000508, 0.00000357)
878+
_coefficients['cdte'] = (0.000643, 0.000130, 0.0000108)
879+
# normalise coefficients by I*sc0, see [1]
880+
_coefficients = {
881+
'multisi': tuple(x / 0.00348 for x in _coefficients['multisi']),
882+
'cdte': tuple(x / 0.001150 for x in _coefficients['cdte'])
883+
}
884+
if module_type is not None and coefficients is None:
885+
coefficients = _coefficients[module_type.lower()]
886+
elif module_type is None and coefficients is not None:
887+
pass
888+
elif module_type is None and coefficients is None:
889+
raise ValueError('No valid input provided, both module_type and ' +
890+
'coefficients are None. module_type can be one of ' +
891+
", ".join(_coefficients.keys()))
892+
else:
893+
raise ValueError('Cannot resolve input, must supply only one of ' +
894+
'module_type and coefficients. module_type can be ' +
895+
'one of' ", ".join(_coefficients.keys()))
896+
897+
coeff = coefficients
898+
mismatch = (
899+
1
900+
+ coeff[0] * (np.exp(-clearsky_index) - np.exp(-1))
901+
+ coeff[1] * (clearsky_index - 1)
902+
+ coeff[2] * (airmass - 1.5)
903+
)
904+
return mismatch
905+
906+
797907
def sr_to_qe(sr, wavelength=None, normalize=False):
798908
"""
799909
Convert spectral responsivities to quantum efficiencies.

pvlib/tests/test_spectrum.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,54 @@ def test_spectral_factor_pvspec_supplied_ambiguous():
426426
coefficients=None)
427427

428428

429+
@pytest.mark.parametrize("module_type,expected", [
430+
('multisi', np.array([1.06129, 1.03098, 1.01155, 0.99849])),
431+
('cdte', np.array([1.09657, 1.05594, 1.02763, 0.97740])),
432+
])
433+
def test_spectral_factor_jrc(module_type, expected):
434+
ams = np.array([1.0, 1.5, 2.0, 1.5])
435+
kcs = np.array([0.4, 0.6, 0.8, 1.4])
436+
out = spectrum.spectral_factor_jrc(ams, kcs,
437+
module_type=module_type)
438+
assert np.allclose(expected, out, atol=1e-4)
439+
440+
441+
@pytest.mark.parametrize("module_type,expected", [
442+
('multisi', np.array([1.06129, 1.03098, 1.01155, 0.99849])),
443+
('cdte', np.array([1.09657, 1.05594, 1.02763, 0.97740])),
444+
])
445+
def test_spectral_factor_jrc_series(module_type, expected):
446+
ams = pd.Series([1.0, 1.5, 2.0, 1.5])
447+
kcs = pd.Series([0.4, 0.6, 0.8, 1.4])
448+
out = spectrum.spectral_factor_jrc(ams, kcs,
449+
module_type=module_type)
450+
assert isinstance(out, pd.Series)
451+
assert np.allclose(expected, out, atol=1e-4)
452+
453+
454+
def test_spectral_factor_jrc_supplied():
455+
# use the multisi coeffs
456+
coeffs = (0.494, 0.146, 0.00103)
457+
out = spectrum.spectral_factor_jrc(1.0, 0.8, coefficients=coeffs)
458+
expected = 1.01052106
459+
assert_allclose(out, expected, atol=1e-4)
460+
461+
462+
def test_spectral_factor_jrc_supplied_redundant():
463+
# Error when specifying both module_type and coefficients
464+
coeffs = (0.494, 0.146, 0.00103)
465+
with pytest.raises(ValueError, match='supply only one of'):
466+
spectrum.spectral_factor_jrc(1.0, 0.8, module_type='multisi',
467+
coefficients=coeffs)
468+
469+
470+
def test_spectral_factor_jrc_supplied_ambiguous():
471+
# Error when specifying neither module_type nor coefficients
472+
with pytest.raises(ValueError, match='No valid input provided'):
473+
spectrum.spectral_factor_jrc(1.0, 0.8, module_type=None,
474+
coefficients=None)
475+
476+
429477
@pytest.fixture
430478
def sr_and_eqe_fixture():
431479
# Just some arbitrary data for testing the conversion functions

0 commit comments

Comments
 (0)