Package: vocmax
vocmaxCalculate the maximum sting size for a photovoltaic installation. The method is consistent with the NEC 2017 690.7 standard.SummaryOne key design decision for photovoltaic (PV) power plants is to select the string size, the number of PV modules connected in series. Longer strings tend to lower total system costs, but the string size must still meet relevant electrical standards to ensure that the maximum system voltage remains less than the design voltage. Conventional methods calculate string size using the temperature coefficient of open-circuit voltage (Voc) assuming that the coldest-expected temperature occurs simultaneously with a full-sun irradiance of 1000 W/m^2. Here, we demonstrate that this traditional method is unnecessarily conservative, resulting in a string size that is ~10% shorter than necessary to maintain system voltage within limits. Instead, we suggest to calculate string size by modeling Voc over time using historical weather data, a method in compliance with the 2017 National Electric Code. We demonstrate that this site-specific modeling procedure is in close agreement with data from field measurements. Furthermore, we perform a comprehensive sensitivity and uncertainty analysis to identify an appropriate safety factor for this method. By using site-specific modeling instead of conventional methods, the levelized cost of electricity is reduced by up to ~1.2%, an impressive improvement attainable just by reorganizing strings. The method is provided as an easy-to-useweb tooland an open-source Python package (vocmax) for the PV community.Filesexample_vocmax_calculation.py- Script for calculating maximum string length. Start here!vocmax/main.py- vocmax main functions.vocmax/NSRDB_sample/- an example set of NSRDB data files for running sample calculation. You may want to download your own for the location of interest.vocmax05_compress_database.py- Script used to compress NSRDB csv files into a python pickle.InstallThe vocmax library can be installed with pip:pipinstallvocmaxThis package depends on the following packages:pvlibpandasnumpypvfactors (for bifacial modeling)matplotlibExamplesFull Example String Size calculationThe following code runs a standard string size calculation. This file is saved in the repository as 'example_vocmax_calculation.py'."""This script shows an example calculation for calculating the maximumstring length allowed in a particular location.The method proceeds in the following steps- Choose module parameters- Choose racking method- Set maximum allowable string voltage.- Import weather data- Run the calculation- Plot."""importnumpyasnpimportmatplotlibmatplotlib.use('TkAgg')importmatplotlib.pyplotaspltimportpandasaspdimportvocmaximporttime# ------------------------------------------------------------------------------# Choose Module Parameters# ------------------------------------------------------------------------------# Option 1. If the module is in the CEC database, then can retrieve parameters.cec_modules=vocmax.cec_modulesmodule_of_choice=cec_modules.keys()[0]cec_parameters=cec_modules[module_of_choice].to_dict()# Create SAPM parameters from CEC parameters.sapm_parameters=vocmax.cec_to_sapm(cec_parameters)# Calculate extra module parameters for your information:module={**sapm_parameters,**cec_parameters}# AOI loss model controls reflection from glass at non-normal incidence angles.# Can be 'ashrae' or 'no_loss'module['aoi_model']='ashrae'module['ashrae_iam_param']=0.05module['is_bifacial']=False"""# Option 2. Or can build a dictionary of parameters manually. Note that in order# to calculate MPP, it is necessary to include the CEC parameters: alpha_sc,# a_ref, I_L_ref, I_o_ref, R_sh_ref, R_s, and Adjust.module = {# Number of cells in series in each module.'cells_in_series': 60,# Open circuit voltage at reference conditions, in Volts.'Voco': 37.2,# Temperature coefficient of Voc, in Volt/C'Bvoco': -0.127,# Short circuit current, in Amp'Isco': 8.09,# Short circuit current temperature coefficient, in Amp/C'alpha_sc': 0.0036,# Module efficiency, unitless'efficiency': 0.15,# Diode Ideality Factor, unitless'n_diode': 1.2,# Fracion of diffuse irradiance used by the module.'FD': 1,# Whether the module is bifacial'is_bifacial': True,# Ratio of backside to frontside efficiency for bifacial modules. Only used if 'is_bifacial'==True'bifaciality_factor': 0.7,# AOI loss model'aoi_model':'ashrae',# AOI loss model parameter.'ashrae_iam_param': 0.05}"""is_cec_module='a_ref'inmoduleprint('\n** Module parameters **')print(pd.Series(module))# ------------------------------------------------------------------------------# Choose Racking Method# ------------------------------------------------------------------------------# Racking parameters for single axis tracking (fixed tilt parameters are below).racking_parameters={# Racking type, can be 'single_axis' or 'fixed_tilt''racking_type':'single_axis',# The tilt of the axis of rotation with respect to horizontal, in degrees'axis_tilt':0,# Compass direction along which the axis of rotation lies. Measured in# degrees East of North'axis_azimuth':0,# Maximum rotation angle of the one-axis tracker from its horizontal# position, in degrees.'max_angle':90,# Controls whether the tracker has the capability to “backtrack” to avoid# row-to-row shading. False denotes no backtrack capability. True denotes# backtrack capability.'backtrack':True,# A value denoting the ground coverage ratio of a tracker system which# utilizes backtracking; i.e. the ratio between the PV array surface area# to total ground area.'gcr':2.0/7.0,# Bifacial model can be 'proportional' or 'pvfactors''bifacial_model':'proportional',# Proportionality factor determining the backside irradiance as a fraction# of the frontside irradiance. Only used if 'bifacial_model' is# 'proportional'.'backside_irradiance_fraction':0.2,# Ground albedo'albedo':0.25}# Example racking parameters for fixed tilt (only use one racking_parameters,# comment the other one out!)"""racking_parameters = {'racking_type': 'fixed_tilt',# Tilt of modules from horizontal.'surface_tilt': 30,# 180 degrees orients the modules towards the South.'surface_azimuth': 180,# Ground albedo'albedo':0.25}"""# Additionally, here is an example set of racking parameters for full bifacial# modeling. Make sure 'is_bifacial' is True in the module parameters. Full# bifacial modeling takes about 10 minutes depending on the exact configuration.# See documentation for pvfactors for additional description of parameters."""racking_parameters = {# Racking type, can be 'single_axis' or 'fixed_tilt''racking_type': 'single_axis',# The tilt of the axis of rotation with respect to horizontal, in degrees'axis_tilt': 0,# Compass direction along which the axis of rotation lies. Measured in# degrees East of North'axis_azimuth': 0,# Maximum rotation angle of the one-axis tracker from its horizontal# position, in degrees.'max_angle': 90,# Controls whether the tracker has the capability to “backtrack” to avoid# row-to-row shading. False denotes no backtrack capability. True denotes# backtrack capability.'backtrack': True,# A value denoting the ground coverage ratio of a tracker system which# utilizes backtracking; i.e. the ratio between the PV array surface area# to total ground area.'gcr': 2.0 / 7.0,# Ground albedo'albedo':0.25,# bifacial model can be 'pfvactors' or 'simple''bifacial_model': 'pvfactors',# number of pv rows'n_pvrows': 3,# Index of row to use backside irradiance for'index_observed_pvrow': 1,# height of pvrows (measured at center / torque tube)'pvrow_height': 1,# width of pvrows'pvrow_width': 1,# azimuth angle of rotation axis'axis_azimuth': 0.,# pv row front surface reflectivity'rho_front_pvrow': 0.01,# pv row back surface reflectivity'rho_back_pvrow': 0.03,# Horizon band angle.'horizon_band_angle': 15,}"""# Sandia thermal model can be a string for using default coefficients or the# parameters can be set manually. Parameters are described in [1].## [1] D.L. King, W.E. Boyson, J.A. Kratochvill. Photovoltaic Array Performance# Model. Sand2004-3535 (2004).thermal_model={'named_model':'open_rack_glass_polymer',# Temperature of open circuit modules is higher, specify whether to include# this effect.'open_circuit_rise':True}# Or can set thermal model coefficients manually:"""thermal_model = {'named_model': 'explicit','a':-3.56,'b':-0.075,'deltaT':3,'open_circuit_rise':True}"""print('\n** Racking parameters **')print(pd.Series(racking_parameters))# ------------------------------------------------------------------------------# Max string length# ------------------------------------------------------------------------------# Max allowable string voltage, for determining string length. Typically this# number is determined by the inverter.string_design_voltage=1500# ------------------------------------------------------------------------------# Import weather data# ------------------------------------------------------------------------------# Get the weather data.print("\nImporting weather data...")# Define the lat, lon of the location (this location is preloaded and does not# require an API key)lat,lon=37.876,-122.247# Get an NSRDB api key for any point but the preloaded one (this api key will# not work, you need to get your own which will look like it.)api_key='BP2hICfC0ZQ2PT6h4xaU3vc4GAadf39fasdsPbZN'# Get weather data (takes a few minutes, result is cached for quick second calls).weather,info=vocmax.get_weather_data(lat,lon,api_key=api_key)# Option 2: Get weather data from a series of NSRDB csv files."""weather_data_directory = 'vocmax/NSRDB_sample'weather, info = vocmax.import_nsrdb_sequence(weather_data_directory)"""# Make sure that the weather data has the correct fields for pvlib.weather=weather.rename(columns={'DNI':'dni','DHI':'dhi','GHI':'ghi','Temperature':'temp_air','Wind Speed':'wind_speed'})# ------------------------------------------------------------------------------# Simulate system# ------------------------------------------------------------------------------# Run the calculation.print('Running Simulation...')t0=time.time()df=vocmax.simulate_system(weather,info,module,racking_parameters,thermal_model)print('Simulation time:{:1.2f}'.format(time.time()-t0))# Calculate max power voltage, only possible if using CEC database for module parameters.ifis_cec_module:_,df['v_mp'],_=vocmax.sapm_mpp(df['effective_irradiance'],df['temp_cell'],module)# ------------------------------------------------------------------------------# Calculate String Size# ------------------------------------------------------------------------------# IMPORTANT: one must add the ASHRAE spreadsheet to this file in order to# automatically calucate traditional values using ASHRAE design conditions.ashrae_available=vocmax.ashrae_is_design_conditions_available()ifnotashrae_available:print("""** IMPORTANT ** add the ASHRAE design conditions spreadsheet to thisdirectory in order to get ASHRAE design.""")# Look up weather data uncertainty safety factor at the point of interest.temperature_error=vocmax.get_nsrdb_temperature_error(info['Latitude'],info['Longitude'])# Calculate weather data safety factor using module Voc temperature coefficientBeta_Voco_fraction=np.abs(module['Bvoco'])/module['Voco']weather_data_safety_factor=np.max([0,temperature_error*Beta_Voco_fraction])# Calculate propensity for extreme temperature fluctuations.extreme_cold_delta_T=vocmax.calculate_mean_yearly_min_temp(df.index,df['temp_air'])-df['temp_air'].min()# Compute safety factor for extreme cold temperaturesextreme_cold_safety_factor=extreme_cold_delta_T*Beta_Voco_fraction# Add up different contributions to obtain an overall safety factorsafety_factor=weather_data_safety_factor+0.016print('Total Safety Factor:{:1.1%}'.format(safety_factor))# Calculate string length.voc_summary=vocmax.make_voc_summary(df,info,module,string_design_voltage=string_design_voltage,safety_factor=safety_factor)print('Simulation complete.')# Make a csv file for saving simulation parameterssummary_text=vocmax.make_simulation_summary(df,info,module,racking_parameters,thermal_model,string_design_voltage,safety_factor)# Save the summary csv to file.summary_file='out.csv'withopen(summary_file,'w')asf:f.write(summary_text)print('\n** Voc Results **')print(voc_summary[['max_module_voltage','safety_factor','string_length','Cell Temperature','POA Irradiance']].to_string())# Calculate some IV curves if we are using CEC database.ifis_cec_module:irradiance_list=[200,400,600,800,1000]iv_curve=[]foreinirradiance_list:ret=vocmax.calculate_iv_curve(e,25,cec_parameters)ret['effective_irradiance']=eiv_curve.append(ret)# ------------------------------------------------------------------------------# Plot results# ------------------------------------------------------------------------------pd.plotting.register_matplotlib_converters()fig_width=6fig_height=4max_pos=np.argmax(np.array(df['v_oc']))plot_width=300# Plot Voc vs. timeplot_key=['v_oc','ghi','effective_irradiance','temp_air']plot_ylabel=['Voc (V)','GHI (W/m2)','POA Irradiance (W/m2)','Air Temperature (C)']forjinrange(len(plot_key)):plt.figure(j,figsize=(fig_width,fig_height))plt.clf()plt.plot(df.index[max_pos-plot_width:max_pos+plot_width],df[plot_key[j]][max_pos-plot_width:max_pos+plot_width])ylims=np.array(plt.ylim())plt.plot([df.index[max_pos],df.index[max_pos]],ylims)plt.ylabel(plot_ylabel[j])plt.show()# Plot Voc histogramplt.figure(11,figsize=(fig_width,fig_height))plt.clf()voc_hist_x,voc_hist_y=vocmax.make_voc_histogram(df,info)plt.plot(voc_hist_x,voc_hist_y)plt.xlabel('Voc (Volts)')plt.ylabel('hrs/year')forkeyinvoc_summary.index:if('ASHRAE'inkeyandashrae_available)or('ASHRAE'notinkey):plt.plot(voc_summary['max_module_voltage'][key]*np.array([1,1]),[0,10],label=key)plt.show()plt.legend()# Plot IV curveifis_cec_module:plt.figure(12)plt.clf()forjinrange(len(iv_curve)):plt.plot(iv_curve[j]['v'],iv_curve[j]['i'])plt.xlabel('Voltage (V)')plt.ylabel('Current (A)')plt.grid()# Scatter plot of Temperature/Irradiance where Voc is highest.plt.figure(13)plt.clf()cax=df['v_oc']>np.percentile(df['v_oc'],99.9)plt.plot(df.loc[:,'effective_irradiance'],df.loc[:,'temp_cell'],'.',label='all data')plt.plot(df.loc[cax,'effective_irradiance'],df.loc[cax,'temp_cell'],'.',label='Voc>P99.9')poa_smooth=np.linspace(1,1100,200)T_smooth=vocmax.sapm_temperature_to_get_voc(poa_smooth,np.percentile(df['v_oc'],99.9),Voco=module['Voco'],Bvoco=module['Bvoco'],diode_factor=module['n_diode'],cells_in_series=module['cells_in_series'])plt.plot(poa_smooth,T_smooth)plt.xlabel('POA Irradiance (W/m^2)')plt.ylabel('Cell Temperature (C)')plt.legend(loc='upper left')# plt.xlim([0,1000])plt.show()Set module parametersModule parameters are set using a dictionary.sapm_parameters={'cells_in_series':96,'n_diode':1.2,'Voco':69.7015,'Bvoco':-0.159,'FD':1}Get weather dataThe following code will download weather data from thenational solar radiation database (NSRDB)for the lat/lon coordinate.importvocmax# Define the lat, lon of the location and the year (this one is preloaded)lat,lon=37.876,-122.247# You must request an NSRDB api key from the link aboveapi_key='apsdofijasdpafkjweo21u09u1082h8h2d2d'# not a real key -- get your own!weather,info=vocmax.get_weather_data(lat,lon,api_key=api_key)Another possibility is to download data directly from the NSRDB map viewer.Get NSRDB safety factorThe safety factor to use depends on location, here is how to look it up.importvocmax# Define the lat, long of the locationlat,lon=37.876,-91# Find the max temperature error for the locationtemperature_error=vocmax.get_nsrdb_temperature_error(lat,lon)# Temperature coefficient of Voc divided by Voco in 1/C.temperature_coefficient_of_voc=0.0035# Find the safety factorsafety_factor=temperature_error*temperature_coefficient_of_vocprint('Safety Factor for NSRDB weather data:{:.2%}'.format(safety_factor))Load ASHRAE dataDue to copyright, the ASHRAE design conditions filemust be purchased separately, directly from ASHRAE.
The weather data viewer DVD, version 6.0 is available at:https://www.techstreet.com/ashrae/standards/weather-data-viewer-dvd-version-6-0?ashrae_auth_token=12ce7b1d-2e2e-472b-b689-8065208f2e36&product_id=1949790Within this DVD is a file titled "2017DesignConditions_s.xlsx" One way to load this file is to place it in the current directory.An exmaple of loading the ASHRAE dataset isimportvocmaxashrae=vocmax.ashrae_get_design_conditions()TodoChange the voc summary to be Vmax rather than Voc.Copyright noticeString Length Calculator Copyright (c) 2020, The Regents of the University of
California, through Lawrence Berkeley National Laboratory (subject to receipt of
any required approvals from the U.S. Dept. of Energy).  All rights reserved.If you have questions about your rights to use or distribute this software,
please contact Berkeley Lab's Intellectual Property Office atIPO@lbl.gov.NOTICE.  This Software was developed under funding from the U.S. Department
of Energy and the U.S. Government consequently retains certain rights.  As
such, the U.S. Government has been granted for itself and others acting on
its behalf a paid-up, nonexclusive, irrevocable, worldwide license in the
Software to reproduce, distribute copies to the public, prepare derivative
works, and perform publicly and display publicly, and to permit others to do so.