def test_run(): result = script.RESULT_FAIL trigger = None inv = None pv = None disable = None power_max = 3050 try: ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') ts.log('Scanning EUT') try: inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % (e)) try: inv.settings.read() power_max = 3050 ts.log('Inverter maximum power = %d W' % (power_max)) except Exception, e: raise('Unable to get WMax setting: %s' % str(e))
def test_run(): result = script.RESULT_FAIL das = None trigger = None inv = None pv = None disable = None try: ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') # Sandia Test Protocol: Communication is established between the Utility Management System Simulator # and EUT ts.log('Scanning EUT') try: inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % (e)) verification_delay = 5 pretest_delay = 0 # Make sure the EUT is on and operating ts.log( 'Verifying EUT is in connected state. Waiting up to %d seconds for EUT to begin power export.' % (verification_delay + pretest_delay)) if verify_initial_conn_state( inv, state=inverter.CONN_CONNECT, time_period=verification_delay + pretest_delay, das=das) is False: inv.controls.read() inv.controls.WMaxLimPct = 100 inv.controls.write() try: inv.settings.read() power_max = int(inv.settings.WMax) ts.log('Inverter maximum power = %d W' % (power_max)) except Exception, e: raise ('Unable to get WMax setting: %s' % str(e))
def test_run(): result = script.RESULT_FAIL f = None # file for saving the data try: # EUT communication parameters ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') # Data parameters duration = ts.param_value('data.duration') interval = ts.param_value('data.interval') parameters = ts.param_value('data.parameters') filename = ts.param_value('data.filename') # Sandia Test Protocol: Communication is established between the Utility Management System Simulator and EUT ts.log('Scanning EUT') try: inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % e) # PARSE PARAMETERS ts.log('Configuring the data capture for the following channels: %s' % parameters) formattedchans = parameters.replace(", ", "\t") formattedchans = formattedchans.replace(",", "\t") formattedchans = 'Time\tTotal_Time\t%s' % formattedchans # add python time and absolute time to channels ts.log('Channel string: %s' % formattedchans) channels = formattedchans.split() results_dir = os.path.dirname(__file__)[:-7] + 'Results' + os.path.sep if not os.path.isdir(results_dir): os.mkdir(results_dir) csv_filename = '%s%s.tsv' % (results_dir, filename) ts.log('Saving to file: %s' % csv_filename) f = open(csv_filename, 'w') try: f.write("%s\n" % formattedchans) except Exception, e: ts.log_error('Unable to save channel list to file: %s' % csv_filename)
def test_run(): result = script.RESULT_FAIL gsim = None ts.log_debug(' ') ts.log_debug( 'Note: Please remove the Grid Guard Code from the test configuration after ' 'it has been to run to avoid exposing your Grid Guard Code to others.') ts.log_debug(' ') try: ipaddr = ts.param_value('gg.ipaddr') new_gg = ts.param_value('gg.code') # register = ts.param_value('gg.register') # port = ts.param_value('gg.port') # comm_id = ts.param_value('gg.id') register = 43090 port = 502 comm_id = 3 if not new_gg or new_gg == 'None': raise script.ScriptFail('No Grid Guard Code specified.') device = client.ModbusClientDeviceTCP(comm_id, ipaddr, port) data = device.read(register, 2) gg = util.data_to_u32(data) ts.log('Current grid guard code: %s' % hex(gg)) if gg == 0: ts.log('Original grid guard was not enabled') else: ts.log('Original grid guard was enabled') device.write(register, util.u32_to_data(int(new_gg))) data = device.read(register, 2) gg = util.data_to_u32(data) ts.log('Updated grid guard code: = %s' % hex(gg)) if gg == 0: ts.log_warning('Current grid guard is not enabled') result = script.RESULT_FAIL else: ts.log('Current grid guard is enabled') result = script.RESULT_PASS except script.ScriptFail, e: reason = str(e) if reason: ts.log_error(reason)
def get_ac_freq_pct(inv, freq_ref=60., das=None): try: #only use the das (data acquisition system) if it is available if das: das.read() gridFraw = das.ac_freq # without the das use the EUT to report the power level else: inv.inverter.read() gridFraw = float(inv.inverter.Hz) inv.settings.read() Freq_nom = float(freq_ref) return (gridFraw / Freq_nom) * 100.0 except Exception, e: raise script.ScriptFail('Unable to get ac freq from das or EUT: %s' % str(e))
def get_ac_voltage_pct(inv, data=None): try: #only use the das (data acquisition system) if it is available if data: data.read() gridVraw = data.ac_freq # without the das use the EUT to report the power level else: inv.inverter.read() gridVraw = float(inv.inverter.PhVphA) inv.settings.read() Vgrid_nom = float(inv.settings.VRef) return (gridVraw / Vgrid_nom) * 100.0 except Exception, e: raise script.ScriptFail( 'Unable to get ac voltage from das or EUT: %s' % str(e))
def test_run(): result = script.RESULT_FAIL daq = None pv = None grid = None try: # read test parameters tests_param = ts.param_value('eut.tests') s_rated = ts.param_value('eut.s_rated') p_rated = ts.param_value('eut.p_rated') # v_dc_min = ts.param_value('eut.v_dc_min') ## # v_dc_max = ts.param_value('eut.v_dc_max') ## v_nom = ts.param_value('eut.v_nom') v_min = ts.param_value('eut.v_min') v_max = ts.param_value('eut.v_max') v_msa = ts.param_value('eut.v_msa') var_msa = ts.param_value('eut.var_msa') var_ramp_max = ts.param_value('eut.var_ramp_max') q_max_cap = ts.param_value('eut.q_max_cap') q_max_ind = ts.param_value('eut.q_max_ind') k_var_max = ts.param_value('eut.k_var_max') deadband_min = ts.param_value('eut.vv_deadband_min') deadband_max = ts.param_value('eut.vv_deadband_max') t_settling = ts.param_value('eut.vv_t_settling') # power_priority = ts.param_value('eut.power_priority') p_min_pct = ts.param_value('srd.vv_p_min_pct') p_max_pct = ts.param_value('srd.vv_p_max_pct') k_var_min_srd = ts.param_value('srd.vv_k_var_min') try: k_var_min = float(k_var_min_srd) except ValueError: k_var_min = None segment_point_count = ts.param_value('srd.vv_segment_point_count') # set power priorities to be tested power_priorities = [] if ts.param_value('vv.pp_active') == 'Enabled': power_priorities.append('Active') if ts.param_value('vv.pp_reactive') == 'Enabled': power_priorities.append('Reactive') # default power range p_min = p_rated * .2 p_max = p_rated # use values from SRD, if supplied if p_min_pct is not None: p_min = p_rated * (p_min_pct / 100.) if p_max is not None: p_max = p_rated * (p_max_pct / 100.) p_avg = (p_min + p_max) / 2 q_min_cap = q_max_cap / 4 q_min_ind = q_max_ind / 4 v_dev = min(v_nom - v_min, v_max - v_nom) # calculate k_var_min if not suppied in the SRD if k_var_min is None: k_var_min = (q_max_cap / 4) / (v_dev - deadband_max / 2) k_var_avg = (k_var_min + k_var_max) / 2 deadband_avg = (deadband_min + deadband_max) / 2 # list of active tests active_tests = [] if ts.param_value('vv.test_1') == 'Enabled': active_tests.append(1) if ts.param_value('vv.test_2') == 'Enabled': active_tests.append(2) if ts.param_value('vv.test_3') == 'Enabled': active_tests.append(3) # create test curves based on input parameters tests = [0] * 4 ''' The script only sets points 1-4 in the EUT, however they use v[0] and v[5] for testing purposes to define n points on the line segment to verify the reactive power ''' # Test 1 - Characteristic 1 "Most Aggressive" Curve q = [0] * 5 q[1] = q_max_cap # Q1 q[2] = 0 q[3] = 0 q[4] = q_max_ind v = [0] * 6 v[2] = v_nom - deadband_min / 2 v[1] = v[2] - abs(q[1]) / k_var_max v[0] = v_min v[3] = v_nom + deadband_min / 2 v[4] = v[3] + abs(q[4]) / k_var_max v[5] = v_max tests[1] = [list(v), list(q)] # Test 2 - Characteristic 2 "Average" Curve q = [0] * 5 q[1] = q_max_cap * .5 q[2] = 0 q[3] = 0 q[4] = q_max_ind * .5 v = [0] * 6 v[2] = v_nom - deadband_avg / 2 v[1] = v[2] - abs(q[1]) / k_var_avg v[0] = v_min v[3] = v_nom + deadband_avg / 2 v[4] = v[3] + abs(q[4]) / k_var_avg v[5] = v_max tests[2] = [list(v), list(q)] # Test 3 - Characteristic 3 "Least Aggressive" Curve q = [0] * 5 q[1] = q_min_cap q[2] = 0 q[3] = 0 q[4] = q_min_ind v = [0] * 6 v[0] = v_min v[2] = v_nom - deadband_min / 2 v[3] = v_nom + deadband_min / 2 if k_var_min == 0: v[1] = 0.99 * v[2] v[4] = 1.01 * v[3] else: v[1] = v[2] - abs(q[1]) / k_var_min v[4] = v[3] + abs(q[4]) / k_var_min v[5] = v_max tests[3] = [list(v), list(q)] ts.log('tests = %s' % (tests)) # list of tuples each containing (power level as % of max, # of test at power level) power_levels = [] count = ts.param_value('vv.n_r_100') if count > 0: power_levels.append((1, count)) count = ts.param_value('vv.n_r_66') if count > 0: power_levels.append((.66, count)) count = ts.param_value('vv.n_r_min') if count > 0: power_levels.append(((p_min / p_max), count)) ''' 1) Connect the EUT and measurement equipment according to the requirements in Sections 4 and 5 of IEEE Std 1547.1-2005 and specifications provided by the manufacturer. ''' ''' 2) Set all AC source parameters to the nominal operating conditions for the EUT. Frequency is set at nominal and held at nominal throughout this test. Set the EUT power to Pmax. ''' # grid simulator is initialized with test parameters and enabled grid = gridsim.gridsim_init(ts) # pv simulator is initialized with test parameters and enabled pv = pvsim.pvsim_init(ts) pv.power_set(p_max) pv.power_on() # initialize data acquisition daq = das.das_init(ts) ''' 3) Turn on the EUT. Set all L/HVRT parameters to the widest range of adjustability possible with the VV Q(V) enabled. The EUT's range of disconnect settings may depend on which function(s) are enabled. ''' # it is assumed the EUT is on eut = der.der_init(ts) eut.config() for priority in power_priorities: ''' 4) If the EUT has the ability to set 'Active Power Priority' or 'Reactive Power Priority', select Priority being evaluated. ''' ''' 5) Set the EUT to provide reactive power according to the Q(V) characteristic defined in Test 1 in Table SA13.1. ''' for test in active_tests: ts.log('Starting test - %s' % (test_labels[test])) # create voltage settings along all segments of the curve v = tests[test][0] q = tests[test][1] voltage_points = voltage_sample_points(v, segment_point_count) ts.log('Voltage test points = %s' % (voltage_points)) # set dependent reference type if priority == 'Active': dept_ref = 'VAR_AVAL_PCT' elif priority == 'Reactive': dept_ref = 'VAR_MAX_PCT' else: raise script.ScriptFail( 'Unknown power priority setting: %s') # set volt/var curve eut.volt_var_curve( 1, params={ # convert curve points to percentages and set DER parameters 'v': [ v[1] / v_nom * 100.0, v[2] / v_nom * 100.0, v[3] / v_nom * 100.0, v[4] / v_nom * 100.0 ], 'var': [ q[1] / q_max_cap * 100.0, q[2] / q_max_cap * 100.0, q[3] / q_max_cap * 100.0, q[4] / q_max_cap * 100.0 ], 'Dept_Ref': dept_ref }) # enable volt/var curve eut.volt_var(params={'Ena': True, 'ActCrv': 1}) for level in power_levels: power = level[0] # set input power level ts.log( ' Setting the input power of the PV simulator to %0.2f' % (p_max * power)) pv.power_set(p_max * power) count = level[1] for i in xrange(1, count + 1): ''' 6) Set the EPS voltage to a value greater than V4 for a duration of not less than the settling time. ''' ''' 7) Begin recording the time domain response of the EUT AC voltage and current, and DC voltage and current. Step down the simulated EPS voltage (the rise/fall time of simulated EPS voltage shall be < 1 cyc or < 1% of settling time) until at least three points are recorded in each line segment of the characteristic curve or the EUT trips from the LVRT must trip requirements. Continue recording the time domain response for at least twice the settling time after each voltage step. ''' ''' 8) Set all AC source parameters to the nominal operating conditions for the EUT. Frequency is set at nominal and held at nominal throughout this test. Set the EUT power to Pmax then repeat Repeat Step (7), except raising, instead of dropping, the simulated EPS voltage (the rise/fall time of simulated EPS voltage shall be < 1 cyc or < 1% of settling time) until at least three points are recorded in each line segment of the characteristic curve or the EUT trips from HVRT must trip requirements. ''' # test voltage high to low # start capture test_str = 'VV_high_%s_%s_%s' % (str(test), str(power), str(i)) ts.log( 'Starting data capture for test %s, testing voltage high to low, with %s, ' 'Power = %s%%, and sweep = %s' % (test_str, test_labels[test], power * 100., i)) daq.data_capture(True) for v in reversed(voltage_points): ts.log( ' Setting the grid voltage to %0.2f and waiting %0.1f seconds.' % (v, t_settling)) grid.voltage(v) ts.sleep(t_settling) # stop capture and save daq.data_capture(False) ds = daq.data_capture_dataset() filename = '%s.csv' % (test_str) ds.to_csv(ts.result_file_path(filename)) ts.result_file(filename) ts.log('Saving data capture') # test voltage low to high # start capture test_str = 'VV_low_%s_%s_%s' % (str(test), str(power), str(i)) ts.log( 'Starting data capture for test %s, testing voltage low to high, with %s, ' 'Power = %s%%, and sweep = %s' % (test_str, test_labels[test], power * 100., i)) daq.data_capture(True) for v in voltage_points: ts.log( ' Setting the grid voltage to %0.2f and waiting %0.1f seconds.' % (v, t_settling)) grid.voltage(v) ts.sleep(t_settling) # stop capture and save daq.data_capture(False) ds = daq.data_capture_dataset() filename = '%s.csv' % (test_str) ds.to_csv(ts.result_file_path(filename)) ts.result_file(filename) ts.log('Saving data capture') ''' 9) Repeat test Steps (6) - (8) at power levels of 20 and 66%; as described by the following: a) For the 20% test, the EUT output power set to 20% of its Prated nominal rating b) For the 66% test the test input source is to be adjusted to limit the EUT output power to a value between 50% and 95% of rated output power. c) The 66% power level, as defined in (b), shall be repeated for a total of five sweeps of the Q(V) curve to validate consistency. ''' ''' 10) Repeat steps (6) - (9) for the remaining tests in Table SA13.1. Other than stated in (9) (c), the required number of sweeps for each of these repetitions is three. In the case of EUT without adjustable (V, Q) points, this step may be eliminated. ''' ''' 11) If the EUT has the ability to set 'Active Power Priority' and 'Reactive Power Priority', select the other Priority, return the simulated EPS voltage to nominal, and repeat steps (5) - (10). ''' result = script.RESULT_COMPLETE except script.ScriptFail, e: reason = str(e) if reason: ts.log_error(reason)
def test_run(): result = script.RESULT_PASS daq = None pv = None grid = None chil = None result_summary = None p_max = None v_nom_grid = None result_params = { 'plot.title': 'title_name', 'plot.x.title': 'Time (secs)', 'plot.x.points': 'TIME', 'plot.y.points': 'AC_P_1, AC_Q_1, Q_ACT, Q_TARGET', 'plot.Q_ACT.point': 'True', 'plot.Q_TARGET.point': 'True', 'plot.Q_TARGET.min_error': 'Q_MIN_ERROR', 'plot.Q_TARGET.max_error': 'Q_MAX_ERROR', 'plot.Q_MIN.point': 'True', 'plot.Q_MAX.point': 'True', 'plot.V_ACT.point': 'True', 'plot.V_TARGET.point': 'True', 'plot.y.title': 'Reactive Power (var)', 'plot.y2.points': 'AC_VRMS_1, V_ACT, V_TARGET', 'plot.y2.title': 'Voltage (V)' } try: # read test parameters tests_param = ts.param_value('eut_vv.tests') s_rated = ts.param_value('eut_vv.s_rated') p_rated = ts.param_value('eut_vv.p_rated') var_rated = ts.param_value('eut_vv.var_rated') # v_dc_min = ts.param_value('eut_vv.v_dc_min') ## # v_dc_max = ts.param_value('eut_vv.v_dc_max') ## v_nom = ts.param_value('eut_vv.v_nom') v_min = ts.param_value('eut_vv.v_min') v_max = ts.param_value('eut_vv.v_max') v_msa = ts.param_value('eut_vv.v_msa') var_msa = ts.param_value('eut_vv.var_msa') var_ramp_max = ts.param_value('eut_vv.var_ramp_max') q_max_over = ts.param_value('eut_vv.q_max_over') q_max_under = ts.param_value('eut_vv.q_max_under') k_var_max = ts.param_value('eut_vv.k_var_max') deadband_min = ts.param_value('eut_vv.vv_deadband_min') deadband_max = ts.param_value('eut_vv.vv_deadband_max') t_settling = ts.param_value('eut_vv.vv_t_settling') phases = ts.param_value('eut_vv.phases') if phases == 'Single Phase': sc_points = ['V_ACT_1', 'Q_ACT_1', # 'V_ACT_PU_1', 'Q_ACT_PU_1', 'V_TARGET_1', 'Q_TARGET_1', 'Q_MIN_1', 'Q_MAX_1', 'Q_MIN_ERROR_1', 'Q_MAX_ERROR_1'] else: sc_points = ['V_ACT_1', 'Q_ACT_1', # 'V_ACT_PU_1', 'Q_ACT_PU_1', 'V_TARGET_1', 'Q_TARGET_1', 'Q_MIN_1', 'Q_MAX_1', 'Q_MIN_ERROR_1', 'Q_MAX_ERROR_1', 'V_ACT_2', 'Q_ACT_2', # 'V_ACT_PU_2', 'Q_ACT_PU_2', 'V_TARGET_2', 'Q_TARGET_2', 'Q_MIN_2', 'Q_MAX_2', 'Q_MIN_ERROR_2', 'Q_MAX_ERROR_2', 'V_ACT_3', 'Q_ACT_3', # 'V_ACT_PU_3', 'Q_ACT_PU_3', 'V_TARGET_3', 'Q_TARGET_3', 'Q_MIN_3', 'Q_MAX_3', 'Q_MIN_ERROR_3', 'Q_MAX_ERROR_3'] p_min_pct = ts.param_value('srd.vv_p_min_pct') p_max_pct = ts.param_value('srd.vv_p_max_pct') k_var_min_srd = ts.param_value('srd.vv_k_var_min') try: k_var_min = float(k_var_min_srd) except ValueError: k_var_min = None segment_point_count = ts.param_value('srd.vv_segment_point_count') # set power priorities to be tested power_priorities = [] if ts.param_value('vv.pp_active') == 'Enabled': power_priorities.append('Active') if ts.param_value('vv.pp_reactive') == 'Enabled': power_priorities.append('Reactive') # default power range p_min = p_rated * .2 p_max = p_rated # use values from SRD, if supplied if p_min_pct is not None: p_min = p_rated * (p_min_pct/100.) if p_max is not None: p_max = p_rated * (p_max_pct/100.) p_avg = (p_min + p_max)/2 # q_max_under should be negative if q_max_under > 0: q_max_under *= -1 q_min_over = q_max_over/4 q_min_under = q_max_under/4 v_dev = min(v_nom - v_min, v_max - v_nom) # calculate k_var_min if not supplied in the SRD if k_var_min is None: k_var_min = (q_max_over/4)/(v_dev - deadband_max/2) k_var_avg = (k_var_min + k_var_max)/2 deadband_avg = (deadband_min + deadband_max)/2 # list of active tests test_1_enabled = test_2_enabled = test_3_enabled = False active_tests = [] if ts.param_value('vv.test_1') == 'Enabled': test_1_enabled = True active_tests.append(1) if ts.param_value('vv.test_2') == 'Enabled': test_2_enabled = True active_tests.append(2) if ts.param_value('vv.test_3') == 'Enabled': test_3_enabled = True active_tests.append(3) # check for specified test curve spec_curve = False spec_curve_v = [] spec_curve_q = [] spec_curve_config = False if ts.param_value('vv.spec_curve') == 'Enabled': spec_curve = True spec_curve_v_str = ts.param_value('vv.spec_curve_v').split(',') if len(spec_curve_v_str) != 4: ts.fail('Invalid specified curve V point count (must be 4): %s' % len(spec_curve_v)) spec_curve_v = [float(i) for i in spec_curve_v_str] spec_curve_q_str = ts.param_value('vv.spec_curve_q').split(',') if len(spec_curve_q_str) != 4: ts.fail('Invalid specified curve Q point count (must be 4): %s' % len(spec_curve_q)) spec_curve_q = [float(i) for i in spec_curve_q_str] if ts.param_value('vv.spec_curve_config') == 'Enabled': spec_curve_config = True # create test curves based on input parameters tests = [0] * 5 ''' The script only sets points 1-4 in the EUT, however they use v[0] and v[5] for testing purposes to define n points on the line segment to verify the reactive power ''' # Test 1 - Characteristic 1 "Most Aggressive" Curve if test_1_enabled: q = [0] * 6 q[0] = q_max_over # Q1 q[1] = q_max_over q[2] = 0 q[3] = 0 q[4] = q_max_under q[5] = q_max_under v = [0] * 6 v[2] = v_nom - deadband_min/2 v[1] = v[2] - abs(q[1])/k_var_max v[0] = v_min v[3] = v_nom + deadband_min/2 v[4] = v[3] + abs(q[4])/k_var_max v[5] = v_max tests[1] = [list(v), list(q), True] # Test 2 - Characteristic 2 "Average" Curve if test_2_enabled: q = [0] * 6 q[0] = q_max_over * .5 q[1] = q_max_over * .5 q[2] = 0 q[3] = 0 q[4] = q_max_under * .5 q[5] = q_max_under * .5 v = [0] * 6 v[2] = v_nom - deadband_avg/2 v[1] = v[2] - abs(q[1])/k_var_avg v[0] = v_min v[3] = v_nom + deadband_avg/2 v[4] = v[3] + abs(q[4])/k_var_avg v[5] = v_max tests[2] = [list(v), list(q), True] ts.log(v) # Test 3 - Characteristic 3 "Least Aggressive" Curve if test_3_enabled: q = [0] * 6 q[0] = q_min_over q[1] = q_min_over q[2] = 0 q[3] = 0 q[4] = q_min_under q[5] = q_min_under v = [0] * 6 v[0] = v_min v[2] = v_nom - deadband_max/2 v[3] = v_nom + deadband_max/2 if k_var_min == 0: v[1] = 0.99*v[2] v[4] = 1.01*v[3] else: v[1] = v[2] - abs(q[1])/k_var_min v[4] = v[3] + abs(q[4])/k_var_min v[5] = v_max tests[3] = [list(v), list(q), True] # Specified curve if spec_curve: q = [0] * 6 q[0] = spec_curve_q[0]/100 * q_max_over q[1] = q[0] q[2] = spec_curve_q[1]/100 * q_max_over q[3] = spec_curve_q[2]/100 * q_max_over q[4] = spec_curve_q[3]/100 * q_max_over q[5] = q[4] v = [0] * 6 v[0] = v_min v[1] = spec_curve_v[0]/100 * v_nom v[2] = spec_curve_v[1]/100 * v_nom v[3] = spec_curve_v[2]/100 * v_nom v[4] = spec_curve_v[3]/100 * v_nom v[5] = v_max tests[4] = [list(v), list(q), spec_curve_config] active_tests.append(4) ts.log('tests = %s' % (tests)) # list of tuples each containing (power level as % of max, # of test at power level) power_levels = [] count = ts.param_value('vv.n_r_100') if count > 0: power_levels.append((1, count)) count = ts.param_value('vv.n_r_66') if count > 0: power_levels.append((.66, count)) count = ts.param_value('vv.n_r_min') if count > 0: power_levels.append(((p_min/p_max), count)) ''' 1) Connect the EUT and measurement equipment according to the requirements in Sections 4 and 5 of IEEE Std 1547.1-2005 and specifications provided by the manufacturer. ''' ''' 2) Set all AC source parameters to the nominal operating conditions for the EUT. Frequency is set at nominal and held at nominal throughout this test. Set the EUT power to Pmax. ''' # initialize HIL environment, if necessary chil = hil.hil_init(ts) if chil is not None: chil.config() # grid simulator is initialized with test parameters and enabled ''' ts.log("here? return=========================") #params=eut.volt_var_curve() #ts.log(params) return result ''' grid = gridsim.gridsim_init(ts) grid.voltage(280) # wanbin # In cases where the grid simulator has voltage rise/loss on the line to the EUT or operates through a # transformer, the nominal voltage of the grid simulator won't be the same as the EUT and a correction # factor is applied. try: v_nom_grid = grid.v_nom_param except Exception, e: v_nom_grid = v_nom # pv simulator is initialized with test parameters and enabled pv = pvsim.pvsim_init(ts) pv.power_set(p_max) pv.power_on() # initialize data acquisition daq = das.das_init(ts, sc_points=sc_points) if phases == 'Single Phase': n_phase = 1 else: n_phase = 3 for ph in range(n_phase): ph_val = ph + 1 # phase names start at 1 (not zero) daq.sc['V_ACT_%i' % ph_val] = '' daq.sc['Q_ACT_%i' % ph_val] = '' # daq.sc['V_ACT_PU_%i' % ph_val] = '' # daq.sc['Q_ACT_PU_%i' % ph_val] = '' daq.sc['V_TARGET_%i' % ph_val] = '' daq.sc['Q_TARGET_%i' % ph_val] = '' daq.sc['Q_MIN_%i' % ph_val] = '' daq.sc['Q_MAX_%i' % ph_val] = '' daq.sc['Q_MIN_ERROR_%i' % ph_val] = '' daq.sc['Q_MAX_ERROR_%i' % ph_val] = '' ''' 3) Turn on the EUT. Set all L/HVRT parameters to the widest range of adjustability possible with the VV Q(V) enabled. The EUT's range of disconnect settings may depend on which function(s) are enabled. ''' # it is assumed the EUT is on eut = der.der_init(ts) if eut is not None: eut.config() eut.fixed_pf(params={'Ena': False}) settling_time = t_settling # open result summary file result_summary_filename = 'result_summary.csv' result_summary = open(ts.result_file_path(result_summary_filename), 'a+') ts.result_file(result_summary_filename) if n_phase == 1: result_summary.write('Result, Test Name, Power Priority, Power Level, Iteration, Var MSA, Dataset File,' 'Point Result, Var Actual, Var Target, Var Min Allowed, Var Max Allowed,' 'Voltage (pu), Total Reactive Power (pu)\n') else: result_summary.write('Result, Test Name, Power Priority, Power Level, Iteration, Var MSA, Dataset File,' 'Point Result 1, Var Actual 1, Var Target 1, Var Min Allowed 1, Var Max Allowed 1,' 'Point Result 2, Var Actual 2, Var Target 2, Var Min Allowed 2, Var Max Allowed 2,' 'Point Result 3, Var Actual 3, Var Target 3, Var Min Allowed 3, Var Max Allowed 3,' 'Average Voltage (pu), Total Reactive Power (pu)\n') for priority in power_priorities: ''' 4) If the EUT has the ability to set 'Active Power Priority' or 'Reactive Power Priority', select Priority being evaluated. ''' ''' 5) Set the EUT to provide reactive power according to the Q(V) characteristic defined in Test 1 in Table SA13.1. ''' for test in active_tests: ts.log('Starting test - %s' % (test_labels[test])) # create voltage settings along all segments of the curve v = tests[test][0] q = tests[test][1] v_points = sample_points(v, segment_point_count) ### q_points = sample_points(q, segment_point_count) q_points = [] q_min_points = [] q_max_points = [] for p in v_points: q_target, q_min, q_max = q_msa_range(p, v_msa, var_msa, tests[test][0], tests[test][1]) q_points.append(q_target) q_min_points.append(q_min) q_max_points.append(q_max) ts.log('Voltage test points = %s' % (v_points)) ts.log('Var test points = %s' % (q_points)) ts.log('Var min pass/fail limits = %s' % (q_min_points)) ts.log('Var max pass/fail limits = %s' % (q_max_points)) ''' q_msa_range(v_value, v_msa, q_msa, v, q) x = [] for p in v_points: x.append(v_q(p, tests[4][0], tests[4][1])) x.append(q_msa_range(p, v_msa, var_msa, tests[4][0], tests[4][1])) ts.log('v_q = %s' % (x)) ''' # set dependent reference type if priority == 'Active': dept_ref = 'VAR_AVAL_PCT' elif priority == 'Reactive': dept_ref = 'VAR_MAX_PCT' else: raise script.ScriptFail('Unknown power priority setting: %s') ts.log_debug({'v': [v[1]/v_nom*100.0, v[2]/v_nom*100.0, v[3]/v_nom*100.0, v[4]/v_nom*100.0], 'var': [q[1]/q_max_over*100.0, q[2]/q_max_over*100.0, q[3]/q_max_over*100.0, q[4]/q_max_over*100.0]}) # configure EUT if configure enabled if tests[test][2]: # set volt/var curve if eut is not None: eut.volt_var_curve(1, params={ # convert curve points to percentages and set DER parameters 'v': [round(v[1]/v_nom*100.0), round(v[2]/v_nom*100.0), round(v[3]/v_nom*100.0), round(v[4]/v_nom*100.0)], 'var': [round(q[1]/q_max_over*100.0), round(q[2]/q_max_over*100.0), round(q[3]/q_max_over*100.0), round(q[4]/q_max_over*100.0)], 'Dept_Ref': dept_ref, }) # enable volt/var curve and verify eut.volt_var(params={'ActCrv': 1, 'Ena': True}) parameters = eut.volt_var() ts.log_debug('EUT VV settings (readback): %s' % parameters) if parameters['Ena'] == False: ts.log_debug('Could not enable the VV function. Trying again in 3 seconds.') ts.sleep(3) eut.volt_var(params={'Ena': True}) parameters = eut.volt_var() ts.log_debug('EUT VV settings (readback): %s' % parameters) if parameters['Ena'] == False: ts.log_error('VV function is not enabled!') else: ts.log('VV function enabled. Proceeding with the test...') ''' ts.log("here? return=========================") #params=eut.volt_var_curve() #ts.log(params) return result ''' for level in power_levels: power = level[0] # set input power level ts.log(' Setting the input power of the PV simulator to %0.2f' % (p_max * power)) pv.power_set(p_max * power) count = level[1] for i in xrange(1, count + 1): ''' 6) Set the EPS voltage to a value greater than V4 for a duration of not less than the settling time. ''' ''' 7) Begin recording the time domain response of the EUT AC voltage and current, and DC voltage and current. Step down the simulated EPS voltage (the rise/fall time of simulated EPS voltage shall be < 1 cyc or < 1% of settling time) until at least three points are recorded in each line segment of the characteristic curve or the EUT trips from the LVRT must trip requirements. Continue recording the time domain response for at least twice the settling time after each voltage step. ''' ''' 8) Set all AC source parameters to the nominal operating conditions for the EUT. Frequency is set at nominal and held at nominal throughout this test. Set the EUT power to Pmax then repeat Repeat Step (7), except raising, instead of dropping, the simulated EPS voltage (the rise/fall time of simulated EPS voltage shall be < 1 cyc or < 1% of settling time) until at least three points are recorded in each line segment of the characteristic curve or the EUT trips from HVRT must trip requirements. ''' order_test = [('down', list(reversed(v_points)), list(reversed(q_points))), ('up', v_points, q_points)] for order in order_test: order_str = order[0] v_test_points = order[1] q_test_points = order[2] # start capture test_str = 'VV_%s_%s_%s_%s' % (str(test), str(int(power*100.)), order_str, str(i)) ts.log('Starting data capture for test %s, testing voltage from %s , with %s, ' 'Power = %s%%, and sweep = %s' % (order_str, test_str, test_labels[test], power*100., i)) filename = '%s.csv' % (test_str) test_passfail = 'Pass' daq.data_capture(True) for p in range(len(v_test_points)): v_target = v_test_points[p] q_target = q_test_points[p] ts.log(' Setting the grid voltage to %0.2f and waiting %0.1f seconds. ' 'Q_targ = %s' % (v_target, settling_time, q_target)) grid.voltage(v_target/v_nom * v_nom_grid) # capture a data sample with trigger enabled ts.sleep(settling_time) # get last voltage reading daq.data_sample() data = daq.data_capture_read() # Collect data from the end of the settling time v_act = [data.get('AC_VRMS_1')] q_act = [data.get('AC_Q_1')] p_act = [data.get('AC_P_1')] if phases != 'Single Phase': v_act.append(data.get('AC_VRMS_2')) v_act.append(data.get('AC_VRMS_3')) q_act.append(data.get('AC_Q_2')) q_act.append(data.get('AC_Q_3')) p_act.append(data.get('AC_P_2')) p_act.append(data.get('AC_P_3')) if v_act is None or q_act is None: ts.fail('Could not get data to record target information') # prepare pass/fail data passfail = [None, None, None] q_target = [0., 0., 0.] q_min = [0., 0., 0.] q_max = [0., 0., 0.] # v_act_pu = [0., 0., 0.] # q_act_pu = [0., 0., 0.] var_aval = [var_rated/3., var_rated/3., var_rated/3.] if priority == 'Active': # In the case of watt priority, calculate the available reactive power per phase if phases == 'Single Phase': var_aval = [math.sqrt(max([((s_rated/3.)**2)-(p_act[0]**2), 0.]))] else: var_aval = [math.sqrt(max([((s_rated/3.)**2)-(p_act[0]**2), 0.])), math.sqrt(max([((s_rated/3.)**2)-(p_act[1]**2), 0.])), math.sqrt(max([((s_rated/3.)**2)-(p_act[2]**2), 0.]))] # Calculate the target reactive power for each phase and save them to the soft channels for ph in range(len(v_act)): # for each phase ph_val = ph + 1 # phase names start at 1 (not zero) q_target[ph], q_min[ph], q_max[ph] = q_msa_range(v_act[ph], v_msa, var_msa, tests[test][0], tests[test][1]) # For 3-phase inverters, the reactive power is spread across all 3 phases if phases != 'Single Phase': q_target[ph] = q_target[ph]/3. q_min[ph] = q_min[ph]/3. q_max[ph] = q_max[ph]/3. daq.sc['V_ACT_%i' % ph_val] = v_act[ph] daq.sc['Q_ACT_%i' % ph_val] = q_act[ph] # daq.sc['V_ACT_PU_%i' % ph_val] = v_act_pu[ph] # daq.sc['Q_ACT_PU_%i' % ph_val] = q_act_pu daq.sc['V_TARGET_%i' % ph_val] = v_target daq.sc['Q_TARGET_%i' % ph_val] = q_target[ph] daq.sc['Q_MIN_%i' % ph_val] = q_min[ph] daq.sc['Q_MAX_%i' % ph_val] = q_max[ph] daq.sc['Q_MIN_ERROR_%i' % ph_val] = abs(q_target[ph] - q_min[ph]) daq.sc['Q_MAX_ERROR_%i' % ph_val] = abs(q_max[ph] - q_target[ph]) # perform pass/fall on current voltage target and phase if priority == 'Reactive': passfail[ph] = test_pass_fail(var_act=q_act[ph], var_min=q_min[ph], var_max=q_max[ph]) else: passfail[ph] = test_pass_fail(var_act=q_act[ph], var_min=q_min[ph], var_max=q_max[ph], var_aval=var_aval[ph], q_msa=var_msa, priority=priority) if passfail[ph] == 'Fail': test_passfail = 'Fail' result = script.RESULT_FAIL ts.sleep(0.05) # insert small sleep so the test/suite can be stopped. # Ensure that 1 data entry includes the soft channel data. daq.data_sample() # Clear soft channel data. Hopefully only 1 data entry will include the soft # channel data, but it's not guaranteed for ph in range(len(v_act)): # for each phase ph_val = ph + 1 # phase names start at 1 (not zero) daq.sc['V_ACT_%i' % ph_val] = '' daq.sc['Q_ACT_%i' % ph_val] = '' # daq.sc['V_ACT_PU_%i' % ph_val] = '' # daq.sc['Q_ACT_PU_%i' % ph_val] = '' daq.sc['V_TARGET_%i' % ph_val] = '' daq.sc['Q_TARGET_%i' % ph_val] = '' daq.sc['Q_MIN_%i' % ph_val] = '' daq.sc['Q_MAX_%i' % ph_val] = '' daq.sc['Q_MIN_ERROR_%i' % ph_val] = '' daq.sc['Q_MAX_ERROR_%i' % ph_val] = '' # For plotting purposes, collect the (V, Q) point for this test point v_act_pu = np.mean(v_act)/v_nom q_act_pu = sum(q_act)/q_max_over # create result summary entry of the final measurements and pass/fail results if result_summary is not None: if phases == 'Single Phase': result_summary.write('%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n' % ('', '', '', '', '', '', '', passfail[0], q_act[0], q_target[0], q_min[0], q_max[0], v_act_pu, q_act_pu)) else: result_summary.write('%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,' '%s, %s, %s, %s, %s, %s, %s, %s, %s, %s \n' % ('', '', '', '', '', '', '', passfail[0], q_act[0], q_target[0], q_min[0], q_max[0], passfail[1], q_act[1], q_target[1], q_min[1], q_max[1], passfail[2], q_act[2], q_target[2], q_min[2], q_max[2], v_act_pu, q_act_pu)) # stop capture and save daq.data_capture(False) ds = daq.data_capture_dataset() ds.to_csv(ts.result_file_path(filename)) result_params['plot.title'] = test_str ts.result_file(filename, params=result_params) ts.log('Saving data capture') if result_summary is not None: if phases == 'Single Phase': result_summary.write('%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s\n' % (test_passfail, test_str, priority, power*100., count, var_msa, filename, '', '', '', '', '')) else: result_summary.write('%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, ' '%s, %s, %s, %s, %s, %s, %s, %s, %s\n' % (test_passfail, test_str, priority, power*100., count, var_msa, filename, '', '', '', '', '', '', '', '', '', '', '', '', '', '', '')) ''' 9) Repeat test Steps (6) - (8) at power levels of 20 and 66%; as described by the following: a) For the 20% test, the EUT output power set to 20% of its Prated nominal rating b) For the 66% test the test input source is to be adjusted to limit the EUT output power to a value between 50% and 95% of rated output power. c) The 66% power level, as defined in (b), shall be repeated for a total of five sweeps of the Q(V) curve to validate consistency. ''' ''' 10) Repeat steps (6) - (9) for the remaining tests in Table SA13.1. Other than stated in (9) (c), the required number of sweeps for each of these repetitions is three. In the case of EUT without adjustable (V, Q) points, this step may be eliminated. ''' '''
def test_run(): result = script.RESULT_FAIL data = None trigger = None inv = None pv = None disable = None try: # EUT communication parameters ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') # INV1 parameters operation = ts.param_value('inv1.operation') time_window = ts.param_value('inv1.time_window') timeout_period = ts.param_value('inv1.timeout_period') # Script timing and pass/fail criteria pretest_delay = ts.param_value('invt.pretest_delay') verification_delay = ts.param_value('invt.verification_delay') posttest_delay = ts.param_value('invt.posttest_delay') power_threshold = ts.param_value('invt.power_threshold') disable = ts.param_value('invt.disable') # initialize data acquisition system daq = das.das_init(ts) data = daq.data_init() trigger = daq.trigger_init() # initialize pv simulation pv = pvsim.pvsim_init(ts) pv.power_on() # It is assumed that the PV and Grid Simulators (if used) are connected to the EUT and operating properly # prior to running this test script. if pretest_delay > 0: ts.log('Waiting for pre-test delay of %d seconds' % pretest_delay) ts.sleep(pretest_delay) # Sandia Test Protocol: Communication is established between the Utility Management System Simulator and EUT ts.log('Scanning EUT') try: inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % e) # Define operation states (connected/disconnected) # Default state is required for timeout_periods because the EUT will return to that mode of operation default_state = inverter.CONN_CONNECT if operation == 'Connect': orig_state = inverter.CONN_DISCONNECT state = inverter.CONN_CONNECT elif operation == 'Disconnect': orig_state = inverter.CONN_CONNECT state = inverter.CONN_DISCONNECT else: ts.log('Unknown operation requested: %s' % operation) raise script.ScriptFail() # Sandia Test Protocol Step 1: Request Status of EUT. # Sandia Test Protocol Step 2: UMS receives response to the DS93 command. # Verify EUT is in correct state before running the test. if inverter.verify_conn_state(inv, orig_state, threshold=power_threshold, das=data) is False: # todo: update inverter module with das changed to data ts.log('Inverter not in correct state, setting state to: %s' % (inverter.conn_state_str(orig_state))) # EUT put into state where INV1 can be verified inverter.set_conn_state(inv, orig_state) if verify_conn_state_change(inv, orig_state, verification_delay=verification_delay, threshold=power_threshold, data=data) is False: raise script.ScriptFail() # Sandia Test Protocol Step 3: Inverter output is measured and logged. log_conn_state(inv, data=data) # Sandia Test Protocol Step 4: UMS issues the INV1 command. ts.log('Executing %s' % operation) inverter.set_conn_state(inv, state, time_window=time_window, timeout_period=timeout_period, trigger=trigger) # Sandia Test Protocol Step 5: Verify the INV1 command was successfully executed. if verify_conn_state_change(inv, state, time_window=time_window, verification_delay=verification_delay, threshold=power_threshold, data=data) is False: raise script.ScriptFail() # Verify revert (timeout) to default state if timeout period specified if timeout_period > 0: if verify_conn_state_change(inv, default_state, timeout_period=timeout_period, verification_delay=verification_delay, threshold=power_threshold, data=data) is False: raise script.ScriptFail() if posttest_delay > 0: ts.log('Waiting for post-test delay of %d seconds' % posttest_delay) ts.sleep(posttest_delay) result = script.RESULT_PASS
def test_run(): result = script.RESULT_FAIL data = None trigger = None grid = None pv = None inv = None volt = {} var = {} disable = None try: ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') var_ramp_rate = ts.param_value( 'vv.settings.var_ramp_rate') # time to ramp msa_var = ts.param_value('vv.settings.MSA_VAr') v_low = ts.param_value('vv.settings.v_low') v_high = ts.param_value('vv.settings.v_high') k_varmax = ts.param_value('vv.settings.k_varmax') v_deadband_min = ts.param_value('vv.settings.v_deadband_min') v_deadband_max = ts.param_value('vv.settings.v_deadband_max') manualcurve = ts.param_value('vv.settings.manualcurve') settling_time = ts.param_value('vv.settings.settling_time') vv_mode = ts.param_value('vv.settings.vv_mode') if vv_mode == 'VV11 (watt priority)': deptRef = inverter.VOLTVAR_WMAX elif vv_mode == 'VV12 (var priority)': deptRef = inverter.VOLTVAR_VARMAX elif vv_mode == 'VV13 (fixed var)': deptRef = inverter.VOLTVAR_VARAVAL fixedVar = ts.param_value('vv.settings.fixedVar') var[1] = fixedVar # Not very clean - will pull 'points' info out later for pass/fail bounds fixedVarRef = ts.param_value('vv.settings.fixedVarRef') if fixedVarRef == '%VarAval': volt[ 1] = 1 # Not very clean - will pull 'points' info out later for pass/fail bounds elif fixedVarRef == '%WMax': volt[ 1] = 2 # Not very clean - will pull 'points' info out later for pass/fail bounds else: #fixedVarRef == '%VarMax' volt[ 1] = 3 # Not very clean - will pull 'points' info out later for pass/fail bounds else: deptRef = 4 if vv_mode == 'VV11 (watt priority)' or vv_mode == 'VV12 (var priority)': curve_num = ts.param_value('vv.settings.curve_num') volt = ts.param_value('vv.curve.volt') var = ts.param_value('vv.curve.var') if manualcurve is 'Manual': n_points = ts.param_value('vv.settings.n_points') else: n_points = 4 var_range = ts.param_value('invt.var_range') pretest_delay = ts.param_value('invt.pretest_delay') verification_delay = ts.param_value('invt.verification_delay') posttest_delay = ts.param_value('invt.posttest_delay') voltage_tests_per_line = ts.param_value('invt.voltage_tests_per_line') test_on_vv_points = ts.param_value('invt.test_on_vv_points') disable = ts.param_value('invt.disable') ''' UL 1741 requirements from the Feb 2015 Draft 1. Connect the EUT according to the Requirements in Sec. 4.3.1 and specifications provided by the manufacturer. 2. Set all AC source parameters to the nominal operating conditions for the EUT. Frequency is set at nominal and held at nominal throughout this test. Set the input power to the value to Prated. 3. Turn on the EUT. Set all R21-1-L/HVRT parameters to the widest range of adjustability possible with the R21-1-VV11 enabled. 4. If the EUT has the ability to set "Real Power Priority" or "Reactive Power Priority", select "Reactive Power Priority". 5. Set the EUT to provide reactive power according to the Q(V) characteristic defined in Test 1 in Table 10. 6. Begin recording the time domain response of the EUT AC voltage and current, and DC voltage and current. Step down the AC voltage until at least three points are recorded in each line segment of the characteristic curve or the EUT trips from the LVRT must trip requirements. Continue recording the time domain response for at least twice the settling time after each voltage step. 7. Repeat Step 6, raising the AC voltage until at least three points are recorded in each line segment of the characteristic curve or the EUT trips from HVRT must trip requirements. 8. Repeat steps 6 - 7 four more times, for a total of five sweeps of the Q(V) curve. 9. Repeat test steps 5 - 8 at power levels 20% and 60% of Prated by reducing the DC voltage of the Input Source. 10. Repeat steps 6 - 9 for the remaining tests in Table 10. ''' # initialize data acquisition system daq = das.das_init(ts) data = daq.data_init() trigger = daq.trigger_init() # initialize pv simulation pv = pvsim.pvsim_init(ts) pv.power_on() # UL 1741 SA Step 2: Set all AC source parameters to the nominal operating conditions for the EUT # initialize grid simulation grid = gridsim.gridsim_init(ts) if grid: gridsim_v_nom = grid.v_nom() #Put inverter scan after grid and PV simulation setup so that Modbus registers can be read. ts.log('Scanning inverter') inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) # Make sure the EUT is on and operating ts.log( 'Verifying EUT is in connected state. Waiting up to %d seconds for EUT to begin power export.' % (verification_delay + pretest_delay)) if verify_initial_conn_state( inv, state=inverter.CONN_CONNECT, time_period=verification_delay + pretest_delay, data=data) is False: ts.log_error('Inverter unable to be set to connected state.') raise script.ScriptFail() # Get parameters try: inv.nameplate.read() inv.controls.read() inv.settings.read() except Exception, e: raise script.ScriptFail('Unable to get parameters from EUT: %s' % str(e)) ts.log('********Parameters of the EUT*************') S_rated = float(inv.nameplate.VARtg) ts.log('Apparent Power Rating (VA) - S_rated: %.3f.' % S_rated) ts.log('EUT Input Power Rating (W) - P_rated: %.3f.' % float(inv.nameplate.WRtg)) ts.log( 'DC Voltage range with function enabled (V) - [V_low, V_high]: [%.1f, %.1f].' % (v_low, v_high)) v_nom = float(inv.settings.VRef) ts.log('Nominal AC Voltage (V): %.3f.' % v_nom) v_min = float(inv.settings.VMin) v_max = float(inv.settings.VMax) ts.log('AC Voltage Range with function enabled (V): %.3f to %.3f' % (v_min, v_max)) ts.log('VAr Accuracy (VAr) - MSA_VAr: %.3f.' % msa_var) ts.log('Max reactive power ramp rate (VAr/s): %.3f.' % var_ramp_rate) Q_max_cap = float(inv.settings.VArMaxQ1) Q_max_ind = float(inv.settings.VArMaxQ4) # negative ts.log( 'Minimum inductive (underexcited) reactive power - Q_max,ind: %.3f.' % Q_max_ind) # negative ts.log( 'Minimum capacitive (overexcited) reactive power - Q_max,cap: %.3f.' % Q_max_cap) ts.log('Maximum slope (VAr/V), K_varmax: %.3f.' % k_varmax) ts.log('Deadband range (V): [%.1f, %.1f].' % (v_deadband_min, v_deadband_max)) ts.log('*******************************************') Q_min_cap = Q_max_cap / 4. Q_min_ind = Q_max_ind / 4. #negative #v_avg = (v_min + v_max)/2. v_min_dev = min(v_nom - v_min, v_max - v_nom) v_deadband_avg = (v_deadband_min + v_deadband_max) / 2. k_varmin = Q_min_cap / (v_min_dev - v_deadband_max / 2.) k_varavg = (k_varmin + k_varmax) / 2. ts.log('Q_mid,cap = half the EUT capacitive VAr range: %.3f.' % Q_min_cap) ts.log('Q_mid,ind = half the EUT inductive VAr range: %.3f.' % Q_min_ind) #ts.log('V_avg = halfway point for the operating ac voltage of the function: %.3f.' % v_avg) ts.log('K_varavg: %.3f.' % k_varavg) ts.log('K_varmin: %.3f.' % k_varmin) ts.log('Average voltage deadband: %.3f.' % v_deadband_avg) ts.log('********Required Test Points for UL 1741*************') volt, var = volt_var_set(v_nom=240., volt=volt, var=var, v_deadband_max=v_deadband_max, v_deadband_avg=v_deadband_avg, v_deadband_min=v_deadband_min, Q_max_cap=Q_max_cap, Q_max_ind=Q_max_ind, k_varmax=k_varmax, k_varavg=k_varavg, k_varmin=k_varmin, manualcurve=manualcurve) ######## Begin Test ######## # UL 1741 SA Step 3: if applicable set LVRT/HVRT settings here. # Request status from EUT and display vars var_original = inverter.get_var(inv, das=data) ts.log('Current reactive power is %.3f VAr' % var_original) # UL 1741 SA Step 4 (using deptRef) and Step 5 (setting the Q(V) characteristic curve) inverter.set_volt_var(inv, volt=volt, var=var, n_points=n_points, curve_num=curve_num, deptRef=deptRef, enable=1) #voltage_pct_test_points = np.linspace(0., 100., voltage_tests_per_line) #ts.log('test_on_vv_points == Yes: %s' % voltage_pct_test_points) #voltage_pct_test_points = np.linspace(0., 100., voltage_tests_per_line+2) #voltage_pct_test_points = voltage_pct_test_points[1:-1] #ts.log('test_on_vv_points == No: %s' % voltage_pct_test_points) if test_on_vv_points == 'Yes': # the test points are on the (V,Q) points voltage_pct_test_points = np.linspace(0., 100., voltage_tests_per_line) ts.log( 'Test points will at %s %% of the volt-var curve segments.' % voltage_pct_test_points) else: # the test points are not on the (V,Q) points voltage_pct_test_points = np.linspace(0., 100., voltage_tests_per_line + 2) voltage_pct_test_points = voltage_pct_test_points[1:-1] ts.log( 'Test points will at %s %% of the volt-var curve segments.' % voltage_pct_test_points) lines_to_test = volt[ 'index_count'] + 1 # There are 1 more line than there are (V,Q) points for irradiance in [1000, 200, 600]: ts.log( 'DC power level is %.3f %% nameplate, so the simulator power level is set to %.1f W/m^2' % (irradiance / 10., irradiance)) pv.irradiance_set(irradiance=irradiance) for repeats in xrange( 1, 6): # UL 1741 Step 8: Repeat the test 5 times ts.log(' Running volt-var sweep number %d.' % (repeats)) if pretest_delay > 0: ts.log(' Waiting for pre-test delay of %d seconds' % pretest_delay) ts.sleep(pretest_delay) for j in xrange(lines_to_test): for i in voltage_pct_test_points: ts.log( ' Testing the reactive power on curve segment %d at %d%% down the line segment.' % (j + 1, i)) voltage_pct = grid_voltage_get( inv, volt=volt, var=var, v_nom=v_nom, line_to_test=j + 1, voltage_pct_test_point=i) # Set grid simulator voltage immediately prior to triggering if grid is not None: ts.log( ' Setting ac voltage percentage = %.2f.%%. Simulator voltage = %.2f' % (voltage_pct, (voltage_pct / 100.) * gridsim_v_nom)) grid_sim_voltage = (voltage_pct / 100.) * gridsim_v_nom gridsim_v_max = grid.v_max() if grid_sim_voltage > gridsim_v_max: grid.voltage(voltage=gridsim_v_max) ts.log_warning( 'The grid simulator voltage is set to the simulator equipment limit.' ) else: grid.voltage(voltage=grid_sim_voltage) else: ts.confirm( 'Set ac voltage percentage to %.2f.%% with grid simulator voltage = %.2f' % (voltage_pct, (voltage_pct / 100.) * gridsim_v_nom)) if trigger: trigger.on() start_time = time.time() inv.nameplate.read() VarAval = inv.nameplate.VArRtgQ1 varTarg, var_upper, var_lower = var_pass_fail_band( inv, volt=volt, var=var, n_points=n_points, var_range=var_range, deptRef=deptRef, das=das) ts.log( ' Target vars: %.3f. Pass limits for screening: lower = %.3f upper = %.3f' % (varTarg, var_lower, var_upper)) ts.log(' Waiting settling time of %.3f' % (settling_time)) time.sleep(settling_time - 0.25) # computer specific time correction current_vars = inverter.get_var(inv, das=data) # Cheat a little since var is unsigned from das (and inverter?) if varTarg < 0 and current_vars > 0: current_vars = -current_vars elapsed_time = time.time() - start_time ts.log( ' Var Target = %.3f [%.3f to %.3f], Vars = %.3f (Total Error = %.3f%%), ' 'Time: %0.3f seconds.' % (varTarg, var_lower, var_upper, current_vars, (current_vars - varTarg) / VarAval * 100.0, elapsed_time)) # if vars out of range if current_vars < var_lower or current_vars > var_upper: ts.log( ' Acceptable reactive power levels were not reacted after the settling time.' ) raise script.ScriptFail() else: # Criteria # For each voltage step, the EUT reactive power measurement should remain within the # manufacturers stated accuracy of the Q(V) value except when the voltage is changing. # The EUT shall obtain the Q(V) characteristic within its stated accuracy within the # stated settling time. ts.log( ' Reactive power level was within the bounds after the settling time.' ) if trigger: trigger.off() if posttest_delay > 0: ts.log( ' Waiting for post-test delay of %d seconds' % posttest_delay) ts.sleep(posttest_delay) result = script.RESULT_PASS
def test_run(): result = script.RESULT_FAIL data = None trigger = None inv = None pv = None disable = None try: # UL 1741 Test Protocol # a. Connect the EUT according to the Requirements in Sec. 11.2.4 and specifications provided by the # manufacturer. Set the EUT to maximum power factor. # b. Set all AC source parameters to the nominal operating conditions for the EUT. # c. Set the input power level to provide Ilow from the EUT. Note: for units that do not adjust output # current as a function of their input such as units with energy storage or multimode products the output # power is to be commanded. # d. Turn on the EUT. Allow the EUT to reach steady state, e.g., maximum power point. # e. Set the EUT ramp rate parameters according to Test 1 in Table SA 11.1. # f. Begin recording the time domain response of the EUT AC voltage and current, and DC voltage and current. # g. Increase the available input power to provide Irated from the EUT according to the step function # described in SA 11. # h. Stop recording the time domain response after the ramp duration plus a manufacturer-specified dwell # time. Ramp duration is defined by 100/RRnorm_up as appropriate for the test settings. # i. Repeat steps c-h two times for a total of 3 repetitions. # j. Repeat steps c-i for Tests 2-3 in Table SA 11.1. # EUT communication parameters ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') # RR parameters RRnorm_up_min = ts.param_value('rr.RRnorm_up_min') RRnorm_up_max = ts.param_value('rr.RRnorm_up_max') Ilow = ts.param_value('rr.Ilow') Irated = ts.param_value('rr.Irated') MSARR = ts.param_value('rr.MSARR') t_dwell = ts.param_value('rr.t_dwell') # Script timing and pass/fail criteria pretest_delay = ts.param_value('invt.pretest_delay') verification_delay = ts.param_value('invt.verification_delay') posttest_delay = ts.param_value('invt.posttest_delay') power_threshold = ts.param_value('invt.power_threshold') disable = ts.param_value('invt.disable') # initialize data acquisition system daq = das.das_init(ts) data = daq.data_init() trigger = daq.trigger_init() # Step b. Set all AC source parameters to the nominal operating conditions for the EUT. # Initialize pv simulation - This is before step (a) because PV power may be required for communications to EUT pv = pvsim.pvsim_init(ts) pv.power_on() # Communication is established between the Utility Management System Simulator and EUT ts.log('Scanning EUT') try: inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % e) # Step a. Connect the EUT according to the Requirements in Sec. 11.2.4 and specifications provided by the # manufacturer. Set the EUT to maximum power factor. # It is assumed that the Grid Simulator (if used) is connected to the EUT and operating properly inverter.set_power_factor(inv, power_factor=1., enable=0) # UL 1741 Step j. Repeat steps c-i for Tests 2-3 in Table SA 11.1. for ramp in [RRnorm_up_min, (RRnorm_up_min + RRnorm_up_max)/2, RRnorm_up_max]: for i in xrange(3): # UL 1741 Step i. Repeat steps c-h two times for a total of 3 repetitions. ts.log('Running test number %d with ramp rate %0.3f %%Irated/sec.' % (i+1, ramp)) # Step c. Set the input power level to provide Ilow from the EUT. Note: for units that do not adjust # output current as a function of their input such as units with energy storage or multimode # products the output power is to be commanded. pv.irradiance_set(irradiance=Ilow*10) # Step d. Turn on the EUT. Allow the EUT to reach steady state, e.g., maximum power point. if pretest_delay > 0: ts.log('Waiting for pre-test delay of %d seconds' % pretest_delay) ts.sleep(pretest_delay) # Verify EUT is in correct state before running the test. if inverter.get_conn_state(inv) is False: ts.log('Inverter not in correct state, setting state to connected.') inverter.set_conn_state(inv, state=1) if verify_conn_state_change(inv, orig_state=0, verification_delay=verification_delay, threshold=power_threshold, data=data) is False: raise script.ScriptFail() # Step e. Set the EUT ramp rate parameters according to Test 1 in Table SA 11.1. try: inv.settings.read() if inv.settings.WGra is not None: inv.settings.WGra = ramp else: ts.log_error('Unable to change ramp rate in the EUT.') except Exception, e: ts.log_error('Error changing ramp rate in the EUT: %s' % str(e)) # Step g. Increase the available input power to provide Irated from the EUT according to the step # function described in SA 11. pv.irradiance_set(irradiance=1000) start_time = time.time() # Step h. Stop recording the time domain response after the ramp duration plus a # manufacturer-specified dwell time. data_update_rate = 1 # Hz check_duration = (Irated-Ilow)/ramp test_duration = t_dwell + check_duration duration = 0 while duration < test_duration+verification_delay: duration = time.time()-start_time ts.log_debug('duration = %0.2f, check duration = %0.2f' % (duration, check_duration)) if duration <= check_duration: # only check the ramp response during the check_duration ramp_in_bounds = verify_ramp(inv, ramp=ramp, t_since_step=duration, Ilow=Ilow, Irated=Irated, MSARR=MSARR, data=data) if ramp_in_bounds is False: ts.log_error('Ramp response was not within limits') # raise script.ScriptFail() else: # The EUT shall reach at least 95% of Irated at the end of the dwell time. ts.log('EUT completed ramping. Waiting for dwell time to check current output. ' 'Remaining time: %0.3f' % (test_duration - duration)) if duration >= test_duration: current_pct = inverter.get_power_norm(inv=inv, das=data)*100 ts.log_error('EUT current is %0.3f%%' % current_pct) if current_pct < 95: ts.log_error('EUT did not reach at least 95% of Irated at the end of the dwell time.') raise script.ScriptFail() break time.sleep(1/data_update_rate) # todo: should improve the loop timing if posttest_delay > 0: ts.log('Waiting for post-test delay of %d seconds' % posttest_delay) ts.sleep(posttest_delay)
def test_run(): result = script.RESULT_FAIL data = None trigger = None inv = None pv = None disable = None try: ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') power_factor = ts.param_value('inv3.power_factor') msa_vac = ts.param_value('inv3.MSA_Vac') msa_vdc = ts.param_value('inv3.MSA_Vdc') p_low = ts.param_value('inv3.p_low') p_high = ts.param_value('inv3.p_high') v_low = ts.param_value('inv3.v_low') v_high = ts.param_value('inv3.v_high') pf_acc = ts.param_value('inv3.pf_acc') pf_settling_time = ts.param_value('inv3.pf_settling_time') dc_nom = ts.param_value('inv3.dc_nom') pretest_delay = ts.param_value('invt.pretest_delay') power_factor_range = ts.param_value('invt.power_factor_range') setpoint_failure_count = ts.param_value('invt.setpoint_failure_count') verification_delay = ts.param_value('invt.verification_delay') posttest_delay = ts.param_value('invt.posttest_delay') disable = ts.param_value('invt.disable') # initialize data acquisition system daq = das.das_init(ts) data = daq.data_init() trigger = daq.trigger_init() # Initialize pv simulation - Part of UL 1741 Step 1 pv = pvsim.pvsim_init(ts) pv.power_on() # Communication is established between the Utility Management System Simulator and EUT ts.log('Scanning EUT') try: inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % (e)) # Make sure the EUT is on and operating ts.log('Verifying EUT is in connected state. Waiting up to %d seconds for EUT to begin power export.' % (verification_delay+pretest_delay)) if verify_initial_conn_state(inv, state=inverter.CONN_CONNECT, time_period=verification_delay+pretest_delay, data=data) is False: ts.log_error('Inverter unable to be set to connected state.') raise script.ScriptFail() # Get parameters try: # This test follows the IEEE Std-1459-2000 reactive power sign convention, in which a leading, capacitive, # overexcited power factor is positive and a lagging, inductive, underexcited power factor is negative. # get min/max PF settings inv.nameplate.read() min_ind_PF = float(inv.nameplate.PFRtgQ1) # negative min_cap_PF = float(inv.nameplate.PFRtgQ4) # positive inv.controls.read() inv.settings.read() inv.inverter.read() OutPFSet_Ena = inv.controls.OutPFSet_Ena ts.log('Power factor is %0.3f.' % float(inv.inverter.PF)) if OutPFSet_Ena: ts.log('Power factor mode is enabled.') else: ts.log('Power factor mode is not enabled.') ts.log('********Parameters of the EUT*************') S_rated = float(inv.nameplate.VARtg) ts.log('Apparent Power Rating (VA) - S_rated: %.3f.' % S_rated) ts.log('EUT Input Power Rating (W) - P_rated: %.3f.' % float(inv.nameplate.WRtg)) ts.log('DC Voltage range with function enabled (V) - [V_low, V_high]: [%.1f, %.1f].' % (v_low, v_high)) ts.log('Nominal DC Voltage (V): %.3f.' % dc_nom) ts.log('Nominal AC Voltage (V): %.3f.' % float(inv.settings.VRef)) ts.log('AC Voltage Range with function enabled (V): %.3f to %.3f' % (float(inv.settings.VMin),float(inv.settings.VMax))) ts.log('AC Voltage Accuracy (V) - MSA_Vac: %.3f.' % msa_vac) ts.log('DC Voltage Accuracy (V) - MSA_Vdc: %.3f.' % msa_vdc) ts.log('Active power range of function (%%nameplate) - [P_low, P_high]: [%.1f, %.1f].' % (p_low, p_high)) ts.log('Power Factor Accuracy: %.3f.' % pf_acc) ts.log('Power Factor Settling Time: %.3f.' % pf_settling_time) ts.log('Minimum inductive (underexcited) power factor - PF_min,ind: %.3f.' % min_cap_PF) ts.log('Minimum capacitive (overexcited) power factor - PF_min,cap: %.3f.' % min_ind_PF) ts.log('*******************************************') mid_cap_PF = (-1. - min_cap_PF)/2. mid_ind_PF = (1. - min_ind_PF)/2. ts.log('Power factor target for the test - PF: %.3f.' % power_factor) ts.log('PF_mid,cap = half the EUT capacitive range: %.3f.' % mid_cap_PF) ts.log('PF_mid,ind = half the EUT inductive range: %.3f.' % mid_ind_PF) ts.log('P_limit, the maximum output power (W): %.3f.' % float(inv.settings.WMax)) ts.log('Q_rated, the reactive power rating of the EUT (VAr): %.3f.' % float(inv.settings.VArMaxQ1)) p_x = math.fabs(power_factor)*100 ts.log('P_X, the maximum input power which an "Active Power Priority" mode maintains the PF ' 'command (%%nameplate): %.3f.' % p_x) ts.log('*******************************************') except Exception, e: raise script.ScriptFail('Unable to get PF limits or other data from EUT: %s' % str(e))
# assume the PF is the correct sign pf = -pf # Screening: determine if the PF is in the target range out_of_range = pf_out_of_range(pf, power_factor_lower, power_factor_upper, power_factor_range) ts.log('PF Target = %.3f, PF = %.3f (Total Error = %.3f%%), Time: %0.3f seconds.' % (power_factor, pf, (pf - power_factor)*100.0, elapsed_time)) # if pf is out of range if out_of_range is True: failures += 1 if failures >= setpoint_failure_count: ts.log_error('Inverter exceeded PF setpoint + buffer after %0.3f seconds. ' 'Fail count = %d.' % (elapsed_time,failures)) raise script.ScriptFail() else: ts.log_warning('Inverter exceeded PF setpoint + buffer after %0.3f seconds. ' 'Fail count = %d.' % (elapsed_time,failures)) else: failures = 0 if posttest_delay > 0: ts.log('Waiting for post-test delay of %d seconds.' % posttest_delay) ts.sleep(posttest_delay) result = script.RESULT_PASS except script.ScriptFail, e: reason = str(e) if reason:
def test_run(): result = script.RESULT_FAIL data = None trigger = None inv = None pv = None disable = None try: ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') power_factor = ts.param_value('inv3.power_factor') ramp_time = ts.param_value('inv3.ramp_time') # time to ramp time_window = ts.param_value('inv3.time_window') timeout_period = ts.param_value('inv3.timeout_period') pretest_delay = ts.param_value('invt.pretest_delay') power_factor_range = ts.param_value('invt.power_factor_range') setpoint_failure_count = ts.param_value('invt.setpoint_failure_count') setpoint_period = ts.param_value('invt.setpoint_period') verification_delay = ts.param_value('invt.verification_delay') posttest_delay = ts.param_value('invt.posttest_delay') disable = ts.param_value('invt.disable') # initialize data acquisition system daq = das.das_init(ts) data = daq.data_init() trigger = daq.trigger_init() # initialize pv simulation pv = pvsim.pvsim_init(ts) pv.irradiance_set(ts.param_value('profile.irr_start')) pv.profile_load(ts.param_value('profile.profile_name')) pv.power_on() # Sandia Test Protocol: Communication is established between the Utility Management System Simulator and EUT ts.log('Scanning EUT') try: # Sandia Test Protocol Step 1: Request status of EUT # Sandia Test Protocol Step 2: UMS receives response from EUT inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % (e)) if pretest_delay > 0: ts.log('Waiting for pre-test delay of %d seconds' % pretest_delay) ts.sleep(pretest_delay) # Make sure the EUT is on and operating ts.log( 'Verifying EUT is in connected state. Waiting up to %d seconds for EUT to begin power export.' % (verification_delay + pretest_delay)) if verify_initial_conn_state( inv, state=inverter.CONN_CONNECT, time_period=verification_delay + pretest_delay, data=data) is False: ts.log_error('Inverter unable to be set to connected state.') raise script.ScriptFail() # Get parameters try: inv.nameplate.read() # get min/max PF settings min_PF = float(inv.nameplate.PFRtgQ1) max_PF = float(inv.nameplate.PFRtgQ4) ts.log('Power factor range for this device is %.3f to %.3f' % (min_PF, max_PF)) # Sandia Test Protocol Step 3: EUT output power factor is measured and logged # Get INV3 settings and report these. # Get PF from EUT pf = inverter.get_power_factor(inv, das=data) ts.log('Power factor is %f.' % pf) except Exception, e: raise script.ScriptFail( 'Unable to get PF limits or PF from EUT: %s' % str(e))
# Get PF from EUT pf = inverter.get_power_factor(inv, das=data) ts.log('Power factor is %f.' % pf) except Exception, e: raise script.ScriptFail( 'Unable to get PF limits or PF from EUT: %s' % str(e)) try: inv.controls.read() OutPFSet_Ena = inv.controls.OutPFSet_Ena if OutPFSet_Ena: ts.log('Power factor mode is enabled.') else: ts.log('Power factor mode is not enabled.') except Exception, e: raise script.ScriptFail('Unable to read OutPFSet_Ena: %s' % str(e)) #### Comparison of DAS PF and the EUT PF # Request status from DAS and display power factor if data: data.read() power_factor_data_original = data.ac_pf ts.log_debug('Current DAS-measured power factor is +/-%.3f' % power_factor_data_original) # Request status from EUT and display power factor power_factor_original = inverter.get_power_factor(inv, data) if power_factor_original is not None: pass # ts.log_debug('Current inverter-measured power factor is +/-%.3f' % power_factor_original) else:
def test_run(): result = script.RESULT_FAIL data = None trigger = None inv = None pv = None disable = None try: ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') power_limit_pct = ts.param_value('inv2.power_limit_pct') ramp_time = ts.param_value( 'inv2.ramp_time') # slope defined by % nameplate power/sec time_window = ts.param_value('inv2.time_window') timeout_period = ts.param_value('inv2.timeout_period') pretest_delay = ts.param_value('invt.pretest_delay') power_limit_pct_buffer = ts.param_value('invt.power_limit_pct_buffer') screening_period = ts.param_value('invt.screening_period') setpoint_failure_count = ts.param_value('invt.setpoint_failure_count') verification_delay = ts.param_value('invt.verification_delay') posttest_delay = ts.param_value('invt.posttest_delay') disable = ts.param_value('invt.disable') # initialize data acquisition system daq = das.das_init(ts) data = daq.data_init() trigger = daq.trigger_init() # initialize pv simulation pv = pvsim.pvsim_init(ts) pv.irradiance_set(ts.param_value('profile.irr_start')) pv.profile_load(ts.param_value('profile.profile_name')) pv.power_on() # Sandia Test Protocol: Communication is established between the Utility Management System Simulator # and EUT ts.log('Scanning EUT') try: inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % (e)) if pretest_delay > 0: ts.log('Waiting for pre-test delay of %d seconds' % pretest_delay) ts.sleep(pretest_delay) # Make sure the EUT is on and operating ts.log( 'Verifying EUT is in connected state. Waiting up to %d seconds for EUT to begin power export.' % (verification_delay + pretest_delay)) if verify_initial_conn_state( inv, state=inverter.CONN_CONNECT, time_period=verification_delay + pretest_delay, data=data) is False: ts.log_error('Inverter unable to be set to connected state.') raise script.ScriptFail() # Sandia Test Protocol Step 1: Request status of EUT # Sandia Test Protocol Step 2: UMS receives response from EUT try: inv.settings.read() power_max = int(inv.settings.WMax) ts.log('Inverter maximum power = %d W' % (power_max)) except Exception, e: raise ('Unable to get WMax setting: %s' % str(e))
def test_run(): result = script.RESULT_FAIL eut = grid = load = pv = daq = chil = None # result params result_params = { 'plot.title': ts.name, 'plot.x.title': 'Time (sec)', 'plot.x.points': 'TIME', 'plot.y.points': 'U1', 'plot.y.title': 'U1', 'plot.y2.points': 'I1', 'plot.y2.title': 'I1' } try: ''' This procedure uses the step function defined in Annex A. a) Connect the EUT according to the instructions and specifications provided by the manufacturer. b) Set all source parameters to the nominal operating conditions for the EUT. c) Set (or verify) all EUT parameters to the nominal operating settings. If the overvoltage trip time setting is adjustable, set it to the minimum. d) Record applicable settings. e) Set the source voltage to a value within 10% of, but not exceeding, the overvoltage trip point setting. The source shall be held at this voltage for period t_hold. At the end of this period, step the source voltage to a value that causes the unit to trip. Hold this value until the unit trips. For multiphase units, this test may be performed on one phase only. f) Record the trip time. g) Repeat steps d) through f) four times for a total of five tests. h) If the overvoltage time setting is adjustable, repeat steps d) through g) at the midpoint and maximum overvoltage time settings. ''' phases = ts.param_value('eut.phases') p_rated = ts.param_value('eut.p_rated') v_nom = ts.param_value('eut.v_nom') # volts v_msa = ts.param_value('eut.v_msa') t_msa = ts.param_value('eut.t_msa') t_trip = ts.param_value('eut.t_trip') P_T = ts.param_value('vrt.v_test') # percentage t_hold = ts.param_value('vrt.t_hold') n_r = ts.param_value('vrt.n_r') # P_T = trip voltage # P_b = starting voltage # P_U = test voltage # Parameter A shall be chosen so that P_U is at least 110% (90% for under value tests) of P_T P_T_volts = (P_T / 100) * v_nom if P_T_volts > v_nom: A = 0.1 * P_T_volts # volts else: A = -0.1 * P_T_volts # volts P_U = P_T_volts + A if P_U < 0: P_U = 0 # P_b = v_nom + (v_nom - v_msa)*0.9 # if the grid sim has a long slew rate P_b = v_nom # starting voltage of the test, in volts ''' Set all AC source parameters to the normal operating conditions for the EUT. ''' # initialize HIL environment, if necessary chil = hil.hil_init(ts) if chil is not None: chil.config() # grid simulator is initialized with test parameters and enabled grid = gridsim.gridsim_init(ts) #ts.log("here?") #return # pv simulator is initialized with test parameters and enabled pv = pvsim.pvsim_init(ts) pv.power_set(p_rated) pv.power_on() # initialize data acquisition daq = das.das_init(ts) ts.log('DAS device: %s' % daq.info()) ''' Turn on the EUT. It is permitted to set all L/HVRT limits and abnormal voltage trip parameters to the widest range of adjustability possible with the SPF enabled in order not to cross the must trip magnitude threshold during the test. ''' # it is assumed the EUT is on eut = der.der_init(ts) eut.config() # run data capture ts.log('Running capture 1') f_sample = 50 #wanbin wfm_config_params = { 'sample_rate': f_sample, 'pre_trigger': 0.5, 'post_trigger': t_trip + 1.5, 'timeout': 30 } if phases == 'Single Phase': wfm_config_params['channels'] = ['AC_V_1', 'AC_I_1', 'EXT'] else: wfm_config_params['channels'] = [ 'AC_V_1', 'AC_V_2', 'AC_V_3', 'AC_I_1', 'AC_I_2', 'AC_I_3', 'EXT' ] if chil is not None: wfm_config_params['channels'] = [ 'AC_V_1', 'AC_V_2', 'AC_V_3', 'AC_I_1', 'AC_I_2', 'AC_I_3' ] if P_T > v_nom: wfm_config_params['trigger_cond'] = 'Rising Edge' wfm_config_params['trigger_channel'] = 'AC_V_1' wfm_config_params['trigger_level'] = ( (P_U + P_b) / 2.) * np.sqrt(2) else: wfm_config_params['trigger_cond'] = 'Rising Edge' wfm_config_params[ 'trigger_channel'] = 'AC_I_1' # catch the current increase on v sag wfm_config_params['trigger_level'] = ( (p_rated / v_nom) / 3) * 1.05 * np.sqrt( 2) # trigger when current 5% above rated else: wfm_config_params['trigger_cond'] = 'Rising Edge' wfm_config_params['trigger_channel'] = 'EXT' wfm_config_params['trigger_level'] = 1 # 0-5 V signal daq.waveform_config(params=wfm_config_params) # open result summary file result_summary_filename = 'result_summary.csv' result_summary = open(ts.result_file_path(result_summary_filename), 'a+') ts.result_file(result_summary_filename) if phases == 'Single Phase': # single phase to be cleaned up result_summary.write( 'Result, Test Name, t_trip, t_trip_meas, Dataset File\n') else: result_summary.write( 'Result, Test Name, t_trip, t_trip_meas, Dataset File\n') # set phase tests that are enabled phase_tests = [] # set single phase test voltages and test labels if phases == 'Single Phase': phase_tests.append(((P_U, v_nom, v_nom), 'Phase 1 Fault Test', 'p1', (P_b, v_nom, v_nom))) if phases == '3-Phase 3-Wire' or phases == '3-Phase 4-Wire': if ts.param_value('vrt.phase_1') == 'Enabled': phase_tests.append(((P_U, v_nom, v_nom), 'Phase 1 Fault Test', 'p1', (P_b, v_nom, v_nom))) if ts.param_value('vrt.phase_2') == 'Enabled': phase_tests.append(((v_nom, P_U, v_nom), 'Phase 2 Fault Test', 'p2', (v_nom, P_b, v_nom))) if ts.param_value('vrt.phase_3') == 'Enabled': phase_tests.append(((v_nom, v_nom, P_U), 'Phase 3 Fault Test', 'p3', (v_nom, v_nom, P_b))) ts.log_debug('Phase Tests: %s' % phase_tests) for phase_test in phase_tests: if daq is not None: ts.log('Starting RMS data capture') daq.data_capture(True) v_1, v_2, v_3 = phase_test[0] v_1_init, v_2_init, v_3_init = phase_test[3] # generate step change profile profile = voltage_rt_profile(v_nom=100, t_t=t_trip, P_b=P_b, P_U=P_U) for i in range(n_r): filename = '%s_%s_%s.csv' % ('voltage_trip', phase_test[2], i + 1) # start trip time test profile_supported = False if profile_supported: # UNTESTED! daq.waveform_capture(True) # turn on daq waveform capture t_sleep = 2 # need time to prepare acquisition ts.log( 'Sleeping for %s seconds, to wait for the capture to prime.' % t_sleep) ts.sleep(t_sleep) grid.profile_load(profile=profile) # grid.profile_load(profile_name='VV Profile') ts.log_debug(profile) ts.log('Starting profile now!') grid.profile_start() # Provide GUI with countdown timer start_time = time.time() profile_time = profile[-1][0] ts.log('Profile duration is %s seconds' % profile_time) while (time.time() - start_time) < profile_time: remaining_time = profile_time - (time.time() - start_time) ts.log('Sleeping for another %0.1f seconds' % remaining_time) ts.sleep(5) grid.profile_stop() else: grid.voltage((v_nom, v_nom, v_nom)) ts.log( 'Setting voltage: v_1 = %s v_2 = %s v_3 = %s for %s seconds' % (v_nom, v_nom, v_nom, t_hold)) # Check that the EUT is functioning daq.data_sample() # Sample before the grid voltage change data = daq.data_capture_read() p1 = data.get('AC_P_1') p2 = data.get('AC_P_2') p3 = data.get('AC_P_3') ts.log( ' EUT powers before dwell: p_1 = %s p_2 = %s p_3 = %s' % (p1, p2, p3)) grid.voltage((v_nom, v_nom, v_nom)) countdown = 330 # Wanbin : 5 min for sma inverter while (p1 < (0.1 * p_rated) / 3 or p2 < (0.1 * p_rated) / 3 or p3 < (0.1 * p_rated) / 3) and countdown > 0: if countdown % 10 == 0: ts.log( ' Waiting for EUT to turn back on for another %s seconds. (p1=%s, p2=%s, p3=%s)' % (countdown, p1, p2, p3)) countdown -= 1 ts.sleep(1) data = daq.data_capture_read() p1 = data.get('AC_P_1') p2 = data.get('AC_P_2') p3 = data.get('AC_P_3') ts.sleep(5) # return to ~rated power forced = False #wanbin if forced: daq.waveform_force_trigger() ts.sleep(0.5) else: # Start Waveform Capture daq.waveform_capture( True) # turn on daq waveform capture t_sleep = 2 # need time to prepare acquisition ts.log( 'Sleeping for %s seconds, to wait for the capture to prime.' % t_sleep) ts.sleep(t_sleep) if v_1_init != v_nom or v_2_init != v_nom or v_3_init != v_nom: # Run Profile ts.log( ' Setting voltage: v_1 = %s v_2 = %s v_3 = %s for %s seconds' % (v_1_init, v_2_init, v_3_init, t_hold)) # v_1_init = v_1_init*(grid.v_nom/v_nom) # v_2_init = v_2_init*(grid.v_nom/v_nom) # v_3_init = v_3_init*(grid.v_nom/v_nom) grid.voltage(voltage=(v_1_init, v_2_init, v_3_init)) ts.sleep(t_hold) ts.log( ' Setting voltage: v_1 = %s v_2 = %s v_3 = %s for %s seconds' % (v_1, v_2, v_3, t_trip + 1)) # v_1 = v_1*(grid.v_nom/v_nom) # v_2 = v_2*(grid.v_nom/v_nom) # v_3 = v_3*(grid.v_nom/v_nom) grid.voltage((v_1, v_2, v_3)) ts.sleep(t_trip + 1) # get data from daq waveform capture done = False countdown = int(t_trip) + 20 while not done and countdown > 0: status = daq.waveform_status() if status == 'COMPLETE': ds = daq.waveform_capture_dataset() done = True elif status == 'INACTIVE': ts.log('Waveform capture inactive') raise script.ScriptFail('Waveform capture inactive') elif status == 'ACTIVE': ts.log('Waveform capture active, sleeping') ts.sleep(1) countdown -= 1 # save captured data set to capture file in SVP result directory if ds is not None: ds.to_csv(ts.result_file_path(filename)) testname = "%s test" % filename result_params['plot.title'] = testname # plot? ts.result_file(filename, params=result_params) #ts.result_file(filename) wf = waveform.Waveform(ts) wf.from_csv(ts.result_file_path(filename)) # wf.compute_rms_data(phase=1) # time_data = wf.rms_data['1'][0] # Time # voltage_data_1 = wf.rms_data['1'][1] # Voltage # current_data_1 = wf.rms_data['1'][2] # Current # plt.figure(1) # plt.plot(time_data, voltage_data_1) # plt.figure(2) # plt.plot(time_data, current_data_1) # plt.show() if phase_test[2] == 'p1': channel_data = [wf.channel_data[1], wf.channel_data[4]] elif phase_test[2] == 'p2': channel_data = [wf.channel_data[2], wf.channel_data[5]] else: channel_data = [wf.channel_data[3], wf.channel_data[6]] _, voltage_data_1 = waveform_analysis.calculateRmsOfSignal( data=channel_data[0], windowSize=40, # ms samplingFrequency=f_sample) #wanbin time_data, current_data_1 = waveform_analysis.calculateRmsOfSignal( data=channel_data[1], windowSize=40, # ms samplingFrequency=f_sample) #wanbin for i in range(10): ts.log("%.2f, %.2f" % (current_data_1[i], voltage_data_1[i])) # plt.figure(1) # plt.plot(time_data, voltage_data_1, 'r', time_data, current_data_1, 'b') # plt.show() v_window = 10 # v_window is the window around the nominal RMS voltage where the VRT test is started #wanbin # with low sampling rate, v_nom may not good ref volt_idx = [] if P_T < 100.0: volt_idx = [ idx for idx, i in enumerate(voltage_data_1) if (i <= (voltage_data_1[1] * P_T / 100.0 + 2)) ] else: volt_idx = [ idx for idx, i in enumerate(voltage_data_1) if (i >= (voltage_data_1[1] * P_T / 100.0 - 2)) ] if len(volt_idx) != 0: t_start = time_data[min(volt_idx)] else: t_start = 0 ts.log_warning( 'Voltage deviation started before the waveform capture.' ) ts.log_debug(voltage_data_1[1] * P_T / 100.0) ts.log_debug(P_T) ac_current_idx = [ idx for idx, i in enumerate(current_data_1) if i <= 0.1 * current_data_1[1] ] #wanbin p_rated -> current_data[0] if len(ac_current_idx) != 0: trip_time = time_data[min(ac_current_idx)] t_trip_meas = trip_time - t_start ts.log( 'Voltage change started at %s, EUT trip at %s. Total trip time: %s sec.' % (t_start, trip_time, t_trip_meas)) # Determine pass/fail if t_trip_meas <= t_trip: passfail = 'Pass' else: passfail = 'Fail' else: ts.log_warning('No waveform data collected') raise result_summary.write('%s, %s, %s, %s, %s \n' % (passfail, ts.config_name(), t_trip, t_trip_meas, filename)) result = script.RESULT_COMPLETE except script.ScriptFail, e: reason = str(e) if reason: ts.log_error(reason)
def test_run(): result = script.RESULT_FAIL data = None trigger = None grid = None pv = None inv = None freq = {} W = {} disable = None try: ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') freq_ref = ts.param_value( 'fw.settings.freq_ref') # is there a sunspec parameter for this? fw_mode = ts.param_value('fw.settings.fw_mode') #fw_mode == 'FW21 (FW parameters)': WGra = ts.param_value('fw.settings.WGra') HzStr = ts.param_value('fw.settings.HzStr') HzStop = ts.param_value('fw.settings.HzStop') HysEna = ts.param_value('fw.settings.HysEna') HzStopWGra = ts.param_value('fw.settings.HzStopWGra') #'FW22 (pointwise FW)' time_window = ts.param_value('fw.settings.time_window') timeout_period = ts.param_value('fw.settings.timeout_period') ramp_time = ts.param_value('fw.settings.ramp_time') recovery_ramp_rate = ts.param_value('fw.settings.recovery_ramp_rate') curve_num = ts.param_value('fw.settings.curve_num') n_points = ts.param_value('fw.settings.n_points') freq = ts.param_value('fw.curve.freq') W = ts.param_value('fw.curve.W') pretest_delay = ts.param_value('invt.pretest_delay') power_range = ts.param_value('invt.power_range') setpoint_failure_count = ts.param_value('invt.setpoint_failure_count') setpoint_period = ts.param_value('invt.setpoint_period') verification_delay = ts.param_value('invt.verification_delay') posttest_delay = ts.param_value('invt.posttest_delay') disable = ts.param_value('invt.disable') # initialize data acquisition system daq = das.das_init(ts) data = daq.data_init() trigger = daq.trigger_init() # initialize pv simulation pv = pvsim.pvsim_init(ts) pv.power_on() # initialize grid simulation grid = gridsim.gridsim_init(ts) grid.profile_load(ts.param_value('profile.profile_name')) # Sandia Test Protocol: Communication is established between the Utility Management System Simulator and EUT # EUT scan after grid and PV simulation setup so that Modbus registers can be read. ts.log('Scanning inverter') inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) # Make sure the EUT is on and operating ts.log( 'Verifying EUT is in connected state. Waiting up to %d seconds for EUT to begin power export.' % (verification_delay + pretest_delay)) if verify_initial_conn_state( inv, state=inverter.CONN_CONNECT, time_period=verification_delay + pretest_delay, das=data) is False: ts.log_error('Inverter unable to be set to connected state.') raise script.ScriptFail() ######## Begin Test ######## if pretest_delay > 0: ts.log('Waiting for pre-test delay of %d seconds' % pretest_delay) ts.sleep(pretest_delay) # Request status and display power freq_original = inverter.get_freq(inv, das=data) power_original = inverter.get_power(inv, das=data) ts.log('Current grid frequency is %.3f Hz and EUT power is %.3f W' % (freq_original, power_original)) ### todo: open the ride-through settings at this point to ensure the EUT doesn't trip during freq profile. # ts.log_debug('%s, %s, %s, %s, %s' % (WGra, HzStr, HzStop, HysEna, HzStopWGra)) if HzStopWGra == 0: ts.log_warning( 'Setting HzStopWGra to 10000 because of the limits of the EUT. This is the fastest available option.' ) inverter.set_freq_watt(inv, fw_mode=fw_mode, freq=freq, W=W, n_points=n_points, curve_num=curve_num, timeout_period=timeout_period, ramp_time=ramp_time, recovery_ramp_rate=recovery_ramp_rate, time_window=time_window, WGra=WGra, HzStr=HzStr, HzStop=HzStop, HysEna=HysEna, HzStopWGra=HzStopWGra, enable=1, trigger=trigger) # Run the grid simulator profile immediately after setting the freq-watt functions and triggering if grid is not None: ts.log('Running frequency profile.') grid.profile_start() # power_pass_fail_band only determines the point on the curve. It does not account for hysteresis. pow_targ, pow_upper, pow_lower = power_pass_fail_band( inv, fw_mode=fw_mode, freq=freq, W=W, n_points=n_points, power_range=power_range, WGra=WGra, HzStr=HzStr, freq_ref=freq_ref, das=das) ts.log( 'Target power: %.3f. Pass limits for screening: upper = %.3f lower = %.3f' % (pow_targ, pow_upper, pow_lower)) # Log FW parameters and calculate test_duration test_duration = setpoint_period + verification_delay ts.log( 'Waiting up to %d seconds for power change with a verification period of %d seconds.' % (ramp_time + time_window, verification_delay)) ts.log_debug('dc_voltage = %0.3f' % data.dc_voltage) ts.log_debug('dc_current = %0.3f' % data.dc_current) ts.log_debug('ac_voltage = %0.3f' % data.ac_voltage) ts.log_debug('ac_current = %0.3f' % data.ac_current) ts.log_debug('dc_watts = %0.3f' % data.dc_watts) ts.log_debug('Power = %0.3f' % data.ac_watts) ts.log_debug('ac_freq = %0.3f' % data.ac_freq) ts.log_debug('trigger = %0.3f' % data.trigger) start_time = time.time() elapsed_time = 0 # Initialize consecutive failure count to not script fail on transient behavior failures = 0 revert_complete = False in_hysteresis = False # flag for when the FW is in hysteresis inv.nameplate.read() max_W = float(inv.nameplate.WRtg) if time_window != 0: window_complete = False else: window_complete = True time_window_execution = time_window while elapsed_time <= test_duration: ts.sleep(0.93) elapsed_time = time.time() - start_time power_pct = (inverter.get_power(inv, das=data) / max_W) * 100. #determine if function is in hysteresis if fw_mode == 'FW21 (FW parameters)' and HysEna == 'Yes': freq_new = inverter.get_freq(inv, das=data) if freq_new < freq_original and freq_original > HzStr: if not in_hysteresis: in_hysteresis = True hys_power = power_pct ts.log( 'Entered the Hysteresis band with power limit = %0.3f%%' % hys_power) else: ts.log( 'Still in the Hysteresis band with power limited to %0.3f%%' % hys_power) elif in_hysteresis and freq_new < HzStop: in_hysteresis = False # No longer in hysteresis band ts.log( 'Exited hysteresis band. Returning to FW curve power at HzStopWGra = %0.3f %%nameplate/min' % HzStopWGra) freq_original = freq_new if window_complete is True and revert_complete is False: if in_hysteresis is False: # pow_targ, pow_upper, pow_lower are in percentages of nameplate power pow_targ, pow_upper, pow_lower = power_pass_fail_band( inv, fw_mode=fw_mode, freq=freq, W=W, n_points=n_points, power_range=power_range, WGra=WGra, HzStr=HzStr, freq_ref=freq_ref, das=data) else: # in hysteresis band pow_targ = hys_power pow_upper = pow_targ + power_range # units of % nameplate watts pow_lower = pow_targ - power_range # units of % nameplate watts else: # Before the time window executes and after timeout period, the upper and lower pass/fail bounds for EUT # use the default power state of 100% Wmax pow_targ = 100. pow_upper = pow_targ + power_range # units of % nameplate watts pow_lower = pow_targ - power_range # units of % nameplate watts ts.log( 'W Target = %.3f [%.3f to %.3f], W = %.3f (Error = %0.3f%%), Time: %0.3f seconds.' % (pow_targ, pow_lower, pow_upper, power_pct, (power_pct - pow_targ), elapsed_time)) if revert_complete is False: #if testing FW21, timing parameters are all 0, so they don't affect results # Check when the EUT is in range for the first time if window_complete is False and \ inverter.get_active_control_status(inv, inverter.STACTCTL_FREQ_WATT_PARAM): window_complete = True time_window_execution = elapsed_time ts.log( 'Randomization window occurred at %0.3f seconds, current power %.3f.' % (time_window_execution, power_pct)) # Check for timeout period (reversion) if window_complete and timeout_period != 0: if not inverter.get_active_control_status( inv, inverter.STACTCTL_FREQ_WATT_PARAM): #reverted revert_complete = True ts.log( 'Reversion occurred at timeout period = %0.3f seconds, current power %.3f.' % (elapsed_time, power_pct)) # Did timeout_period fail? If so, end the test here. # Note: there's a final timeout_period check outside the while loop. elif elapsed_time >= timeout_period + min( time_window, time_window_execution) + verification_delay: ts.log_error( 'Inverter did not revert after %0.3f seconds.' % elapsed_time) raise script.ScriptFail() # if power out of range if power_pct < pow_lower or power_pct > pow_upper: ts.log_debug( 'Power %0.3f, Pow Lower = %0.3f, Pow Upper = %0.3f.' % (power_pct, pow_lower, pow_upper)) # There are three acceptable sources of noncompliance. If the randomization window hasn't occurred, # the reversion (timeout) occurred, or it is ramping to the target vars if window_complete is False: #time window ts.log( 'Randomization window still in effect after %0.3f seconds.' % (time.time() - start_time)) elif elapsed_time > min(time_window, time_window_execution) + ramp_time: # Noncompliance is not from time period, time window, or ramp rate # Count this as a failure failures += 1 if failures >= setpoint_failure_count: ts.log_error( 'Inverter exceeded var setpoint + buffer after %0.3f seconds. ' 'Fail count = %d.' % (elapsed_time, failures)) raise script.ScriptFail() else: ts.log_warning( 'Inverter exceeded var setpoint + buffer after %0.3f seconds. ' 'Fail count = %d.' % (elapsed_time, failures)) else: ts.log_warning( 'EUT has not reached the target reactive power because it is ramping.' ) else: failures = 0 # Additional timeout check to determine if the timeout_period occurred during the test. This is necessary # in cases where the verification_delay is not set sufficiently long. if timeout_period != 0 and inverter.get_active_control_status( inv, inverter.STACTCTL_VOLT_VAR): ts.log_error( 'Inverter did not revert by the end of the test duration. Elapsed time = %0.3f seconds. ' 'Increase the verification period if the timeout period is greater than the elapsed time.' % (elapsed_time)) raise script.ScriptFail() if posttest_delay > 0: ts.log('Waiting for post-test delay of %d seconds' % posttest_delay) ts.sleep(posttest_delay) result = script.RESULT_PASS except script.ScriptFail, e: reason = str(e) if reason: ts.log_error(reason)