Skip to content

Commit a994fb7

Browse files
OmarBahamidacwhanseadriesseechedey-lskandersolar
authored
Add 2025 coefficients for Huld model (#2486)
* 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 f0ba338) * 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 7c0feba) * Fix Flake8 linter errors remove trailing whitespace and break long lines * Fix Flake8 errors: remove whitespace from blank lines and break long lines - Removed trailing whitespace from blank lines in pvlib/pvarray.py - Broke long lines in function definitions and assertions to comply with line length limits - Reformatted comments and code in tests/test_pvarray.py for Flake8 compliance * restructure lookup and test * fix test and formatting * adjust error message * add whatsnew * Apply suggestions from code review Co-authored-by: Anton Driesse <[email protected]> * Update pvlib/pvarray.py Co-authored-by: Echedey Luis <[email protected]> * Update pvlib/pvarray.py * Update pvlib/pvarray.py * correct coefficients for 2025 and references * fix docstring * change parameter key to pvgis5, etc. * error message * lint * fix test * Apply suggestions from code review --------- Co-authored-by: Cliff Hansen <[email protected]> Co-authored-by: Anton Driesse <[email protected]> Co-authored-by: Echedey Luis <[email protected]> Co-authored-by: Kevin Anderson <[email protected]>
1 parent 3e8bd1f commit a994fb7

File tree

3 files changed

+113
-20
lines changed

3 files changed

+113
-20
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Bug fixes
2121

2222
Enhancements
2323
~~~~~~~~~~~~
24+
* Add new parameters for the Huld PV array mode :py:func:`~pvlib.pvarray.huld` (:issue:`2461`, :pull:`2486`)
2425
* Add k coefficient in :py:func:`~pvlib.temperature.ross`
2526
(:issue:`2506`, :pull:`2521`)
2627
* Add iotools functions to retrieve irradiance and weather data from Meteonorm:
@@ -73,6 +74,9 @@ Maintenance
7374
Contributors
7475
~~~~~~~~~~~~
7576
* Elijah Passmore (:ghuser:`eljpsm`)
77+
* Omar Bahamida (:ghuser:`OmarBahamida`)
78+
* Cliff Hansen (:ghuser:`cwhanse`)
79+
7680
* Ioannis Sifnaios (:ghuser:`IoannisSifnaios`)
7781
* Rajiv Daxini (:ghuser:`RDaxini`)
7882
* Omar Bahamida (:ghuser:`OmarBahamida`)

pvlib/pvarray.py

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def pvefficiency_adr(effective_irradiance, temp_cell,
3737
the reference conditions. [unitless]
3838
3939
k_d : numeric, negative
40-
Dark irradiance or diode coefficient which influences the voltage
40+
"Dark irradiance" or diode coefficient which influences the voltage
4141
increase with irradiance. [unitless]
4242
4343
tc_d : numeric
@@ -225,24 +225,55 @@ def adr_wrapper(xdata, *params):
225225
return popt
226226

227227

228-
def _infer_k_huld(cell_type, pdc0):
228+
def _infer_k_huld(cell_type, pdc0, k_version):
229+
r"""
230+
Get the EU JRC updated coefficients for the Huld model.
231+
232+
Parameters
233+
----------
234+
cell_type : str
235+
Must be one of 'csi', 'cis', or 'cdte'
236+
pdc0 : numeric
237+
Power of the modules at reference conditions [W]
238+
k_version : str
239+
Either 'pvgis5' or 'pvgis6'.
240+
241+
Returns
242+
-------
243+
tuple
244+
The six coefficients (k1-k6) for the Huld model, scaled by pdc0
245+
"""
229246
# from PVGIS documentation, "PVGIS data sources & calculation methods",
230247
# Section 5.2.3, accessed 12/22/2023
231248
# The parameters in PVGIS' documentation are for a version of Huld's
232249
# equation that has factored Pdc0 out of the polynomial:
233250
# P = G/1000 * Pdc0 * (1 + k1 log(Geff) + ...) so these parameters are
234251
# multiplied by pdc0
235-
huld_params = {'csi': (-0.017237, -0.040465, -0.004702, 0.000149,
236-
0.000170, 0.000005),
237-
'cis': (-0.005554, -0.038724, -0.003723, -0.000905,
238-
-0.001256, 0.000001),
239-
'cdte': (-0.046689, -0.072844, -0.002262, 0.000276,
240-
0.000159, -0.000006)}
252+
if k_version.lower() == 'pvgis5':
253+
# coefficients from PVGIS webpage
254+
huld_params = {'csi': (-0.017237, -0.040465, -0.004702, 0.000149,
255+
0.000170, 0.000005),
256+
'cis': (-0.005554, -0.038724, -0.003723, -0.000905,
257+
-0.001256, 0.000001),
258+
'cdte': (-0.046689, -0.072844, -0.002262, 0.000276,
259+
0.000159, -0.000006)}
260+
elif k_version.lower() == 'pvgis6':
261+
# Coefficients from EU JRC paper
262+
huld_params = {'csi': (-0.0067560, -0.016444, -0.003015, -0.000045,
263+
-0.000043, 0.0),
264+
'cis': (-0.011001, -0.029734, -0.002887, 0.000217,
265+
-0.000163, 0.0),
266+
'cdte': (-0.020644, -0.035136, -0.003406, 0.000073,
267+
-0.000141, 0.000002)}
268+
else:
269+
raise ValueError(f'Invalid k_version={k_version}: must be either '
270+
'"pvgis5" or "pvgis6"')
241271
k = tuple([x*pdc0 for x in huld_params[cell_type.lower()]])
242272
return k
243273

244274

245-
def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None):
275+
def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None,
276+
k_version='pvgis5'):
246277
r"""
247278
Power (DC) using the Huld model.
248279
@@ -274,6 +305,11 @@ def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None):
274305
cell_type : str, optional
275306
If provided, must be one of ``'cSi'``, ``'CIS'``, or ``'CdTe'``.
276307
Used to look up default values for ``k`` if ``k`` is not specified.
308+
k_version : str, optional
309+
Either ``'pvgis5'`` (default) or ``'pvgis6'``. Selects values
310+
for ``k`` if ``k`` is not specified. If ``'pvgis5'``, values are
311+
from PVGIS documentation and are labeled in [2]_ as "current".
312+
If ``'pvgis6'`` values are from [2]_ labeled as "updated".
277313
278314
Returns
279315
-------
@@ -328,14 +364,19 @@ def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None):
328364
329365
References
330366
----------
331-
.. [1] T. Huld, G. Friesen, A. Skoczek, R. Kenny, T. Sample, M. Field,
332-
E. Dunlop. A power-rating model for crystalline silicon PV modules.
333-
Solar Energy Materials and Solar Cells 95, (2011), pp. 3359-3369.
334-
:doi:`10.1016/j.solmat.2011.07.026`.
367+
.. [1] T. Huld, G. Friesen, A. Skoczek, R. Kenny, T. Sample, M. Field, and
368+
E. Dunlop, "A power-rating model for crystalline silicon PV
369+
modules," Solar Energy Materials and Solar Cells 95, (2011),
370+
pp. 3359-3369. :doi:`10.1016/j.solmat.2011.07.026`.
371+
.. [2] A. Chatzipanagi, N. Taylor, I. Suarez, A. Martinez, T. Lyubenova,
372+
and E. Dunlop, "An Updated Simplified Energy Yield Model for Recent
373+
Photovoltaic Module Technologies,"
374+
Progress in Photovoltaics: Research and Applications 33,
375+
no. 8 (2025): 905–917, :doi:`10.1002/pip.3926`.
335376
"""
336377
if k is None:
337378
if cell_type is not None:
338-
k = _infer_k_huld(cell_type, pdc0)
379+
k = _infer_k_huld(cell_type, pdc0, k_version)
339380
else:
340381
raise ValueError('Either k or cell_type must be specified')
341382

@@ -346,7 +387,10 @@ def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None):
346387
logGprime = np.log(gprime, out=np.zeros_like(gprime),
347388
where=np.array(gprime > 0))
348389
# Eq. 1 in [1]
349-
pdc = gprime * (pdc0 + k[0] * logGprime + k[1] * logGprime**2 +
350-
k[2] * tprime + k[3] * tprime * logGprime +
351-
k[4] * tprime * logGprime**2 + k[5] * tprime**2)
390+
pdc = gprime * (
391+
pdc0 + k[0] * logGprime + k[1] * logGprime**2 +
392+
k[2] * tprime + k[3] * tprime * logGprime +
393+
k[4] * tprime * logGprime**2 +
394+
k[5] * tprime**2
395+
)
352396
return pdc

tests/test_pvarray.py

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ def test_pvefficiency_adr_round_trip():
5050

5151

5252
def test_huld():
53+
# tests with default k_version='pvgis5'
5354
pdc0 = 100
5455
res = pvarray.huld(1000, 25, pdc0, cell_type='cSi')
5556
assert np.isclose(res, pdc0)
56-
exp_sum = np.exp(1) * (np.sum(pvarray._infer_k_huld('cSi', pdc0)) + pdc0)
57+
k = pvarray._infer_k_huld('cSi', pdc0, 'pvgis5')
58+
exp_sum = np.exp(1) * (np.sum(k) + pdc0)
5759
res = pvarray.huld(1000*np.exp(1), 26, pdc0, cell_type='cSi')
5860
assert np.isclose(res, exp_sum)
5961
res = pvarray.huld(100, 30, pdc0, k=(1, 1, 1, 1, 1, 1))
@@ -67,5 +69,48 @@ def test_huld():
6769
res = pvarray.huld(eff_irr, tm, pdc0, k=(1, 1, 1, 1, 1, 1))
6870
assert_series_equal(res, expected)
6971
with pytest.raises(ValueError,
70-
match='Either k or cell_type must be specified'):
71-
res = pvarray.huld(1000, 25, 100)
72+
match='Either k or cell_type must be specified'
73+
):
74+
pvarray.huld(1000, 25, 100)
75+
76+
77+
def test_huld_params():
78+
"""Test Huld with built-in coefficients."""
79+
pdc0 = 100
80+
# Use non-reference values so coefficients affect the result
81+
eff_irr = 800 # W/m^2 (not 1000)
82+
temp_mod = 35 # deg C (not 25)
83+
# calculated by C. Hansen using Excel, 2025
84+
expected = {'pvgis5': {'csi': 76.405089,
85+
'cis': 77.086016,
86+
'cdte': 78.642762
87+
},
88+
'pvgis6': {'csi': 77.649421,
89+
'cis': 77.723110,
90+
'cdte': 77.500399
91+
}
92+
}
93+
# Test with PVGIS5 coefficients for all cell types
94+
for yr in expected:
95+
for cell_type in expected[yr]:
96+
result = pvarray.huld(eff_irr, temp_mod, pdc0, cell_type=cell_type,
97+
k_version=yr)
98+
assert np.isclose(result, expected[yr][cell_type])
99+
100+
101+
def test_huld_errors():
102+
# Check errors
103+
pdc0 = 100
104+
# Use non-reference values so coefficients affect the result
105+
eff_irr = 800 # W/m^2 (not 1000)
106+
temp_mod = 35 # deg C (not 25)
107+
# provide both cell_type and k_version
108+
with pytest.raises(KeyError):
109+
pvarray.huld(
110+
eff_irr, temp_mod, pdc0, cell_type='invalid', k_version='pvgis5'
111+
)
112+
# provide invalid k_version
113+
with pytest.raises(ValueError, match='Invalid k_version=2021'):
114+
pvarray.huld(
115+
eff_irr, temp_mod, pdc0, cell_type='csi', k_version='2021'
116+
)

0 commit comments

Comments
 (0)