Skip to content

Commit 2a436c6

Browse files
mikofskiwholmgren
authored andcommitted
ENH: implementing pvsyst recombination loss current for CdTe and a:Si (#504)
* implementing pvsyst recombination loss current for CdTe and a:Si * closes #163 * add constant VOLTAGE_BUILTIN = 0.9 (V) to singlediode_methods.py * add arguments d2mutau=0, voltage_builtin=VOLTAGE_BUILTIN, and cells_in_series to calculate i_recomb and v_recomb * add check for d2mutau to calc i_recomb, v_recomb, and gradients * add terms to current and gradients * ENH: need to set grad_i_recomb if d2mutau not given * also set v_recomb to Inf, so that 1/v_recomb is always zero * but precalculate grad_2i_recomb only if d2mutau > 0, otherwise, use zero * ENH: fix need to multiply vbi by Ns, add test for recombination * WIP: ENH: TST: BUG: in test compare desoto vs. pvsyst * ENH: respond to comments * change order of bishop88 args: cells_in_series to be first before d2mutau and voltage_builtin * hardcode PVSYST_FS495 coefficients * don't compare pvsyst to desoto, instead compare pvsyst to fixed values at two conditions: reference and 888[W/m^2],55[degC] * rename test to be agnostic to module SKU * remove testing script if __name__ == '__main__': section, not for release * DOC: ENH: update bishop88 documentation for pvsyst thin-film recombination loss * DOC: ENH: update what's new * DOC: add utf-8 file encoding * DOC: ENH: BUG: minor doc fixes and formatting * need to indent bullets in warning * only need cells in series for PVSyst thin-film recombination loss * escape math latex twice inside docstrings without raw prefix, eg: \\tau without extra escape is a tab character, ha ha ha * in rst, italics is a single asterisk, not underscore, thats markdown * ENH: improve code style, fix d2mutau is array * expand module type abbrev. in warnings * also expand EG to For example, too terse * cells in series can be int _or_ `None` * since d2mutau and vbi are arrays, then ambiguous to test for zero, so use np.where to assign conditionally instead (in two places) * ENH: TST: use fixture instead of module-level dictionary for test * dangerous to use module-level dictionary inside test, b/c dictionary values could be changed inadvertently, but not a fixture * add fixture as argument in test * change parametrize to call fixture instead of module-level dictionary * ENH: replace voltage_builtin with NsVbi and remove cells_in_series * related to #516, the use of cells_in_series here is problematic * to calculate arrays of different cells or modules with different parameters we use np.where(is_recomb, ..., ...) 3d0deb2 but what should cells_in_series be if d2mutau is zero? doesn't make physical sense for it to be zero, but None doesn't work with numbers * remove cells_in_series arg from bishop88 * remove last warning about setting cells_in_series correctly, move it to Notes, but worded differently in the context of setting NsVbi * replace voltage_builtin with NsVbi, default to np.inf * fix docstring parameter descriptions
1 parent f57f4c6 commit 2a436c6

File tree

3 files changed

+132
-9
lines changed

3 files changed

+132
-9
lines changed

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

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Enhancements
5858
:func:`~pvlib.singlediode_methods.bishop88_i_from_v`,
5959
:func:`~pvlib.singlediode_methods.bishop88_v_from_i`, and
6060
:func:`~pvlib.singlediode_methods.bishop88_mpp`.
61+
* Add PVSyst thin-film recombination losses for CdTe and a:Si (:issue:`163`)
6162
* Python 3.7 officially supported. (:issue:`496`)
6263

6364

pvlib/singlediode_methods.py

+56-8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- coding: utf-8 -*-
12
"""
23
Low-level functions for solving the single diode equation.
34
"""
@@ -22,6 +23,9 @@
2223
# rename newton and set keyword arguments
2324
newton = partial(_array_newton, tol=1e-6, maxiter=100, fprime2=None)
2425

26+
# intrinsic voltage per cell junction for a:Si, CdTe, Mertens et al.
27+
VOLTAGE_BUILTIN = 0.9 # [V]
28+
2529

2630
def estimate_voc(photocurrent, saturation_current, nNsVth):
2731
"""
@@ -62,14 +66,16 @@ def estimate_voc(photocurrent, saturation_current, nNsVth):
6266

6367

6468
def bishop88(diode_voltage, photocurrent, saturation_current,
65-
resistance_series, resistance_shunt, nNsVth, gradients=False):
69+
resistance_series, resistance_shunt, nNsVth, d2mutau=0,
70+
NsVbi=np.Inf, gradients=False):
6671
"""
6772
Explicit calculation of points on the IV curve described by the single
68-
diode equation [1].
73+
diode equation [1]_.
6974
70-
[1] "Computer simulation of the effects of electrical mismatches in
71-
photovoltaic cell interconnection circuits" JW Bishop, Solar Cell (1988)
72-
https://doi.org/10.1016/0379-6787(88)90059-2
75+
.. warning::
76+
* Do not use ``d2mutau`` with CEC coefficients.
77+
* Usage of ``d2mutau`` with PVSyst coefficients is required for cadmium-
78+
telluride (CdTe) and amorphous-silicon (a:Si) PV modules only.
7379
7480
Parameters
7581
----------
@@ -86,6 +92,14 @@ def bishop88(diode_voltage, photocurrent, saturation_current,
8692
nNsVth : numeric
8793
product of thermal voltage ``Vth`` [V], diode ideality factor ``n``,
8894
and number of series cells ``Ns``
95+
d2mutau : numeric
96+
PVSyst thin-film recombination parameter that is the ratio of thickness
97+
of the intrinsic layer squared :math:`d^2` and the diffusion length of
98+
charge carriers :math:`\\mu \\tau`, in volts [V], defaults to 0[V]
99+
NsVbi : numeric
100+
PVSyst thin-film recombination parameter that is the product of the PV
101+
module number of series cells ``Ns`` and the builtin voltage ``Vbi`` of
102+
the intrinsic layer, in volts [V], defaults to ``np.inf``
89103
gradients : bool
90104
False returns only I, V, and P. True also returns gradients
91105
@@ -96,22 +110,56 @@ def bishop88(diode_voltage, photocurrent, saturation_current,
96110
:math:`\\frac{dI}{dV_d}`, :math:`\\frac{dV}{dV_d}`,
97111
:math:`\\frac{dI}{dV}`, :math:`\\frac{dP}{dV}`, and
98112
:math:`\\frac{d^2 P}{dV dV_d}`
113+
114+
Notes
115+
-----
116+
The PVSyst thin-film recombination losses parameters ``d2mutau`` and
117+
``NsVbi`` are only applied to cadmium-telluride (CdTe) and amorphous-
118+
silicon (a:Si) PV modules, [2]_, [3]_. The builtin voltage :math:`V_{bi}`
119+
should account for all junctions. For example: tandem and triple junction
120+
cells would have builtin voltages of 1.8[V] and 2.7[V] respectively, based
121+
on the default of 0.9[V] for a single junction. The parameter ``NsVbi``
122+
should only account for the number of series cells in a single parallel
123+
sub-string if the module has cells in parallel greater than 1.
124+
125+
References
126+
----------
127+
.. [1] "Computer simulation of the effects of electrical mismatches in
128+
photovoltaic cell interconnection circuits" JW Bishop, Solar Cell (1988)
129+
:doi:`10.1016/0379-6787(88)90059-2`
130+
131+
.. [2] "Improved equivalent circuit and Analytical Model for Amorphous
132+
Silicon Solar Cells and Modules." J. Mertens, et al., IEEE Transactions
133+
on Electron Devices, Vol 45, No 2, Feb 1998.
134+
:doi:`10.1109/16.658676`
135+
136+
.. [3] "Performance assessment of a simulation model for PV modules of any
137+
available technology", André Mermoud and Thibault Lejeune, 25th EUPVSEC,
138+
2010
139+
:doi:`10.4229/25thEUPVSEC2010-4BV.1.114`
99140
"""
141+
# calculate recombination loss current where d2mutau > 0
142+
is_recomb = d2mutau > 0 # True where there is thin-film recombination loss
143+
v_recomb = np.where(is_recomb, NsVbi - diode_voltage, np.inf)
144+
i_recomb = np.where(is_recomb, photocurrent * d2mutau / v_recomb, 0)
100145
# calculate temporary values to simplify calculations
101146
v_star = diode_voltage / nNsVth # non-dimensional diode voltage
102147
g_sh = 1.0 / resistance_shunt # conductance
103148
i = (photocurrent - saturation_current * np.expm1(v_star)
104-
- diode_voltage * g_sh)
149+
- diode_voltage * g_sh - i_recomb)
105150
v = diode_voltage - i * resistance_series
106151
retval = (i, v, i*v)
107152
if gradients:
153+
# calculate recombination loss current gradients where d2mutau > 0
154+
grad_i_recomb = np.where(is_recomb, i_recomb / v_recomb, 0)
155+
grad_2i_recomb = np.where(is_recomb, 2 * grad_i_recomb / v_recomb, 0)
108156
g_diode = saturation_current * np.exp(v_star) / nNsVth # conductance
109-
grad_i = -g_diode - g_sh # di/dvd
157+
grad_i = -g_diode - g_sh - grad_i_recomb # di/dvd
110158
grad_v = 1.0 - grad_i * resistance_series # dv/dvd
111159
# dp/dv = d(iv)/dv = v * di/dv + i
112160
grad = grad_i / grad_v # di/dv
113161
grad_p = v * grad + i # dp/dv
114-
grad2i = -g_diode / nNsVth # d2i/dvd
162+
grad2i = -g_diode / nNsVth - grad_2i_recomb # d2i/dvd
115163
grad2v = -grad2i * resistance_series # d2v/dvd
116164
grad2p = (
117165
grad_v * grad + v * (grad2i/grad_v - grad_i*grad2v/grad_v**2)

pvlib/test/test_singlediode_methods.py

+75-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import numpy as np
66
from pvlib import pvsystem
7+
from pvlib.singlediode_methods import bishop88, estimate_voc, VOLTAGE_BUILTIN
8+
import pytest
79
from conftest import requires_scipy
810

911
POA = 888
@@ -100,7 +102,7 @@ def test_brentq_spr_e20_327():
100102

101103
@requires_scipy
102104
def test_brentq_fs_495():
103-
"""test pvsystem.singlediode with Brent method on SPR-E20-327"""
105+
"""test pvsystem.singlediode with Brent method on FS495"""
104106
fs_495 = CECMOD.First_Solar_FS_495
105107
x = pvsystem.calcparams_desoto(
106108
effective_irradiance=POA, temp_cell=TCELL,
@@ -125,3 +127,75 @@ def test_brentq_fs_495():
125127
method='lambertw')
126128
assert np.isclose(pvs_ixx, ixx)
127129
return isc, voc, imp, vmp, pmp, i, v, pvs
130+
131+
132+
@pytest.fixture
133+
def pvsyst_fs_495():
134+
"""
135+
PVsyst parameters for First Solar FS-495 module from PVSyst-6.7.2 database.
136+
137+
I_L_ref derived from Isc_ref conditions::
138+
139+
I_L_ref = (I_sc_ref + Id + Ish) / (1 - d2mutau/(Vbi*N_s - Vd))
140+
141+
where::
142+
143+
Vd = I_sc_ref * R_s
144+
Id = I_o_ref * (exp(Vd / nNsVt) - 1)
145+
Ish = Vd / R_sh_ref
146+
147+
"""
148+
return {
149+
'd2mutau': 1.31, 'alpha_sc': 0.00039, 'gamma_ref': 1.48,
150+
'mu_gamma': 0.001, 'I_o_ref': 9.62e-10, 'R_sh_ref': 5000,
151+
'R_sh_0': 12500, 'R_sh_exp': 3.1, 'R_s': 4.6, 'beta_oc': -0.2116,
152+
'EgRef': 1.5, 'cells_in_series': 108, 'cells_in_parallel': 2,
153+
'I_sc_ref': 1.55, 'V_oc_ref': 86.5, 'I_mp_ref': 1.4, 'V_mp_ref': 67.85,
154+
'temp_ref': 25, 'irrad_ref': 1000, 'I_L_ref': 1.5743233463848496
155+
}
156+
157+
158+
@pytest.mark.parametrize(
159+
'poa, temp_cell, expected, tol',
160+
[(pvsyst_fs_495()['irrad_ref'], pvsyst_fs_495()['temp_ref'],
161+
{'pmp': pvsyst_fs_495()['I_mp_ref'] * pvsyst_fs_495()['V_mp_ref'],
162+
'isc': pvsyst_fs_495()['I_sc_ref'], 'voc': pvsyst_fs_495()['V_oc_ref']},
163+
(5e-4, 0.04)),
164+
(POA, TCELL, {'pmp': 76.26, 'isc': 1.387, 'voc': 79.29}, (1e-3, 1e-3))]
165+
) # DeSoto @(888[W/m**2], 55[degC]) = {Pmp: 72.71, Isc: 1.402, Voc: 75.42)
166+
def test_pvsyst_recombination_loss(pvsyst_fs_495, poa, temp_cell, expected,
167+
tol):
168+
"""test PVSst recombination loss"""
169+
# first evaluate PVSyst model with thin-film recombination loss current
170+
# at reference conditions
171+
x = pvsystem.calcparams_pvsyst(
172+
effective_irradiance=poa, temp_cell=temp_cell,
173+
alpha_sc=pvsyst_fs_495['alpha_sc'],
174+
gamma_ref=pvsyst_fs_495['gamma_ref'],
175+
mu_gamma=pvsyst_fs_495['mu_gamma'], I_L_ref=pvsyst_fs_495['I_L_ref'],
176+
I_o_ref=pvsyst_fs_495['I_o_ref'], R_sh_ref=pvsyst_fs_495['R_sh_ref'],
177+
R_sh_0=pvsyst_fs_495['R_sh_0'], R_sh_exp=pvsyst_fs_495['R_sh_exp'],
178+
R_s=pvsyst_fs_495['R_s'],
179+
cells_in_series=pvsyst_fs_495['cells_in_series'],
180+
EgRef=pvsyst_fs_495['EgRef']
181+
)
182+
il_pvsyst, io_pvsyst, rs_pvsyst, rsh_pvsyst, nnsvt_pvsyst = x
183+
voc_est_pvsyst = estimate_voc(photocurrent=il_pvsyst,
184+
saturation_current=io_pvsyst,
185+
nNsVth=nnsvt_pvsyst)
186+
vd_pvsyst = np.linspace(0, voc_est_pvsyst, 1000)
187+
pvsyst = bishop88(
188+
diode_voltage=vd_pvsyst, photocurrent=il_pvsyst,
189+
saturation_current=io_pvsyst, resistance_series=rs_pvsyst,
190+
resistance_shunt=rsh_pvsyst, nNsVth=nnsvt_pvsyst,
191+
d2mutau=pvsyst_fs_495['d2mutau'],
192+
NsVbi=VOLTAGE_BUILTIN*pvsyst_fs_495['cells_in_series']
193+
)
194+
# test max power
195+
assert np.isclose(max(pvsyst[2]), expected['pmp'], *tol)
196+
# test short circuit current
197+
isc_pvsyst = np.interp(0, pvsyst[1], pvsyst[0])
198+
assert np.isclose(isc_pvsyst, expected['isc'], *tol)
199+
# test open circuit current
200+
voc_pvsyst = np.interp(0, pvsyst[0][::-1], pvsyst[1][::-1])
201+
assert np.isclose(voc_pvsyst, expected['voc'], *tol)

0 commit comments

Comments
 (0)