pvlib 0.9.4a1__py3-none-any.whl → 0.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. pvlib/__init__.py +3 -2
  2. pvlib/atmosphere.py +23 -173
  3. pvlib/bifacial/infinite_sheds.py +88 -277
  4. pvlib/bifacial/utils.py +270 -28
  5. pvlib/data/adr-library-cec-inverters-2019-03-05.csv +5009 -0
  6. pvlib/data/precise_iv_curves1.json +10251 -0
  7. pvlib/data/precise_iv_curves2.json +10251 -0
  8. pvlib/data/precise_iv_curves_parameter_sets1.csv +33 -0
  9. pvlib/data/precise_iv_curves_parameter_sets2.csv +33 -0
  10. pvlib/data/test_psm3_2017.csv +17521 -17521
  11. pvlib/data/test_psm3_2019_5min.csv +288 -288
  12. pvlib/data/test_read_psm3.csv +17522 -17522
  13. pvlib/data/test_read_pvgis_horizon.csv +49 -0
  14. pvlib/data/variables_style_rules.csv +3 -0
  15. pvlib/iam.py +207 -51
  16. pvlib/inverter.py +6 -1
  17. pvlib/iotools/__init__.py +7 -2
  18. pvlib/iotools/acis.py +516 -0
  19. pvlib/iotools/midc.py +4 -4
  20. pvlib/iotools/psm3.py +59 -42
  21. pvlib/iotools/pvgis.py +84 -28
  22. pvlib/iotools/sodapro.py +8 -6
  23. pvlib/iotools/srml.py +121 -18
  24. pvlib/iotools/surfrad.py +2 -2
  25. pvlib/iotools/tmy.py +146 -102
  26. pvlib/irradiance.py +270 -15
  27. pvlib/ivtools/sde.py +14 -20
  28. pvlib/ivtools/sdm.py +31 -20
  29. pvlib/ivtools/utils.py +127 -6
  30. pvlib/location.py +3 -2
  31. pvlib/modelchain.py +67 -70
  32. pvlib/pvarray.py +225 -0
  33. pvlib/pvsystem.py +169 -539
  34. pvlib/shading.py +43 -2
  35. pvlib/singlediode.py +216 -66
  36. pvlib/snow.py +36 -15
  37. pvlib/soiling.py +3 -3
  38. pvlib/spa.py +327 -368
  39. pvlib/spectrum/__init__.py +8 -2
  40. pvlib/spectrum/mismatch.py +335 -0
  41. pvlib/temperature.py +124 -13
  42. pvlib/tests/bifacial/test_infinite_sheds.py +44 -106
  43. pvlib/tests/bifacial/test_utils.py +102 -5
  44. pvlib/tests/conftest.py +0 -31
  45. pvlib/tests/iotools/test_acis.py +213 -0
  46. pvlib/tests/iotools/test_midc.py +6 -6
  47. pvlib/tests/iotools/test_psm3.py +7 -5
  48. pvlib/tests/iotools/test_pvgis.py +21 -14
  49. pvlib/tests/iotools/test_sodapro.py +1 -1
  50. pvlib/tests/iotools/test_srml.py +71 -6
  51. pvlib/tests/iotools/test_tmy.py +43 -8
  52. pvlib/tests/ivtools/test_sde.py +19 -17
  53. pvlib/tests/ivtools/test_sdm.py +9 -4
  54. pvlib/tests/ivtools/test_utils.py +96 -1
  55. pvlib/tests/test_atmosphere.py +8 -64
  56. pvlib/tests/test_clearsky.py +0 -1
  57. pvlib/tests/test_iam.py +74 -1
  58. pvlib/tests/test_irradiance.py +56 -2
  59. pvlib/tests/test_location.py +1 -1
  60. pvlib/tests/test_modelchain.py +33 -76
  61. pvlib/tests/test_pvarray.py +46 -0
  62. pvlib/tests/test_pvsystem.py +366 -201
  63. pvlib/tests/test_shading.py +35 -0
  64. pvlib/tests/test_singlediode.py +306 -29
  65. pvlib/tests/test_snow.py +84 -1
  66. pvlib/tests/test_soiling.py +8 -7
  67. pvlib/tests/test_solarposition.py +7 -7
  68. pvlib/tests/test_spa.py +6 -7
  69. pvlib/tests/test_spectrum.py +145 -1
  70. pvlib/tests/test_temperature.py +29 -11
  71. pvlib/tests/test_tools.py +41 -0
  72. pvlib/tests/test_tracking.py +0 -149
  73. pvlib/tools.py +49 -25
  74. pvlib/tracking.py +1 -269
  75. pvlib-0.10.0.dist-info/AUTHORS.md +35 -0
  76. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/LICENSE +5 -2
  77. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/METADATA +3 -13
  78. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/RECORD +80 -75
  79. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/WHEEL +1 -1
  80. pvlib/data/adr-library-2013-10-01.csv +0 -1762
  81. pvlib/forecast.py +0 -1211
  82. pvlib/iotools/ecmwf_macc.py +0 -312
  83. pvlib/tests/iotools/test_ecmwf_macc.py +0 -162
  84. pvlib/tests/test_forecast.py +0 -228
  85. pvlib-0.9.4a1.dist-info/AUTHORS.md +0 -32
  86. {pvlib-0.9.4a1.dist-info → pvlib-0.10.0.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,9 @@
1
1
  from pvlib.spectrum.spectrl2 import spectrl2 # noqa: F401
2
- from pvlib.spectrum.mismatch import (get_example_spectral_response, get_am15g,
3
- calc_spectral_mismatch_field)
2
+ from pvlib.spectrum.mismatch import ( # noqa: F401
3
+ calc_spectral_mismatch_field,
4
+ get_am15g,
5
+ get_example_spectral_response,
6
+ spectral_factor_caballero,
7
+ spectral_factor_firstsolar,
8
+ spectral_factor_sapm,
9
+ )
@@ -8,6 +8,8 @@ import pandas as pd
8
8
  from scipy.interpolate import interp1d
9
9
  import os
10
10
 
11
+ from warnings import warn
12
+
11
13
 
12
14
  def get_example_spectral_response(wavelength=None):
13
15
  '''
@@ -235,3 +237,336 @@ def calc_spectral_mismatch_field(sr, e_sun, e_ref=None):
235
237
  smm = pd.Series(smm, index=e_sun.index)
236
238
 
237
239
  return smm
240
+
241
+
242
+ def spectral_factor_firstsolar(precipitable_water, airmass_absolute,
243
+ module_type=None, coefficients=None,
244
+ min_precipitable_water=0.1,
245
+ max_precipitable_water=8):
246
+ r"""
247
+ Spectral mismatch modifier based on precipitable water and absolute
248
+ (pressure-adjusted) airmass.
249
+
250
+ Estimates a spectral mismatch modifier :math:`M` representing the effect on
251
+ module short circuit current of variation in the spectral
252
+ irradiance. :math:`M` is estimated from absolute (pressure currected) air
253
+ mass, :math:`AM_a`, and precipitable water, :math:`Pw`, using the following
254
+ function:
255
+
256
+ .. math::
257
+
258
+ M = c_1 + c_2 AM_a + c_3 Pw + c_4 AM_a^{0.5}
259
+ + c_5 Pw^{0.5} + c_6 \frac{AM_a} {Pw^{0.5}}
260
+
261
+ Default coefficients are determined for several cell types with
262
+ known quantum efficiency curves, by using the Simple Model of the
263
+ Atmospheric Radiative Transfer of Sunshine (SMARTS) [1]_. Using
264
+ SMARTS, spectrums are simulated with all combinations of AMa and
265
+ Pw where:
266
+
267
+ * :math:`0.5 \textrm{cm} <= Pw <= 5 \textrm{cm}`
268
+ * :math:`1.0 <= AM_a <= 5.0`
269
+ * Spectral range is limited to that of CMP11 (280 nm to 2800 nm)
270
+ * spectrum simulated on a plane normal to the sun
271
+ * All other parameters fixed at G173 standard
272
+
273
+ From these simulated spectra, M is calculated using the known
274
+ quantum efficiency curves. Multiple linear regression is then
275
+ applied to fit Eq. 1 to determine the coefficients for each module.
276
+
277
+ Based on the PVLIB Matlab function ``pvl_FSspeccorr`` by Mitchell
278
+ Lee and Alex Panchula of First Solar, 2016 [2]_.
279
+
280
+ Parameters
281
+ ----------
282
+ precipitable_water : numeric
283
+ atmospheric precipitable water. [cm]
284
+
285
+ airmass_absolute : numeric
286
+ absolute (pressure-adjusted) airmass. [unitless]
287
+
288
+ module_type : str, optional
289
+ a string specifying a cell type. Values of 'cdte', 'monosi', 'xsi',
290
+ 'multisi', and 'polysi' (can be lower or upper case). If provided,
291
+ module_type selects default coefficients for the following modules:
292
+
293
+ * 'cdte' - First Solar Series 4-2 CdTe module.
294
+ * 'monosi', 'xsi' - First Solar TetraSun module.
295
+ * 'multisi', 'polysi' - anonymous multi-crystalline silicon module.
296
+ * 'cigs' - anonymous copper indium gallium selenide module.
297
+ * 'asi' - anonymous amorphous silicon module.
298
+
299
+ The module used to calculate the spectral correction
300
+ coefficients corresponds to the Multi-crystalline silicon
301
+ Manufacturer 2 Model C from [3]_. The spectral response (SR) of CIGS
302
+ and a-Si modules used to derive coefficients can be found in [4]_
303
+
304
+ coefficients : array-like, optional
305
+ Allows for entry of user-defined spectral correction
306
+ coefficients. Coefficients must be of length 6. Derivation of
307
+ coefficients requires use of SMARTS and PV module quantum
308
+ efficiency curve. Useful for modeling PV module types which are
309
+ not included as defaults, or to fine tune the spectral
310
+ correction to a particular PV module. Note that the parameters for
311
+ modules with very similar quantum efficiency should be similar,
312
+ in most cases limiting the need for module specific coefficients.
313
+
314
+ min_precipitable_water : float, default 0.1
315
+ minimum atmospheric precipitable water. Any ``precipitable_water``
316
+ value lower than ``min_precipitable_water``
317
+ is set to ``min_precipitable_water`` to avoid model divergence. [cm]
318
+
319
+ max_precipitable_water : float, default 8
320
+ maximum atmospheric precipitable water. Any ``precipitable_water``
321
+ value greater than ``max_precipitable_water``
322
+ is set to ``np.nan`` to avoid model divergence. [cm]
323
+
324
+ Returns
325
+ -------
326
+ modifier: array-like
327
+ spectral mismatch factor (unitless) which can be multiplied
328
+ with broadband irradiance reaching a module's cells to estimate
329
+ effective irradiance, i.e., the irradiance that is converted to
330
+ electrical current.
331
+
332
+ References
333
+ ----------
334
+ .. [1] Gueymard, Christian. SMARTS2: a simple model of the atmospheric
335
+ radiative transfer of sunshine: algorithms and performance
336
+ assessment. Cocoa, FL: Florida Solar Energy Center, 1995.
337
+ .. [2] Lee, Mitchell, and Panchula, Alex. "Spectral Correction for
338
+ Photovoltaic Module Performance Based on Air Mass and Precipitable
339
+ Water." IEEE Photovoltaic Specialists Conference, Portland, 2016
340
+ .. [3] Marion, William F., et al. User's Manual for Data for Validating
341
+ Models for PV Module Performance. National Renewable Energy
342
+ Laboratory, 2014. http://www.nrel.gov/docs/fy14osti/61610.pdf
343
+ .. [4] Schweiger, M. and Hermann, W, Influence of Spectral Effects
344
+ on Energy Yield of Different PV Modules: Comparison of Pwat and
345
+ MMF Approach, TUV Rheinland Energy GmbH report 21237296.003,
346
+ January 2017
347
+ """
348
+
349
+ # --- Screen Input Data ---
350
+
351
+ # *** Pw ***
352
+ # Replace Pw Values below 0.1 cm with 0.1 cm to prevent model from
353
+ # diverging"
354
+ pw = np.atleast_1d(precipitable_water)
355
+ pw = pw.astype('float64')
356
+ if np.min(pw) < min_precipitable_water:
357
+ pw = np.maximum(pw, min_precipitable_water)
358
+ warn('Exceptionally low pw values replaced with '
359
+ f'{min_precipitable_water} cm to prevent model divergence')
360
+
361
+ # Warn user about Pw data that is exceptionally high
362
+ if np.max(pw) > max_precipitable_water:
363
+ pw[pw > max_precipitable_water] = np.nan
364
+ warn('Exceptionally high pw values replaced by np.nan: '
365
+ 'check input data.')
366
+
367
+ # *** AMa ***
368
+ # Replace Extremely High AM with AM 10 to prevent model divergence
369
+ # AM > 10 will only occur very close to sunset
370
+ if np.max(airmass_absolute) > 10:
371
+ airmass_absolute = np.minimum(airmass_absolute, 10)
372
+
373
+ # Warn user about AMa data that is exceptionally low
374
+ if np.min(airmass_absolute) < 0.58:
375
+ warn('Exceptionally low air mass: ' +
376
+ 'model not intended for extra-terrestrial use')
377
+ # pvl_absoluteairmass(1,pvl_alt2pres(4340)) = 0.58 Elevation of
378
+ # Mina Pirquita, Argentian = 4340 m. Highest elevation city with
379
+ # population over 50,000.
380
+
381
+ _coefficients = {}
382
+ _coefficients['cdte'] = (
383
+ 0.86273, -0.038948, -0.012506, 0.098871, 0.084658, -0.0042948)
384
+ _coefficients['monosi'] = (
385
+ 0.85914, -0.020880, -0.0058853, 0.12029, 0.026814, -0.0017810)
386
+ _coefficients['xsi'] = _coefficients['monosi']
387
+ _coefficients['polysi'] = (
388
+ 0.84090, -0.027539, -0.0079224, 0.13570, 0.038024, -0.0021218)
389
+ _coefficients['multisi'] = _coefficients['polysi']
390
+ _coefficients['cigs'] = (
391
+ 0.85252, -0.022314, -0.0047216, 0.13666, 0.013342, -0.0008945)
392
+ _coefficients['asi'] = (
393
+ 1.12094, -0.047620, -0.0083627, -0.10443, 0.098382, -0.0033818)
394
+
395
+ if module_type is not None and coefficients is None:
396
+ coefficients = _coefficients[module_type.lower()]
397
+ elif module_type is None and coefficients is not None:
398
+ pass
399
+ elif module_type is None and coefficients is None:
400
+ raise TypeError('No valid input provided, both module_type and ' +
401
+ 'coefficients are None')
402
+ else:
403
+ raise TypeError('Cannot resolve input, must supply only one of ' +
404
+ 'module_type and coefficients')
405
+
406
+ # Evaluate Spectral Shift
407
+ coeff = coefficients
408
+ ama = airmass_absolute
409
+ modifier = (
410
+ coeff[0] + coeff[1]*ama + coeff[2]*pw + coeff[3]*np.sqrt(ama) +
411
+ coeff[4]*np.sqrt(pw) + coeff[5]*ama/np.sqrt(pw))
412
+
413
+ return modifier
414
+
415
+
416
+ def spectral_factor_sapm(airmass_absolute, module):
417
+ """
418
+ Calculates the SAPM spectral loss coefficient, F1.
419
+
420
+ Parameters
421
+ ----------
422
+ airmass_absolute : numeric
423
+ Absolute airmass
424
+
425
+ module : dict-like
426
+ A dict, Series, or DataFrame defining the SAPM performance
427
+ parameters. See the :py:func:`sapm` notes section for more
428
+ details.
429
+
430
+ Returns
431
+ -------
432
+ F1 : numeric
433
+ The SAPM spectral loss coefficient.
434
+
435
+ Notes
436
+ -----
437
+ nan airmass values will result in 0 output.
438
+ """
439
+
440
+ am_coeff = [module['A4'], module['A3'], module['A2'], module['A1'],
441
+ module['A0']]
442
+
443
+ spectral_loss = np.polyval(am_coeff, airmass_absolute)
444
+
445
+ spectral_loss = np.where(np.isnan(spectral_loss), 0, spectral_loss)
446
+
447
+ spectral_loss = np.maximum(0, spectral_loss)
448
+
449
+ if isinstance(airmass_absolute, pd.Series):
450
+ spectral_loss = pd.Series(spectral_loss, airmass_absolute.index)
451
+
452
+ return spectral_loss
453
+
454
+
455
+ def spectral_factor_caballero(precipitable_water, airmass_absolute, aod500,
456
+ module_type=None, coefficients=None):
457
+ r"""
458
+ Estimate a technology-specific spectral mismatch modifier from
459
+ airmass, aerosol optical depth, and atmospheric precipitable water,
460
+ using the Caballero model.
461
+
462
+ The model structure was motivated by examining the effect of these three
463
+ atmospheric parameters on simulated irradiance spectra and spectral
464
+ modifiers. However, the coefficient values reported in [1]_ and
465
+ available here via the ``module_type`` parameter were determined
466
+ by fitting the model equations to spectral factors calculated from
467
+ global tilted spectral irradiance measurements taken in the city of
468
+ Jaén, Spain. See [1]_ for details.
469
+
470
+ Parameters
471
+ ----------
472
+ precipitable_water : numeric
473
+ atmospheric precipitable water. [cm]
474
+
475
+ airmass_absolute : numeric
476
+ absolute (pressure-adjusted) airmass. [unitless]
477
+
478
+ aod500 : numeric
479
+ atmospheric aerosol optical depth at 500 nm. [unitless]
480
+
481
+ module_type : str, optional
482
+ One of the following PV technology strings from [1]_:
483
+
484
+ * ``'cdte'`` - anonymous CdTe module.
485
+ * ``'monosi'``, - anonymous sc-si module.
486
+ * ``'multisi'``, - anonymous mc-si- module.
487
+ * ``'cigs'`` - anonymous copper indium gallium selenide module.
488
+ * ``'asi'`` - anonymous amorphous silicon module.
489
+ * ``'perovskite'`` - anonymous pervoskite module.
490
+
491
+ coefficients : array-like, optional
492
+ user-defined coefficients, if not using one of the default coefficient
493
+ sets via the ``module_type`` parameter.
494
+
495
+ Returns
496
+ -------
497
+ modifier: numeric
498
+ spectral mismatch factor (unitless) which is multiplied
499
+ with broadband irradiance reaching a module's cells to estimate
500
+ effective irradiance, i.e., the irradiance that is converted to
501
+ electrical current.
502
+
503
+ References
504
+ ----------
505
+ .. [1] Caballero, J.A., Fernández, E., Theristis, M.,
506
+ Almonacid, F., and Nofuentes, G. "Spectral Corrections Based on
507
+ Air Mass, Aerosol Optical Depth and Precipitable Water
508
+ for PV Performance Modeling."
509
+ IEEE Journal of Photovoltaics 2018, 8(2), 552-558.
510
+ :doi:`10.1109/jphotov.2017.2787019`
511
+ """
512
+
513
+ if module_type is None and coefficients is None:
514
+ raise ValueError('Must provide either `module_type` or `coefficients`')
515
+ if module_type is not None and coefficients is not None:
516
+ raise ValueError('Only one of `module_type` and `coefficients` should '
517
+ 'be provided')
518
+
519
+ # Experimental coefficients from [1]_.
520
+ # The extra 0/1 coefficients at the end are used to enable/disable
521
+ # terms to match the different equation forms in Table 1.
522
+ _coefficients = {}
523
+ _coefficients['cdte'] = (
524
+ 1.0044, 0.0095, -0.0037, 0.0002, 0.0000, -0.0046,
525
+ -0.0182, 0, 0.0095, 0.0068, 0, 1)
526
+ _coefficients['monosi'] = (
527
+ 0.9706, 0.0377, -0.0123, 0.0025, -0.0002, 0.0159,
528
+ -0.0165, 0, -0.0016, -0.0027, 1, 0)
529
+ _coefficients['multisi'] = (
530
+ 0.9836, 0.0254, -0.0085, 0.0016, -0.0001, 0.0094,
531
+ -0.0132, 0, -0.0002, -0.0011, 1, 0)
532
+ _coefficients['cigs'] = (
533
+ 0.9801, 0.0283, -0.0092, 0.0019, -0.0001, 0.0117,
534
+ -0.0126, 0, -0.0011, -0.0019, 1, 0)
535
+ _coefficients['asi'] = (
536
+ 1.1060, -0.0848, 0.0302, -0.0076, 0.0006, -0.1283,
537
+ 0.0986, -0.0254, 0.0156, 0.0146, 1, 0)
538
+ _coefficients['perovskite'] = (
539
+ 1.0637, -0.0491, 0.0180, -0.0047, 0.0004, -0.0773,
540
+ 0.0583, -0.0159, 0.01251, 0.0109, 1, 0)
541
+
542
+ if module_type is not None:
543
+ coeff = _coefficients[module_type]
544
+ else:
545
+ coeff = coefficients
546
+
547
+ # Evaluate spectral correction factor
548
+ ama = airmass_absolute
549
+ aod500_ref = 0.084
550
+ pw_ref = 1.4164
551
+
552
+ f_AM = (
553
+ coeff[0]
554
+ + coeff[1] * ama
555
+ + coeff[2] * ama**2
556
+ + coeff[3] * ama**3
557
+ + coeff[4] * ama**4
558
+ )
559
+ # Eq 6, with Table 1
560
+ f_AOD = (aod500 - aod500_ref) * (
561
+ coeff[5]
562
+ + coeff[10] * coeff[6] * ama
563
+ + coeff[11] * coeff[6] * np.log(ama)
564
+ + coeff[7] * ama**2
565
+ )
566
+ # Eq 7, with Table 1
567
+ f_PW = (precipitable_water - pw_ref) * (
568
+ coeff[8]
569
+ + coeff[9] * np.log(ama)
570
+ )
571
+ modifier = f_AM + f_AOD + f_PW # Eq 5
572
+ return modifier
pvlib/temperature.py CHANGED
@@ -9,6 +9,7 @@ from pvlib.tools import sind
9
9
  from pvlib._deprecation import warn_deprecated
10
10
  from pvlib.tools import _get_sample_intervals
11
11
  import scipy
12
+ import scipy.constants
12
13
  import warnings
13
14
 
14
15
 
@@ -290,7 +291,7 @@ def sapm_cell_from_module(module_temperature, poa_global, deltaT,
290
291
 
291
292
 
292
293
  def pvsyst_cell(poa_global, temp_air, wind_speed=1.0, u_c=29.0, u_v=0.0,
293
- eta_m=None, module_efficiency=0.1, alpha_absorption=0.9):
294
+ module_efficiency=0.1, alpha_absorption=0.9):
294
295
  r"""
295
296
  Calculate cell temperature using an empirical heat loss factor model
296
297
  as implemented in PVsyst.
@@ -318,9 +319,7 @@ def pvsyst_cell(poa_global, temp_air, wind_speed=1.0, u_c=29.0, u_v=0.0,
318
319
  u_v : float, default 0.0
319
320
  Combined heat loss factor influenced by wind. Parameter :math:`U_{v}`
320
321
  in :eq:`pvsyst`.
321
- :math:`\left[ \frac{\text{W}/\text{m}^2}{\text{C}\ \left( \text{m/s} \right)} \right]` # noQA: E501
322
-
323
- eta_m : numeric, default None (deprecated, use module_efficiency instead)
322
+ :math:`\left[ \frac{\text{W}/\text{m}^2}{\text{C}\ \left( \text{m/s} \right)} \right]`
324
323
 
325
324
  module_efficiency : numeric, default 0.1
326
325
  Module external efficiency as a fraction. Parameter :math:`\eta_{m}`
@@ -375,13 +374,8 @@ def pvsyst_cell(poa_global, temp_air, wind_speed=1.0, u_c=29.0, u_v=0.0,
375
374
  >>> params = TEMPERATURE_MODEL_PARAMETERS['pvsyst']['freestanding']
376
375
  >>> pvsyst_cell(1000, 10, **params)
377
376
  37.93103448275862
378
- """
377
+ """ # noQA: E501
379
378
 
380
- if eta_m:
381
- warn_deprecated(
382
- since='v0.9', message='eta_m overwriting module_efficiency',
383
- name='eta_m', alternative='module_efficiency', removal='v0.10')
384
- module_efficiency = eta_m
385
379
  total_loss_factor = u_c + u_v * wind_speed
386
380
  heat_input = poa_global * alpha_absorption * (1 - module_efficiency)
387
381
  temp_difference = heat_input / total_loss_factor
@@ -413,12 +407,14 @@ def faiman(poa_global, temp_air, wind_speed=1.0, u0=25.0, u1=6.84):
413
407
 
414
408
  u0 : numeric, default 25.0
415
409
  Combined heat loss factor coefficient. The default value is one
416
- determined by Faiman for 7 silicon modules.
410
+ determined by Faiman for 7 silicon modules
411
+ in the Negev desert on an open rack at 30.9° tilt.
417
412
  :math:`\left[\frac{\text{W}/{\text{m}^2}}{\text{C}}\right]`
418
413
 
419
414
  u1 : numeric, default 6.84
420
415
  Combined heat loss factor influenced by wind. The default value is one
421
- determined by Faiman for 7 silicon modules.
416
+ determined by Faiman for 7 silicon modules
417
+ in the Negev desert on an open rack at 30.9° tilt.
422
418
  :math:`\left[ \frac{\text{W}/\text{m}^2}{\text{C}\ \left( \text{m/s} \right)} \right]`
423
419
 
424
420
  Returns
@@ -434,6 +430,7 @@ def faiman(poa_global, temp_air, wind_speed=1.0, u0=25.0, u1=6.84):
434
430
  ----------
435
431
  .. [1] Faiman, D. (2008). "Assessing the outdoor operating temperature of
436
432
  photovoltaic modules." Progress in Photovoltaics 16(4): 307-315.
433
+ :doi:`10.1002/pip.813`
437
434
 
438
435
  .. [2] "IEC 61853-2 Photovoltaic (PV) module performance testing and energy
439
436
  rating - Part 2: Spectral responsivity, incidence angle and module
@@ -442,7 +439,12 @@ def faiman(poa_global, temp_air, wind_speed=1.0, u0=25.0, u1=6.84):
442
439
  .. [3] "IEC 61853-3 Photovoltaic (PV) module performance testing and energy
443
440
  rating - Part 3: Energy rating of PV modules". IEC, Geneva, 2018.
444
441
 
445
- '''
442
+ See also
443
+ --------
444
+ pvlib.temperature.faiman_rad
445
+
446
+ ''' # noQA: E501
447
+
446
448
  # Contributed by Anton Driesse (@adriesse), PV Performance Labs. Dec., 2019
447
449
 
448
450
  # The following lines may seem odd since u0 & u1 are probably scalar,
@@ -457,6 +459,115 @@ def faiman(poa_global, temp_air, wind_speed=1.0, u0=25.0, u1=6.84):
457
459
  return temp_air + temp_difference
458
460
 
459
461
 
462
+ def faiman_rad(poa_global, temp_air, wind_speed=1.0, ir_down=None,
463
+ u0=25.0, u1=6.84, sky_view=1.0, emissivity=0.88):
464
+ r'''
465
+ Calculate cell or module temperature using the Faiman model augmented
466
+ with a radiative loss term.
467
+
468
+ The Faiman model uses an empirical heat loss factor model [1]_ and is
469
+ adopted in the IEC 61853 standards [2]_ and [3]_. The radiative loss
470
+ term was proposed and developed by Driesse [4]_.
471
+
472
+ The model can be used to represent cell or module temperature.
473
+
474
+ Parameters
475
+ ----------
476
+ poa_global : numeric
477
+ Total incident irradiance [W/m^2].
478
+
479
+ temp_air : numeric
480
+ Ambient dry bulb temperature [C].
481
+
482
+ wind_speed : numeric, default 1.0
483
+ Wind speed measured at the same height for which the wind loss
484
+ factor was determined. The default value 1.0 m/s is the wind
485
+ speed at module height used to determine NOCT. [m/s]
486
+
487
+ ir_down : numeric, default 0.0
488
+ Downwelling infrared radiation from the sky, measured on a horizontal
489
+ surface. [W/m^2]
490
+
491
+ u0 : numeric, default 25.0
492
+ Combined heat loss factor coefficient. The default value is one
493
+ determined by Faiman for 7 silicon modules
494
+ in the Negev desert on an open rack at 30.9° tilt.
495
+ :math:`\left[\frac{\text{W}/{\text{m}^2}}{\text{C}}\right]`
496
+
497
+ u1 : numeric, default 6.84
498
+ Combined heat loss factor influenced by wind. The default value is one
499
+ determined by Faiman for 7 silicon modules
500
+ in the Negev desert on an open rack at 30.9° tilt.
501
+ :math:`\left[ \frac{\text{W}/\text{m}^2}{\text{C}\ \left( \text{m/s} \right)} \right]`
502
+
503
+ sky_view : numeric, default 1.0
504
+ Effective view factor limiting the radiative exchange between the
505
+ module and the sky. For a tilted array the expressions
506
+ (1 + 3*cos(tilt)) / 4 can be used as a first estimate for sky_view
507
+ as discussed in [4]_. The default value is for a horizontal module.
508
+ [unitless]
509
+
510
+ emissivity : numeric, default 0.88
511
+ Infrared emissivity of the module surface facing the sky. The default
512
+ value represents the middle of a range of values found in the
513
+ literature. [unitless]
514
+
515
+ Returns
516
+ -------
517
+ numeric, values in degrees Celsius
518
+
519
+ Notes
520
+ -----
521
+ All arguments may be scalars or vectors. If multiple arguments
522
+ are vectors they must be the same length.
523
+
524
+ When only irradiance, air temperature and wind speed inputs are provided
525
+ (`ir_down` is `None`) this function calculates the same device temperature
526
+ as the original faiman model. When down-welling long-wave radiation data
527
+ are provided as well (`ir_down` is not None) the default u0 and u1 values
528
+ from the original model should not be used because a portion of the
529
+ radiative losses would be double-counted.
530
+
531
+ References
532
+ ----------
533
+ .. [1] Faiman, D. (2008). "Assessing the outdoor operating temperature of
534
+ photovoltaic modules." Progress in Photovoltaics 16(4): 307-315.
535
+ :doi:`10.1002/pip.813`
536
+
537
+ .. [2] "IEC 61853-2 Photovoltaic (PV) module performance testing and energy
538
+ rating - Part 2: Spectral responsivity, incidence angle and module
539
+ operating temperature measurements". IEC, Geneva, 2018.
540
+
541
+ .. [3] "IEC 61853-3 Photovoltaic (PV) module performance testing and energy
542
+ rating - Part 3: Energy rating of PV modules". IEC, Geneva, 2018.
543
+
544
+ .. [4] Driesse, A. et al (2022) "Improving Common PV Module Temperature
545
+ Models by Incorporating Radiative Losses to the Sky". SAND2022-11604.
546
+ :doi:`10.2172/1884890`
547
+
548
+ See also
549
+ --------
550
+ pvlib.temperature.faiman
551
+
552
+ ''' # noQA: E501
553
+
554
+ # Contributed by Anton Driesse (@adriesse), PV Performance Labs. Nov., 2022
555
+
556
+ abs_zero = -273.15
557
+ sigma = scipy.constants.Stefan_Boltzmann
558
+
559
+ if ir_down is None:
560
+ qrad_sky = 0.0
561
+ else:
562
+ ir_up = sigma * ((temp_air - abs_zero)**4)
563
+ qrad_sky = emissivity * sky_view * (ir_up - ir_down)
564
+
565
+ heat_input = poa_global - qrad_sky
566
+ total_loss_factor = u0 + u1 * wind_speed
567
+ temp_difference = heat_input / total_loss_factor
568
+ return temp_air + temp_difference
569
+
570
+
460
571
  def ross(poa_global, temp_air, noct):
461
572
  r'''
462
573
  Calculate cell temperature using the Ross model.