Skip to content

Commit 73b828d

Browse files
ramaroesilvacwhansekandersolarRDaxini
authored
Add k parameter to temperature.ross (#2521)
* Adds k parameter to temperature.ross * Updates whatsnew file for v13.1 * Corrects minor typos. * Corrects doi formatting. * Improve docstring and initial test messages. * Adds tests for temperature.ross * Changes variables in test from int to float. * Addresses flake8 issues. * Fixes flake8 issue. * Covers errors in testing temperature.ross * Improves documentation on temperature.ross * Corrects minor typo. * Apply suggestions from code review Co-authored-by: RDaxini <143435106+RDaxini@users.noreply.github.com> * a few tweaks * Update pvlib/temperature.py --------- Co-authored-by: Cliff Hansen <cwhanse@sandia.gov> Co-authored-by: Kevin Anderson <kevin.anderso@gmail.com> Co-authored-by: RDaxini <143435106+RDaxini@users.noreply.github.com>
1 parent 2aa17b4 commit 73b828d

File tree

3 files changed

+100
-15
lines changed

3 files changed

+100
-15
lines changed

docs/sphinx/source/whatsnew/v0.13.1.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ Bug fixes
2020

2121
Enhancements
2222
~~~~~~~~~~~~
23+
* Add k coefficient in :py:func:`~pvlib.temperature.ross`
24+
(:issue:`2506`, :pull:`2521`)
2325
* Add iotools functions to retrieve irradiance and weather data from Meteonorm:
2426
:py:func:`~pvlib.iotools.get_meteonorm_forecast_basic`, :py:func:`~pvlib.iotools.get_meteonorm_forecast_precision`,
2527
:py:func:`~pvlib.iotools.get_meteonorm_observation_realtime`, :py:func:`~pvlib.iotools.get_meteonorm_observation_training`,
@@ -65,5 +67,6 @@ Contributors
6567
* Ioannis Sifnaios (:ghuser:`IoannisSifnaios`)
6668
* Rajiv Daxini (:ghuser:`RDaxini`)
6769
* Omar Bahamida (:ghuser:`OmarBahamida`)
70+
* Rodrigo Amaro e Silva (:ghuser:`ramaroesilva`)
6871
* Kevin Anderson (:ghuser:`kandersolar`)
6972
* Mikaella Brewer (:ghuser:`brwerx`)

pvlib/temperature.py

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ def faiman_rad(poa_global, temp_air, wind_speed=1.0, ir_down=None,
618618
return temp_air + temp_difference
619619

620620

621-
def ross(poa_global, temp_air, noct):
621+
def ross(poa_global, temp_air, noct=None, k=None):
622622
r'''
623623
Calculate cell temperature using the Ross model.
624624
@@ -630,14 +630,19 @@ def ross(poa_global, temp_air, noct):
630630
Parameters
631631
----------
632632
poa_global : numeric
633-
Total incident irradiance. [W/m^2]
633+
Total incident irradiance. [W/m⁻²]
634634
635635
temp_air : numeric
636636
Ambient dry bulb temperature. [C]
637637
638-
noct : numeric
638+
noct : numeric, optional
639639
Nominal operating cell temperature [C], determined at conditions of
640-
800 W/m^2 irradiance, 20 C ambient air temperature and 1 m/s wind.
640+
800 W/m⁻² irradiance, 20 C ambient air temperature and 1 m/s wind.
641+
If ``noct`` is not provided, ``k`` is required.
642+
k: numeric, optional
643+
Ross coefficient [Km²W⁻¹], which is an alternative to employing
644+
NOCT in Ross's equation. If ``k`` is not provided, ``noct`` is
645+
required.
641646
642647
Returns
643648
-------
@@ -650,19 +655,62 @@ def ross(poa_global, temp_air, noct):
650655
651656
.. math::
652657
653-
T_{C} = T_{a} + \frac{NOCT - 20}{80} S
654-
655-
where :math:`S` is the plane of array irradiance in :math:`mW/{cm}^2`.
656-
This function expects irradiance in :math:`W/m^2`.
658+
T_{C} = T_{a} + \frac{NOCT - 20}{80} S = T_{a} + k × S
659+
660+
where :math:`S` is the plane of array irradiance in mWcm⁻².
661+
This function expects irradiance in Wm⁻².
662+
663+
Representative values for k are provided in [2]_, covering different types
664+
of mounting and degrees of back ventialtion. The naming designations,
665+
however, are adapted from [3]_ to enhance clarity and usability.
666+
667+
+--------------------------------------+-----------+
668+
| Mounting | :math:`k` |
669+
+======================================+===========+
670+
| Sloped roof, well ventilated | 0.02 |
671+
+--------------------------------------+-----------+
672+
| Free-standing system | 0.0208 |
673+
+--------------------------------------+-----------+
674+
| Flat roof, well ventilated | 0.026 |
675+
+--------------------------------------+-----------+
676+
| Sloped roof, poorly ventilated | 0.0342 |
677+
+--------------------------------------+-----------+
678+
| Facade integrated, semi-ventilated | 0.0455 |
679+
+--------------------------------------+-----------+
680+
| Facade integrated, poorly ventilated | 0.0538 |
681+
+--------------------------------------+-----------+
682+
| Sloped roof, non-ventilated | 0.0563 |
683+
+--------------------------------------+-----------+
684+
685+
It is also worth noting that the semi-ventilated facade case refers to
686+
partly transparent compound glass insulation modules, while the non-
687+
ventilated case corresponds to opaque, insulated PV-cladding elements.
688+
However, the emphasis in [3]_ appears to be on ventilation conditions
689+
rather than module construction.
657690
658691
References
659692
----------
660693
.. [1] Ross, R. G. Jr., (1981). "Design Techniques for Flat-Plate
661694
Photovoltaic Arrays". 15th IEEE Photovoltaic Specialist Conference,
662695
Orlando, FL.
696+
.. [2] E. Skoplaki and J. A. Palyvos, "Operating temperature of
697+
photovoltaic modules: A survey of pertinent correlations," Renewable
698+
Energy, vol. 34, no. 1, pp. 23–29, Jan. 2009,
699+
:doi:`10.1016/j.renene.2008.04.009`
700+
.. [3] T. Nordmann and L. Clavadetscher, "Understanding temperature
701+
effects on PV system performance," Proceedings of 3rd World Conference
702+
on Photovoltaic Energy Conversion, May 2003.
663703
'''
664-
# factor of 0.1 converts irradiance from W/m2 to mW/cm2
665-
return temp_air + (noct - 20.) / 80. * poa_global * 0.1
704+
if (noct is None) & (k is None):
705+
raise ValueError("Either noct or k is required.")
706+
elif (noct is not None) & (k is not None):
707+
raise ValueError("Provide only one of noct or k, not both.")
708+
elif k is None:
709+
# factor of 0.1 converts irradiance from W/m2 to mW/cm2
710+
return temp_air + (noct - 20.) / 80. * poa_global * 0.1
711+
elif noct is None:
712+
# k assumes irradiance in W.m-2, dismissing 0.1 factor
713+
return temp_air + k * poa_global
666714

667715

668716
def _fuentes_hconv(tave, windmod, tinoct, temp_delta, xlen, tilt,

tests/test_temperature.py

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,45 @@ def test_faiman_rad_ir():
152152

153153

154154
def test_ross():
155-
result = temperature.ross(np.array([1000., 600., 1000.]),
156-
np.array([20., 40., 60.]),
157-
np.array([40., 100., 20.]))
158-
expected = np.array([45., 100., 60.])
159-
assert_allclose(expected, result)
155+
# single values
156+
result1 = temperature.ross(1000., 30., noct=50)
157+
result2 = temperature.ross(1000., 30., k=0.0375)
158+
159+
expected = 67.5
160+
assert_allclose(expected, result1)
161+
assert_allclose(expected, result2)
162+
163+
# pd.Series
164+
times = pd.date_range('2025-07-30 14:00', '2025-07-30 16:00', freq='h')
165+
166+
df = pd.DataFrame({'t_air': np.array([20., 30., 40.]),
167+
'ghi': np.array([800., 700., 600.])},
168+
index=times)
169+
170+
result1 = temperature.ross(df['ghi'], df['t_air'], noct=50.)
171+
result2 = temperature.ross(df['ghi'], df['t_air'], k=0.0375)
172+
173+
expected = pd.Series([50., 56.25, 62.5], index=times)
174+
assert_allclose(expected, result1)
175+
assert_allclose(expected, result2)
176+
177+
# np.array
178+
ghi_array = df['ghi'].values
179+
t_air_array = df['t_air'].values
180+
181+
result1 = temperature.ross(ghi_array, t_air_array, noct=50.)
182+
result2 = temperature.ross(ghi_array, t_air_array, k=0.0375)
183+
184+
expected = expected.values
185+
assert_allclose(expected, result1)
186+
assert_allclose(expected, result2)
187+
188+
189+
def test_ross_errors():
190+
with pytest.raises(ValueError, match='Either noct or k is required'):
191+
temperature.ross(1000., 30.)
192+
with pytest.raises(ValueError, match='Provide only one of noct or k'):
193+
temperature.ross(1000., 30., noct=45., k=0.02)
160194

161195

162196
def test_faiman_series():

0 commit comments

Comments
 (0)