Skip to content

Commit 72a6d47

Browse files
committed
bring in changes from #2291
1 parent acab5bb commit 72a6d47

File tree

2 files changed

+74
-38
lines changed

2 files changed

+74
-38
lines changed

pvlib/ivtools/sdm/desoto.py

+54-38
Original file line numberDiff line numberDiff line change
@@ -15,107 +15,123 @@
1515

1616
def fit_desoto(v_mp, i_mp, v_oc, i_sc, alpha_sc, beta_voc, cells_in_series,
1717
EgRef=1.121, dEgdT=-0.0002677, temp_ref=25, irrad_ref=1000,
18-
root_kwargs={}):
18+
init_guess={}, root_kwargs={}):
1919
"""
2020
Calculates the parameters for the De Soto single diode model.
2121
22-
This procedure (described in [1]_) has the advantage of
23-
using common specifications given by manufacturers in the
22+
This procedure (described in [1]_) fits the De Soto model [2]_ using
23+
common specifications given by manufacturers in the
2424
datasheets of PV modules.
2525
26-
The solution is found using the scipy.optimize.root() function,
27-
with the corresponding default solver method 'hybr'.
28-
No restriction is put on the fit variables, i.e. series
26+
The solution is found using :py:func:`scipy.optimize.root`,
27+
with the default solver method 'hybr'.
28+
No restriction is put on the fit variables, e.g. series
2929
or shunt resistance could go negative. Nevertheless, if it happens,
30-
check carefully the inputs and their units; alpha_sc and beta_voc are
31-
often given in %/K in manufacturers datasheets and should be given
32-
in A/K and V/K here.
30+
check carefully the inputs and their units. For example, ``alpha_sc`` and
31+
``beta_voc`` are often given in %/K in manufacturers datasheets but should
32+
be given in A/K and V/K here.
3333
3434
The parameters returned by this function can be used by
35-
:py:func:`pvlib.pvsystem.calcparams_desoto` to calculate the values at
36-
different irradiance and cell temperature.
35+
:py:func:`pvlib.pvsystem.calcparams_desoto` to calculate single diode
36+
equation parameters at different irradiance and cell temperature.
3737
3838
Parameters
3939
----------
4040
v_mp: float
41-
Module voltage at the maximum-power point at reference conditions [V].
41+
Module voltage at the maximum-power point at reference conditions. [V]
4242
i_mp: float
43-
Module current at the maximum-power point at reference conditions [A].
43+
Module current at the maximum-power point at reference conditions. [A]
4444
v_oc: float
45-
Open-circuit voltage at reference conditions [V].
45+
Open-circuit voltage at reference conditions. [V]
4646
i_sc: float
47-
Short-circuit current at reference conditions [A].
47+
Short-circuit current at reference conditions. [A]
4848
alpha_sc: float
4949
The short-circuit current (i_sc) temperature coefficient of the
50-
module [A/K].
50+
module. [A/K]
5151
beta_voc: float
5252
The open-circuit voltage (v_oc) temperature coefficient of the
53-
module [V/K].
53+
module. [V/K]
5454
cells_in_series: integer
5555
Number of cell in the module.
5656
EgRef: float, default 1.121 eV - value for silicon
57-
Energy of bandgap of semi-conductor used [eV]
57+
Energy of bandgap of semi-conductor used. [eV]
5858
dEgdT: float, default -0.0002677 - value for silicon
59-
Variation of bandgap according to temperature [eV/K]
59+
Variation of bandgap according to temperature. [eV/K]
6060
temp_ref: float, default 25
61-
Reference temperature condition [C]
61+
Reference temperature condition. [C]
6262
irrad_ref: float, default 1000
63-
Reference irradiance condition [W/m2]
63+
Reference irradiance condition. [Wm⁻²]
64+
init_guess: dict, optional
65+
Initial values for optimization. Keys can be `'Rsh_0'`, `'a_0'`,
66+
`'IL_0'`, `'Io_0'`, `'Rs_0'`.
6467
root_kwargs : dictionary, optional
6568
Dictionary of arguments to pass onto scipy.optimize.root()
6669
6770
Returns
6871
-------
6972
dict with the following elements:
7073
I_L_ref: float
71-
Light-generated current at reference conditions [A]
74+
Light-generated current at reference conditions. [A]
7275
I_o_ref: float
73-
Diode saturation current at reference conditions [A]
76+
Diode saturation current at reference conditions. [A]
7477
R_s: float
75-
Series resistance [ohm]
78+
Series resistance. [ohm]
7679
R_sh_ref: float
77-
Shunt resistance at reference conditions [ohm].
80+
Shunt resistance at reference conditions. [ohm].
7881
a_ref: float
7982
Modified ideality factor at reference conditions.
8083
The product of the usual diode ideality factor (n, unitless),
8184
number of cells in series (Ns), and cell thermal voltage at
8285
specified effective irradiance and cell temperature.
8386
alpha_sc: float
8487
The short-circuit current (i_sc) temperature coefficient of the
85-
module [A/K].
88+
module. [A/K]
8689
EgRef: float
87-
Energy of bandgap of semi-conductor used [eV]
90+
Energy of bandgap of semi-conductor used. [eV]
8891
dEgdT: float
89-
Variation of bandgap according to temperature [eV/K]
92+
Variation of bandgap according to temperature. [eV/K]
9093
irrad_ref: float
91-
Reference irradiance condition [W/m2]
94+
Reference irradiance condition. [Wm⁻²]
9295
temp_ref: float
93-
Reference temperature condition [C]
96+
Reference temperature condition. [C]
9497
9598
scipy.optimize.OptimizeResult
9699
Optimization result of scipy.optimize.root().
97100
See scipy.optimize.OptimizeResult for more details.
98101
99102
References
100103
----------
101-
.. [1] W. De Soto et al., "Improvement and validation of a model for
104+
.. [1] J. A Duffie, W. A Beckman, "Solar Engineering of Thermal Processes",
105+
4th ed., Wiley, 2013. :doi:`10.1002/9781118671603`
106+
.. [2] W. De Soto et al., "Improvement and validation of a model for
102107
photovoltaic array performance", Solar Energy, vol 80, pp. 78-88,
103108
2006. :doi:`10.1016/j.solener.2005.06.010`
109+
104110
"""
105111

106112
# Constants
107113
k = constants.value('Boltzmann constant in eV/K') # in eV/K
108114
Tref = temp_ref + 273.15 # [K]
109115

110116
# initial guesses of variables for computing convergence:
111-
# Values are taken from [2], p753
112-
Rsh_0 = 100.0
113-
a_0 = 1.5*k*Tref*cells_in_series
114-
IL_0 = i_sc
115-
Io_0 = i_sc * np.exp(-v_oc/a_0)
116-
Rs_0 = (a_0*np.log1p((IL_0-i_mp)/Io_0) - v_mp)/i_mp
117+
# Default values are taken from [1], p753
118+
init_guess_keys = ['IL_0', 'Io_0', 'Rs_0', 'Rsh_0', 'a_0'] # order matters
119+
init = {key: None for key in init_guess_keys}
120+
init['IL_0'] = i_sc
121+
init['a_0'] = 1.5*k*Tref*cells_in_series
122+
init['Io_0'] = i_sc * np.exp(-v_oc/init['a_0'])
123+
init['Rs_0'] = (init['a_0']*np.log1p((init['IL_0'] - i_mp)/init['Io_0'])
124+
- v_mp) / i_mp
125+
init['Rsh_0'] = 100.0
126+
# overwrite if optional init_guess is provided
127+
for key in init_guess:
128+
if key in init_guess_keys:
129+
init[key] = init_guess[key]
130+
else:
131+
raise ValueError(f"'{key}' is not a valid name;"
132+
f" allowed values are {init_guess_keys}")
117133
# params_i : initial values vector
118-
params_i = np.array([IL_0, Io_0, Rs_0, Rsh_0, a_0])
134+
params_i = np.array([init[k] for k in init_guess_keys])
119135

120136
# specs of module
121137
specs = (i_sc, v_oc, i_mp, v_mp, beta_voc, alpha_sc, EgRef, dEgdT,

pvlib/tests/ivtools/sdm/test_desoto.py

+20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22
import pandas as pd
3+
from scipy import optimize
34

45
import pytest
56

@@ -27,6 +28,25 @@ def test_fit_desoto():
2728
rtol=1e-4)
2829

2930

31+
def test_fit_desoto_init_guess(mocker):
32+
init_guess_array = np.array([9.4, 3.0e-10, 0.3, 125., 1.6])
33+
init_guess = {k: v for k, v in zip(
34+
['IL_0', 'Io_0', 'Rs_0', 'Rsh_0', 'a_0'], init_guess_array)}
35+
spy = mocker.spy(optimize, 'root')
36+
result, _ = sdm.fit_desoto(v_mp=31.0, i_mp=8.71, v_oc=38.3, i_sc=9.43,
37+
alpha_sc=0.005658, beta_voc=-0.13788,
38+
cells_in_series=60, init_guess=init_guess)
39+
np.testing.assert_array_equal(init_guess_array, spy.call_args[1]['x0'])
40+
41+
42+
def test_fit_desoto_init_bad_key():
43+
init_guess = {'IL_0': 6., 'bad_key': 0}
44+
with pytest.raises(ValueError, match='is not a valid name;'):
45+
result, _ = sdm.fit_desoto(v_mp=31.0, i_mp=8.71, v_oc=38.3, i_sc=9.43,
46+
alpha_sc=0.005658, beta_voc=-0.13788,
47+
cells_in_series=60, init_guess=init_guess)
48+
49+
3050
def test_fit_desoto_failure():
3151
with pytest.raises(RuntimeError) as exc:
3252
sdm.fit_desoto(v_mp=31.0, i_mp=8.71, v_oc=38.3, i_sc=9.43,

0 commit comments

Comments
 (0)