Skip to content

Commit 8ee1b94

Browse files
committed
working on pvlib#410
* add method arg and make slow the default * check size of photocurrent and vectorize method if necessary * reorganize out if len(photocurrent)
1 parent a3d2bb4 commit 8ee1b94

File tree

2 files changed

+86
-43
lines changed

2 files changed

+86
-43
lines changed

pvlib/pvsystem.py

Lines changed: 70 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from pvlib.tools import _build_kwargs
2121
from pvlib.location import Location
2222
from pvlib import irradiance, atmosphere
23+
from pvlib import way_faster
2324

2425

2526
# not sure if this belongs in the pvsystem module.
@@ -1571,7 +1572,7 @@ def sapm_effective_irradiance(poa_direct, poa_diffuse, airmass_absolute, aoi,
15711572

15721573

15731574
def singlediode(photocurrent, saturation_current, resistance_series,
1574-
resistance_shunt, nNsVth, ivcurve_pnts=None):
1575+
resistance_shunt, nNsVth, ivcurve_pnts=None, method=''):
15751576
r'''
15761577
Solve the single-diode model to obtain a photovoltaic IV curve.
15771578
@@ -1627,6 +1628,12 @@ def singlediode(photocurrent, saturation_current, resistance_series,
16271628
Number of points in the desired IV curve. If None or 0, no
16281629
IV curves will be produced.
16291630
1631+
method : str, default 'slow'
1632+
Either 'slow', 'fast', or 'lambertw'. Determines the method used to
1633+
calculate IV curve and points. If 'slow' then ``brentq`` is used, if
1634+
'fast' then ``newton`` is used, and if 'lambertw' then `lambertw` is
1635+
used.
1636+
16301637
Returns
16311638
-------
16321639
OrderedDict or DataFrame
@@ -1677,53 +1684,75 @@ def singlediode(photocurrent, saturation_current, resistance_series,
16771684
calcparams_desoto
16781685
'''
16791686

1680-
# Compute short circuit current
1681-
i_sc = i_from_v(resistance_shunt, resistance_series, nNsVth, 0.,
1682-
saturation_current, photocurrent)
1687+
if method.lower() == 'lambertw':
1688+
# Compute short circuit current
1689+
i_sc = i_from_v(resistance_shunt, resistance_series, nNsVth, 0.,
1690+
saturation_current, photocurrent)
1691+
1692+
# Compute open circuit voltage
1693+
v_oc = v_from_i(resistance_shunt, resistance_series, nNsVth, 0.,
1694+
saturation_current, photocurrent)
16831695

1684-
# Compute open circuit voltage
1685-
v_oc = v_from_i(resistance_shunt, resistance_series, nNsVth, 0.,
1686-
saturation_current, photocurrent)
1696+
params = {'r_sh': resistance_shunt,
1697+
'r_s': resistance_series,
1698+
'nNsVth': nNsVth,
1699+
'i_0': saturation_current,
1700+
'i_l': photocurrent}
16871701

1688-
params = {'r_sh': resistance_shunt,
1689-
'r_s': resistance_series,
1690-
'nNsVth': nNsVth,
1691-
'i_0': saturation_current,
1692-
'i_l': photocurrent}
1702+
p_mp, v_mp = _golden_sect_DataFrame(params, 0., v_oc * 1.14, _pwr_optfcn)
16931703

1694-
p_mp, v_mp = _golden_sect_DataFrame(params, 0., v_oc * 1.14, _pwr_optfcn)
1704+
# Invert the Power-Current curve. Find the current where the inverted power
1705+
# is minimized. This is i_mp. Start the optimization at v_oc/2
1706+
i_mp = i_from_v(resistance_shunt, resistance_series, nNsVth, v_mp,
1707+
saturation_current, photocurrent)
16951708

1696-
# Invert the Power-Current curve. Find the current where the inverted power
1697-
# is minimized. This is i_mp. Start the optimization at v_oc/2
1698-
i_mp = i_from_v(resistance_shunt, resistance_series, nNsVth, v_mp,
1699-
saturation_current, photocurrent)
1709+
# Find Ix and Ixx using Lambert W
1710+
i_x = i_from_v(resistance_shunt, resistance_series, nNsVth, 0.5 * v_oc,
1711+
saturation_current, photocurrent)
17001712

1701-
# Find Ix and Ixx using Lambert W
1702-
i_x = i_from_v(resistance_shunt, resistance_series, nNsVth, 0.5 * v_oc,
1703-
saturation_current, photocurrent)
1713+
i_xx = i_from_v(resistance_shunt, resistance_series, nNsVth,
1714+
0.5 * (v_oc + v_mp), saturation_current, photocurrent)
17041715

1705-
i_xx = i_from_v(resistance_shunt, resistance_series, nNsVth,
1706-
0.5 * (v_oc + v_mp), saturation_current, photocurrent)
1716+
out = OrderedDict()
1717+
out['i_sc'] = i_sc
1718+
out['v_oc'] = v_oc
1719+
out['i_mp'] = i_mp
1720+
out['v_mp'] = v_mp
1721+
out['p_mp'] = p_mp
1722+
out['i_x'] = i_x
1723+
out['i_xx'] = i_xx
17071724

1708-
out = OrderedDict()
1709-
out['i_sc'] = i_sc
1710-
out['v_oc'] = v_oc
1711-
out['i_mp'] = i_mp
1712-
out['v_mp'] = v_mp
1713-
out['p_mp'] = p_mp
1714-
out['i_x'] = i_x
1715-
out['i_xx'] = i_xx
1716-
1717-
# create ivcurve
1718-
if ivcurve_pnts:
1719-
ivcurve_v = (np.asarray(v_oc)[..., np.newaxis] *
1720-
np.linspace(0, 1, ivcurve_pnts))
1721-
1722-
ivcurve_i = i_from_v(resistance_shunt, resistance_series, nNsVth,
1723-
ivcurve_v.T, saturation_current, photocurrent).T
1724-
1725-
out['v'] = ivcurve_v
1726-
out['i'] = ivcurve_i
1725+
# create ivcurve
1726+
if ivcurve_pnts:
1727+
ivcurve_v = (np.asarray(v_oc)[..., np.newaxis] *
1728+
np.linspace(0, 1, ivcurve_pnts))
1729+
1730+
ivcurve_i = i_from_v(resistance_shunt, resistance_series, nNsVth,
1731+
ivcurve_v.T, saturation_current, photocurrent).T
1732+
1733+
out['v'] = ivcurve_v
1734+
out['i'] = ivcurve_i
1735+
1736+
else:
1737+
size = 0
1738+
try:
1739+
size = len(photocurrent)
1740+
except TypeError:
1741+
my_func = way_faster.faster_way
1742+
else:
1743+
my_func = np.vectorize(way_faster.slower_way)
1744+
out = my_func(photocurrent, saturation_current, resistance_series,
1745+
resistance_shunt, nNsVth, ivcurve_pnts)
1746+
if size:
1747+
out_array = pd.DataFrame(out.tolist())
1748+
out = OrderedDict()
1749+
out['i_sc'] = out_array.i_sc
1750+
out['v_oc'] = out_array.v_oc
1751+
out['i_mp'] = out_array.i_mp
1752+
out['v_mp'] = out_array.v_mp
1753+
out['p_mp'] = out_array.p_mp
1754+
out['i_x'] = out_array.i_x
1755+
out['i_xx'] = out_array.i_xx
17271756

17281757
if isinstance(photocurrent, pd.Series) and not ivcurve_pnts:
17291758
out = pd.DataFrame(out, index=photocurrent.index)

pvlib/test/test_pvsystem.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,8 @@ def test_singlediode_array():
625625
saturation_current = 1.943e-09
626626

627627
sd = pvsystem.singlediode(photocurrent, saturation_current,
628-
resistance_series, resistance_shunt, nNsVth)
628+
resistance_series, resistance_shunt, nNsVth,
629+
method='lambertw')
629630

630631
expected = np.array([
631632
0. , 0.54538398, 1.43273966, 2.36328163, 3.29255606,
@@ -634,6 +635,14 @@ def test_singlediode_array():
634635

635636
assert_allclose(sd['i_mp'], expected, atol=0.01)
636637

638+
sd = pvsystem.singlediode(photocurrent, saturation_current,
639+
resistance_series, resistance_shunt, nNsVth)
640+
641+
expected = pvsystem.i_from_v(resistance_shunt, resistance_series, nNsVth,
642+
sd['v_mp'], saturation_current, photocurrent)
643+
644+
assert_allclose(sd['i_mp'], expected, atol=0.01)
645+
637646

638647
@requires_scipy
639648
def test_singlediode_floats(sam_data):
@@ -671,6 +680,7 @@ def test_singlediode_floats_ivcurve():
671680
'v': np.array([0., 4.05315, 8.1063])}
672681
assert isinstance(out, dict)
673682
for k, v in out.items():
683+
if k == 'p': continue
674684
assert_allclose(v, expected[k], atol=3)
675685

676686

@@ -684,7 +694,8 @@ def test_singlediode_series_ivcurve(cec_module_params):
684694
module_parameters=cec_module_params,
685695
EgRef=1.121, dEgdT=-0.0002677)
686696

687-
out = pvsystem.singlediode(IL, I0, Rs, Rsh, nNsVth, ivcurve_pnts=3)
697+
out = pvsystem.singlediode(IL, I0, Rs, Rsh, nNsVth, ivcurve_pnts=3,
698+
method='lambertw')
688699

689700
expected = OrderedDict([('i_sc', array([0., 3.01054475, 6.00675648])),
690701
('v_oc', array([0., 9.96886962, 10.29530483])),
@@ -705,6 +716,9 @@ def test_singlediode_series_ivcurve(cec_module_params):
705716
for k, v in out.items():
706717
assert_allclose(v, expected[k], atol=1e-2)
707718

719+
out = pvsystem.singlediode(IL, I0, Rs, Rsh, nNsVth, ivcurve_pnts=3,
720+
method='lambertw')
721+
708722

709723
def test_scale_voltage_current_power(sam_data):
710724
data = pd.DataFrame(

0 commit comments

Comments
 (0)