def log_conn_state(inv, data=None): try: connected = inverter.get_conn_state(inv) power = inverter.get_power(inv, data) ts.log('Current connection state is %s - power output = %0.3f W' % (inverter.conn_state_str(connected), power)) except Exception, e: ts.log('Error logging connect state: %s' % str(e)) raise
def log_conn_state(inv, data=None): try: connected = inverter.get_conn_state(inv) power = inverter.get_power(inv, data) pf = inverter.get_power_factor(inv, data) ts.log('Current connection state is %s. Power output = %0.3f W. power factor %0.3f.' % (inverter.conn_state_str(connected), power, pf)) except Exception, e: ts.log_error('Error logging connect state: %s' % str(e)) raise
def verify_conn_state_change(inv, state, time_window=0, timeout_period=0, verification_delay=5, threshold=50, data=None): result = None start_time = time.time() elapsed_time = 0 # Time window takes precedence over timeout period: time_window is passed first when time_window and timeout_period # are used at the same time. if time_window != 0: time_period = time_window + verification_delay # Note: the actual amount of time allowed for the change is time_period, not time_window ts.log('Randomization window in use. Waiting up to %d seconds for %s state' % (time_window, inverter.conn_state_str(state))) elif timeout_period != 0: time_period = timeout_period + verification_delay # Note: the actual amount of time allowed for the change is time_period, not timeout_period ts.log('Time period in use. Waiting up to %d seconds for EUT to revert to %s. ' 'Verification time is %d seconds.' % (timeout_period, inverter.conn_state_str(state), verification_delay)) else: time_period = verification_delay ts.log('Waiting for verification delay of up to %d seconds' % verification_delay) while result is None: if elapsed_time <= time_period: power = inverter.get_power(inv, data) ts.log('Elapsed time is %0.3f seconds, EUT power is %0.3f W' % (elapsed_time, power)) if not inverter.verify_conn_state(inv, state, threshold, data): ts.sleep(0.89) # Attempt to make loop exactly 1 second elapsed_time = time.time()-start_time else: ts.log('State changed to %s after %0.3f seconds' % (inverter.conn_state_str(state), elapsed_time)) result = True else: ts.log('Connection state did not change within required time') result = False log_conn_state(inv, data) return result
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)
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)) for power_limit_pct in [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]: # Sandia Test Protocol Step 4: Issue power curtailment function # (Trigger set immediately before sending the enable command to the DER) inv.controls.read() inv.controls.WMaxLimPct = power_limit_pct inv.controls.write() curr_power = inverter.get_power(inv, das=None) ts.log('INV2 setpoint changed to %d%%, power = %d W' % (power_limit_pct, curr_power)) time.sleep(3) except script.ScriptFail, e: reason = str(e) if reason: ts.log_error(reason) finally: if trigger: trigger.off() if pv is not None: pv.close() if disable == 'yes' and inv is not None:
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)) # Sandia Test Protocol Step 3: EUT output power is measured and logged power_original = float(inverter.get_power(inv, das=data)) ts.log('Inverter power = %0.3f W' % power_original) # Sandia Test Protocol Step 4: Issue power curtailment function # (Trigger set immediately before sending the enable command to the DER) inverter.set_power_limit(inv, time_window=time_window, timeout_period=timeout_period, ramp_time=ramp_time, power_limit_pct=power_limit_pct, enable=1, trigger=trigger) # Start the pv simulator irradiance profile pv.profile_start() # Store INV2 execution time for determining when time window and timeout period occur # Note: this is below the pv.profile_start command to allow the manual operator time to begin he profile. start_time = time.time() elapsed_time = 0
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)
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)) # Sandia Test Protocol Step 3: EUT output power is measured and logged power_original = float(inverter.get_power(inv, das=data)) ts.log('Inverter power = %0.3f W' % power_original) # Sandia Test Protocol Step 4: Issue power curtailment function # (Trigger set immediately before sending the enable command to the DER) inverter.set_power_limit(inv, time_window=time_window, timeout_period=timeout_period, ramp_time=ramp_time, power_limit_pct=power_limit_pct, enable=1, trigger=trigger) # Start the pv simulator irradiance profile pv.profile_start()
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)) for power_limit_pct in [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]: # Sandia Test Protocol Step 4: Issue power curtailment function # (Trigger set immediately before sending the enable command to the DER) inv.controls.read() inv.controls.WMaxLimPct = power_limit_pct inv.controls.write() curr_power = inverter.get_power(inv, das=None) ts.log('INV2 setpoint changed to %d%%, power = %d W' % (power_limit_pct, curr_power)) time.sleep(3) except script.ScriptFail, e: reason = str(e) if reason: ts.log_error(reason) finally: if trigger: trigger.off() if pv is not None: pv.close() if disable == 'yes' and inv is not None: inv.controls.WMaxLim_Ena = 0