-
Notifications
You must be signed in to change notification settings - Fork 1.1k
ENH: implementing pvsyst recombination loss current for CdTe and a:Si #504
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
4b0df1b
2bd8b13
1650bc6
9d96585
f5d6dda
a62759e
bfa9c5f
79fde5b
1e9434a
3d0deb2
8a1efcb
21157e2
adde5bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,8 @@ | |
# rename newton and set keyword arguments | ||
newton = partial(_array_newton, tol=1e-6, maxiter=100, fprime2=None) | ||
|
||
VOLTAGE_BUILTIN = 0.9 # (V) intrinsic voltage for a:Si, CdTe, Mertens et al. | ||
|
||
|
||
def estimate_voc(photocurrent, saturation_current, nNsVth): | ||
""" | ||
|
@@ -62,7 +64,9 @@ def estimate_voc(photocurrent, saturation_current, nNsVth): | |
|
||
|
||
def bishop88(diode_voltage, photocurrent, saturation_current, | ||
resistance_series, resistance_shunt, nNsVth, gradients=False): | ||
resistance_series, resistance_shunt, nNsVth, cells_in_series=None, | ||
d2mutau=0, voltage_builtin=VOLTAGE_BUILTIN, | ||
gradients=False): | ||
""" | ||
Explicit calculation of points on the IV curve described by the single | ||
diode equation [1]. | ||
|
@@ -97,21 +101,31 @@ def bishop88(diode_voltage, photocurrent, saturation_current, | |
:math:`\\frac{dI}{dV}`, :math:`\\frac{dP}{dV}`, and | ||
:math:`\\frac{d^2 P}{dV dV_d}` | ||
""" | ||
# check if need to calculate recombination loss current | ||
i_recomb, v_recomb = 0, np.inf | ||
if d2mutau > 0: | ||
v_recomb = voltage_builtin * cells_in_series - diode_voltage | ||
i_recomb = photocurrent * d2mutau / v_recomb | ||
|
||
# calculate temporary values to simplify calculations | ||
v_star = diode_voltage / nNsVth # non-dimensional diode voltage | ||
g_sh = 1.0 / resistance_shunt # conductance | ||
i = (photocurrent - saturation_current * np.expm1(v_star) | ||
- diode_voltage * g_sh) | ||
- diode_voltage * g_sh - i_recomb) | ||
v = diode_voltage - i * resistance_series | ||
retval = (i, v, i*v) | ||
if gradients: | ||
# check again if need to calculate recombination loss current gradients | ||
grad_i_recomb = grad_2i_recomb = 0 | ||
|
||
if d2mutau > 0: | ||
grad_i_recomb = i_recomb / v_recomb | ||
grad_2i_recomb = 2 * grad_i_recomb / v_recomb | ||
|
||
g_diode = saturation_current * np.exp(v_star) / nNsVth # conductance | ||
grad_i = -g_diode - g_sh # di/dvd | ||
grad_i = -g_diode - g_sh - grad_i_recomb # di/dvd | ||
grad_v = 1.0 - grad_i * resistance_series # dv/dvd | ||
# dp/dv = d(iv)/dv = v * di/dv + i | ||
grad = grad_i / grad_v # di/dv | ||
grad_p = v * grad + i # dp/dv | ||
grad2i = -g_diode / nNsVth # d2i/dvd | ||
grad2i = -g_diode / nNsVth - grad_2i_recomb # d2i/dvd | ||
grad2v = -grad2i * resistance_series # d2v/dvd | ||
grad2p = ( | ||
grad_v * grad + v * (grad2i/grad_v - grad_i*grad2v/grad_v**2) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,8 @@ | |
|
||
import numpy as np | ||
from pvlib import pvsystem | ||
from pvlib.singlediode_methods import bishop88, estimate_voc | ||
import pytest | ||
from conftest import requires_scipy | ||
|
||
POA = 888 | ||
|
@@ -100,7 +102,7 @@ def test_brentq_spr_e20_327(): | |
|
||
@requires_scipy | ||
def test_brentq_fs_495(): | ||
"""test pvsystem.singlediode with Brent method on SPR-E20-327""" | ||
"""test pvsystem.singlediode with Brent method on FS495""" | ||
fs_495 = CECMOD.First_Solar_FS_495 | ||
x = pvsystem.calcparams_desoto( | ||
effective_irradiance=POA, temp_cell=TCELL, | ||
|
@@ -125,3 +127,66 @@ def test_brentq_fs_495(): | |
method='lambertw') | ||
assert np.isclose(pvs_ixx, ixx) | ||
return isc, voc, imp, vmp, pmp, i, v, pvs | ||
|
||
|
||
# PVsyst parameters for First Solar FS-495 module from PVSyst-6.7.2 database | ||
# I_L_ref derived from Isc_ref conditions: | ||
# I_L_ref = (I_sc_ref + Id + Ish) / (1 - d2mutau/(Vbi*N_s - Vd)) | ||
# where | ||
# Vd = I_sc_ref * R_s | ||
# Id = I_o_ref * (exp(Vd / nNsVt) - 1) | ||
# Ish = Vd / R_sh_ref | ||
PVSYST_FS_495 = { | ||
|
||
'd2mutau': 1.31, 'alpha_sc': 0.00039, 'gamma_ref': 1.48, 'mu_gamma': 0.001, | ||
'I_o_ref': 9.62e-10, 'R_sh_ref': 5000, 'R_sh_0': 12500, 'R_sh_exp': 3.1, | ||
'R_s': 4.6, 'beta_oc': -0.2116, 'EgRef': 1.5, 'cells_in_series': 108, | ||
'cells_in_parallel': 2, 'I_sc_ref': 1.55, 'V_oc_ref': 86.5, | ||
'I_mp_ref': 1.4, 'V_mp_ref': 67.85, 'temp_ref': 25, 'irrad_ref': 1000, | ||
'I_L_ref': 1.5743233463848496 | ||
} | ||
|
||
|
||
@pytest.mark.parametrize( | ||
'poa, temp_cell, expected, tol', | ||
[(PVSYST_FS_495['irrad_ref'], PVSYST_FS_495['temp_ref'], | ||
{'pmp': PVSYST_FS_495['I_mp_ref']*PVSYST_FS_495['V_mp_ref'], | ||
'isc': PVSYST_FS_495['I_sc_ref'], 'voc': PVSYST_FS_495['V_oc_ref']}, | ||
|
||
(5e-4, 0.04)), | ||
(POA, TCELL, {'pmp': 76.26, 'isc': 1.387, 'voc': 79.29}, (1e-3, 1e-3))] | ||
) # DeSoto @(888[W/m**2], 55[degC]) = {Pmp: 72.71, Isc: 1.402, Voc: 75.42) | ||
def test_pvsyst_recombination_loss(poa, temp_cell, expected, tol): | ||
|
||
"""test PVSst recombination loss""" | ||
# first evaluate PVSyst model with thin-film recombination loss current | ||
# at reference conditions | ||
pvsyst_fs_495 = PVSYST_FS_495 | ||
x = pvsystem.calcparams_pvsyst( | ||
effective_irradiance=poa, temp_cell=temp_cell, | ||
alpha_sc=pvsyst_fs_495['alpha_sc'], | ||
gamma_ref=pvsyst_fs_495['gamma_ref'], | ||
mu_gamma=pvsyst_fs_495['mu_gamma'], I_L_ref=pvsyst_fs_495['I_L_ref'], | ||
I_o_ref=pvsyst_fs_495['I_o_ref'], R_sh_ref=pvsyst_fs_495['R_sh_ref'], | ||
R_sh_0=pvsyst_fs_495['R_sh_0'], R_sh_exp=pvsyst_fs_495['R_sh_exp'], | ||
R_s=pvsyst_fs_495['R_s'], | ||
cells_in_series=pvsyst_fs_495['cells_in_series'], | ||
EgRef=pvsyst_fs_495['EgRef'] | ||
) | ||
il_pvsyst, io_pvsyst, rs_pvsyst, rsh_pvsyst, nnsvt_pvsyst = x | ||
voc_est_pvsyst = estimate_voc(photocurrent=il_pvsyst, | ||
saturation_current=io_pvsyst, | ||
nNsVth=nnsvt_pvsyst) | ||
vd_pvsyst = np.linspace(0, voc_est_pvsyst, 1000) | ||
pvsyst = bishop88( | ||
diode_voltage=vd_pvsyst, photocurrent=il_pvsyst, | ||
saturation_current=io_pvsyst, resistance_series=rs_pvsyst, | ||
resistance_shunt=rsh_pvsyst, nNsVth=nnsvt_pvsyst, | ||
d2mutau=pvsyst_fs_495['d2mutau'], | ||
cells_in_series=pvsyst_fs_495['cells_in_series'] | ||
) | ||
# test max power | ||
assert np.isclose(max(pvsyst[2]), expected['pmp'], *tol) | ||
# test short circuit current | ||
isc_pvsyst = np.interp(0, pvsyst[1], pvsyst[0]) | ||
assert np.isclose(isc_pvsyst, expected['isc'], *tol) | ||
# test open circuit current | ||
voc_pvsyst = np.interp(0, pvsyst[0][::-1], pvsyst[1][::-1]) | ||
assert np.isclose(voc_pvsyst, expected['voc'], *tol) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
d2mutau : numeric
implies that it can be an array (see here). Thisif
statement will error ifd2mutau
is an array. Perhaps the docstring should be changed toscalar
?