Skip to content

Commit 26579be

Browse files
authored
Match pvsystem.i_from_v, v_from_i single diode parameters with singlediode order. (#1719)
* reorder i_from_v, v_from_i args and refactor tests * reorder args to _update_io v_from_i call * fix condition in type checks for i_from_v tests * reorder arguments for _lambertw methods * adding versionchanged directives * breaking changes section in whatsnew; edit v_from_i, i_from_v docstrings * "Breaking Changes" to "Breaking changes" to match casing of "Bug fixes" * rename I to current
1 parent 50e1998 commit 26579be

File tree

7 files changed

+197
-158
lines changed

7 files changed

+197
-158
lines changed
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
.. _whatsnew_01000:
2+
3+
4+
v0.10.0
5+
-------
6+
7+
8+
Breaking changes
9+
~~~~~~~~~~~~~~~~
10+
* Reorder arguments of :py:func:`pvlib.pvsystem.PVSystem.i_from_v`,
11+
:py:func:`pvlib.pvsystem.i_from_v`, :py:func:`pvlib.pvsystem.v_from_i`,
12+
:py:func:`pvlib.singlediode._lambertw_i_from_v`, and
13+
:py:func:`pvlib.singlediode._lambertw_v_from_i` to match
14+
:py:func:`pvlib.pvsystem.singlediode`.
15+
(:issue:`1718`, :pull:`1719`)
16+
17+
18+
Deprecations
19+
~~~~~~~~~~~~
20+
21+
22+
Enhancements
23+
~~~~~~~~~~~~
24+
25+
26+
Bug fixes
27+
~~~~~~~~~
28+
29+
30+
Testing
31+
~~~~~~~
32+
33+
34+
Documentation
35+
~~~~~~~~~~~~~
36+
37+
Benchmarking
38+
~~~~~~~~~~~~~
39+
40+
41+
Requirements
42+
~~~~~~~~~~~~
43+
44+
45+
Contributors
46+
~~~~~~~~~~~~
47+
* Taos Transue (:ghuser:`reepoi`)

pvlib/ivtools/sdm.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ def _update_io(voc, iph, io, rs, rsh, nnsvth):
942942

943943
while maxerr > eps and k < niter:
944944
# Predict Voc
945-
pvoc = v_from_i(rsh, rs, nnsvth, 0., tio, iph)
945+
pvoc = v_from_i(0., iph, tio, rs, rsh, nnsvth)
946946

947947
# Difference in Voc
948948
dvoc = pvoc - voc

pvlib/pvsystem.py

+61-52
Original file line numberDiff line numberDiff line change
@@ -944,14 +944,17 @@ def singlediode(self, photocurrent, saturation_current,
944944
resistance_series, resistance_shunt, nNsVth,
945945
ivcurve_pnts=ivcurve_pnts)
946946

947-
def i_from_v(self, resistance_shunt, resistance_series, nNsVth, voltage,
948-
saturation_current, photocurrent):
947+
def i_from_v(self, voltage, photocurrent, saturation_current,
948+
resistance_series, resistance_shunt, nNsVth):
949949
"""Wrapper around the :py:func:`pvlib.pvsystem.i_from_v` function.
950950
951-
See :py:func:`pvsystem.i_from_v` for details
951+
See :py:func:`pvlib.pvsystem.i_from_v` for details.
952+
953+
.. versionchanged:: 0.10.0
954+
The function's arguments have been reordered.
952955
"""
953-
return i_from_v(resistance_shunt, resistance_series, nNsVth, voltage,
954-
saturation_current, photocurrent)
956+
return i_from_v(voltage, photocurrent, saturation_current,
957+
resistance_series, resistance_shunt, nNsVth)
955958

956959
def get_ac(self, model, p_dc, v_dc=None):
957960
r"""Calculates AC power from p_dc using the inverter model indicated
@@ -2962,8 +2965,8 @@ def max_power_point(photocurrent, saturation_current, resistance_series,
29622965
return out
29632966

29642967

2965-
def v_from_i(resistance_shunt, resistance_series, nNsVth, current,
2966-
saturation_current, photocurrent, method='lambertw'):
2968+
def v_from_i(current, photocurrent, saturation_current, resistance_series,
2969+
resistance_shunt, nNsVth, method='lambertw'):
29672970
'''
29682971
Device voltage at the given device current for the single diode model.
29692972
@@ -2977,18 +2980,34 @@ def v_from_i(resistance_shunt, resistance_series, nNsVth, current,
29772980
the caller's responsibility to ensure that the arguments are all float64
29782981
and within the proper ranges.
29792982
2983+
.. versionchanged:: 0.10.0
2984+
The function's arguments have been reordered.
2985+
29802986
Parameters
29812987
----------
2982-
resistance_shunt : numeric
2983-
Shunt resistance in ohms under desired IV curve conditions.
2984-
Often abbreviated ``Rsh``.
2985-
0 < resistance_shunt <= numpy.inf
2988+
current : numeric
2989+
The current in amperes under desired IV curve conditions.
2990+
2991+
photocurrent : numeric
2992+
Light-generated current (photocurrent) in amperes under desired
2993+
IV curve conditions. Often abbreviated ``I_L``.
2994+
0 <= photocurrent
2995+
2996+
saturation_current : numeric
2997+
Diode saturation current in amperes under desired IV curve
2998+
conditions. Often abbreviated ``I_0``.
2999+
0 < saturation_current
29863000
29873001
resistance_series : numeric
29883002
Series resistance in ohms under desired IV curve conditions.
29893003
Often abbreviated ``Rs``.
29903004
0 <= resistance_series < numpy.inf
29913005
3006+
resistance_shunt : numeric
3007+
Shunt resistance in ohms under desired IV curve conditions.
3008+
Often abbreviated ``Rsh``.
3009+
0 < resistance_shunt <= numpy.inf
3010+
29923011
nNsVth : numeric
29933012
The product of three components. 1) The usual diode ideal factor
29943013
(n), 2) the number of cells in series (Ns), and 3) the cell
@@ -2999,19 +3018,6 @@ def v_from_i(resistance_shunt, resistance_series, nNsVth, current,
29993018
q is the charge of an electron (coulombs).
30003019
0 < nNsVth
30013020
3002-
current : numeric
3003-
The current in amperes under desired IV curve conditions.
3004-
3005-
saturation_current : numeric
3006-
Diode saturation current in amperes under desired IV curve
3007-
conditions. Often abbreviated ``I_0``.
3008-
0 < saturation_current
3009-
3010-
photocurrent : numeric
3011-
Light-generated current (photocurrent) in amperes under desired
3012-
IV curve conditions. Often abbreviated ``I_L``.
3013-
0 <= photocurrent
3014-
30153021
method : str
30163022
Method to use: ``'lambertw'``, ``'newton'``, or ``'brentq'``. *Note*:
30173023
``'brentq'`` is limited to 1st quadrant only.
@@ -3028,8 +3034,8 @@ def v_from_i(resistance_shunt, resistance_series, nNsVth, current,
30283034
'''
30293035
if method.lower() == 'lambertw':
30303036
return _singlediode._lambertw_v_from_i(
3031-
resistance_shunt, resistance_series, nNsVth, current,
3032-
saturation_current, photocurrent
3037+
current, photocurrent, saturation_current, resistance_series,
3038+
resistance_shunt, nNsVth
30333039
)
30343040
else:
30353041
# Calculate points on the IV curve using either 'newton' or 'brentq'
@@ -3050,33 +3056,49 @@ def v_from_i(resistance_shunt, resistance_series, nNsVth, current,
30503056
return V
30513057

30523058

3053-
def i_from_v(resistance_shunt, resistance_series, nNsVth, voltage,
3054-
saturation_current, photocurrent, method='lambertw'):
3059+
def i_from_v(voltage, photocurrent, saturation_current, resistance_series,
3060+
resistance_shunt, nNsVth, method='lambertw'):
30553061
'''
30563062
Device current at the given device voltage for the single diode model.
30573063
30583064
Uses the single diode model (SDM) as described in, e.g.,
3059-
Jain and Kapoor 2004 [1]_.
3065+
Jain and Kapoor 2004 [1]_.
30603066
The solution is per Eq 2 of [1] except when resistance_series=0,
3061-
in which case the explict solution for current is used.
3067+
in which case the explict solution for current is used.
30623068
Ideal device parameters are specified by resistance_shunt=np.inf and
3063-
resistance_series=0.
3069+
resistance_series=0.
30643070
Inputs to this function can include scalars and pandas.Series, but it is
3065-
the caller's responsibility to ensure that the arguments are all float64
3066-
and within the proper ranges.
3071+
the caller's responsibility to ensure that the arguments are all float64
3072+
and within the proper ranges.
3073+
3074+
.. versionchanged:: 0.10.0
3075+
The function's arguments have been reordered.
30673076
30683077
Parameters
30693078
----------
3070-
resistance_shunt : numeric
3071-
Shunt resistance in ohms under desired IV curve conditions.
3072-
Often abbreviated ``Rsh``.
3073-
0 < resistance_shunt <= numpy.inf
3079+
voltage : numeric
3080+
The voltage in Volts under desired IV curve conditions.
3081+
3082+
photocurrent : numeric
3083+
Light-generated current (photocurrent) in amperes under desired
3084+
IV curve conditions. Often abbreviated ``I_L``.
3085+
0 <= photocurrent
3086+
3087+
saturation_current : numeric
3088+
Diode saturation current in amperes under desired IV curve
3089+
conditions. Often abbreviated ``I_0``.
3090+
0 < saturation_current
30743091
30753092
resistance_series : numeric
30763093
Series resistance in ohms under desired IV curve conditions.
30773094
Often abbreviated ``Rs``.
30783095
0 <= resistance_series < numpy.inf
30793096
3097+
resistance_shunt : numeric
3098+
Shunt resistance in ohms under desired IV curve conditions.
3099+
Often abbreviated ``Rsh``.
3100+
0 < resistance_shunt <= numpy.inf
3101+
30803102
nNsVth : numeric
30813103
The product of three components. 1) The usual diode ideal factor
30823104
(n), 2) the number of cells in series (Ns), and 3) the cell
@@ -3087,19 +3109,6 @@ def i_from_v(resistance_shunt, resistance_series, nNsVth, voltage,
30873109
q is the charge of an electron (coulombs).
30883110
0 < nNsVth
30893111
3090-
voltage : numeric
3091-
The voltage in Volts under desired IV curve conditions.
3092-
3093-
saturation_current : numeric
3094-
Diode saturation current in amperes under desired IV curve
3095-
conditions. Often abbreviated ``I_0``.
3096-
0 < saturation_current
3097-
3098-
photocurrent : numeric
3099-
Light-generated current (photocurrent) in amperes under desired
3100-
IV curve conditions. Often abbreviated ``I_L``.
3101-
0 <= photocurrent
3102-
31033112
method : str
31043113
Method to use: ``'lambertw'``, ``'newton'``, or ``'brentq'``. *Note*:
31053114
``'brentq'`` is limited to 1st quadrant only.
@@ -3116,8 +3125,8 @@ def i_from_v(resistance_shunt, resistance_series, nNsVth, voltage,
31163125
'''
31173126
if method.lower() == 'lambertw':
31183127
return _singlediode._lambertw_i_from_v(
3119-
resistance_shunt, resistance_series, nNsVth, voltage,
3120-
saturation_current, photocurrent
3128+
voltage, photocurrent, saturation_current, resistance_series,
3129+
resistance_shunt, nNsVth
31213130
)
31223131
else:
31233132
# Calculate points on the IV curve using either 'newton' or 'brentq'

pvlib/singlediode.py

+32-39
Original file line numberDiff line numberDiff line change
@@ -495,12 +495,12 @@ def _prepare_newton_inputs(i_or_v_tup, args, v0):
495495
return args, v0
496496

497497

498-
def _lambertw_v_from_i(resistance_shunt, resistance_series, nNsVth, current,
499-
saturation_current, photocurrent):
498+
def _lambertw_v_from_i(current, photocurrent, saturation_current,
499+
resistance_series, resistance_shunt, nNsVth):
500500
# Record if inputs were all scalar
501501
output_is_scalar = all(map(np.isscalar,
502-
[resistance_shunt, resistance_series, nNsVth,
503-
current, saturation_current, photocurrent]))
502+
(current, photocurrent, saturation_current,
503+
resistance_series, resistance_shunt, nNsVth)))
504504

505505
# This transforms Gsh=1/Rsh, including ideal Rsh=np.inf into Gsh=0., which
506506
# is generally more numerically stable
@@ -509,9 +509,9 @@ def _lambertw_v_from_i(resistance_shunt, resistance_series, nNsVth, current,
509509
# Ensure that we are working with read-only views of numpy arrays
510510
# Turns Series into arrays so that we don't have to worry about
511511
# multidimensional broadcasting failing
512-
Gsh, Rs, a, I, I0, IL = \
513-
np.broadcast_arrays(conductance_shunt, resistance_series, nNsVth,
514-
current, saturation_current, photocurrent)
512+
I, IL, I0, Rs, Gsh, a = \
513+
np.broadcast_arrays(current, photocurrent, saturation_current,
514+
resistance_series, conductance_shunt, nNsVth)
515515

516516
# Intitalize output V (I might not be float64)
517517
V = np.full_like(I, np.nan, dtype=np.float64)
@@ -572,12 +572,12 @@ def _lambertw_v_from_i(resistance_shunt, resistance_series, nNsVth, current,
572572
return V
573573

574574

575-
def _lambertw_i_from_v(resistance_shunt, resistance_series, nNsVth, voltage,
576-
saturation_current, photocurrent):
575+
def _lambertw_i_from_v(voltage, photocurrent, saturation_current,
576+
resistance_series, resistance_shunt, nNsVth):
577577
# Record if inputs were all scalar
578578
output_is_scalar = all(map(np.isscalar,
579-
[resistance_shunt, resistance_series, nNsVth,
580-
voltage, saturation_current, photocurrent]))
579+
(voltage, photocurrent, saturation_current,
580+
resistance_series, resistance_shunt, nNsVth)))
581581

582582
# This transforms Gsh=1/Rsh, including ideal Rsh=np.inf into Gsh=0., which
583583
# is generally more numerically stable
@@ -586,9 +586,9 @@ def _lambertw_i_from_v(resistance_shunt, resistance_series, nNsVth, voltage,
586586
# Ensure that we are working with read-only views of numpy arrays
587587
# Turns Series into arrays so that we don't have to worry about
588588
# multidimensional broadcasting failing
589-
Gsh, Rs, a, V, I0, IL = \
590-
np.broadcast_arrays(conductance_shunt, resistance_series, nNsVth,
591-
voltage, saturation_current, photocurrent)
589+
V, IL, I0, Rs, Gsh, a = \
590+
np.broadcast_arrays(voltage, photocurrent, saturation_current,
591+
resistance_series, conductance_shunt, nNsVth)
592592

593593
# Intitalize output I (V might not be float64)
594594
I = np.full_like(V, np.nan, dtype=np.float64) # noqa: E741, N806
@@ -632,36 +632,29 @@ def _lambertw_i_from_v(resistance_shunt, resistance_series, nNsVth, voltage,
632632

633633
def _lambertw(photocurrent, saturation_current, resistance_series,
634634
resistance_shunt, nNsVth, ivcurve_pnts=None):
635+
# collect args
636+
params = {'photocurrent': photocurrent,
637+
'saturation_current': saturation_current,
638+
'resistance_series': resistance_series,
639+
'resistance_shunt': resistance_shunt, 'nNsVth': nNsVth}
640+
635641
# Compute short circuit current
636-
i_sc = _lambertw_i_from_v(resistance_shunt, resistance_series, nNsVth, 0.,
637-
saturation_current, photocurrent)
642+
i_sc = _lambertw_i_from_v(0., **params)
638643

639644
# Compute open circuit voltage
640-
v_oc = _lambertw_v_from_i(resistance_shunt, resistance_series, nNsVth, 0.,
641-
saturation_current, photocurrent)
642-
643-
params = {'r_sh': resistance_shunt,
644-
'r_s': resistance_series,
645-
'nNsVth': nNsVth,
646-
'i_0': saturation_current,
647-
'i_l': photocurrent}
645+
v_oc = _lambertw_v_from_i(0., **params)
648646

649647
# Find the voltage, v_mp, where the power is maximized.
650648
# Start the golden section search at v_oc * 1.14
651-
p_mp, v_mp = _golden_sect_DataFrame(params, 0., v_oc * 1.14,
652-
_pwr_optfcn)
649+
p_mp, v_mp = _golden_sect_DataFrame(params, 0., v_oc * 1.14, _pwr_optfcn)
653650

654651
# Find Imp using Lambert W
655-
i_mp = _lambertw_i_from_v(resistance_shunt, resistance_series, nNsVth,
656-
v_mp, saturation_current, photocurrent)
652+
i_mp = _lambertw_i_from_v(v_mp, **params)
657653

658654
# Find Ix and Ixx using Lambert W
659-
i_x = _lambertw_i_from_v(resistance_shunt, resistance_series, nNsVth,
660-
0.5 * v_oc, saturation_current, photocurrent)
655+
i_x = _lambertw_i_from_v(0.5 * v_oc, **params)
661656

662-
i_xx = _lambertw_i_from_v(resistance_shunt, resistance_series, nNsVth,
663-
0.5 * (v_oc + v_mp), saturation_current,
664-
photocurrent)
657+
i_xx = _lambertw_i_from_v(0.5 * (v_oc + v_mp), **params)
665658

666659
out = (i_sc, v_oc, i_mp, v_mp, p_mp, i_x, i_xx)
667660

@@ -670,9 +663,7 @@ def _lambertw(photocurrent, saturation_current, resistance_series,
670663
ivcurve_v = (np.asarray(v_oc)[..., np.newaxis] *
671664
np.linspace(0, 1, ivcurve_pnts))
672665

673-
ivcurve_i = _lambertw_i_from_v(resistance_shunt, resistance_series,
674-
nNsVth, ivcurve_v.T, saturation_current,
675-
photocurrent).T
666+
ivcurve_i = _lambertw_i_from_v(ivcurve_v.T, **params).T
676667

677668
out += (ivcurve_i, ivcurve_v)
678669

@@ -684,7 +675,9 @@ def _pwr_optfcn(df, loc):
684675
Function to find power from ``i_from_v``.
685676
'''
686677

687-
I = _lambertw_i_from_v(df['r_sh'], df['r_s'], # noqa: E741, N806
688-
df['nNsVth'], df[loc], df['i_0'], df['i_l'])
678+
current = _lambertw_i_from_v(df[loc], df['photocurrent'],
679+
df['saturation_current'],
680+
df['resistance_series'],
681+
df['resistance_shunt'], df['nNsVth'])
689682

690-
return I * df[loc]
683+
return current * df[loc]

0 commit comments

Comments
 (0)