Пример #1
0
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
Пример #2
0
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
Пример #3
0
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
Пример #4
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)
Пример #5
0
        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:
Пример #6
0
        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
Пример #7
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)
Пример #8
0
                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()
Пример #9
0
        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