Skip to content

Commit 3269dc7

Browse files
authored
Function to calculate temperature coefficient of power for pvsyst (pvlib#1190)
* initial implementation of function to calculate pvsyst temperature coefficient * add reference * add test for pvsyst_tempco * correct test reference * api, whatsnews * add to whatsnew * change to 1/C, edit test * fix bad merge * change from W/C to 1/C
1 parent 2a1ed55 commit 3269dc7

File tree

4 files changed

+124
-9
lines changed

4 files changed

+124
-9
lines changed

docs/sphinx/source/api.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ Functions relevant for single diode models.
268268
pvsystem.singlediode
269269
pvsystem.v_from_i
270270
pvsystem.max_power_point
271+
ivtools.sdm.pvsyst_temperature_coeff
271272

272273
Low-level functions for solving the single diode equation.
273274

@@ -334,6 +335,7 @@ Pvsyst model
334335
temperature.pvsyst_cell
335336
pvsystem.calcparams_pvsyst
336337
pvsystem.singlediode
338+
ivtools.sdm.pvsyst_temperature_coeff
337339
pvsystem.dc_ohms_from_percent
338340
pvsystem.dc_ohmic_losses
339341

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,10 @@ Enhancements
102102
from DC power. Use parameter ``model`` to specify which inverter model to use.
103103
(:pull:`1147`, :issue:`998`, :pull:`1150`)
104104
* Added :py:func:`~pvlib.temperature.noct_sam`, a cell temperature model
105-
implemented in SAM (:pull:`1177`, :pull:`1195`)
105+
implemented in SAM. (:pull:`1177`, :pull:`1195`)
106+
* Added :py:func:`~pvlib.ivtools.sdm.pvsyst_temperature_coeff` to calculate
107+
the temperature coefficient of power for the pvsyst module model.
108+
(:pull:`1190`)
106109

107110
Bug fixes
108111
~~~~~~~~~

pvlib/ivtools/sdm.py

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
import scipy.constants
1212
from scipy import optimize
1313
from scipy.special import lambertw
14+
from scipy.misc import derivative
1415

15-
from pvlib.pvsystem import singlediode, v_from_i
16+
from pvlib.pvsystem import calcparams_pvsyst, singlediode, v_from_i
17+
from pvlib.singlediode import bishop88_mpp
1618

1719
from pvlib.ivtools.utils import rectify_iv_curve, _numdiff
1820
from pvlib.ivtools.sde import _fit_sandia_cocontent
@@ -1252,3 +1254,91 @@ def _calc_theta_phi_exact(vmp, imp, iph, io, rs, rsh, nnsvth):
12521254
theta = np.transpose(theta)
12531255

12541256
return theta, phi
1257+
1258+
1259+
def pvsyst_temperature_coeff(alpha_sc, gamma_ref, mu_gamma, I_L_ref, I_o_ref,
1260+
R_sh_ref, R_sh_0, R_s, cells_in_series,
1261+
R_sh_exp=5.5, EgRef=1.121, irrad_ref=1000,
1262+
temp_ref=25):
1263+
r"""
1264+
Calculates the temperature coefficient of power for a pvsyst single
1265+
diode model.
1266+
1267+
The temperature coefficient is determined as the numerical derivative
1268+
:math:`\frac{dP}{dT}` at the maximum power point at reference conditions
1269+
[1]_.
1270+
1271+
Parameters
1272+
----------
1273+
alpha_sc : float
1274+
The short-circuit current temperature coefficient of the module. [A/C]
1275+
1276+
gamma_ref : float
1277+
The diode ideality factor. [unitless]
1278+
1279+
mu_gamma : float
1280+
The temperature coefficient for the diode ideality factor. [1/K]
1281+
1282+
I_L_ref : float
1283+
The light-generated current (or photocurrent) at reference conditions.
1284+
[A]
1285+
1286+
I_o_ref : float
1287+
The dark or diode reverse saturation current at reference conditions.
1288+
[A]
1289+
1290+
R_sh_ref : float
1291+
The shunt resistance at reference conditions. [ohm]
1292+
1293+
R_sh_0 : float
1294+
The shunt resistance at zero irradiance conditions. [ohm]
1295+
1296+
R_s : float
1297+
The series resistance at reference conditions. [ohm]
1298+
1299+
cells_in_series : int
1300+
The number of cells connected in series.
1301+
1302+
R_sh_exp : float, default 5.5
1303+
The exponent in the equation for shunt resistance. [unitless]
1304+
1305+
EgRef : float, default 1.121
1306+
The energy bandgap of the module's cells at reference temperature.
1307+
Default of 1.121 eV is for crystalline silicon. Must be positive. [eV]
1308+
1309+
irrad_ref : float, default 1000
1310+
Reference irradiance. [W/m^2].
1311+
1312+
temp_ref : float, default 25
1313+
Reference cell temperature. [C]
1314+
1315+
1316+
Returns
1317+
-------
1318+
gamma_pdc : float
1319+
Temperature coefficient of power at maximum power point at reference
1320+
conditions. [1/C]
1321+
1322+
References
1323+
----------
1324+
.. [1] K. Sauer, T. Roessler, C. W. Hansen, Modeling the Irradiance and
1325+
Temperature Dependence of Photovoltaic Modules in PVsyst, IEEE Journal
1326+
of Photovoltaics v5(1), January 2015.
1327+
"""
1328+
1329+
def maxp(temp_cell, irrad_ref, alpha_sc, gamma_ref, mu_gamma, I_L_ref,
1330+
I_o_ref, R_sh_ref, R_sh_0, R_s, cells_in_series, R_sh_exp, EgRef,
1331+
temp_ref):
1332+
params = calcparams_pvsyst(
1333+
irrad_ref, temp_cell, alpha_sc, gamma_ref, mu_gamma, I_L_ref,
1334+
I_o_ref, R_sh_ref, R_sh_0, R_s, cells_in_series, R_sh_exp, EgRef,
1335+
irrad_ref, temp_ref)
1336+
res = bishop88_mpp(*params)
1337+
return res[2]
1338+
1339+
args = (irrad_ref, alpha_sc, gamma_ref, mu_gamma, I_L_ref,
1340+
I_o_ref, R_sh_ref, R_sh_0, R_s, cells_in_series, R_sh_exp, EgRef,
1341+
temp_ref)
1342+
pmp = maxp(temp_ref, *args)
1343+
gamma_pdc = derivative(maxp, temp_ref, args=args)
1344+
return gamma_pdc / pmp

pvlib/tests/ivtools/test_sdm.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import pandas as pd
33

44
import pytest
5+
from numpy.testing import assert_allclose
56

67
from pvlib.ivtools import sdm
78
from pvlib import pvsystem
@@ -306,7 +307,7 @@ def test__update_rsh_fixed_pt_nans(vmp, imp, iph, io, rs, rsh, nnsvth,
306307
def test__update_rsh_fixed_pt_vmp0():
307308
outrsh = sdm._update_rsh_fixed_pt(vmp=0., imp=2., iph=2., io=2., rs=2.,
308309
rsh=2., nnsvth=2.)
309-
np.testing.assert_allclose(outrsh, np.array([502.]), atol=.0001)
310+
assert_allclose(outrsh, np.array([502.]), atol=.0001)
310311

311312

312313
def test__update_rsh_fixed_pt_vector():
@@ -318,7 +319,7 @@ def test__update_rsh_fixed_pt_vector():
318319
imp=np.array([.2, .2, -1., 2.]),
319320
vmp=np.array([0., -1, 0., 0.]))
320321
assert np.all(np.isnan(outrsh[0:3]))
321-
np.testing.assert_allclose(outrsh[3], np.array([502.]), atol=.0001)
322+
assert_allclose(outrsh[3], np.array([502.]), atol=.0001)
322323

323324

324325
@pytest.mark.parametrize('voc, iph, io, rs, rsh, nnsvth, expected', [
@@ -329,7 +330,7 @@ def test__update_rsh_fixed_pt_vector():
329330
(0., 2., 2., 2., 2., 2., 17.9436)])
330331
def test__update_io(voc, iph, io, rs, rsh, nnsvth, expected):
331332
outio = sdm._update_io(voc, iph, io, rs, rsh, nnsvth)
332-
np.testing.assert_allclose(outio, expected, atol=.0001)
333+
assert_allclose(outio, expected, atol=.0001)
333334

334335

335336
@pytest.mark.parametrize('voc, iph, io, rs, rsh, nnsvth', [
@@ -347,8 +348,8 @@ def test__update_io_nan(voc, iph, io, rs, rsh, nnsvth):
347348
(0., 2., 2., 2., 2., 2., 2., (1.5571, 2.))])
348349
def test__calc_theta_phi_exact(vmp, imp, iph, io, rs, rsh, nnsvth, expected):
349350
theta, phi = sdm._calc_theta_phi_exact(vmp, imp, iph, io, rs, rsh, nnsvth)
350-
np.testing.assert_allclose(theta, expected[0], atol=.0001)
351-
np.testing.assert_allclose(phi, expected[1], atol=.0001)
351+
assert_allclose(theta, expected[0], atol=.0001)
352+
assert_allclose(phi, expected[1], atol=.0001)
352353

353354

354355
@pytest.mark.parametrize('vmp, imp, iph, io, rs, rsh, nnsvth', [
@@ -365,7 +366,7 @@ def test__calc_theta_phi_exact_one_nan():
365366
theta, phi = sdm._calc_theta_phi_exact(imp=2., iph=2., vmp=2., io=2.,
366367
nnsvth=2., rs=0., rsh=2.)
367368
assert np.isnan(theta)
368-
np.testing.assert_allclose(phi, 2., atol=.0001)
369+
assert_allclose(phi, 2., atol=.0001)
369370

370371

371372
def test__calc_theta_phi_exact_vector():
@@ -379,4 +380,23 @@ def test__calc_theta_phi_exact_vector():
379380
assert np.isnan(theta[0])
380381
assert np.isnan(theta[1])
381382
assert np.isnan(phi[0])
382-
np.testing.assert_allclose(phi[1], 2.2079, atol=.0001)
383+
assert_allclose(phi[1], 2.2079, atol=.0001)
384+
385+
386+
def test_pvsyst_temperature_coeff():
387+
# test for consistency with dP/dT estimated with secant rule
388+
params = {'alpha_sc': 0., 'gamma_ref': 1.1, 'mu_gamma': 0.,
389+
'I_L_ref': 6., 'I_o_ref': 5.e-9, 'R_sh_ref': 200.,
390+
'R_sh_0': 2000., 'R_s': 0.5, 'cells_in_series': 60}
391+
expected = -0.004886706494879083
392+
# params defines a Pvsyst model for a notional module.
393+
# expected value is created by calculating power at 1000 W/m2, and cell
394+
# temperature of 24 and 26C, using pvsystem.calcparams_pvsyst and
395+
# pvsystem.singlediode. The derivative (value for expected) is estimated
396+
# as the slope (p_mp at 26C - p_mp at 24C) / 2
397+
# using the secant rule for derivatives.
398+
gamma_pdc = sdm.pvsyst_temperature_coeff(
399+
params['alpha_sc'], params['gamma_ref'], params['mu_gamma'],
400+
params['I_L_ref'], params['I_o_ref'], params['R_sh_ref'],
401+
params['R_sh_0'], params['R_s'], params['cells_in_series'])
402+
assert_allclose(gamma_pdc, expected, rtol=0.0005)

0 commit comments

Comments
 (0)