Skip to content

Commit 5bf127e

Browse files
authored
add v_from_i, improve singlediode speed by 2x (#190)
* implement v_from_i * add and use v_from_i, just add _dpower_dcurrent * remove _dpower_dcurrent * add notes to whatsnew * remove _v_oc_optfcn * fix doc typo * add a v_from_i test representative of a cdte voc
1 parent 3fb07d4 commit 5bf127e

File tree

3 files changed

+88
-16
lines changed

3 files changed

+88
-16
lines changed

docs/sphinx/source/whatsnew/v0.3.3.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ Enhancements
2424
(:issue:`169`)
2525
* Add ``__repr__`` method to PVSystem, LocalizedPVSystem, ModelChain,
2626
SingleAxisTracker, Location. (:issue:`142`)
27+
* Add ``v_from_i`` function for solving the single diode model.
28+
(:issue:`190`)
29+
* Improve speed of ``singlediode`` function by using ``v_from_i`` to
30+
determine ``v_oc``. Speed is ~2x faster. (:issue:`190`)
2731

2832

2933
Bug fixes

pvlib/pvsystem.py

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,15 +1395,16 @@ def singlediode(module, photocurrent, saturation_current,
13951395
i_sc = i_from_v(resistance_shunt, resistance_series, nNsVth, 0.01,
13961396
saturation_current, photocurrent)
13971397

1398+
# Find open circuit voltage using Lambert W
1399+
v_oc = v_from_i(resistance_shunt, resistance_series, nNsVth, 0.0,
1400+
saturation_current, photocurrent)
1401+
13981402
params = {'r_sh': resistance_shunt,
13991403
'r_s': resistance_series,
14001404
'nNsVth': nNsVth,
14011405
'i_0': saturation_current,
14021406
'i_l': photocurrent}
14031407

1404-
__, v_oc = _golden_sect_DataFrame(params, 0, module['V_oc_ref']*1.6,
1405-
_v_oc_optfcn)
1406-
14071408
p_mp, v_mp = _golden_sect_DataFrame(params, 0, module['V_oc_ref']*1.14,
14081409
_pwr_optfcn)
14091410

@@ -1534,13 +1535,70 @@ def _pwr_optfcn(df, loc):
15341535
return I*df[loc]
15351536

15361537

1537-
def _v_oc_optfcn(df, loc):
1538+
def v_from_i(resistance_shunt, resistance_series, nNsVth, current,
1539+
saturation_current, photocurrent):
15381540
'''
1539-
Function to find the open circuit voltage from ``i_from_v``.
1541+
Calculates voltage from current per Eq 3 Jain and Kapoor 2004 [1].
1542+
1543+
Parameters
1544+
----------
1545+
resistance_shunt : float or Series
1546+
Shunt resistance in ohms under desired IV curve conditions.
1547+
Often abbreviated ``Rsh``.
1548+
1549+
resistance_series : float or Series
1550+
Series resistance in ohms under desired IV curve conditions.
1551+
Often abbreviated ``Rs``.
1552+
1553+
nNsVth : float or Series
1554+
The product of three components. 1) The usual diode ideal factor
1555+
(n), 2) the number of cells in series (Ns), and 3) the cell
1556+
thermal voltage under the desired IV curve conditions (Vth). The
1557+
thermal voltage of the cell (in volts) may be calculated as
1558+
``k*temp_cell/q``, where k is Boltzmann's constant (J/K),
1559+
temp_cell is the temperature of the p-n junction in Kelvin, and
1560+
q is the charge of an electron (coulombs).
1561+
1562+
current : float or Series
1563+
The current in amperes under desired IV curve conditions.
1564+
1565+
saturation_current : float or Series
1566+
Diode saturation current in amperes under desired IV curve
1567+
conditions. Often abbreviated ``I_0``.
1568+
1569+
photocurrent : float or Series
1570+
Light-generated current (photocurrent) in amperes under desired
1571+
IV curve conditions. Often abbreviated ``I_L``.
1572+
1573+
Returns
1574+
-------
1575+
current : np.array
1576+
1577+
References
1578+
----------
1579+
[1] A. Jain, A. Kapoor, "Exact analytical solutions of the
1580+
parameters of real solar cells using Lambert W-function", Solar
1581+
Energy Materials and Solar Cells, 81 (2004) 269-277.
15401582
'''
1541-
I = -abs(i_from_v(df['r_sh'], df['r_s'], df['nNsVth'],
1542-
df[loc], df['i_0'], df['i_l']))
1543-
return I
1583+
try:
1584+
from scipy.special import lambertw
1585+
except ImportError:
1586+
raise ImportError('This function requires scipy')
1587+
1588+
Rsh = resistance_shunt
1589+
Rs = resistance_series
1590+
I0 = saturation_current
1591+
IL = photocurrent
1592+
I = current
1593+
1594+
argW = I0 * Rsh / nNsVth * np.exp(Rsh *(-I + IL + I0) / nNsVth)
1595+
lambertwterm = lambertw(argW)
1596+
1597+
# Eqn. 3 in Jain and Kapoor, 2004
1598+
1599+
V = -I*(Rs + Rsh) + IL*Rsh - nNsVth*lambertwterm + I0*Rsh
1600+
1601+
return V.real
15441602

15451603

15461604
def i_from_v(resistance_shunt, resistance_series, nNsVth, voltage,

pvlib/test/test_pvsystem.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,16 @@ def test_PVSystem_calcparams_desoto():
229229
assert_almost_equals(nNsVth, 0.473)
230230

231231

232+
def test_v_from_i():
233+
output = pvsystem.v_from_i(20, .1, .5, 3, 6e-7, 7)
234+
assert_almost_equals(7.5049875193450521, output, 5)
235+
236+
237+
def test_v_from_i_big():
238+
output = pvsystem.v_from_i(500, 10, 4.06, 0, 6e-10, 1.2)
239+
assert_almost_equals(86.320000493521079, output, 5)
240+
241+
232242
def test_i_from_v():
233243
output = pvsystem.i_from_v(20, .1, .5, 40, 6e-7, 7)
234244
assert_almost_equals(-299.746389916, output, 5)
@@ -263,16 +273,16 @@ def test_singlediode_floats():
263273
module = 'Example_Module'
264274
module_parameters = sam_data['cecmod'][module]
265275
out = pvsystem.singlediode(module_parameters, 7, 6e-7, .1, 20, .5)
266-
expected = {'i_xx': 4.2549732697234193,
276+
expected = {'i_xx': 4.2685798754011426,
267277
'i_mp': 6.1390251797935704,
268-
'v_oc': 8.1147298764528042,
278+
'v_oc': 8.1063001465863085,
269279
'p_mp': 38.194165464983037,
270280
'i_x': 6.7556075876880621,
271281
'i_sc': 6.9646747613963198,
272282
'v_mp': 6.221535886625464}
273283
assert isinstance(out, dict)
274284
for k, v in out.items():
275-
assert_almost_equals(expected[k], v, 5)
285+
yield assert_almost_equals, expected[k], v, 3
276286

277287

278288
def test_PVSystem_singlediode_floats():
@@ -281,16 +291,16 @@ def test_PVSystem_singlediode_floats():
281291
system = pvsystem.PVSystem(module=module,
282292
module_parameters=module_parameters)
283293
out = system.singlediode(7, 6e-7, .1, 20, .5)
284-
expected = {'i_xx': 4.2549732697234193,
294+
expected = {'i_xx': 4.2685798754011426,
285295
'i_mp': 6.1390251797935704,
286-
'v_oc': 8.1147298764528042,
296+
'v_oc': 8.1063001465863085,
287297
'p_mp': 38.194165464983037,
288298
'i_x': 6.7556075876880621,
289299
'i_sc': 6.9646747613963198,
290300
'v_mp': 6.221535886625464}
291301
assert isinstance(out, dict)
292302
for k, v in out.items():
293-
assert_almost_equals(expected[k], v, 5)
303+
yield assert_almost_equals, expected[k], v, 3
294304

295305

296306
def test_scale_voltage_current_power():
@@ -478,7 +488,7 @@ def test_PVSystem___repr__():
478488

479489
assert system.__repr__()==('PVSystem with tilt:0 and azimuth:'+
480490
' 180 with Module: blah and Inverter: blarg')
481-
491+
482492

483493
def test_PVSystem_localize___repr__():
484494
system = pvsystem.PVSystem(module='blah', inverter='blarg')
@@ -504,7 +514,7 @@ def test_LocalizedPVSystem_creation():
504514
assert localized_system.latitude == 32
505515
assert localized_system.longitude == -111
506516

507-
517+
508518
def test_LocalizedPVSystem___repr__():
509519
localized_system = pvsystem.LocalizedPVSystem(latitude=32,
510520
longitude=-111,

0 commit comments

Comments
 (0)