From 3005fdcbf21130cc7012c9a3d817b7dcaf2ba11f Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 4 Sep 2020 10:50:34 -0600 Subject: [PATCH 1/6] add Ross temperature model --- docs/sphinx/source/api.rst | 1 + docs/sphinx/source/whatsnew/v0.8.0.rst | 2 + pvlib/temp_calc_snlinverter_efficiency.py | 69 +++++++++++++++++++++++ pvlib/temperature.py | 51 ++++++++++++++++- pvlib/tests/test_temperature.py | 8 +++ 5 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 pvlib/temp_calc_snlinverter_efficiency.py diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index 5ccc5d4062..9720cecd64 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -238,6 +238,7 @@ PV temperature models temperature.pvsyst_cell temperature.faiman temperature.fuentes + temperature.ross Temperature Model Parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index e19ddb71f9..d644d87605 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -96,6 +96,8 @@ Enhancements * Add :py:func:`pvlib.pvsystem.combine_loss_factors` as general purpose function to combine loss factors with a common index. Partialy addresses :issue:`988`. Contributed by Brock Taute :ghuser:`btaute` +* Added :py:func:`pvlib.temperature.ross` for cell temperature modeling using + only NOCT. (:pull:`XXXX`) Bug fixes ~~~~~~~~~ diff --git a/pvlib/temp_calc_snlinverter_efficiency.py b/pvlib/temp_calc_snlinverter_efficiency.py new file mode 100644 index 0000000000..134c264028 --- /dev/null +++ b/pvlib/temp_calc_snlinverter_efficiency.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +""" +Created on Wed Jun 3 12:53:11 2020 + +@author: cliff +""" + +import pandas as pd +import numpy as np +import itertools + +from scipy.optimize import minimize + +from pvlib.pvsystem import snlinverter + +params = {'Paco': 1000., 'Pdco': 1050., 'Vdco': 240., 'Pso': 10., 'C0': 1e-6, + 'C1': 1e-4, 'C2': 1e-2, 'C3': 1e-3, 'Pnt': 1} + +power_levels = [0.1, 0.2, 0.3, 0.5, 0.75, 1.0] +v_levels = {'Vmin': 220., 'Vnom': 240., 'Vmax': 260.} + +num = len(power_levels) * len(v_levels) +res = pd.DataFrame(index=range(num), columns=['fraction_of_rated_power', + 'efficiency', 'dc_voltage_level', 'pdc', 'pac']) + + +def obj(pdc, pac, vdc, inverter): + Paco = inverter['Paco'] + Pdco = inverter['Pdco'] + Vdco = inverter['Vdco'] + Pso = inverter['Pso'] + C0 = inverter['C0'] + C1 = inverter['C1'] + C2 = inverter['C2'] + C3 = inverter['C3'] + + A = Pdco * (1 + C1*(vdc - Vdco)) + B = Pso * (1 + C2*(vdc - Vdco)) + C = C0 * (1 + C3*(vdc - Vdco)) + + ac_power = (Paco/(A-B) - C*(A-B)) * (pdc-B) + C*((pdc-B)**2) + + return (pac - ac_power)**2. + + +for idx, pair in enumerate(itertools.product(power_levels, v_levels.keys())): + plev, vlev = pair + p_ac = plev * params['Paco'] + opt = minimize(obj, plev*params['Pdco'], + args=(p_ac, v_levels[vlev], params)) + p_dc = opt.x[0] +# p_dc = plev * params['Pdco'] +# v_input = v_levels[vlev] +# p_ac = snlinverter(v_input, p_dc, params) + res['fraction_of_rated_power'][idx] = plev + res['dc_voltage_level'][idx] = vlev + res['efficiency'][idx] = p_ac / p_dc + res['pac'][idx] = p_ac + res['pdc'][idx] = p_dc + +#with open('inverter_fit_snl_datasheet.csv', 'w') as outfile: +# res.to_csv(outfile, index=False, line_terminator='\n') + +def _calc_c0(curves, p_ac0, p_dc0, p_s0): + x = curves['pdc'] - p_s0 + return (curves['pac'] - x / (p_dc0 - p_s0) * p_ac0) / (x**2. - x * (p_dc0 - p_s0)) + +c_M = params['C0'] * (1. + params['C3'] * (v_levels['Vmax'] - v_levels['Vnom'])) +c_m = params['C0'] * (1. + params['C3'] * (v_levels['Vmin'] - v_levels['Vnom'])) diff --git a/pvlib/temperature.py b/pvlib/temperature.py index 1d98736b4f..06cee0f452 100644 --- a/pvlib/temperature.py +++ b/pvlib/temperature.py @@ -377,9 +377,10 @@ def pvsyst_cell(poa_global, temp_air, wind_speed=1.0, u_c=29.0, u_v=0.0, def faiman(poa_global, temp_air, wind_speed=1.0, u0=25.0, u1=6.84): r''' - Calculate cell or module temperature using the Faiman model. The Faiman - model uses an empirical heat loss factor model [1]_ and is adopted in the - IEC 61853 standards [2]_ and [3]_. + Calculate cell or module temperature using the Faiman model. + + The Faiman model uses an empirical heat loss factor model [1]_ and is + adopted in the IEC 61853 standards [2]_ and [3]_. Usage of this model in the IEC 61853 standard does not distinguish between cell and module temperature. @@ -443,6 +444,50 @@ def faiman(poa_global, temp_air, wind_speed=1.0, u0=25.0, u1=6.84): return temp_air + temp_difference +def ross(poa_global, temp_air, noct): + r''' + Calculate cell temperature using the Ross model. + + The Ross model [1]_ assumes that cell temperature is proportional to the + plane of array irradiance, and ignores the effects of wind. + + Parameters + ---------- + poa_global : numeric + Total incident irradiance [W/m^2]. + + temp_air : numeric + Ambient dry bulb temperature [C]. + + noct : numeric + Nominal operating cell temperature, determiend at conditions of + 800 W/m^2 irradiance, 20C ambient air temperature and 1 m/s wind. + + Returns + ------- + numeric, values in degrees Celsius + + Notes + ----- + The Ross model for cell temperature :math:`T_{C}` is given in [1]_ as + + .. math:: + :label: pvsyst + + T_{C} = T_{a} + \frac{NOCT - 20}{80} S + + where :math:`S` is the plane of array irradiance in mW/{cm}^2. + + References + ---------- + .. [1] Ross, R. G. Jr., (1981). "Design Techniques for Flat-Plate + Photovoltaic Arrays". 15th IEEE Photovoltaic Specialist Conference, + Orlando, FL. + ''' + # factor of 0.1 converts irradiance from W/m2 to mW/cm2 + return temp_air + (noct - 20.) / 80. * poa_global * 0.1 + + def _fuentes_hconv(tave, windmod, tinoct, temp_delta, xlen, tilt, check_reynold): # Calculate the convective coefficient as in Fuentes 1987 -- a mixture of diff --git a/pvlib/tests/test_temperature.py b/pvlib/tests/test_temperature.py index 245c5d2807..f3c3fa9fa1 100644 --- a/pvlib/tests/test_temperature.py +++ b/pvlib/tests/test_temperature.py @@ -124,6 +124,14 @@ def test_faiman_ndarray(): assert_allclose(expected, result, 3) +def test_ross(): + result = temperature.ross(np.array([1000., 600., 1000.]), + np.array([20., 40., 60.]), + np.array([40., 100., 20.])) + expected = np.array([45., 100., 60.]) + assert_allclose(expected, result) + + def test_faiman_series(): times = pd.date_range(start="2015-01-01", end="2015-01-02", freq="12H") temps = pd.Series([0, 10, 5], index=times) From 4e776450a581855f023b58fdb3c20a6c35e3bef7 Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 4 Sep 2020 10:54:21 -0600 Subject: [PATCH 2/6] remove file added by mistake --- pvlib/temp_calc_snlinverter_efficiency.py | 69 ----------------------- 1 file changed, 69 deletions(-) delete mode 100644 pvlib/temp_calc_snlinverter_efficiency.py diff --git a/pvlib/temp_calc_snlinverter_efficiency.py b/pvlib/temp_calc_snlinverter_efficiency.py deleted file mode 100644 index 134c264028..0000000000 --- a/pvlib/temp_calc_snlinverter_efficiency.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Wed Jun 3 12:53:11 2020 - -@author: cliff -""" - -import pandas as pd -import numpy as np -import itertools - -from scipy.optimize import minimize - -from pvlib.pvsystem import snlinverter - -params = {'Paco': 1000., 'Pdco': 1050., 'Vdco': 240., 'Pso': 10., 'C0': 1e-6, - 'C1': 1e-4, 'C2': 1e-2, 'C3': 1e-3, 'Pnt': 1} - -power_levels = [0.1, 0.2, 0.3, 0.5, 0.75, 1.0] -v_levels = {'Vmin': 220., 'Vnom': 240., 'Vmax': 260.} - -num = len(power_levels) * len(v_levels) -res = pd.DataFrame(index=range(num), columns=['fraction_of_rated_power', - 'efficiency', 'dc_voltage_level', 'pdc', 'pac']) - - -def obj(pdc, pac, vdc, inverter): - Paco = inverter['Paco'] - Pdco = inverter['Pdco'] - Vdco = inverter['Vdco'] - Pso = inverter['Pso'] - C0 = inverter['C0'] - C1 = inverter['C1'] - C2 = inverter['C2'] - C3 = inverter['C3'] - - A = Pdco * (1 + C1*(vdc - Vdco)) - B = Pso * (1 + C2*(vdc - Vdco)) - C = C0 * (1 + C3*(vdc - Vdco)) - - ac_power = (Paco/(A-B) - C*(A-B)) * (pdc-B) + C*((pdc-B)**2) - - return (pac - ac_power)**2. - - -for idx, pair in enumerate(itertools.product(power_levels, v_levels.keys())): - plev, vlev = pair - p_ac = plev * params['Paco'] - opt = minimize(obj, plev*params['Pdco'], - args=(p_ac, v_levels[vlev], params)) - p_dc = opt.x[0] -# p_dc = plev * params['Pdco'] -# v_input = v_levels[vlev] -# p_ac = snlinverter(v_input, p_dc, params) - res['fraction_of_rated_power'][idx] = plev - res['dc_voltage_level'][idx] = vlev - res['efficiency'][idx] = p_ac / p_dc - res['pac'][idx] = p_ac - res['pdc'][idx] = p_dc - -#with open('inverter_fit_snl_datasheet.csv', 'w') as outfile: -# res.to_csv(outfile, index=False, line_terminator='\n') - -def _calc_c0(curves, p_ac0, p_dc0, p_s0): - x = curves['pdc'] - p_s0 - return (curves['pac'] - x / (p_dc0 - p_s0) * p_ac0) / (x**2. - x * (p_dc0 - p_s0)) - -c_M = params['C0'] * (1. + params['C3'] * (v_levels['Vmax'] - v_levels['Vnom'])) -c_m = params['C0'] * (1. + params['C3'] * (v_levels['Vmin'] - v_levels['Vnom'])) From 9354ad317d9c10e355903faf1dfc51dce6f4763d Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Fri, 4 Sep 2020 10:54:47 -0600 Subject: [PATCH 3/6] add PR number --- docs/sphinx/source/whatsnew/v0.8.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/whatsnew/v0.8.0.rst b/docs/sphinx/source/whatsnew/v0.8.0.rst index d644d87605..2e6fa67075 100644 --- a/docs/sphinx/source/whatsnew/v0.8.0.rst +++ b/docs/sphinx/source/whatsnew/v0.8.0.rst @@ -97,7 +97,7 @@ Enhancements function to combine loss factors with a common index. Partialy addresses :issue:`988`. Contributed by Brock Taute :ghuser:`btaute` * Added :py:func:`pvlib.temperature.ross` for cell temperature modeling using - only NOCT. (:pull:`XXXX`) + only NOCT. (:pull:`1045`) Bug fixes ~~~~~~~~~ From 00fa329d15e79948b3f2f9c70ec944c7a555865c Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 21 Sep 2020 09:11:27 -0600 Subject: [PATCH 4/6] review --- pvlib/temperature.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pvlib/temperature.py b/pvlib/temperature.py index 06cee0f452..68660b86cb 100644 --- a/pvlib/temperature.py +++ b/pvlib/temperature.py @@ -448,8 +448,9 @@ def ross(poa_global, temp_air, noct): r''' Calculate cell temperature using the Ross model. - The Ross model [1]_ assumes that cell temperature is proportional to the - plane of array irradiance, and ignores the effects of wind. + The Ross model [1]_ assumes that difference betwen cell temperature + and ambient temperature is proportional to the plane of array irradiance, + and ignores the effects of wind. Parameters ---------- @@ -460,8 +461,8 @@ def ross(poa_global, temp_air, noct): Ambient dry bulb temperature [C]. noct : numeric - Nominal operating cell temperature, determiend at conditions of - 800 W/m^2 irradiance, 20C ambient air temperature and 1 m/s wind. + Nominal operating cell temperature, determined at conditions of + 800 W/m^2 irradiance, 20C ambient air temperature and 1 m/s wind. [C] Returns ------- @@ -472,11 +473,10 @@ def ross(poa_global, temp_air, noct): The Ross model for cell temperature :math:`T_{C}` is given in [1]_ as .. math:: - :label: pvsyst T_{C} = T_{a} + \frac{NOCT - 20}{80} S - where :math:`S` is the plane of array irradiance in mW/{cm}^2. + where :math:`S` is the plane of array irradiance in :math:`mW/{cm}^2`. References ---------- From 8bf2613fc8722aaf9171858cb269861a8d40cabb Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Wed, 23 Sep 2020 10:43:18 -0600 Subject: [PATCH 5/6] review --- docs/sphinx/source/api.rst | 3 +++ docs/sphinx/source/whatsnew/v0.8.1.rst | 2 ++ pvlib/temperature.py | 17 ++++++++++------- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst index 4e9b4d8ad2..2e882e9a46 100644 --- a/docs/sphinx/source/api.rst +++ b/docs/sphinx/source/api.rst @@ -237,6 +237,9 @@ PV temperature models temperature.faiman temperature.fuentes temperature.ross + pvsystem.PVSystem.sapm_celltemp + pvsystem.PVSystem.pvsyst_celltemp + pvsystem.PVSystem.faiman_celltemp Temperature Model Parameters ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/sphinx/source/whatsnew/v0.8.1.rst b/docs/sphinx/source/whatsnew/v0.8.1.rst index 4597800da3..b6590283f2 100644 --- a/docs/sphinx/source/whatsnew/v0.8.1.rst +++ b/docs/sphinx/source/whatsnew/v0.8.1.rst @@ -37,3 +37,5 @@ Requirements Contributors ~~~~~~~~~~~~ * Kevin Anderson (:ghuser:`kanderso-nrel`) +* Will Holmgren (:ghuser:`wholmgren`) +* Cliff Hansen (:ghuser:`cwhanse`) diff --git a/pvlib/temperature.py b/pvlib/temperature.py index 68660b86cb..b1966faea9 100644 --- a/pvlib/temperature.py +++ b/pvlib/temperature.py @@ -448,25 +448,27 @@ def ross(poa_global, temp_air, noct): r''' Calculate cell temperature using the Ross model. - The Ross model [1]_ assumes that difference betwen cell temperature + The Ross model [1]_ assumes the difference between cell temperature and ambient temperature is proportional to the plane of array irradiance, - and ignores the effects of wind. + and ignores the effects of wind. The model implicitly assumes steady or + slowly changing irradiance conditions. Parameters ---------- poa_global : numeric - Total incident irradiance [W/m^2]. + Total incident irradiance. [W/m^2] temp_air : numeric - Ambient dry bulb temperature [C]. + Ambient dry bulb temperature. [C] noct : numeric - Nominal operating cell temperature, determined at conditions of - 800 W/m^2 irradiance, 20C ambient air temperature and 1 m/s wind. [C] + Nominal operating cell temperature [C], determined at conditions of + 800 W/m^2 irradiance, 20 C ambient air temperature and 1 m/s wind. Returns ------- - numeric, values in degrees Celsius + cell_temperature : numeric + Cell temperature. [C] Notes ----- @@ -477,6 +479,7 @@ def ross(poa_global, temp_air, noct): T_{C} = T_{a} + \frac{NOCT - 20}{80} S where :math:`S` is the plane of array irradiance in :math:`mW/{cm}^2`. + This function expects irradiance in :math:`W/m^2`. References ---------- From 0f1e460efaff495551e9d1a7c077de319e2c044f Mon Sep 17 00:00:00 2001 From: Cliff Hansen Date: Mon, 5 Oct 2020 13:11:14 -0600 Subject: [PATCH 6/6] change docstring to say 1 m/s --- pvlib/temperature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/temperature.py b/pvlib/temperature.py index b1966faea9..e1c4cad7cf 100644 --- a/pvlib/temperature.py +++ b/pvlib/temperature.py @@ -450,7 +450,7 @@ def ross(poa_global, temp_air, noct): The Ross model [1]_ assumes the difference between cell temperature and ambient temperature is proportional to the plane of array irradiance, - and ignores the effects of wind. The model implicitly assumes steady or + and assumes wind speed of 1 m/s. The model implicitly assumes steady or slowly changing irradiance conditions. Parameters