diff --git a/docs/examples/adr-pvarray/README.rst b/docs/examples/adr-pvarray/README.rst new file mode 100644 index 0000000000..0db64aa046 --- /dev/null +++ b/docs/examples/adr-pvarray/README.rst @@ -0,0 +1,3 @@ +ADR Model for PV Module Efficiency +---------------------------------- + diff --git a/docs/examples/adr-pvarray/plot_fit_to_matrix.py b/docs/examples/adr-pvarray/plot_fit_to_matrix.py new file mode 100644 index 0000000000..b256262664 --- /dev/null +++ b/docs/examples/adr-pvarray/plot_fit_to_matrix.py @@ -0,0 +1,108 @@ +""" +Obtaining ADR model parameters from IEC 61853 matrix measurements +================================================================= + +There's a fitting function provided in pvlib to do exactly that. + +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. + +Author: Anton Driesse +""" + +from io import StringIO +import pandas as pd +import matplotlib.pyplot as plt + +from pvlib.pvarray import pvefficiency_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 +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 +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 = %8.5f' % (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 = pvefficiency_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'], 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() + +# %% +# +# References +# ---------- +# .. [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` +# 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..380744f626 --- /dev/null +++ b/docs/examples/adr-pvarray/plot_simulate_fast.py @@ -0,0 +1,176 @@ +""" +Fast simulation using the ADR efficiency model starting from 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 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``. + +Author: Anton Driesse +""" + +import numpy as np +import matplotlib.pyplot as plt + +from pvlib.pvsystem import calcparams_pvsyst, max_power_point +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.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 + +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 = %8.5f' % (k, v)) + +# %% +# +# Compare the ADR model output to the PVsyst model output +# + +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.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'], loc='lower right') +plt.title('Differences: mean %.5f, RMS %.5f' % (mbe, rmse)) +plt.show() + +# %% +# +# 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 + + +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 acceleration 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))) + +# 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.4, 1.4) +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.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 typical uncertainty in measured output +# 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. +# + +# %% +# +# References +# ---------- +# .. [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` +# diff --git a/docs/examples/adr-pvarray/plot_simulate_system.py b/docs/examples/adr-pvarray/plot_simulate_system.py new file mode 100644 index 0000000000..e9c2d8985e --- /dev/null +++ b/docs/examples/adr-pvarray/plot_simulate_system.py @@ -0,0 +1,156 @@ +""" +Simulating PV system DC output using the ADR module efficiency model +=========================================================== + +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. +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 +import pandas as pd +import matplotlib.pyplot as plt + +import pvlib +from pvlib import iotools, location +from pvlib.irradiance import get_total_irradiance +from pvlib.pvarray import pvefficiency_adr + +# %% +# +# 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'], + '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 + +total_irrad = get_total_irradiance(TILT, ORIENT, + solpos.apparent_zenith, solpos.azimuth, + df.dni, df.ghi, df.dhi) + +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.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) + +# 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. +# :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` +# diff --git a/docs/sphinx/source/reference/pv_modeling.rst b/docs/sphinx/source/reference/pv_modeling.rst index 797681ce23..a67d9cb9a3 100644 --- a/docs/sphinx/source/reference/pv_modeling.rst +++ b/docs/sphinx/source/reference/pv_modeling.rst @@ -160,6 +160,16 @@ PVWatts model pvsystem.pvwatts_losses pvsystem.pvwattsv5_losses +ADR model +^^^^^^^^^ + +.. autosummary:: + :toctree: generated/ + + pvarray.pvefficiency_adr + pvarray.fit_pvefficiency_adr + + Estimating PV model parameters ------------------------------ diff --git a/docs/sphinx/source/whatsnew/v0.9.4.rst b/docs/sphinx/source/whatsnew/v0.9.4.rst index efac8f7d40..a8412e6409 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 new file mode 100644 index 0000000000..30e824e8f2 --- /dev/null +++ b/pvlib/pvarray.py @@ -0,0 +1,225 @@ +""" +This module contains implementations of PV module and array electrical models. + +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 +from scipy.optimize import curve_fit +from scipy.special import exp10 + + +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. + + The efficiency varies with irradiance and operating temperature + and is determined by 5 model parameters as described in [1]_. + + Parameters + ---------- + effective_irradiance : numeric, non-negative + The effective irradiance incident on the PV module. [W/m^2] + + temp_cell : 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 : 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 + The efficiency of the module at the specified irradiance and + temperature. + + Notes + ----- + 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 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 + same shape. + + See also + -------- + pvlib.pvarray.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. + :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` + + Examples + -------- + >>> 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]) + + >>> 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]) + + ''' + # Contributed by Anton Driesse (@adriesse), PV Performance Labs, Dec. 2022 + # Adapted from https://github.com/adriesse/pvpltools-python + + 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 = effective_irradiance / G_REF + + # obtain the difference from reference temperature + T_REF = np.array(25.) + dt = temp_cell - 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(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. + + Parameters + ---------- + effective_irradiance : numeric, non-negative + Effective irradiance incident on the PV module. [W/m^2] + + temp_cell : 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 `scipy.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.pvarray.pvefficiency_adr + scipy.optimize.curve_fit + + """ + # 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) + + 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] + + 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) + + def adr_wrapper(xdata, *params): + return pvefficiency_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 diff --git a/pvlib/tests/test_pvarray.py b/pvlib/tests/test_pvarray.py new file mode 100644 index 0000000000..6dcacdefe1 --- /dev/null +++ b/pvlib/tests/test_pvarray.py @@ -0,0 +1,46 @@ +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, 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) + 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] + 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) + # 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, params, rtol=1e-3) + + 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] + eta = [1.0, 0.949125, 0.928148, 0.876472, 0.855759, 0.803281] + + 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)