pvlib 0.10.5__py3-none-any.whl → 0.11.0a1__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/albedo.py +168 -0
- pvlib/data/ASTMG173.csv +2004 -0
- pvlib/iam.py +28 -28
- pvlib/iotools/__init__.py +0 -1
- pvlib/iotools/midc.py +15 -10
- pvlib/iotools/psm3.py +10 -25
- pvlib/iotools/srml.py +0 -61
- pvlib/irradiance.py +133 -95
- pvlib/location.py +13 -5
- pvlib/modelchain.py +2 -165
- pvlib/pvsystem.py +23 -63
- pvlib/shading.py +350 -0
- pvlib/spectrum/__init__.py +5 -0
- pvlib/spectrum/mismatch.py +572 -43
- pvlib/spectrum/spectrl2.py +8 -8
- pvlib/tests/iotools/test_psm3.py +0 -18
- pvlib/tests/iotools/test_srml.py +1 -43
- pvlib/tests/test_albedo.py +84 -0
- pvlib/tests/test_inverter.py +2 -2
- pvlib/tests/test_irradiance.py +35 -2
- pvlib/tests/test_location.py +26 -18
- pvlib/tests/test_modelchain.py +0 -57
- pvlib/tests/test_pvsystem.py +11 -39
- pvlib/tests/test_shading.py +167 -1
- pvlib/tests/test_singlediode.py +0 -19
- pvlib/tests/test_spectrum.py +283 -22
- pvlib/tests/test_temperature.py +7 -7
- pvlib/tests/test_tools.py +24 -0
- pvlib/tests/test_transformer.py +60 -0
- pvlib/tools.py +27 -0
- pvlib/transformer.py +117 -0
- {pvlib-0.10.5.dist-info → pvlib-0.11.0a1.dist-info}/METADATA +1 -1
- {pvlib-0.10.5.dist-info → pvlib-0.11.0a1.dist-info}/RECORD +38 -34
- {pvlib-0.10.5.dist-info → pvlib-0.11.0a1.dist-info}/WHEEL +1 -1
- pvlib/data/astm_g173_am15g.csv +0 -2003
- {pvlib-0.10.5.dist-info → pvlib-0.11.0a1.dist-info}/AUTHORS.md +0 -0
- {pvlib-0.10.5.dist-info → pvlib-0.11.0a1.dist-info}/LICENSE +0 -0
- {pvlib-0.10.5.dist-info → pvlib-0.11.0a1.dist-info}/top_level.txt +0 -0
pvlib/spectrum/mismatch.py
CHANGED
|
@@ -3,13 +3,25 @@ The ``mismatch`` module provides functions for spectral mismatch calculations.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import pvlib
|
|
6
|
+
from pvlib._deprecation import deprecated
|
|
7
|
+
from pvlib.tools import normalize_max2one
|
|
6
8
|
import numpy as np
|
|
7
9
|
import pandas as pd
|
|
8
|
-
|
|
10
|
+
import scipy.constants
|
|
9
11
|
from scipy.integrate import trapezoid
|
|
10
|
-
import
|
|
12
|
+
from scipy.interpolate import interp1d
|
|
11
13
|
|
|
14
|
+
from pathlib import Path
|
|
12
15
|
from warnings import warn
|
|
16
|
+
from functools import partial
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_PLANCK_BY_LIGHT_SPEED_OVER_ELEMENTAL_CHARGE_BY_BILLION = (
|
|
20
|
+
scipy.constants.speed_of_light
|
|
21
|
+
* scipy.constants.Planck
|
|
22
|
+
/ scipy.constants.elementary_charge
|
|
23
|
+
* 1e9
|
|
24
|
+
)
|
|
13
25
|
|
|
14
26
|
|
|
15
27
|
def get_example_spectral_response(wavelength=None):
|
|
@@ -44,14 +56,14 @@ def get_example_spectral_response(wavelength=None):
|
|
|
44
56
|
'''
|
|
45
57
|
# Contributed by Anton Driesse (@adriesse), PV Performance Labs. Aug. 2022
|
|
46
58
|
|
|
47
|
-
SR_DATA = np.array([[
|
|
48
|
-
[
|
|
49
|
-
[
|
|
50
|
-
[
|
|
51
|
-
[
|
|
52
|
-
[
|
|
53
|
-
[
|
|
54
|
-
[
|
|
59
|
+
SR_DATA = np.array([[290, 0.00],
|
|
60
|
+
[350, 0.27],
|
|
61
|
+
[400, 0.37],
|
|
62
|
+
[500, 0.52],
|
|
63
|
+
[650, 0.71],
|
|
64
|
+
[800, 0.88],
|
|
65
|
+
[900, 0.97],
|
|
66
|
+
[950, 1.00],
|
|
55
67
|
[1000, 0.93],
|
|
56
68
|
[1050, 0.58],
|
|
57
69
|
[1100, 0.21],
|
|
@@ -77,8 +89,18 @@ def get_example_spectral_response(wavelength=None):
|
|
|
77
89
|
return sr
|
|
78
90
|
|
|
79
91
|
|
|
92
|
+
@deprecated(
|
|
93
|
+
since="0.11",
|
|
94
|
+
removal="0.12",
|
|
95
|
+
name="pvlib.spectrum.get_am15g",
|
|
96
|
+
alternative="pvlib.spectrum.get_reference_spectra",
|
|
97
|
+
addendum=(
|
|
98
|
+
"The new function reads more data. Use it with "
|
|
99
|
+
+ "standard='ASTM G173-03' and extract the 'global' column."
|
|
100
|
+
),
|
|
101
|
+
)
|
|
80
102
|
def get_am15g(wavelength=None):
|
|
81
|
-
|
|
103
|
+
r"""
|
|
82
104
|
Read the ASTM G173-03 AM1.5 global spectrum on a 37-degree tilted surface,
|
|
83
105
|
optionally interpolated to the specified wavelength(s).
|
|
84
106
|
|
|
@@ -92,19 +114,19 @@ def get_am15g(wavelength=None):
|
|
|
92
114
|
----------
|
|
93
115
|
wavelength: 1-D sequence of numeric, optional
|
|
94
116
|
Wavelengths at which the spectrum is interpolated.
|
|
95
|
-
By default the 2002 wavelengths of the standard are returned. [nm]
|
|
117
|
+
By default the 2002 wavelengths of the standard are returned. [nm].
|
|
96
118
|
|
|
97
119
|
Returns
|
|
98
120
|
-------
|
|
99
121
|
am15g: pandas.Series
|
|
100
|
-
The AM1.5g standard spectrum indexed by ``wavelength``. [
|
|
122
|
+
The AM1.5g standard spectrum indexed by ``wavelength``. [W/(m²nm)].
|
|
101
123
|
|
|
102
124
|
Notes
|
|
103
125
|
-----
|
|
104
126
|
If ``wavelength`` is specified this function uses linear interpolation.
|
|
105
127
|
|
|
106
128
|
If the values in ``wavelength`` are too widely spaced, the integral of the
|
|
107
|
-
spectrum may deviate from the standard value of 1000.37 W/m
|
|
129
|
+
spectrum may deviate from the standard value of 1000.37 W/m².
|
|
108
130
|
|
|
109
131
|
The values in the data file provided with pvlib-python are copied from an
|
|
110
132
|
Excel file distributed by NREL, which is found here:
|
|
@@ -113,32 +135,125 @@ def get_am15g(wavelength=None):
|
|
|
113
135
|
More information about reference spectra is found here:
|
|
114
136
|
https://www.nrel.gov/grid/solar-resource/spectra-am1.5.html
|
|
115
137
|
|
|
138
|
+
See Also
|
|
139
|
+
--------
|
|
140
|
+
pvlib.spectrum.get_reference_spectra : reads also the direct and
|
|
141
|
+
extraterrestrial components of the spectrum.
|
|
142
|
+
|
|
116
143
|
References
|
|
117
144
|
----------
|
|
118
145
|
.. [1] ASTM "G173-03 Standard Tables for Reference Solar Spectral
|
|
119
146
|
Irradiances: Direct Normal and Hemispherical on 37° Tilted Surface."
|
|
120
|
-
|
|
147
|
+
""" # noqa: E501
|
|
121
148
|
# Contributed by Anton Driesse (@adriesse), PV Performance Labs. Aug. 2022
|
|
149
|
+
# modified by @echedey-ls, as a wrapper of spectrum.get_reference_spectra
|
|
150
|
+
standard = get_reference_spectra(wavelength, standard="ASTM G173-03")
|
|
151
|
+
return standard["global"]
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def get_reference_spectra(wavelengths=None, standard="ASTM G173-03"):
|
|
155
|
+
r"""
|
|
156
|
+
Read a standard spectrum specified by ``standard``, optionally
|
|
157
|
+
interpolated to the specified wavelength(s).
|
|
158
|
+
|
|
159
|
+
Defaults to ``ASTM G173-03`` AM1.5 standard [1]_, which returns
|
|
160
|
+
``extraterrestrial``, ``global`` and ``direct`` spectrum on a 37-degree
|
|
161
|
+
tilted surface, optionally interpolated to the specified wavelength(s).
|
|
162
|
+
|
|
163
|
+
Parameters
|
|
164
|
+
----------
|
|
165
|
+
wavelengths : numeric, optional
|
|
166
|
+
Wavelengths at which the spectrum is interpolated. [nm].
|
|
167
|
+
If not provided, the original wavelengths from the specified standard
|
|
168
|
+
are used. Values outside that range are filled with zeros.
|
|
169
|
+
|
|
170
|
+
standard : str, default "ASTM G173-03"
|
|
171
|
+
The reference standard to be read. Only the reference
|
|
172
|
+
``"ASTM G173-03"`` is available at the moment.
|
|
173
|
+
|
|
174
|
+
Returns
|
|
175
|
+
-------
|
|
176
|
+
standard_spectra : pandas.DataFrame
|
|
177
|
+
The standard spectrum by ``wavelength [nm]``. [W/(m²nm)].
|
|
178
|
+
Column names are ``extraterrestrial``, ``direct`` and ``global``.
|
|
179
|
+
|
|
180
|
+
Notes
|
|
181
|
+
-----
|
|
182
|
+
If ``wavelength`` is specified, linear interpolation is used.
|
|
122
183
|
|
|
123
|
-
|
|
124
|
-
|
|
184
|
+
If the values in ``wavelength`` are too widely spaced, the integral of each
|
|
185
|
+
spectrum may deviate from its standard value.
|
|
186
|
+
For global spectra, it is about 1000.37 W/m².
|
|
125
187
|
|
|
126
|
-
|
|
188
|
+
The values of the ASTM G173-03 provided with pvlib-python are copied from
|
|
189
|
+
an Excel file distributed by NREL, which is found here [2]_:
|
|
190
|
+
https://www.nrel.gov/grid/solar-resource/assets/data/astmg173.xls
|
|
127
191
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
192
|
+
Examples
|
|
193
|
+
--------
|
|
194
|
+
>>> from pvlib import spectrum
|
|
195
|
+
>>> am15 = spectrum.get_reference_spectra()
|
|
196
|
+
>>> am15_extraterrestrial, am15_global, am15_direct = \
|
|
197
|
+
>>> am15['extraterrestrial'], am15['global'], am15['direct']
|
|
198
|
+
>>> print(am15.head())
|
|
199
|
+
extraterrestrial global direct
|
|
200
|
+
wavelength
|
|
201
|
+
280.0 0.082 4.730900e-23 2.536100e-26
|
|
202
|
+
280.5 0.099 1.230700e-21 1.091700e-24
|
|
203
|
+
281.0 0.150 5.689500e-21 6.125300e-24
|
|
204
|
+
281.5 0.212 1.566200e-19 2.747900e-22
|
|
205
|
+
282.0 0.267 1.194600e-18 2.834600e-21
|
|
206
|
+
|
|
207
|
+
>>> am15 = spectrum.get_reference_spectra([300, 500, 800, 1100])
|
|
208
|
+
>>> print(am15)
|
|
209
|
+
extraterrestrial global direct
|
|
210
|
+
wavelength
|
|
211
|
+
300 0.45794 0.00102 0.000456
|
|
212
|
+
500 1.91600 1.54510 1.339100
|
|
213
|
+
800 1.12480 1.07250 0.988590
|
|
214
|
+
1100 0.60000 0.48577 0.461130
|
|
135
215
|
|
|
136
|
-
|
|
216
|
+
References
|
|
217
|
+
----------
|
|
218
|
+
.. [1] ASTM "G173-03 Standard Tables for Reference Solar Spectral
|
|
219
|
+
Irradiances: Direct Normal and Hemispherical on 37° Tilted Surface."
|
|
220
|
+
.. [2] “Reference Air Mass 1.5 Spectra,” www.nrel.gov.
|
|
221
|
+
https://www.nrel.gov/grid/solar-resource/spectra-am1.5.html
|
|
222
|
+
""" # Contributed by Echedey Luis, inspired by Anton Driesse (get_am15g)
|
|
223
|
+
SPECTRA_FILES = {
|
|
224
|
+
"ASTM G173-03": "ASTMG173.csv",
|
|
225
|
+
}
|
|
226
|
+
pvlib_datapath = Path(pvlib.__path__[0]) / "data"
|
|
227
|
+
|
|
228
|
+
try:
|
|
229
|
+
filepath = pvlib_datapath / SPECTRA_FILES[standard]
|
|
230
|
+
except KeyError:
|
|
231
|
+
raise ValueError(
|
|
232
|
+
f"Invalid standard identifier '{standard}'. Available "
|
|
233
|
+
+ "identifiers are: "
|
|
234
|
+
+ ", ".join(SPECTRA_FILES.keys())
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
standard = pd.read_csv(
|
|
238
|
+
filepath,
|
|
239
|
+
header=1, # expect first line of description, then column names
|
|
240
|
+
index_col=0, # first column is "wavelength"
|
|
241
|
+
dtype=float,
|
|
242
|
+
)
|
|
137
243
|
|
|
138
|
-
|
|
139
|
-
|
|
244
|
+
if wavelengths is not None:
|
|
245
|
+
interpolator = partial(
|
|
246
|
+
np.interp, xp=standard.index, left=0.0, right=0.0
|
|
247
|
+
)
|
|
248
|
+
standard = pd.DataFrame(
|
|
249
|
+
index=wavelengths,
|
|
250
|
+
data={
|
|
251
|
+
col: interpolator(x=wavelengths, fp=standard[col])
|
|
252
|
+
for col in standard.columns
|
|
253
|
+
},
|
|
254
|
+
)
|
|
140
255
|
|
|
141
|
-
return
|
|
256
|
+
return standard
|
|
142
257
|
|
|
143
258
|
|
|
144
259
|
def calc_spectral_mismatch_field(sr, e_sun, e_ref=None):
|
|
@@ -154,7 +269,7 @@ def calc_spectral_mismatch_field(sr, e_sun, e_ref=None):
|
|
|
154
269
|
|
|
155
270
|
e_sun: pandas.DataFrame or pandas.Series
|
|
156
271
|
One or more measured solar irradiance spectra in a pandas.DataFrame
|
|
157
|
-
having wavelength in nm as column index.
|
|
272
|
+
having wavelength in nm as column index. A single spectrum may be
|
|
158
273
|
be given as a pandas.Series having wavelength in nm as index.
|
|
159
274
|
[(W/m^2)/nm]
|
|
160
275
|
|
|
@@ -216,7 +331,7 @@ def calc_spectral_mismatch_field(sr, e_sun, e_ref=None):
|
|
|
216
331
|
|
|
217
332
|
# get the reference spectrum at wavelengths matching the measured spectra
|
|
218
333
|
if e_ref is None:
|
|
219
|
-
e_ref =
|
|
334
|
+
e_ref = get_reference_spectra(wavelengths=e_sun.T.index)["global"]
|
|
220
335
|
|
|
221
336
|
# interpolate the sr at the wavelengths of the spectra
|
|
222
337
|
# reference spectrum wavelengths may differ if e_ref is from caller
|
|
@@ -246,7 +361,7 @@ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
|
|
|
246
361
|
max_precipitable_water=8):
|
|
247
362
|
r"""
|
|
248
363
|
Spectral mismatch modifier based on precipitable water and absolute
|
|
249
|
-
(pressure-adjusted)
|
|
364
|
+
(pressure-adjusted) air mass.
|
|
250
365
|
|
|
251
366
|
Estimates a spectral mismatch modifier :math:`M` representing the effect on
|
|
252
367
|
module short circuit current of variation in the spectral
|
|
@@ -265,11 +380,11 @@ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
|
|
|
265
380
|
SMARTS, spectrums are simulated with all combinations of AMa and
|
|
266
381
|
Pw where:
|
|
267
382
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
383
|
+
* :math:`0.5 \textrm{cm} <= Pw <= 5 \textrm{cm}`
|
|
384
|
+
* :math:`1.0 <= AM_a <= 5.0`
|
|
385
|
+
* Spectral range is limited to that of CMP11 (280 nm to 2800 nm)
|
|
386
|
+
* spectrum simulated on a plane normal to the sun
|
|
387
|
+
* All other parameters fixed at G173 standard
|
|
273
388
|
|
|
274
389
|
From these simulated spectra, M is calculated using the known
|
|
275
390
|
quantum efficiency curves. Multiple linear regression is then
|
|
@@ -284,18 +399,18 @@ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
|
|
|
284
399
|
atmospheric precipitable water. [cm]
|
|
285
400
|
|
|
286
401
|
airmass_absolute : numeric
|
|
287
|
-
absolute (pressure-adjusted)
|
|
402
|
+
absolute (pressure-adjusted) air mass. [unitless]
|
|
288
403
|
|
|
289
404
|
module_type : str, optional
|
|
290
405
|
a string specifying a cell type. Values of 'cdte', 'monosi', 'xsi',
|
|
291
406
|
'multisi', and 'polysi' (can be lower or upper case). If provided,
|
|
292
407
|
module_type selects default coefficients for the following modules:
|
|
293
408
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
409
|
+
* 'cdte' - First Solar Series 4-2 CdTe module.
|
|
410
|
+
* 'monosi', 'xsi' - First Solar TetraSun module.
|
|
411
|
+
* 'multisi', 'polysi' - anonymous multi-crystalline silicon module.
|
|
412
|
+
* 'cigs' - anonymous copper indium gallium selenide module.
|
|
413
|
+
* 'asi' - anonymous amorphous silicon module.
|
|
299
414
|
|
|
300
415
|
The module used to calculate the spectral correction
|
|
301
416
|
coefficients corresponds to the Multi-crystalline silicon
|
|
@@ -571,3 +686,417 @@ def spectral_factor_caballero(precipitable_water, airmass_absolute, aod500,
|
|
|
571
686
|
)
|
|
572
687
|
modifier = f_AM + f_AOD + f_PW # Eq 5
|
|
573
688
|
return modifier
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
def spectral_factor_pvspec(airmass_absolute, clearsky_index,
|
|
692
|
+
module_type=None, coefficients=None):
|
|
693
|
+
r"""
|
|
694
|
+
Estimate a technology-specific spectral mismatch modifier from absolute
|
|
695
|
+
airmass and clear sky index using the PVSPEC model.
|
|
696
|
+
|
|
697
|
+
The PVSPEC spectral mismatch model includes the effects of cloud cover on
|
|
698
|
+
the irradiance spectrum. Model coefficients are derived using spectral
|
|
699
|
+
irradiance and other meteorological data from eight locations. Coefficients
|
|
700
|
+
for six module types are available via the ``module_type`` parameter.
|
|
701
|
+
More details on the model can be found in [1]_.
|
|
702
|
+
|
|
703
|
+
Parameters
|
|
704
|
+
----------
|
|
705
|
+
airmass_absolute : numeric
|
|
706
|
+
absolute (pressure-adjusted) airmass. [unitless]
|
|
707
|
+
|
|
708
|
+
clearsky_index: numeric
|
|
709
|
+
clear sky index. [unitless]
|
|
710
|
+
|
|
711
|
+
module_type : str, optional
|
|
712
|
+
One of the following PV technology strings from [1]_:
|
|
713
|
+
|
|
714
|
+
* ``'fs4-1'`` - First Solar series 4-1 and earlier CdTe module.
|
|
715
|
+
* ``'fs4-2'`` - First Solar 4-2 and later CdTe module.
|
|
716
|
+
* ``'monosi'``, - anonymous monocrystalline Si module.
|
|
717
|
+
* ``'multisi'``, - anonymous multicrystalline Si module.
|
|
718
|
+
* ``'cigs'`` - anonymous copper indium gallium selenide module.
|
|
719
|
+
* ``'asi'`` - anonymous amorphous silicon module.
|
|
720
|
+
|
|
721
|
+
coefficients : array-like, optional
|
|
722
|
+
user-defined coefficients, if not using one of the default coefficient
|
|
723
|
+
sets via the ``module_type`` parameter.
|
|
724
|
+
|
|
725
|
+
Returns
|
|
726
|
+
-------
|
|
727
|
+
mismatch: numeric
|
|
728
|
+
spectral mismatch factor (unitless) which is multiplied
|
|
729
|
+
with broadband irradiance reaching a module's cells to estimate
|
|
730
|
+
effective irradiance, i.e., the irradiance that is converted to
|
|
731
|
+
electrical current.
|
|
732
|
+
|
|
733
|
+
Notes
|
|
734
|
+
-----
|
|
735
|
+
The PVSPEC model parameterises the spectral mismatch factor as a function
|
|
736
|
+
of absolute air mass and the clear sky index as follows:
|
|
737
|
+
|
|
738
|
+
.. math::
|
|
739
|
+
|
|
740
|
+
M = a_1 k_c^{a_2} AM_a^{a_3},
|
|
741
|
+
|
|
742
|
+
where :math:`M` is the spectral mismatch factor, :math:`k_c` is the clear
|
|
743
|
+
sky index, :math:`AM_a` is the absolute air mass, and :math:`a_1, a_2, a_3`
|
|
744
|
+
are module-specific coefficients. In the PVSPEC model publication, absolute
|
|
745
|
+
air mass (denoted as :math:`AM`) is estimated starting from the Kasten and
|
|
746
|
+
Young relative air mass [2]_. The clear sky index, which is the ratio of
|
|
747
|
+
GHI to clear sky GHI, uses the ESRA model [3]_ to estimate the clear sky
|
|
748
|
+
GHI with monthly Linke turbidity values from [4]_ as inputs.
|
|
749
|
+
|
|
750
|
+
References
|
|
751
|
+
----------
|
|
752
|
+
.. [1] Pelland, S., Beswick, C., Thevenard, D., Côté, A., Pai, A. and
|
|
753
|
+
Poissant, Y., 2020. Development and testing of the PVSPEC model of
|
|
754
|
+
photovoltaic spectral mismatch factor. In 2020 47th IEEE Photovoltaic
|
|
755
|
+
Specialists Conference (PVSC) (pp. 1258-1264). IEEE.
|
|
756
|
+
:doi:`10.1109/PVSC45281.2020.9300932`
|
|
757
|
+
.. [2] Kasten, F. and Young, A.T., 1989. Revised optical air mass tables
|
|
758
|
+
and approximation formula. Applied Optics, 28(22), pp.4735-4738.
|
|
759
|
+
:doi:`10.1364/AO.28.004735`
|
|
760
|
+
.. [3] Rigollier, C., Bauer, O. and Wald, L., 2000. On the clear sky model
|
|
761
|
+
of the ESRA—European Solar Radiation Atlas—with respect to the Heliosat
|
|
762
|
+
method. Solar energy, 68(1), pp.33-48.
|
|
763
|
+
:doi:`10.1016/S0038-092X(99)00055-9`
|
|
764
|
+
.. [4] SoDa website monthly Linke turbidity values:
|
|
765
|
+
http://www.soda-pro.com/
|
|
766
|
+
"""
|
|
767
|
+
|
|
768
|
+
_coefficients = {}
|
|
769
|
+
_coefficients['multisi'] = (0.9847, -0.05237, 0.03034)
|
|
770
|
+
_coefficients['monosi'] = (0.9845, -0.05169, 0.03034)
|
|
771
|
+
_coefficients['fs-2'] = (1.002, -0.07108, 0.02465)
|
|
772
|
+
_coefficients['fs-4'] = (0.9981, -0.05776, 0.02336)
|
|
773
|
+
_coefficients['cigs'] = (0.9791, -0.03904, 0.03096)
|
|
774
|
+
_coefficients['asi'] = (1.051, -0.1033, 0.009838)
|
|
775
|
+
|
|
776
|
+
if module_type is not None and coefficients is None:
|
|
777
|
+
coefficients = _coefficients[module_type.lower()]
|
|
778
|
+
elif module_type is None and coefficients is not None:
|
|
779
|
+
pass
|
|
780
|
+
elif module_type is None and coefficients is None:
|
|
781
|
+
raise ValueError('No valid input provided, both module_type and ' +
|
|
782
|
+
'coefficients are None. module_type can be one of ' +
|
|
783
|
+
", ".join(_coefficients.keys()))
|
|
784
|
+
else:
|
|
785
|
+
raise ValueError('Cannot resolve input, must supply only one of ' +
|
|
786
|
+
'module_type and coefficients. module_type can be ' +
|
|
787
|
+
'one of' ", ".join(_coefficients.keys()))
|
|
788
|
+
|
|
789
|
+
coeff = coefficients
|
|
790
|
+
ama = airmass_absolute
|
|
791
|
+
kc = clearsky_index
|
|
792
|
+
mismatch = coeff[0]*np.power(kc, coeff[1])*np.power(ama, coeff[2])
|
|
793
|
+
|
|
794
|
+
return mismatch
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
def spectral_factor_jrc(airmass, clearsky_index, module_type=None,
|
|
798
|
+
coefficients=None):
|
|
799
|
+
r"""
|
|
800
|
+
Estimate a technology-specific spectral mismatch modifier from
|
|
801
|
+
airmass and clear sky index using the JRC model.
|
|
802
|
+
|
|
803
|
+
The JRC spectral mismatch model includes the effects of cloud cover on
|
|
804
|
+
the irradiance spectrum. Model coefficients are derived using measurements
|
|
805
|
+
of irradiance and module performance at the Joint Research Centre (JRC) in
|
|
806
|
+
Ispra, Italy (45.80N, 8.62E). Coefficients for two module types are
|
|
807
|
+
available via the ``module_type`` parameter. More details on the model can
|
|
808
|
+
be found in [1]_.
|
|
809
|
+
|
|
810
|
+
Parameters
|
|
811
|
+
----------
|
|
812
|
+
airmass : numeric
|
|
813
|
+
relative airmass. [unitless]
|
|
814
|
+
|
|
815
|
+
clearsky_index: numeric
|
|
816
|
+
clear sky index. [unitless]
|
|
817
|
+
|
|
818
|
+
module_type : str, optional
|
|
819
|
+
One of the following PV technology strings from [1]_:
|
|
820
|
+
|
|
821
|
+
* ``'cdte'`` - anonymous CdTe module.
|
|
822
|
+
* ``'multisi'`` - anonymous multicrystalline Si module.
|
|
823
|
+
|
|
824
|
+
coefficients : array-like, optional
|
|
825
|
+
user-defined coefficients, if not using one of the default coefficient
|
|
826
|
+
sets via the ``module_type`` parameter.
|
|
827
|
+
|
|
828
|
+
Returns
|
|
829
|
+
-------
|
|
830
|
+
mismatch: numeric
|
|
831
|
+
spectral mismatch factor (unitless) which is multiplied
|
|
832
|
+
with broadband irradiance reaching a module's cells to estimate
|
|
833
|
+
effective irradiance, i.e., the irradiance that is converted to
|
|
834
|
+
electrical current.
|
|
835
|
+
|
|
836
|
+
Notes
|
|
837
|
+
-----
|
|
838
|
+
The JRC model parameterises the spectral mismatch factor as a function
|
|
839
|
+
of air mass and the clear sky index as follows:
|
|
840
|
+
|
|
841
|
+
.. math::
|
|
842
|
+
|
|
843
|
+
M = 1 + a_1(e^{-k_c}-e^{-1}) + a_2(k_c-1)+a_3(AM-1.5),
|
|
844
|
+
|
|
845
|
+
where :math:`M` is the spectral mismatch factor, :math:`k_c` is the clear
|
|
846
|
+
sky index, :math:`AM` is the air mass, :math:`e` is Euler's number, and
|
|
847
|
+
:math:`a_1, a_2, a_3` are module-specific coefficients. The :math:`a_n`
|
|
848
|
+
coefficients available via the ``coefficients`` parameter differ from the
|
|
849
|
+
:math:`k_n` coefficients documented in [1]_ in that they are normalised by
|
|
850
|
+
the specific short-circuit current value, :math:`I_{sc0}^*`, which is the
|
|
851
|
+
expected short-circuit current at standard test conditions indoors. The
|
|
852
|
+
model used to estimate the air mass (denoted as :math:`AM`) is not stated
|
|
853
|
+
in the original publication. The authors of [1]_ used the ESRA model [2]_
|
|
854
|
+
to estimate the clear sky GHI for the clear sky index, which is the ratio
|
|
855
|
+
of GHI to clear sky GHI. Also, prior to the calculation of :math:`k_c`, the
|
|
856
|
+
irradiance measurements were corrected for angle of incidence using the
|
|
857
|
+
Martin and Ruiz model [3]_.
|
|
858
|
+
|
|
859
|
+
References
|
|
860
|
+
----------
|
|
861
|
+
.. [1] Huld, T., Sample, T., and Dunlop, E., 2009. A simple model
|
|
862
|
+
for estimating the influence of spectrum variations on PV performance.
|
|
863
|
+
In Proceedings of the 24th European Photovoltaic Solar Energy
|
|
864
|
+
Conference, Hamburg, Germany pp. 3385-3389. 2009. Accessed at:
|
|
865
|
+
https://www.researchgate.net/publication/256080247
|
|
866
|
+
.. [2] Rigollier, C., Bauer, O., and Wald, L., 2000. On the clear sky model
|
|
867
|
+
of the ESRA—European Solar Radiation Atlas—with respect to the Heliosat
|
|
868
|
+
method. Solar energy, 68(1), pp.33-48.
|
|
869
|
+
:doi:`10.1016/S0038-092X(99)00055-9`
|
|
870
|
+
.. [3] Martin, N. and Ruiz, J. M., 2001. Calculation of the PV modules
|
|
871
|
+
angular losses under field conditions by means of an analytical model.
|
|
872
|
+
Solar Energy Materials and Solar Cells, 70(1), 25-38.
|
|
873
|
+
:doi:`10.1016/S0927-0248(00)00408-6`
|
|
874
|
+
"""
|
|
875
|
+
|
|
876
|
+
_coefficients = {}
|
|
877
|
+
_coefficients['multisi'] = (0.00172, 0.000508, 0.00000357)
|
|
878
|
+
_coefficients['cdte'] = (0.000643, 0.000130, 0.0000108)
|
|
879
|
+
# normalise coefficients by I*sc0, see [1]
|
|
880
|
+
_coefficients = {
|
|
881
|
+
'multisi': tuple(x / 0.00348 for x in _coefficients['multisi']),
|
|
882
|
+
'cdte': tuple(x / 0.001150 for x in _coefficients['cdte'])
|
|
883
|
+
}
|
|
884
|
+
if module_type is not None and coefficients is None:
|
|
885
|
+
coefficients = _coefficients[module_type.lower()]
|
|
886
|
+
elif module_type is None and coefficients is not None:
|
|
887
|
+
pass
|
|
888
|
+
elif module_type is None and coefficients is None:
|
|
889
|
+
raise ValueError('No valid input provided, both module_type and ' +
|
|
890
|
+
'coefficients are None. module_type can be one of ' +
|
|
891
|
+
", ".join(_coefficients.keys()))
|
|
892
|
+
else:
|
|
893
|
+
raise ValueError('Cannot resolve input, must supply only one of ' +
|
|
894
|
+
'module_type and coefficients. module_type can be ' +
|
|
895
|
+
'one of' ", ".join(_coefficients.keys()))
|
|
896
|
+
|
|
897
|
+
coeff = coefficients
|
|
898
|
+
mismatch = (
|
|
899
|
+
1
|
|
900
|
+
+ coeff[0] * (np.exp(-clearsky_index) - np.exp(-1))
|
|
901
|
+
+ coeff[1] * (clearsky_index - 1)
|
|
902
|
+
+ coeff[2] * (airmass - 1.5)
|
|
903
|
+
)
|
|
904
|
+
return mismatch
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
def sr_to_qe(sr, wavelength=None, normalize=False):
|
|
908
|
+
"""
|
|
909
|
+
Convert spectral responsivities to quantum efficiencies.
|
|
910
|
+
If ``wavelength`` is not provided, the spectral responsivity ``sr`` must be
|
|
911
|
+
a :py:class:`pandas.Series` or :py:class:`pandas.DataFrame`, with the
|
|
912
|
+
wavelengths in the index.
|
|
913
|
+
|
|
914
|
+
Provide wavelengths in nanometers, [nm].
|
|
915
|
+
|
|
916
|
+
Conversion is described in [1]_.
|
|
917
|
+
|
|
918
|
+
.. versionadded:: 0.11.0
|
|
919
|
+
|
|
920
|
+
Parameters
|
|
921
|
+
----------
|
|
922
|
+
sr : numeric, pandas.Series or pandas.DataFrame
|
|
923
|
+
Spectral response, [A/W].
|
|
924
|
+
Index must be the wavelength in nanometers, [nm].
|
|
925
|
+
|
|
926
|
+
wavelength : numeric, optional
|
|
927
|
+
Points where spectral response is measured, in nanometers, [nm].
|
|
928
|
+
|
|
929
|
+
normalize : bool, default False
|
|
930
|
+
If True, the quantum efficiency is normalized so that the maximum value
|
|
931
|
+
is 1.
|
|
932
|
+
For ``pandas.DataFrame``, normalization is done for each column.
|
|
933
|
+
For 2D arrays, normalization is done for each sub-array.
|
|
934
|
+
|
|
935
|
+
Returns
|
|
936
|
+
-------
|
|
937
|
+
quantum_efficiency : numeric, same type as ``sr``
|
|
938
|
+
Quantum efficiency, in the interval [0, 1].
|
|
939
|
+
|
|
940
|
+
Notes
|
|
941
|
+
-----
|
|
942
|
+
- If ``sr`` is of type ``pandas.Series`` or ``pandas.DataFrame``,
|
|
943
|
+
column names will remain unchanged in the returned object.
|
|
944
|
+
- If ``wavelength`` is provided it will be used independently of the
|
|
945
|
+
datatype of ``sr``.
|
|
946
|
+
|
|
947
|
+
Examples
|
|
948
|
+
--------
|
|
949
|
+
>>> import numpy as np
|
|
950
|
+
>>> import pandas as pd
|
|
951
|
+
>>> from pvlib import spectrum
|
|
952
|
+
>>> wavelengths = np.array([350, 550, 750])
|
|
953
|
+
>>> spectral_response = np.array([0.25, 0.40, 0.57])
|
|
954
|
+
>>> quantum_efficiency = spectrum.sr_to_qe(spectral_response, wavelengths)
|
|
955
|
+
>>> print(quantum_efficiency)
|
|
956
|
+
array([0.88560142, 0.90170326, 0.94227991])
|
|
957
|
+
|
|
958
|
+
>>> spectral_response_series = pd.Series(spectral_response, index=wavelengths, name="dataset")
|
|
959
|
+
>>> qe = spectrum.sr_to_qe(spectral_response_series)
|
|
960
|
+
>>> print(qe)
|
|
961
|
+
350 0.885601
|
|
962
|
+
550 0.901703
|
|
963
|
+
750 0.942280
|
|
964
|
+
Name: dataset, dtype: float64
|
|
965
|
+
|
|
966
|
+
>>> qe = spectrum.sr_to_qe(spectral_response_series, normalize=True)
|
|
967
|
+
>>> print(qe)
|
|
968
|
+
350 0.939850
|
|
969
|
+
550 0.956938
|
|
970
|
+
750 1.000000
|
|
971
|
+
Name: dataset, dtype: float64
|
|
972
|
+
|
|
973
|
+
References
|
|
974
|
+
----------
|
|
975
|
+
.. [1] “Spectral Response,” PV Performance Modeling Collaborative (PVPMC).
|
|
976
|
+
https://pvpmc.sandia.gov/modeling-guide/2-dc-module-iv/effective-irradiance/spectral-response/
|
|
977
|
+
.. [2] “Spectral Response | PVEducation,” www.pveducation.org.
|
|
978
|
+
https://www.pveducation.org/pvcdrom/solar-cell-operation/spectral-response
|
|
979
|
+
|
|
980
|
+
See Also
|
|
981
|
+
--------
|
|
982
|
+
pvlib.spectrum.qe_to_sr
|
|
983
|
+
""" # noqa: E501
|
|
984
|
+
if wavelength is None:
|
|
985
|
+
if hasattr(sr, "index"): # true for pandas objects
|
|
986
|
+
# use reference to index values instead of index alone so
|
|
987
|
+
# sr / wavelength returns a series with the same name
|
|
988
|
+
wavelength = sr.index.array
|
|
989
|
+
else:
|
|
990
|
+
raise TypeError(
|
|
991
|
+
"'sr' must have an '.index' attribute"
|
|
992
|
+
+ " or 'wavelength' must be provided"
|
|
993
|
+
)
|
|
994
|
+
quantum_efficiency = (
|
|
995
|
+
sr
|
|
996
|
+
/ wavelength
|
|
997
|
+
* _PLANCK_BY_LIGHT_SPEED_OVER_ELEMENTAL_CHARGE_BY_BILLION
|
|
998
|
+
)
|
|
999
|
+
|
|
1000
|
+
if normalize:
|
|
1001
|
+
quantum_efficiency = normalize_max2one(quantum_efficiency)
|
|
1002
|
+
|
|
1003
|
+
return quantum_efficiency
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
def qe_to_sr(qe, wavelength=None, normalize=False):
|
|
1007
|
+
"""
|
|
1008
|
+
Convert quantum efficiencies to spectral responsivities.
|
|
1009
|
+
If ``wavelength`` is not provided, the quantum efficiency ``qe`` must be
|
|
1010
|
+
a :py:class:`pandas.Series` or :py:class:`pandas.DataFrame`, with the
|
|
1011
|
+
wavelengths in the index.
|
|
1012
|
+
|
|
1013
|
+
Provide wavelengths in nanometers, [nm].
|
|
1014
|
+
|
|
1015
|
+
Conversion is described in [1]_.
|
|
1016
|
+
|
|
1017
|
+
.. versionadded:: 0.11.0
|
|
1018
|
+
|
|
1019
|
+
Parameters
|
|
1020
|
+
----------
|
|
1021
|
+
qe : numeric, pandas.Series or pandas.DataFrame
|
|
1022
|
+
Quantum efficiency.
|
|
1023
|
+
If pandas subtype, index must be the wavelength in nanometers, [nm].
|
|
1024
|
+
|
|
1025
|
+
wavelength : numeric, optional
|
|
1026
|
+
Points where quantum efficiency is measured, in nanometers, [nm].
|
|
1027
|
+
|
|
1028
|
+
normalize : bool, default False
|
|
1029
|
+
If True, the spectral response is normalized so that the maximum value
|
|
1030
|
+
is 1.
|
|
1031
|
+
For ``pandas.DataFrame``, normalization is done for each column.
|
|
1032
|
+
For 2D arrays, normalization is done for each sub-array.
|
|
1033
|
+
|
|
1034
|
+
Returns
|
|
1035
|
+
-------
|
|
1036
|
+
spectral_response : numeric, same type as ``qe``
|
|
1037
|
+
Spectral response, [A/W].
|
|
1038
|
+
|
|
1039
|
+
Notes
|
|
1040
|
+
-----
|
|
1041
|
+
- If ``qe`` is of type ``pandas.Series`` or ``pandas.DataFrame``,
|
|
1042
|
+
column names will remain unchanged in the returned object.
|
|
1043
|
+
- If ``wavelength`` is provided it will be used independently of the
|
|
1044
|
+
datatype of ``qe``.
|
|
1045
|
+
|
|
1046
|
+
Examples
|
|
1047
|
+
--------
|
|
1048
|
+
>>> import numpy as np
|
|
1049
|
+
>>> import pandas as pd
|
|
1050
|
+
>>> from pvlib import spectrum
|
|
1051
|
+
>>> wavelengths = np.array([350, 550, 750])
|
|
1052
|
+
>>> quantum_efficiency = np.array([0.86, 0.90, 0.94])
|
|
1053
|
+
>>> spectral_response = spectrum.qe_to_sr(quantum_efficiency, wavelengths)
|
|
1054
|
+
>>> print(spectral_response)
|
|
1055
|
+
array([0.24277287, 0.39924442, 0.56862085])
|
|
1056
|
+
|
|
1057
|
+
>>> quantum_efficiency_series = pd.Series(quantum_efficiency, index=wavelengths, name="dataset")
|
|
1058
|
+
>>> sr = spectrum.qe_to_sr(quantum_efficiency_series)
|
|
1059
|
+
>>> print(sr)
|
|
1060
|
+
350 0.242773
|
|
1061
|
+
550 0.399244
|
|
1062
|
+
750 0.568621
|
|
1063
|
+
Name: dataset, dtype: float64
|
|
1064
|
+
|
|
1065
|
+
>>> sr = spectrum.qe_to_sr(quantum_efficiency_series, normalize=True)
|
|
1066
|
+
>>> print(sr)
|
|
1067
|
+
350 0.426950
|
|
1068
|
+
550 0.702128
|
|
1069
|
+
750 1.000000
|
|
1070
|
+
Name: dataset, dtype: float64
|
|
1071
|
+
|
|
1072
|
+
References
|
|
1073
|
+
----------
|
|
1074
|
+
.. [1] “Spectral Response,” PV Performance Modeling Collaborative (PVPMC).
|
|
1075
|
+
https://pvpmc.sandia.gov/modeling-guide/2-dc-module-iv/effective-irradiance/spectral-response/
|
|
1076
|
+
.. [2] “Spectral Response | PVEducation,” www.pveducation.org.
|
|
1077
|
+
https://www.pveducation.org/pvcdrom/solar-cell-operation/spectral-response
|
|
1078
|
+
|
|
1079
|
+
See Also
|
|
1080
|
+
--------
|
|
1081
|
+
pvlib.spectrum.sr_to_qe
|
|
1082
|
+
""" # noqa: E501
|
|
1083
|
+
if wavelength is None:
|
|
1084
|
+
if hasattr(qe, "index"): # true for pandas objects
|
|
1085
|
+
# use reference to index values instead of index alone so
|
|
1086
|
+
# sr / wavelength returns a series with the same name
|
|
1087
|
+
wavelength = qe.index.array
|
|
1088
|
+
else:
|
|
1089
|
+
raise TypeError(
|
|
1090
|
+
"'qe' must have an '.index' attribute"
|
|
1091
|
+
+ " or 'wavelength' must be provided"
|
|
1092
|
+
)
|
|
1093
|
+
spectral_responsivity = (
|
|
1094
|
+
qe
|
|
1095
|
+
* wavelength
|
|
1096
|
+
/ _PLANCK_BY_LIGHT_SPEED_OVER_ELEMENTAL_CHARGE_BY_BILLION
|
|
1097
|
+
)
|
|
1098
|
+
|
|
1099
|
+
if normalize:
|
|
1100
|
+
spectral_responsivity = normalize_max2one(spectral_responsivity)
|
|
1101
|
+
|
|
1102
|
+
return spectral_responsivity
|