pvlib 0.11.0a1__py3-none-any.whl → 0.11.1__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.
Files changed (51) hide show
  1. pvlib/atmosphere.py +157 -1
  2. pvlib/bifacial/__init__.py +4 -4
  3. pvlib/bifacial/loss_models.py +163 -0
  4. pvlib/clearsky.py +18 -29
  5. pvlib/data/pvgis_tmy_meta.json +32 -93
  6. pvlib/data/pvgis_tmy_test.dat +8761 -8761
  7. pvlib/data/tmy_45.000_8.000_2005_2020.csv +8789 -0
  8. pvlib/data/tmy_45.000_8.000_2005_2020.epw +8768 -0
  9. pvlib/data/tmy_45.000_8.000_2005_2020.json +1 -0
  10. pvlib/data/tmy_45.000_8.000_2005_2020.txt +8761 -0
  11. pvlib/data/tmy_45.000_8.000_userhorizon.json +1 -1
  12. pvlib/data/variables_style_rules.csv +2 -1
  13. pvlib/iotools/pvgis.py +39 -3
  14. pvlib/irradiance.py +141 -120
  15. pvlib/location.py +5 -5
  16. pvlib/modelchain.py +1 -1
  17. pvlib/pvsystem.py +2 -2
  18. pvlib/shading.py +8 -8
  19. pvlib/singlediode.py +1 -1
  20. pvlib/solarposition.py +55 -50
  21. pvlib/spa.py +24 -22
  22. pvlib/spectrum/__init__.py +9 -4
  23. pvlib/spectrum/irradiance.py +272 -0
  24. pvlib/spectrum/mismatch.py +118 -508
  25. pvlib/spectrum/response.py +280 -0
  26. pvlib/spectrum/spectrl2.py +16 -16
  27. pvlib/tests/bifacial/test_losses_models.py +54 -0
  28. pvlib/tests/iotools/test_pvgis.py +57 -11
  29. pvlib/tests/spectrum/__init__.py +0 -0
  30. pvlib/tests/spectrum/conftest.py +40 -0
  31. pvlib/tests/spectrum/test_irradiance.py +138 -0
  32. pvlib/tests/{test_spectrum.py → spectrum/test_mismatch.py} +32 -306
  33. pvlib/tests/spectrum/test_response.py +124 -0
  34. pvlib/tests/spectrum/test_spectrl2.py +72 -0
  35. pvlib/tests/test_atmosphere.py +71 -0
  36. pvlib/tests/test_clearsky.py +37 -25
  37. pvlib/tests/test_irradiance.py +6 -6
  38. pvlib/tests/test_solarposition.py +84 -36
  39. pvlib/tests/test_spa.py +1 -1
  40. pvlib/tools.py +26 -2
  41. pvlib/tracking.py +53 -47
  42. {pvlib-0.11.0a1.dist-info → pvlib-0.11.1.dist-info}/METADATA +31 -29
  43. {pvlib-0.11.0a1.dist-info → pvlib-0.11.1.dist-info}/RECORD +47 -38
  44. {pvlib-0.11.0a1.dist-info → pvlib-0.11.1.dist-info}/WHEEL +1 -1
  45. pvlib/data/tmy_45.000_8.000_2005_2016.csv +0 -8789
  46. pvlib/data/tmy_45.000_8.000_2005_2016.epw +0 -8768
  47. pvlib/data/tmy_45.000_8.000_2005_2016.json +0 -1
  48. pvlib/data/tmy_45.000_8.000_2005_2016.txt +0 -8761
  49. {pvlib-0.11.0a1.dist-info → pvlib-0.11.1.dist-info}/AUTHORS.md +0 -0
  50. {pvlib-0.11.0a1.dist-info → pvlib-0.11.1.dist-info}/LICENSE +0 -0
  51. {pvlib-0.11.0a1.dist-info → pvlib-0.11.1.dist-info}/top_level.txt +0 -0
@@ -1,259 +1,15 @@
1
1
  """
2
- The ``mismatch`` module provides functions for spectral mismatch calculations.
2
+ The ``mismatch`` module in the ``spectrum`` package provides functions for
3
+ spectral mismatch calculations. Spectral mismatch models quantify the effect on
4
+ a device's photocurrent (or its short-circuit current) of changes in the solar
5
+ spectrum due to the atmosphere.
3
6
  """
4
-
5
7
  import pvlib
6
- from pvlib._deprecation import deprecated
7
- from pvlib.tools import normalize_max2one
8
8
  import numpy as np
9
9
  import pandas as pd
10
- import scipy.constants
11
10
  from scipy.integrate import trapezoid
12
- from scipy.interpolate import interp1d
13
11
 
14
- from pathlib import Path
15
12
  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
- )
25
-
26
-
27
- def get_example_spectral_response(wavelength=None):
28
- '''
29
- Generate a generic smooth spectral response (SR) for tests and experiments.
30
-
31
- Parameters
32
- ----------
33
- wavelength: 1-D sequence of numeric, optional
34
- Wavelengths at which spectral response values are generated.
35
- By default ``wavelength`` is from 280 to 1200 in 5 nm intervals. [nm]
36
-
37
- Returns
38
- -------
39
- spectral_response : pandas.Series
40
- The relative spectral response indexed by ``wavelength`` in nm. [-]
41
-
42
- Notes
43
- -----
44
- This spectral response is based on measurements taken on a c-Si cell.
45
- A small number of points near the measured curve are used to define
46
- a cubic spline having no undue oscillations, as shown in [1]_. The spline
47
- can be interpolated at arbitrary wavelengths to produce a continuous,
48
- smooth curve , which makes it suitable for experimenting with spectral
49
- data of different resolutions.
50
-
51
- References
52
- ----------
53
- .. [1] Driesse, Anton, and Stein, Joshua. "Global Normal Spectral
54
- Irradiance in Albuquerque: a One-Year Open Dataset for PV Research".
55
- United States 2020. :doi:`10.2172/1814068`.
56
- '''
57
- # Contributed by Anton Driesse (@adriesse), PV Performance Labs. Aug. 2022
58
-
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],
67
- [1000, 0.93],
68
- [1050, 0.58],
69
- [1100, 0.21],
70
- [1150, 0.05],
71
- [1190, 0.00]]).transpose()
72
-
73
- if wavelength is None:
74
- resolution = 5.0
75
- wavelength = np.arange(280, 1200 + resolution, resolution)
76
-
77
- interpolator = interp1d(SR_DATA[0], SR_DATA[1],
78
- kind='cubic',
79
- bounds_error=False,
80
- fill_value=0.0,
81
- copy=False,
82
- assume_sorted=True)
83
-
84
- sr = pd.Series(data=interpolator(wavelength), index=wavelength)
85
-
86
- sr.index.name = 'wavelength'
87
- sr.name = 'spectral_response'
88
-
89
- return sr
90
-
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
- )
102
- def get_am15g(wavelength=None):
103
- r"""
104
- Read the ASTM G173-03 AM1.5 global spectrum on a 37-degree tilted surface,
105
- optionally interpolated to the specified wavelength(s).
106
-
107
- Global (tilted) irradiance includes direct and diffuse irradiance from sky
108
- and ground reflections, and is more formally called hemispherical
109
- irradiance (on a tilted surface). In the context of photovoltaic systems
110
- the irradiance on a flat receiver is frequently called plane-of-array (POA)
111
- irradiance.
112
-
113
- Parameters
114
- ----------
115
- wavelength: 1-D sequence of numeric, optional
116
- Wavelengths at which the spectrum is interpolated.
117
- By default the 2002 wavelengths of the standard are returned. [nm].
118
-
119
- Returns
120
- -------
121
- am15g: pandas.Series
122
- The AM1.5g standard spectrum indexed by ``wavelength``. [W/(m²nm)].
123
-
124
- Notes
125
- -----
126
- If ``wavelength`` is specified this function uses linear interpolation.
127
-
128
- If the values in ``wavelength`` are too widely spaced, the integral of the
129
- spectrum may deviate from the standard value of 1000.37 W/m².
130
-
131
- The values in the data file provided with pvlib-python are copied from an
132
- Excel file distributed by NREL, which is found here:
133
- https://www.nrel.gov/grid/solar-resource/assets/data/astmg173.xls
134
-
135
- More information about reference spectra is found here:
136
- https://www.nrel.gov/grid/solar-resource/spectra-am1.5.html
137
-
138
- See Also
139
- --------
140
- pvlib.spectrum.get_reference_spectra : reads also the direct and
141
- extraterrestrial components of the spectrum.
142
-
143
- References
144
- ----------
145
- .. [1] ASTM "G173-03 Standard Tables for Reference Solar Spectral
146
- Irradiances: Direct Normal and Hemispherical on 37° Tilted Surface."
147
- """ # noqa: E501
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.
183
-
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².
187
-
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
191
-
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
215
-
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
- )
243
-
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
- )
255
-
256
- return standard
257
13
 
258
14
 
259
15
  def calc_spectral_mismatch_field(sr, e_sun, e_ref=None):
@@ -331,7 +87,8 @@ def calc_spectral_mismatch_field(sr, e_sun, e_ref=None):
331
87
 
332
88
  # get the reference spectrum at wavelengths matching the measured spectra
333
89
  if e_ref is None:
334
- e_ref = get_reference_spectra(wavelengths=e_sun.T.index)["global"]
90
+ e_ref = pvlib.spectrum.get_reference_spectra(
91
+ wavelengths=e_sun.T.index)["global"]
335
92
 
336
93
  # interpolate the sr at the wavelengths of the spectra
337
94
  # reference spectrum wavelengths may differ if e_ref is from caller
@@ -358,21 +115,17 @@ def calc_spectral_mismatch_field(sr, e_sun, e_ref=None):
358
115
  def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
359
116
  module_type=None, coefficients=None,
360
117
  min_precipitable_water=0.1,
361
- max_precipitable_water=8):
118
+ max_precipitable_water=8,
119
+ min_airmass_absolute=0.58,
120
+ max_airmass_absolute=10):
362
121
  r"""
363
122
  Spectral mismatch modifier based on precipitable water and absolute
364
123
  (pressure-adjusted) air mass.
365
124
 
366
- Estimates a spectral mismatch modifier :math:`M` representing the effect on
367
- module short circuit current of variation in the spectral
368
- irradiance. :math:`M` is estimated from absolute (pressure currected) air
369
- mass, :math:`AM_a`, and precipitable water, :math:`Pw`, using the following
370
- function:
371
-
372
- .. math::
373
-
374
- M = c_1 + c_2 AM_a + c_3 Pw + c_4 AM_a^{0.5}
375
- + c_5 Pw^{0.5} + c_6 \frac{AM_a} {Pw^{0.5}}
125
+ Estimates the spectral mismatch modifier, :math:`M`, representing the
126
+ effect of variation in the spectral irradiance on the module short circuit
127
+ current :math:`M` is estimated from absolute (pressure-corrected) air
128
+ mass, :math:`AM_a`, and precipitable water, :math:`Pw`.
376
129
 
377
130
  Default coefficients are determined for several cell types with
378
131
  known quantum efficiency curves, by using the Simple Model of the
@@ -383,15 +136,13 @@ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
383
136
  * :math:`0.5 \textrm{cm} <= Pw <= 5 \textrm{cm}`
384
137
  * :math:`1.0 <= AM_a <= 5.0`
385
138
  * Spectral range is limited to that of CMP11 (280 nm to 2800 nm)
386
- * spectrum simulated on a plane normal to the sun
139
+ * Spectrum simulated on an equatorial facing surface with 37° tilt
387
140
  * All other parameters fixed at G173 standard
388
141
 
389
- From these simulated spectra, M is calculated using the known
142
+ From these simulated spectra, :math:`M` is calculated using the known
390
143
  quantum efficiency curves. Multiple linear regression is then
391
- applied to fit Eq. 1 to determine the coefficients for each module.
392
-
393
- Based on the PVLIB Matlab function ``pvl_FSspeccorr`` by Mitchell
394
- Lee and Alex Panchula of First Solar, 2016 [2]_.
144
+ applied to fit Eq. 1 to determine the coefficients for each module. More
145
+ details on the model can be found in [2]_.
395
146
 
396
147
  Parameters
397
148
  ----------
@@ -406,11 +157,12 @@ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
406
157
  'multisi', and 'polysi' (can be lower or upper case). If provided,
407
158
  module_type selects default coefficients for the following modules:
408
159
 
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.
160
+ * ``'cdte'`` - First Solar Series 4-2 CdTe module.
161
+ * ``'monosi'``, ``'xsi'`` - First Solar TetraSun module.
162
+ * ``'multisi'``, ``'polysi'`` - anonymous multi-crystalline silicon
163
+ module.
164
+ * ``'cigs'`` - anonymous copper indium gallium selenide module.
165
+ * ``'asi'`` - anonymous amorphous silicon module.
414
166
 
415
167
  The module used to calculate the spectral correction
416
168
  coefficients corresponds to the Multi-crystalline silicon
@@ -430,12 +182,20 @@ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
430
182
  min_precipitable_water : float, default 0.1
431
183
  minimum atmospheric precipitable water. Any ``precipitable_water``
432
184
  value lower than ``min_precipitable_water``
433
- is set to ``min_precipitable_water`` to avoid model divergence. [cm]
185
+ is set to ``min_precipitable_water``. [cm]
434
186
 
435
187
  max_precipitable_water : float, default 8
436
188
  maximum atmospheric precipitable water. Any ``precipitable_water``
437
189
  value greater than ``max_precipitable_water``
438
- is set to ``np.nan`` to avoid model divergence. [cm]
190
+ is set to ``np.nan``. [cm]
191
+
192
+ min_airmass_absolute : float, default 0.58
193
+ minimum absolute airmass. Any ``airmass_absolute`` value lower than
194
+ ``min_airmass_absolute`` is set to ``min_airmass_absolute``. [unitless]
195
+
196
+ max_airmass_absolute : float, default 10
197
+ minimum absolute airmass. Any ``airmass_absolute`` value greater than
198
+ ``max_airmass_absolute`` is set to ``max_airmass_absolute``. [unitless]
439
199
 
440
200
  Returns
441
201
  -------
@@ -445,6 +205,22 @@ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
445
205
  effective irradiance, i.e., the irradiance that is converted to
446
206
  electrical current.
447
207
 
208
+ Notes
209
+ ----
210
+ The ``spectral_factor_firstsolar`` model takes the following form:
211
+
212
+ .. math::
213
+
214
+ M = c_1 + c_2 AM_a + c_3 Pw + c_4 AM_a^{0.5}
215
+ + c_5 Pw^{0.5} + c_6 \frac{AM_a} {Pw^{0.5}}.
216
+
217
+ The default values for the limits applied to :math:`AM_a` and :math:`Pw`
218
+ via the ``min_precipitable_water``, ``max_precipitable_water``,
219
+ ``min_airmass_absolute``, and ``max_airmass_absolute`` are set to prevent
220
+ divergence of the model presented above. These default values were
221
+ determined by the publication authors in the original pvlib-python
222
+ implementation (:pull:`208`).
223
+
448
224
  References
449
225
  ----------
450
226
  .. [1] Gueymard, Christian. SMARTS2: a simple model of the atmospheric
@@ -461,36 +237,27 @@ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
461
237
  MMF Approach, TUV Rheinland Energy GmbH report 21237296.003,
462
238
  January 2017
463
239
  """
464
-
465
- # --- Screen Input Data ---
466
-
467
- # *** Pw ***
468
- # Replace Pw Values below 0.1 cm with 0.1 cm to prevent model from
469
- # diverging"
470
240
  pw = np.atleast_1d(precipitable_water)
471
241
  pw = pw.astype('float64')
472
242
  if np.min(pw) < min_precipitable_water:
473
243
  pw = np.maximum(pw, min_precipitable_water)
474
- warn('Exceptionally low pw values replaced with '
475
- f'{min_precipitable_water} cm to prevent model divergence')
244
+ warn('Low precipitable water values replaced with '
245
+ f'{min_precipitable_water} cm in the calculation of spectral '
246
+ 'mismatch.')
476
247
 
477
- # Warn user about Pw data that is exceptionally high
478
248
  if np.max(pw) > max_precipitable_water:
479
249
  pw[pw > max_precipitable_water] = np.nan
480
- warn('Exceptionally high pw values replaced by np.nan: '
481
- 'check input data.')
482
-
483
- # *** AMa ***
484
- # Replace Extremely High AM with AM 10 to prevent model divergence
485
- # AM > 10 will only occur very close to sunset
486
- if np.max(airmass_absolute) > 10:
487
- airmass_absolute = np.minimum(airmass_absolute, 10)
488
-
489
- # Warn user about AMa data that is exceptionally low
490
- if np.min(airmass_absolute) < 0.58:
491
- warn('Exceptionally low air mass: ' +
492
- 'model not intended for extra-terrestrial use')
493
- # pvl_absoluteairmass(1,pvl_alt2pres(4340)) = 0.58 Elevation of
250
+ warn('High precipitable water values replaced with np.nan in '
251
+ 'the calculation of spectral mismatch.')
252
+
253
+ airmass_absolute = np.minimum(airmass_absolute, max_airmass_absolute)
254
+
255
+ if np.min(airmass_absolute) < min_airmass_absolute:
256
+ airmass_absolute = np.maximum(airmass_absolute, min_airmass_absolute)
257
+ warn('Low airmass values replaced with 'f'{min_airmass_absolute} in '
258
+ 'the calculation of spectral mismatch.')
259
+ # pvlib.atmosphere.get_absolute_airmass(1,
260
+ # pvlib.atmosphere.alt2pres(4340)) = 0.58 Elevation of
494
261
  # Mina Pirquita, Argentian = 4340 m. Highest elevation city with
495
262
  # population over 50,000.
496
263
 
@@ -519,7 +286,6 @@ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
519
286
  raise TypeError('Cannot resolve input, must supply only one of ' +
520
287
  'module_type and coefficients')
521
288
 
522
- # Evaluate Spectral Shift
523
289
  coeff = coefficients
524
290
  ama = airmass_absolute
525
291
  modifier = (
@@ -531,26 +297,68 @@ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
531
297
 
532
298
  def spectral_factor_sapm(airmass_absolute, module):
533
299
  """
534
- Calculates the SAPM spectral loss coefficient, F1.
300
+ Calculates the spectral mismatch factor, :math:`f_1`,
301
+ using the Sandia Array Performance Model approach.
302
+
303
+ The SAPM spectral factor function is part of the broader Sandia Array
304
+ Performance Model, which defines five points on an IV curve using empirical
305
+ module-specific coefficients. Module coefficients for the SAPM are
306
+ available in the SAPM database and can be retrieved for use in the
307
+ ``module`` parameter through
308
+ :py:func:`pvlib.pvsystem.retrieve_sam()`. More details on the
309
+ SAPM can be found in [1]_, while a full description of the procedure to
310
+ determine the empirical model coefficients, including those for the SAPM
311
+ spectral correction, can be found in [2]_.
535
312
 
536
313
  Parameters
537
314
  ----------
538
315
  airmass_absolute : numeric
539
- Absolute airmass
316
+ Absolute airmass [unitless]
317
+
318
+ Note: ``np.nan`` airmass values will result in 0 output.
540
319
 
541
320
  module : dict-like
542
- A dict, Series, or DataFrame defining the SAPM performance
543
- parameters. See the :py:func:`sapm` notes section for more
544
- details.
321
+ A dict, Series, or DataFrame defining the SAPM parameters.
322
+ Must contain keys `'A0'` through `'A4'`.
323
+ See the :py:func:`pvlib.pvsystem.sapm` notes section for more details.
545
324
 
546
325
  Returns
547
326
  -------
548
- F1 : numeric
549
- The SAPM spectral loss coefficient.
327
+ f1 : numeric
328
+ The spectral mismatch factor. [unitless]
550
329
 
551
330
  Notes
552
331
  -----
553
- nan airmass values will result in 0 output.
332
+ The SAPM spectral correction functions parameterises :math:`f_1` as a
333
+ fourth order polynomial function of absolute air mass:
334
+
335
+ .. math::
336
+
337
+ f_1 = a_0 + a_1 AM_a + a_2 AM_a^2 + a_3 AM_a^3 + a_4 AM_a^4,
338
+
339
+ where :math:`f_1` is the spectral mismatch factor, :math:`a_{0-4}` are
340
+ the module-specific coefficients, and :math:`AM_a` is the absolute airmass,
341
+ which is calculated by applying a pressure correction to the relative
342
+ airmass. More detail on how this spectral correction function was developed
343
+ can be found in [3]_.
344
+
345
+ References
346
+ ----------
347
+ .. [1] King, D., Kratochvil, J., and Boyson W. (2004), "Sandia
348
+ Photovoltaic Array Performance Model", (No. SAND2004-3535), Sandia
349
+ National Laboratories, Albuquerque, NM (United States).
350
+ :doi:`10.2172/919131`
351
+ .. [2] King, B., Hansen, C., Riley, D., Robinson, C., and Pratt, L.
352
+ (2016). Procedure to determine coefficients for the Sandia Array
353
+ Performance Model (SAPM) (No. SAND2016-5284). Sandia National
354
+ Laboratories, Albuquerque, NM (United States).
355
+ :doi:`10.2172/1256510`
356
+ .. [3] King, D., Kratochvil, J., and Boyson, W. "Measuring solar spectral
357
+ and angle-of-incidence effects on photovoltaic modules and solar
358
+ irradiance sensors." Conference Record of the 26th IEEE Potovoltaic
359
+ Specialists Conference (PVSC). IEEE, 1997.
360
+ :doi:`10.1109/PVSC.1997.654283`
361
+
554
362
  """
555
363
 
556
364
  am_coeff = [module['A4'], module['A3'], module['A2'], module['A1'],
@@ -581,7 +389,7 @@ def spectral_factor_caballero(precipitable_water, airmass_absolute, aod500,
581
389
  available here via the ``module_type`` parameter were determined
582
390
  by fitting the model equations to spectral factors calculated from
583
391
  global tilted spectral irradiance measurements taken in the city of
584
- Jaén, Spain. See [1]_ for details.
392
+ Jaén, Spain. See [1]_ for details.
585
393
 
586
394
  Parameters
587
395
  ----------
@@ -598,8 +406,8 @@ def spectral_factor_caballero(precipitable_water, airmass_absolute, aod500,
598
406
  One of the following PV technology strings from [1]_:
599
407
 
600
408
  * ``'cdte'`` - anonymous CdTe module.
601
- * ``'monosi'``, - anonymous sc-si module.
602
- * ``'multisi'``, - anonymous mc-si- module.
409
+ * ``'monosi'`` - anonymous sc-si module.
410
+ * ``'multisi'`` - anonymous mc-si- module.
603
411
  * ``'cigs'`` - anonymous copper indium gallium selenide module.
604
412
  * ``'asi'`` - anonymous amorphous silicon module.
605
413
  * ``'perovskite'`` - anonymous pervoskite module.
@@ -713,8 +521,8 @@ def spectral_factor_pvspec(airmass_absolute, clearsky_index,
713
521
 
714
522
  * ``'fs4-1'`` - First Solar series 4-1 and earlier CdTe module.
715
523
  * ``'fs4-2'`` - First Solar 4-2 and later CdTe module.
716
- * ``'monosi'``, - anonymous monocrystalline Si module.
717
- * ``'multisi'``, - anonymous multicrystalline Si module.
524
+ * ``'monosi'`` - anonymous monocrystalline Si module.
525
+ * ``'multisi'`` - anonymous multicrystalline Si module.
718
526
  * ``'cigs'`` - anonymous copper indium gallium selenide module.
719
527
  * ``'asi'`` - anonymous amorphous silicon module.
720
528
 
@@ -902,201 +710,3 @@ def spectral_factor_jrc(airmass, clearsky_index, module_type=None,
902
710
  + coeff[2] * (airmass - 1.5)
903
711
  )
904
712
  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