-
Notifications
You must be signed in to change notification settings - Fork 1.1k
MAINT: DOC: rename singlediode module, and clean up docstring for singlediode function #525
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 3 commits
611f409
1a42153
a49e959
1b024e1
fa03a93
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 |
---|---|---|
|
@@ -81,6 +81,7 @@ Contents | |
api | ||
comparison_pvlib_matlab | ||
variables_style_rules | ||
singlediode | ||
|
||
|
||
Indices and tables | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
.. _singlediode: | ||
|
||
Single Diode Model | ||
================== | ||
|
||
This section reviews the solutions to the single diode model used in | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
These are my preferred terms, and the meaning of 'model' can be debated at length without adding value. I'm pushing here for consistency and hopefully, clarity. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ agreed, I changed all references for now to single diode equations, since I don't discuss any single diode models here yet eg: PVSyst or DeSoto |
||
pvlib-python to generate an IV curve of a PV module. | ||
|
||
pvlib-python supports two ways to solve the single diode model, by passing the | ||
a ``method`` keyword to the :func:`pvlib.pvsystem.singlediode` function: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest something like... pvlib-python supports two ways to solve the single diode model: The :func: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree with @wholmgren here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ nice change thx! |
||
|
||
1. Lambert W-Function | ||
2. Bishop's Algorithm | ||
|
||
Lambert W-Function | ||
------------------ | ||
When ``method='lambertw'``, the Lambert W-function is used as previously shown | ||
by Jain and Kapoor [1, 2]. The following algorithm can be found on | ||
`Wikipedia: Theory of Solar Cells | ||
<https://en.wikipedia.org/wiki/Theory_of_solar_cells>`_, given the basic single | ||
diode model equation. | ||
|
||
.. math:: | ||
|
||
I = I_L - I_0 \left(\exp \left(\frac{\left(V + I R_s \right)}{n Ns V_{th}} \right) - 1 \right) | ||
- \frac{\left(V + I R_s \right)}{R_{sh}} | ||
|
||
Lambert W-function is the inverse of the function | ||
:math:`f \left( w \right) = w \exp \left( w \right)` or | ||
:math:`w = f^{-1} \left( w \exp \left( w \right) \right)` also given as | ||
:math:`w = W \left( w \exp \left( w \right) \right)`. Rearranging the single | ||
diode equation above with a Lambert W-function yields the following. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd replace the phrase "Rearranging the single diode equation above with a Lambert W-function yields the following. " with "Defining" Because I could not find a derivation of the Lambert W solution in literature, I wrote it out in a Sandia report. We could add a reference if you want. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ OK, I think I've reworded it using "Defining ..." is this better:
|
||
|
||
.. math:: | ||
|
||
z = \frac{R_s I_0}{n Ns V_{th} \left(1 + \frac{R_s}{R_{sh}} \right)} \exp \left( | ||
\frac{R_s \left( I_L + I_0 \right) + V}{n Ns V_{th} \left(1 + \frac{R_s}{R_{sh}}\right)} | ||
\right) | ||
|
||
The the module current can be solved using the Lambert W-function. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ thanks |
||
|
||
.. math:: | ||
|
||
I = \frac{I_L + I_0 - \frac{V}{R_{sh}}}{1 + \frac{R_s}{R_{sh}}} | ||
- \frac{n Ns V_{th}}{R_s} W(z) | ||
|
||
|
||
Bishop's Algorithm | ||
------------------ | ||
The function :func:`pvlib.singlediode.bishop88` uses an explicit solution [3] | ||
that finds points on the IV curve by first solving for pairs :math:`(V_d, I)` | ||
where :math:`V_d` is the diode voltage :math:`V_d = V + I*Rs`. Then the voltage | ||
is backed out from :math:`V_d`. Points with specific voltage, such as open | ||
circuit, are located using the bisection search method, ``brentq``, bounded | ||
by a zero diode voltage and an estimate of open circuit voltage given by | ||
|
||
.. math:: | ||
|
||
V_{oc, est} = n Ns V_{th} \log \left( \frac{I_L}{I_0} + 1 \right) | ||
|
||
We know that :math:`V_d = 0` corresponds to a voltage less than zero, and | ||
we can also show that when :math:`V_d = V_{oc, est}`, the resulting | ||
current is also negative, meaning that the corresponding voltage must be | ||
in the 4th quadrant and therefore greater than the open circuit voltage | ||
(see proof below). Therefore the entire forward-bias 1st quadrant IV-curve | ||
is bounded, and a bisection search within these points will always find | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please clarify "these points" I believe you mean "a bisection search for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ I tried to make this wording better. I added between Vd and Voc,est, but the point is not just to find Voc, but to be able to find any 1st quadrant point including Voc. |
||
desired condition. | ||
|
||
.. math:: | ||
|
||
I = I_L - I_0 \left(\exp \left(\frac{V_{oc, est}}{n Ns V_{th}} \right) - 1 \right) | ||
- \frac{V_{oc, est}}{R_{sh}} \newline | ||
|
||
I = I_L - I_0 \left(\exp \left(\frac{n Ns V_{th} \log \left(\frac{I_L}{I_0} + 1 \right)}{n Ns V_{th}} \right) - 1 \right) | ||
- \frac{n Ns V_{th} \log \left(\frac{I_L}{I_0} + 1 \right)}{R_{sh}} \newline | ||
|
||
I = I_L - I_0 \left(\exp \left(\log \left(\frac{I_L}{I_0} + 1 \right) \right) - 1 \right) | ||
- \frac{n Ns V_{th} \log \left(\frac{I_L}{I_0} + 1 \right)}{R_{sh}} \newline | ||
|
||
I = I_L - I_0 \left(\frac{I_L}{I_0} + 1 - 1 \right) | ||
- \frac{n Ns V_{th} \log \left(\frac{I_L}{I_0} + 1 \right)}{R_{sh}} \newline | ||
|
||
I = I_L - I_0 \left(\frac{I_L}{I_0} \right) | ||
- \frac{n Ns V_{th} \log \left(\frac{I_L}{I_0} + 1 \right)}{R_{sh}} \newline | ||
|
||
I = I_L - I_L - \frac{n Ns V_{th} \log \left( \frac{I_L}{I_0} + 1 \right)}{R_{sh}} \newline | ||
|
||
I = - \frac{n Ns V_{th} \log \left( \frac{I_L}{I_0} + 1 \right)}{R_{sh}} | ||
|
||
References | ||
---------- | ||
[1] "Exact analytical solutions of the parameters of real solar cells using | ||
Lambert W-function," A. Jain, A. Kapoor, Solar Energy Materials and Solar Cells, | ||
81, (2004) pp 269-277. | ||
:doi:`10.1016/j.solmat.2003.11.018` | ||
|
||
[2] "A new method to determine the diode ideality factor of real solar cell | ||
using Lambert W-function," A. Jain, A. Kapoor, Solar Energy Materials and Solar | ||
Cells, 85, (2005) 391-396. | ||
:doi:`10.1016/j.solmat.2004.05.022` | ||
|
||
[3] "Computer simulation of the effects of electrical mismatches in | ||
photovoltaic cell interconnection circuits" JW Bishop, Solar Cell (1988) | ||
:doi:`10.1016/0379-6787(88)90059-2` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,7 @@ | |
from pvlib.tools import _build_kwargs | ||
from pvlib.location import Location | ||
from pvlib import irradiance, atmosphere | ||
from pvlib import singlediode_methods | ||
import pvlib # FIXME: import singlediode module from pvlib | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why FIXME? seems ok to me. Something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ✅ removed fixme, replace with comment |
||
|
||
|
||
# not sure if this belongs in the pvsystem module. | ||
|
@@ -1963,52 +1963,12 @@ def singlediode(photocurrent, saturation_current, resistance_series, | |
open-circuit. | ||
|
||
If the method is either ``'newton'`` or ``'brentq'`` and ``ivcurve_pnts`` | ||
are indicated, then :func:`pvlib.singlediode_methods.bishop88` is used to | ||
are indicated, then :func:`pvlib.singlediode.bishop88` [4] is used to | ||
calculate the points on the IV curve points at diode voltages from zero to | ||
open-circuit voltage with a log spacing that gets closer as voltage | ||
increases. If the method is ``'lambertw'`` then the calculated points on | ||
the IV curve are linearly spaced. | ||
|
||
The ``bishop88`` method uses an explicit solution from [4] that finds | ||
points on the IV curve by first solving for pairs :math:`(V_d, I)` where | ||
:math:`V_d` is the diode voltage :math:`V_d = V + I*Rs`. Then the voltage | ||
is backed out from :math:`V_d`. Points with specific voltage, such as open | ||
circuit, are located using the bisection search method, ``brentq``, bounded | ||
by a zero diode voltage and an estimate of open circuit voltage given by | ||
|
||
.. math:: | ||
|
||
V_{oc, est} = n Ns V_{th} \\log \\left( \\frac{I_L}{I_0} + 1 \\right) | ||
|
||
We know that :math:`V_d = 0` corresponds to a voltage less than zero, and | ||
we can also show that when :math:`V_d = V_{oc, est}`, the resulting | ||
current is also negative, meaning that the corresponding voltage must be | ||
in the 4th quadrant and therefore greater than the open circuit voltage | ||
(see proof below). Therefore the entire forward-bias 1st quadrant IV-curve | ||
is bounded, and a bisection search within these points will always find | ||
desired condition. | ||
|
||
.. math:: | ||
|
||
I = I_L - I_0 \\left(\\exp \\left(\\frac{V_{oc, est}}{n Ns V_{th}} \\right) - 1 \\right) | ||
- \\frac{V_{oc, est}}{R_{sh}} \\newline | ||
|
||
I = I_L - I_0 \\left(\\exp \\left(\\frac{n Ns V_{th} \\log \\left(\\frac{I_L}{I_0} + 1 \\right)}{n Ns V_{th}} \\right) - 1 \\right) | ||
- \\frac{n Ns V_{th} \\log \\left(\\frac{I_L}{I_0} + 1 \\right)}{R_{sh}} \\newline | ||
|
||
I = I_L - I_0 \\left(\\exp \\left(\\log \\left(\\frac{I_L}{I_0} + 1 \\right) \\right) - 1 \\right) | ||
- \\frac{n Ns V_{th} \\log \\left(\\frac{I_L}{I_0} + 1 \\right)}{R_{sh}} \\newline | ||
|
||
I = I_L - I_0 \\left(\\frac{I_L}{I_0} + 1 - 1 \\right) | ||
- \\frac{n Ns V_{th} \\log \\left(\\frac{I_L}{I_0} + 1 \\right)}{R_{sh}} \\newline | ||
|
||
I = I_L - I_0 \\left(\\frac{I_L}{I_0} \\right) | ||
- \\frac{n Ns V_{th} \\log \\left(\\frac{I_L}{I_0} + 1 \\right)}{R_{sh}} \\newline | ||
|
||
I = I_L - I_L - \\frac{n Ns V_{th} \log \\left( \\frac{I_L}{I_0} + 1 \\right)}{R_{sh}} \\newline | ||
|
||
I = - \\frac{n Ns V_{th} \\log \\left( \\frac{I_L}{I_0} + 1 \\right)}{R_{sh}} | ||
|
||
References | ||
----------- | ||
[1] S.R. Wenham, M.A. Green, M.E. Watt, "Applied Photovoltaics" ISBN | ||
|
@@ -2029,12 +1989,12 @@ def singlediode(photocurrent, saturation_current, resistance_series, | |
-------- | ||
sapm | ||
calcparams_desoto | ||
pvlib.singlediode_methods.bishop88 | ||
pvlib.singlediode.bishop88 | ||
""" | ||
# Calculate points on the IV curve using the LambertW solution to the | ||
# single diode equation | ||
if method.lower() == 'lambertw': | ||
out = singlediode_methods._lambertw( | ||
out = pvlib.singlediode._lambertw( | ||
photocurrent, saturation_current, resistance_series, | ||
resistance_shunt, nNsVth, ivcurve_pnts | ||
) | ||
|
@@ -2047,19 +2007,19 @@ def singlediode(photocurrent, saturation_current, resistance_series, | |
# equation for the diode voltage V_d then backing out voltage | ||
args = (photocurrent, saturation_current, resistance_series, | ||
resistance_shunt, nNsVth) # collect args | ||
v_oc = singlediode_methods.bishop88_v_from_i( | ||
v_oc = pvlib.singlediode.bishop88_v_from_i( | ||
0.0, *args, method=method.lower() | ||
) | ||
i_mp, v_mp, p_mp = singlediode_methods.bishop88_mpp( | ||
i_mp, v_mp, p_mp = pvlib.singlediode.bishop88_mpp( | ||
*args, method=method.lower() | ||
) | ||
i_sc = singlediode_methods.bishop88_i_from_v( | ||
i_sc = pvlib.singlediode.bishop88_i_from_v( | ||
0.0, *args, method=method.lower() | ||
) | ||
i_x = singlediode_methods.bishop88_i_from_v( | ||
i_x = pvlib.singlediode.bishop88_i_from_v( | ||
v_oc / 2.0, *args, method=method.lower() | ||
) | ||
i_xx = singlediode_methods.bishop88_i_from_v( | ||
i_xx = pvlib.singlediode.bishop88_i_from_v( | ||
(v_oc + v_mp) / 2.0, *args, method=method.lower() | ||
) | ||
|
||
|
@@ -2069,7 +2029,7 @@ def singlediode(photocurrent, saturation_current, resistance_series, | |
(11.0 - np.logspace(np.log10(11.0), 0.0, | ||
ivcurve_pnts)) / 10.0 | ||
) | ||
ivcurve_i, ivcurve_v, _ = singlediode_methods.bishop88(vd, *args) | ||
ivcurve_i, ivcurve_v, _ = pvlib.singlediode.bishop88(vd, *args) | ||
|
||
out = OrderedDict() | ||
out['i_sc'] = i_sc | ||
|
@@ -2125,7 +2085,7 @@ def max_power_point(photocurrent, saturation_current, resistance_series, | |
curve. This function uses Brent's method by default because it is | ||
guaranteed to converge. | ||
""" | ||
i_mp, v_mp, p_mp = singlediode_methods.bishop88_mpp( | ||
i_mp, v_mp, p_mp = pvlib.singlediode.bishop88_mpp( | ||
photocurrent, saturation_current, resistance_series, | ||
resistance_shunt, nNsVth, method=method.lower() | ||
) | ||
|
@@ -2205,7 +2165,7 @@ def v_from_i(resistance_shunt, resistance_series, nNsVth, current, | |
Energy Materials and Solar Cells, 81 (2004) 269-277. | ||
''' | ||
if method.lower() == 'lambertw': | ||
return singlediode_methods._lambertw_v_from_i( | ||
return pvlib.singlediode._lambertw_v_from_i( | ||
resistance_shunt, resistance_series, nNsVth, current, | ||
saturation_current, photocurrent | ||
) | ||
|
@@ -2215,9 +2175,9 @@ def v_from_i(resistance_shunt, resistance_series, nNsVth, current, | |
# equation for the diode voltage V_d then backing out voltage | ||
args = (current, photocurrent, saturation_current, | ||
resistance_series, resistance_shunt, nNsVth) | ||
V = singlediode_methods.bishop88_v_from_i(*args, method=method.lower()) | ||
V = pvlib.singlediode.bishop88_v_from_i(*args, method=method.lower()) | ||
# find the right size and shape for returns | ||
size, shape = singlediode_methods._get_size_and_shape(args) | ||
size, shape = pvlib.singlediode._get_size_and_shape(args) | ||
if size <= 1: | ||
if shape is not None: | ||
V = np.tile(V, shape) | ||
|
@@ -2293,7 +2253,7 @@ def i_from_v(resistance_shunt, resistance_series, nNsVth, voltage, | |
Energy Materials and Solar Cells, 81 (2004) 269-277. | ||
''' | ||
if method.lower() == 'lambertw': | ||
return singlediode_methods._lambertw_i_from_v( | ||
return pvlib.singlediode._lambertw_i_from_v( | ||
resistance_shunt, resistance_series, nNsVth, voltage, | ||
saturation_current, photocurrent | ||
) | ||
|
@@ -2303,9 +2263,9 @@ def i_from_v(resistance_shunt, resistance_series, nNsVth, voltage, | |
# equation for the diode voltage V_d then backing out voltage | ||
args = (voltage, photocurrent, saturation_current, resistance_series, | ||
resistance_shunt, nNsVth) | ||
I = singlediode_methods.bishop88_i_from_v(*args, method=method.lower()) | ||
I = pvlib.singlediode.bishop88_i_from_v(*args, method=method.lower()) | ||
# find the right size and shape for returns | ||
size, shape = singlediode_methods._get_size_and_shape(args) | ||
size, shape = pvlib.singlediode._get_size_and_shape(args) | ||
if size <= 1: | ||
if shape is not None: | ||
I = np.tile(I, shape) | ||
|
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.
Thanks for adding this! Perhaps it deserves its own note in the whatsnew document.
Didn't you make something else (a wiki?) with more information that might belong here?
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.
Are you set up to get readthedocs to render this version? It's pretty easy to do if you're not. Always nice to see that it works when making bigger documentation changes. If you've rendered locally and say it looks good then ok with me.
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.
Yes, there is a wiki on cell model solutions, but in order to close #518, I just need to move the section on
bishop88()
out ofsinglediode()
, so I would like to open a separate documentation issue/pr to address moving the material appropriate from the wiki to the documents, and perhaps augmenting that with more detail as needed. Is this okay?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.
✅ added note under documentation in what's new:
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.
yes, that's ok with me.