-
Notifications
You must be signed in to change notification settings - Fork 1.1k
coefficient estimation method following DeSoto(2006) #784
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 all commits
c5287ea
5a39fea
7b24201
c16f1d0
e7ef571
cdb2a73
0cfe13f
0c27829
d8653cd
bbb4580
6b8fadf
121cb06
47e1be4
c1b62c4
4e62d1a
747ed48
9ea2ed8
bd39dbd
ae5c8be
2d4f8f3
485dae6
77d88a2
6fcafc7
2d53d5d
fdbf5ec
0e1b4b3
d2d8c45
a70debb
e01f262
17f8617
e14ad40
32049b0
bfe3994
7ff8a96
7f08d80
27ab961
79ef920
5e9cf8d
c02e74f
fa41eb8
753d312
b1b405c
22d613c
ae19a68
6913a52
05051e1
d4772c6
d821494
9d23552
5037da6
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 |
---|---|---|
|
@@ -262,6 +262,147 @@ def fit_sde_sandia(voltage, current, v_oc=None, i_sc=None, v_mp_i_mp=None, | |
v_oc) | ||
|
||
|
||
def fit_sdm_desoto(v_mp, i_mp, v_oc, i_sc, alpha_sc, beta_voc, | ||
cells_in_series, EgRef=1.121, dEgdT=-0.0002677, | ||
temp_ref=25, irrad_ref=1000, root_kwargs={}): | ||
""" | ||
Calculates the parameters for the De Soto single diode model using the | ||
procedure described in [1]. This procedure has the advantage of | ||
using common specifications given by manufacturers in the | ||
datasheets of PV modules. | ||
|
||
The solution is found using the scipy.optimize.root() function, | ||
cwhanse marked this conversation as resolved.
Show resolved
Hide resolved
|
||
with the corresponding default solver method 'hybr'. | ||
No restriction is put on the fit variables, i.e. series | ||
or shunt resistance could go negative. Nevertheless, if it happens, | ||
check carefully the inputs and their units; alpha_sc and beta_voc are | ||
often given in %/K in manufacturers datasheets and should be given | ||
in A/K and V/K here. | ||
|
||
The parameters returned by this function can be used by | ||
pvsystem.calcparams_desoto to calculate the values at different | ||
irradiance and cell temperature. | ||
|
||
Parameters | ||
---------- | ||
v_mp: float | ||
Module voltage at the maximum-power point at reference conditions [V]. | ||
i_mp: float | ||
Module current at the maximum-power point at reference conditions [A]. | ||
v_oc: float | ||
Open-circuit voltage at reference conditions [V]. | ||
i_sc: float | ||
Short-circuit current at reference conditions [A]. | ||
alpha_sc: float | ||
The short-circuit current (i_sc) temperature coefficient of the | ||
module [A/K]. | ||
beta_voc: float | ||
The open-circuit voltage (v_oc) temperature coefficient of the | ||
module [V/K]. | ||
cells_in_series: integer | ||
Number of cell in the module. | ||
tylunel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
EgRef: float, default 1.121 eV - value for silicon | ||
Energy of bandgap of semi-conductor used [eV] | ||
dEgdT: float, default -0.0002677 - value for silicon | ||
Variation of bandgap according to temperature [eV/K] | ||
temp_ref: float, default 25 | ||
Reference temperature condition [C] | ||
irrad_ref: float, default 1000 | ||
Reference irradiance condition [W/m2] | ||
root_kwargs: dictionary, default None | ||
Dictionary of arguments to pass onto scipy.optimize.root() | ||
|
||
Returns | ||
------- | ||
Tuple of the following elements: | ||
|
||
* Dictionary with the following elements: | ||
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. The other two fitting functions return tuples of values rather than a dictionary. Is there a trend one way or another? 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 agree that it’s good to be consistent. However, I very much prefer interfaces where order does not matter, because this ordering is a form of complexity, which is harder to maintain/extend without breakages. Also, the dictionary output is perhaps best paired with keyword-only inputs to subsequent functions/methods, but it still works with pvlib’s current mixture of named positional and keyword arguments. However, it would not be compatible with Python 3.8’s new positional-only arguments. 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 don't think there's a right answer. It would be most helpful if people could provide some good references for pros/cons of modern scientific python design patterns. I am not aware of any references that tackle non-trivial cases. 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. 24 minutes into this keynote talk on simplicity, Rich Hickey (creator of Clojure) discusses the complexity of ordering things in lists: https://m.youtube.com/watch?v=rI8tNMsozo0&t=3s This is not gospel of course, and indeed ordering can provide performance gains, etc. (which is why dictionaries are now ordered in CPython, which I personally treat as an implementation detail to not to be relied upon). 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. Let's address consistency among functions returns in a follow-on PR. I can't say I had a pattern in mind when I started |
||
I_L_ref: float | ||
Light-generated current at reference conditions [A] | ||
I_o_ref: float | ||
Diode saturation current at reference conditions [A] | ||
R_s: float | ||
Series resistance [ohms] | ||
R_sh_ref: float | ||
Shunt resistance at reference conditions [ohms]. | ||
a_ref: float | ||
Modified ideality factor at reference conditions. | ||
The product of the usual diode ideality factor (n, unitless), | ||
number of cells in series (Ns), and cell thermal voltage at | ||
specified effective irradiance and cell temperature. | ||
alpha_sc: float | ||
The short-circuit current (i_sc) temperature coefficient of the | ||
module [A/K]. | ||
EgRef: float | ||
Energy of bandgap of semi-conductor used [eV] | ||
dEgdT: float | ||
Variation of bandgap according to temperature [eV/K] | ||
irrad_ref: float | ||
Reference irradiance condition [W/m2] | ||
temp_ref: float | ||
Reference temperature condition [C] | ||
* scipy.optimize.OptimizeResult | ||
Optimization result of scipy.optimize.root(). | ||
See scipy.optimize.OptimizeResult for more details. | ||
|
||
References | ||
---------- | ||
[1] W. De Soto et al., "Improvement and validation of a model for | ||
photovoltaic array performance", Solar Energy, vol 80, pp. 78-88, | ||
2006. | ||
|
||
[2] John A Duffie, William A Beckman, "Solar Engineering of Thermal | ||
Processes", Wiley, 2013 | ||
""" | ||
|
||
try: | ||
from scipy.optimize import root | ||
from scipy import constants | ||
except ImportError: | ||
raise ImportError("The fit_sdm_desoto function requires scipy.") | ||
|
||
# Constants | ||
k = constants.value('Boltzmann constant in eV/K') | ||
Tref = temp_ref + 273.15 # [K] | ||
|
||
# initial guesses of variables for computing convergence: | ||
# Values are taken from [2], p753 | ||
Rsh_0 = 100.0 | ||
a_0 = 1.5*k*Tref*cells_in_series | ||
IL_0 = i_sc | ||
Io_0 = i_sc * np.exp(-v_oc/a_0) | ||
Rs_0 = (a_0*np.log1p((IL_0-i_mp)/Io_0) - v_mp)/i_mp | ||
# params_i : initial values vector | ||
params_i = np.array([IL_0, Io_0, a_0, Rsh_0, Rs_0]) | ||
|
||
# specs of module | ||
specs = (i_sc, v_oc, i_mp, v_mp, beta_voc, alpha_sc, EgRef, dEgdT, | ||
Tref, k) | ||
|
||
# computing with system of equations described in [1] | ||
optimize_result = root(_system_of_equations_desoto, x0=params_i, | ||
args=(specs,), **root_kwargs) | ||
|
||
if optimize_result.success: | ||
sdm_params = optimize_result.x | ||
else: | ||
raise RuntimeError( | ||
'Parameter estimation failed:\n' + optimize_result.message) | ||
|
||
# results | ||
return ({'I_L_ref': sdm_params[0], | ||
'I_o_ref': sdm_params[1], | ||
'a_ref': sdm_params[2], | ||
'R_sh_ref': sdm_params[3], | ||
'R_s': sdm_params[4], | ||
'alpha_sc': alpha_sc, | ||
'EgRef': EgRef, | ||
'dEgdT': dEgdT, | ||
'irrad_ref': irrad_ref, | ||
'temp_ref': temp_ref}, | ||
optimize_result) | ||
|
||
|
||
def _find_mp(voltage, current): | ||
""" | ||
Finds voltage and current at maximum power point. | ||
|
@@ -348,3 +489,69 @@ def _calculate_sde_parameters(beta0, beta1, beta3, beta4, v_mp, i_mp, v_oc): | |
else: # I0_voc > 0 | ||
I0 = I0_voc | ||
return (IL, I0, Rsh, Rs, nNsVth) | ||
|
||
|
||
def _system_of_equations_desoto(params, specs): | ||
"""Evaluates the systems of equations used to solve for the single | ||
diode equation parameters. Function designed to be used by | ||
scipy.optimize.root() in fit_sdm_desoto(). | ||
|
||
Parameters | ||
---------- | ||
params: ndarray | ||
Array with parameters of the De Soto single diode model. Must be | ||
given in the following order: IL, Io, a, Rsh, Rs | ||
specs: tuple | ||
Specifications of pv module given by manufacturer. Must be given | ||
in the following order: Isc, Voc, Imp, Vmp, beta_oc, alpha_sc | ||
|
||
Returns | ||
------- | ||
system of equations to solve with scipy.optimize.root(). | ||
|
||
|
||
References | ||
---------- | ||
[1] W. De Soto et al., "Improvement and validation of a model for | ||
photovoltaic array performance", Solar Energy, vol 80, pp. 78-88, | ||
2006. | ||
|
||
[2] John A Duffie, William A Beckman, "Solar Engineering of Thermal | ||
Processes", Wiley, 2013 | ||
""" | ||
|
||
# six input known variables | ||
Isc, Voc, Imp, Vmp, beta_oc, alpha_sc, EgRef, dEgdT, Tref, k = specs | ||
|
||
# five parameters vector to find | ||
IL, Io, a, Rsh, Rs = params | ||
|
||
# five equation vector | ||
y = [0, 0, 0, 0, 0] | ||
|
||
# 1st equation - short-circuit - eq(3) in [1] | ||
y[0] = Isc - IL + Io * np.expm1(Isc * Rs / a) + Isc * Rs / Rsh | ||
|
||
# 2nd equation - open-circuit Tref - eq(4) in [1] | ||
y[1] = -IL + Io * np.expm1(Voc / a) + Voc / Rsh | ||
|
||
# 3rd equation - Imp & Vmp - eq(5) in [1] | ||
y[2] = Imp - IL + Io * np.expm1((Vmp + Imp * Rs) / a) \ | ||
+ (Vmp + Imp * Rs) / Rsh | ||
|
||
# 4th equation - Pmp derivated=0 - eq23.2.6 in [2] | ||
# caution: eq(6) in [1] has a sign error | ||
y[3] = Imp \ | ||
- Vmp * ((Io / a) * np.exp((Vmp + Imp * Rs) / a) + 1.0 / Rsh) \ | ||
/ (1.0 + (Io * Rs / a) * np.exp((Vmp + Imp * Rs) / a) + Rs / Rsh) | ||
|
||
# 5th equation - open-circuit T2 - eq (4) at temperature T2 in [1] | ||
T2 = Tref + 2 | ||
Voc2 = (T2 - Tref) * beta_oc + Voc # eq (7) in [1] | ||
a2 = a * T2 / Tref # eq (8) in [1] | ||
IL2 = IL + alpha_sc * (T2 - Tref) # eq (11) in [1] | ||
Eg2 = EgRef * (1 + dEgdT * (T2 - Tref)) # eq (10) in [1] | ||
Io2 = Io * (T2 / Tref)**3 * np.exp(1 / k * (EgRef/Tref - Eg2/T2)) # eq (9) | ||
y[4] = -IL2 + Io2 * np.expm1(Voc2 / a2) + Voc2 / Rsh # eq (4) at T2 | ||
|
||
return y |
Uh oh!
There was an error while loading. Please reload this page.