pvlib / pvlib-python

A set of documented functions for simulating the performance of photovoltaic energy systems.
https://pvlib-python.readthedocs.io
BSD 3-Clause "New" or "Revised" License
1.19k stars 997 forks source link

bishop88_v_from_i does not always converge #1757

Open cwhanse opened 1 year ago

cwhanse commented 1 year ago

Describe the bug

bishop88_v_from_i does not converge to a voltage solution when current is greater than short-circuit, and the reverse bias term is active.

To Reproduce

    pvlib.singlediode.bishop88_v_from_i(resistance_shunt=1000., resistance_series=1., nNsVth=2.3, photocurrent=8., saturation_current=1e-8, current=8.1, breakdown_factor=0.1)

  File "C:\Users\cliff\anaconda3\lib\site-packages\pvlib\singlediode.py", line 372, in bishop88_v_from_i
    vd = newton(func=lambda x, *a: fi(x, current, *a), x0=v0,

  File "C:\Users\cliff\anaconda3\lib\site-packages\scipy\optimize\_zeros_py.py", line 368, in newton
    raise RuntimeError(msg)

RuntimeError: Failed to converge after 100 iterations, value is nan.

Expected behavior Converge to a voltage on the reverse bias voltage portion of the I, V curve.

Versions:

cwhanse commented 1 year ago

The "fail to converge" appears to be intrinsic whenever the reverse bias term is activated (breakdown_factor > 0) when using either method newton or brentq. (Using brentq returns the failure message ValueError: f(a) and f(b) must have different signs).

The reason is that including the reverse bias term changes the IV curve at negative voltage, from being defined for all voltage, to having a vertical asymptote at -Vbr (breakdown_voltage). When using Newton's method (for illustration), the iteration will push the candidate voltage for the zero of the objective function to the left of the asymptote, where the objective function is undefined (due to it raising a negative number to the power breakdown_exp). (The objective function is current solved for the IV curve - current at which voltage is wanted). An illustration is below.

pvlib-bishop88_v_from_i_newton

Attempts to get the optimization to work by optimizing on a transformed voltage have so far been fruitless. I've tried, for example, mapping V from the interval (Vbr, Voc) to all reals with inverse logit, and optimizing on the transformed voltage. The transformation removes the problem caused by the asymptote. For Newton's method, once the solution hits the middle "flat" part of the objective function, the iteration shoots far to the left, and then crawls slowly back towards the zero, but so slowly that the method exceeds the default iterations (100). I haven't been able to come up with a 1:1 transformation that preserves the zero, is defined for all reals, and transforms the 1/x behavior near the asymptote to something that would rapidly direct the iteration back close to the zero.

We want a vectorized numerical method to solve these reverse bias curves, for use in the proposed mismatch.py functions #1781 For this reason I haven't tried to fix use of brentq.

A proposed solution: sacrifice some performance for reliability and use the Golden mean search (from the LambertW functions) to solve in bishop88_v_from_i only where the reverse bias term is active.

adriesse commented 1 year ago

Could change the breakdown approximation to something non-vertical?

cwhanse commented 1 year ago

Could change the breakdown approximation to something non-vertical?

I considered adding a second reverse bias model:

With the current code, the 'clip' model would first ignore the user direction to include the reverse bias term (choice is indicated by breakdown_factor>0), then solve for (V, I) without the reverse bias term and clip V. It would be less clumsy if we didn't use breakdown_factor as the flag to turn on reverse bias modeling.

Maybe instead of:

bishop88_v_from_i(..., 'breakdown_factor'=0.1, method='newton')

Something like this:

bishop88_v_from_i(..., 'reverse_bias_model'=None, 'bishop88', 'clip', 'reverse_bias_params'=dict)

We'd also need to let users know that bishop88_v_from_i(..., 'reverse_bias_model'='clip')` is no longer Bishop's 1988 model which is where the current (sorry) reverse bias model originates.

adriesse commented 1 year ago

Instead of clipping, could you perhaps drop the (no longer significant) exponential and solve remaining terms explicitly where needed (V<0)? (I haven't thought this all the way through...)

mikofski commented 1 year ago

Even pvmismatch only solves the “current given voltage” or “voltage given current” problem in forward bias only and excludes reverse breakdown: https://github.com/SunPower/PVMismatch/blob/b391a98c5ded478a73b3c6a08e8de89024be5156/pvmismatch/pvmismatch_lib/pvcell.py#L278

The reason for this is that the reverse bias portion of the curve is closed form so solving for current or voltage is trivial.

The point of using Bishop is that you solve for many points along the entire curve simultaneously from the breakdown voltage to some arbitrary forward bias, then add up the curves in series or parallel, and then find the operating point on the system IV curve. This point will ALWAYS be in forward bias.

cwhanse commented 1 year ago

Instead of clipping, could you perhaps drop the (no longer significant) exponential and solve remaining terms explicitly where needed (V<0)? (I haven't thought this all the way through...)

Dropping the insignificant forward diode current wouldn't help at negative voltage; the challenge to the iteration is the asymptotic behavior of the reverse diode current.

cwhanse commented 1 year ago

Maybe consider consulting pvmismatch?

Does pvmismatch have an exponential-like model for the reverse bias current (breakdown current)?

Yes it does but I don't understand how it all works. https://github.com/SunPower/PVMismatch/blob/b391a98c5ded478a73b3c6a08e8de89024be5156/pvmismatch/pvmismatch_lib/pvcell.py#L238

I'm guessing the use of EPS is equivalent to clipping the voltage, somehow.

mikofski commented 1 year ago

Hi Cliff, sorry I was mistaken and I revised my comment. No, PVMismatch ignores reverse bias when solving I from V or the reverse. You are correct. See my revised comment above.

cwhanse commented 1 year ago

Aha. So the reverse bias current is accounted for when solving an individual IV curve without specified I or V values - when newton isn't needed. When doing "V from I" or "I from V", reverse bias current is ignored.

mikofski commented 1 year ago

Reverse bias is included in the full IV curves that are added together in pvmismatch. It’s just not included when searching for specific points on the IV curve.

tbh I don’t recall what that EPS but is for, the comment says it avoids numpy “divide by zero” warnings. This is very old code from before numpy version 1.

adriesse commented 1 year ago

Instead of clipping, could you perhaps drop the (no longer significant) exponential and solve remaining terms explicitly where needed (V<0)? (I haven't thought this all the way through...)

Dropping the insignificant forward diode current wouldn't help at negative voltage; the challenge to the iteration is the asymptotic behavior of the reverse diode current.

I meant: solve without reverse breakdown first, as you previously suggested. Then rework the negative voltages using the model with reverse breakdown added and exponential removed (hopefully without iteration) rather than a hard clip.

adriesse commented 1 year ago

is no longer Bishop's 1988 model

Most things go out of style at some point.