Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
22d2e5c
add methods and tests for a faster way to calculate single-diode model
mikofski Jan 27, 2018
bb7c49a
log estimate of speedup in test
mikofski Jan 27, 2018
36d4f78
use ordered dict for output, match inputs and outputs, add iv-curve
mikofski Jan 27, 2018
817a303
add "slow" but reliable ways to calculate i_from_v and vv
mikofski Jan 28, 2018
b17a8cd
add check for numerical errors
mikofski Jan 30, 2018
0666d29
use float64, output symbols for fun, make executable
mikofski Jan 30, 2018
595e254
add tests for slower_way using fminbound
mikofski Jan 30, 2018
5ade588
change voc to v_oc
mikofski Jan 30, 2018
7179096
add numeric type to args in docstrings
mikofski Jan 30, 2018
4b66f87
replace custom newton method with scipy.optimize.newton
mikofski Jan 31, 2018
664d7d8
get lambdas working in fast_i_from_v
mikofski Jan 31, 2018
09a9e14
add fast_v_from_i using newton
mikofski Jan 31, 2018
06be522
add fast_mppt
mikofski Jan 31, 2018
1aba56a
calculate i_x and i_xx too for both fast and slow
mikofski Jan 31, 2018
f09be91
test i_x and i_xx too
mikofski Jan 31, 2018
4905363
use brentq instead of fminbound
mikofski Jan 31, 2018
a3d2bb4
change test for numerical errors to use data file
mikofski Jan 31, 2018
8ee1b94
working on #410
mikofski Jan 31, 2018
c9a893a
helping test_singlediode pass tests
mikofski Jan 31, 2018
c5248bb
add the requires scipy decorator
mikofski Jan 31, 2018
68c65c3
fixes #410
mikofski Jan 31, 2018
41e0c83
add i, v, and p to out
mikofski Jan 31, 2018
d7b6e62
need to calculate i-v curve points to compare
mikofski Jan 31, 2018
aa3d29a
add mppt method, update docs
mikofski Jan 31, 2018
9fc350d
fix latex and other sphinx formatting issue sand typos
mikofski Jan 31, 2018
54e8d18
fix circular import issues?
mikofski Feb 1, 2018
16ad9b4
try something remove redundant package imports
mikofski Feb 1, 2018
7aca302
don't raise import error at module level if no scipy
mikofski Feb 1, 2018
086e73f
okay I think I fixed it, now return pvlib module objects
mikofski Feb 1, 2018
9f2b157
try to modify i_from_v
mikofski Feb 1, 2018
555e946
implement v_from_i wrapper
mikofski Feb 1, 2018
52a8e88
respond to @thunderfish24 review items:
mikofski Feb 1, 2018
c0e18a5
change default argument for method to "gold"
mikofski Feb 1, 2018
09c6a75
update test_singlediode_methods to use lambertw in comparison
mikofski Feb 1, 2018
ff8cc0b
change name from mppt -> mpp
mikofski Feb 1, 2018
446fa9e
add test to check for verbose yet graceful failure of v_from_i
mikofski Feb 1, 2018
f976f61
fix pytest.raise context, add test_v_from_i
mikofski Feb 1, 2018
db88022
change mppt->mpp in api.rst docs
mikofski Feb 1, 2018
a509dd3
fix what's new to point to mpp in docs, also add links to bishop88 an…
mikofski Feb 1, 2018
62010c2
Merge branch 'master' into faster_way
mikofski Jun 20, 2018
5c939b8
TST: fix precision test to use new calcparams* API
mikofski Jun 20, 2018
66a801d
TST: update singlediode test for updated atol in #415
mikofski Jun 20, 2018
df1423b
DOC: update what's new for 0.6 with proposed explicit SDM solution
mikofski Jun 20, 2018
eb20cf4
DOC: update docstring to conform to numpydoc style in sdm methods
mikofski Jun 20, 2018
e3805ef
Merge branch 'master' into faster_way
mikofski Jun 26, 2018
5f89578
ENH: refactor est_voc -> estimate_voc
mikofski Jun 26, 2018
ba84fcf
ENH refactor pvsystem.estimate_voc too, also update docs to numpy style
mikofski Jun 26, 2018
0f3893c
ENH refactor vd->diode_voltage in bishop88
mikofski Jun 26, 2018
d6023b1
ENH: TST: refactor reshaping conditions for _array_newton
mikofski Jun 27, 2018
80b3352
ENH: TST: make brentq vectorized always
mikofski Jun 27, 2018
ef20676
ENH: TST: can't vectorize brentq because it treats args as array
mikofski Jun 27, 2018
98d1c01
BUG: TST: use "brentq" instead of "gold"
mikofski Jun 27, 2018
4ecd913
TST: change test fixtures with nonsensical values in quadrant four
mikofski Jun 27, 2018
bf05d2d
TST: fix mpp tests
mikofski Jun 28, 2018
edc445d
ENH: clean up last little bit
mikofski Jun 28, 2018
f542d15
ENH: BUG: TST: DOC: remove all traces for "fast" or "slow"
mikofski Jun 28, 2018
cc6c976
TST: BUG: fix the boolean mask numpy<1.14 bug in tests
mikofski Jun 28, 2018
22c53fc
ENH: TST: ignore .pytest_cache/ folder
mikofski Jun 29, 2018
442a3d4
DOC: MAINT: respond to review by @cwhanse , clean up docstrings
mikofski Jun 29, 2018
6bcffe8
MAINT: update comment about mpp search algorithm
mikofski Jun 29, 2018
e6b60c6
MAINT: update what's new for v0.6
mikofski Jun 29, 2018
0fc9c83
DOC: make sure docs render well
mikofski Jun 29, 2018
fc6cee1
DOC: MAINT: rewording what's new with @cwhanse comments to make it clear
mikofski Jun 29, 2018
28c8ffb
API: change bishop88 and estimate_voc to be used from singlediode_met…
mikofski Jun 29, 2018
58361c1
DOC: link to new singlediode_methods subfunctions in what's new
mikofski Jun 29, 2018
5f9ed41
API: DOC: ENH: change pvsystem.mpp() -> max_power_point()
mikofski Jun 29, 2018
43475cc
MAINT: address comments by @wholmgren
mikofski Jun 30, 2018
c79ab97
Merge branch 'master' into faster_way
mikofski Jul 10, 2018
1ad6031
MAINT: add comment to explain why we import brentq in try-except
mikofski Jul 10, 2018
f14ba04
MAINT: move lambertw methods to singlediode_methods.py
mikofski Jul 10, 2018
8d86560
MAINT: add docstring elaborating the numerical precision test
mikofski Jul 10, 2018
337d7b4
MAINT: use np.expm1(x) for exp(x) - 1 in bishop88 single diode method
mikofski Jul 10, 2018
ce5b0f5
MAINT: replace boilerplate code for broadcasting newton array args
mikofski Jul 10, 2018
3e009f8
MAINT: TEST: parametrize i_from_v and v_from_i for methods, atol
mikofski Jul 10, 2018
082dfd5
MAINT: remove import of functools.partial in pvsystem.py
mikofski Jul 10, 2018
ceb69cd
MAINT: wrap lines longer than 79 characters
mikofski Jul 10, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/sphinx/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ Functions relevant for the single diode model.
pvsystem.i_from_v
pvsystem.singlediode
pvsystem.v_from_i
pvsystem.mppt
pvsystem.bishop88
pvsystem.est_voc

SAPM model
----------
Expand Down
1 change: 1 addition & 0 deletions docs/sphinx/source/whatsnew.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ What's New

These are new features and improvements of note in each release.

.. include:: whatsnew/v0.5.2.rst
.. include:: whatsnew/v0.5.1.rst
.. include:: whatsnew/v0.5.0.rst
.. include:: whatsnew/v0.4.5.txt
Expand Down
12 changes: 11 additions & 1 deletion docs/sphinx/source/whatsnew/v0.5.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@ API Changes

Enhancements
~~~~~~~~~~~~
*
* Implement a reliable "gold" implementation of the single diode model (SDM)
using a bisection method (Brent, 1973) bounded by points known to include the
full forward-bias 1st quadrant IV-curve. Also implement a "fast" method using
a gradient decent method (Newton-Raphson) that is not bounded, but should be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

descent (but also decent!)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

safe for well behaved IV-curves. (:issue:`408`)
* Combine existing :func:`~pvlib.pvsystem.singlediode` method using Lambert-W
with the two new implementations to form a wrapper, that takes an additional
``method`` argument ``('lambertw', 'fast')`` that defaults to the new "gold"
bounded bisection method. (:issue:`410`)
* Add :func:`~pvlib.pvsystem.mppt` method to compute the max power point.

Bug fixes
~~~~~~~~~
Expand All @@ -31,5 +40,6 @@ Contributors
* Cliff Hansen
* Will Holmgren
* KonstantinTr
* Mark Mikofski


101 changes: 101 additions & 0 deletions pvlib/data/bishop88_numerical_precision.csv

Large diffs are not rendered by default.

218 changes: 175 additions & 43 deletions pvlib/pvsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
from pvlib.tools import _build_kwargs
from pvlib.location import Location
from pvlib import irradiance, atmosphere
from pvlib import way_faster
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of this module name. Way faster what exactly?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️ changed it to singlediode_methods - thank you pycharm for refactor feature!


bishop88 = way_faster.bishop88
est_voc = way_faster.est_voc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this use case, I view this more as an upper bound on Voc, rather than an estimate.



# not sure if this belongs in the pvsystem module.
Expand Down Expand Up @@ -1571,7 +1575,7 @@ def sapm_effective_irradiance(poa_direct, poa_diffuse, airmass_absolute, aoi,


def singlediode(photocurrent, saturation_current, resistance_series,
resistance_shunt, nNsVth, ivcurve_pnts=None):
resistance_shunt, nNsVth, ivcurve_pnts=None, method=''):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the default method should be given a unique name. Something like 'gold' or 'robust' (which then refer to a particular method), or perhaps just the name of the default method. This method could change in the future.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️ change it to "gold" but anything that is not "fast" or "lambertw" will be run using the default

r'''
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mikofski can you confirm that the equation still renders properly? If I remember correctly, I added r to some of the doc strings at one point because it was necessary for the equations to render properly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, rendered okay for me - I read somewhere that you can avoid using r""":math:`\frac{numerator}{denominator}`""" by escaping the backslashes, and it works for me:

"""
.. math::
   \\frac{numerator}{denominator}
"""

image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the check. That sounds familiar. Maybe I added "r" in a few places because I thought it was easier to do than escape the backslashes. One could argue that it improves readability too, but let's not fret over it.

Solve the single-diode model to obtain a photovoltaic IV curve.

Expand Down Expand Up @@ -1627,6 +1631,13 @@ def singlediode(photocurrent, saturation_current, resistance_series,
Number of points in the desired IV curve. If None or 0, no
IV curves will be produced.

method : str, default ''
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In ivcurve_pnts above this line, we should specify that the points are between Isc and Voc, inclusive, and linear-spaced (or log-spaced, see further comments).

Determines the method used to calculate IV curve and points. If
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'calculate points on the IV curve'

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

'lambertw' then ``lambertw`` is used. If 'fast' then ``newton`` is
used. Otherwise the problem is bounded between zero and open-circuit
voltage and a bisection method, ``brentq``, is used, that guarantees
convergence.

Returns
-------
OrderedDict or DataFrame
Expand Down Expand Up @@ -1655,9 +1666,48 @@ def singlediode(photocurrent, saturation_current, resistance_series,

Notes
-----
The solution employed to solve the implicit diode equation utilizes
the Lambert W function to obtain an explicit function of V=f(i) and
I=f(V) as shown in [2].
The default method employed is an explicit solution using [4] to find an
Copy link
Member

@cwhanse cwhanse Jun 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More editing. Move this description of bishop88 to after the paragraph about log-spacing.

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 didoe 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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

arbitrary point on the IV curve as a function of the diode voltage
:math:`V_d = V + I*Rs`. Then the voltage is backed out from :math:`V_d`.
A specific desired point, such as short circuit current or max power, is
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}} \\
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}} \\
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}} \\
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}} \\
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}} \\
I = I_L - I_L - \frac{n Ns V_{th} \log \left( \frac{I_L}{I_0} + 1\right)}{R_{sh}} \\
I = - \frac{n Ns V_{th} \log \left( \frac{I_L}{I_0} + 1\right)}{R_{sh}}

If ``method.lower() == 'fast'`` then a gradient descent method, ``newton``,
is used to solve the implicit diode equation. It should be safe for well
behaved IV-curves, but the default method is recommended for reliability,
it is often just as fast.

If either the "fast" or default methods are indicated, then
:func:`pvlib.pvsystem.bishop88` is used to calculate the points at diode
voltages from zero to open-circuit voltage with a log spacing so that
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider making it an option spacing='log' (with default spacing='linear'), or at the very least call it out this change in whatsnew/v0.5.2.rst and clarify somewhere here that lambertw method still uses linear spacing.

Equal spacing by arc length would be another cool option to explore later!

points get closer as they approach the open-circuit voltage.

If ``method.lower() == 'lambertw'`` then the solution employed to solve the
Copy link
Member

@cwhanse cwhanse Jun 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lambertw is the default, so move this paragraph to first in the order.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

method='lambertw' I don't see the need for .lower() or == in the comments

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

implicit diode equation utilizes the Lambert W function to obtain an
explicit function of V=f(i) and I=f(V) as shown in [2].

References
-----------
Expand All @@ -1671,63 +1721,145 @@ def singlediode(photocurrent, saturation_current, resistance_series,
[3] D. King et al, "Sandia Photovoltaic Array Performance Model",
SAND2004-3535, Sandia National Laboratories, Albuquerque, NM

[4] "Computer simulation of the effects of electrical mismatches in
photovoltaic cell interconnection circuits" JW Bishop, Solar Cell (1988)
https://doi.org/10.1016/0379-6787(88)90059-2

See also
--------
sapm
calcparams_desoto
'''

# Compute short circuit current
i_sc = i_from_v(resistance_shunt, resistance_series, nNsVth, 0.,
saturation_current, photocurrent)
if method.lower() == 'lambertw':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a lot of lines to read within an if/else...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we'll handle this in another PR see #497

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️ moved to private function in singlediode_methods.py

# Compute short circuit current
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a comment block here. Calculate points on the IV curve using the LambertW solution to the single diode equation

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

i_sc = i_from_v(resistance_shunt, resistance_series, nNsVth, 0.,
saturation_current, photocurrent)

# Compute open circuit voltage
v_oc = v_from_i(resistance_shunt, resistance_series, nNsVth, 0.,
saturation_current, photocurrent)

# Compute open circuit voltage
v_oc = v_from_i(resistance_shunt, resistance_series, nNsVth, 0.,
saturation_current, photocurrent)
params = {'r_sh': resistance_shunt,
'r_s': resistance_series,
'nNsVth': nNsVth,
'i_0': saturation_current,
'i_l': photocurrent}

params = {'r_sh': resistance_shunt,
'r_s': resistance_series,
'nNsVth': nNsVth,
'i_0': saturation_current,
'i_l': photocurrent}
p_mp, v_mp = _golden_sect_DataFrame(params, 0., v_oc * 1.14, _pwr_optfcn)

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

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

# Find Ix and Ixx using Lambert W
i_x = i_from_v(resistance_shunt, resistance_series, nNsVth, 0.5 * v_oc,
saturation_current, photocurrent)
i_xx = i_from_v(resistance_shunt, resistance_series, nNsVth,
0.5 * (v_oc + v_mp), saturation_current, photocurrent)

i_xx = i_from_v(resistance_shunt, resistance_series, nNsVth,
0.5 * (v_oc + v_mp), saturation_current, photocurrent)
out = OrderedDict()
out['i_sc'] = i_sc
out['v_oc'] = v_oc
out['i_mp'] = i_mp
out['v_mp'] = v_mp
out['p_mp'] = p_mp
out['i_x'] = i_x
out['i_xx'] = i_xx

out = OrderedDict()
out['i_sc'] = i_sc
out['v_oc'] = v_oc
out['i_mp'] = i_mp
out['v_mp'] = v_mp
out['p_mp'] = p_mp
out['i_x'] = i_x
out['i_xx'] = i_xx
# create ivcurve
if ivcurve_pnts:
ivcurve_v = (np.asarray(v_oc)[..., np.newaxis] *
np.linspace(0, 1, ivcurve_pnts))

# create ivcurve
if ivcurve_pnts:
ivcurve_v = (np.asarray(v_oc)[..., np.newaxis] *
np.linspace(0, 1, ivcurve_pnts))
ivcurve_i = i_from_v(resistance_shunt, resistance_series, nNsVth,
ivcurve_v.T, saturation_current, photocurrent).T
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a problem from this PR, but I wish this expression and the previous were commented a bit better, esp. w.r.t. array manipulations and resulting dimensions.


ivcurve_i = i_from_v(resistance_shunt, resistance_series, nNsVth,
ivcurve_v.T, saturation_current, photocurrent).T
out['v'] = ivcurve_v
out['i'] = ivcurve_i

out['v'] = ivcurve_v
out['i'] = ivcurve_i
if isinstance(photocurrent, pd.Series) and not ivcurve_pnts:
out = pd.DataFrame(out, index=photocurrent.index)

if isinstance(photocurrent, pd.Series) and not ivcurve_pnts:
out = pd.DataFrame(out, index=photocurrent.index)
else:
if method.lower() == 'fast':
sdm_fun = way_faster.faster_way
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps module name and function names should be made more representative of methods employed instead of relative performance to current implementation.

else:
sdm_fun = way_faster.slower_way
try:
len(photocurrent)
except TypeError:
out = sdm_fun(
photocurrent, saturation_current, resistance_series,
resistance_shunt, nNsVth, ivcurve_pnts
)
else:
vecfun = np.vectorize(sdm_fun)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps numba can work wonders here in a followup.

out = vecfun(photocurrent, saturation_current, resistance_series,
resistance_shunt, nNsVth, ivcurve_pnts)
if isinstance(photocurrent, pd.Series) and not ivcurve_pnts:
out = pd.DataFrame(out.tolist(), index=photocurrent.index)
else:
out_array = pd.DataFrame(out.tolist())
out = OrderedDict()
out['i_sc'] = out_array.i_sc.values
out['v_oc'] = out_array.v_oc.values
out['i_mp'] = out_array.i_mp.values
out['v_mp'] = out_array.v_mp.values
out['p_mp'] = out_array.p_mp.values
out['i_x'] = out_array.i_x.values
out['i_xx'] = out_array.i_xx.values
if ivcurve_pnts:
out['i'] = np.vstack(out_array.i.values)
out['v'] = np.vstack(out_array.v.values)
out['p'] = np.vstack(out_array.p.values)
return out


def mppt(photocurrent, saturation_current, resistance_series, resistance_shunt,
nNsVth, method=''):
"""
Max power point tracker. Given the calculated DeSoto parameters calculates
the maximum power point (MPP).

:param numeric photocurrent: photo-generated current [A]
:param numeric saturation_current: diode one reverse saturation current [A]
:param numeric resistance_series: series resitance [ohms]
:param numeric resistance_shunt: shunt resitance [ohms]
:param numeric nNsVth: product of thermal voltage ``Vth`` [V], diode
:param str method: if "fast" then use Newton, otherwise use bisection
:returns: ``OrderedDict`` or ``pandas.Datafrane`` with ``i_mp``, ``v_mp``,
and ``p_mp``
"""
if method.lower() == 'fast':
mppt_func = way_faster.fast_mppt
else:
mppt_func = way_faster.slow_mppt
try:
len(photocurrent)
except TypeError:
i_mp, v_mp, p_mp = mppt_func(
photocurrent, saturation_current, resistance_series,
resistance_shunt, nNsVth
)
out = OrderedDict()
out['i_mp'] = i_mp
out['v_mp'] = v_mp
out['p_mp'] = p_mp
else:
vecfun = np.vectorize(mppt_func)
ivp = vecfun(photocurrent, saturation_current, resistance_series,
resistance_shunt, nNsVth)
if isinstance(photocurrent, pd.Series):
ivp = {k: v for k, v in zip(('i_mp', 'v_mp', 'p_mp'), ivp)}
out = pd.DataFrame(ivp, index=photocurrent.index)
else:
out = OrderedDict()
out['i_mp'] = ivp[0]
out['v_mp'] = ivp[1]
out['p_mp'] = ivp[2]
return out


Expand Down
Loading