Closed
Description
Describe the bug
The bishop88 functions can sometimes fail, or return incorrect results, when using the d2mutau
and NsVbi
parameters.
To Reproduce
Set-up:
import pvlib
import numpy as np
import matplotlib.pyplot as plt
sdm_params = {
'alpha_sc': 0.001, 'gamma_ref': 1.409, 'mu_gamma': 0.001, 'I_o_ref': 3.96e-11,
'R_sh_ref': 4900, 'R_sh_0': 8800, 'R_sh_exp': 5.5,
'R_s': 6.76, 'cells_in_series': 264, 'EgRef': 1.121, 'I_L_ref': 2.278883384981941
}
d2mutau = 1.5
NsVbi = 237.6
G = np.linspace(0, 1200)
T = 25
sde_params = pvlib.pvsystem.calcparams_pvsyst(G, T, **sdm_params)
method='brentq'
errors with ValueError: f(a) and f(b) must have different signs
.
Click to show traceback
Traceback (most recent call last):
Cell In[16], line 17
mpp = pvlib.singlediode.bishop88_mpp(*sde_params, d2mutau=d2mutau, NsVbi=NsVbi, method='brentq')
File ~\software\miniconda3\envs\dev\lib\site-packages\pvlib\singlediode.py:577 in bishop88_mpp
vd = vec_fun(voc_est, *args)
File ~\software\miniconda3\envs\dev\lib\site-packages\numpy\lib\function_base.py:2372 in __call__
return self._call_as_normal(*args, **kwargs)
File ~\software\miniconda3\envs\dev\lib\site-packages\numpy\lib\function_base.py:2365 in _call_as_normal
return self._vectorize_call(func=func, args=vargs)
File ~\software\miniconda3\envs\dev\lib\site-packages\numpy\lib\function_base.py:2450 in _vectorize_call
ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args)
File ~\software\miniconda3\envs\dev\lib\site-packages\numpy\lib\function_base.py:2410 in _get_ufunc_and_otypes
outputs = func(*inputs)
File ~\software\miniconda3\envs\dev\lib\site-packages\pvlib\singlediode.py:572 in <lambda>
vbr_exp: brentq(fmpp, 0.0, voc,
File ~\software\miniconda3\envs\dev\lib\site-packages\scipy\optimize\_zeros_py.py:809 in brentq
r = _zeros._brentq(f, a, b, xtol, rtol, maxiter, args, full_output, disp)
ValueError: f(a) and f(b) must have different signs
method='newton'
gives incorrect results for some conditions:
mpp_newton = pvlib.singlediode.bishop88_mpp(*sde_params, d2mutau=d2mutau, NsVbi=NsVbi, method='newton')
plt.plot(G, mpp_newton[2])
plt.ylabel('$P_{mp}$ [W]')
plt.xlabel('Irradiance [W/m2]')
Versions:
pvlib.__version__
: 0.10.4scipy.__version__
: 1.12.0
Additional context
I think the problem has something to do with the following:
- The SDE with the thin film recombination current term has a singularity at
NsVbi = Vd
, and our code only returns valid results forVd < NsVbi
(ref Adding New Single Diode Model For CdTe #163 (comment)) estimate_voc
can sometimes return a value on the other side of the singularity (Vd > NsVbi
), where our bishop88-style calculations are not valid.bishop88_mpp
usesestimate_voc
to calculate either an upper bound for the bracketed optimization (withmethod='brentq'
) or the initial guess (withmethod='newton'
), meaning we are sometimes providing invalid starting points to the root finder.
Here is an example of the estimated Voc being greater than NsVbi:
import pvlib
sdm_params = {
'alpha_sc': 0.001, 'gamma_ref': 1.409, 'mu_gamma': 0.001, 'I_o_ref': 3.96e-11,
'R_sh_ref': 4900, 'R_sh_0': 8800, 'R_sh_exp': 5.5,
'R_s': 6.76, 'cells_in_series': 264, 'EgRef': 1.121, 'I_L_ref': 2.278883384981941
}
d2mutau = 1.5
NsVbi = 237.6
G = 1100
T = 25
sde_params = pvlib.pvsystem.calcparams_pvsyst(G, T, **sdm_params)
voc_est = pvlib.singlediode.estimate_voc(sde_params[0], sde_params[1], sde_params[-1])
print(voc_est) # 237.6945087345138, greater than NsVbi=237.6