From 8a0328b673cae71e2b01d474c317c817cabeef99 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Sun, 27 Nov 2022 22:17:29 +0100 Subject: [PATCH 01/16] Add ADR model and fitting function. --- pvlib/pvefficiency.py | 214 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 pvlib/pvefficiency.py diff --git a/pvlib/pvefficiency.py b/pvlib/pvefficiency.py new file mode 100644 index 0000000000..50f7c6e56c --- /dev/null +++ b/pvlib/pvefficiency.py @@ -0,0 +1,214 @@ +""" +This module contains implementations of PV module efficiency models. + +These models have a common purpose, which is to predict the efficiency at +maximum power point as a function of the main operating conditions: +effective irradiance and module temperature. +""" + +import numpy as np +from scipy.optimize import curve_fit +from scipy.special import exp10 + + +def adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): + ''' + Calculate PV module efficiency using the ADR model. + + The efficiency varies with irradiance and operating temperature + and is determined by 5 model parameters as described in [1]_. + + Parameters + ---------- + irradiance : numeric, non-negative + The effective irradiance incident on the PV module. [W/m²] + + temperature : numeric + The PV module operating temperature. [°C] + + k_a : numeric + Absolute scaling factor, which is equal to the efficiency at + reference conditions. This factor allows the model to be used + with relative or absolute efficiencies, and to accommodate data sets + which are not perfectly normalized but have a slight bias at + the reference conditions. [unitless|%] + + k_d : numeric, negative + “Dark irradiance” or diode coefficient which influences the voltage + increase with irradiance. [unitless] + + tc_d : numeric + Temperature coefficient of the diode coefficient, which indirectly + influences voltage. Because it is the only temperature coefficient + in the model, its value will also reflect secondary temperature + dependencies that are present in the PV module. [unitless] + + k_rs and k_rsh : numeric + Series and shunt resistance loss factors. Because of the normalization + they can be read as power loss fractions at reference conditions. + For example, if k_rs is 0.05, the internal loss assigned to the + series resistance has a magnitude equal to 5% of the module output. + [unitless] + + Returns + ------- + eta : numeric + The efficiency of the module at the specified irradiance and + temperature. + + Notes + ----- + The efficiency values may be absolute or relative, and may be expressed + as percent or per unit. This is determined by the efficiency data + used to derive values for the 5 model parameters. The first model + parameter k_a is equal to the efficiency at STC and therefore + indicates the efficiency scale being used. k_a can also be changed + freely to adjust the scale, or to change the module class to a slightly + higher or lower efficiency. + + All arguments may be scalars or array-like. If multiple arguments + are array-like they must be the same shape or broadcastable to the + same shape. + + See also + -------- + pvlib.pvefficiency.fit_pvefficiency_adr + + References + ---------- + .. [1] A. Driesse and J. S. Stein, "From IEC 61853 power measurements + to PV system simulations", Sandia Report No. SAND2020-3877, 2020. + + .. [2] A. Driesse, M. Theristis and J. S. Stein, "A New Photovoltaic Module + Efficiency Model for Energy Prediction and Rating," in IEEE Journal + of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021, + doi: 10.1109/JPHOTOV.2020.3045677. + + Examples + -------- + >>> adr([1000, 200], 25, + k_a=100, k_d=-6.0, tc_d=0.02, k_rs=0.05, k_rsh=0.10) + array([100. , 92.79729308]) + + >>> adr([1000, 200], 25, + k_a=1.0, k_d=-6.0, tc_d=0.02, k_rs=0.05, k_rsh=0.10) + array([1. , 0.92797293]) + + + Adapted from https://github.com/adriesse/pvpltools-python + Copyright (c) 2022, Anton Driesse, PV Performance Labs + All rights reserved. + ''' + k_a = np.array(k_a) + k_d = np.array(k_d) + tc_d = np.array(tc_d) + k_rs = np.array(k_rs) + k_rsh = np.array(k_rsh) + + # normalize the irradiance + G_REF = np.array(1000.) + s = irradiance / G_REF + + # obtain the difference from reference temperature + T_REF = np.array(25.) + dt = temperature - T_REF + + # equation 29 in JPV + s_o = exp10(k_d + (dt * tc_d)) # noQA: E221 + s_o_ref = exp10(k_d) + + # equation 28 and 30 in JPV + # the constant k_v does not appear here because it cancels out + v = np.log(s / s_o + 1) # noQA: E221 + v /= np.log(1 / s_o_ref + 1) + + # equation 25 in JPV + eta = k_a * ((1 + k_rs + k_rsh) * v - k_rs * s - k_rsh * v**2) + + return eta + + +def fit_pvefficiency_adr(irradiance, temperature, eta, dict_output=True, + **kwargs): + """ + Determine the parameters of the adr module efficiency model by non-linear + least-squares fit to lab or field measurements. + + Parameters + ---------- + irradiance : numeric, non-negative + Effective irradiance incident on the PV module. [W/m²] + + temperature : numeric + PV module operating temperature. [°C] + + eta : numeric + Efficiency of the PV module at the specified irradiance and + temperature(s). [unitless] or [%] + + dict_output : boolean, optional + When True (default), return the result as a dictionary; when False, + return the result as a numpy array. + + kwargs : + Optional keyword arguments passed to `scip.optimize.curve_fit`. + These kwargs can over-ride some options set within this function, + which could be interesting for very advanced users. + + Returns + ------- + popt : array or dict + Optimal values for the parameters. + + Notes + ----- + The best fits are obtained when the lab or field data include a wide range + of both irradiance and temperature values. A minimal data set + would consist of 6 operating points covering low, medium and high + irradiance levels at two operating temperatures. + + See also + -------- + pvlib.pvefficiency.adr + scipy.optimize.curve_fit + + Adapted from https://github.com/adriesse/pvpltools-python + Copyright (c) 2022, Anton Driesse, PV Performance Labs + All rights reserved. + """ + irradiance = np.asarray(irradiance, dtype=float).reshape(-1) + temperature = np.asarray(temperature, dtype=float).reshape(-1) + eta = np.asarray(eta, dtype=float).reshape(-1) + + eta_max = np.max(eta) + + P_NAMES = ['k_a', 'k_d', 'tc_d', 'k_rs', 'k_rsh'] + P_MAX = [+np.inf, 0, +0.1, 1, 1] # noQA: E221 + P_MIN = [0, -12, -0.1, 0, 0] # noQA: E221 + P0 = [eta_max, -6, 0.0, 0, 0] # noQA: E221 + P_SCALE = [eta_max, 10, 0.1, 1, 1] + + fit_options = dict(p0=P0, + bounds=[P_MIN, P_MAX], + method='trf', + x_scale=P_SCALE, + loss='soft_l1', + f_scale=eta_max * 0.05, + ) + + fit_options.update(kwargs) + + def adr_wrapper(xdata, *params): + return adr(*xdata, *params) + + result = curve_fit(adr_wrapper, + xdata=[irradiance, temperature], + ydata=eta, + **fit_options, + ) + popt = result[0] + + if dict_output: + return dict(zip(P_NAMES, popt)) + else: + return popt From 2cd81e15c80dc83d62fd53f060ab2ec62bfdc2d0 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Sun, 27 Nov 2022 22:22:07 +0100 Subject: [PATCH 02/16] Add tests. --- pvlib/tests/test_pvefficiency.py | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 pvlib/tests/test_pvefficiency.py diff --git a/pvlib/tests/test_pvefficiency.py b/pvlib/tests/test_pvefficiency.py new file mode 100644 index 0000000000..804ce092fa --- /dev/null +++ b/pvlib/tests/test_pvefficiency.py @@ -0,0 +1,41 @@ +from numpy.testing import assert_allclose + +from pvlib import pvefficiency + + +def test_adr(): + g = [1000, 200, 1000, 200, 1000, 200] + t = [25, 25, 50, 50, 75, 75] + p = [1.0, -6.684898, 0.018855, 0.069917, 0.054369] + + e = [1.0, 0.949154, 0.92812, 0.876472, 0.855699, 0.80325] + + result = pvefficiency.adr(g, t, *p) + assert_allclose(result, e, rtol=1e-5) + + +def test_fit_pvefficiency_adr(): + g = [1000, 200, 1000, 200, 1000, 200] + t = [25, 25, 50, 50, 75, 75] + e = [1.0, 0.949154, 0.92812, 0.876472, 0.855699, 0.80325] + + p = [1.0, -6.684898, 0.018855, 0.069917, 0.054369] + + result = pvefficiency.fit_pvefficiency_adr(g, t, e, dict_output=False) + # the fitted parameters vary somewhat by platform during the testing + # so the tolerance is higher on the parameters than on the efficiencies + # in the other tests + assert_allclose(result, p, rtol=1e-3) + + result = pvefficiency.fit_pvefficiency_adr(g, t, e, dict_output=True) + assert 'k_a' in result + + +def test_adr_round_trip(): + g = [1000, 200, 1000, 200, 1000, 200] + t = [25, 25, 50, 50, 75, 75] + e = [1.0, 0.949154, 0.92812, 0.876472, 0.855699, 0.80325] + + p = pvefficiency.fit_pvefficiency_adr(g, t, e, dict_output=False) + result = pvefficiency.adr(g, t, *p) + assert_allclose(result, e, rtol=1e-5) From 111186a291601e8f53ca9eddd209a3ff5d536196 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Sun, 27 Nov 2022 22:23:23 +0100 Subject: [PATCH 03/16] Add examples. --- .../adr-pv-module-efficiency/README.rst | 3 + .../plot_fit_to_matrix.py | 110 +++++++++++++ .../plot_simulate_system.py | 152 ++++++++++++++++++ 3 files changed, 265 insertions(+) create mode 100644 docs/examples/adr-pv-module-efficiency/README.rst create mode 100644 docs/examples/adr-pv-module-efficiency/plot_fit_to_matrix.py create mode 100644 docs/examples/adr-pv-module-efficiency/plot_simulate_system.py diff --git a/docs/examples/adr-pv-module-efficiency/README.rst b/docs/examples/adr-pv-module-efficiency/README.rst new file mode 100644 index 0000000000..0db64aa046 --- /dev/null +++ b/docs/examples/adr-pv-module-efficiency/README.rst @@ -0,0 +1,3 @@ +ADR Model for PV Module Efficiency +---------------------------------- + diff --git a/docs/examples/adr-pv-module-efficiency/plot_fit_to_matrix.py b/docs/examples/adr-pv-module-efficiency/plot_fit_to_matrix.py new file mode 100644 index 0000000000..e692d2300d --- /dev/null +++ b/docs/examples/adr-pv-module-efficiency/plot_fit_to_matrix.py @@ -0,0 +1,110 @@ +""" +Obtaining ADR model parameters from IEC 61853 matrix measurements +================================================================= + +There's a fitting function provided in pvlib to do exactly that. + +(WORK IN PROGRESS) + +Since PV module efficiency varies with irradiance and temperature +what better way to train a model than using efficiency measurement +over a broad range of temperature and irradiance levels? +The standard IEC 61853-1 defines a standard matrix of conditions +for such measurements and this example shows how the ADR model +parameters can be determined with just a few lines of code using +functions in pvlib-python. + +""" + +from io import StringIO +import pandas as pd +import matplotlib.pyplot as plt + +from pvlib.pvefficiency import adr, fit_pvefficiency_adr + +# %% The text on this line is not displayed +# +# Here are some matrix measurements: +# + +iec61853data = ''' + irradiance temperature p_mp +0 100 15.0 30.159 +1 200 15.0 63.057 +2 400 15.0 129.849 +3 600 15.0 197.744 +4 800 15.0 264.825 +5 1000 15.0 330.862 +6 100 25.0 29.250 +7 200 25.0 61.137 +8 400 25.0 126.445 +9 600 25.0 192.278 +10 800 25.0 257.561 +11 1000 25.0 322.305 +12 1100 25.0 354.174 +13 100 50.0 26.854 +14 200 50.0 56.698 +15 400 50.0 117.062 +16 600 50.0 177.959 +17 800 50.0 238.626 +18 1000 50.0 298.954 +19 1100 50.0 328.413 +20 100 75.0 24.074 +21 200 75.0 51.103 +22 400 75.0 106.546 +23 600 75.0 162.966 +24 800 75.0 218.585 +25 1000 75.0 273.651 +26 1100 75.0 301.013 +''' +df = pd.read_csv(StringIO(iec61853data), delim_whitespace=True) + +# %% +# +# Now calculate the normalized or relative efficiency values +# and use the fitting function to determine the parameters. +# The parameters (shown below) can now be used to +# simulate the module operating in a PV system. +# + +P_REF = 322.305 # (W) STC value from the table above +G_REF = 1000. # (W/m2) + +df['eta_rel'] = (df['p_mp'] / P_REF) / (df['irradiance'] / G_REF) + +adr_params = fit_pvefficiency_adr(df['irradiance'], df['temperature'], + df['eta_rel']) + +for k, v in adr_params.items(): + print('%-5s = %7.4f' % (k, v)) + +# %% +# +# Compare the model output to the original measurements. +# The chart below shows minor differences but due to their random nature +# they are most likely evidence of the limitations of measurement accuracy. +# + +eta_rel_adr = adr(df['irradiance'], df['temperature'], **adr_params) + +plt.figure() +plt.plot(df['irradiance'], df['eta_rel'], 'oc', ms=8) +plt.plot(df['irradiance'], eta_rel_adr, '.k') +plt.legend(['Lab measurements', 'ADR model fit']) +plt.xlabel('Irradiance [W/m²]') +plt.ylabel('Relative efficiency [-]') +plt.grid(alpha=0.5) +plt.show() + +# %% +# +# References +# ---------- +# .. [1] A. Driesse and J. S. Stein, "From IEC 61853 power measurements +# to PV system simulations", Sandia Report No. SAND2020-3877, 2020. +# +# .. [2] A. Driesse, M. Theristis and J. S. Stein, "A New Photovoltaic Module +# Efficiency Model for Energy Prediction and Rating," in IEEE Journal +# of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021, +# doi: 10.1109/JPHOTOV.2020.3045677. +# diff --git a/docs/examples/adr-pv-module-efficiency/plot_simulate_system.py b/docs/examples/adr-pv-module-efficiency/plot_simulate_system.py new file mode 100644 index 0000000000..4273e6159f --- /dev/null +++ b/docs/examples/adr-pv-module-efficiency/plot_simulate_system.py @@ -0,0 +1,152 @@ +""" +Simulating PV systems using the ADR module efficiency model +=========================================================== + +Time series processing with the ADR model is fast and ... efficient! + +This example reads a TMY3 weather file, and runs a basic simulation +on a fixed latitude-tilt system. +Efficiency is independent of system size, so adjusting the system +capacity is just a matter of setting the desired value, e.g. P_STC = 5000. + +""" + +import os +import pandas as pd +import matplotlib.pyplot as plt + +import pvlib +from pvlib import iotools, location, pvefficiency +from pvlib.irradiance import aoi, get_total_irradiance + +# %% +# +# Read a TMY3 file containing weather data and select needed columns +# + +PVLIB_DIR = pvlib.__path__[0] +DATA_FILE = os.path.join(PVLIB_DIR, 'data', '723170TYA.CSV') + +tmy, metadata = iotools.read_tmy3(DATA_FILE, coerce_year=1990) + +df = pd.DataFrame({'ghi': tmy['GHI'], 'dhi': tmy['DHI'], + 'dni': tmy['DNI'], 'dni_extra': tmy['ETRN'], + 'temp_air': tmy['DryBulb'], 'wind_speed': tmy['Wspd'], + }) + +# %% +# +# Shift timestamps to middle of hour and then calculate sun positions +# + +df.index = df.index - pd.Timedelta(minutes=30) + +loc = location.Location.from_tmy(metadata) +solpos = loc.get_solarposition(df.index) + +# %% +# +# Determine total irradiance on a fixed-tilt array +# + +TILT = metadata['latitude'] +ORIENT = 180 + +df['aoi'] = aoi(TILT, ORIENT, solpos.apparent_zenith, solpos.azimuth) + +total_irrad = get_total_irradiance(TILT, ORIENT, + solpos.apparent_zenith, solpos.azimuth, + df.dni, df.ghi, df.dhi, df.dni_extra) + +df['poa_global'] = total_irrad.poa_global + +# %% +# +# Estimate the expected operating temperature of the PV modules +# + +df['temp_pv'] = pvlib.temperature.faiman(df.poa_global, df.temp_air, + df.wind_speed) + +# %% +# +# Now we're ready to calculate PV array DC output power based +# on POA irradiance and PV module operating temperature. +# Among the models available in pvlib-python to do this are: +# - PVWatts +# - SAPM +# - single-diode model variations +# - and now also the ADR PV efficiency model +# +# Simulation is done in two steps: +# - first calculate efficiency using the ADR model, +# - then convert (scale up) efficiency to power. +# + +# Borrow the ADR model parameters from the other example: + +adr_params = {'k_a': 0.99879, + 'k_d': -5.85188, + 'tc_d': 0.01939, + 'k_rs': 0.06962, + 'k_rsh': 0.21036 + } + +df['eta_rel'] = pvefficiency.adr(df['poa_global'], df['temp_pv'], **adr_params) + +# Set the desired array size: +P_STC = 5000. # (W) +# and the irradiance level needed to achieve this output ( +G_STC = 1000. # (W/m2) + +df['p_mp'] = P_STC * df['eta_rel'] * (df['poa_global'] / G_STC) + +# %% +# +# Show how power and efficiency vary with both irradiance and temperature +# + +plt.figure() +pc = plt.scatter(df['poa_global'], df['eta_rel'], c=df['temp_pv'], cmap='jet') +plt.colorbar(label='Temperature [C]', ax=plt.gca()) +pc.set_alpha(0.25) +plt.grid(alpha=0.5) +plt.ylim(0.48) +plt.xlabel('Irradiance [W/m²]') +plt.ylabel('Relative efficiency [-]') +plt.show() + +plt.figure() +pc = plt.scatter(df['poa_global'], df['p_mp'], c=df['temp_pv'], cmap='jet') +plt.colorbar(label='Temperature [C]', ax=plt.gca()) +pc.set_alpha(0.25) +plt.grid(alpha=0.5) +plt.xlabel('Irradiance [W/m²]') +plt.ylabel('Array power [W]') +plt.show() + +# %% +# +# One day: +# + +DEMO_DAY = '1990-08-05' + +plt.figure() +plt.plot(df['p_mp'][DEMO_DAY]) +plt.xticks(rotation=30) +plt.ylabel('Power [W]') +plt.show() + +# %% +# +# References +# ---------- +# .. [1] A. Driesse and J. S. Stein, "From IEC 61853 power measurements +# to PV system simulations", Sandia Report No. SAND2020-3877, 2020. +# +# .. [2] A. Driesse, M. Theristis and J. S. Stein, "A New Photovoltaic Module +# Efficiency Model for Energy Prediction and Rating," in IEEE Journal +# of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021, +# doi: 10.1109/JPHOTOV.2020.3045677. +# From 69079346ea31d04cac02f42a2147e5bf275b73ad Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Sun, 27 Nov 2022 22:25:11 +0100 Subject: [PATCH 04/16] Register API changes. --- docs/sphinx/source/reference/pv_modeling.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sphinx/source/reference/pv_modeling.rst b/docs/sphinx/source/reference/pv_modeling.rst index 31c380c1bb..918d237ff5 100644 --- a/docs/sphinx/source/reference/pv_modeling.rst +++ b/docs/sphinx/source/reference/pv_modeling.rst @@ -187,3 +187,5 @@ Other pvsystem.retrieve_sam pvsystem.scale_voltage_current_power + pvefficiency.adr + pvefficiency.fit_pvefficiency_adr From 9329d5641760554fa018c50a57841c94342dad99 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Sun, 27 Nov 2022 22:41:44 +0100 Subject: [PATCH 05/16] Fix bullet lists in example. --- .../plot_simulate_system.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/examples/adr-pv-module-efficiency/plot_simulate_system.py b/docs/examples/adr-pv-module-efficiency/plot_simulate_system.py index 4273e6159f..d636d0bfc4 100644 --- a/docs/examples/adr-pv-module-efficiency/plot_simulate_system.py +++ b/docs/examples/adr-pv-module-efficiency/plot_simulate_system.py @@ -73,14 +73,17 @@ # Now we're ready to calculate PV array DC output power based # on POA irradiance and PV module operating temperature. # Among the models available in pvlib-python to do this are: -# - PVWatts -# - SAPM -# - single-diode model variations -# - and now also the ADR PV efficiency model +# +# - PVWatts +# - SAPM +# - single-diode model variations +# +# And now also the ADR PV efficiency model # # Simulation is done in two steps: -# - first calculate efficiency using the ADR model, -# - then convert (scale up) efficiency to power. +# +# - first calculate efficiency using the ADR model, +# - then convert (scale up) efficiency to power. # # Borrow the ADR model parameters from the other example: From ebfcb74b94e3ee48394e60115e0189a7e43e1107 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Fri, 2 Dec 2022 12:02:35 +0100 Subject: [PATCH 06/16] Move new model to new module pvarray.py. --- .../README.rst | 0 .../plot_fit_to_matrix.py | 6 ++--- .../plot_simulate_system.py | 7 +++--- pvlib/{pvefficiency.py => pvarray.py} | 22 ++++++++++--------- .../{test_pvefficiency.py => test_pvarray.py} | 16 +++++++------- 5 files changed, 26 insertions(+), 25 deletions(-) rename docs/examples/{adr-pv-module-efficiency => adr-pvarray}/README.rst (100%) rename docs/examples/{adr-pv-module-efficiency => adr-pvarray}/plot_fit_to_matrix.py (95%) rename docs/examples/{adr-pv-module-efficiency => adr-pvarray}/plot_simulate_system.py (95%) rename pvlib/{pvefficiency.py => pvarray.py} (90%) rename pvlib/tests/{test_pvefficiency.py => test_pvarray.py} (70%) diff --git a/docs/examples/adr-pv-module-efficiency/README.rst b/docs/examples/adr-pvarray/README.rst similarity index 100% rename from docs/examples/adr-pv-module-efficiency/README.rst rename to docs/examples/adr-pvarray/README.rst diff --git a/docs/examples/adr-pv-module-efficiency/plot_fit_to_matrix.py b/docs/examples/adr-pvarray/plot_fit_to_matrix.py similarity index 95% rename from docs/examples/adr-pv-module-efficiency/plot_fit_to_matrix.py rename to docs/examples/adr-pvarray/plot_fit_to_matrix.py index e692d2300d..20b571caa5 100644 --- a/docs/examples/adr-pv-module-efficiency/plot_fit_to_matrix.py +++ b/docs/examples/adr-pvarray/plot_fit_to_matrix.py @@ -4,8 +4,6 @@ There's a fitting function provided in pvlib to do exactly that. -(WORK IN PROGRESS) - Since PV module efficiency varies with irradiance and temperature what better way to train a model than using efficiency measurement over a broad range of temperature and irradiance levels? @@ -20,7 +18,7 @@ import pandas as pd import matplotlib.pyplot as plt -from pvlib.pvefficiency import adr, fit_pvefficiency_adr +from pvlib.pvarray import pvefficiency_adr, fit_pvefficiency_adr # %% The text on this line is not displayed # @@ -85,7 +83,7 @@ # they are most likely evidence of the limitations of measurement accuracy. # -eta_rel_adr = adr(df['irradiance'], df['temperature'], **adr_params) +eta_rel_adr = pvefficiency_adr(df['irradiance'], df['temperature'], **adr_params) plt.figure() plt.plot(df['irradiance'], df['eta_rel'], 'oc', ms=8) diff --git a/docs/examples/adr-pv-module-efficiency/plot_simulate_system.py b/docs/examples/adr-pvarray/plot_simulate_system.py similarity index 95% rename from docs/examples/adr-pv-module-efficiency/plot_simulate_system.py rename to docs/examples/adr-pvarray/plot_simulate_system.py index d636d0bfc4..a269d6986a 100644 --- a/docs/examples/adr-pv-module-efficiency/plot_simulate_system.py +++ b/docs/examples/adr-pvarray/plot_simulate_system.py @@ -2,7 +2,7 @@ Simulating PV systems using the ADR module efficiency model =========================================================== -Time series processing with the ADR model is fast and ... efficient! +Time series processing with the ADR model is really easy. This example reads a TMY3 weather file, and runs a basic simulation on a fixed latitude-tilt system. @@ -16,8 +16,9 @@ import matplotlib.pyplot as plt import pvlib -from pvlib import iotools, location, pvefficiency +from pvlib import iotools, location from pvlib.irradiance import aoi, get_total_irradiance +from pvlib.pvarray import pvefficiency_adr # %% # @@ -95,7 +96,7 @@ 'k_rsh': 0.21036 } -df['eta_rel'] = pvefficiency.adr(df['poa_global'], df['temp_pv'], **adr_params) +df['eta_rel'] = pvefficiency_adr(df['poa_global'], df['temp_pv'], **adr_params) # Set the desired array size: P_STC = 5000. # (W) diff --git a/pvlib/pvefficiency.py b/pvlib/pvarray.py similarity index 90% rename from pvlib/pvefficiency.py rename to pvlib/pvarray.py index 50f7c6e56c..44b8e5e2f4 100644 --- a/pvlib/pvefficiency.py +++ b/pvlib/pvarray.py @@ -1,9 +1,11 @@ """ -This module contains implementations of PV module efficiency models. +This module contains implementations of PV module and array electrical models. -These models have a common purpose, which is to predict the efficiency at -maximum power point as a function of the main operating conditions: -effective irradiance and module temperature. +These models are used to predict the electrical behavior of pv modules +or collections of pv modules (arrays). The primary inputs are +effective irradiance and operating temperature and the outputs may range from +power or efficiency at the maximum power point to complete IV curves. +Supporting functions and parameter fitting functions may also be found here. """ import numpy as np @@ -11,7 +13,7 @@ from scipy.special import exp10 -def adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): +def pvefficiency_adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): ''' Calculate PV module efficiency using the ADR model. @@ -86,11 +88,11 @@ def adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): Examples -------- - >>> adr([1000, 200], 25, + >>> pvefficiency_adr([1000, 200], 25, k_a=100, k_d=-6.0, tc_d=0.02, k_rs=0.05, k_rsh=0.10) array([100. , 92.79729308]) - >>> adr([1000, 200], 25, + >>> pvefficiency_adr([1000, 200], 25, k_a=1.0, k_d=-6.0, tc_d=0.02, k_rs=0.05, k_rsh=0.10) array([1. , 0.92797293]) @@ -131,7 +133,7 @@ def adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): def fit_pvefficiency_adr(irradiance, temperature, eta, dict_output=True, **kwargs): """ - Determine the parameters of the adr module efficiency model by non-linear + Determine the parameters of the ADR module efficiency model by non-linear least-squares fit to lab or field measurements. Parameters @@ -169,7 +171,7 @@ def fit_pvefficiency_adr(irradiance, temperature, eta, dict_output=True, See also -------- - pvlib.pvefficiency.adr + pvlib.pvefficiency.pvefficiency_adr scipy.optimize.curve_fit Adapted from https://github.com/adriesse/pvpltools-python @@ -199,7 +201,7 @@ def fit_pvefficiency_adr(irradiance, temperature, eta, dict_output=True, fit_options.update(kwargs) def adr_wrapper(xdata, *params): - return adr(*xdata, *params) + return pvefficiency_adr(*xdata, *params) result = curve_fit(adr_wrapper, xdata=[irradiance, temperature], diff --git a/pvlib/tests/test_pvefficiency.py b/pvlib/tests/test_pvarray.py similarity index 70% rename from pvlib/tests/test_pvefficiency.py rename to pvlib/tests/test_pvarray.py index 804ce092fa..8d6ceb8427 100644 --- a/pvlib/tests/test_pvefficiency.py +++ b/pvlib/tests/test_pvarray.py @@ -1,16 +1,16 @@ from numpy.testing import assert_allclose -from pvlib import pvefficiency +from pvlib import pvarray -def test_adr(): +def test_pvefficiency_adr(): g = [1000, 200, 1000, 200, 1000, 200] t = [25, 25, 50, 50, 75, 75] p = [1.0, -6.684898, 0.018855, 0.069917, 0.054369] e = [1.0, 0.949154, 0.92812, 0.876472, 0.855699, 0.80325] - result = pvefficiency.adr(g, t, *p) + result = pvarray.pvefficiency_adr(g, t, *p) assert_allclose(result, e, rtol=1e-5) @@ -21,21 +21,21 @@ def test_fit_pvefficiency_adr(): p = [1.0, -6.684898, 0.018855, 0.069917, 0.054369] - result = pvefficiency.fit_pvefficiency_adr(g, t, e, dict_output=False) + result = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=False) # the fitted parameters vary somewhat by platform during the testing # so the tolerance is higher on the parameters than on the efficiencies # in the other tests assert_allclose(result, p, rtol=1e-3) - result = pvefficiency.fit_pvefficiency_adr(g, t, e, dict_output=True) + result = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=True) assert 'k_a' in result -def test_adr_round_trip(): +def test_pvefficiency_adr_round_trip(): g = [1000, 200, 1000, 200, 1000, 200] t = [25, 25, 50, 50, 75, 75] e = [1.0, 0.949154, 0.92812, 0.876472, 0.855699, 0.80325] - p = pvefficiency.fit_pvefficiency_adr(g, t, e, dict_output=False) - result = pvefficiency.adr(g, t, *p) + p = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=False) + result = pvarray.pvefficiency_adr(g, t, *p) assert_allclose(result, e, rtol=1e-5) From af60b151a9b9fa537241419a2db914edf5de4875 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Fri, 2 Dec 2022 17:54:18 +0100 Subject: [PATCH 07/16] Add another gallery example and tweak fitting function. --- .../adr-pvarray/plot_fit_to_matrix.py | 1 + .../adr-pvarray/plot_simulate_fast.py | 162 ++++++++++++++++++ .../adr-pvarray/plot_simulate_system.py | 1 + pvlib/pvarray.py | 3 + 4 files changed, 167 insertions(+) create mode 100644 docs/examples/adr-pvarray/plot_simulate_fast.py diff --git a/docs/examples/adr-pvarray/plot_fit_to_matrix.py b/docs/examples/adr-pvarray/plot_fit_to_matrix.py index 20b571caa5..9f115ec2cc 100644 --- a/docs/examples/adr-pvarray/plot_fit_to_matrix.py +++ b/docs/examples/adr-pvarray/plot_fit_to_matrix.py @@ -12,6 +12,7 @@ parameters can be determined with just a few lines of code using functions in pvlib-python. +Author: Anton Driesse """ from io import StringIO diff --git a/docs/examples/adr-pvarray/plot_simulate_fast.py b/docs/examples/adr-pvarray/plot_simulate_fast.py new file mode 100644 index 0000000000..4b5ae061a7 --- /dev/null +++ b/docs/examples/adr-pvarray/plot_simulate_fast.py @@ -0,0 +1,162 @@ +""" +Fast simulation using the ADR efficiency model with PVsyst parameters +===================================================================== + +Would you like to increase simulation speed by a factor of 4000+? + +Simulation using single-diode models can be slow because the maximum +power point is usually found by an iterative search. +In this example we use the PVsyst single diode model to generate +a matrix of efficiency values, then determine the ADR model +parameters to reproduce the behavior of the PVsyst model. +This way both PVsyst and ADR models can simulate the same PV module type. + +To compare simulation speed, we run them using ```timeit```. + +Author: Anton Driesse +""" + +import numpy as np +# import pandas as pd +import matplotlib.pyplot as plt + +from pvlib.pvsystem import calcparams_pvsyst, max_power_point +from pvlib.pvarray import pvefficiency_adr, fit_pvefficiency_adr + +# %% The text on this line is not displayed +# +# Generate a matrix of power values +# + +pvsyst_params = { + 'alpha_sc': 0.0015, + 'gamma_ref': 1.20585, + 'mu_gamma': -9.41066e-05, + 'I_L_ref': 5.930108567118184, + 'I_o_ref': 2.9690970560272695e-10, + 'R_sh_ref': 1144, + 'R_sh_0': 3850, + 'R_s': 0.6, + 'cells_in_series': 96, + 'R_sh_exp': 5.5, + 'EgRef': 1.12, + } + +G_REF = 1000 +T_REF = 25 + +params_stc = calcparams_pvsyst(G_REF, T_REF, **pvsyst_params) +mpp_stc = max_power_point(*params_stc) + +P_REF = mpp_stc['p_mp'] + +g, t = np.meshgrid(np.linspace(100, 1100, 11), + np.linspace(0, 75, 4)) + +adjusted_params = calcparams_pvsyst(g, t, **pvsyst_params) +mpp = max_power_point(*adjusted_params) +p_mp = mpp['p_mp'] + +print('irradiance') +print(g[:1].round(0)) + +print('maximum power') +print(p_mp.round(1)) + +# %% +# +# Convert power matrix to efficiency and fit the ADR model to all the points +# + +eta_rel_pvs = (p_mp / P_REF) / (g / G_REF) + +adr_params = fit_pvefficiency_adr(g, t, eta_rel_pvs, dict_output=True) + +for k, v in adr_params.items(): + print('%-5s = %7.4f' % (k, v)) + +# %% +# +# Compare the ADR model output to the PVsyst model output +# + +eta_rel_adr = pvefficiency_adr(g, t, **adr_params) + +plt.figure() +plt.plot(g.flat, eta_rel_pvs.flat, 'oc', ms=8) +plt.plot(g.flat, eta_rel_adr.flat, '.k') +plt.legend(['PVsyst model output', 'ADR model fit']) +plt.xlabel('Irradiance [W/m²]') +plt.ylabel('Relative efficiency [-]') +plt.grid(alpha=0.5) +plt.show() + +mbe = np.mean(eta_rel_adr - eta_rel_pvs) +rmse = np.sqrt(np.mean(np.square(eta_rel_adr - eta_rel_pvs))) +# plt.title('RMS difference is %.4f' % (rmse)) +plt.title('Differences: mean %.5f, RMS %.5f' % (mbe, rmse)) + +# %% +# +# Generate some random irradiance and temperature data +# + +g = np.random.uniform(0, 1200, 8760) +t = np.random.uniform(20, 80, 8760) + +def run_adr(): + eta_rel = pvefficiency_adr(g, t, **adr_params) + p_adr = P_REF * eta_rel * (g / G_REF) + return p_adr + +def run_pvsyst(): + adjusted_params = calcparams_pvsyst(g, t, **pvsyst_params) + mpp = max_power_point(*adjusted_params) + p_pvs = mpp['p_mp'] + return p_pvs + +from timeit import timeit, repeat + +elapsed_adr = timeit('run_adr()', number=1, globals=globals()) +elapsed_pvs = timeit('run_pvsyst()', number=1, globals=globals()) + +print('Elapsed time for the PVsyst model: %9.6f s' % elapsed_pvs) +print('Elapsed time for the ADR model: %9.6f s' % elapsed_adr) +print('ADR accelleration ratio: %9.0f x' % (elapsed_pvs / elapsed_adr)) + +#%% +# +# That's fast, but is it accurate? +# Run them again to compare the simulated power values +# + +p_pvs = run_pvsyst() +p_adr = run_adr() + +mbe = np.mean(p_adr - p_pvs) +rmse = np.sqrt(np.mean(np.square(p_adr - p_pvs))) + +plt.figure() +pc = plt.scatter(p_pvs, p_adr-p_pvs, c=t, cmap='jet') +plt.colorbar() +pc.set_alpha(0.25) +plt.grid(alpha=0.5) +plt.xlabel('Power calculated using the PVsyst model [W]') +plt.ylabel('ADR model power - PVsyst model power [W]') + +plt.title('Differences: mean %.2f W, RMS %.2f W' % (mbe, rmse)) +plt.ylim(-1, 1) +plt.show() + +# %% +# +# References +# ---------- +# .. [1] A. Driesse and J. S. Stein, "From IEC 61853 power measurements +# to PV system simulations", Sandia Report No. SAND2020-3877, 2020. +# +# .. [2] A. Driesse, M. Theristis and J. S. Stein, "A New Photovoltaic Module +# Efficiency Model for Energy Prediction and Rating," in IEEE Journal +# of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021, +# doi: 10.1109/JPHOTOV.2020.3045677. +# diff --git a/docs/examples/adr-pvarray/plot_simulate_system.py b/docs/examples/adr-pvarray/plot_simulate_system.py index a269d6986a..9cdd9ddf60 100644 --- a/docs/examples/adr-pvarray/plot_simulate_system.py +++ b/docs/examples/adr-pvarray/plot_simulate_system.py @@ -9,6 +9,7 @@ Efficiency is independent of system size, so adjusting the system capacity is just a matter of setting the desired value, e.g. P_STC = 5000. +Author: Anton Driesse """ import os diff --git a/pvlib/pvarray.py b/pvlib/pvarray.py index 44b8e5e2f4..fa2dd8ff44 100644 --- a/pvlib/pvarray.py +++ b/pvlib/pvarray.py @@ -190,12 +190,15 @@ def fit_pvefficiency_adr(irradiance, temperature, eta, dict_output=True, P0 = [eta_max, -6, 0.0, 0, 0] # noQA: E221 P_SCALE = [eta_max, 10, 0.1, 1, 1] + SIGMA = 1 / np.sqrt(irradiance / 1000) + fit_options = dict(p0=P0, bounds=[P_MIN, P_MAX], method='trf', x_scale=P_SCALE, loss='soft_l1', f_scale=eta_max * 0.05, + sigma=SIGMA, ) fit_options.update(kwargs) From 2c632bab7081e58e7ab0613764373ca0459fc7b2 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Fri, 2 Dec 2022 23:11:44 +0100 Subject: [PATCH 08/16] Adjust expected values in tests and optimistically tighten the tolerances, plus make stickler happy again. --- .../adr-pvarray/plot_fit_to_matrix.py | 3 +- .../adr-pvarray/plot_simulate_fast.py | 63 +++++++++++-------- pvlib/tests/test_pvarray.py | 16 ++--- 3 files changed, 46 insertions(+), 36 deletions(-) diff --git a/docs/examples/adr-pvarray/plot_fit_to_matrix.py b/docs/examples/adr-pvarray/plot_fit_to_matrix.py index 9f115ec2cc..f700d5e07a 100644 --- a/docs/examples/adr-pvarray/plot_fit_to_matrix.py +++ b/docs/examples/adr-pvarray/plot_fit_to_matrix.py @@ -84,7 +84,8 @@ # they are most likely evidence of the limitations of measurement accuracy. # -eta_rel_adr = pvefficiency_adr(df['irradiance'], df['temperature'], **adr_params) +eta_rel_adr = pvefficiency_adr(df['irradiance'], + df['temperature'], **adr_params) plt.figure() plt.plot(df['irradiance'], df['eta_rel'], 'oc', ms=8) diff --git a/docs/examples/adr-pvarray/plot_simulate_fast.py b/docs/examples/adr-pvarray/plot_simulate_fast.py index 4b5ae061a7..b2ee83f711 100644 --- a/docs/examples/adr-pvarray/plot_simulate_fast.py +++ b/docs/examples/adr-pvarray/plot_simulate_fast.py @@ -17,30 +17,30 @@ """ import numpy as np -# import pandas as pd import matplotlib.pyplot as plt from pvlib.pvsystem import calcparams_pvsyst, max_power_point -from pvlib.pvarray import pvefficiency_adr, fit_pvefficiency_adr +from pvlib.pvarray import fit_pvefficiency_adr, pvefficiency_adr + +from timeit import timeit # %% The text on this line is not displayed # # Generate a matrix of power values # -pvsyst_params = { - 'alpha_sc': 0.0015, - 'gamma_ref': 1.20585, - 'mu_gamma': -9.41066e-05, - 'I_L_ref': 5.930108567118184, - 'I_o_ref': 2.9690970560272695e-10, - 'R_sh_ref': 1144, - 'R_sh_0': 3850, - 'R_s': 0.6, - 'cells_in_series': 96, - 'R_sh_exp': 5.5, - 'EgRef': 1.12, - } +pvsyst_params = {'alpha_sc': 0.0015, + 'gamma_ref': 1.20585, + 'mu_gamma': -9.41066e-05, + 'I_L_ref': 5.9301, + 'I_o_ref': 2.9691e-10, + 'R_sh_ref': 1144, + 'R_sh_0': 3850, + 'R_s': 0.6, + 'cells_in_series': 96, + 'R_sh_exp': 5.5, + 'EgRef': 1.12, + } G_REF = 1000 T_REF = 25 @@ -81,20 +81,19 @@ # eta_rel_adr = pvefficiency_adr(g, t, **adr_params) +mbe = np.mean(eta_rel_adr - eta_rel_pvs) +rmse = np.sqrt(np.mean(np.square(eta_rel_adr - eta_rel_pvs))) plt.figure() plt.plot(g.flat, eta_rel_pvs.flat, 'oc', ms=8) plt.plot(g.flat, eta_rel_adr.flat, '.k') -plt.legend(['PVsyst model output', 'ADR model fit']) -plt.xlabel('Irradiance [W/m²]') -plt.ylabel('Relative efficiency [-]') plt.grid(alpha=0.5) -plt.show() -mbe = np.mean(eta_rel_adr - eta_rel_pvs) -rmse = np.sqrt(np.mean(np.square(eta_rel_adr - eta_rel_pvs))) -# plt.title('RMS difference is %.4f' % (rmse)) +plt.xlabel('Irradiance [W/m²]') +plt.ylabel('Relative efficiency [-]') +plt.legend(['PVsyst model output', 'ADR model fit']) plt.title('Differences: mean %.5f, RMS %.5f' % (mbe, rmse)) +plt.show() # %% # @@ -104,27 +103,28 @@ g = np.random.uniform(0, 1200, 8760) t = np.random.uniform(20, 80, 8760) + def run_adr(): eta_rel = pvefficiency_adr(g, t, **adr_params) p_adr = P_REF * eta_rel * (g / G_REF) return p_adr + def run_pvsyst(): adjusted_params = calcparams_pvsyst(g, t, **pvsyst_params) mpp = max_power_point(*adjusted_params) p_pvs = mpp['p_mp'] return p_pvs -from timeit import timeit, repeat elapsed_adr = timeit('run_adr()', number=1, globals=globals()) elapsed_pvs = timeit('run_pvsyst()', number=1, globals=globals()) print('Elapsed time for the PVsyst model: %9.6f s' % elapsed_pvs) print('Elapsed time for the ADR model: %9.6f s' % elapsed_adr) -print('ADR accelleration ratio: %9.0f x' % (elapsed_pvs / elapsed_adr)) +print('ADR accelleration ratio: %9.0f x' % (elapsed_pvs/elapsed_adr)) -#%% +# %% # # That's fast, but is it accurate? # Run them again to compare the simulated power values @@ -136,18 +136,27 @@ def run_pvsyst(): mbe = np.mean(p_adr - p_pvs) rmse = np.sqrt(np.mean(np.square(p_adr - p_pvs))) +# sphinx_gallery_thumbnail_number = 2 plt.figure() pc = plt.scatter(p_pvs, p_adr-p_pvs, c=t, cmap='jet') plt.colorbar() pc.set_alpha(0.25) +plt.ylim(-1, 1) plt.grid(alpha=0.5) + plt.xlabel('Power calculated using the PVsyst model [W]') plt.ylabel('ADR model power - PVsyst model power [W]') - plt.title('Differences: mean %.2f W, RMS %.2f W' % (mbe, rmse)) -plt.ylim(-1, 1) plt.show() +# %% +# +# There are some small systematic differences between the original +# PVsyst model output and the ADR fit. But these differences are +# much smaller than the uncertainty w.r.t. actual output +# of modules of this type. +# + # %% # # References diff --git a/pvlib/tests/test_pvarray.py b/pvlib/tests/test_pvarray.py index 8d6ceb8427..2f689583b8 100644 --- a/pvlib/tests/test_pvarray.py +++ b/pvlib/tests/test_pvarray.py @@ -6,26 +6,26 @@ def test_pvefficiency_adr(): g = [1000, 200, 1000, 200, 1000, 200] t = [25, 25, 50, 50, 75, 75] - p = [1.0, -6.684898, 0.018855, 0.069917, 0.054369] + p = [1.0, -6.651460, 0.018736, 0.070679, 0.054170] - e = [1.0, 0.949154, 0.92812, 0.876472, 0.855699, 0.80325] + e = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] result = pvarray.pvefficiency_adr(g, t, *p) - assert_allclose(result, e, rtol=1e-5) + assert_allclose(result, e, rtol=1e-6) def test_fit_pvefficiency_adr(): g = [1000, 200, 1000, 200, 1000, 200] t = [25, 25, 50, 50, 75, 75] - e = [1.0, 0.949154, 0.92812, 0.876472, 0.855699, 0.80325] + e = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] - p = [1.0, -6.684898, 0.018855, 0.069917, 0.054369] + p = [1.0, -6.651460, 0.018736, 0.070679, 0.054170] result = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=False) # the fitted parameters vary somewhat by platform during the testing # so the tolerance is higher on the parameters than on the efficiencies # in the other tests - assert_allclose(result, p, rtol=1e-3) + assert_allclose(result, p, rtol=1e-5) result = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=True) assert 'k_a' in result @@ -34,8 +34,8 @@ def test_fit_pvefficiency_adr(): def test_pvefficiency_adr_round_trip(): g = [1000, 200, 1000, 200, 1000, 200] t = [25, 25, 50, 50, 75, 75] - e = [1.0, 0.949154, 0.92812, 0.876472, 0.855699, 0.80325] + e = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] p = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=False) result = pvarray.pvefficiency_adr(g, t, *p) - assert_allclose(result, e, rtol=1e-5) + assert_allclose(result, e, rtol=1e-6) From d5b57b5936722b08c825f420a1619efceb5c4fd8 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Fri, 2 Dec 2022 23:32:38 +0100 Subject: [PATCH 09/16] Roll back my optimism on those test tolerances again. --- pvlib/tests/test_pvarray.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pvlib/tests/test_pvarray.py b/pvlib/tests/test_pvarray.py index 2f689583b8..afa73da319 100644 --- a/pvlib/tests/test_pvarray.py +++ b/pvlib/tests/test_pvarray.py @@ -11,7 +11,7 @@ def test_pvefficiency_adr(): e = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] result = pvarray.pvefficiency_adr(g, t, *p) - assert_allclose(result, e, rtol=1e-6) + assert_allclose(result, e, atol=1e-6) def test_fit_pvefficiency_adr(): @@ -25,7 +25,7 @@ def test_fit_pvefficiency_adr(): # the fitted parameters vary somewhat by platform during the testing # so the tolerance is higher on the parameters than on the efficiencies # in the other tests - assert_allclose(result, p, rtol=1e-5) + assert_allclose(result, p, rtol=1e-4) result = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=True) assert 'k_a' in result @@ -38,4 +38,4 @@ def test_pvefficiency_adr_round_trip(): p = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=False) result = pvarray.pvefficiency_adr(g, t, *p) - assert_allclose(result, e, rtol=1e-6) + assert_allclose(result, e, atol=1e-6) From 9735124e78921e6796c234a9782b32ed4f22cd2c Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Fri, 2 Dec 2022 23:59:06 +0100 Subject: [PATCH 10/16] Back off the tolelerance one more time to get the last three environments to pass. --- pvlib/tests/test_pvarray.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tests/test_pvarray.py b/pvlib/tests/test_pvarray.py index afa73da319..7d6c25bee8 100644 --- a/pvlib/tests/test_pvarray.py +++ b/pvlib/tests/test_pvarray.py @@ -25,7 +25,7 @@ def test_fit_pvefficiency_adr(): # the fitted parameters vary somewhat by platform during the testing # so the tolerance is higher on the parameters than on the efficiencies # in the other tests - assert_allclose(result, p, rtol=1e-4) + assert_allclose(result, p, rtol=1e-3) result = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=True) assert 'k_a' in result From 19cdcbf213689f620ef384416785b36d88e0c09d Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Tue, 13 Dec 2022 10:28:54 +0100 Subject: [PATCH 11/16] Apply suggestions from code review Kevin's bug observations and identifications. :) Co-authored-by: Kevin Anderson --- docs/examples/adr-pvarray/plot_simulate_fast.py | 4 ++-- pvlib/pvarray.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/examples/adr-pvarray/plot_simulate_fast.py b/docs/examples/adr-pvarray/plot_simulate_fast.py index b2ee83f711..178844519d 100644 --- a/docs/examples/adr-pvarray/plot_simulate_fast.py +++ b/docs/examples/adr-pvarray/plot_simulate_fast.py @@ -11,7 +11,7 @@ parameters to reproduce the behavior of the PVsyst model. This way both PVsyst and ADR models can simulate the same PV module type. -To compare simulation speed, we run them using ```timeit```. +To compare simulation speed, we run them using ``timeit``. Author: Anton Driesse """ @@ -122,7 +122,7 @@ def run_pvsyst(): print('Elapsed time for the PVsyst model: %9.6f s' % elapsed_pvs) print('Elapsed time for the ADR model: %9.6f s' % elapsed_adr) -print('ADR accelleration ratio: %9.0f x' % (elapsed_pvs/elapsed_adr)) +print('ADR acceleration ratio: %9.0f x' % (elapsed_pvs/elapsed_adr)) # %% # diff --git a/pvlib/pvarray.py b/pvlib/pvarray.py index fa2dd8ff44..3b36684a21 100644 --- a/pvlib/pvarray.py +++ b/pvlib/pvarray.py @@ -74,7 +74,7 @@ def pvefficiency_adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): See also -------- - pvlib.pvefficiency.fit_pvefficiency_adr + pvlib.pvarray.fit_pvefficiency_adr References ---------- @@ -153,7 +153,7 @@ def fit_pvefficiency_adr(irradiance, temperature, eta, dict_output=True, return the result as a numpy array. kwargs : - Optional keyword arguments passed to `scip.optimize.curve_fit`. + Optional keyword arguments passed to `scipy.optimize.curve_fit`. These kwargs can over-ride some options set within this function, which could be interesting for very advanced users. @@ -171,7 +171,7 @@ def fit_pvefficiency_adr(irradiance, temperature, eta, dict_output=True, See also -------- - pvlib.pvefficiency.pvefficiency_adr + pvlib.pvarray.pvefficiency_adr scipy.optimize.curve_fit Adapted from https://github.com/adriesse/pvpltools-python From a64c66aa8151891b55591a28399df39de9a424e3 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Tue, 13 Dec 2022 13:52:30 +0100 Subject: [PATCH 12/16] Improvements after first review. --- .../adr-pvarray/plot_simulate_system.py | 9 ++---- pvlib/pvarray.py | 8 ++--- pvlib/tests/test_pvarray.py | 31 ++++++++++--------- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/docs/examples/adr-pvarray/plot_simulate_system.py b/docs/examples/adr-pvarray/plot_simulate_system.py index 9cdd9ddf60..655d8dae0a 100644 --- a/docs/examples/adr-pvarray/plot_simulate_system.py +++ b/docs/examples/adr-pvarray/plot_simulate_system.py @@ -31,8 +31,7 @@ tmy, metadata = iotools.read_tmy3(DATA_FILE, coerce_year=1990) -df = pd.DataFrame({'ghi': tmy['GHI'], 'dhi': tmy['DHI'], - 'dni': tmy['DNI'], 'dni_extra': tmy['ETRN'], +df = pd.DataFrame({'ghi': tmy['GHI'], 'dhi': tmy['DHI'], 'dni': tmy['DNI'], 'temp_air': tmy['DryBulb'], 'wind_speed': tmy['Wspd'], }) @@ -54,11 +53,9 @@ TILT = metadata['latitude'] ORIENT = 180 -df['aoi'] = aoi(TILT, ORIENT, solpos.apparent_zenith, solpos.azimuth) - total_irrad = get_total_irradiance(TILT, ORIENT, solpos.apparent_zenith, solpos.azimuth, - df.dni, df.ghi, df.dhi, df.dni_extra) + df.dni, df.ghi, df.dhi) df['poa_global'] = total_irrad.poa_global @@ -101,7 +98,7 @@ # Set the desired array size: P_STC = 5000. # (W) -# and the irradiance level needed to achieve this output ( +# and the irradiance level needed to achieve this output: G_STC = 1000. # (W/m2) df['p_mp'] = P_STC * df['eta_rel'] * (df['poa_global'] / G_STC) diff --git a/pvlib/pvarray.py b/pvlib/pvarray.py index 3b36684a21..0ce4b891de 100644 --- a/pvlib/pvarray.py +++ b/pvlib/pvarray.py @@ -96,11 +96,11 @@ def pvefficiency_adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): k_a=1.0, k_d=-6.0, tc_d=0.02, k_rs=0.05, k_rsh=0.10) array([1. , 0.92797293]) - - Adapted from https://github.com/adriesse/pvpltools-python - Copyright (c) 2022, Anton Driesse, PV Performance Labs - All rights reserved. ''' + # Adapted from https://github.com/adriesse/pvpltools-python + # Copyright (c) 2022, Anton Driesse, PV Performance Labs + # All rights reserved. + k_a = np.array(k_a) k_d = np.array(k_d) tc_d = np.array(tc_d) diff --git a/pvlib/tests/test_pvarray.py b/pvlib/tests/test_pvarray.py index 7d6c25bee8..d743220e76 100644 --- a/pvlib/tests/test_pvarray.py +++ b/pvlib/tests/test_pvarray.py @@ -1,41 +1,42 @@ +import numpy as np from numpy.testing import assert_allclose from pvlib import pvarray def test_pvefficiency_adr(): - g = [1000, 200, 1000, 200, 1000, 200] - t = [25, 25, 50, 50, 75, 75] - p = [1.0, -6.651460, 0.018736, 0.070679, 0.054170] + g = [1000, 200, 1000, 200, 1000, 200, 0, np.nan] + t = [25, 25, 50, 50, 75, 75, 25, 25] + params = [1.0, -6.651460, 0.018736, 0.070679, 0.054170] - e = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] + eta = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281, 0.0, np.nan] - result = pvarray.pvefficiency_adr(g, t, *p) - assert_allclose(result, e, atol=1e-6) + result = pvarray.pvefficiency_adr(g, t, *params) + assert_allclose(result, eta, atol=1e-6) def test_fit_pvefficiency_adr(): g = [1000, 200, 1000, 200, 1000, 200] t = [25, 25, 50, 50, 75, 75] - e = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] + eta = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] - p = [1.0, -6.651460, 0.018736, 0.070679, 0.054170] + params = [1.0, -6.651460, 0.018736, 0.070679, 0.054170] - result = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=False) + result = pvarray.fit_pvefficiency_adr(g, t, eta, dict_output=False) # the fitted parameters vary somewhat by platform during the testing # so the tolerance is higher on the parameters than on the efficiencies # in the other tests - assert_allclose(result, p, rtol=1e-3) + assert_allclose(result, params, rtol=1e-3) - result = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=True) + result = pvarray.fit_pvefficiency_adr(g, t, eta, dict_output=True) assert 'k_a' in result def test_pvefficiency_adr_round_trip(): g = [1000, 200, 1000, 200, 1000, 200] t = [25, 25, 50, 50, 75, 75] - e = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] + eta = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] - p = pvarray.fit_pvefficiency_adr(g, t, e, dict_output=False) - result = pvarray.pvefficiency_adr(g, t, *p) - assert_allclose(result, e, atol=1e-6) + params = pvarray.fit_pvefficiency_adr(g, t, eta, dict_output=False) + result = pvarray.pvefficiency_adr(g, t, *params) + assert_allclose(result, eta, atol=1e-6) From 9dc53acd7f0a0625bd8f0c1fb862b559ddd21d33 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Thu, 15 Dec 2022 23:28:02 +0100 Subject: [PATCH 13/16] Apply suggestions from code review Co-authored-by: Cliff Hansen --- docs/examples/adr-pvarray/plot_simulate_fast.py | 2 +- docs/examples/adr-pvarray/plot_simulate_system.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/examples/adr-pvarray/plot_simulate_fast.py b/docs/examples/adr-pvarray/plot_simulate_fast.py index 178844519d..4b6bc56881 100644 --- a/docs/examples/adr-pvarray/plot_simulate_fast.py +++ b/docs/examples/adr-pvarray/plot_simulate_fast.py @@ -153,7 +153,7 @@ def run_pvsyst(): # # There are some small systematic differences between the original # PVsyst model output and the ADR fit. But these differences are -# much smaller than the uncertainty w.r.t. actual output +# much smaller than the typical uncertainty in measured output # of modules of this type. # diff --git a/docs/examples/adr-pvarray/plot_simulate_system.py b/docs/examples/adr-pvarray/plot_simulate_system.py index 655d8dae0a..5078b23cbf 100644 --- a/docs/examples/adr-pvarray/plot_simulate_system.py +++ b/docs/examples/adr-pvarray/plot_simulate_system.py @@ -1,5 +1,5 @@ """ -Simulating PV systems using the ADR module efficiency model +Simulating PV system DC output using the ADR module efficiency model =========================================================== Time series processing with the ADR model is really easy. @@ -77,7 +77,7 @@ # - SAPM # - single-diode model variations # -# And now also the ADR PV efficiency model +# And now also the ADR PV efficiency model # # Simulation is done in two steps: # @@ -98,7 +98,9 @@ # Set the desired array size: P_STC = 5000. # (W) + # and the irradiance level needed to achieve this output: + G_STC = 1000. # (W/m2) df['p_mp'] = P_STC * df['eta_rel'] * (df['poa_global'] / G_STC) From e8dd0e004939c7a734ab125df49e2c29bfc9028e Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Thu, 15 Dec 2022 23:37:20 +0100 Subject: [PATCH 14/16] Improvements after second review. --- .../adr-pvarray/plot_fit_to_matrix.py | 5 ---- .../adr-pvarray/plot_simulate_fast.py | 2 +- .../adr-pvarray/plot_simulate_system.py | 3 +- docs/sphinx/source/reference/pv_modeling.rst | 12 ++++++-- pvlib/pvarray.py | 29 +++++++++---------- pvlib/tests/test_pvarray.py | 6 +++- 6 files changed, 31 insertions(+), 26 deletions(-) diff --git a/docs/examples/adr-pvarray/plot_fit_to_matrix.py b/docs/examples/adr-pvarray/plot_fit_to_matrix.py index f700d5e07a..58613a0e11 100644 --- a/docs/examples/adr-pvarray/plot_fit_to_matrix.py +++ b/docs/examples/adr-pvarray/plot_fit_to_matrix.py @@ -41,16 +41,11 @@ 10 800 25.0 257.561 11 1000 25.0 322.305 12 1100 25.0 354.174 -13 100 50.0 26.854 -14 200 50.0 56.698 15 400 50.0 117.062 16 600 50.0 177.959 17 800 50.0 238.626 18 1000 50.0 298.954 19 1100 50.0 328.413 -20 100 75.0 24.074 -21 200 75.0 51.103 -22 400 75.0 106.546 23 600 75.0 162.966 24 800 75.0 218.585 25 1000 75.0 273.651 diff --git a/docs/examples/adr-pvarray/plot_simulate_fast.py b/docs/examples/adr-pvarray/plot_simulate_fast.py index 4b6bc56881..731766334f 100644 --- a/docs/examples/adr-pvarray/plot_simulate_fast.py +++ b/docs/examples/adr-pvarray/plot_simulate_fast.py @@ -8,7 +8,7 @@ power point is usually found by an iterative search. In this example we use the PVsyst single diode model to generate a matrix of efficiency values, then determine the ADR model -parameters to reproduce the behavior of the PVsyst model. +parameters to approximate the behavior of the PVsyst model. This way both PVsyst and ADR models can simulate the same PV module type. To compare simulation speed, we run them using ``timeit``. diff --git a/docs/examples/adr-pvarray/plot_simulate_system.py b/docs/examples/adr-pvarray/plot_simulate_system.py index 5078b23cbf..76d558566f 100644 --- a/docs/examples/adr-pvarray/plot_simulate_system.py +++ b/docs/examples/adr-pvarray/plot_simulate_system.py @@ -18,7 +18,7 @@ import pvlib from pvlib import iotools, location -from pvlib.irradiance import aoi, get_total_irradiance +from pvlib.irradiance import get_total_irradiance from pvlib.pvarray import pvefficiency_adr # %% @@ -100,7 +100,6 @@ P_STC = 5000. # (W) # and the irradiance level needed to achieve this output: - G_STC = 1000. # (W/m2) df['p_mp'] = P_STC * df['eta_rel'] * (df['poa_global'] / G_STC) diff --git a/docs/sphinx/source/reference/pv_modeling.rst b/docs/sphinx/source/reference/pv_modeling.rst index b76422a616..2b7afd6406 100644 --- a/docs/sphinx/source/reference/pv_modeling.rst +++ b/docs/sphinx/source/reference/pv_modeling.rst @@ -155,6 +155,16 @@ PVWatts model inverter.pvwatts pvsystem.pvwatts_losses +ADR model +^^^^^^^^^ + +.. autosummary:: + :toctree: generated/ + + pvarray.adr + pvarray.fit_pvefficiency_adr + + Estimating PV model parameters ------------------------------ @@ -190,5 +200,3 @@ Other pvsystem.retrieve_sam pvsystem.scale_voltage_current_power - pvefficiency.adr - pvefficiency.fit_pvefficiency_adr diff --git a/pvlib/pvarray.py b/pvlib/pvarray.py index 0ce4b891de..7e62673735 100644 --- a/pvlib/pvarray.py +++ b/pvlib/pvarray.py @@ -13,7 +13,7 @@ from scipy.special import exp10 -def pvefficiency_adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): +def pvefficiency_adr(effective_irradiance, temp_cell, k_a, k_d, tc_d, k_rs, k_rsh): ''' Calculate PV module efficiency using the ADR model. @@ -22,10 +22,10 @@ def pvefficiency_adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): Parameters ---------- - irradiance : numeric, non-negative + effective_irradiance : numeric, non-negative The effective irradiance incident on the PV module. [W/m²] - temperature : numeric + temp_cell : numeric The PV module operating temperature. [°C] k_a : numeric @@ -97,9 +97,8 @@ def pvefficiency_adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): array([1. , 0.92797293]) ''' + # Contributed by Anton Driesse (@adriesse), PV Performance Labs, Dec. 2022 # Adapted from https://github.com/adriesse/pvpltools-python - # Copyright (c) 2022, Anton Driesse, PV Performance Labs - # All rights reserved. k_a = np.array(k_a) k_d = np.array(k_d) @@ -109,11 +108,11 @@ def pvefficiency_adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): # normalize the irradiance G_REF = np.array(1000.) - s = irradiance / G_REF + s = effective_irradiance / G_REF # obtain the difference from reference temperature T_REF = np.array(25.) - dt = temperature - T_REF + dt = temp_cell - T_REF # equation 29 in JPV s_o = exp10(k_d + (dt * tc_d)) # noQA: E221 @@ -130,7 +129,7 @@ def pvefficiency_adr(irradiance, temperature, k_a, k_d, tc_d, k_rs, k_rsh): return eta -def fit_pvefficiency_adr(irradiance, temperature, eta, dict_output=True, +def fit_pvefficiency_adr(effective_irradiance, temp_cell, eta, dict_output=True, **kwargs): """ Determine the parameters of the ADR module efficiency model by non-linear @@ -138,10 +137,10 @@ def fit_pvefficiency_adr(irradiance, temperature, eta, dict_output=True, Parameters ---------- - irradiance : numeric, non-negative + effective_irradiance : numeric, non-negative Effective irradiance incident on the PV module. [W/m²] - temperature : numeric + temp_cell : numeric PV module operating temperature. [°C] eta : numeric @@ -174,12 +173,12 @@ def fit_pvefficiency_adr(irradiance, temperature, eta, dict_output=True, pvlib.pvarray.pvefficiency_adr scipy.optimize.curve_fit - Adapted from https://github.com/adriesse/pvpltools-python - Copyright (c) 2022, Anton Driesse, PV Performance Labs - All rights reserved. """ - irradiance = np.asarray(irradiance, dtype=float).reshape(-1) - temperature = np.asarray(temperature, dtype=float).reshape(-1) + # Contributed by Anton Driesse (@adriesse), PV Performance Labs, Dec. 2022 + # Adapted from https://github.com/adriesse/pvpltools-python + + irradiance = np.asarray(effective_irradiance, dtype=float).reshape(-1) + temperature = np.asarray(temp_cell, dtype=float).reshape(-1) eta = np.asarray(eta, dtype=float).reshape(-1) eta_max = np.max(eta) diff --git a/pvlib/tests/test_pvarray.py b/pvlib/tests/test_pvarray.py index d743220e76..6dcacdefe1 100644 --- a/pvlib/tests/test_pvarray.py +++ b/pvlib/tests/test_pvarray.py @@ -5,10 +5,12 @@ def test_pvefficiency_adr(): - g = [1000, 200, 1000, 200, 1000, 200, 0, np.nan] + g = [1000, 200, 1000, 200, 1000, 200, 0.0, np.nan] t = [25, 25, 50, 50, 75, 75, 25, 25] params = [1.0, -6.651460, 0.018736, 0.070679, 0.054170] + # the expected values were calculated using the new function itself + # hence this test is primarily a regression test eta = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281, 0.0, np.nan] result = pvarray.pvefficiency_adr(g, t, *params) @@ -20,6 +22,8 @@ def test_fit_pvefficiency_adr(): t = [25, 25, 50, 50, 75, 75] eta = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] + # the expected values were calculated using the new function itself + # hence this test is primarily a regression test params = [1.0, -6.651460, 0.018736, 0.070679, 0.054170] result = pvarray.fit_pvefficiency_adr(g, t, eta, dict_output=False) From cd46b33eaf6bfe634578b6bf44abf20d11b9e0c1 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Fri, 16 Dec 2022 00:18:58 +0100 Subject: [PATCH 15/16] Stickler, and various other small mostly appearance-related changes. --- docs/examples/adr-pvarray/plot_fit_to_matrix.py | 11 +++++++---- docs/examples/adr-pvarray/plot_simulate_fast.py | 13 ++++++++----- docs/examples/adr-pvarray/plot_simulate_system.py | 15 ++++++++------- docs/sphinx/source/reference/pv_modeling.rst | 2 +- docs/sphinx/source/whatsnew/v0.9.4.rst | 7 ++++++- pvlib/pvarray.py | 12 +++++++----- 6 files changed, 37 insertions(+), 23 deletions(-) diff --git a/docs/examples/adr-pvarray/plot_fit_to_matrix.py b/docs/examples/adr-pvarray/plot_fit_to_matrix.py index 58613a0e11..b256262664 100644 --- a/docs/examples/adr-pvarray/plot_fit_to_matrix.py +++ b/docs/examples/adr-pvarray/plot_fit_to_matrix.py @@ -70,7 +70,7 @@ df['eta_rel']) for k, v in adr_params.items(): - print('%-5s = %7.4f' % (k, v)) + print('%-5s = %8.5f' % (k, v)) # %% # @@ -85,10 +85,12 @@ plt.figure() plt.plot(df['irradiance'], df['eta_rel'], 'oc', ms=8) plt.plot(df['irradiance'], eta_rel_adr, '.k') -plt.legend(['Lab measurements', 'ADR model fit']) +plt.legend(['Lab measurements', 'ADR model fit'], loc='lower right') plt.xlabel('Irradiance [W/m²]') plt.ylabel('Relative efficiency [-]') plt.grid(alpha=0.5) +plt.xlim(0, 1200) +plt.ylim(0.7, 1.1) plt.show() # %% @@ -97,9 +99,10 @@ # ---------- # .. [1] A. Driesse and J. S. Stein, "From IEC 61853 power measurements # to PV system simulations", Sandia Report No. SAND2020-3877, 2020. +# :doi:`10.2172/1615179` # # .. [2] A. Driesse, M. Theristis and J. S. Stein, "A New Photovoltaic Module # Efficiency Model for Energy Prediction and Rating," in IEEE Journal -# of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021, -# doi: 10.1109/JPHOTOV.2020.3045677. +# of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021. +# :doi:`10.1109/JPHOTOV.2020.3045677` # diff --git a/docs/examples/adr-pvarray/plot_simulate_fast.py b/docs/examples/adr-pvarray/plot_simulate_fast.py index 731766334f..ee83373e68 100644 --- a/docs/examples/adr-pvarray/plot_simulate_fast.py +++ b/docs/examples/adr-pvarray/plot_simulate_fast.py @@ -73,7 +73,7 @@ adr_params = fit_pvefficiency_adr(g, t, eta_rel_pvs, dict_output=True) for k, v in adr_params.items(): - print('%-5s = %7.4f' % (k, v)) + print('%-5s = %8.5f' % (k, v)) # %% # @@ -88,10 +88,12 @@ plt.plot(g.flat, eta_rel_pvs.flat, 'oc', ms=8) plt.plot(g.flat, eta_rel_adr.flat, '.k') plt.grid(alpha=0.5) +plt.xlim(0, 1200) +plt.ylim(0.7, 1.1) plt.xlabel('Irradiance [W/m²]') plt.ylabel('Relative efficiency [-]') -plt.legend(['PVsyst model output', 'ADR model fit']) +plt.legend(['PVsyst model output', 'ADR model fit'], loc='lower right') plt.title('Differences: mean %.5f, RMS %.5f' % (mbe, rmse)) plt.show() @@ -141,7 +143,7 @@ def run_pvsyst(): pc = plt.scatter(p_pvs, p_adr-p_pvs, c=t, cmap='jet') plt.colorbar() pc.set_alpha(0.25) -plt.ylim(-1, 1) +plt.ylim(-1.4, 1.4) plt.grid(alpha=0.5) plt.xlabel('Power calculated using the PVsyst model [W]') @@ -163,9 +165,10 @@ def run_pvsyst(): # ---------- # .. [1] A. Driesse and J. S. Stein, "From IEC 61853 power measurements # to PV system simulations", Sandia Report No. SAND2020-3877, 2020. +# :doi:`10.2172/1615179` # # .. [2] A. Driesse, M. Theristis and J. S. Stein, "A New Photovoltaic Module # Efficiency Model for Energy Prediction and Rating," in IEEE Journal -# of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021, -# doi: 10.1109/JPHOTOV.2020.3045677. +# of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021. +# :doi:`10.1109/JPHOTOV.2020.3045677` # diff --git a/docs/examples/adr-pvarray/plot_simulate_system.py b/docs/examples/adr-pvarray/plot_simulate_system.py index 76d558566f..e9c2d8985e 100644 --- a/docs/examples/adr-pvarray/plot_simulate_system.py +++ b/docs/examples/adr-pvarray/plot_simulate_system.py @@ -87,11 +87,11 @@ # Borrow the ADR model parameters from the other example: -adr_params = {'k_a': 0.99879, - 'k_d': -5.85188, - 'tc_d': 0.01939, - 'k_rs': 0.06962, - 'k_rsh': 0.21036 +adr_params = {'k_a': 0.99924, + 'k_d': -5.49097, + 'tc_d': 0.01918, + 'k_rs': 0.06999, + 'k_rsh': 0.26144 } df['eta_rel'] = pvefficiency_adr(df['poa_global'], df['temp_pv'], **adr_params) @@ -147,9 +147,10 @@ # ---------- # .. [1] A. Driesse and J. S. Stein, "From IEC 61853 power measurements # to PV system simulations", Sandia Report No. SAND2020-3877, 2020. +# :doi:`10.2172/1615179` # # .. [2] A. Driesse, M. Theristis and J. S. Stein, "A New Photovoltaic Module # Efficiency Model for Energy Prediction and Rating," in IEEE Journal -# of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021, -# doi: 10.1109/JPHOTOV.2020.3045677. +# of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021. +# :doi:`10.1109/JPHOTOV.2020.3045677` # diff --git a/docs/sphinx/source/reference/pv_modeling.rst b/docs/sphinx/source/reference/pv_modeling.rst index 188e4a43b2..a67d9cb9a3 100644 --- a/docs/sphinx/source/reference/pv_modeling.rst +++ b/docs/sphinx/source/reference/pv_modeling.rst @@ -166,7 +166,7 @@ ADR model .. autosummary:: :toctree: generated/ - pvarray.adr + pvarray.pvefficiency_adr pvarray.fit_pvefficiency_adr diff --git a/docs/sphinx/source/whatsnew/v0.9.4.rst b/docs/sphinx/source/whatsnew/v0.9.4.rst index cebb864758..75729533be 100644 --- a/docs/sphinx/source/whatsnew/v0.9.4.rst +++ b/docs/sphinx/source/whatsnew/v0.9.4.rst @@ -19,7 +19,7 @@ Deprecations * ``pvlib.modelchain.ModelChain.pvwatts_dc`` is now :py:meth:`pvlib.modelchain.ModelChain.pvwattsv5_dc` * ``pvlib.modelchain.ModelChain.pvwatts_inverter`` is now :py:meth:`pvlib.modelchain.ModelChain.pvwattsv5_inverter` * ``pvlib.modelchain.ModelChain.pvwatts_losses`` is now :py:meth:`pvlib.modelchain.ModelChain.pvwattsv5_losses` - + * The ``model`` parameter to :py:meth:`pvlib.pvsystem.PVSystem.get_ac` should now be ``'pvwattsv5'`` instead of ``'pvwatts'``. * The ``dc_model``, ``ac_model``, and ``losses_model`` parameters of @@ -47,6 +47,11 @@ Enhancements (:issue:`1594`, :pull:`1595`) * Add a function :py:func:`pvlib.ivtools.utils.astm_e1036` to perform ASTM E1036 extraction of IV curve parameters (:pull:`1585`) +* Added the ADR PV module efficiency model and a function to find its parameters from field or lab measurements. + Three gallery examples are also added to demonstrate how the model can be used for time series simulation. + :py:func:`~pvlib.pvarray.pvefficiency_adr` + :py:func:`~pvlib.pvarray.fit_pvefficiency_adr` + (:issue:`1544`, :pull:`1602`) Bug fixes ~~~~~~~~~ diff --git a/pvlib/pvarray.py b/pvlib/pvarray.py index 7e62673735..ebae5c60b6 100644 --- a/pvlib/pvarray.py +++ b/pvlib/pvarray.py @@ -13,7 +13,8 @@ from scipy.special import exp10 -def pvefficiency_adr(effective_irradiance, temp_cell, k_a, k_d, tc_d, k_rs, k_rsh): +def pvefficiency_adr(effective_irradiance, temp_cell, + k_a, k_d, tc_d, k_rs, k_rsh): ''' Calculate PV module efficiency using the ADR model. @@ -80,11 +81,12 @@ def pvefficiency_adr(effective_irradiance, temp_cell, k_a, k_d, tc_d, k_rs, k_rs ---------- .. [1] A. Driesse and J. S. Stein, "From IEC 61853 power measurements to PV system simulations", Sandia Report No. SAND2020-3877, 2020. + :doi:`10.2172/1615179` .. [2] A. Driesse, M. Theristis and J. S. Stein, "A New Photovoltaic Module Efficiency Model for Energy Prediction and Rating," in IEEE Journal - of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021, - doi: 10.1109/JPHOTOV.2020.3045677. + of Photovoltaics, vol. 11, no. 2, pp. 527-534, March 2021. + :doi:`10.1109/JPHOTOV.2020.3045677` Examples -------- @@ -129,8 +131,8 @@ def pvefficiency_adr(effective_irradiance, temp_cell, k_a, k_d, tc_d, k_rs, k_rs return eta -def fit_pvefficiency_adr(effective_irradiance, temp_cell, eta, dict_output=True, - **kwargs): +def fit_pvefficiency_adr(effective_irradiance, temp_cell, eta, + dict_output=True, **kwargs): """ Determine the parameters of the ADR module efficiency model by non-linear least-squares fit to lab or field measurements. From 91dfaa652a9a375d6f0023abc89a90b9f39b19f2 Mon Sep 17 00:00:00 2001 From: Anton Driesse Date: Fri, 16 Dec 2022 22:19:27 +0100 Subject: [PATCH 16/16] Changes after documentation review. --- .../adr-pvarray/plot_simulate_fast.py | 8 +++-- pvlib/pvarray.py | 29 +++++++++++-------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/docs/examples/adr-pvarray/plot_simulate_fast.py b/docs/examples/adr-pvarray/plot_simulate_fast.py index ee83373e68..380744f626 100644 --- a/docs/examples/adr-pvarray/plot_simulate_fast.py +++ b/docs/examples/adr-pvarray/plot_simulate_fast.py @@ -1,6 +1,6 @@ """ -Fast simulation using the ADR efficiency model with PVsyst parameters -===================================================================== +Fast simulation using the ADR efficiency model starting from PVsyst parameters +============================================================================== Would you like to increase simulation speed by a factor of 4000+? @@ -156,7 +156,9 @@ def run_pvsyst(): # There are some small systematic differences between the original # PVsyst model output and the ADR fit. But these differences are # much smaller than the typical uncertainty in measured output -# of modules of this type. +# of modules of this type. The PVsyst model and the parameters +# we started with are of course also only approximations of the +# true module behavior. # # %% diff --git a/pvlib/pvarray.py b/pvlib/pvarray.py index ebae5c60b6..30e824e8f2 100644 --- a/pvlib/pvarray.py +++ b/pvlib/pvarray.py @@ -24,7 +24,7 @@ def pvefficiency_adr(effective_irradiance, temp_cell, Parameters ---------- effective_irradiance : numeric, non-negative - The effective irradiance incident on the PV module. [W/m²] + The effective irradiance incident on the PV module. [W/m^2] temp_cell : numeric The PV module operating temperature. [°C] @@ -34,7 +34,7 @@ def pvefficiency_adr(effective_irradiance, temp_cell, reference conditions. This factor allows the model to be used with relative or absolute efficiencies, and to accommodate data sets which are not perfectly normalized but have a slight bias at - the reference conditions. [unitless|%] + the reference conditions. [unitless] k_d : numeric, negative “Dark irradiance” or diode coefficient which influences the voltage @@ -46,13 +46,18 @@ def pvefficiency_adr(effective_irradiance, temp_cell, in the model, its value will also reflect secondary temperature dependencies that are present in the PV module. [unitless] - k_rs and k_rsh : numeric - Series and shunt resistance loss factors. Because of the normalization - they can be read as power loss fractions at reference conditions. - For example, if k_rs is 0.05, the internal loss assigned to the + k_rs : numeric + Series resistance loss coefficient. Because of the normalization + it can be read as a power loss fraction at reference conditions. + For example, if ``k_rs`` is 0.05, the internal loss assigned to the series resistance has a magnitude equal to 5% of the module output. [unitless] + k_rsh : numeric + Shunt resistance loss coefficient. Can be interpreted as a power + loss fraction at reference conditions like ``k_rs``. + [unitless] + Returns ------- eta : numeric @@ -61,13 +66,13 @@ def pvefficiency_adr(effective_irradiance, temp_cell, Notes ----- - The efficiency values may be absolute or relative, and may be expressed + Efficiency values ``eta`` may be absolute or relative, and may be expressed as percent or per unit. This is determined by the efficiency data used to derive values for the 5 model parameters. The first model - parameter k_a is equal to the efficiency at STC and therefore - indicates the efficiency scale being used. k_a can also be changed - freely to adjust the scale, or to change the module class to a slightly - higher or lower efficiency. + parameter ``k_a`` is equal to the efficiency at STC and therefore + indicates the efficiency scale being used. ``k_a`` can also be changed + freely to adjust the scale, or to change the module to a slightly + higher or lower efficiency class. All arguments may be scalars or array-like. If multiple arguments are array-like they must be the same shape or broadcastable to the @@ -140,7 +145,7 @@ def fit_pvefficiency_adr(effective_irradiance, temp_cell, eta, Parameters ---------- effective_irradiance : numeric, non-negative - Effective irradiance incident on the PV module. [W/m²] + Effective irradiance incident on the PV module. [W/m^2] temp_cell : numeric PV module operating temperature. [°C]