pvlib 0.13.0__py3-none-any.whl → 0.13.1a1__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/bifacial/pvfactors.py +1 -1
- pvlib/clearsky.py +21 -12
- pvlib/inverter.py +11 -7
- pvlib/iotools/__init__.py +6 -0
- pvlib/iotools/meteonorm.py +623 -0
- pvlib/iotools/nasa_power.py +153 -0
- pvlib/iotools/pvgis.py +1 -1
- pvlib/iotools/tmy.py +4 -2
- pvlib/irradiance.py +307 -295
- pvlib/ivtools/sdm/_fit_desoto_pvsyst_sandia.py +1 -1
- pvlib/ivtools/sdm/cec.py +1 -1
- pvlib/ivtools/sdm/desoto.py +6 -6
- pvlib/ivtools/sdm/pvsyst.py +7 -7
- pvlib/modelchain.py +19 -10
- pvlib/pvarray.py +61 -17
- pvlib/singlediode.py +16 -10
- pvlib/solarposition.py +11 -10
- pvlib/spectrum/mismatch.py +7 -19
- pvlib/temperature.py +58 -10
- pvlib/tools.py +2 -2
- pvlib/tracking.py +11 -6
- {pvlib-0.13.0.dist-info → pvlib-0.13.1a1.dist-info}/METADATA +5 -5
- {pvlib-0.13.0.dist-info → pvlib-0.13.1a1.dist-info}/RECORD +27 -25
- {pvlib-0.13.0.dist-info → pvlib-0.13.1a1.dist-info}/WHEEL +0 -0
- {pvlib-0.13.0.dist-info → pvlib-0.13.1a1.dist-info}/licenses/AUTHORS.md +0 -0
- {pvlib-0.13.0.dist-info → pvlib-0.13.1a1.dist-info}/licenses/LICENSE +0 -0
- {pvlib-0.13.0.dist-info → pvlib-0.13.1a1.dist-info}/top_level.txt +0 -0
|
@@ -267,7 +267,7 @@ def _update_io(voc, iph, io, rs, rsh, nnsvth):
|
|
|
267
267
|
.. [1] PVLib MATLAB https://github.com/sandialabs/MATLAB_PV_LIB
|
|
268
268
|
.. [2] C. Hansen, Parameter Estimation for Single Diode Models of
|
|
269
269
|
Photovoltaic Modules, Sandia National Laboratories Report SAND2015-2065
|
|
270
|
-
.. [3] C. Hansen, Estimation of
|
|
270
|
+
.. [3] C. Hansen, Estimation of Parameters for Single Diode Models using
|
|
271
271
|
Measured IV Curves, Proc. of the 39th IEEE PVSC, June 2013.
|
|
272
272
|
"""
|
|
273
273
|
|
pvlib/ivtools/sdm/cec.py
CHANGED
|
@@ -27,7 +27,7 @@ def fit_cec_sam(celltype, v_mp, i_mp, v_oc, i_sc, alpha_sc, beta_voc,
|
|
|
27
27
|
cells_in_series : int
|
|
28
28
|
Number of cells in series
|
|
29
29
|
temp_ref : float, default 25
|
|
30
|
-
Reference temperature condition [C]
|
|
30
|
+
Reference temperature condition, [°C]
|
|
31
31
|
|
|
32
32
|
Returns
|
|
33
33
|
-------
|
pvlib/ivtools/sdm/desoto.py
CHANGED
|
@@ -58,7 +58,7 @@ def fit_desoto(v_mp, i_mp, v_oc, i_sc, alpha_sc, beta_voc, cells_in_series,
|
|
|
58
58
|
dEgdT: float, default -0.0002677 - value for silicon
|
|
59
59
|
Variation of bandgap according to temperature. [1/K]
|
|
60
60
|
temp_ref: float, default 25
|
|
61
|
-
Reference temperature condition. [C]
|
|
61
|
+
Reference temperature condition. [°C]
|
|
62
62
|
irrad_ref: float, default 1000
|
|
63
63
|
Reference irradiance condition. [Wm⁻²]
|
|
64
64
|
init_guess: dict, optional
|
|
@@ -93,7 +93,7 @@ def fit_desoto(v_mp, i_mp, v_oc, i_sc, alpha_sc, beta_voc, cells_in_series,
|
|
|
93
93
|
irrad_ref: float
|
|
94
94
|
Reference irradiance condition. [Wm⁻²]
|
|
95
95
|
temp_ref: float
|
|
96
|
-
Reference temperature condition. [C]
|
|
96
|
+
Reference temperature condition. [°C]
|
|
97
97
|
|
|
98
98
|
scipy.optimize.OptimizeResult
|
|
99
99
|
Optimization result of scipy.optimize.root().
|
|
@@ -110,7 +110,7 @@ def fit_desoto(v_mp, i_mp, v_oc, i_sc, alpha_sc, beta_voc, cells_in_series,
|
|
|
110
110
|
"""
|
|
111
111
|
|
|
112
112
|
# Constants
|
|
113
|
-
k = constants.value('Boltzmann constant in eV/K')
|
|
113
|
+
k = constants.value('Boltzmann constant in eV/K')
|
|
114
114
|
Tref = temp_ref + 273.15 # [K]
|
|
115
115
|
|
|
116
116
|
# initial guesses of variables for computing convergence:
|
|
@@ -234,7 +234,7 @@ def fit_desoto_sandia(ivcurves, specs, const=None, maxiter=5, eps1=1.e-3):
|
|
|
234
234
|
effective irradiance for each IV curve, i.e., POA broadband
|
|
235
235
|
irradiance adjusted by solar spectrum modifier [W / m^2]
|
|
236
236
|
tc : array
|
|
237
|
-
cell temperature for each IV curve [C]
|
|
237
|
+
cell temperature for each IV curve. [°C]
|
|
238
238
|
i_sc : array
|
|
239
239
|
short circuit current for each IV curve [A]
|
|
240
240
|
v_oc : array
|
|
@@ -254,9 +254,9 @@ def fit_desoto_sandia(ivcurves, specs, const=None, maxiter=5, eps1=1.e-3):
|
|
|
254
254
|
|
|
255
255
|
const : dict
|
|
256
256
|
E0 : float
|
|
257
|
-
effective irradiance at STC, default 1000 [
|
|
257
|
+
effective irradiance at STC, default 1000 [Wm⁻²]
|
|
258
258
|
T0 : float
|
|
259
|
-
cell temperature at STC, default 25 [C]
|
|
259
|
+
cell temperature at STC, default 25°C. [°C]
|
|
260
260
|
k : float
|
|
261
261
|
Boltzmann's constant [J/K]
|
|
262
262
|
q : float
|
pvlib/ivtools/sdm/pvsyst.py
CHANGED
|
@@ -38,7 +38,7 @@ def fit_pvsyst_sandia(ivcurves, specs, const=None, maxiter=5, eps1=1.e-3):
|
|
|
38
38
|
effective irradiance for each IV curve, i.e., POA broadband
|
|
39
39
|
irradiance adjusted by solar spectrum modifier [W / m^2]
|
|
40
40
|
tc : array
|
|
41
|
-
cell temperature for each IV curve [C]
|
|
41
|
+
cell temperature for each IV curve [°C]
|
|
42
42
|
i_sc : array
|
|
43
43
|
short circuit current for each IV curve [A]
|
|
44
44
|
v_oc : array
|
|
@@ -56,9 +56,9 @@ def fit_pvsyst_sandia(ivcurves, specs, const=None, maxiter=5, eps1=1.e-3):
|
|
|
56
56
|
|
|
57
57
|
const : dict
|
|
58
58
|
E0 : float
|
|
59
|
-
effective irradiance at STC, default 1000 [
|
|
59
|
+
effective irradiance at STC, default 1000 [Wm⁻²]
|
|
60
60
|
T0 : float
|
|
61
|
-
cell temperature at STC, default 25 [C]
|
|
61
|
+
cell temperature at STC, default 25°C. [°C]
|
|
62
62
|
k : float
|
|
63
63
|
Boltzmann's constant [J/K]
|
|
64
64
|
q : float
|
|
@@ -272,10 +272,10 @@ def pvsyst_temperature_coeff(alpha_sc, gamma_ref, mu_gamma, I_L_ref, I_o_ref,
|
|
|
272
272
|
Default of 1.121 eV is for crystalline silicon. Must be positive. [eV]
|
|
273
273
|
|
|
274
274
|
irrad_ref : float, default 1000
|
|
275
|
-
Reference irradiance. [
|
|
275
|
+
Reference irradiance. [Wm⁻²].
|
|
276
276
|
|
|
277
277
|
temp_ref : float, default 25
|
|
278
|
-
Reference cell temperature. [C]
|
|
278
|
+
Reference cell temperature. [°C]
|
|
279
279
|
|
|
280
280
|
|
|
281
281
|
Returns
|
|
@@ -327,7 +327,7 @@ def fit_pvsyst_iec61853_sandia_2025(effective_irradiance, temp_cell,
|
|
|
327
327
|
effective_irradiance : array
|
|
328
328
|
Effective irradiance for each test condition [W/m²]
|
|
329
329
|
temp_cell : array
|
|
330
|
-
Cell temperature for each test condition [C]
|
|
330
|
+
Cell temperature for each test condition. [°C]
|
|
331
331
|
i_sc : array
|
|
332
332
|
Short circuit current for each test condition [A]
|
|
333
333
|
v_oc : array
|
|
@@ -366,7 +366,7 @@ def fit_pvsyst_iec61853_sandia_2025(effective_irradiance, temp_cell,
|
|
|
366
366
|
temperature_tolerance : float, default 1
|
|
367
367
|
Tolerance for temperature variation around the STC value.
|
|
368
368
|
The default value corresponds to a +/- 1 degree interval around the STC
|
|
369
|
-
value of 25
|
|
369
|
+
value of 25°C. [°C]
|
|
370
370
|
|
|
371
371
|
Returns
|
|
372
372
|
-------
|
pvlib/modelchain.py
CHANGED
|
@@ -18,6 +18,8 @@ import pvlib.irradiance # avoid name conflict with full import
|
|
|
18
18
|
from pvlib.pvsystem import _DC_MODEL_PARAMS
|
|
19
19
|
from pvlib.tools import _build_kwargs
|
|
20
20
|
|
|
21
|
+
from pvlib._deprecation import deprecated
|
|
22
|
+
|
|
21
23
|
# keys that are used to detect input data and assign data to appropriate
|
|
22
24
|
# ModelChain attribute
|
|
23
25
|
# for ModelChain.weather
|
|
@@ -31,7 +33,7 @@ POA_KEYS = ('poa_global', 'poa_direct', 'poa_diffuse')
|
|
|
31
33
|
# 'cell_temperature' overrides ModelChain.temperature_model and sets
|
|
32
34
|
# ModelChain.cell_temperature to the data. If 'module_temperature' is provided,
|
|
33
35
|
# overrides ModelChain.temperature_model with
|
|
34
|
-
# pvlib.temperature.
|
|
36
|
+
# pvlib.temperature.sapm_cell_from_module
|
|
35
37
|
TEMPERATURE_KEYS = ('module_temperature', 'cell_temperature')
|
|
36
38
|
|
|
37
39
|
DATA_KEYS = WEATHER_KEYS + POA_KEYS + TEMPERATURE_KEYS
|
|
@@ -46,7 +48,7 @@ DATA_KEYS = WEATHER_KEYS + POA_KEYS + TEMPERATURE_KEYS
|
|
|
46
48
|
# for Flat-Plate Photovoltaic Arrays. SAND85-0330. Albuquerque, NM:
|
|
47
49
|
# Sandia National Laboratories. Accessed September 3, 2013:
|
|
48
50
|
# http://prod.sandia.gov/techlib/access-control.cgi/1985/850330.pdf
|
|
49
|
-
# pvlib
|
|
51
|
+
# pvlib-python does not implement that model, so it uses the SAPM instead.
|
|
50
52
|
PVWATTS_CONFIG = dict(
|
|
51
53
|
dc_model='pvwatts', ac_model='pvwatts', losses_model='pvwatts',
|
|
52
54
|
transposition_model='perez', aoi_model='physical',
|
|
@@ -59,6 +61,13 @@ SAPM_CONFIG = dict(
|
|
|
59
61
|
)
|
|
60
62
|
|
|
61
63
|
|
|
64
|
+
@deprecated(
|
|
65
|
+
since="0.13.1",
|
|
66
|
+
removal="",
|
|
67
|
+
name="pvlib.modelchain.get_orientation",
|
|
68
|
+
alternative=None,
|
|
69
|
+
addendum=None,
|
|
70
|
+
)
|
|
62
71
|
def get_orientation(strategy, **kwargs):
|
|
63
72
|
"""
|
|
64
73
|
Determine a PV system's surface tilt and surface azimuth
|
|
@@ -84,7 +93,7 @@ def get_orientation(strategy, **kwargs):
|
|
|
84
93
|
surface_tilt = 0
|
|
85
94
|
else:
|
|
86
95
|
raise ValueError('invalid orientation strategy. strategy must '
|
|
87
|
-
'be one of
|
|
96
|
+
'be one of south_at_latitude_tilt, flat,')
|
|
88
97
|
|
|
89
98
|
return surface_tilt, surface_azimuth
|
|
90
99
|
|
|
@@ -162,8 +171,8 @@ class ModelChainResult:
|
|
|
162
171
|
# per DC array information
|
|
163
172
|
total_irrad: Optional[PerArray[pd.DataFrame]] = field(default=None)
|
|
164
173
|
""" DataFrame (or tuple of DataFrame, one for each array) containing
|
|
165
|
-
columns ``'poa_global'``, ``'poa_direct'
|
|
166
|
-
``poa_sky_diffuse'``, ``'poa_ground_diffuse'`` (
|
|
174
|
+
columns ``'poa_global'``, ``'poa_direct'``, ``'poa_diffuse'``,
|
|
175
|
+
``poa_sky_diffuse'``, and ``'poa_ground_diffuse'`` (Wm⁻²); see
|
|
167
176
|
:py:func:`~pvlib.irradiance.get_total_irradiance` for details.
|
|
168
177
|
"""
|
|
169
178
|
|
|
@@ -190,12 +199,12 @@ class ModelChainResult:
|
|
|
190
199
|
|
|
191
200
|
cell_temperature: Optional[PerArray[pd.Series]] = field(default=None)
|
|
192
201
|
"""Series (or tuple of Series, one for each array) containing cell
|
|
193
|
-
temperature (C).
|
|
202
|
+
temperature (°C).
|
|
194
203
|
"""
|
|
195
204
|
|
|
196
205
|
effective_irradiance: Optional[PerArray[pd.Series]] = field(default=None)
|
|
197
206
|
"""Series (or tuple of Series, one for each array) containing effective
|
|
198
|
-
irradiance (
|
|
207
|
+
irradiance (Wm⁻²) which is total plane-of-array irradiance adjusted for
|
|
199
208
|
reflections and spectral content.
|
|
200
209
|
"""
|
|
201
210
|
|
|
@@ -215,12 +224,12 @@ class ModelChainResult:
|
|
|
215
224
|
|
|
216
225
|
dc_ohmic_losses: Optional[PerArray[pd.Series]] = field(default=None)
|
|
217
226
|
"""Series (or tuple of Series, one for each array) containing DC ohmic
|
|
218
|
-
|
|
227
|
+
losses (W) calculated by ``ModelChain.dc_ohmic_model``.
|
|
219
228
|
"""
|
|
220
229
|
|
|
221
230
|
# copies of input data, for user convenience
|
|
222
231
|
weather: Optional[PerArray[pd.DataFrame]] = None
|
|
223
|
-
"""DataFrame (or tuple of DataFrame, one for each array)
|
|
232
|
+
"""DataFrame (or tuple of DataFrame, one for each array) containing a
|
|
224
233
|
copy of the input weather data.
|
|
225
234
|
"""
|
|
226
235
|
|
|
@@ -806,7 +815,7 @@ class ModelChain:
|
|
|
806
815
|
'system.arrays[i].module_parameters. Check that '
|
|
807
816
|
'the module_parameters for all Arrays in '
|
|
808
817
|
'system.arrays contain parameters for the '
|
|
809
|
-
'physical,
|
|
818
|
+
'physical, sapm, ashrae, martin_ruiz or interp '
|
|
810
819
|
'model; explicitly set the model with the '
|
|
811
820
|
'aoi_model kwarg; or set aoi_model="no_loss".')
|
|
812
821
|
|
pvlib/pvarray.py
CHANGED
|
@@ -37,7 +37,7 @@ def pvefficiency_adr(effective_irradiance, temp_cell,
|
|
|
37
37
|
the reference conditions. [unitless]
|
|
38
38
|
|
|
39
39
|
k_d : numeric, negative
|
|
40
|
-
|
|
40
|
+
"Dark irradiance" or diode coefficient which influences the voltage
|
|
41
41
|
increase with irradiance. [unitless]
|
|
42
42
|
|
|
43
43
|
tc_d : numeric
|
|
@@ -225,24 +225,55 @@ def fit_pvefficiency_adr(effective_irradiance, temp_cell, eta,
|
|
|
225
225
|
return popt
|
|
226
226
|
|
|
227
227
|
|
|
228
|
-
def _infer_k_huld(cell_type, pdc0):
|
|
228
|
+
def _infer_k_huld(cell_type, pdc0, k_version):
|
|
229
|
+
r"""
|
|
230
|
+
Get the EU JRC updated coefficients for the Huld model.
|
|
231
|
+
|
|
232
|
+
Parameters
|
|
233
|
+
----------
|
|
234
|
+
cell_type : str
|
|
235
|
+
Must be one of 'csi', 'cis', or 'cdte'
|
|
236
|
+
pdc0 : numeric
|
|
237
|
+
Power of the modules at reference conditions [W]
|
|
238
|
+
k_version : str
|
|
239
|
+
Either 'pvgis5' or 'pvgis6'.
|
|
240
|
+
|
|
241
|
+
Returns
|
|
242
|
+
-------
|
|
243
|
+
tuple
|
|
244
|
+
The six coefficients (k1-k6) for the Huld model, scaled by pdc0
|
|
245
|
+
"""
|
|
229
246
|
# from PVGIS documentation, "PVGIS data sources & calculation methods",
|
|
230
247
|
# Section 5.2.3, accessed 12/22/2023
|
|
231
248
|
# The parameters in PVGIS' documentation are for a version of Huld's
|
|
232
249
|
# equation that has factored Pdc0 out of the polynomial:
|
|
233
250
|
# P = G/1000 * Pdc0 * (1 + k1 log(Geff) + ...) so these parameters are
|
|
234
251
|
# multiplied by pdc0
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
252
|
+
if k_version.lower() == 'pvgis5':
|
|
253
|
+
# coefficients from PVGIS webpage
|
|
254
|
+
huld_params = {'csi': (-0.017237, -0.040465, -0.004702, 0.000149,
|
|
255
|
+
0.000170, 0.000005),
|
|
256
|
+
'cis': (-0.005554, -0.038724, -0.003723, -0.000905,
|
|
257
|
+
-0.001256, 0.000001),
|
|
258
|
+
'cdte': (-0.046689, -0.072844, -0.002262, 0.000276,
|
|
259
|
+
0.000159, -0.000006)}
|
|
260
|
+
elif k_version.lower() == 'pvgis6':
|
|
261
|
+
# Coefficients from EU JRC paper
|
|
262
|
+
huld_params = {'csi': (-0.0067560, -0.016444, -0.003015, -0.000045,
|
|
263
|
+
-0.000043, 0.0),
|
|
264
|
+
'cis': (-0.011001, -0.029734, -0.002887, 0.000217,
|
|
265
|
+
-0.000163, 0.0),
|
|
266
|
+
'cdte': (-0.020644, -0.035136, -0.003406, 0.000073,
|
|
267
|
+
-0.000141, 0.000002)}
|
|
268
|
+
else:
|
|
269
|
+
raise ValueError(f'Invalid k_version={k_version}: must be either '
|
|
270
|
+
'"pvgis5" or "pvgis6"')
|
|
241
271
|
k = tuple([x*pdc0 for x in huld_params[cell_type.lower()]])
|
|
242
272
|
return k
|
|
243
273
|
|
|
244
274
|
|
|
245
|
-
def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None
|
|
275
|
+
def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None,
|
|
276
|
+
k_version='pvgis5'):
|
|
246
277
|
r"""
|
|
247
278
|
Power (DC) using the Huld model.
|
|
248
279
|
|
|
@@ -274,6 +305,11 @@ def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None):
|
|
|
274
305
|
cell_type : str, optional
|
|
275
306
|
If provided, must be one of ``'cSi'``, ``'CIS'``, or ``'CdTe'``.
|
|
276
307
|
Used to look up default values for ``k`` if ``k`` is not specified.
|
|
308
|
+
k_version : str, optional
|
|
309
|
+
Either ``'pvgis5'`` (default) or ``'pvgis6'``. Selects values
|
|
310
|
+
for ``k`` if ``k`` is not specified. If ``'pvgis5'``, values are
|
|
311
|
+
from PVGIS documentation and are labeled in [2]_ as "current".
|
|
312
|
+
If ``'pvgis6'`` values are from [2]_ labeled as "updated".
|
|
277
313
|
|
|
278
314
|
Returns
|
|
279
315
|
-------
|
|
@@ -328,14 +364,19 @@ def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None):
|
|
|
328
364
|
|
|
329
365
|
References
|
|
330
366
|
----------
|
|
331
|
-
.. [1] T. Huld, G. Friesen, A. Skoczek, R. Kenny, T. Sample, M. Field,
|
|
332
|
-
E. Dunlop
|
|
333
|
-
Solar Energy Materials and Solar Cells 95, (2011),
|
|
334
|
-
:doi:`10.1016/j.solmat.2011.07.026`.
|
|
367
|
+
.. [1] T. Huld, G. Friesen, A. Skoczek, R. Kenny, T. Sample, M. Field, and
|
|
368
|
+
E. Dunlop, "A power-rating model for crystalline silicon PV
|
|
369
|
+
modules," Solar Energy Materials and Solar Cells 95, (2011),
|
|
370
|
+
pp. 3359-3369. :doi:`10.1016/j.solmat.2011.07.026`.
|
|
371
|
+
.. [2] A. Chatzipanagi, N. Taylor, I. Suarez, A. Martinez, T. Lyubenova,
|
|
372
|
+
and E. Dunlop, "An Updated Simplified Energy Yield Model for Recent
|
|
373
|
+
Photovoltaic Module Technologies,"
|
|
374
|
+
Progress in Photovoltaics: Research and Applications 33,
|
|
375
|
+
no. 8 (2025): 905–917, :doi:`10.1002/pip.3926`.
|
|
335
376
|
"""
|
|
336
377
|
if k is None:
|
|
337
378
|
if cell_type is not None:
|
|
338
|
-
k = _infer_k_huld(cell_type, pdc0)
|
|
379
|
+
k = _infer_k_huld(cell_type, pdc0, k_version)
|
|
339
380
|
else:
|
|
340
381
|
raise ValueError('Either k or cell_type must be specified')
|
|
341
382
|
|
|
@@ -346,7 +387,10 @@ def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None):
|
|
|
346
387
|
logGprime = np.log(gprime, out=np.zeros_like(gprime),
|
|
347
388
|
where=np.array(gprime > 0))
|
|
348
389
|
# Eq. 1 in [1]
|
|
349
|
-
pdc = gprime * (
|
|
350
|
-
|
|
351
|
-
|
|
390
|
+
pdc = gprime * (
|
|
391
|
+
pdc0 + k[0] * logGprime + k[1] * logGprime**2 +
|
|
392
|
+
k[2] * tprime + k[3] * tprime * logGprime +
|
|
393
|
+
k[4] * tprime * logGprime**2 +
|
|
394
|
+
k[5] * tprime**2
|
|
395
|
+
)
|
|
352
396
|
return pdc
|
pvlib/singlediode.py
CHANGED
|
@@ -696,27 +696,34 @@ def _lambertw_v_from_i(current, photocurrent, saturation_current,
|
|
|
696
696
|
|
|
697
697
|
# Only compute using LambertW if there are cases with Gsh>0
|
|
698
698
|
if np.any(idx_p):
|
|
699
|
+
|
|
700
|
+
# use only the relevant subset for what follows
|
|
701
|
+
I = I[idx_p]
|
|
702
|
+
IL = IL[idx_p]
|
|
703
|
+
I0 = I0[idx_p]
|
|
704
|
+
Rs = Rs[idx_p]
|
|
705
|
+
Gsh = Gsh[idx_p]
|
|
706
|
+
a = a[idx_p]
|
|
707
|
+
|
|
699
708
|
# LambertW argument, cannot be float128, may overflow to np.inf
|
|
700
709
|
# overflow is explicitly handled below, so ignore warnings here
|
|
701
710
|
with np.errstate(over='ignore'):
|
|
702
|
-
argW =
|
|
703
|
-
np.exp((-I[idx_p] + IL[idx_p] + I0[idx_p]) /
|
|
704
|
-
(Gsh[idx_p] * a[idx_p])))
|
|
711
|
+
argW = I0 / (Gsh * a) * np.exp((-I + IL + I0) / (Gsh * a))
|
|
705
712
|
|
|
706
713
|
# lambertw typically returns complex value with zero imaginary part
|
|
707
714
|
# may overflow to np.inf
|
|
708
715
|
lambertwterm = lambertw(argW).real
|
|
709
716
|
|
|
710
717
|
# Record indices where lambertw input overflowed output
|
|
711
|
-
idx_inf = np.
|
|
718
|
+
idx_inf = np.isinf(lambertwterm)
|
|
712
719
|
|
|
713
720
|
# Only re-compute LambertW if it overflowed
|
|
714
721
|
if np.any(idx_inf):
|
|
715
722
|
# Calculate using log(argW) in case argW is really big
|
|
716
|
-
logargW = (np.log(I0[
|
|
717
|
-
np.log(a[
|
|
718
|
-
(-I[
|
|
719
|
-
(Gsh[
|
|
723
|
+
logargW = (np.log(I0[idx_inf]) - np.log(Gsh[idx_inf]) -
|
|
724
|
+
np.log(a[idx_inf]) +
|
|
725
|
+
(-I[idx_inf] + IL[idx_inf] + I0[idx_inf]) /
|
|
726
|
+
(Gsh[idx_inf] * a[idx_inf]))
|
|
720
727
|
|
|
721
728
|
# Three iterations of Newton-Raphson method to solve
|
|
722
729
|
# w+log(w)=logargW. The initial guess is w=logargW. Where direct
|
|
@@ -730,8 +737,7 @@ def _lambertw_v_from_i(current, photocurrent, saturation_current,
|
|
|
730
737
|
# Eqn. 3 in Jain and Kapoor, 2004
|
|
731
738
|
# V = -I*(Rs + Rsh) + IL*Rsh - a*lambertwterm + I0*Rsh
|
|
732
739
|
# Recast in terms of Gsh=1/Rsh for better numerical stability.
|
|
733
|
-
V[idx_p] = (IL
|
|
734
|
-
I[idx_p] * Rs[idx_p] - a[idx_p] * lambertwterm
|
|
740
|
+
V[idx_p] = (IL + I0 - I) / Gsh - I * Rs - a * lambertwterm
|
|
735
741
|
|
|
736
742
|
if output_is_scalar:
|
|
737
743
|
return V.item()
|
pvlib/solarposition.py
CHANGED
|
@@ -285,7 +285,7 @@ def spa_python(time, latitude, longitude,
|
|
|
285
285
|
Calculate the solar position using a python implementation of the
|
|
286
286
|
NREL SPA algorithm.
|
|
287
287
|
|
|
288
|
-
The details of the NREL SPA algorithm are described in [1]_.
|
|
288
|
+
The details of the NREL SPA algorithm are described in [1]_, [2]_.
|
|
289
289
|
|
|
290
290
|
If numba is installed, the functions can be compiled to
|
|
291
291
|
machine code and the function can be multithreaded.
|
|
@@ -328,25 +328,26 @@ def spa_python(time, latitude, longitude,
|
|
|
328
328
|
-------
|
|
329
329
|
DataFrame
|
|
330
330
|
The DataFrame will have the following columns:
|
|
331
|
-
apparent_zenith (degrees),
|
|
332
|
-
zenith (degrees),
|
|
333
|
-
apparent_elevation (degrees),
|
|
334
|
-
elevation (degrees),
|
|
335
|
-
azimuth (degrees),
|
|
336
|
-
equation_of_time (minutes).
|
|
337
331
|
|
|
332
|
+
- apparent_zenith (degrees),
|
|
333
|
+
- zenith (degrees),
|
|
334
|
+
- apparent_elevation (degrees),
|
|
335
|
+
- elevation (degrees),
|
|
336
|
+
- azimuth (degrees),
|
|
337
|
+
- equation_of_time (minutes).
|
|
338
338
|
|
|
339
339
|
References
|
|
340
340
|
----------
|
|
341
341
|
.. [1] I. Reda and A. Andreas, Solar position algorithm for solar
|
|
342
342
|
radiation applications. Solar Energy, vol. 76, no. 5, pp. 577-589, 2004.
|
|
343
|
+
:doi:`10.1016/j.solener.2003.12.003`.
|
|
343
344
|
|
|
344
345
|
.. [2] I. Reda and A. Andreas, Corrigendum to Solar position algorithm for
|
|
345
346
|
solar radiation applications. Solar Energy, vol. 81, no. 6, p. 838,
|
|
346
|
-
2007.
|
|
347
|
+
2007. :doi:`10.1016/j.solener.2007.01.003`.
|
|
347
348
|
|
|
348
|
-
.. [3]
|
|
349
|
-
https://maia.usno.navy.mil/products/deltaT
|
|
349
|
+
.. [3] `U.S. Naval Observatory, delta T
|
|
350
|
+
<https://maia.usno.navy.mil/products/deltaT>`_
|
|
350
351
|
|
|
351
352
|
See also
|
|
352
353
|
--------
|
pvlib/spectrum/mismatch.py
CHANGED
|
@@ -239,27 +239,15 @@ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
|
|
|
239
239
|
"""
|
|
240
240
|
pw = np.atleast_1d(precipitable_water)
|
|
241
241
|
pw = pw.astype('float64')
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
warn('Low precipitable water values replaced with '
|
|
245
|
-
f'{min_precipitable_water} cm in the calculation of spectral '
|
|
246
|
-
'mismatch.')
|
|
247
|
-
|
|
248
|
-
if np.max(pw) > max_precipitable_water:
|
|
249
|
-
pw[pw > max_precipitable_water] = np.nan
|
|
250
|
-
warn('High precipitable water values replaced with np.nan in '
|
|
251
|
-
'the calculation of spectral mismatch.')
|
|
242
|
+
pw = np.maximum(pw, min_precipitable_water)
|
|
243
|
+
pw[pw > max_precipitable_water] = np.nan
|
|
252
244
|
|
|
253
245
|
airmass_absolute = np.minimum(airmass_absolute, max_airmass_absolute)
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
# pvlib.atmosphere.get_absolute_airmass(1,
|
|
260
|
-
# pvlib.atmosphere.alt2pres(4340)) = 0.58 Elevation of
|
|
261
|
-
# Mina Pirquita, Argentian = 4340 m. Highest elevation city with
|
|
262
|
-
# population over 50,000.
|
|
246
|
+
# pvlib.atmosphere.get_absolute_airmass(1,
|
|
247
|
+
# pvlib.atmosphere.alt2pres(4340)) = 0.58 Elevation of
|
|
248
|
+
# Mina Pirquita, Argentian = 4340 m. Highest elevation city with
|
|
249
|
+
# population over 50,000.
|
|
250
|
+
airmass_absolute = np.maximum(airmass_absolute, min_airmass_absolute)
|
|
263
251
|
|
|
264
252
|
_coefficients = {}
|
|
265
253
|
_coefficients['cdte'] = (
|
pvlib/temperature.py
CHANGED
|
@@ -618,7 +618,7 @@ def faiman_rad(poa_global, temp_air, wind_speed=1.0, ir_down=None,
|
|
|
618
618
|
return temp_air + temp_difference
|
|
619
619
|
|
|
620
620
|
|
|
621
|
-
def ross(poa_global, temp_air, noct):
|
|
621
|
+
def ross(poa_global, temp_air, noct=None, k=None):
|
|
622
622
|
r'''
|
|
623
623
|
Calculate cell temperature using the Ross model.
|
|
624
624
|
|
|
@@ -630,14 +630,19 @@ def ross(poa_global, temp_air, noct):
|
|
|
630
630
|
Parameters
|
|
631
631
|
----------
|
|
632
632
|
poa_global : numeric
|
|
633
|
-
Total incident irradiance. [W/m
|
|
633
|
+
Total incident irradiance. [W/m⁻²]
|
|
634
634
|
|
|
635
635
|
temp_air : numeric
|
|
636
636
|
Ambient dry bulb temperature. [C]
|
|
637
637
|
|
|
638
|
-
noct : numeric
|
|
638
|
+
noct : numeric, optional
|
|
639
639
|
Nominal operating cell temperature [C], determined at conditions of
|
|
640
|
-
800 W/m
|
|
640
|
+
800 W/m⁻² irradiance, 20 C ambient air temperature and 1 m/s wind.
|
|
641
|
+
If ``noct`` is not provided, ``k`` is required.
|
|
642
|
+
k: numeric, optional
|
|
643
|
+
Ross coefficient [Km²W⁻¹], which is an alternative to employing
|
|
644
|
+
NOCT in Ross's equation. If ``k`` is not provided, ``noct`` is
|
|
645
|
+
required.
|
|
641
646
|
|
|
642
647
|
Returns
|
|
643
648
|
-------
|
|
@@ -650,19 +655,62 @@ def ross(poa_global, temp_air, noct):
|
|
|
650
655
|
|
|
651
656
|
.. math::
|
|
652
657
|
|
|
653
|
-
T_{C} = T_{a} + \frac{NOCT - 20}{80} S
|
|
654
|
-
|
|
655
|
-
where :math:`S` is the plane of array irradiance in
|
|
656
|
-
This function expects irradiance in
|
|
658
|
+
T_{C} = T_{a} + \frac{NOCT - 20}{80} S = T_{a} + k × S
|
|
659
|
+
|
|
660
|
+
where :math:`S` is the plane of array irradiance in mWcm⁻².
|
|
661
|
+
This function expects irradiance in Wm⁻².
|
|
662
|
+
|
|
663
|
+
Representative values for k are provided in [2]_, covering different types
|
|
664
|
+
of mounting and degrees of back ventialtion. The naming designations,
|
|
665
|
+
however, are adapted from [3]_ to enhance clarity and usability.
|
|
666
|
+
|
|
667
|
+
+--------------------------------------+-----------+
|
|
668
|
+
| Mounting | :math:`k` |
|
|
669
|
+
+======================================+===========+
|
|
670
|
+
| Sloped roof, well ventilated | 0.02 |
|
|
671
|
+
+--------------------------------------+-----------+
|
|
672
|
+
| Free-standing system | 0.0208 |
|
|
673
|
+
+--------------------------------------+-----------+
|
|
674
|
+
| Flat roof, well ventilated | 0.026 |
|
|
675
|
+
+--------------------------------------+-----------+
|
|
676
|
+
| Sloped roof, poorly ventilated | 0.0342 |
|
|
677
|
+
+--------------------------------------+-----------+
|
|
678
|
+
| Facade integrated, semi-ventilated | 0.0455 |
|
|
679
|
+
+--------------------------------------+-----------+
|
|
680
|
+
| Facade integrated, poorly ventilated | 0.0538 |
|
|
681
|
+
+--------------------------------------+-----------+
|
|
682
|
+
| Sloped roof, non-ventilated | 0.0563 |
|
|
683
|
+
+--------------------------------------+-----------+
|
|
684
|
+
|
|
685
|
+
It is also worth noting that the semi-ventilated facade case refers to
|
|
686
|
+
partly transparent compound glass insulation modules, while the non-
|
|
687
|
+
ventilated case corresponds to opaque, insulated PV-cladding elements.
|
|
688
|
+
However, the emphasis in [3]_ appears to be on ventilation conditions
|
|
689
|
+
rather than module construction.
|
|
657
690
|
|
|
658
691
|
References
|
|
659
692
|
----------
|
|
660
693
|
.. [1] Ross, R. G. Jr., (1981). "Design Techniques for Flat-Plate
|
|
661
694
|
Photovoltaic Arrays". 15th IEEE Photovoltaic Specialist Conference,
|
|
662
695
|
Orlando, FL.
|
|
696
|
+
.. [2] E. Skoplaki and J. A. Palyvos, "Operating temperature of
|
|
697
|
+
photovoltaic modules: A survey of pertinent correlations," Renewable
|
|
698
|
+
Energy, vol. 34, no. 1, pp. 23–29, Jan. 2009,
|
|
699
|
+
:doi:`10.1016/j.renene.2008.04.009`
|
|
700
|
+
.. [3] T. Nordmann and L. Clavadetscher, "Understanding temperature
|
|
701
|
+
effects on PV system performance," Proceedings of 3rd World Conference
|
|
702
|
+
on Photovoltaic Energy Conversion, May 2003.
|
|
663
703
|
'''
|
|
664
|
-
|
|
665
|
-
|
|
704
|
+
if (noct is None) & (k is None):
|
|
705
|
+
raise ValueError("Either noct or k is required.")
|
|
706
|
+
elif (noct is not None) & (k is not None):
|
|
707
|
+
raise ValueError("Provide only one of noct or k, not both.")
|
|
708
|
+
elif k is None:
|
|
709
|
+
# factor of 0.1 converts irradiance from W/m2 to mW/cm2
|
|
710
|
+
return temp_air + (noct - 20.) / 80. * poa_global * 0.1
|
|
711
|
+
elif noct is None:
|
|
712
|
+
# k assumes irradiance in W.m-2, dismissing 0.1 factor
|
|
713
|
+
return temp_air + k * poa_global
|
|
666
714
|
|
|
667
715
|
|
|
668
716
|
def _fuentes_hconv(tave, windmod, tinoct, temp_delta, xlen, tilt,
|
pvlib/tools.py
CHANGED
|
@@ -562,7 +562,7 @@ def normalize_max2one(a):
|
|
|
562
562
|
return res
|
|
563
563
|
|
|
564
564
|
|
|
565
|
-
def _file_context_manager(filename_or_object, mode='r'):
|
|
565
|
+
def _file_context_manager(filename_or_object, mode='r', encoding=None):
|
|
566
566
|
"""
|
|
567
567
|
Open a filename/path for reading, or pass a file-like object
|
|
568
568
|
through unchanged.
|
|
@@ -584,5 +584,5 @@ def _file_context_manager(filename_or_object, mode='r'):
|
|
|
584
584
|
context = contextlib.nullcontext(filename_or_object)
|
|
585
585
|
else:
|
|
586
586
|
# otherwise, assume a filename or path
|
|
587
|
-
context = open(str(filename_or_object), mode=mode)
|
|
587
|
+
context = open(str(filename_or_object), mode=mode, encoding=encoding)
|
|
588
588
|
return context
|
pvlib/tracking.py
CHANGED
|
@@ -4,9 +4,14 @@ import pandas as pd
|
|
|
4
4
|
from pvlib.tools import cosd, sind, tand, acosd, asind
|
|
5
5
|
from pvlib import irradiance
|
|
6
6
|
from pvlib import shading
|
|
7
|
+
from pvlib._deprecation import renamed_kwarg_warning
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
@renamed_kwarg_warning(
|
|
11
|
+
since='0.13.1',
|
|
12
|
+
old_param_name='apparent_azimuth',
|
|
13
|
+
new_param_name='solar_azimuth')
|
|
14
|
+
def singleaxis(apparent_zenith, solar_azimuth,
|
|
10
15
|
axis_tilt=0, axis_azimuth=0, max_angle=90,
|
|
11
16
|
backtrack=True, gcr=2.0/7.0, cross_axis_tilt=0):
|
|
12
17
|
"""
|
|
@@ -33,7 +38,7 @@ def singleaxis(apparent_zenith, apparent_azimuth,
|
|
|
33
38
|
apparent_zenith : float, 1d array, or Series
|
|
34
39
|
Solar apparent zenith angles in decimal degrees.
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
solar_azimuth : float, 1d array, or Series
|
|
37
42
|
Solar apparent azimuth angles in decimal degrees.
|
|
38
43
|
|
|
39
44
|
axis_tilt : float, default 0
|
|
@@ -123,10 +128,10 @@ def singleaxis(apparent_zenith, apparent_azimuth,
|
|
|
123
128
|
index = None
|
|
124
129
|
|
|
125
130
|
# convert scalars to arrays
|
|
126
|
-
|
|
131
|
+
solar_azimuth = np.atleast_1d(solar_azimuth)
|
|
127
132
|
apparent_zenith = np.atleast_1d(apparent_zenith)
|
|
128
133
|
|
|
129
|
-
if
|
|
134
|
+
if solar_azimuth.ndim > 1 or apparent_zenith.ndim > 1:
|
|
130
135
|
raise ValueError('Input dimensions must not exceed 1')
|
|
131
136
|
|
|
132
137
|
# The ideal tracking angle, omega_ideal, is the rotation to place the sun
|
|
@@ -142,7 +147,7 @@ def singleaxis(apparent_zenith, apparent_azimuth,
|
|
|
142
147
|
axis_tilt=axis_tilt,
|
|
143
148
|
axis_azimuth=axis_azimuth,
|
|
144
149
|
solar_zenith=apparent_zenith,
|
|
145
|
-
solar_azimuth=
|
|
150
|
+
solar_azimuth=solar_azimuth,
|
|
146
151
|
)
|
|
147
152
|
|
|
148
153
|
# filter for sun above panel horizon
|
|
@@ -191,7 +196,7 @@ def singleaxis(apparent_zenith, apparent_azimuth,
|
|
|
191
196
|
surface_tilt = surface['surface_tilt']
|
|
192
197
|
surface_azimuth = surface['surface_azimuth']
|
|
193
198
|
aoi = irradiance.aoi(surface_tilt, surface_azimuth,
|
|
194
|
-
apparent_zenith,
|
|
199
|
+
apparent_zenith, solar_azimuth)
|
|
195
200
|
|
|
196
201
|
# Bundle DataFrame for return values and filter for sun below horizon.
|
|
197
202
|
out = {'tracker_theta': tracker_theta, 'aoi': aoi,
|