pvlib 0.12.0__py3-none-any.whl → 0.13.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pvlib/atmosphere.py +40 -31
- pvlib/bifacial/infinite_sheds.py +11 -16
- pvlib/iotools/__init__.py +5 -0
- pvlib/iotools/bsrn.py +16 -10
- pvlib/iotools/epw.py +14 -11
- pvlib/iotools/psm3.py +37 -71
- pvlib/iotools/psm4.py +766 -0
- pvlib/iotools/pvgis.py +116 -101
- pvlib/iotools/sodapro.py +54 -69
- pvlib/iotools/srml.py +1 -2
- pvlib/irradiance.py +28 -19
- pvlib/ivtools/sdm/__init__.py +20 -0
- pvlib/ivtools/sdm/_fit_desoto_pvsyst_sandia.py +585 -0
- pvlib/ivtools/sdm/cec.py +93 -0
- pvlib/ivtools/sdm/desoto.py +401 -0
- pvlib/ivtools/sdm/pvsyst.py +630 -0
- pvlib/modelchain.py +1 -1
- pvlib/pvsystem.py +130 -69
- pvlib/solarposition.py +1 -1
- pvlib/spectrum/irradiance.py +2 -1
- pvlib/temperature.py +13 -10
- pvlib/tools.py +27 -0
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/METADATA +2 -3
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/RECORD +28 -23
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/WHEEL +1 -1
- pvlib/ivtools/sdm.py +0 -1379
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/licenses/AUTHORS.md +0 -0
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/licenses/LICENSE +0 -0
- {pvlib-0.12.0.dist-info → pvlib-0.13.0.dist-info}/top_level.txt +0 -0
pvlib/ivtools/sdm.py
DELETED
|
@@ -1,1379 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
The ``sdm`` module contains functions to fit single diode models.
|
|
3
|
-
|
|
4
|
-
Function names should follow the pattern "fit_" + name of model + "_" +
|
|
5
|
-
fitting method.
|
|
6
|
-
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import numpy as np
|
|
10
|
-
|
|
11
|
-
from scipy import constants
|
|
12
|
-
from scipy import optimize
|
|
13
|
-
from scipy.special import lambertw
|
|
14
|
-
|
|
15
|
-
from pvlib.pvsystem import calcparams_pvsyst, singlediode, v_from_i
|
|
16
|
-
from pvlib.singlediode import bishop88_mpp
|
|
17
|
-
|
|
18
|
-
from pvlib.ivtools.utils import rectify_iv_curve, _numdiff
|
|
19
|
-
from pvlib.ivtools.sde import _fit_sandia_cocontent
|
|
20
|
-
|
|
21
|
-
from pvlib.tools import _first_order_centered_difference
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
CONSTANTS = {'E0': 1000.0, 'T0': 25.0, 'k': constants.k, 'q': constants.e}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def fit_cec_sam(celltype, v_mp, i_mp, v_oc, i_sc, alpha_sc, beta_voc,
|
|
28
|
-
gamma_pmp, cells_in_series, temp_ref=25):
|
|
29
|
-
"""
|
|
30
|
-
Estimates parameters for the CEC single diode model (SDM) using the SAM
|
|
31
|
-
SDK.
|
|
32
|
-
|
|
33
|
-
Parameters
|
|
34
|
-
----------
|
|
35
|
-
celltype : str
|
|
36
|
-
Value is one of 'monoSi', 'multiSi', 'polySi', 'cis', 'cigs', 'cdte',
|
|
37
|
-
'amorphous'
|
|
38
|
-
v_mp : float
|
|
39
|
-
Voltage at maximum power point [V]
|
|
40
|
-
i_mp : float
|
|
41
|
-
Current at maximum power point [A]
|
|
42
|
-
v_oc : float
|
|
43
|
-
Open circuit voltage [V]
|
|
44
|
-
i_sc : float
|
|
45
|
-
Short circuit current [A]
|
|
46
|
-
alpha_sc : float
|
|
47
|
-
Temperature coefficient of short circuit current [A/C]
|
|
48
|
-
beta_voc : float
|
|
49
|
-
Temperature coefficient of open circuit voltage [V/C]
|
|
50
|
-
gamma_pmp : float
|
|
51
|
-
Temperature coefficient of power at maximum power point [%/C]
|
|
52
|
-
cells_in_series : int
|
|
53
|
-
Number of cells in series
|
|
54
|
-
temp_ref : float, default 25
|
|
55
|
-
Reference temperature condition [C]
|
|
56
|
-
|
|
57
|
-
Returns
|
|
58
|
-
-------
|
|
59
|
-
I_L_ref : float
|
|
60
|
-
The light-generated current (or photocurrent) at reference
|
|
61
|
-
conditions [A]
|
|
62
|
-
I_o_ref : float
|
|
63
|
-
The dark or diode reverse saturation current at reference
|
|
64
|
-
conditions [A]
|
|
65
|
-
R_s : float
|
|
66
|
-
The series resistance at reference conditions, in ohms.
|
|
67
|
-
R_sh_ref : float
|
|
68
|
-
The shunt resistance at reference conditions, in ohms.
|
|
69
|
-
a_ref : float
|
|
70
|
-
The product of the usual diode ideality factor ``n`` (unitless),
|
|
71
|
-
number of cells in series ``Ns``, and cell thermal voltage at
|
|
72
|
-
reference conditions [V]
|
|
73
|
-
Adjust : float
|
|
74
|
-
The adjustment to the temperature coefficient for short circuit
|
|
75
|
-
current, in percent.
|
|
76
|
-
|
|
77
|
-
Raises
|
|
78
|
-
------
|
|
79
|
-
ImportError
|
|
80
|
-
if NREL-PySAM is not installed.
|
|
81
|
-
RuntimeError
|
|
82
|
-
if parameter extraction is not successful.
|
|
83
|
-
|
|
84
|
-
Notes
|
|
85
|
-
-----
|
|
86
|
-
The CEC model and estimation method are described in [1]_.
|
|
87
|
-
Inputs ``v_mp``, ``i_mp``, ``v_oc`` and ``i_sc`` are assumed to be from a
|
|
88
|
-
single IV curve at constant irradiance and cell temperature. Irradiance is
|
|
89
|
-
not explicitly used by the fitting procedure. The irradiance level at which
|
|
90
|
-
the input IV curve is determined and the specified cell temperature
|
|
91
|
-
``temp_ref`` are the reference conditions for the output parameters
|
|
92
|
-
``I_L_ref``, ``I_o_ref``, ``R_s``, ``R_sh_ref``, ``a_ref`` and ``Adjust``.
|
|
93
|
-
|
|
94
|
-
References
|
|
95
|
-
----------
|
|
96
|
-
.. [1] A. Dobos, "An Improved Coefficient Calculator for the California
|
|
97
|
-
Energy Commission 6 Parameter Photovoltaic Module Model", Journal of
|
|
98
|
-
Solar Energy Engineering, vol 134, 2012. :doi:`10.1115/1.4005759`
|
|
99
|
-
"""
|
|
100
|
-
|
|
101
|
-
try:
|
|
102
|
-
from PySAM import PySSC
|
|
103
|
-
except ImportError:
|
|
104
|
-
raise ImportError("Requires NREL's PySAM package at "
|
|
105
|
-
"https://pypi.org/project/NREL-PySAM/.")
|
|
106
|
-
|
|
107
|
-
datadict = {'tech_model': '6parsolve', 'financial_model': None,
|
|
108
|
-
'celltype': celltype, 'Vmp': v_mp,
|
|
109
|
-
'Imp': i_mp, 'Voc': v_oc, 'Isc': i_sc, 'alpha_isc': alpha_sc,
|
|
110
|
-
'beta_voc': beta_voc, 'gamma_pmp': gamma_pmp,
|
|
111
|
-
'Nser': cells_in_series, 'Tref': temp_ref}
|
|
112
|
-
|
|
113
|
-
result = PySSC.ssc_sim_from_dict(datadict)
|
|
114
|
-
if result['cmod_success'] == 1:
|
|
115
|
-
return tuple([result[k] for k in ['Il', 'Io', 'Rs', 'Rsh', 'a',
|
|
116
|
-
'Adj']])
|
|
117
|
-
else:
|
|
118
|
-
raise RuntimeError('Parameter estimation failed')
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def fit_desoto(v_mp, i_mp, v_oc, i_sc, alpha_sc, beta_voc, cells_in_series,
|
|
122
|
-
EgRef=1.121, dEgdT=-0.0002677, temp_ref=25, irrad_ref=1000,
|
|
123
|
-
init_guess={}, root_kwargs={}):
|
|
124
|
-
"""
|
|
125
|
-
Calculates the parameters for the De Soto single diode model.
|
|
126
|
-
|
|
127
|
-
This procedure (described in [1]_) fits the De Soto model [2]_ using
|
|
128
|
-
common specifications given by manufacturers in the
|
|
129
|
-
datasheets of PV modules.
|
|
130
|
-
|
|
131
|
-
The solution is found using :py:func:`scipy.optimize.root`,
|
|
132
|
-
with the default solver method 'hybr'.
|
|
133
|
-
No restriction is put on the fit variables, e.g. series
|
|
134
|
-
or shunt resistance could go negative. Nevertheless, if it happens,
|
|
135
|
-
check carefully the inputs and their units. For example, ``alpha_sc`` and
|
|
136
|
-
``beta_voc`` are often given in %/K in manufacturers datasheets but should
|
|
137
|
-
be given in A/K and V/K here.
|
|
138
|
-
|
|
139
|
-
The parameters returned by this function can be used by
|
|
140
|
-
:py:func:`pvlib.pvsystem.calcparams_desoto` to calculate single diode
|
|
141
|
-
equation parameters at different irradiance and cell temperature.
|
|
142
|
-
|
|
143
|
-
Parameters
|
|
144
|
-
----------
|
|
145
|
-
v_mp: float
|
|
146
|
-
Module voltage at the maximum-power point at reference conditions. [V]
|
|
147
|
-
i_mp: float
|
|
148
|
-
Module current at the maximum-power point at reference conditions. [A]
|
|
149
|
-
v_oc: float
|
|
150
|
-
Open-circuit voltage at reference conditions. [V]
|
|
151
|
-
i_sc: float
|
|
152
|
-
Short-circuit current at reference conditions. [A]
|
|
153
|
-
alpha_sc: float
|
|
154
|
-
The short-circuit current (``i_sc``) temperature coefficient of the
|
|
155
|
-
module. [A/K]
|
|
156
|
-
beta_voc: float
|
|
157
|
-
The open-circuit voltage (``v_oc``) temperature coefficient of the
|
|
158
|
-
module. [V/K]
|
|
159
|
-
cells_in_series: integer
|
|
160
|
-
Number of cell in the module.
|
|
161
|
-
EgRef: float, default 1.121 eV - value for silicon
|
|
162
|
-
Energy of bandgap of semi-conductor used. [eV]
|
|
163
|
-
dEgdT: float, default -0.0002677 - value for silicon
|
|
164
|
-
Variation of bandgap according to temperature. [1/K]
|
|
165
|
-
temp_ref: float, default 25
|
|
166
|
-
Reference temperature condition. [C]
|
|
167
|
-
irrad_ref: float, default 1000
|
|
168
|
-
Reference irradiance condition. [Wm⁻²]
|
|
169
|
-
init_guess: dict, optional
|
|
170
|
-
Initial values for optimization. Keys can be `'Rsh_0'`, `'a_0'`,
|
|
171
|
-
`'IL_0'`, `'Io_0'`, `'Rs_0'`.
|
|
172
|
-
root_kwargs : dictionary, optional
|
|
173
|
-
Dictionary of arguments to pass onto scipy.optimize.root()
|
|
174
|
-
|
|
175
|
-
Returns
|
|
176
|
-
-------
|
|
177
|
-
dict with the following elements:
|
|
178
|
-
I_L_ref: float
|
|
179
|
-
Light-generated current at reference conditions. [A]
|
|
180
|
-
I_o_ref: float
|
|
181
|
-
Diode saturation current at reference conditions. [A]
|
|
182
|
-
R_s: float
|
|
183
|
-
Series resistance. [ohm]
|
|
184
|
-
R_sh_ref: float
|
|
185
|
-
Shunt resistance at reference conditions. [ohm].
|
|
186
|
-
a_ref: float
|
|
187
|
-
Modified ideality factor at reference conditions.
|
|
188
|
-
The product of the usual diode ideality factor (n, unitless),
|
|
189
|
-
number of cells in series (Ns), and cell thermal voltage at
|
|
190
|
-
specified effective irradiance and cell temperature.
|
|
191
|
-
alpha_sc: float
|
|
192
|
-
The short-circuit current (i_sc) temperature coefficient of the
|
|
193
|
-
module. [A/K]
|
|
194
|
-
EgRef: float
|
|
195
|
-
Energy of bandgap of semi-conductor used. [eV]
|
|
196
|
-
dEgdT: float
|
|
197
|
-
Variation of bandgap according to temperature. [1/K]
|
|
198
|
-
irrad_ref: float
|
|
199
|
-
Reference irradiance condition. [Wm⁻²]
|
|
200
|
-
temp_ref: float
|
|
201
|
-
Reference temperature condition. [C]
|
|
202
|
-
|
|
203
|
-
scipy.optimize.OptimizeResult
|
|
204
|
-
Optimization result of scipy.optimize.root().
|
|
205
|
-
See scipy.optimize.OptimizeResult for more details.
|
|
206
|
-
|
|
207
|
-
References
|
|
208
|
-
----------
|
|
209
|
-
.. [1] J. A Duffie, W. A Beckman, "Solar Engineering of Thermal Processes",
|
|
210
|
-
4th ed., Wiley, 2013. :doi:`10.1002/9781118671603`
|
|
211
|
-
.. [2] W. De Soto et al., "Improvement and validation of a model for
|
|
212
|
-
photovoltaic array performance", Solar Energy, vol 80, pp. 78-88,
|
|
213
|
-
2006. :doi:`10.1016/j.solener.2005.06.010`
|
|
214
|
-
|
|
215
|
-
"""
|
|
216
|
-
|
|
217
|
-
# Constants
|
|
218
|
-
k = constants.value('Boltzmann constant in eV/K') # in eV/K
|
|
219
|
-
Tref = temp_ref + 273.15 # [K]
|
|
220
|
-
|
|
221
|
-
# initial guesses of variables for computing convergence:
|
|
222
|
-
# Default values are taken from [1], p753
|
|
223
|
-
init_guess_keys = ['IL_0', 'Io_0', 'Rs_0', 'Rsh_0', 'a_0'] # order matters
|
|
224
|
-
init = {key: None for key in init_guess_keys}
|
|
225
|
-
init['IL_0'] = i_sc
|
|
226
|
-
init['a_0'] = 1.5*k*Tref*cells_in_series
|
|
227
|
-
init['Io_0'] = i_sc * np.exp(-v_oc/init['a_0'])
|
|
228
|
-
init['Rs_0'] = (init['a_0']*np.log1p((init['IL_0'] - i_mp)/init['Io_0'])
|
|
229
|
-
- v_mp) / i_mp
|
|
230
|
-
init['Rsh_0'] = 100.0
|
|
231
|
-
# overwrite if optional init_guess is provided
|
|
232
|
-
for key in init_guess:
|
|
233
|
-
if key in init_guess_keys:
|
|
234
|
-
init[key] = init_guess[key]
|
|
235
|
-
else:
|
|
236
|
-
raise ValueError(f"'{key}' is not a valid name;"
|
|
237
|
-
f" allowed values are {init_guess_keys}")
|
|
238
|
-
# params_i : initial values vector
|
|
239
|
-
params_i = np.array([init[k] for k in init_guess_keys])
|
|
240
|
-
|
|
241
|
-
# specs of module
|
|
242
|
-
specs = (i_sc, v_oc, i_mp, v_mp, beta_voc, alpha_sc, EgRef, dEgdT,
|
|
243
|
-
Tref, k)
|
|
244
|
-
|
|
245
|
-
# computing with system of equations described in [1]
|
|
246
|
-
optimize_result = optimize.root(_system_of_equations_desoto, x0=params_i,
|
|
247
|
-
args=(specs,), **root_kwargs)
|
|
248
|
-
|
|
249
|
-
if optimize_result.success:
|
|
250
|
-
sdm_params = optimize_result.x
|
|
251
|
-
else:
|
|
252
|
-
raise RuntimeError(
|
|
253
|
-
'Parameter estimation failed:\n' + optimize_result.message)
|
|
254
|
-
|
|
255
|
-
# results
|
|
256
|
-
return ({'I_L_ref': sdm_params[0],
|
|
257
|
-
'I_o_ref': sdm_params[1],
|
|
258
|
-
'R_s': sdm_params[2],
|
|
259
|
-
'R_sh_ref': sdm_params[3],
|
|
260
|
-
'a_ref': sdm_params[4],
|
|
261
|
-
'alpha_sc': alpha_sc,
|
|
262
|
-
'EgRef': EgRef,
|
|
263
|
-
'dEgdT': dEgdT,
|
|
264
|
-
'irrad_ref': irrad_ref,
|
|
265
|
-
'temp_ref': temp_ref},
|
|
266
|
-
optimize_result)
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
def _system_of_equations_desoto(params, specs):
|
|
270
|
-
"""Evaluates the systems of equations used to solve for the single
|
|
271
|
-
diode equation parameters. Function designed to be used by
|
|
272
|
-
scipy.optimize.root in fit_desoto.
|
|
273
|
-
|
|
274
|
-
Parameters
|
|
275
|
-
----------
|
|
276
|
-
params: ndarray
|
|
277
|
-
Array with parameters of the De Soto single diode model. Must be
|
|
278
|
-
given in the following order: IL, Io, a, Rs, Rsh
|
|
279
|
-
specs: tuple
|
|
280
|
-
Specifications of pv module given by manufacturer. Must be given
|
|
281
|
-
in the following order: Isc, Voc, Imp, Vmp, beta_oc, alpha_sc
|
|
282
|
-
|
|
283
|
-
Returns
|
|
284
|
-
-------
|
|
285
|
-
value of the system of equations to solve with scipy.optimize.root().
|
|
286
|
-
"""
|
|
287
|
-
|
|
288
|
-
# six input known variables
|
|
289
|
-
Isc, Voc, Imp, Vmp, beta_oc, alpha_sc, EgRef, dEgdT, Tref, k = specs
|
|
290
|
-
|
|
291
|
-
# five parameters vector to find
|
|
292
|
-
IL, Io, Rs, Rsh, a = params
|
|
293
|
-
|
|
294
|
-
# five equation vector
|
|
295
|
-
y = [0, 0, 0, 0, 0]
|
|
296
|
-
|
|
297
|
-
# 1st equation - short-circuit - eq(3) in [1]
|
|
298
|
-
y[0] = Isc - IL + Io * np.expm1(Isc * Rs / a) + Isc * Rs / Rsh
|
|
299
|
-
|
|
300
|
-
# 2nd equation - open-circuit Tref - eq(4) in [1]
|
|
301
|
-
y[1] = -IL + Io * np.expm1(Voc / a) + Voc / Rsh
|
|
302
|
-
|
|
303
|
-
# 3rd equation - Imp & Vmp - eq(5) in [1]
|
|
304
|
-
y[2] = Imp - IL + Io * np.expm1((Vmp + Imp * Rs) / a) \
|
|
305
|
-
+ (Vmp + Imp * Rs) / Rsh
|
|
306
|
-
|
|
307
|
-
# 4th equation - Pmp derivated=0 - eq23.2.6 in [2]
|
|
308
|
-
# caution: eq(6) in [1] has a sign error
|
|
309
|
-
y[3] = Imp \
|
|
310
|
-
- Vmp * ((Io / a) * np.exp((Vmp + Imp * Rs) / a) + 1.0 / Rsh) \
|
|
311
|
-
/ (1.0 + (Io * Rs / a) * np.exp((Vmp + Imp * Rs) / a) + Rs / Rsh)
|
|
312
|
-
|
|
313
|
-
# 5th equation - open-circuit T2 - eq (4) at temperature T2 in [1]
|
|
314
|
-
T2 = Tref + 2
|
|
315
|
-
Voc2 = (T2 - Tref) * beta_oc + Voc # eq (7) in [1]
|
|
316
|
-
a2 = a * T2 / Tref # eq (8) in [1]
|
|
317
|
-
IL2 = IL + alpha_sc * (T2 - Tref) # eq (11) in [1]
|
|
318
|
-
Eg2 = EgRef * (1 + dEgdT * (T2 - Tref)) # eq (10) in [1]
|
|
319
|
-
Io2 = Io * (T2 / Tref)**3 * np.exp(1 / k * (EgRef/Tref - Eg2/T2)) # eq (9)
|
|
320
|
-
y[4] = -IL2 + Io2 * np.expm1(Voc2 / a2) + Voc2 / Rsh # eq (4) at T2
|
|
321
|
-
|
|
322
|
-
return y
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
def fit_pvsyst_sandia(ivcurves, specs, const=None, maxiter=5, eps1=1.e-3):
|
|
326
|
-
"""
|
|
327
|
-
Estimate parameters for the PVsyst module performance model.
|
|
328
|
-
|
|
329
|
-
Parameters
|
|
330
|
-
----------
|
|
331
|
-
ivcurves : dict
|
|
332
|
-
i : array
|
|
333
|
-
One array element for each IV curve. The jth element is itself an
|
|
334
|
-
array of current for jth IV curve (same length as v[j]) [A]
|
|
335
|
-
v : array
|
|
336
|
-
One array element for each IV curve. The jth element is itself an
|
|
337
|
-
array of voltage for jth IV curve (same length as i[j]) [V]
|
|
338
|
-
ee : array
|
|
339
|
-
effective irradiance for each IV curve, i.e., POA broadband
|
|
340
|
-
irradiance adjusted by solar spectrum modifier [W / m^2]
|
|
341
|
-
tc : array
|
|
342
|
-
cell temperature for each IV curve [C]
|
|
343
|
-
i_sc : array
|
|
344
|
-
short circuit current for each IV curve [A]
|
|
345
|
-
v_oc : array
|
|
346
|
-
open circuit voltage for each IV curve [V]
|
|
347
|
-
i_mp : array
|
|
348
|
-
current at max power point for each IV curve [A]
|
|
349
|
-
v_mp : array
|
|
350
|
-
voltage at max power point for each IV curve [V]
|
|
351
|
-
|
|
352
|
-
specs : dict
|
|
353
|
-
cells_in_series : int
|
|
354
|
-
number of cells in series
|
|
355
|
-
alpha_sc : float
|
|
356
|
-
temperature coefficient of isc [A/C]
|
|
357
|
-
|
|
358
|
-
const : dict
|
|
359
|
-
E0 : float
|
|
360
|
-
effective irradiance at STC, default 1000 [W/m^2]
|
|
361
|
-
T0 : float
|
|
362
|
-
cell temperature at STC, default 25 [C]
|
|
363
|
-
k : float
|
|
364
|
-
Boltzmann's constant [J/K]
|
|
365
|
-
q : float
|
|
366
|
-
elementary charge [Coulomb]
|
|
367
|
-
|
|
368
|
-
maxiter : int, default 5
|
|
369
|
-
input that sets the maximum number of iterations for the parameter
|
|
370
|
-
updating part of the algorithm.
|
|
371
|
-
|
|
372
|
-
eps1: float, default 1e-3
|
|
373
|
-
Tolerance for the IV curve fitting. The parameter updating stops when
|
|
374
|
-
absolute values of the percent change in mean, max and standard
|
|
375
|
-
deviation of Imp, Vmp and Pmp between iterations are all less than
|
|
376
|
-
eps1, or when the number of iterations exceeds maxiter.
|
|
377
|
-
|
|
378
|
-
Returns
|
|
379
|
-
-------
|
|
380
|
-
dict
|
|
381
|
-
I_L_ref : float
|
|
382
|
-
light current at STC [A]
|
|
383
|
-
I_o_ref : float
|
|
384
|
-
dark current at STC [A]
|
|
385
|
-
EgRef : float
|
|
386
|
-
effective band gap at STC [eV]
|
|
387
|
-
R_s : float
|
|
388
|
-
series resistance at STC [ohm]
|
|
389
|
-
R_sh_ref : float
|
|
390
|
-
shunt resistance at STC [ohm]
|
|
391
|
-
R_sh_0 : float
|
|
392
|
-
shunt resistance at zero irradiance [ohm]
|
|
393
|
-
R_sh_exp : float
|
|
394
|
-
exponential factor defining decrease in shunt resistance with
|
|
395
|
-
increasing effective irradiance
|
|
396
|
-
gamma_ref : float
|
|
397
|
-
diode (ideality) factor at STC [unitless]
|
|
398
|
-
mu_gamma : float
|
|
399
|
-
temperature coefficient for diode (ideality) factor [1/K]
|
|
400
|
-
cells_in_series : int
|
|
401
|
-
number of cells in series
|
|
402
|
-
iph : array
|
|
403
|
-
light current for each IV curve [A]
|
|
404
|
-
io : array
|
|
405
|
-
dark current for each IV curve [A]
|
|
406
|
-
rs : array
|
|
407
|
-
series resistance for each IV curve [ohm]
|
|
408
|
-
rsh : array
|
|
409
|
-
shunt resistance for each IV curve [ohm]
|
|
410
|
-
u : array
|
|
411
|
-
boolean for each IV curve indicating that the parameter values
|
|
412
|
-
are deemed reasonable by the private function ``_filter_params``
|
|
413
|
-
|
|
414
|
-
Notes
|
|
415
|
-
-----
|
|
416
|
-
The PVsyst module performance model is described in [1]_, [2]_, and [3]_.
|
|
417
|
-
The fitting method is documented in [4]_, [5]_, and [6]_.
|
|
418
|
-
Ported from PVLib Matlab [7]_.
|
|
419
|
-
|
|
420
|
-
References
|
|
421
|
-
----------
|
|
422
|
-
.. [1] K. Sauer, T. Roessler, C. W. Hansen, Modeling the Irradiance and
|
|
423
|
-
Temperature Dependence of Photovoltaic Modules in PVsyst, IEEE Journal
|
|
424
|
-
of Photovoltaics v5(1), January 2015.
|
|
425
|
-
:doi:`10.1109/JPHOTOV.2014.2364133`
|
|
426
|
-
.. [2] A. Mermoud, PV Modules modeling, Presentation at the 2nd PV
|
|
427
|
-
Performance Modeling Workshop, Santa Clara, CA, May 2013
|
|
428
|
-
.. [3] A. Mermoud, T. Lejeuene, Performance Assessment of a Simulation
|
|
429
|
-
Model for PV modules of any available technology, 25th European
|
|
430
|
-
Photovoltaic Solar Energy Conference, Valencia, Spain, Sept. 2010
|
|
431
|
-
.. [4] C. Hansen, Estimating Parameters for the PVsyst Version 6
|
|
432
|
-
Photovoltaic Module Performance Model, Sandia National Laboratories
|
|
433
|
-
Report SAND2015-8598. :doi:`10.2172/1223058`
|
|
434
|
-
.. [5] C. Hansen, Parameter Estimation for Single Diode Models of
|
|
435
|
-
Photovoltaic Modules, Sandia National Laboratories Report SAND2015-2065.
|
|
436
|
-
:doi:`10.2172/1177157`
|
|
437
|
-
.. [6] C. Hansen, Estimation of Parameters for Single Diode Models using
|
|
438
|
-
Measured IV Curves, Proc. of the 39th IEEE PVSC, June 2013.
|
|
439
|
-
:doi:`10.1109/PVSC.2013.6744135`
|
|
440
|
-
.. [7] PVLib MATLAB https://github.com/sandialabs/MATLAB_PV_LIB
|
|
441
|
-
"""
|
|
442
|
-
|
|
443
|
-
if const is None:
|
|
444
|
-
const = CONSTANTS
|
|
445
|
-
|
|
446
|
-
ee = ivcurves['ee']
|
|
447
|
-
tc = ivcurves['tc']
|
|
448
|
-
tck = tc + 273.15
|
|
449
|
-
isc = ivcurves['i_sc']
|
|
450
|
-
voc = ivcurves['v_oc']
|
|
451
|
-
imp = ivcurves['i_mp']
|
|
452
|
-
vmp = ivcurves['v_mp']
|
|
453
|
-
|
|
454
|
-
# Cell Thermal Voltage
|
|
455
|
-
vth = const['k'] / const['q'] * tck
|
|
456
|
-
|
|
457
|
-
n = len(ivcurves['v_oc'])
|
|
458
|
-
|
|
459
|
-
# Initial estimate of Rsh used to obtain the diode factor gamma0 and diode
|
|
460
|
-
# temperature coefficient mu_gamma. Rsh is estimated using the co-content
|
|
461
|
-
# integral method.
|
|
462
|
-
|
|
463
|
-
rsh = np.ones(n)
|
|
464
|
-
for j in range(n):
|
|
465
|
-
voltage, current = rectify_iv_curve(ivcurves['v'][j], ivcurves['i'][j])
|
|
466
|
-
# initial estimate of Rsh, from integral over voltage regression
|
|
467
|
-
# [5] Step 3a; [6] Step 3a
|
|
468
|
-
_, _, _, rsh[j], _ = _fit_sandia_cocontent(
|
|
469
|
-
voltage, current, vth[j] * specs['cells_in_series'])
|
|
470
|
-
|
|
471
|
-
gamma_ref, mu_gamma = _fit_pvsyst_sandia_gamma(voc, isc, rsh, vth, tck,
|
|
472
|
-
specs, const)
|
|
473
|
-
|
|
474
|
-
badgamma = np.isnan(gamma_ref) or np.isnan(mu_gamma) \
|
|
475
|
-
or not np.isreal(gamma_ref) or not np.isreal(mu_gamma)
|
|
476
|
-
|
|
477
|
-
if badgamma:
|
|
478
|
-
raise RuntimeError(
|
|
479
|
-
"Failed to estimate the diode (ideality) factor parameter;"
|
|
480
|
-
" aborting parameter estimation.")
|
|
481
|
-
|
|
482
|
-
gamma = gamma_ref + mu_gamma * (tc - const['T0'])
|
|
483
|
-
nnsvth = gamma * (vth * specs['cells_in_series'])
|
|
484
|
-
|
|
485
|
-
# For each IV curve, sequentially determine initial values for Io, Rs,
|
|
486
|
-
# and Iph [5] Step 3a; [6] Step 3
|
|
487
|
-
iph, io, rs, u = _initial_iv_params(ivcurves, ee, voc, isc, rsh,
|
|
488
|
-
nnsvth)
|
|
489
|
-
|
|
490
|
-
# Update values for each IV curve to converge at vmp, imp, voc and isc
|
|
491
|
-
iph, io, rs, rsh, u = _update_iv_params(voc, isc, vmp, imp, ee,
|
|
492
|
-
iph, io, rs, rsh, nnsvth, u,
|
|
493
|
-
maxiter, eps1)
|
|
494
|
-
|
|
495
|
-
# get single diode models from converged values for each IV curve
|
|
496
|
-
pvsyst = _extract_sdm_params(ee, tc, iph, io, rs, rsh, gamma, u,
|
|
497
|
-
specs, const, model='pvsyst')
|
|
498
|
-
# Add parameters estimated in this function
|
|
499
|
-
pvsyst['gamma_ref'] = gamma_ref
|
|
500
|
-
pvsyst['mu_gamma'] = mu_gamma
|
|
501
|
-
pvsyst['cells_in_series'] = specs['cells_in_series']
|
|
502
|
-
|
|
503
|
-
return pvsyst
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
def fit_desoto_sandia(ivcurves, specs, const=None, maxiter=5, eps1=1.e-3):
|
|
507
|
-
"""
|
|
508
|
-
Estimate parameters for the De Soto module performance model.
|
|
509
|
-
|
|
510
|
-
Parameters
|
|
511
|
-
----------
|
|
512
|
-
ivcurves : dict
|
|
513
|
-
i : array
|
|
514
|
-
One array element for each IV curve. The jth element is itself an
|
|
515
|
-
array of current for jth IV curve (same length as v[j]) [A]
|
|
516
|
-
v : array
|
|
517
|
-
One array element for each IV curve. The jth element is itself an
|
|
518
|
-
array of voltage for jth IV curve (same length as i[j]) [V]
|
|
519
|
-
ee : array
|
|
520
|
-
effective irradiance for each IV curve, i.e., POA broadband
|
|
521
|
-
irradiance adjusted by solar spectrum modifier [W / m^2]
|
|
522
|
-
tc : array
|
|
523
|
-
cell temperature for each IV curve [C]
|
|
524
|
-
i_sc : array
|
|
525
|
-
short circuit current for each IV curve [A]
|
|
526
|
-
v_oc : array
|
|
527
|
-
open circuit voltage for each IV curve [V]
|
|
528
|
-
i_mp : array
|
|
529
|
-
current at max power point for each IV curve [A]
|
|
530
|
-
v_mp : array
|
|
531
|
-
voltage at max power point for each IV curve [V]
|
|
532
|
-
|
|
533
|
-
specs : dict
|
|
534
|
-
cells_in_series : int
|
|
535
|
-
number of cells in series
|
|
536
|
-
alpha_sc : float
|
|
537
|
-
temperature coefficient of Isc [A/C]
|
|
538
|
-
beta_voc : float
|
|
539
|
-
temperature coefficient of Voc [V/C]
|
|
540
|
-
|
|
541
|
-
const : dict
|
|
542
|
-
E0 : float
|
|
543
|
-
effective irradiance at STC, default 1000 [W/m^2]
|
|
544
|
-
T0 : float
|
|
545
|
-
cell temperature at STC, default 25 [C]
|
|
546
|
-
k : float
|
|
547
|
-
Boltzmann's constant [J/K]
|
|
548
|
-
q : float
|
|
549
|
-
elementary charge [Coulomb]
|
|
550
|
-
|
|
551
|
-
maxiter : int, default 5
|
|
552
|
-
input that sets the maximum number of iterations for the parameter
|
|
553
|
-
updating part of the algorithm.
|
|
554
|
-
|
|
555
|
-
eps1: float, default 1e-3
|
|
556
|
-
Tolerance for the IV curve fitting. The parameter updating stops when
|
|
557
|
-
absolute values of the percent change in mean, max and standard
|
|
558
|
-
deviation of Imp, Vmp and Pmp between iterations are all less than
|
|
559
|
-
eps1, or when the number of iterations exceeds maxiter.
|
|
560
|
-
|
|
561
|
-
Returns
|
|
562
|
-
-------
|
|
563
|
-
dict
|
|
564
|
-
I_L_ref : float
|
|
565
|
-
Light current at STC [A]
|
|
566
|
-
I_o_ref : float
|
|
567
|
-
Dark current at STC [A]
|
|
568
|
-
EgRef : float
|
|
569
|
-
Effective band gap at STC [eV]
|
|
570
|
-
R_s : float
|
|
571
|
-
Series resistance at STC [ohm]
|
|
572
|
-
R_sh_ref : float
|
|
573
|
-
Shunt resistance at STC [ohm]
|
|
574
|
-
cells_in_series : int
|
|
575
|
-
Number of cells in series
|
|
576
|
-
iph : array
|
|
577
|
-
Light current for each IV curve [A]
|
|
578
|
-
io : array
|
|
579
|
-
Dark current for each IV curve [A]
|
|
580
|
-
rs : array
|
|
581
|
-
Series resistance for each IV curve [ohm]
|
|
582
|
-
rsh : array
|
|
583
|
-
Shunt resistance for each IV curve [ohm]
|
|
584
|
-
a_ref : float
|
|
585
|
-
The product of the usual diode ideality factor (n, unitless),
|
|
586
|
-
number of cells in series (Ns), and cell thermal voltage at
|
|
587
|
-
reference conditions, in units of V.
|
|
588
|
-
dEgdT : float
|
|
589
|
-
The temperature dependence of the energy bandgap (Eg) at reference
|
|
590
|
-
conditions [1/K].
|
|
591
|
-
u : array
|
|
592
|
-
Boolean for each IV curve indicating that the parameter values
|
|
593
|
-
are deemed reasonable by the private function ``_filter_params``
|
|
594
|
-
|
|
595
|
-
Notes
|
|
596
|
-
-----
|
|
597
|
-
The De Soto module performance model is described in [1]_. The fitting
|
|
598
|
-
method is documented in [2]_, [3]_. Ported from PVLib Matlab [4]_.
|
|
599
|
-
|
|
600
|
-
References
|
|
601
|
-
----------
|
|
602
|
-
.. [1] W. De Soto et al., "Improvement and validation of a model for
|
|
603
|
-
photovoltaic array performance", Solar Energy, vol 80, pp. 78-88,
|
|
604
|
-
2006. :doi:`10.1016/j.solener.2005.06.010`
|
|
605
|
-
.. [2] C. Hansen, Parameter Estimation for Single Diode Models of
|
|
606
|
-
Photovoltaic Modules, Sandia National Laboratories Report SAND2015-2065.
|
|
607
|
-
:doi:`10.2172/1177157`
|
|
608
|
-
.. [3] C. Hansen, Estimation of Parameters for Single Diode Models using
|
|
609
|
-
Measured IV Curves, Proc. of the 39th IEEE PVSC, June 2013.
|
|
610
|
-
:doi:`10.1109/PVSC.2013.6744135`
|
|
611
|
-
.. [4] PVLib MATLAB https://github.com/sandialabs/MATLAB_PV_LIB
|
|
612
|
-
"""
|
|
613
|
-
|
|
614
|
-
if const is None:
|
|
615
|
-
const = CONSTANTS
|
|
616
|
-
|
|
617
|
-
ee = ivcurves['ee']
|
|
618
|
-
tc = ivcurves['tc']
|
|
619
|
-
tck = tc + 273.15
|
|
620
|
-
isc = ivcurves['i_sc']
|
|
621
|
-
voc = ivcurves['v_oc']
|
|
622
|
-
imp = ivcurves['i_mp']
|
|
623
|
-
vmp = ivcurves['v_mp']
|
|
624
|
-
|
|
625
|
-
# Cell Thermal Voltage
|
|
626
|
-
vth = const['k'] / const['q'] * tck
|
|
627
|
-
|
|
628
|
-
n = len(voc)
|
|
629
|
-
|
|
630
|
-
# Initial estimate of Rsh used to obtain the diode factor gamma0 and diode
|
|
631
|
-
# temperature coefficient mu_gamma. Rsh is estimated using the co-content
|
|
632
|
-
# integral method.
|
|
633
|
-
|
|
634
|
-
rsh = np.ones(n)
|
|
635
|
-
for j in range(n):
|
|
636
|
-
voltage, current = rectify_iv_curve(ivcurves['v'][j], ivcurves['i'][j])
|
|
637
|
-
# initial estimate of Rsh, from integral over voltage regression
|
|
638
|
-
# [5] Step 3a; [6] Step 3a
|
|
639
|
-
_, _, _, rsh[j], _ = _fit_sandia_cocontent(
|
|
640
|
-
voltage, current, vth[j] * specs['cells_in_series'])
|
|
641
|
-
|
|
642
|
-
n0 = _fit_desoto_sandia_diode(ee, voc, vth, tc, specs, const)
|
|
643
|
-
|
|
644
|
-
bad_n = np.isnan(n0) or not np.isreal(n0)
|
|
645
|
-
|
|
646
|
-
if bad_n:
|
|
647
|
-
raise RuntimeError(
|
|
648
|
-
"Failed to estimate the diode (ideality) factor parameter;"
|
|
649
|
-
" aborting parameter estimation.")
|
|
650
|
-
|
|
651
|
-
nnsvth = n0 * specs['cells_in_series'] * vth
|
|
652
|
-
|
|
653
|
-
# For each IV curve, sequentially determine initial values for Io, Rs,
|
|
654
|
-
# and Iph [5] Step 3a; [6] Step 3
|
|
655
|
-
iph, io, rs, u = _initial_iv_params(ivcurves, ee, voc, isc, rsh,
|
|
656
|
-
nnsvth)
|
|
657
|
-
|
|
658
|
-
# Update values for each IV curve to converge at vmp, imp, voc and isc
|
|
659
|
-
iph, io, rs, rsh, u = _update_iv_params(voc, isc, vmp, imp, ee,
|
|
660
|
-
iph, io, rs, rsh, nnsvth, u,
|
|
661
|
-
maxiter, eps1)
|
|
662
|
-
|
|
663
|
-
# get single diode models from converged values for each IV curve
|
|
664
|
-
desoto = _extract_sdm_params(ee, tc, iph, io, rs, rsh, n0, u,
|
|
665
|
-
specs, const, model='desoto')
|
|
666
|
-
# Add parameters estimated in this function
|
|
667
|
-
desoto['a_ref'] = n0 * specs['cells_in_series'] * const['k'] / \
|
|
668
|
-
const['q'] * (const['T0'] + 273.15)
|
|
669
|
-
desoto['cells_in_series'] = specs['cells_in_series']
|
|
670
|
-
|
|
671
|
-
return desoto
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
def _fit_pvsyst_sandia_gamma(voc, isc, rsh, vth, tck, specs, const):
|
|
675
|
-
# Estimate the diode factor gamma from Isc-Voc data. Method incorporates
|
|
676
|
-
# temperature dependence by means of the equation for Io
|
|
677
|
-
|
|
678
|
-
y = np.log(isc - voc / rsh) - 3. * np.log(tck / (const['T0'] + 273.15))
|
|
679
|
-
x1 = const['q'] / const['k'] * (1. / (const['T0'] + 273.15) - 1. / tck)
|
|
680
|
-
x2 = voc / (vth * specs['cells_in_series'])
|
|
681
|
-
uu = np.logical_or(np.isnan(y), np.isnan(x1), np.isnan(x2))
|
|
682
|
-
|
|
683
|
-
x = np.vstack((np.ones(len(x1[~uu])), x1[~uu], -x1[~uu] *
|
|
684
|
-
(tck[~uu] - (const['T0'] + 273.15)), x2[~uu],
|
|
685
|
-
-x2[~uu] * (tck[~uu] - (const['T0'] + 273.15)))).T
|
|
686
|
-
alpha = np.linalg.lstsq(x, y[~uu], rcond=None)[0]
|
|
687
|
-
|
|
688
|
-
gamma_ref = 1. / alpha[3]
|
|
689
|
-
mu_gamma = alpha[4] / alpha[3] ** 2
|
|
690
|
-
return gamma_ref, mu_gamma
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
def _fit_desoto_sandia_diode(ee, voc, vth, tc, specs, const):
|
|
694
|
-
# estimates the diode factor for the De Soto model.
|
|
695
|
-
# Helper function for fit_desoto_sandia
|
|
696
|
-
try:
|
|
697
|
-
import statsmodels.api as sm
|
|
698
|
-
except ImportError:
|
|
699
|
-
raise ImportError(
|
|
700
|
-
'Parameter extraction using Sandia method requires statsmodels')
|
|
701
|
-
|
|
702
|
-
x = specs['cells_in_series'] * vth * np.log(ee / const['E0'])
|
|
703
|
-
y = voc - specs['beta_voc'] * (tc - const['T0'])
|
|
704
|
-
new_x = sm.add_constant(x)
|
|
705
|
-
res = sm.RLM(y, new_x).fit()
|
|
706
|
-
return np.array(res.params)[1]
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
def _initial_iv_params(ivcurves, ee, voc, isc, rsh, nnsvth):
|
|
710
|
-
# sets initial values for iph, io, rs and quality filter u.
|
|
711
|
-
# Helper function for fit_<model>_sandia.
|
|
712
|
-
n = len(ivcurves['v_oc'])
|
|
713
|
-
io = np.ones(n)
|
|
714
|
-
iph = np.ones(n)
|
|
715
|
-
rs = np.ones(n)
|
|
716
|
-
|
|
717
|
-
for j in range(n):
|
|
718
|
-
|
|
719
|
-
if rsh[j] > 0:
|
|
720
|
-
volt, curr = rectify_iv_curve(ivcurves['v'][j],
|
|
721
|
-
ivcurves['i'][j])
|
|
722
|
-
# Initial estimate of Io, evaluate the single diode model at
|
|
723
|
-
# voc and approximate Iph + Io = Isc [5] Step 3a; [6] Step 3b
|
|
724
|
-
io[j] = (isc[j] - voc[j] / rsh[j]) * np.exp(-voc[j] /
|
|
725
|
-
nnsvth[j])
|
|
726
|
-
|
|
727
|
-
# initial estimate of rs from dI/dV near Voc
|
|
728
|
-
# [5] Step 3a; [6] Step 3c
|
|
729
|
-
[didv, d2id2v] = _numdiff(volt, curr)
|
|
730
|
-
t3 = volt > .5 * voc[j]
|
|
731
|
-
t4 = volt < .9 * voc[j]
|
|
732
|
-
tmp = -rsh[j] * didv - 1.
|
|
733
|
-
with np.errstate(invalid="ignore"): # expect nan in didv
|
|
734
|
-
v = np.logical_and.reduce(np.array([t3, t4, ~np.isnan(tmp),
|
|
735
|
-
np.greater(tmp, 0)]))
|
|
736
|
-
if np.any(v):
|
|
737
|
-
vtrs = (nnsvth[j] / isc[j] * (
|
|
738
|
-
np.log(tmp[v] * nnsvth[j] / (rsh[j] * io[j]))
|
|
739
|
-
- volt[v] / nnsvth[j]))
|
|
740
|
-
rs[j] = np.mean(vtrs[vtrs > 0], axis=0)
|
|
741
|
-
else:
|
|
742
|
-
rs[j] = 0.
|
|
743
|
-
|
|
744
|
-
# Initial estimate of Iph, evaluate the single diode model at
|
|
745
|
-
# Isc [5] Step 3a; [6] Step 3d
|
|
746
|
-
iph[j] = isc[j] + io[j] * np.expm1(isc[j] / nnsvth[j]) \
|
|
747
|
-
+ isc[j] * rs[j] / rsh[j]
|
|
748
|
-
|
|
749
|
-
else:
|
|
750
|
-
io[j] = np.nan
|
|
751
|
-
rs[j] = np.nan
|
|
752
|
-
iph[j] = np.nan
|
|
753
|
-
|
|
754
|
-
# Filter IV curves for good initial values
|
|
755
|
-
# [5] Step 3b
|
|
756
|
-
u = _filter_params(ee, isc, io, rs, rsh)
|
|
757
|
-
|
|
758
|
-
# [5] Step 3c
|
|
759
|
-
# Refine Io to match Voc
|
|
760
|
-
io[u] = _update_io(voc[u], iph[u], io[u], rs[u], rsh[u], nnsvth[u])
|
|
761
|
-
|
|
762
|
-
# parameters [6], Step 3c
|
|
763
|
-
# Calculate Iph to be consistent with Isc and current values of other
|
|
764
|
-
iph = isc + io * np.expm1(rs * isc / nnsvth) + isc * rs / rsh
|
|
765
|
-
|
|
766
|
-
return iph, io, rs, u
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
def _update_iv_params(voc, isc, vmp, imp, ee, iph, io, rs, rsh, nnsvth, u,
|
|
770
|
-
maxiter, eps1):
|
|
771
|
-
# Refine Rsh, Rs, Io and Iph in that order.
|
|
772
|
-
# Helper function for fit_<model>_sandia.
|
|
773
|
-
counter = 1. # counter variable for parameter updating while loop,
|
|
774
|
-
# counts iterations
|
|
775
|
-
prevconvergeparams = {}
|
|
776
|
-
prevconvergeparams['state'] = 0.0
|
|
777
|
-
|
|
778
|
-
not_converged = np.array([True])
|
|
779
|
-
|
|
780
|
-
while not_converged.any() and counter <= maxiter:
|
|
781
|
-
# update rsh to match max power point using a fixed point method.
|
|
782
|
-
rsh[u] = _update_rsh_fixed_pt(vmp[u], imp[u], iph[u], io[u], rs[u],
|
|
783
|
-
rsh[u], nnsvth[u])
|
|
784
|
-
|
|
785
|
-
# Calculate Rs to be consistent with Rsh and maximum power point
|
|
786
|
-
_, phi = _calc_theta_phi_exact(vmp[u], imp[u], iph[u], io[u],
|
|
787
|
-
rs[u], rsh[u], nnsvth[u])
|
|
788
|
-
rs[u] = (iph[u] + io[u] - imp[u]) * rsh[u] / imp[u] - \
|
|
789
|
-
nnsvth[u] * phi / imp[u] - vmp[u] / imp[u]
|
|
790
|
-
|
|
791
|
-
# Update filter for good parameters
|
|
792
|
-
u = _filter_params(ee, isc, io, rs, rsh)
|
|
793
|
-
|
|
794
|
-
# Update value for io to match voc
|
|
795
|
-
io[u] = _update_io(voc[u], iph[u], io[u], rs[u], rsh[u], nnsvth[u])
|
|
796
|
-
|
|
797
|
-
# Calculate Iph to be consistent with Isc and other parameters
|
|
798
|
-
iph = isc + io * np.expm1(rs * isc / nnsvth) + isc * rs / rsh
|
|
799
|
-
|
|
800
|
-
# update filter for good parameters
|
|
801
|
-
u = _filter_params(ee, isc, io, rs, rsh)
|
|
802
|
-
|
|
803
|
-
# compute the IV curve from the current parameter values
|
|
804
|
-
result = singlediode(iph[u], io[u], rs[u], rsh[u], nnsvth[u])
|
|
805
|
-
|
|
806
|
-
# check convergence criteria
|
|
807
|
-
# [5] Step 3d
|
|
808
|
-
convergeparams = _check_converge(
|
|
809
|
-
prevconvergeparams, result, vmp[u], imp[u], counter)
|
|
810
|
-
|
|
811
|
-
prevconvergeparams = convergeparams
|
|
812
|
-
counter += 1.
|
|
813
|
-
t5 = prevconvergeparams['vmperrmeanchange'] >= eps1
|
|
814
|
-
t6 = prevconvergeparams['imperrmeanchange'] >= eps1
|
|
815
|
-
t7 = prevconvergeparams['pmperrmeanchange'] >= eps1
|
|
816
|
-
t8 = prevconvergeparams['vmperrstdchange'] >= eps1
|
|
817
|
-
t9 = prevconvergeparams['imperrstdchange'] >= eps1
|
|
818
|
-
t10 = prevconvergeparams['pmperrstdchange'] >= eps1
|
|
819
|
-
t11 = prevconvergeparams['vmperrabsmaxchange'] >= eps1
|
|
820
|
-
t12 = prevconvergeparams['imperrabsmaxchange'] >= eps1
|
|
821
|
-
t13 = prevconvergeparams['pmperrabsmaxchange'] >= eps1
|
|
822
|
-
not_converged = np.logical_or.reduce(np.array([t5, t6, t7, t8, t9,
|
|
823
|
-
t10, t11, t12, t13]))
|
|
824
|
-
|
|
825
|
-
return iph, io, rs, rsh, u
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
def _extract_sdm_params(ee, tc, iph, io, rs, rsh, n, u, specs, const,
|
|
829
|
-
model):
|
|
830
|
-
# Get single diode model parameters from five parameters iph, io, rs, rsh
|
|
831
|
-
# and n vs. effective irradiance and temperature
|
|
832
|
-
try:
|
|
833
|
-
import statsmodels.api as sm
|
|
834
|
-
except ImportError:
|
|
835
|
-
raise ImportError(
|
|
836
|
-
'Parameter extraction using Sandia method requires statsmodels')
|
|
837
|
-
|
|
838
|
-
tck = tc + 273.15
|
|
839
|
-
tok = const['T0'] + 273.15 # convert to to K
|
|
840
|
-
|
|
841
|
-
params = {}
|
|
842
|
-
|
|
843
|
-
if model == 'pvsyst':
|
|
844
|
-
# Estimate I_o_ref and EgRef
|
|
845
|
-
x_for_io = const['q'] / const['k'] * (1. / tok - 1. / tck[u]) / n[u]
|
|
846
|
-
|
|
847
|
-
# Estimate R_sh_0, R_sh_ref and R_sh_exp
|
|
848
|
-
# Initial guesses. R_sh_0 is value at ee=0.
|
|
849
|
-
nans = np.isnan(rsh)
|
|
850
|
-
if any(ee < 400):
|
|
851
|
-
grsh0 = np.mean(rsh[np.logical_and(~nans, ee < 400)])
|
|
852
|
-
else:
|
|
853
|
-
grsh0 = np.max(rsh)
|
|
854
|
-
# Rsh_ref is value at Ee = 1000
|
|
855
|
-
if any(ee > 400):
|
|
856
|
-
grshref = np.mean(rsh[np.logical_and(~nans, ee > 400)])
|
|
857
|
-
else:
|
|
858
|
-
grshref = np.min(rsh)
|
|
859
|
-
# PVsyst default for Rshexp is 5.5
|
|
860
|
-
R_sh_exp = 5.5
|
|
861
|
-
|
|
862
|
-
# Find parameters for Rsh equation
|
|
863
|
-
|
|
864
|
-
def fun_rsh(x, rshexp, ee, e0, rsh):
|
|
865
|
-
tf = np.log10(_rsh_pvsyst(x, R_sh_exp, ee, e0)) - np.log10(rsh)
|
|
866
|
-
return tf
|
|
867
|
-
|
|
868
|
-
x0 = np.array([grsh0, grshref])
|
|
869
|
-
beta = optimize.least_squares(
|
|
870
|
-
fun_rsh, x0, args=(R_sh_exp, ee[u], const['E0'], rsh[u]),
|
|
871
|
-
bounds=np.array([[1., 1.], [1.e7, 1.e6]]), verbose=2)
|
|
872
|
-
# Extract PVsyst parameter values
|
|
873
|
-
R_sh_0 = beta.x[0]
|
|
874
|
-
R_sh_ref = beta.x[1]
|
|
875
|
-
|
|
876
|
-
# parameters unique to PVsyst
|
|
877
|
-
params['R_sh_0'] = R_sh_0
|
|
878
|
-
params['R_sh_exp'] = R_sh_exp
|
|
879
|
-
|
|
880
|
-
elif model == 'desoto':
|
|
881
|
-
dEgdT = -0.0002677
|
|
882
|
-
x_for_io = const['q'] / const['k'] * (
|
|
883
|
-
1. / tok - 1. / tck[u] + dEgdT * (tc[u] - const['T0']) / tck[u])
|
|
884
|
-
|
|
885
|
-
# Estimate R_sh_ref
|
|
886
|
-
nans = np.isnan(rsh)
|
|
887
|
-
x = const['E0'] / ee[np.logical_and(u, ee > 400, ~nans)]
|
|
888
|
-
y = rsh[np.logical_and(u, ee > 400, ~nans)]
|
|
889
|
-
new_x = sm.add_constant(x)
|
|
890
|
-
beta = sm.RLM(y, new_x).fit()
|
|
891
|
-
R_sh_ref = beta.params[1]
|
|
892
|
-
|
|
893
|
-
params['dEgdT'] = dEgdT
|
|
894
|
-
|
|
895
|
-
# Estimate I_o_ref and EgRef
|
|
896
|
-
y = np.log(io[u]) - 3. * np.log(tck[u] / tok)
|
|
897
|
-
new_x = sm.add_constant(x_for_io)
|
|
898
|
-
res = sm.RLM(y, new_x).fit()
|
|
899
|
-
beta = res.params
|
|
900
|
-
I_o_ref = np.exp(beta[0])
|
|
901
|
-
EgRef = beta[1]
|
|
902
|
-
|
|
903
|
-
# Estimate I_L_ref
|
|
904
|
-
x = tc[u] - const['T0']
|
|
905
|
-
y = iph[u] * (const['E0'] / ee[u])
|
|
906
|
-
# average over non-NaN values of Y and X
|
|
907
|
-
nans = np.isnan(y - specs['alpha_sc'] * x)
|
|
908
|
-
I_L_ref = np.mean(y[~nans] - specs['alpha_sc'] * x[~nans])
|
|
909
|
-
|
|
910
|
-
# Estimate R_s
|
|
911
|
-
nans = np.isnan(rs)
|
|
912
|
-
R_s = np.mean(rs[np.logical_and(u, ee > 400, ~nans)])
|
|
913
|
-
|
|
914
|
-
params['I_L_ref'] = I_L_ref
|
|
915
|
-
params['I_o_ref'] = I_o_ref
|
|
916
|
-
params['EgRef'] = EgRef
|
|
917
|
-
params['R_sh_ref'] = R_sh_ref
|
|
918
|
-
params['R_s'] = R_s
|
|
919
|
-
# save values for each IV curve
|
|
920
|
-
params['iph'] = iph
|
|
921
|
-
params['io'] = io
|
|
922
|
-
params['rsh'] = rsh
|
|
923
|
-
params['rs'] = rs
|
|
924
|
-
params['u'] = u
|
|
925
|
-
|
|
926
|
-
return params
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
def _update_io(voc, iph, io, rs, rsh, nnsvth):
|
|
930
|
-
"""
|
|
931
|
-
Adjusts Io to match Voc using other parameter values.
|
|
932
|
-
|
|
933
|
-
Helper function for fit_pvsyst_sandia, fit_desoto_sandia
|
|
934
|
-
|
|
935
|
-
Description
|
|
936
|
-
-----------
|
|
937
|
-
Io is updated iteratively 10 times or until successive
|
|
938
|
-
values are less than 0.000001 % different. The updating is similar to
|
|
939
|
-
Newton's method.
|
|
940
|
-
|
|
941
|
-
Parameters
|
|
942
|
-
----------
|
|
943
|
-
voc: a numpy array of length N of values for Voc (V)
|
|
944
|
-
iph: a numpy array of length N of values for lighbt current IL (A)
|
|
945
|
-
io: a numpy array of length N of initial values for Io (A)
|
|
946
|
-
rs: a numpy array of length N of values for the series resistance (ohm)
|
|
947
|
-
rsh: a numpy array of length N of values for the shunt resistance (ohm)
|
|
948
|
-
nnsvth: a numpy array of length N of values for the diode factor x thermal
|
|
949
|
-
voltage for the module, equal to Ns (number of cells in series) x
|
|
950
|
-
Vth (thermal voltage per cell).
|
|
951
|
-
|
|
952
|
-
Returns
|
|
953
|
-
-------
|
|
954
|
-
new_io - a numpy array of length N of updated values for io
|
|
955
|
-
|
|
956
|
-
References
|
|
957
|
-
----------
|
|
958
|
-
.. [1] PVLib MATLAB https://github.com/sandialabs/MATLAB_PV_LIB
|
|
959
|
-
.. [2] C. Hansen, Parameter Estimation for Single Diode Models of
|
|
960
|
-
Photovoltaic Modules, Sandia National Laboratories Report SAND2015-2065
|
|
961
|
-
.. [3] C. Hansen, Estimation of Parameteres for Single Diode Models using
|
|
962
|
-
Measured IV Curves, Proc. of the 39th IEEE PVSC, June 2013.
|
|
963
|
-
"""
|
|
964
|
-
|
|
965
|
-
eps = 1e-6
|
|
966
|
-
niter = 10
|
|
967
|
-
k = 1
|
|
968
|
-
maxerr = 1
|
|
969
|
-
|
|
970
|
-
tio = io # Current Estimate of Io
|
|
971
|
-
|
|
972
|
-
while maxerr > eps and k < niter:
|
|
973
|
-
# Predict Voc
|
|
974
|
-
pvoc = v_from_i(0., iph, tio, rs, rsh, nnsvth)
|
|
975
|
-
|
|
976
|
-
# Difference in Voc
|
|
977
|
-
dvoc = pvoc - voc
|
|
978
|
-
|
|
979
|
-
# Update Io
|
|
980
|
-
with np.errstate(invalid="ignore", divide="ignore"):
|
|
981
|
-
new_io = tio * (1. + (2. * dvoc) / (2. * nnsvth - dvoc))
|
|
982
|
-
# Calculate Maximum Percent Difference
|
|
983
|
-
maxerr = np.max(np.abs(new_io - tio) / tio) * 100.
|
|
984
|
-
|
|
985
|
-
tio = new_io
|
|
986
|
-
k += 1.
|
|
987
|
-
|
|
988
|
-
return new_io
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
def _rsh_pvsyst(x, rshexp, g, go):
|
|
992
|
-
# computes rsh for PVsyst model where the parameters are in vector xL
|
|
993
|
-
# x[0] = Rsh0
|
|
994
|
-
# x[1] = Rshref
|
|
995
|
-
|
|
996
|
-
rsho = x[0]
|
|
997
|
-
rshref = x[1]
|
|
998
|
-
|
|
999
|
-
rshb = np.maximum(
|
|
1000
|
-
(rshref - rsho * np.exp(-rshexp)) / (1. - np.exp(-rshexp)), 0.)
|
|
1001
|
-
rsh = rshb + (rsho - rshb) * np.exp(-rshexp * g / go)
|
|
1002
|
-
return rsh
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
def _filter_params(ee, isc, io, rs, rsh):
|
|
1006
|
-
# Function _filter_params identifies bad parameter sets. A bad set contains
|
|
1007
|
-
# Nan, non-positive or imaginary values for parameters; Rs > Rsh; or data
|
|
1008
|
-
# where effective irradiance Ee differs by more than 5% from a linear fit
|
|
1009
|
-
# to Isc vs. Ee
|
|
1010
|
-
|
|
1011
|
-
badrsh = np.logical_or(rsh < 0., np.isnan(rsh))
|
|
1012
|
-
negrs = rs < 0.
|
|
1013
|
-
badrs = np.logical_or(rs > rsh, np.isnan(rs))
|
|
1014
|
-
imagrs = ~(np.isreal(rs))
|
|
1015
|
-
badio = np.logical_or(np.logical_or(~(np.isreal(rs)), io <= 0),
|
|
1016
|
-
np.isnan(io))
|
|
1017
|
-
goodr = np.logical_and(~badrsh, ~imagrs)
|
|
1018
|
-
goodr = np.logical_and(goodr, ~negrs)
|
|
1019
|
-
goodr = np.logical_and(goodr, ~badrs)
|
|
1020
|
-
goodr = np.logical_and(goodr, ~badio)
|
|
1021
|
-
|
|
1022
|
-
matrix = np.vstack((ee / 1000., np.zeros(len(ee)))).T
|
|
1023
|
-
eff = np.linalg.lstsq(matrix, isc, rcond=None)[0][0]
|
|
1024
|
-
pisc = eff * ee / 1000
|
|
1025
|
-
pisc_error = np.abs(pisc - isc) / isc
|
|
1026
|
-
# check for departure from linear relation between Isc and Ee
|
|
1027
|
-
badiph = pisc_error > .05
|
|
1028
|
-
|
|
1029
|
-
u = np.logical_and(goodr, ~badiph)
|
|
1030
|
-
return u
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
def _check_converge(prevparams, result, vmp, imp, i):
|
|
1034
|
-
"""
|
|
1035
|
-
Function _check_converge computes convergence metrics for all IV curves.
|
|
1036
|
-
|
|
1037
|
-
Helper function for fit_pvsyst_sandia, fit_desoto_sandia
|
|
1038
|
-
|
|
1039
|
-
Parameters
|
|
1040
|
-
----------
|
|
1041
|
-
prevparams: Convergence Parameters from the previous Iteration (used to
|
|
1042
|
-
determine Percent Change in values between iterations)
|
|
1043
|
-
result: performacne paramters of the (predicted) single diode fitting,
|
|
1044
|
-
which includes Voc, Vmp, Imp, Pmp and Isc
|
|
1045
|
-
vmp: measured values for each IV curve
|
|
1046
|
-
imp: measured values for each IV curve
|
|
1047
|
-
i: Index of current iteration in cec_parameter_estimation
|
|
1048
|
-
|
|
1049
|
-
Returns
|
|
1050
|
-
-------
|
|
1051
|
-
convergeparam: dict containing the following for Imp, Vmp and Pmp:
|
|
1052
|
-
- maximum percent difference between measured and modeled values
|
|
1053
|
-
- minimum percent difference between measured and modeled values
|
|
1054
|
-
- maximum absolute percent difference between measured and modeled
|
|
1055
|
-
values
|
|
1056
|
-
- mean percent difference between measured and modeled values
|
|
1057
|
-
- standard deviation of percent difference between measured and modeled
|
|
1058
|
-
values
|
|
1059
|
-
- absolute difference for previous and current values of maximum
|
|
1060
|
-
absolute percent difference (measured vs. modeled)
|
|
1061
|
-
- absolute difference for previous and current values of mean percent
|
|
1062
|
-
difference (measured vs. modeled)
|
|
1063
|
-
- absolute difference for previous and current values of standard
|
|
1064
|
-
deviation of percent difference (measured vs. modeled)
|
|
1065
|
-
"""
|
|
1066
|
-
|
|
1067
|
-
convergeparam = {}
|
|
1068
|
-
|
|
1069
|
-
imperror = (result['i_mp'] - imp) / imp * 100.
|
|
1070
|
-
vmperror = (result['v_mp'] - vmp) / vmp * 100.
|
|
1071
|
-
pmperror = (result['p_mp'] - (imp * vmp)) / (imp * vmp) * 100.
|
|
1072
|
-
|
|
1073
|
-
convergeparam['imperrmax'] = max(imperror) # max of the error in Imp
|
|
1074
|
-
convergeparam['imperrmin'] = min(imperror) # min of the error in Imp
|
|
1075
|
-
# max of the absolute error in Imp
|
|
1076
|
-
convergeparam['imperrabsmax'] = max(abs(imperror))
|
|
1077
|
-
# mean of the error in Imp
|
|
1078
|
-
convergeparam['imperrmean'] = np.mean(imperror, axis=0)
|
|
1079
|
-
# std of the error in Imp
|
|
1080
|
-
convergeparam['imperrstd'] = np.std(imperror, axis=0, ddof=1)
|
|
1081
|
-
|
|
1082
|
-
convergeparam['vmperrmax'] = max(vmperror) # max of the error in Vmp
|
|
1083
|
-
convergeparam['vmperrmin'] = min(vmperror) # min of the error in Vmp
|
|
1084
|
-
# max of the absolute error in Vmp
|
|
1085
|
-
convergeparam['vmperrabsmax'] = max(abs(vmperror))
|
|
1086
|
-
# mean of the error in Vmp
|
|
1087
|
-
convergeparam['vmperrmean'] = np.mean(vmperror, axis=0)
|
|
1088
|
-
# std of the error in Vmp
|
|
1089
|
-
convergeparam['vmperrstd'] = np.std(vmperror, axis=0, ddof=1)
|
|
1090
|
-
|
|
1091
|
-
convergeparam['pmperrmax'] = max(pmperror) # max of the error in Pmp
|
|
1092
|
-
convergeparam['pmperrmin'] = min(pmperror) # min of the error in Pmp
|
|
1093
|
-
# max of the abs err. in Pmp
|
|
1094
|
-
convergeparam['pmperrabsmax'] = max(abs(pmperror))
|
|
1095
|
-
# mean error in Pmp
|
|
1096
|
-
convergeparam['pmperrmean'] = np.mean(pmperror, axis=0)
|
|
1097
|
-
# std error Pmp
|
|
1098
|
-
convergeparam['pmperrstd'] = np.std(pmperror, axis=0, ddof=1)
|
|
1099
|
-
|
|
1100
|
-
if prevparams['state'] != 0.0:
|
|
1101
|
-
convergeparam['imperrstdchange'] = np.abs(
|
|
1102
|
-
convergeparam['imperrstd'] / prevparams['imperrstd'] - 1.)
|
|
1103
|
-
convergeparam['vmperrstdchange'] = np.abs(
|
|
1104
|
-
convergeparam['vmperrstd'] / prevparams['vmperrstd'] - 1.)
|
|
1105
|
-
convergeparam['pmperrstdchange'] = np.abs(
|
|
1106
|
-
convergeparam['pmperrstd'] / prevparams['pmperrstd'] - 1.)
|
|
1107
|
-
convergeparam['imperrmeanchange'] = np.abs(
|
|
1108
|
-
convergeparam['imperrmean'] / prevparams['imperrmean'] - 1.)
|
|
1109
|
-
convergeparam['vmperrmeanchange'] = np.abs(
|
|
1110
|
-
convergeparam['vmperrmean'] / prevparams['vmperrmean'] - 1.)
|
|
1111
|
-
convergeparam['pmperrmeanchange'] = np.abs(
|
|
1112
|
-
convergeparam['pmperrmean'] / prevparams['pmperrmean'] - 1.)
|
|
1113
|
-
convergeparam['imperrabsmaxchange'] = np.abs(
|
|
1114
|
-
convergeparam['imperrabsmax'] / prevparams['imperrabsmax'] - 1.)
|
|
1115
|
-
convergeparam['vmperrabsmaxchange'] = np.abs(
|
|
1116
|
-
convergeparam['vmperrabsmax'] / prevparams['vmperrabsmax'] - 1.)
|
|
1117
|
-
convergeparam['pmperrabsmaxchange'] = np.abs(
|
|
1118
|
-
convergeparam['pmperrabsmax'] / prevparams['pmperrabsmax'] - 1.)
|
|
1119
|
-
convergeparam['state'] = 1.0
|
|
1120
|
-
else:
|
|
1121
|
-
convergeparam['imperrstdchange'] = float("Inf")
|
|
1122
|
-
convergeparam['vmperrstdchange'] = float("Inf")
|
|
1123
|
-
convergeparam['pmperrstdchange'] = float("Inf")
|
|
1124
|
-
convergeparam['imperrmeanchange'] = float("Inf")
|
|
1125
|
-
convergeparam['vmperrmeanchange'] = float("Inf")
|
|
1126
|
-
convergeparam['pmperrmeanchange'] = float("Inf")
|
|
1127
|
-
convergeparam['imperrabsmaxchange'] = float("Inf")
|
|
1128
|
-
convergeparam['vmperrabsmaxchange'] = float("Inf")
|
|
1129
|
-
convergeparam['pmperrabsmaxchange'] = float("Inf")
|
|
1130
|
-
convergeparam['state'] = 1.
|
|
1131
|
-
return convergeparam
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
def _update_rsh_fixed_pt(vmp, imp, iph, io, rs, rsh, nnsvth):
|
|
1135
|
-
"""
|
|
1136
|
-
Adjust Rsh to match Vmp using other parameter values
|
|
1137
|
-
|
|
1138
|
-
Helper function for fit_pvsyst_sandia, fit_desoto_sandia
|
|
1139
|
-
|
|
1140
|
-
Description
|
|
1141
|
-
-----------
|
|
1142
|
-
Rsh is updated iteratively using a fixed point expression
|
|
1143
|
-
obtained from combining Vmp = Vmp(Imp) (using the analytic solution to the
|
|
1144
|
-
single diode equation) and dP / dI = 0 at Imp. 500 iterations are performed
|
|
1145
|
-
because convergence can be very slow.
|
|
1146
|
-
|
|
1147
|
-
Parameters
|
|
1148
|
-
----------
|
|
1149
|
-
vmp: a numpy array of length N of values for Vmp (V)
|
|
1150
|
-
imp: a numpy array of length N of values for Imp (A)
|
|
1151
|
-
iph: a numpy array of length N of values for light current IL (A)
|
|
1152
|
-
io: a numpy array of length N of values for Io (A)
|
|
1153
|
-
rs: a numpy array of length N of values for series resistance (ohm)
|
|
1154
|
-
rsh: a numpy array of length N of initial values for shunt resistance (ohm)
|
|
1155
|
-
nnsvth: a numpy array length N of values for the diode factor x thermal
|
|
1156
|
-
voltage for the module, equal to Ns (number of cells in series) x
|
|
1157
|
-
Vth (thermal voltage per cell).
|
|
1158
|
-
|
|
1159
|
-
Returns
|
|
1160
|
-
-------
|
|
1161
|
-
numpy array of length N of updated values for Rsh
|
|
1162
|
-
|
|
1163
|
-
References
|
|
1164
|
-
----------
|
|
1165
|
-
.. [1] PVLib for MATLAB https://github.com/sandialabs/MATLAB_PV_LIB
|
|
1166
|
-
.. [2] C. Hansen, Parameter Estimation for Single Diode Models of
|
|
1167
|
-
Photovoltaic Modules, Sandia National Laboratories Report SAND2015-2065
|
|
1168
|
-
"""
|
|
1169
|
-
niter = 500
|
|
1170
|
-
x1 = rsh
|
|
1171
|
-
|
|
1172
|
-
for i in range(niter):
|
|
1173
|
-
_, z = _calc_theta_phi_exact(vmp, imp, iph, io, rs, x1, nnsvth)
|
|
1174
|
-
with np.errstate(divide="ignore"):
|
|
1175
|
-
next_x1 = (1 + z) / z * ((iph + io) * x1 / imp - nnsvth * z / imp
|
|
1176
|
-
- 2 * vmp / imp)
|
|
1177
|
-
x1 = next_x1
|
|
1178
|
-
|
|
1179
|
-
return x1
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
def _calc_theta_phi_exact(vmp, imp, iph, io, rs, rsh, nnsvth):
|
|
1183
|
-
"""
|
|
1184
|
-
_calc_theta_phi_exact computes Lambert W values appearing in the analytic
|
|
1185
|
-
solutions to the single diode equation for the max power point.
|
|
1186
|
-
|
|
1187
|
-
Helper function for fit_pvsyst_sandia
|
|
1188
|
-
|
|
1189
|
-
Parameters
|
|
1190
|
-
----------
|
|
1191
|
-
vmp: a numpy array of length N of values for Vmp (V)
|
|
1192
|
-
imp: a numpy array of length N of values for Imp (A)
|
|
1193
|
-
iph: a numpy array of length N of values for the light current IL (A)
|
|
1194
|
-
io: a numpy array of length N of values for Io (A)
|
|
1195
|
-
rs: a numpy array of length N of values for the series resistance (ohm)
|
|
1196
|
-
rsh: a numpy array of length N of values for the shunt resistance (ohm)
|
|
1197
|
-
nnsvth: a numpy array of length N of values for the diode factor x
|
|
1198
|
-
thermal voltage for the module, equal to Ns
|
|
1199
|
-
(number of cells in series) x Vth
|
|
1200
|
-
(thermal voltage per cell).
|
|
1201
|
-
|
|
1202
|
-
Returns
|
|
1203
|
-
-------
|
|
1204
|
-
theta: a numpy array of values for the Lamber W function for solving
|
|
1205
|
-
I = I(V)
|
|
1206
|
-
phi: a numpy array of values for the Lambert W function for solving
|
|
1207
|
-
V = V(I)
|
|
1208
|
-
|
|
1209
|
-
Notes
|
|
1210
|
-
-----
|
|
1211
|
-
_calc_theta_phi_exact calculates values for the Lambert W function which
|
|
1212
|
-
are used in the analytic solutions for the single diode equation at the
|
|
1213
|
-
maximum power point. For V=V(I),
|
|
1214
|
-
phi = W(Io*Rsh/n*Vth * exp((IL + Io - Imp)*Rsh/n*Vth)). For I=I(V),
|
|
1215
|
-
theta = W(Rs*Io/n*Vth *
|
|
1216
|
-
Rsh/ (Rsh+Rs) * exp(Rsh/ (Rsh+Rs)*((Rs(IL+Io) + V)/n*Vth))
|
|
1217
|
-
|
|
1218
|
-
References
|
|
1219
|
-
----------
|
|
1220
|
-
.. [1] PVL MATLAB 2065 https://github.com/sandialabs/MATLAB_PV_LIB
|
|
1221
|
-
.. [2] C. Hansen, Parameter Estimation for Single Diode Models of
|
|
1222
|
-
Photovoltaic Modules, Sandia National Laboratories Report SAND2015-2065
|
|
1223
|
-
.. [3] A. Jain, A. Kapoor, "Exact analytical solutions of the parameters of
|
|
1224
|
-
real solar cells using Lambert W-function", Solar Energy Materials and
|
|
1225
|
-
Solar Cells, 81 (2004) 269-277.
|
|
1226
|
-
"""
|
|
1227
|
-
# handle singleton inputs
|
|
1228
|
-
vmp = np.asarray(vmp)
|
|
1229
|
-
imp = np.asarray(imp)
|
|
1230
|
-
iph = np.asarray(iph)
|
|
1231
|
-
io = np.asarray(io)
|
|
1232
|
-
rs = np.asarray(rs)
|
|
1233
|
-
rsh = np.asarray(rsh)
|
|
1234
|
-
nnsvth = np.asarray(nnsvth)
|
|
1235
|
-
|
|
1236
|
-
# Argument for Lambert W function involved in V = V(I) [2] Eq. 12; [3]
|
|
1237
|
-
# Eq. 3
|
|
1238
|
-
with np.errstate(over="ignore", divide="ignore", invalid="ignore"):
|
|
1239
|
-
argw = np.where(
|
|
1240
|
-
nnsvth == 0,
|
|
1241
|
-
np.nan,
|
|
1242
|
-
rsh * io / nnsvth * np.exp(rsh * (iph + io - imp) / nnsvth))
|
|
1243
|
-
phi = np.where(argw > 0, lambertw(argw).real, np.nan)
|
|
1244
|
-
|
|
1245
|
-
# NaN where argw overflows. Switch to log space to evaluate
|
|
1246
|
-
u = np.isinf(argw)
|
|
1247
|
-
if np.any(u):
|
|
1248
|
-
logargw = (
|
|
1249
|
-
np.log(rsh[u]) + np.log(io[u]) - np.log(nnsvth[u])
|
|
1250
|
-
+ rsh[u] * (iph[u] + io[u] - imp[u]) / nnsvth[u])
|
|
1251
|
-
# Three iterations of Newton-Raphson method to solve w+log(w)=logargW.
|
|
1252
|
-
# The initial guess is w=logargW. Where direct evaluation (above)
|
|
1253
|
-
# results in NaN from overflow, 3 iterations of Newton's method gives
|
|
1254
|
-
# approximately 8 digits of precision.
|
|
1255
|
-
x = logargw
|
|
1256
|
-
for i in range(3):
|
|
1257
|
-
x *= ((1. - np.log(x) + logargw) / (1. + x))
|
|
1258
|
-
phi[u] = x
|
|
1259
|
-
phi = np.transpose(phi)
|
|
1260
|
-
|
|
1261
|
-
# Argument for Lambert W function involved in I = I(V) [2] Eq. 11; [3]
|
|
1262
|
-
# E1. 2
|
|
1263
|
-
with np.errstate(over="ignore", divide="ignore", invalid="ignore"):
|
|
1264
|
-
argw = np.where(
|
|
1265
|
-
nnsvth == 0,
|
|
1266
|
-
np.nan,
|
|
1267
|
-
rsh / (rsh + rs) * rs * io / nnsvth * np.exp(
|
|
1268
|
-
rsh / (rsh + rs) * (rs * (iph + io) + vmp) / nnsvth))
|
|
1269
|
-
theta = np.where(argw > 0, lambertw(argw).real, np.nan)
|
|
1270
|
-
|
|
1271
|
-
# NaN where argw overflows. Switch to log space to evaluate
|
|
1272
|
-
u = np.isinf(argw)
|
|
1273
|
-
if np.any(u):
|
|
1274
|
-
with np.errstate(divide="ignore"):
|
|
1275
|
-
logargw = (
|
|
1276
|
-
np.log(rsh[u]) - np.log(rsh[u] + rs[u]) + np.log(rs[u])
|
|
1277
|
-
+ np.log(io[u]) - np.log(nnsvth[u])
|
|
1278
|
-
+ (rsh[u] / (rsh[u] + rs[u]))
|
|
1279
|
-
* (rs[u] * (iph[u] + io[u]) + vmp[u]) / nnsvth[u])
|
|
1280
|
-
# Three iterations of Newton-Raphson method to solve w+log(w)=logargW.
|
|
1281
|
-
# The initial guess is w=logargW. Where direct evaluation (above)
|
|
1282
|
-
# results in NaN from overflow, 3 iterations of Newton's method gives
|
|
1283
|
-
# approximately 8 digits of precision.
|
|
1284
|
-
x = logargw
|
|
1285
|
-
for i in range(3):
|
|
1286
|
-
x *= ((1. - np.log(x) + logargw) / (1. + x))
|
|
1287
|
-
theta[u] = x
|
|
1288
|
-
theta = np.transpose(theta)
|
|
1289
|
-
|
|
1290
|
-
return theta, phi
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
def pvsyst_temperature_coeff(alpha_sc, gamma_ref, mu_gamma, I_L_ref, I_o_ref,
|
|
1294
|
-
R_sh_ref, R_sh_0, R_s, cells_in_series,
|
|
1295
|
-
R_sh_exp=5.5, EgRef=1.121, irrad_ref=1000,
|
|
1296
|
-
temp_ref=25):
|
|
1297
|
-
r"""
|
|
1298
|
-
Calculates the temperature coefficient of power for a pvsyst single
|
|
1299
|
-
diode model.
|
|
1300
|
-
|
|
1301
|
-
The temperature coefficient is determined as the numerical derivative
|
|
1302
|
-
:math:`\frac{dP}{dT}` at the maximum power point at reference conditions
|
|
1303
|
-
[1]_.
|
|
1304
|
-
|
|
1305
|
-
Parameters
|
|
1306
|
-
----------
|
|
1307
|
-
alpha_sc : float
|
|
1308
|
-
The short-circuit current temperature coefficient of the module. [A/C]
|
|
1309
|
-
|
|
1310
|
-
gamma_ref : float
|
|
1311
|
-
The diode ideality factor. [unitless]
|
|
1312
|
-
|
|
1313
|
-
mu_gamma : float
|
|
1314
|
-
The temperature coefficient for the diode ideality factor. [1/K]
|
|
1315
|
-
|
|
1316
|
-
I_L_ref : float
|
|
1317
|
-
The light-generated current (or photocurrent) at reference conditions.
|
|
1318
|
-
[A]
|
|
1319
|
-
|
|
1320
|
-
I_o_ref : float
|
|
1321
|
-
The dark or diode reverse saturation current at reference conditions.
|
|
1322
|
-
[A]
|
|
1323
|
-
|
|
1324
|
-
R_sh_ref : float
|
|
1325
|
-
The shunt resistance at reference conditions. [ohm]
|
|
1326
|
-
|
|
1327
|
-
R_sh_0 : float
|
|
1328
|
-
The shunt resistance at zero irradiance conditions. [ohm]
|
|
1329
|
-
|
|
1330
|
-
R_s : float
|
|
1331
|
-
The series resistance at reference conditions. [ohm]
|
|
1332
|
-
|
|
1333
|
-
cells_in_series : int
|
|
1334
|
-
The number of cells connected in series.
|
|
1335
|
-
|
|
1336
|
-
R_sh_exp : float, default 5.5
|
|
1337
|
-
The exponent in the equation for shunt resistance. [unitless]
|
|
1338
|
-
|
|
1339
|
-
EgRef : float, default 1.121
|
|
1340
|
-
The energy bandgap of the module's cells at reference temperature.
|
|
1341
|
-
Default of 1.121 eV is for crystalline silicon. Must be positive. [eV]
|
|
1342
|
-
|
|
1343
|
-
irrad_ref : float, default 1000
|
|
1344
|
-
Reference irradiance. [W/m^2].
|
|
1345
|
-
|
|
1346
|
-
temp_ref : float, default 25
|
|
1347
|
-
Reference cell temperature. [C]
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
Returns
|
|
1351
|
-
-------
|
|
1352
|
-
gamma_pdc : float
|
|
1353
|
-
Temperature coefficient of power at maximum power point at reference
|
|
1354
|
-
conditions. [1/C]
|
|
1355
|
-
|
|
1356
|
-
References
|
|
1357
|
-
----------
|
|
1358
|
-
.. [1] K. Sauer, T. Roessler, C. W. Hansen, Modeling the Irradiance and
|
|
1359
|
-
Temperature Dependence of Photovoltaic Modules in PVsyst, IEEE Journal
|
|
1360
|
-
of Photovoltaics v5(1), January 2015.
|
|
1361
|
-
"""
|
|
1362
|
-
|
|
1363
|
-
def maxp(temp_cell, irrad_ref, alpha_sc, gamma_ref, mu_gamma, I_L_ref,
|
|
1364
|
-
I_o_ref, R_sh_ref, R_sh_0, R_s, cells_in_series, R_sh_exp, EgRef,
|
|
1365
|
-
temp_ref):
|
|
1366
|
-
params = calcparams_pvsyst(
|
|
1367
|
-
irrad_ref, temp_cell, alpha_sc, gamma_ref, mu_gamma, I_L_ref,
|
|
1368
|
-
I_o_ref, R_sh_ref, R_sh_0, R_s, cells_in_series, R_sh_exp, EgRef,
|
|
1369
|
-
irrad_ref, temp_ref)
|
|
1370
|
-
res = bishop88_mpp(*params)
|
|
1371
|
-
return res[2]
|
|
1372
|
-
|
|
1373
|
-
args = (irrad_ref, alpha_sc, gamma_ref, mu_gamma, I_L_ref,
|
|
1374
|
-
I_o_ref, R_sh_ref, R_sh_0, R_s, cells_in_series, R_sh_exp, EgRef,
|
|
1375
|
-
temp_ref)
|
|
1376
|
-
pmp = maxp(temp_ref, *args)
|
|
1377
|
-
gamma_pdc = _first_order_centered_difference(maxp, x0=temp_ref, args=args)
|
|
1378
|
-
|
|
1379
|
-
return gamma_pdc / pmp
|