pvlib 0.10.3__py3-none-any.whl → 0.10.5__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/__init__.py +1 -0
- pvlib/bifacial/utils.py +2 -1
- pvlib/clearsky.py +7 -8
- pvlib/iam.py +3 -3
- pvlib/inverter.py +3 -3
- pvlib/iotools/__init__.py +2 -0
- pvlib/iotools/solargis.py +214 -0
- pvlib/iotools/solcast.py +2 -7
- pvlib/iotools/solrad.py +121 -23
- pvlib/iotools/srml.py +12 -12
- pvlib/iotools/surfrad.py +2 -2
- pvlib/irradiance.py +28 -22
- pvlib/location.py +3 -1
- pvlib/modelchain.py +10 -9
- pvlib/pvarray.py +127 -0
- pvlib/pvsystem.py +52 -43
- pvlib/scaling.py +4 -2
- pvlib/shading.py +110 -0
- pvlib/singlediode.py +37 -9
- pvlib/snow.py +3 -1
- pvlib/solarposition.py +38 -30
- pvlib/spa.py +3 -11
- pvlib/spectrum/mismatch.py +2 -1
- pvlib/temperature.py +3 -2
- pvlib/tests/bifacial/test_utils.py +6 -5
- pvlib/tests/conftest.py +13 -14
- pvlib/tests/iotools/test_sodapro.py +2 -1
- pvlib/tests/iotools/test_solargis.py +68 -0
- pvlib/tests/iotools/test_solcast.py +2 -2
- pvlib/tests/iotools/test_solrad.py +58 -7
- pvlib/tests/iotools/test_srml.py +7 -14
- pvlib/tests/test_clearsky.py +1 -1
- pvlib/tests/test_irradiance.py +24 -8
- pvlib/tests/test_location.py +1 -1
- pvlib/tests/test_modelchain.py +37 -26
- pvlib/tests/test_pvarray.py +25 -0
- pvlib/tests/test_pvsystem.py +76 -104
- pvlib/tests/test_shading.py +130 -11
- pvlib/tests/test_singlediode.py +68 -10
- pvlib/tests/test_snow.py +1 -1
- pvlib/tests/test_solarposition.py +121 -7
- pvlib/tests/test_spa.py +5 -15
- pvlib/tests/test_temperature.py +4 -4
- pvlib/tests/test_tracking.py +2 -2
- pvlib/tracking.py +8 -38
- pvlib/version.py +1 -5
- {pvlib-0.10.3.dist-info → pvlib-0.10.5.dist-info}/METADATA +9 -33
- {pvlib-0.10.3.dist-info → pvlib-0.10.5.dist-info}/RECORD +52 -51
- {pvlib-0.10.3.dist-info → pvlib-0.10.5.dist-info}/WHEEL +1 -1
- pvlib/spa_c_files/SPA_NOTICE.md +0 -39
- {pvlib-0.10.3.dist-info → pvlib-0.10.5.dist-info}/AUTHORS.md +0 -0
- {pvlib-0.10.3.dist-info → pvlib-0.10.5.dist-info}/LICENSE +0 -0
- {pvlib-0.10.3.dist-info → pvlib-0.10.5.dist-info}/top_level.txt +0 -0
pvlib/irradiance.py
CHANGED
|
@@ -73,7 +73,7 @@ def get_extra_radiation(datetime_or_doy, solar_constant=1366.1,
|
|
|
73
73
|
Clear Sky Models: Implementation and Analysis", Sandia National
|
|
74
74
|
Laboratories, SAND2012-2389, 2012.
|
|
75
75
|
|
|
76
|
-
.. [2]
|
|
76
|
+
.. [2] http://solardata.uoregon.edu/SolarRadiationBasics.html, Eqs.
|
|
77
77
|
SR1 and SR2
|
|
78
78
|
|
|
79
79
|
.. [3] Partridge, G. W. and Platt, C. M. R. 1976. Radiative Processes
|
|
@@ -551,13 +551,16 @@ def poa_components(aoi, dni, poa_sky_diffuse, poa_ground_diffuse):
|
|
|
551
551
|
|
|
552
552
|
|
|
553
553
|
def get_ground_diffuse(surface_tilt, ghi, albedo=.25, surface_type=None):
|
|
554
|
-
'''
|
|
555
|
-
Estimate diffuse irradiance from ground reflections
|
|
556
|
-
|
|
554
|
+
r'''
|
|
555
|
+
Estimate diffuse irradiance on a tilted surface from ground reflections.
|
|
556
|
+
|
|
557
|
+
Ground diffuse irradiance is calculated as
|
|
558
|
+
|
|
559
|
+
.. math::
|
|
560
|
+
|
|
561
|
+
G_{ground} = GHI \times \rho \times \frac{1 - \cos\beta}{2}
|
|
557
562
|
|
|
558
|
-
|
|
559
|
-
due to ground reflections. Any of the inputs may be DataFrames or
|
|
560
|
-
scalars.
|
|
563
|
+
where :math:`\rho` is ``albedo`` and :math:`\beta` is ``surface_tilt``.
|
|
561
564
|
|
|
562
565
|
Parameters
|
|
563
566
|
----------
|
|
@@ -567,13 +570,13 @@ def get_ground_diffuse(surface_tilt, ghi, albedo=.25, surface_type=None):
|
|
|
567
570
|
(e.g. surface facing up = 0, surface facing horizon = 90).
|
|
568
571
|
|
|
569
572
|
ghi : numeric
|
|
570
|
-
Global horizontal irradiance.
|
|
573
|
+
Global horizontal irradiance. :math:`W/m^2`
|
|
571
574
|
|
|
572
575
|
albedo : numeric, default 0.25
|
|
573
576
|
Ground reflectance, typically 0.1-0.4 for surfaces on Earth
|
|
574
577
|
(land), may increase over snow, ice, etc. May also be known as
|
|
575
578
|
the reflection coefficient. Must be >=0 and <=1. Will be
|
|
576
|
-
overridden if surface_type is supplied.
|
|
579
|
+
overridden if ``surface_type`` is supplied.
|
|
577
580
|
|
|
578
581
|
surface_type : string, optional
|
|
579
582
|
If supplied, overrides ``albedo``. ``surface_type`` can be one of
|
|
@@ -584,23 +587,23 @@ def get_ground_diffuse(surface_tilt, ghi, albedo=.25, surface_type=None):
|
|
|
584
587
|
Returns
|
|
585
588
|
-------
|
|
586
589
|
grounddiffuse : numeric
|
|
587
|
-
Ground reflected irradiance.
|
|
590
|
+
Ground reflected irradiance. :math:`W/m^2`
|
|
588
591
|
|
|
592
|
+
Notes
|
|
593
|
+
-----
|
|
594
|
+
Table of albedo values by ``surface_type`` are from [2]_, [3]_, [4]_;
|
|
595
|
+
see :py:data:`~pvlib.irradiance.SURFACE_ALBEDOS`.
|
|
589
596
|
|
|
590
597
|
References
|
|
591
598
|
----------
|
|
592
599
|
.. [1] Loutzenhiser P.G. et. al. "Empirical validation of models to compute
|
|
593
600
|
solar irradiance on inclined surfaces for building energy simulation"
|
|
594
601
|
2007, Solar Energy vol. 81. pp. 254-267.
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
and
|
|
601
|
-
http://en.wikipedia.org/wiki/Albedo
|
|
602
|
-
and
|
|
603
|
-
https://doi.org/10.1175/1520-0469(1972)029<0959:AOTSS>2.0.CO;2
|
|
602
|
+
.. [2] https://www.pvsyst.com/help/albedo.htm Accessed January, 2024.
|
|
603
|
+
.. [3] http://en.wikipedia.org/wiki/Albedo Accessed January, 2024.
|
|
604
|
+
.. [4] Payne, R. E. "Albedo of the Sea Surface". J. Atmos. Sci., 29,
|
|
605
|
+
pp. 959–970, 1972.
|
|
606
|
+
:doi:`10.1175/1520-0469(1972)029<0959:AOTSS>2.0.CO;2`
|
|
604
607
|
'''
|
|
605
608
|
|
|
606
609
|
if surface_type is not None:
|
|
@@ -1555,8 +1558,8 @@ def ghi_from_poa_driesse_2023(surface_tilt, surface_azimuth,
|
|
|
1555
1558
|
albedo : numeric, default 0.25
|
|
1556
1559
|
Ground surface albedo. [unitless]
|
|
1557
1560
|
xtol : numeric, default 0.01
|
|
1558
|
-
Convergence criterion.
|
|
1559
|
-
true value. [W/m^2]
|
|
1561
|
+
Convergence criterion. The estimated GHI will be within xtol of the
|
|
1562
|
+
true value. Must be positive. [W/m^2]
|
|
1560
1563
|
full_output : boolean, default False
|
|
1561
1564
|
If full_output is False, only ghi is returned, otherwise the return
|
|
1562
1565
|
value is (ghi, converged, niter). (see Returns section for details).
|
|
@@ -1591,13 +1594,16 @@ def ghi_from_poa_driesse_2023(surface_tilt, surface_azimuth,
|
|
|
1591
1594
|
'''
|
|
1592
1595
|
# Contributed by Anton Driesse (@adriesse), PV Performance Labs. Nov., 2023
|
|
1593
1596
|
|
|
1597
|
+
if xtol <= 0:
|
|
1598
|
+
raise ValueError(f"xtol too small ({xtol:g} <= 0)")
|
|
1599
|
+
|
|
1594
1600
|
ghi_from_poa_array = np.vectorize(_ghi_from_poa)
|
|
1595
1601
|
|
|
1596
1602
|
ghi, conv, niter = ghi_from_poa_array(surface_tilt, surface_azimuth,
|
|
1597
1603
|
solar_zenith, solar_azimuth,
|
|
1598
1604
|
poa_global,
|
|
1599
1605
|
dni_extra, airmass, albedo,
|
|
1600
|
-
xtol=
|
|
1606
|
+
xtol=xtol)
|
|
1601
1607
|
|
|
1602
1608
|
if isinstance(poa_global, pd.Series):
|
|
1603
1609
|
ghi = pd.Series(ghi, poa_global.index)
|
pvlib/location.py
CHANGED
|
@@ -439,8 +439,10 @@ def lookup_altitude(latitude, longitude):
|
|
|
439
439
|
# 255 is a special value that means nodata. Fallback to 0 if nodata.
|
|
440
440
|
if alt == 255:
|
|
441
441
|
return 0
|
|
442
|
+
# convert from np.uint8 to float so that the following operations succeed
|
|
443
|
+
alt = float(alt)
|
|
442
444
|
# Altitude is encoded in 28 meter steps from -450 meters to 6561 meters
|
|
443
445
|
# There are 0-254 possible altitudes, with 255 reserved for nodata.
|
|
444
446
|
alt *= 28
|
|
445
447
|
alt -= 450
|
|
446
|
-
return
|
|
448
|
+
return alt
|
pvlib/modelchain.py
CHANGED
|
@@ -1117,10 +1117,7 @@ class ModelChain:
|
|
|
1117
1117
|
temperature_model_parameters = tuple(
|
|
1118
1118
|
array.temperature_model_parameters for array in self.system.arrays)
|
|
1119
1119
|
params = _common_keys(temperature_model_parameters)
|
|
1120
|
-
|
|
1121
|
-
if {'a', 'b', 'deltaT'} <= params or (
|
|
1122
|
-
not params and self.system.racking_model is None
|
|
1123
|
-
and self.system.module_type is None):
|
|
1120
|
+
if {'a', 'b', 'deltaT'} <= params:
|
|
1124
1121
|
return self.sapm_temp
|
|
1125
1122
|
elif {'u_c', 'u_v'} <= params:
|
|
1126
1123
|
return self.pvsyst_temp
|
|
@@ -1131,11 +1128,15 @@ class ModelChain:
|
|
|
1131
1128
|
elif {'noct', 'module_efficiency'} <= params:
|
|
1132
1129
|
return self.noct_sam_temp
|
|
1133
1130
|
else:
|
|
1134
|
-
raise ValueError(
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1131
|
+
raise ValueError('Could not infer temperature model from '
|
|
1132
|
+
'ModelChain.system. '
|
|
1133
|
+
'If Arrays are used to construct the PVSystem, '
|
|
1134
|
+
'check that all Arrays in '
|
|
1135
|
+
'ModelChain.system.arrays '
|
|
1136
|
+
'have parameters for the same temperature model. '
|
|
1137
|
+
'If Arrays are not used, check that the PVSystem '
|
|
1138
|
+
'attributes `racking_model` and `module_type` '
|
|
1139
|
+
'are valid.')
|
|
1139
1140
|
|
|
1140
1141
|
def _set_celltemp(self, model):
|
|
1141
1142
|
"""Set self.results.cell_temperature using the given cell
|
pvlib/pvarray.py
CHANGED
|
@@ -223,3 +223,130 @@ def fit_pvefficiency_adr(effective_irradiance, temp_cell, eta,
|
|
|
223
223
|
return dict(zip(P_NAMES, popt))
|
|
224
224
|
else:
|
|
225
225
|
return popt
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _infer_k_huld(cell_type, pdc0):
|
|
229
|
+
# from PVGIS documentation, "PVGIS data sources & calculation methods",
|
|
230
|
+
# Section 5.2.3, accessed 12/22/2023
|
|
231
|
+
# The parameters in PVGIS' documentation are for a version of Huld's
|
|
232
|
+
# equation that has factored Pdc0 out of the polynomial:
|
|
233
|
+
# P = G/1000 * Pdc0 * (1 + k1 log(Geff) + ...) so these parameters are
|
|
234
|
+
# multiplied by pdc0
|
|
235
|
+
huld_params = {'csi': (-0.017237, -0.040465, -0.004702, 0.000149,
|
|
236
|
+
0.000170, 0.000005),
|
|
237
|
+
'cis': (-0.005554, -0.038724, -0.003723, -0.000905,
|
|
238
|
+
-0.001256, 0.000001),
|
|
239
|
+
'cdte': (-0.046689, -0.072844, -0.002262, 0.000276,
|
|
240
|
+
0.000159, -0.000006)}
|
|
241
|
+
k = tuple([x*pdc0 for x in huld_params[cell_type.lower()]])
|
|
242
|
+
return k
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def huld(effective_irradiance, temp_mod, pdc0, k=None, cell_type=None):
|
|
246
|
+
r"""
|
|
247
|
+
Power (DC) using the Huld model.
|
|
248
|
+
|
|
249
|
+
The Huld model [1]_ is used by PVGIS and is given by
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
.. math::
|
|
253
|
+
|
|
254
|
+
P_{dc} &= G' ( P_{dc0} + k_1 \log(G') + k_2 \log^2 (G') + k_3 T' +
|
|
255
|
+
k_4 T' \log(G') + k_5 T' \log^2 (G') + k_6 T'^2)
|
|
256
|
+
|
|
257
|
+
G' &= \frac{G_{poa eff}}{1000}
|
|
258
|
+
|
|
259
|
+
T' &= T_{mod} - 25^{\circ}C
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
Parameters
|
|
263
|
+
----------
|
|
264
|
+
effective_irradiance : numeric
|
|
265
|
+
The irradiance that is converted to photocurrent. [:math:`W/m^2`]
|
|
266
|
+
temp_mod: numeric
|
|
267
|
+
Module back-surface temperature. [C]
|
|
268
|
+
pdc0: numeric
|
|
269
|
+
Power of the modules at reference conditions 1000 :math:`W/m^2`
|
|
270
|
+
and :math:`25^{\circ}C`. [W]
|
|
271
|
+
k : tuple, optional
|
|
272
|
+
Empirical coefficients used in the power model. Length 6. If ``k`` is
|
|
273
|
+
not provided, ``cell_type`` must be specified.
|
|
274
|
+
cell_type : str, optional
|
|
275
|
+
If provided, must be one of ``'cSi'``, ``'CIS'``, or ``'CdTe'``.
|
|
276
|
+
Used to look up default values for ``k`` if ``k`` is not specified.
|
|
277
|
+
|
|
278
|
+
Returns
|
|
279
|
+
-------
|
|
280
|
+
pdc: numeric
|
|
281
|
+
DC power. [W]
|
|
282
|
+
|
|
283
|
+
Raises
|
|
284
|
+
------
|
|
285
|
+
ValueError
|
|
286
|
+
If neither ``k`` nor ``cell_type`` are specified.
|
|
287
|
+
|
|
288
|
+
Notes
|
|
289
|
+
-----
|
|
290
|
+
The equation for :math:`P_{dc}` is from [1]_. The expression used in PVGIS
|
|
291
|
+
documentation differs by factoring :math:`P_{dc0}` out of the
|
|
292
|
+
polynomial:
|
|
293
|
+
|
|
294
|
+
.. math::
|
|
295
|
+
|
|
296
|
+
P_{dc} = G' P_{dc0} (1 + k'_1 \log(G') + k'_2 \log^2 (G') + k'_3 T' +
|
|
297
|
+
k'_4 T' \log(G') + k'_5 T' \log^2 (G') + k'_6 T'^2)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
PVGIS documentation shows a table of default parameters :math:`k'` for
|
|
301
|
+
different cell types. The parameters :math:`k'` differ from the parameters
|
|
302
|
+
:math:`k` for :py:func:`huld` by the factor ``pdc0``, that is,
|
|
303
|
+
|
|
304
|
+
.. math::
|
|
305
|
+
|
|
306
|
+
k = P_{dc0} k'
|
|
307
|
+
|
|
308
|
+
With default values for :math:`k`, at very low irradiance, i.e.,
|
|
309
|
+
:math:`G' < 20 W/m^2`, :math:`P_{dc}` may be negative
|
|
310
|
+
due to the terms involving :math:`\log(G')`.
|
|
311
|
+
|
|
312
|
+
:py:func:`huld` is a component of the PV performance model implemented in
|
|
313
|
+
PVGIS. Among other components, the full PVGIS model includes:
|
|
314
|
+
|
|
315
|
+
- the Faiman model for module temperature
|
|
316
|
+
:py:func:`pvlib.temperature.faiman`
|
|
317
|
+
- the Martin and Ruiz model for the incidence angle modifier (IAM)
|
|
318
|
+
:py:func:`pvlib.iam.martin_ruiz`
|
|
319
|
+
- a custom model for a spectral adjustment factor
|
|
320
|
+
|
|
321
|
+
The PVGIS API (see :py:func:`pvlib.iotools.get_pvgis_hourly`) returns
|
|
322
|
+
broadband plane-of-array irradiance (``poa_global``) and DC power (``P``).
|
|
323
|
+
``poa_global`` is irradiance before applying the IAM and spectral
|
|
324
|
+
adjustments. In contrast the ``effective_irradiance`` for :py:func:`huld`
|
|
325
|
+
should have the IAM and spectral adjustments. Users comparing output of
|
|
326
|
+
:py:func:`huld` to PVGIS' ``P`` values should expect differences unless
|
|
327
|
+
``effective_irradiance`` is computed in the same way as done by PVGIS.
|
|
328
|
+
|
|
329
|
+
References
|
|
330
|
+
----------
|
|
331
|
+
.. [1] T. Huld, G. Friesen, A. Skoczek, R. Kenny, T. Sample, M. Field,
|
|
332
|
+
E. Dunlop. A power-rating model for crystalline silicon PV modules.
|
|
333
|
+
Solar Energy Materials and Solar Cells 95, (2011), pp. 3359-3369.
|
|
334
|
+
:doi:`10.1016/j.solmat.2011.07.026`.
|
|
335
|
+
"""
|
|
336
|
+
if k is None:
|
|
337
|
+
if cell_type is not None:
|
|
338
|
+
k = _infer_k_huld(cell_type, pdc0)
|
|
339
|
+
else:
|
|
340
|
+
raise ValueError('Either k or cell_type must be specified')
|
|
341
|
+
|
|
342
|
+
gprime = effective_irradiance / 1000
|
|
343
|
+
tprime = temp_mod - 25
|
|
344
|
+
# accomodate gprime<=0
|
|
345
|
+
with np.errstate(divide='ignore'):
|
|
346
|
+
logGprime = np.log(gprime, out=np.zeros_like(gprime),
|
|
347
|
+
where=np.array(gprime > 0))
|
|
348
|
+
# Eq. 1 in [1]
|
|
349
|
+
pdc = gprime * (pdc0 + k[0] * logGprime + k[1] * logGprime**2 +
|
|
350
|
+
k[2] * tprime + k[3] * tprime * logGprime +
|
|
351
|
+
k[4] * tprime * logGprime**2 + k[5] * tprime**2)
|
|
352
|
+
return pdc
|
pvlib/pvsystem.py
CHANGED
|
@@ -7,7 +7,7 @@ from collections import OrderedDict
|
|
|
7
7
|
import functools
|
|
8
8
|
import io
|
|
9
9
|
import itertools
|
|
10
|
-
import
|
|
10
|
+
from pathlib import Path
|
|
11
11
|
import inspect
|
|
12
12
|
from urllib.request import urlopen
|
|
13
13
|
import numpy as np
|
|
@@ -1487,8 +1487,10 @@ def calcparams_desoto(effective_irradiance, temp_cell,
|
|
|
1487
1487
|
'''
|
|
1488
1488
|
Calculates five parameter values for the single diode equation at
|
|
1489
1489
|
effective irradiance and cell temperature using the De Soto et al.
|
|
1490
|
-
model
|
|
1491
|
-
|
|
1490
|
+
model. The five values returned by ``calcparams_desoto`` can be used by
|
|
1491
|
+
singlediode to calculate an IV curve.
|
|
1492
|
+
|
|
1493
|
+
The model is described in [1]_.
|
|
1492
1494
|
|
|
1493
1495
|
Parameters
|
|
1494
1496
|
----------
|
|
@@ -1958,9 +1960,9 @@ def calcparams_pvsyst(effective_irradiance, temp_cell,
|
|
|
1958
1960
|
|
|
1959
1961
|
|
|
1960
1962
|
def retrieve_sam(name=None, path=None):
|
|
1961
|
-
|
|
1962
|
-
Retrieve latest module and inverter info from a
|
|
1963
|
-
SAM website.
|
|
1963
|
+
"""
|
|
1964
|
+
Retrieve latest module and inverter info from a file bundled with pvlib,
|
|
1965
|
+
a path or an URL (like SAM's website).
|
|
1964
1966
|
|
|
1965
1967
|
This function will retrieve either:
|
|
1966
1968
|
|
|
@@ -1971,10 +1973,14 @@ def retrieve_sam(name=None, path=None):
|
|
|
1971
1973
|
|
|
1972
1974
|
and return it as a pandas DataFrame.
|
|
1973
1975
|
|
|
1976
|
+
.. note::
|
|
1977
|
+
Only provide one of ``name`` or ``path``.
|
|
1978
|
+
|
|
1974
1979
|
Parameters
|
|
1975
1980
|
----------
|
|
1976
1981
|
name : string, optional
|
|
1977
|
-
|
|
1982
|
+
Use one of the following strings to retrieve a database bundled with
|
|
1983
|
+
pvlib:
|
|
1978
1984
|
|
|
1979
1985
|
* 'CECMod' - returns the CEC module database
|
|
1980
1986
|
* 'CECInverter' - returns the CEC Inverter database
|
|
@@ -1985,7 +1991,7 @@ def retrieve_sam(name=None, path=None):
|
|
|
1985
1991
|
* 'ADRInverter' - returns the ADR Inverter database
|
|
1986
1992
|
|
|
1987
1993
|
path : string, optional
|
|
1988
|
-
Path to
|
|
1994
|
+
Path to a CSV file or a URL.
|
|
1989
1995
|
|
|
1990
1996
|
Returns
|
|
1991
1997
|
-------
|
|
@@ -1997,7 +2003,11 @@ def retrieve_sam(name=None, path=None):
|
|
|
1997
2003
|
Raises
|
|
1998
2004
|
------
|
|
1999
2005
|
ValueError
|
|
2000
|
-
If no name or path is provided.
|
|
2006
|
+
If no ``name`` or ``path`` is provided.
|
|
2007
|
+
ValueError
|
|
2008
|
+
If both ``name`` and ``path`` are provided.
|
|
2009
|
+
KeyError
|
|
2010
|
+
If the provided ``name`` is not a valid database name.
|
|
2001
2011
|
|
|
2002
2012
|
Notes
|
|
2003
2013
|
-----
|
|
@@ -2030,38 +2040,38 @@ def retrieve_sam(name=None, path=None):
|
|
|
2030
2040
|
CEC_Date NaN
|
|
2031
2041
|
CEC_Type Utility Interactive
|
|
2032
2042
|
Name: AE_Solar_Energy__AE6_0__277V_, dtype: object
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
if name is not None:
|
|
2036
|
-
name
|
|
2037
|
-
data_path = os.path.join(
|
|
2038
|
-
os.path.dirname(os.path.abspath(__file__)), 'data')
|
|
2039
|
-
if name == 'cecmod':
|
|
2040
|
-
csvdata = os.path.join(
|
|
2041
|
-
data_path, 'sam-library-cec-modules-2019-03-05.csv')
|
|
2042
|
-
elif name == 'sandiamod':
|
|
2043
|
-
csvdata = os.path.join(
|
|
2044
|
-
data_path, 'sam-library-sandia-modules-2015-6-30.csv')
|
|
2045
|
-
elif name == 'adrinverter':
|
|
2046
|
-
csvdata = os.path.join(
|
|
2047
|
-
data_path, 'adr-library-cec-inverters-2019-03-05.csv')
|
|
2048
|
-
elif name in ['cecinverter', 'sandiainverter']:
|
|
2049
|
-
# Allowing either, to provide for old code,
|
|
2050
|
-
# while aligning with current expectations
|
|
2051
|
-
csvdata = os.path.join(
|
|
2052
|
-
data_path, 'sam-library-cec-inverters-2019-03-05.csv')
|
|
2053
|
-
else:
|
|
2054
|
-
raise ValueError(f'invalid name {name}')
|
|
2055
|
-
elif path is not None:
|
|
2056
|
-
if path.startswith('http'):
|
|
2057
|
-
response = urlopen(path)
|
|
2058
|
-
csvdata = io.StringIO(response.read().decode(errors='ignore'))
|
|
2059
|
-
else:
|
|
2060
|
-
csvdata = path
|
|
2043
|
+
"""
|
|
2044
|
+
# error: path was previously silently ignored if name was given GH#2018
|
|
2045
|
+
if name is not None and path is not None:
|
|
2046
|
+
raise ValueError("Please provide either 'name' or 'path', not both.")
|
|
2061
2047
|
elif name is None and path is None:
|
|
2062
|
-
raise ValueError("
|
|
2063
|
-
|
|
2064
|
-
|
|
2048
|
+
raise ValueError("Please provide either 'name' or 'path'.")
|
|
2049
|
+
elif name is not None:
|
|
2050
|
+
internal_dbs = {
|
|
2051
|
+
"cecmod": "sam-library-cec-modules-2019-03-05.csv",
|
|
2052
|
+
"sandiamod": "sam-library-sandia-modules-2015-6-30.csv",
|
|
2053
|
+
"adrinverter": "adr-library-cec-inverters-2019-03-05.csv",
|
|
2054
|
+
# Both 'cecinverter' and 'sandiainverter', point to same database
|
|
2055
|
+
# to provide for old code, while aligning with current expectations
|
|
2056
|
+
"cecinverter": "sam-library-cec-inverters-2019-03-05.csv",
|
|
2057
|
+
"sandiainverter": "sam-library-cec-inverters-2019-03-05.csv",
|
|
2058
|
+
}
|
|
2059
|
+
try:
|
|
2060
|
+
csvdata_path = Path(__file__).parent.joinpath(
|
|
2061
|
+
"data", internal_dbs[name.lower()]
|
|
2062
|
+
)
|
|
2063
|
+
except KeyError:
|
|
2064
|
+
raise KeyError(
|
|
2065
|
+
f"Invalid name {name}. "
|
|
2066
|
+
+ f"Provide one of {list(internal_dbs.keys())}."
|
|
2067
|
+
) from None
|
|
2068
|
+
else: # path is not None
|
|
2069
|
+
if path.lower().startswith("http"): # URL check is not case-sensitive
|
|
2070
|
+
response = urlopen(path) # URL is case-sensitive
|
|
2071
|
+
csvdata_path = io.StringIO(response.read().decode(errors="ignore"))
|
|
2072
|
+
else:
|
|
2073
|
+
csvdata_path = path
|
|
2074
|
+
return _parse_raw_sam_df(csvdata_path)
|
|
2065
2075
|
|
|
2066
2076
|
|
|
2067
2077
|
def _normalize_sam_product_names(names):
|
|
@@ -2254,10 +2264,9 @@ def sapm(effective_irradiance, temp_cell, module):
|
|
|
2254
2264
|
module['IXO'] * (module['C4']*Ee + module['C5']*(Ee**2)) *
|
|
2255
2265
|
(1 + module['Aisc']*(temp_cell - temp_ref)))
|
|
2256
2266
|
|
|
2257
|
-
# the Ixx calculation in King 2004 has a typo (mixes up Aisc and Aimp)
|
|
2258
2267
|
out['i_xx'] = (
|
|
2259
2268
|
module['IXXO'] * (module['C6']*Ee + module['C7']*(Ee**2)) *
|
|
2260
|
-
(1 + module['
|
|
2269
|
+
(1 + module['Aimp']*(temp_cell - temp_ref)))
|
|
2261
2270
|
|
|
2262
2271
|
if isinstance(out['i_sc'], pd.Series):
|
|
2263
2272
|
out = pd.DataFrame(out)
|
|
@@ -2536,7 +2545,7 @@ def singlediode(photocurrent, saturation_current, resistance_series,
|
|
|
2536
2545
|
|
|
2537
2546
|
|
|
2538
2547
|
def max_power_point(photocurrent, saturation_current, resistance_series,
|
|
2539
|
-
resistance_shunt, nNsVth, d2mutau=0, NsVbi=np.
|
|
2548
|
+
resistance_shunt, nNsVth, d2mutau=0, NsVbi=np.inf,
|
|
2540
2549
|
method='brentq'):
|
|
2541
2550
|
"""
|
|
2542
2551
|
Given the single diode equation coefficients, calculates the maximum power
|
pvlib/scaling.py
CHANGED
|
@@ -13,8 +13,10 @@ from scipy.spatial.distance import pdist
|
|
|
13
13
|
def wvm(clearsky_index, positions, cloud_speed, dt=None):
|
|
14
14
|
"""
|
|
15
15
|
Compute spatial aggregation time series smoothing on clear sky index based
|
|
16
|
-
on the Wavelet Variability model
|
|
17
|
-
|
|
16
|
+
on the Wavelet Variability model.
|
|
17
|
+
|
|
18
|
+
This model is described in Lave et al. [1]_, [2]_.
|
|
19
|
+
Implementation is basically a port of the Matlab version of the code [3]_.
|
|
18
20
|
|
|
19
21
|
Parameters
|
|
20
22
|
----------
|
pvlib/shading.py
CHANGED
|
@@ -232,3 +232,113 @@ def sky_diffuse_passias(masking_angle):
|
|
|
232
232
|
Available at https://www.nrel.gov/docs/fy18osti/67399.pdf
|
|
233
233
|
"""
|
|
234
234
|
return 1 - cosd(masking_angle/2)**2
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def projected_solar_zenith_angle(solar_zenith, solar_azimuth,
|
|
238
|
+
axis_tilt, axis_azimuth):
|
|
239
|
+
r"""
|
|
240
|
+
Calculate projected solar zenith angle in degrees.
|
|
241
|
+
|
|
242
|
+
This solar zenith angle is projected onto the plane whose normal vector is
|
|
243
|
+
defined by ``axis_tilt`` and ``axis_azimuth``. The normal vector is in the
|
|
244
|
+
direction of ``axis_azimuth`` (clockwise from north) and tilted from
|
|
245
|
+
horizontal by ``axis_tilt``. See Figure 5 in [1]_:
|
|
246
|
+
|
|
247
|
+
.. figure:: ../../_images/Anderson_Mikofski_2020_Fig5.jpg
|
|
248
|
+
:alt: Wire diagram of coordinates systems to obtain the projected angle.
|
|
249
|
+
:align: center
|
|
250
|
+
:scale: 50 %
|
|
251
|
+
|
|
252
|
+
Fig. 5, [1]_: Solar coordinates projection onto tracker rotation plane.
|
|
253
|
+
|
|
254
|
+
Parameters
|
|
255
|
+
----------
|
|
256
|
+
solar_zenith : numeric
|
|
257
|
+
Sun's apparent zenith in degrees.
|
|
258
|
+
solar_azimuth : numeric
|
|
259
|
+
Sun's azimuth in degrees.
|
|
260
|
+
axis_tilt : numeric
|
|
261
|
+
Axis tilt angle in degrees. From horizontal plane to array plane.
|
|
262
|
+
axis_azimuth : numeric
|
|
263
|
+
Axis azimuth angle in degrees.
|
|
264
|
+
North = 0°; East = 90°; South = 180°; West = 270°
|
|
265
|
+
|
|
266
|
+
Returns
|
|
267
|
+
-------
|
|
268
|
+
Projected_solar_zenith : numeric
|
|
269
|
+
In degrees.
|
|
270
|
+
|
|
271
|
+
Notes
|
|
272
|
+
-----
|
|
273
|
+
This projection has a variety of applications in PV. For example:
|
|
274
|
+
|
|
275
|
+
- Projecting the sun's position onto the plane perpendicular to
|
|
276
|
+
the axis of a single-axis tracker (i.e. the plane
|
|
277
|
+
whose normal vector coincides with the tracker torque tube)
|
|
278
|
+
yields the tracker rotation angle that maximizes direct irradiance
|
|
279
|
+
capture. This tracking strategy is called *true-tracking*. Learn more
|
|
280
|
+
about tracking in
|
|
281
|
+
:ref:`sphx_glr_gallery_solar-tracking_plot_single_axis_tracking.py`.
|
|
282
|
+
|
|
283
|
+
- Self-shading in large PV arrays is often modeled by assuming
|
|
284
|
+
a simplified 2-D array geometry where the sun's position is
|
|
285
|
+
projected onto the plane perpendicular to the PV rows.
|
|
286
|
+
The projected zenith angle is then used for calculations
|
|
287
|
+
regarding row-to-row shading.
|
|
288
|
+
|
|
289
|
+
Examples
|
|
290
|
+
--------
|
|
291
|
+
Calculate the ideal true-tracking angle for a horizontal north-south
|
|
292
|
+
single-axis tracker:
|
|
293
|
+
|
|
294
|
+
>>> rotation = projected_solar_zenith_angle(solar_zenith, solar_azimuth,
|
|
295
|
+
>>> axis_tilt=0, axis_azimuth=180)
|
|
296
|
+
|
|
297
|
+
Calculate the projected zenith angle in a south-facing fixed tilt array
|
|
298
|
+
(note: the ``axis_azimuth`` of a fixed-tilt row points along the length
|
|
299
|
+
of the row):
|
|
300
|
+
|
|
301
|
+
>>> psza = projected_solar_zenith_angle(solar_zenith, solar_azimuth,
|
|
302
|
+
>>> axis_tilt=0, axis_azimuth=90)
|
|
303
|
+
|
|
304
|
+
References
|
|
305
|
+
----------
|
|
306
|
+
.. [1] K. Anderson and M. Mikofski, 'Slope-Aware Backtracking for
|
|
307
|
+
Single-Axis Trackers', National Renewable Energy Lab. (NREL), Golden,
|
|
308
|
+
CO (United States);
|
|
309
|
+
NREL/TP-5K00-76626, Jul. 2020. :doi:`10.2172/1660126`.
|
|
310
|
+
|
|
311
|
+
See Also
|
|
312
|
+
--------
|
|
313
|
+
pvlib.solarposition.get_solarposition
|
|
314
|
+
"""
|
|
315
|
+
# Assume the tracker reference frame is right-handed. Positive y-axis is
|
|
316
|
+
# oriented along tracking axis; from north, the y-axis is rotated clockwise
|
|
317
|
+
# by the axis azimuth and tilted from horizontal by the axis tilt. The
|
|
318
|
+
# positive x-axis is 90 deg clockwise from the y-axis and parallel to
|
|
319
|
+
# horizontal (e.g., if the y-axis is south, the x-axis is west); the
|
|
320
|
+
# positive z-axis is normal to the x and y axes, pointed upward.
|
|
321
|
+
|
|
322
|
+
# Since elevation = 90 - zenith, sin(90-x) = cos(x) & cos(90-x) = sin(x):
|
|
323
|
+
# Notation from [1], modified to use zenith instead of elevation
|
|
324
|
+
# cos(elevation) = sin(zenith) and sin(elevation) = cos(zenith)
|
|
325
|
+
# Avoid recalculating these values
|
|
326
|
+
sind_solar_zenith = sind(solar_zenith)
|
|
327
|
+
cosd_axis_azimuth = cosd(axis_azimuth)
|
|
328
|
+
sind_axis_azimuth = sind(axis_azimuth)
|
|
329
|
+
sind_axis_tilt = sind(axis_tilt)
|
|
330
|
+
|
|
331
|
+
# Sun's x, y, z coords
|
|
332
|
+
sx = sind_solar_zenith * sind(solar_azimuth)
|
|
333
|
+
sy = sind_solar_zenith * cosd(solar_azimuth)
|
|
334
|
+
sz = cosd(solar_zenith)
|
|
335
|
+
# Eq. (4); sx', sz' values from sun coordinates projected onto surface
|
|
336
|
+
sx_prime = sx * cosd_axis_azimuth - sy * sind_axis_azimuth
|
|
337
|
+
sz_prime = (
|
|
338
|
+
sx * sind_axis_azimuth * sind_axis_tilt
|
|
339
|
+
+ sy * sind_axis_tilt * cosd_axis_azimuth
|
|
340
|
+
+ sz * cosd(axis_tilt)
|
|
341
|
+
)
|
|
342
|
+
# Eq. (5); angle between sun's beam and surface
|
|
343
|
+
theta_T = np.degrees(np.arctan2(sx_prime, sz_prime))
|
|
344
|
+
return theta_T
|