Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/sphinx/source/reference/pv_modeling/system_models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,4 @@ PVGIS model
:toctree: ../generated/

pvarray.huld
pvarray.fit_huld
1 change: 1 addition & 0 deletions docs/sphinx/source/whatsnew/v0.10.4.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ v0.10.4 (March 19, 2024)
Enhancements
~~~~~~~~~~~~
* Added the Huld PV model used by PVGIS (:pull:`1940`)
* Added a method to fit the Huld PV model (:pull:`1979`)
* Add :py:func:`~pvlib.iotools.get_solargis` for retrieving Solargis
irradiance data. (:pull:`1969`)
* Added function :py:func:`pvlib.shading.projected_solar_zenith_angle`,
Expand Down
67 changes: 66 additions & 1 deletion pvlib/pvarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None):
Power of the modules at reference conditions 1000 :math:`W/m^2`
and :math:`25^{\circ}C`. [W]
k : tuple, optional
Empirical coefficients used in the power model. Length 6. If ``k`` is
Empirical coefficients used in the Huld model. Length 6. If ``k`` is
not provided, ``cell_type`` must be specified.
cell_type : str, optional
If provided, must be one of ``'cSi'``, ``'CIS'``, or ``'CdTe'``.
Expand Down Expand Up @@ -348,3 +348,68 @@ def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None):
k[2] * tprime + k[3] * tprime * logGprime +
k[4] * tprime * logGprime**2 + k[5] * tprime**2)
return pdc


def _build_iec61853():
ee = np.array([100, 100, 200, 200, 400, 400, 400, 600, 600, 600, 600,
800, 800, 800, 800, 1000, 1000, 1000, 1000, 1100, 1100,
1100]).T
tc = np.array([15, 25, 15, 25, 15, 25, 50, 15, 25, 50, 75,
15, 25, 50, 75, 15, 25, 50, 75, 25, 50, 75]).T
return ee, tc


def fit_huld(effective_irradiance, temp_mod, pdc):
r'''
Fit the Huld model to the input data.

Parameters
----------
effective_irradiance : numeric
The irradiance that is converted to photocurrent. [:math:`W/m^2`]
temp_mod: numeric
Module back-surface temperature. [C]
pdc: numeric
DC power at ``effectuve_irradiance`` and ``temp_mod``. [W]

Returns
-------
pdc0: numeric
Power of the modules at reference conditions 1000 :math:`W/m^2`
and :math:`25^{\circ}C`. [W]
k : tuple
Empirical coefficients used in the Huld model. Length 6.

Notes
-----
Requires ``statsmodels``.

See Also
--------
pvlib.pvarray.huld
'''

try:
import statsmodels.api as sm
except ImportError:
raise ImportError(
'fit_huld requires statsmodels')

gprime = effective_irradiance / 1000
tprime = temp_mod - 25
# accomodate gprime<=0
with np.errstate(divide='ignore'):
logGprime = np.log(gprime, out=np.zeros_like(gprime),
where=np.array(gprime > 0))
Y = np.divide(pdc, gprime, out=np.zeros_like(gprime),
where=np.array(gprime > 0))

X = np.stack((logGprime, logGprime**2, tprime, tprime*logGprime,
tprime*logGprime**2, tprime**2), axis=0).T
X = sm.add_constant(X)

rlm_model = sm.RLM(Y, X)
rlm_result = rlm_model.fit()
pdc0 = rlm_result.params[0]
k = rlm_result.params[1:]
return pdc0, k
18 changes: 17 additions & 1 deletion pvlib/tests/test_pvarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from numpy.testing import assert_allclose
from .conftest import assert_series_equal
import pytest

from pvlib.tests.conftest import requires_statsmodels
from pvlib import pvarray


Expand Down Expand Up @@ -69,3 +69,19 @@ def test_huld():
with pytest.raises(ValueError,
match='Either k or cell_type must be specified'):
res = pvarray.huld(1000, 25, 100)


@requires_statsmodels
def test_fit_huld():
# test is to recover the parameters in _infer_huld_k for each cell type
# IEC61853 conditions to make data for fitting
ee, tc = pvarray._build_iec61853()
techs = ['csi', 'cis', 'cdte']
pdc0 = 250
for tech in techs:
k0 = pvarray._infer_k_huld(tech, pdc0)
pdc = pvarray.huld(ee, tc, pdc0, cell_type=tech)
m_pdc0, k = pvarray.fit_huld(ee, tc, pdc)
expected = np.array([pdc0, ] + [v for v in k0], dtype=float)
modeled = np.hstack((m_pdc0, k))
assert_allclose(expected, modeled, rtol=1e-8)