From 6d1a41463fec4da894f5f463e0e92b6d0623b669 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Sat, 15 Jun 2024 11:52:55 +0200 Subject: [PATCH 01/20] create spectral_factor_jrc --- .../effects_on_pv_system_output/spectrum.rst | 1 + pvlib/spectrum/__init__.py | 1 + pvlib/spectrum/mismatch.py | 98 +++++++++++++++++++ pvlib/tests/test_spectrum.py | 48 +++++++++ 4 files changed, 148 insertions(+) diff --git a/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst b/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst index 56d7a6df15..5aaf760ec5 100644 --- a/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst +++ b/docs/sphinx/source/reference/effects_on_pv_system_output/spectrum.rst @@ -14,5 +14,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 diff --git a/pvlib/spectrum/__init__.py b/pvlib/spectrum/__init__.py index cda7202689..ca2e9d6dfa 100644 --- a/pvlib/spectrum/__init__.py +++ b/pvlib/spectrum/__init__.py @@ -7,6 +7,7 @@ spectral_factor_firstsolar, spectral_factor_sapm, spectral_factor_pvspec, + spectral_factor_jrc, sr_to_qe, qe_to_sr ) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 7c70a35360..ad519f441e 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -10,6 +10,7 @@ from scipy.integrate import trapezoid from scipy.interpolate import interp1d import os +import math from warnings import warn @@ -689,6 +690,103 @@ 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 absolute + 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°48'N, 8°37'E). Coefficients for two module types are + available via the ``module_type`` parameter. More details on the model can + be found in [1]_. + + Parameters + ---------- + airmass_absolute : numeric + absolute (pressure-adjusted) 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 absolute air mass and the clear sky index as follows: + + .. math:: + + M = 1 + a_1(e^{-k_c}) + 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, and :math:`a_1, a_2, a_3` + are module-specific coefficients. In the JRC model publication, the model + used to estimate the air mass (denoted as :math:`AM`) is not stated. The + clear sky index, which is the ratio of GHI to clear sky GHI, uses the ESRA + model [2]_ to estimate the clear sky GHI. Prior to this calculation, the + irradiance measurements are corrected for angle of incidence using the + Martin and Ruiz model [3]_. + + References + ---------- + .. [1] Huld, Thomas, Tony Sample, and Ewan D. Dunlop., 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. + :doi:`10.4229/24thEUPVSEC2009-4AV.3.27` + .. [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., & 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. + """ + + _coefficients = {} + _coefficients['multisi'] = (0.00172, 0.000508, 0.00000357) + _coefficients['cdte'] = (0.000643, 0.000130, 0.0000108) + + 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 + am = airmass + kc = clearsky_index + mismatch = 1 + coeff[0]*(np.power(math.e, -kc) - np.power(math.e, -1)) + coeff[1]*(kc-1)+coeff[2]*(am-1.5) + return mismatch + + def sr_to_qe(sr, wavelength=None, normalize=False): """ Convert spectral responsivities to quantum efficiencies. diff --git a/pvlib/tests/test_spectrum.py b/pvlib/tests/test_spectrum.py index 6b1dcd4506..8e560cb492 100644 --- a/pvlib/tests/test_spectrum.py +++ b/pvlib/tests/test_spectrum.py @@ -374,6 +374,54 @@ def test_spectral_factor_pvspec_supplied_ambiguous(): coefficients=None) +@pytest.mark.parametrize("module_type,expected", [ + ('multisi', np.array([1.00021361, 1.00010800, 1.00004028, 0.99999459])), + ('cdte', np.array([1.00011106, 1.00006434, 1.00003177, 0.99997402])), +]) +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-8) + + +@pytest.mark.parametrize("module_type,expected", [ + ('multisi', np.array([1.00021361, 1.00010800, 1.00004028, 0.99999459])), + ('cdte', np.array([1.00011106, 1.00006434, 1.00003177, 0.99997402])), +]) +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-8) + + +def test_spectral_factor_jrc_supplied(): + # use the multisi coeffs + coeffs = (0.00172, 0.000508, 0.00000357) + out = spectrum.spectral_factor_jrc(1.0, 0.8, coefficients=coeffs) + expected = 1.00003671 + assert_allclose(out, expected, atol=1e-5) + + +def test_spectral_factor_jrc_supplied_redundant(): + # Error when specifying both module_type and coefficients + coeffs = (0.00172, 0.000508, 0.00000357) + 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 From 46233c91c358c45eb0c71f1d4ffeaba9f812bb22 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Sat, 15 Jun 2024 12:15:56 +0200 Subject: [PATCH 02/20] Update mismatch.py --- pvlib/spectrum/mismatch.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index ad519f441e..6e31408f18 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -783,7 +783,8 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, coeff = coefficients am = airmass kc = clearsky_index - mismatch = 1 + coeff[0]*(np.power(math.e, -kc) - np.power(math.e, -1)) + coeff[1]*(kc-1)+coeff[2]*(am-1.5) + mismatch = 1 + coeff[0]*(np.power(math.e, -kc) - np.power(math.e, -1)) +\ + coeff[1]*(kc-1)+coeff[2]*(am-1.5) return mismatch From 4f2dffc12a3684e72d48af99f8148e2e5f62340e Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Sat, 15 Jun 2024 12:27:03 +0200 Subject: [PATCH 03/20] Update mismatch.py --- pvlib/spectrum/mismatch.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 6e31408f18..cae427838f 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -739,9 +739,10 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, M = 1 + a_1(e^{-k_c}) + 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, and :math:`a_1, a_2, a_3` - are module-specific coefficients. In the JRC model publication, the model - used to estimate the air mass (denoted as :math:`AM`) is not stated. The + 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. In the JRC model + publication, the model used to estimate the air mass (denoted as :math:`AM` + ) is not stated. The clear sky index, which is the ratio of GHI to clear sky GHI, uses the ESRA model [2]_ to estimate the clear sky GHI. Prior to this calculation, the irradiance measurements are corrected for angle of incidence using the @@ -758,9 +759,10 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, 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., & Ruiz, J. M., 2001. Calculation of the PV modules + .. [3] Martin, N., & 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 = {} From 193e5ce7b1f488fdb2510b5c9e9a825ca3316223 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:34:02 +0200 Subject: [PATCH 04/20] Update pvlib/spectrum/mismatch.py Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> --- pvlib/spectrum/mismatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index cae427838f..709ab6c371 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -742,7 +742,7 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, 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. In the JRC model publication, the model used to estimate the air mass (denoted as :math:`AM` - ) is not stated. The + ) is not stated. The clear sky index, which is the ratio of GHI to clear sky GHI, uses the ESRA model [2]_ to estimate the clear sky GHI. Prior to this calculation, the irradiance measurements are corrected for angle of incidence using the From 7fe65319f7424f9e6d94b4677f0ed9c309dcc4e1 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:36:43 +0200 Subject: [PATCH 05/20] Update pvlib/spectrum/mismatch.py Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> --- pvlib/spectrum/mismatch.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 709ab6c371..120d133d44 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -783,10 +783,12 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, 'one of' ", ".join(_coefficients.keys())) coeff = coefficients - am = airmass - kc = clearsky_index - mismatch = 1 + coeff[0]*(np.power(math.e, -kc) - np.power(math.e, -1)) +\ - coeff[1]*(kc-1)+coeff[2]*(am-1.5) +mismatch = ( + 1 + + coeff[0] * (np.exp(-clearsky_index) - np.exp(-1)) + + coeff[1] * (clearsky_index - 1) + + coeff[2] * (airmass - 1.5) + ) return mismatch From 33a68372b8abacb11922aaee8816c23970bb5798 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:50:07 +0200 Subject: [PATCH 06/20] Update mismatch.py --- pvlib/spectrum/mismatch.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 120d133d44..ab191488f8 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -736,7 +736,7 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, .. math:: - M = 1 + a_1(e^{-k_c}) + a_2(k_c-1)+a_3(AM-1.5), + 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 @@ -750,16 +750,16 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, References ---------- - .. [1] Huld, Thomas, Tony Sample, and Ewan D. Dunlop., 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. - :doi:`10.4229/24thEUPVSEC2009-4AV.3.27` - .. [2] Rigollier, C., Bauer, O. and Wald, L., 2000. On the clear sky model + .. [1] Huld, T., Tony, S., and Ewan, D., 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., & Ruiz, J. M., 2001. Calculation of the PV modules + .. [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` @@ -783,7 +783,7 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, 'one of' ", ".join(_coefficients.keys())) coeff = coefficients -mismatch = ( + mismatch = ( 1 + coeff[0] * (np.exp(-clearsky_index) - np.exp(-1)) + coeff[1] * (clearsky_index - 1) From ab8ea6612f92f50abe162b59962cb0a1e118259d Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:55:21 +0200 Subject: [PATCH 07/20] Update mismatch.py --- pvlib/spectrum/mismatch.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index ab191488f8..05c9a28aac 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -10,7 +10,6 @@ from scipy.integrate import trapezoid from scipy.interpolate import interp1d import os -import math from warnings import warn From 49ee2aecf1295882c17d34d6668c8579f3de2712 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:05:55 +0200 Subject: [PATCH 08/20] Update mismatch.py --- pvlib/spectrum/mismatch.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 05c9a28aac..a7ce886ec8 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -741,11 +741,10 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, 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. In the JRC model publication, the model used to estimate the air mass (denoted as :math:`AM` - ) is not stated. The - clear sky index, which is the ratio of GHI to clear sky GHI, uses the ESRA - model [2]_ to estimate the clear sky GHI. Prior to this calculation, the - irradiance measurements are corrected for angle of incidence using the - Martin and Ruiz model [3]_. + ) is not stated. The clear sky index, which is the ratio of GHI to clear + sky GHI, uses the ESRA model [2]_ to estimate the clear sky GHI. Prior to + the calculation of :math:`k_c`, the irradiance measurements are corrected + for angle of incidence using the Martin and Ruiz model [3]_. References ---------- From 22fbedcdb82143b24a9454667de828b5c7b201d5 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 17 Jun 2024 16:59:33 +0200 Subject: [PATCH 09/20] Update v0.11.0.rst --- docs/sphinx/source/whatsnew/v0.11.0.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.11.0.rst b/docs/sphinx/source/whatsnew/v0.11.0.rst index 119881157b..c7344e7c3b 100644 --- a/docs/sphinx/source/whatsnew/v0.11.0.rst +++ b/docs/sphinx/source/whatsnew/v0.11.0.rst @@ -35,9 +35,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 absolute airmass and clearsky + index using the JRC model. + (:issue:`1950`, :issue:`2065`, :issue:`2087`, :pull:`2088`) Bug fixes ~~~~~~~~~ From 301c3ee82e8109dc4651381dd5971eef277bed39 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Mon, 17 Jun 2024 18:13:52 +0200 Subject: [PATCH 10/20] normalise coefficients --- pvlib/spectrum/mismatch.py | 4 ++-- pvlib/tests/test_spectrum.py | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index a7ce886ec8..472a3ba8d4 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -764,8 +764,8 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, """ _coefficients = {} - _coefficients['multisi'] = (0.00172, 0.000508, 0.00000357) - _coefficients['cdte'] = (0.000643, 0.000130, 0.0000108) + _coefficients['multisi'] = (0.494, 0.146, 0.00103) + _coefficients['cdte'] = (0.559, 0.113, 0.00939) if module_type is not None and coefficients is None: coefficients = _coefficients[module_type.lower()] diff --git a/pvlib/tests/test_spectrum.py b/pvlib/tests/test_spectrum.py index 8e560cb492..7d4c5b6545 100644 --- a/pvlib/tests/test_spectrum.py +++ b/pvlib/tests/test_spectrum.py @@ -375,8 +375,8 @@ def test_spectral_factor_pvspec_supplied_ambiguous(): @pytest.mark.parametrize("module_type,expected", [ - ('multisi', np.array([1.00021361, 1.00010800, 1.00004028, 0.99999459])), - ('cdte', np.array([1.00011106, 1.00006434, 1.00003177, 0.99997402])), + ('multisi', np.array([1.06129066, 1.03098050, 1.01155106, 0.99848646])), + ('cdte', np.array([1.09656930, 1.05594110, 1.02762528, 0.97740310])), ]) def test_spectral_factor_jrc(module_type, expected): ams = np.array([1.0, 1.5, 2.0, 1.5]) @@ -387,8 +387,8 @@ def test_spectral_factor_jrc(module_type, expected): @pytest.mark.parametrize("module_type,expected", [ - ('multisi', np.array([1.00021361, 1.00010800, 1.00004028, 0.99999459])), - ('cdte', np.array([1.00011106, 1.00006434, 1.00003177, 0.99997402])), + ('multisi', np.array([1.06129066, 1.03098050, 1.01155106, 0.99848646])), + ('cdte', np.array([1.09656930, 1.05594110, 1.02762528, 0.97740310])), ]) def test_spectral_factor_jrc_series(module_type, expected): ams = pd.Series([1.0, 1.5, 2.0, 1.5]) @@ -401,15 +401,15 @@ def test_spectral_factor_jrc_series(module_type, expected): def test_spectral_factor_jrc_supplied(): # use the multisi coeffs - coeffs = (0.00172, 0.000508, 0.00000357) + coeffs = (0.494, 0.146, 0.00103) out = spectrum.spectral_factor_jrc(1.0, 0.8, coefficients=coeffs) - expected = 1.00003671 + expected = 1.01052106 assert_allclose(out, expected, atol=1e-5) def test_spectral_factor_jrc_supplied_redundant(): # Error when specifying both module_type and coefficients - coeffs = (0.00172, 0.000508, 0.00000357) + 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) From 910bcb3f1d34f1b3ef0b7e10ad5d3fcaed78eac7 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:46:48 +0200 Subject: [PATCH 11/20] normalisation calc, test tolerance include normalisation calculation for built in coeff inside the function adjust tests --- additional calculation seems to affect this(?) --- pvlib/spectrum/mismatch.py | 10 +++++++--- pvlib/tests/test_spectrum.py | 14 +++++++------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 472a3ba8d4..63ab837fb6 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -764,9 +764,13 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, """ _coefficients = {} - _coefficients['multisi'] = (0.494, 0.146, 0.00103) - _coefficients['cdte'] = (0.559, 0.113, 0.00939) - + _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: diff --git a/pvlib/tests/test_spectrum.py b/pvlib/tests/test_spectrum.py index 7d4c5b6545..e8f2aa3720 100644 --- a/pvlib/tests/test_spectrum.py +++ b/pvlib/tests/test_spectrum.py @@ -375,20 +375,20 @@ def test_spectral_factor_pvspec_supplied_ambiguous(): @pytest.mark.parametrize("module_type,expected", [ - ('multisi', np.array([1.06129066, 1.03098050, 1.01155106, 0.99848646])), - ('cdte', np.array([1.09656930, 1.05594110, 1.02762528, 0.97740310])), + ('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-8) + assert np.allclose(expected, out, atol=1e-4) @pytest.mark.parametrize("module_type,expected", [ - ('multisi', np.array([1.06129066, 1.03098050, 1.01155106, 0.99848646])), - ('cdte', np.array([1.09656930, 1.05594110, 1.02762528, 0.97740310])), + ('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]) @@ -396,7 +396,7 @@ def test_spectral_factor_jrc_series(module_type, expected): out = spectrum.spectral_factor_jrc(ams, kcs, module_type=module_type) assert isinstance(out, pd.Series) - assert np.allclose(expected, out, atol=1e-8) + assert np.allclose(expected, out, atol=1e-4) def test_spectral_factor_jrc_supplied(): @@ -404,7 +404,7 @@ def test_spectral_factor_jrc_supplied(): 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-5) + assert_allclose(out, expected, atol=1e-4) def test_spectral_factor_jrc_supplied_redundant(): From 2e4ddea8674f828621185fbe16bf2013c20cc0ce Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:38:02 +0200 Subject: [PATCH 12/20] Update mismatch.py --- pvlib/spectrum/mismatch.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 247f7f645a..d610be8081 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -844,12 +844,16 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, 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. In the JRC model - publication, the model used to estimate the air mass (denoted as :math:`AM` - ) is not stated. The clear sky index, which is the ratio of GHI to clear - sky GHI, uses the ESRA model [2]_ to estimate the clear sky GHI. Prior to - the calculation of :math:`k_c`, the irradiance measurements are corrected - for angle of incidence using the Martin and Ruiz model [3]_. + :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 clear sky index, which is the ratio of GHI + to clear sky GHI, uses the ESRA model [2]_ to estimate the clear sky GHI. + Prior to the calculation of :math:`k_c`, the irradiance measurements are + corrected for angle of incidence using the Martin and Ruiz model [3]_. References ---------- From f03beb23a87da07f7b73ccd71f9d82e6c92fbea8 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 19 Jun 2024 18:49:14 +0200 Subject: [PATCH 13/20] Update mismatch.py --- pvlib/spectrum/mismatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index d610be8081..117b8eb120 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -847,7 +847,7 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, :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 + 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 clear sky index, which is the ratio of GHI From 628e3e3a4c3a9306f1133b2f3422ec8433ecec09 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 19 Jun 2024 20:21:00 +0200 Subject: [PATCH 14/20] Update pvlib/spectrum/mismatch.py Co-authored-by: Cliff Hansen --- pvlib/spectrum/mismatch.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 117b8eb120..183d923742 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -850,10 +850,11 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, 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 clear sky index, which is the ratio of GHI - to clear sky GHI, uses the ESRA model [2]_ to estimate the clear sky GHI. - Prior to the calculation of :math:`k_c`, the irradiance measurements are - corrected for angle of incidence using the Martin and Ruiz model [3]_. + 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 ---------- From 37ca87080a2cb8103cbb94f926bfcff5764269eb Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Wed, 19 Jun 2024 20:25:03 +0200 Subject: [PATCH 15/20] Update mismatch.py line length --- pvlib/spectrum/mismatch.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 183d923742..ddf08fce5e 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -851,10 +851,10 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, 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]_. + 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 ---------- From 6c3b11bc370fe93747b1c691e4c014f1ba745586 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 20 Jun 2024 07:43:45 +0200 Subject: [PATCH 16/20] Update v0.11.0.rst --- docs/sphinx/source/whatsnew/v0.11.0.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.11.0.rst b/docs/sphinx/source/whatsnew/v0.11.0.rst index 8434129983..fe137a92c7 100644 --- a/docs/sphinx/source/whatsnew/v0.11.0.rst +++ b/docs/sphinx/source/whatsnew/v0.11.0.rst @@ -49,12 +49,9 @@ Enhancements 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 absolute airmass and clearsky + the spectral mismatch factor as a function of airmass and clearsky index using the JRC model. (:issue:`1950`, :issue:`2065`, :issue:`2087`, :pull:`2088`) -* 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`) * 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`) From 555547f93653b2078e36a0c9c0e7710e65746fc8 Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 20 Jun 2024 07:43:52 +0200 Subject: [PATCH 17/20] Update mismatch.py --- pvlib/spectrum/mismatch.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index ddf08fce5e..aba4c3abf0 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -797,7 +797,7 @@ def spectral_factor_pvspec(airmass_absolute, clearsky_index, def spectral_factor_jrc(airmass, clearsky_index, module_type=None, coefficients=None): r""" - Estimate a technology-specific spectral mismatch modifier from absolute + 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 @@ -809,8 +809,8 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, Parameters ---------- - airmass_absolute : numeric - absolute (pressure-adjusted) airmass. [unitless] + airmass : numeric + relative airmass. [unitless] clearsky_index: numeric clear sky index. [unitless] @@ -836,7 +836,7 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, Notes ----- The JRC model parameterises the spectral mismatch factor as a function - of absolute air mass and the clear sky index as follows: + of air mass and the clear sky index as follows: .. math:: From c20d2f5206de35533ecbeb143c77f7e7ccc7234a Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 20 Jun 2024 07:45:14 +0200 Subject: [PATCH 18/20] Update pvlib/spectrum/mismatch.py Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> --- pvlib/spectrum/mismatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index aba4c3abf0..59939a1173 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -818,7 +818,7 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, module_type : str, optional One of the following PV technology strings from [1]_: - * ``'cdte'``, - anonymous CdTe module. + * ``'cdte'`` - anonymous CdTe module. * ``'multisi'`` - anonymous multicrystalline Si module. coefficients : array-like, optional From 502749b21f3802d1d9fed92a994b3648357cbb5f Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:02:49 +0200 Subject: [PATCH 19/20] Update mismatch.py --- pvlib/spectrum/mismatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index aba4c3abf0..ad81598bcd 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -858,7 +858,7 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, References ---------- - .. [1] Huld, T., Tony, S., and Ewan, D., 2009. A simple model + .. [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: From dfdf218b579a204bb6964393eff45dabc570c33a Mon Sep 17 00:00:00 2001 From: RDaxini <143435106+RDaxini@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:17:48 +0200 Subject: [PATCH 20/20] Update mismatch.py --- pvlib/spectrum/mismatch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/spectrum/mismatch.py b/pvlib/spectrum/mismatch.py index 4ab2fcf062..d2fc4dcf1d 100644 --- a/pvlib/spectrum/mismatch.py +++ b/pvlib/spectrum/mismatch.py @@ -803,7 +803,7 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None, 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°48'N, 8°37'E). Coefficients for two module types are + 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]_.