From 4b668109d51c454f35ea17b6c21fa9ff20384954 Mon Sep 17 00:00:00 2001 From: Omar Bahamida Date: Sun, 15 Jun 2025 23:09:13 +0200 Subject: [PATCH 1/2] Enhance Huld model with EU JRC coefficients - Introduced a new function to infer updated coefficients for the Huld model based on EU JRC research. - Added a parameter to the existing Huld function to optionally use these updated coefficients. - Updated documentation to reflect the new functionality and included references to the EU JRC paper. - Added tests to verify the implementation and ensure compatibility with existing functionality. (cherry picked from commit f0ba338c73d01f4e9cbdacbf594d0866850cb7ff) --- pvlib/pvarray.py | 52 ++++++++++++++++++++++++++++++++++++++++--- tests/test_pvarray.py | 26 ++++++++++++++++++++++ 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/pvlib/pvarray.py b/pvlib/pvarray.py index ab7530f3e5..ed0f242767 100644 --- a/pvlib/pvarray.py +++ b/pvlib/pvarray.py @@ -37,7 +37,7 @@ def pvefficiency_adr(effective_irradiance, temp_cell, the reference conditions. [unitless] k_d : numeric, negative - “Dark irradiance” or diode coefficient which influences the voltage + "Dark irradiance" or diode coefficient which influences the voltage increase with irradiance. [unitless] tc_d : numeric @@ -242,7 +242,45 @@ def _infer_k_huld(cell_type, pdc0): return k -def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None): +def _infer_k_huld_eu_jrc(cell_type, pdc0): + """ + Get the EU JRC updated coefficients for the Huld model. + + Parameters + ---------- + cell_type : str + Must be one of 'csi', 'cis', or 'cdte' + pdc0 : numeric + Power of the modules at reference conditions [W] + + Returns + ------- + tuple + The six coefficients (k1-k6) for the Huld model, scaled by pdc0 + + Notes + ----- + These coefficients are from the EU JRC paper [1]_. The coefficients are + for the version of Huld's equation that has factored Pdc0 out of the + polynomial, so they are multiplied by pdc0 before being returned. + + References + ---------- + .. [1] EU JRC paper, "Updated coefficients for the Huld model", + https://doi.org/10.1002/pip.3926 + """ + # Updated coefficients from EU JRC paper + huld_params = {'csi': (-0.017162, -0.040289, -0.004681, 0.000148, + 0.000169, 0.000005), + 'cis': (-0.005521, -0.038576, -0.003711, -0.000901, + -0.001251, 0.000001), + 'cdte': (-0.046477, -0.072509, -0.002252, 0.000275, + 0.000158, -0.000006)} + k = tuple([x*pdc0 for x in huld_params[cell_type.lower()]]) + return k + + +def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None, use_eu_jrc=False): r""" Power (DC) using the Huld model. @@ -274,6 +312,9 @@ def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None): cell_type : str, optional If provided, must be one of ``'cSi'``, ``'CIS'``, or ``'CdTe'``. Used to look up default values for ``k`` if ``k`` is not specified. + use_eu_jrc : bool, default False + If True, use the updated coefficients from the EU JRC paper [2]_. + Only used if ``k`` is not provided and ``cell_type`` is specified. Returns ------- @@ -332,10 +373,15 @@ def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None): E. Dunlop. A power-rating model for crystalline silicon PV modules. Solar Energy Materials and Solar Cells 95, (2011), pp. 3359-3369. :doi:`10.1016/j.solmat.2011.07.026`. + .. [2] EU JRC paper, "Updated coefficients for the Huld model", + https://doi.org/10.1002/pip.3926 """ if k is None: if cell_type is not None: - k = _infer_k_huld(cell_type, pdc0) + if use_eu_jrc: + k = _infer_k_huld_eu_jrc(cell_type, pdc0) + else: + k = _infer_k_huld(cell_type, pdc0) else: raise ValueError('Either k or cell_type must be specified') diff --git a/tests/test_pvarray.py b/tests/test_pvarray.py index 693ef78b2a..73c728de83 100644 --- a/tests/test_pvarray.py +++ b/tests/test_pvarray.py @@ -69,3 +69,29 @@ def test_huld(): with pytest.raises(ValueError, match='Either k or cell_type must be specified'): res = pvarray.huld(1000, 25, 100) + + +def test_huld_eu_jrc(): + """Test the EU JRC updated coefficients for the Huld model.""" + pdc0 = 100 + + # Test that EU JRC coefficients give different results than original + res_orig = pvarray.huld(1000, 25, pdc0, cell_type='cSi') + res_eu_jrc = pvarray.huld(1000, 25, pdc0, cell_type='cSi', use_eu_jrc=True) + assert not np.isclose(res_orig, res_eu_jrc) + + # Test that coefficients are properly scaled by pdc0 + k_orig = pvarray._infer_k_huld('cSi', pdc0) + k_eu_jrc = pvarray._infer_k_huld_eu_jrc('cSi', pdc0) + assert len(k_orig) == len(k_eu_jrc) == 6 + assert all(np.isclose(k1/pdc0, k2/pdc0) for k1, k2 in zip(k_orig, k_eu_jrc)) + + # Test that all cell types are supported + for cell_type in ['csi', 'cis', 'cdte']: + k = pvarray._infer_k_huld_eu_jrc(cell_type, pdc0) + assert len(k) == 6 + assert all(isinstance(x, float) for x in k) + + # Test invalid cell type + with pytest.raises(KeyError): + pvarray._infer_k_huld_eu_jrc('invalid', pdc0) From 928207e2eb064fd4479b511d1f93dfae4e440f4d Mon Sep 17 00:00:00 2001 From: Omar Bahamida Date: Sun, 15 Jun 2025 23:29:15 +0200 Subject: [PATCH 2/2] Refactor Huld model tests for EU JRC coefficients - Updated the test for the Huld model to use non-reference values for irradiance and temperature. - Enhanced the test to verify that results differ for all supported cell types when using EU JRC coefficients. - Added checks to ensure all cell types are supported and that a KeyError is raised for invalid cell types. (cherry picked from commit 7c0feba6935d2d45397afd06a7abacd481d83f32) --- tests/test_pvarray.py | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/tests/test_pvarray.py b/tests/test_pvarray.py index 73c728de83..cec40273b3 100644 --- a/tests/test_pvarray.py +++ b/tests/test_pvarray.py @@ -74,24 +74,18 @@ def test_huld(): def test_huld_eu_jrc(): """Test the EU JRC updated coefficients for the Huld model.""" pdc0 = 100 - - # Test that EU JRC coefficients give different results than original - res_orig = pvarray.huld(1000, 25, pdc0, cell_type='cSi') - res_eu_jrc = pvarray.huld(1000, 25, pdc0, cell_type='cSi', use_eu_jrc=True) - assert not np.isclose(res_orig, res_eu_jrc) - - # Test that coefficients are properly scaled by pdc0 - k_orig = pvarray._infer_k_huld('cSi', pdc0) - k_eu_jrc = pvarray._infer_k_huld_eu_jrc('cSi', pdc0) - assert len(k_orig) == len(k_eu_jrc) == 6 - assert all(np.isclose(k1/pdc0, k2/pdc0) for k1, k2 in zip(k_orig, k_eu_jrc)) - - # Test that all cell types are supported - for cell_type in ['csi', 'cis', 'cdte']: - k = pvarray._infer_k_huld_eu_jrc(cell_type, pdc0) - assert len(k) == 6 - assert all(isinstance(x, float) for x in k) - - # Test invalid cell type - with pytest.raises(KeyError): - pvarray._infer_k_huld_eu_jrc('invalid', pdc0) + # Use non-reference values so coefficients affect the result + eff_irr = 800 # W/m^2 (not 1000) + temp_mod = 35 # deg C (not 25) + # Test that EU JRC coefficients give different results than original for all cell types + for cell_type in ['cSi', 'CIS', 'CdTe']: + res_orig = pvarray.huld(eff_irr, temp_mod, pdc0, cell_type=cell_type) + res_eu_jrc = pvarray.huld(eff_irr, temp_mod, pdc0, cell_type=cell_type, use_eu_jrc=True) + assert not np.isclose(res_orig, res_eu_jrc), f"Results should differ for {cell_type}: {res_orig} vs {res_eu_jrc}" + # Also check that all cell types are supported and error is raised for invalid type + try: + pvarray.huld(eff_irr, temp_mod, pdc0, cell_type='invalid', use_eu_jrc=True) + except KeyError: + pass + else: + assert False, "Expected KeyError for invalid cell_type"