def test_run():

    # initialize data acquisition system
    daq_1 = das.das_init(ts, id=1)
    daq_2 = das.das_init(ts, id=2)

    daq_1.data_capture(True)
    daq_2.data_capture(True)
    ts.sleep(2)

    ts.log('current data 1: %s' % daq_1.data_capture_read())
    ts.log('current data 2: %s' % daq_2.data_capture_read())

    # initialize EUTs
    der_1 = der.der_init(ts, id=1)
    der_2 = der.der_init(ts, id=2)

    der_1.config()
    der_2.config()

    der_1.inv.common.read()
    ts.log("Common Model is %s" % der_1.inv.common)

    der_2.inv.common.read()
    ts.log("Common Model is %s" % der_2.inv.common)

    return script.RESULT_COMPLETE
예제 #2
0
def test_run():

    # initialize DER configuration
    eut_1 = der.der_init(ts, id=1)
    eut_2 = der.der_init(ts, id=2)
    eut_3 = der.der_init(ts, id=3)
    eut_1.config()
    eut_2.config()
    eut_3.config()

    for i in range(10):
        for pf in [
                -0.1, -0.25, -0.35, -.5, -.6, -.7, -.8, -.9, 1, .9, .8, .7, .6,
                .5, .4, .3, .2, .1
        ]:
            eut_1.fixed_pf(params={
                'Ena': True,
                'PF': pf,
                'WinTms': 0,
                'RmpTms': 0,
                'RvrtTms': 0
            })
            eut_2.fixed_pf(params={
                'Ena': True,
                'PF': pf,
                'WinTms': 0,
                'RmpTms': 0,
                'RvrtTms': 0
            })
            eut_3.fixed_pf(params={
                'Ena': True,
                'PF': pf,
                'WinTms': 0,
                'RmpTms': 0,
                'RvrtTms': 0
            })
            ts.log('Sleeping 3 seconds...')
            ts.sleep(5)

    return script.RESULT_COMPLETE
def test_run():

    # initialize DER configuration
    eut = der.der_init(ts)
    eut.config()

    ts.log('---')
    info = eut.info()
    if info is not None:
        ts.log('DER info:')
        ts.log('  Manufacturer: %s' % (info.get('Manufacturer')))
        ts.log('  Model: %s' % (info.get('Model')))
        ts.log('  Options: %s' % (info.get('Options')))
        ts.log('  Version: %s' % (info.get('Version')))
        ts.log('  Serial Number: %s' % (info.get('SerialNumber')))
    else:
        ts.log_warning('DER info not supported')
    ts.log('---')

    for power in range(5, 25, 2):
        eut.limit_max_power(params={'Ena': True, 'WMaxPct': power})
        limit_max_power = eut.limit_max_power()
        if limit_max_power is not None:
            ts.log('DER limit_max_power:')
            ts.log('  Ena: %s' % (limit_max_power.get('Ena')))
            ts.log('  WMaxPct: %s' % (limit_max_power.get('WMaxPct')))

    for pf in [1, -0.85, -.9, -.95, 1, .95, .9, .85]:
        eut.fixed_pf(params={'Ena': True, 'PF': pf})
        fixed_pf = eut.fixed_pf()
        if fixed_pf is not None:
            ts.log('DER power factor:')
            ts.log('  Ena: %s' % (fixed_pf.get('Ena')))
            ts.log('  PF: %s' % (fixed_pf.get('PF')))

    return script.RESULT_COMPLETE
예제 #4
0
def watt_var_mode(wv_curves, wv_response_time):

    result = script.RESULT_FAIL
    daq = None
    v_nom = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None
    dataset_filename = None

    try:
        cat = ts.param_value('eut.cat')
        cat2 = ts.param_value('eut.cat2')
        sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        p_rated_prime = ts.param_value('eut.p_rated_prime')
        var_rated = ts.param_value('eut.var_rated')
        s_rated = ts.param_value('eut.s_rated')

        # DC voltages
        v_in_nom = ts.param_value('eut.v_in_nom')
        #v_min_in = ts.param_value('eut.v_in_min')
        #v_max_in = ts.param_value('eut.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_low = ts.param_value('eut.v_low')
        v_high = ts.param_value('eut.v_high')
        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')

        # EUI Absorb capabilities
        absorb = {}
        absorb['ena'] = ts.param_value('eut_cpf.sink_power')
        """
        A separate module has been create for the 1547.1 Standard
        """
        lib_1547 = p1547.module_1547(ts=ts, aif='WV', absorb=absorb)
        ts.log_debug("1547.1 Library configured for %s" %
                     lib_1547.get_test_name())

        # result params
        result_params = lib_1547.get_rslt_param_plot()
        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''

        # initialize HIL environment, if necessary
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()

        # DAS soft channels
        das_points = lib_1547.get_sc_points()
        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'])
        daq.sc['P_TARGET'] = p_min
        daq.sc['Q_TARGET'] = 100
        daq.sc['Q_TARGET_MIN'] = 100
        daq.sc['Q_TARGET_MAX'] = 100
        daq.sc['event'] = 'None'
        ts.log('DAS device: %s' % daq.info())

        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized
            if callable(getattr(daq, "set_dc_measurement", None)
                        ):  # for DAQs that don't natively have dc measurements
                daq.set_dc_measurement(
                    pv)  # send pv obj to daq to get dc measurements
                ts.sleep(0.5)

        eut = der.der_init(ts)
        if eut is not None:
            eut.config()
            ts.log_debug(eut.measurements())

        # Special considerations for CHIL ASGC/Typhoon startup
        if chil is not None:
            if chil.hil_info()['mode'] == 'Typhoon':
                inv_power = eut.measurements().get('W')
                timeout = 120.
                if inv_power <= p_rated * 0.85:
                    pv.irradiance_set(
                        995)  # Perturb the pv slightly to start the inverter
                    ts.sleep(3)
                    eut.connect(params={'Conn': True})
                while inv_power <= p_rated * 0.85 and timeout >= 0:
                    ts.log(
                        'Inverter power is at %0.1f. Waiting up to %s more seconds or until EUT starts...'
                        % (inv_power, timeout))
                    ts.sleep(1)
                    timeout -= 1
                    inv_power = eut.measurements().get('W')
                    if timeout == 0:
                        result = script.RESULT_FAIL
                        raise der.DERError('Inverter did not start.')
                ts.log('Waiting for EUT to ramp up')
                ts.sleep(8)
                ts.log_debug('DAS data_read(): %s' % daq.data_read())
        '''
        b) Set all AC test source parameters to the nominal operating voltage and frequency.
        '''
        grid = gridsim.gridsim_init(
            ts)  # Turn on AC so the EUT can be initialized
        if grid is not None:
            # for HIL-based gridsim objects, link the chil parameters to voltage/frequency simulink parameters
            if callable(getattr(grid, "gridsim_info", None)):
                if grid.gridsim_info()['mode'] == 'Opal':
                    grid.config(hil_object=chil)
            grid.voltage(v_nom)

        # 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)
        result_summary.write(lib_1547.get_rslt_sum_col_name())
        '''
        c) Set all EUT parameters to the rated active power conditions for the EUT.
        '''
        if pv is not None:
            pv.iv_curve_config(pmp=p_rated, vmp=v_in_nom)
            pv.irradiance_set(1000.)
            ts.log('Waiting for EUT to power up. Sleeping 30 sec.')
            ts.sleep(30)
        '''
        d) Set all voltage trip parameters to default settings.
        '''
        try:
            eut.vrt_stay_connected_high(
                params={
                    'Ena': True,
                    'ActCrv': 0,
                    'Tms1': 3000,
                    'V1': v_high,
                    'Tms2': 0.16,
                    'V2': v_high
                })
        except Exception, e:
            ts.log_error('Could not set VRT Stay Connected High curve. %s' % e)
        try:
            eut.vrt_stay_connected_low(
                params={
                    'Ena': True,
                    'ActCrv': 0,
                    'Tms1': 3000,
                    'V1': v_low,
                    'Tms2': 0.16,
                    'V2': v_low
                })
        except Exception, e:
            ts.log_error('Could not set VRT Stay Connected Low curve. %s' % e)
예제 #5
0
def test_run():

    eut = None
    chil = None
    daq = None
    pv = None
    result_summary = None
    result = script.RESULT_FAIL

    # result params
    result_params = {
        'plot.title': ts.name,
        'plot.x.title': 'Time (sec)',
        'plot.x.points': 'TIME',
        'plot.y.points': 'W_TARG, W_TOTAL, W_INV',
        'plot.y.title': 'EUT Power (W)',
    }

    try:
        # Initialize DER configuration
        eut = der.der_init(ts)
        eut.config()

        # Initialize CHIL environment, if necessary
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()

        # PV simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        pv.irradiance_set(1000)
        pv.power_on()

        # Initialize data acquisition with soft channels (sc) that include data that doesn't come from the DAQ
        sc_points = ['W_TARG', 'W_TOTAL', 'W_INV']
        daq = das.das_init(ts, sc_points=sc_points)
        ts.log('DAS device: %s' % daq.info())

        # Open result summary file - this will include a selection of DAQ data to evaluate performance of the EUT
        result_summary_filename = 'result_summary.csv'
        result_summary = open(ts.result_file_path(result_summary_filename),
                              'a+')  # Open .csv file
        ts.result_file(
            result_summary_filename)  # create result file in the GUI
        # Write result summary header
        result_summary.write(
            'Test Name, Power Setting (%), Inverter-Reported Power (W), DAS Power (W), '
            'Inverter-Reported Power (%), DAS Power (%)\n')

        # Get EUT nameplate power
        eut_nameplate_power = eut.nameplate().get('WRtg')

        inv_power = eut.measurements().get('W')
        timeout = 20.
        if inv_power <= eut_nameplate_power / 10.:
            eut.connect(params={'Conn': True})
            pv.irradiance_set(
                995)  # Perturb the pv slightly to start the inverter
        while inv_power <= eut_nameplate_power / 10. and timeout >= 0:
            ts.log(
                'Inverter power is at %0.1f. Waiting %s more seconds or until EUT starts...'
                % (inv_power, timeout))
            ts.sleep(1)
            timeout -= 1
            inv_power = eut.measurements().get('W')
            if timeout == 0:
                result = script.RESULT_FAIL
                raise der.DERError('Inverter did not start.')

        for time_loop in range(2):
            daq.data_capture(True)  # Begin data capture for this power loop

            for power_limit_pct in [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]:
                daq.sc['W_TARG'] = eut_nameplate_power * (
                    float(power_limit_pct) / 100.)
                eut.limit_max_power(params={
                    'Ena': True,
                    'WMaxPct': power_limit_pct
                })
                ts.log('EUT power set to %0.2f%%' % power_limit_pct)
                ts.sleep(2)
                daq.sc['W_INV'] = eut.measurements().get(
                    'W')  # Get the inverter-measured power and save it.
                daq.data_sample(
                )  # force a data capture point after the sleep and add this to the dataset
                daq_data = daq.data_capture_read(
                )  # read the last data point dictionary from the daq object
                try:  # if 3 phase device add up the power from each phase
                    daq.sc['W_TOTAL'] = daq_data['AC_P_1'] + daq_data[
                        'AC_P_2'] + daq_data['AC_P_2']
                except Exception, e:  # if single phase device
                    daq.sc['W_TOTAL'] = daq_data['AC_P_1']
                # Record 1 set of power values for each power level setting
                result_summary.write(
                    '%s, %s, %s, %s, %s, %s\n' %
                    (time_loop + 1, power_limit_pct, daq.sc['W_INV'],
                     daq.sc['W_TOTAL'], daq.sc['W_INV'] / eut_nameplate_power,
                     daq.sc['W_TOTAL'] / eut_nameplate_power))

            daq.data_capture(False)  # Stop data capture
            ds = daq.data_capture_dataset(
            )  # generate dataset from the daq data that was recorded
            testname = 'CurtailmentRun_%s' % (str(time_loop + 1)
                                              )  # Pick name for the DAS data
            filename = testname + '.csv'  # Pick name for the DAS .csv data file
            ds.to_csv(
                ts.result_file_path(filename))  # Convert data to .cvs file
            result_params[
                'plot.title'] = testname  # update title for the excel plot for this dataset
            ts.result_file(
                filename, params=result_params
            )  # Add results info to .xml log, which will be used to plot
            ts.log('Saving data capture: %s' % filename)

        result = script.RESULT_COMPLETE
예제 #6
0
def volt_vars_mode(vv_curves, vv_response_time, pwr_lvls, v_ref_value):

    result = script.RESULT_FAIL
    daq = None
    v_nom = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None
    dataset_filename = None

    try:
        cat = ts.param_value('eut.cat')
        cat2 = ts.param_value('eut.cat2')
        sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        p_rated_prime = ts.param_value('eut.p_rated_prime')
        var_rated = ts.param_value('eut.var_rated')
        s_rated = ts.param_value('eut.s_rated')

        #absorb_enable = ts.param_value('eut.abs_enabled')
        # DC voltages
        v_in_nom = ts.param_value('eut.v_in_nom')
        #v_min_in = ts.param_value('eut.v_in_min')
        #v_max_in = ts.param_value('eut.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_low = ts.param_value('eut.v_low')
        v_high = ts.param_value('eut.v_high')
        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')

        """
        Version validation
        """
        p1547.VersionValidation(script_version=ts.info.version)

        """
        A separate module has been create for the 1547.1 Standard
        """
        ActiveFunction = p1547.ActiveFunction(ts=ts,
                                              functions=[VV],
                                              script_name='Volt-Var',
                                              criteria_mode=[True, True, True])
        ts.log_debug("1547.1 Library configured for %s" % ActiveFunction.get_script_name())

        # result params
        result_params = ActiveFunction.get_rslt_param_plot()
        ts.log_debug(result_params)

        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''
        ts.log_debug(15*"*"+"HIL initialization"+15*"*")

        # initialize HIL environment, if necessary
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()
        ts.log_debug(15*"*"+"PVSIM initialization"+15*"*")
        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts, support_interfaces={'hil': chil}) 
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized
            #daq.set_dc_measurement(pv)  # send pv obj to daq to get dc measurements
            ts.sleep(0.5)

        # DAS soft channels
        ts.log_debug(15*"*"+"DAS initialization"+15*"*")

        #das_points = {'sc': ('Q_TARGET', 'Q_TARGET_MIN', 'Q_TARGET_MAX', 'Q_MEAS', 'V_TARGET', 'V_MEAS', 'event')}
        das_points = ActiveFunction.get_sc_points()
        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'], support_interfaces={'hil': chil}) 

        daq.sc['V_TARGET'] = v_nom
        daq.sc['Q_TARGET'] = 100
        daq.sc['Q_TARGET_MIN'] = 100
        daq.sc['Q_TARGET_MAX'] = 100
        daq.sc['event'] = 'None'

        ts.log('DAS device: %s' % daq.info())

        '''
        b) Set all voltage trip parameters to the widest range of adjustability.  Disable all reactive/active power
        control functions.
        '''
        ts.log_debug(15*"*"+"EUT initialization"+15*"*")

        eut = der.der_init(ts, support_interfaces={'hil': chil}) 
        if eut is not None:
            eut.config()
            ts.log_debug(eut.measurements())

            #Deactivating all functions on EUT
            #eut.deactivate_all_fct()

            ts.log_debug('Voltage trip parameters set to the widest range: v_min: {0} V, '
                         'v_max: {1} V'.format(v_low, v_high))
            try:
                eut.vrt_stay_connected_high(params={'Ena': True, 'ActCrv': 0, 'Tms1': 3000,
                                                    'V1': v_high, 'Tms2': 0.16, 'V2': v_high})
            except Exception as e:
                ts.log_error('Could not set VRT Stay Connected High curve. %s' % e)
            try:
                eut.vrt_stay_connected_low(params={'Ena': True, 'ActCrv': 0, 'Tms1': 3000,
                                                   'V1': v_low, 'Tms2': 0.16, 'V2': v_low})
            except Exception as e:
                ts.log_error('Could not set VRT Stay Connected Low curve. %s' % e)
        else:
            ts.log_debug('Set L/HVRT and trip parameters set to the widest range of adjustability possible.')

        # # Special considerations for CHIL ASGC/Typhoon startup
        if chil is not None:
            if eut is not None:
                if eut.measurements() is not None:
                    inv_power = eut.measurements().get('W')
                    timeout = 120.
                    if inv_power <= p_rated * 0.85:
                        pv.irradiance_set(995)  # Perturb the pv slightly to start the inverter
                        ts.sleep(3)
                        eut.connect(params={'Conn': True})
                    while inv_power <= p_rated * 0.85 and timeout >= 0:
                        ts.log('Inverter power is at %0.1f. Waiting up to %s more seconds or until EUT starts...' %
                            (inv_power, timeout))
                        ts.sleep(1)
                        timeout -= 1
                        inv_power = eut.measurements().get('W')
                        if timeout == 0:
                            result = script.RESULT_FAIL
                            raise der.DERError('Inverter did not start.')
                    ts.log('Waiting for EUT to ramp up')
                    ts.sleep(8)
                    ts.log_debug('DAS data_read(): %s' % daq.data_read())

        '''
        c) Set all AC test source parameters to the nominal operating voltage and frequency.
        '''
        ts.log_debug(15*"*"+"GRIDSIM initialization"+15*"*")

        grid = gridsim.gridsim_init(ts,support_interfaces={'hil': chil})  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)
            if chil is not None:  # If using HIL, give the grid simulator the hil object
                grid.config()

        # 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)
        result_summary.write(ActiveFunction.get_rslt_sum_col_name())

        '''
        d) Adjust the EUT's available active power to Prated. For an EUT with an input voltage range, set the input
        voltage to Vin_nom. The EUT may limit active power throughout the test to meet reactive power requirements.
        For an EUT with an input voltage range.
        '''

        if pv is not None:
            pv.iv_curve_config(pmp=p_rated, vmp=v_in_nom)
            pv.irradiance_set(1000.)

        '''
        gg) Repeat steps g) through dd) for characteristics 2 and 3.
        '''
        for vv_curve in vv_curves:
            ts.log('Starting test with characteristic curve %s' % (vv_curve))
            ActiveFunction.reset_curve(vv_curve)
            ActiveFunction.reset_time_settings(tr=vv_response_time[vv_curve], number_tr=2)
            v_pairs = ActiveFunction.get_params(function=VV, curve=vv_curve)
            #ts.log_debug('v_pairs:%s' % v_pairs)

            '''
            ff) Repeat test steps d) through ee) at EUT power set at 20% and 66% of rated power.
            '''
            for power in pwr_lvls:
                ActiveFunction.reset_pwr(power)

                if pv is not None:
                    pv_power_setting = (p_rated * power)
                    pv.iv_curve_config(pmp=pv_power_setting, vmp=v_in_nom)
                    pv.irradiance_set(1000.)

                # Special considerations for CHIL ASGC/Typhoon startup #
                # Why does it need to appear twice, shouldn't this be at the driver level
                if chil is not None:
                    if eut is not None:
                        if  eut.measurements() is not None:
                            inv_power = eut.measurements().get('W')
                            timeout = 120.
                            if inv_power <= pv_power_setting * 0.85:
                                pv.irradiance_set(995)  # Perturb the pv slightly to start the inverter
                                ts.sleep(3)
                                eut.connect(params={'Conn': True})
                            while inv_power <= pv_power_setting * 0.85 and timeout >= 0:
                                ts.log('Inverter power is at %0.1f. Waiting up to %s more seconds or until EUT starts...' %
                                    (inv_power, timeout))
                                ts.sleep(1)
                                timeout -= 1
                                inv_power = eut.measurements().get('W')
                                if timeout == 0:
                                    result = script.RESULT_FAIL
                                    raise der.DERError('Inverter did not start.')
                            ts.log('Waiting for EUT to ramp up')
                            ts.sleep(8)
                    



                '''
                ee) Repeat test steps e) through dd) with Vref set to 1.05*VN and 0.95*VN, respectively.
                '''
                for v_ref in v_ref_value:
                    ts.log('Setting v_ref at %s %% of v_nom' % (int(v_ref * 100)))

                    #Setting grid to vnom before test
                    if grid is not None:
                        grid.voltage(v_nom)

                    if eut is not None:
                        '''
                        e) Set EUT volt-var parameters to the values specified by Characteristic 1.
                        All other function should be turned off. Turn off the autonomously adjusting reference voltage.
                        '''
                        # Activate volt-var function with following parameters
                        # SunSpec convention is to use percentages for V and Q points.
                        vv_curve_params = {
                            'v': [(v_pairs['V1'] / v_nom) , (v_pairs['V2'] / v_nom) ,
                                  (v_pairs['V3'] / v_nom), (v_pairs['V4'] / v_nom) ],
                            'var': [(v_pairs['Q1'] / s_rated), (v_pairs['Q2'] / s_rated) ,
                                    (v_pairs['Q3'] / s_rated) , (v_pairs['Q4'] / s_rated)],
                            'vref': v_ref,
                            'RmpPtTms': vv_response_time[vv_curve]
                        }
                        ts.log_debug('Sending VV points: %s' % vv_curve_params)
                        eut.volt_var(params={'Ena': True, 'ACTCRV': vv_curve, 'curve': vv_curve_params})
                        # TODO autonomous vref adjustment to be included
                        # eut.autonomous_vref_adjustment(params={'Ena': False})
                        '''
                        f) Verify volt-var mode is reported as active and that the correct characteristic is reported.
                        '''
                        ts.log_debug('Initial EUT VV settings are %s' % eut.volt_var())
                    if chil is not None:                        
                        ts.log('Start simulation of CHIL')  
                        chil.start_simulation()
                    v_steps_dict = ActiveFunction.create_vv_dict_steps(v_ref=v_ref)

                    dataset_filename = 'VV_%s_PWR_%d_vref_%d' % (vv_curve, power * 100, v_ref*100)
                    ActiveFunction.reset_filename(filename=dataset_filename)
                    #ts.log('------------{}------------'.format(dataset_filename))
                    # Start the data acquisition systems
                    daq.data_capture(True)

                    for step_label, v_step in v_steps_dict.items():

                        ts.log('Voltage step: setting Grid simulator voltage to %s (%s)' % (v_step, step_label))

                        ActiveFunction.start(daq=daq, step_label=step_label)
                        step_dict = {'V': v_step}

                        if grid is not None:
                            grid.voltage(step_dict['V'])

                        ActiveFunction.record_timeresponse(daq=daq)
                        ActiveFunction.evaluate_criterias(daq=daq, step_dict=step_dict)
                        result_summary.write(ActiveFunction.write_rslt_sum())

                    ts.log('Sampling complete')
                    dataset_filename = dataset_filename + ".csv"
                    daq.data_capture(False)
                    ds = daq.data_capture_dataset()
                    ts.log('Saving file: %s' % dataset_filename)
                    ds.to_csv(ts.result_file_path(dataset_filename))
                    result_params['plot.title'] = dataset_filename.split('.csv')[0]
                    ts.result_file(dataset_filename, params=result_params)
                    result = script.RESULT_COMPLETE



    except script.ScriptFail as e:
        reason = str(e)
        if reason:
            ts.log_error(reason)

    except Exception as e:
        if dataset_filename is not None:
            dataset_filename = dataset_filename + ".csv"
            daq.data_capture(False)
            ds = daq.data_capture_dataset()
            ts.log('Saving file: %s' % dataset_filename)
            ds.to_csv(ts.result_file_path(dataset_filename))
            result_params['plot.title'] = dataset_filename.split('.csv')[0]
            ts.result_file(dataset_filename, params=result_params)
        ts.log_error('Test script exception: %s' % traceback.format_exc())

    finally:
        if daq is not None:
            daq.close()
        if pv is not None:
            pv.close()
        if grid is not None:
            if v_nom is not None:
                grid.voltage(v_nom)
            grid.close()
        if chil is not None:
            chil.close()
        if eut is not None:
            #eut.volt_var(params={'Ena': False})
            eut.close()
        if result_summary is not None:
            result_summary.close()


    return result
예제 #7
0
def volt_vars_mode(vv_curves, vv_response_time, pwr_lvls, v_ref_value):

    result = script.RESULT_FAIL
    daq = None
    v_nom = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None
    dataset_filename = None

    try:
        cat = ts.param_value('eut.cat')
        cat2 = ts.param_value('eut.cat2')
        sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        p_rated_prime = ts.param_value('eut.p_rated_prime')
        var_rated = ts.param_value('eut.var_rated')
        s_rated = ts.param_value('eut.s_rated')

        #absorb_enable = ts.param_value('eut.abs_enabled')
        # DC voltages
        v_in_nom = ts.param_value('eut.v_in_nom')
        #v_min_in = ts.param_value('eut.v_in_min')
        #v_max_in = ts.param_value('eut.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_low = ts.param_value('eut.v_low')
        v_high = ts.param_value('eut.v_high')
        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')
        """
        A separate module has been create for the 1547.1 Standard
        """
        lib_1547 = p1547.module_1547(ts=ts, aif='VV')
        ts.log_debug("1547.1 Library configured for %s" %
                     lib_1547.get_test_name())

        # result params
        result_params = lib_1547.get_rslt_param_plot()
        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''

        # initialize HIL environment, if necessary
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()

        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized

        # DAS soft channels
        # TODO : add to library 1547
        das_points = {
            'sc': ('Q_TARGET', 'Q_TARGET_MIN', 'Q_TARGET_MAX', 'Q_MEAS',
                   'V_TARGET', 'V_MEAS', 'event')
        }

        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'])

        daq.sc['V_TARGET'] = v_nom
        daq.sc['Q_TARGET'] = 100
        daq.sc['Q_TARGET_MIN'] = 100
        daq.sc['Q_TARGET_MAX'] = 100
        daq.sc['event'] = 'None'

        ts.log('DAS device: %s' % daq.info())
        '''
        b) Set all voltage trip parameters to the widest range of adjustability.  Disable all reactive/active power
        control functions.
        '''

        eut = der.der_init(ts)
        if eut is not None:
            eut.config()
            ts.log_debug(eut.measurements())

            eut.volt_var(params={'Ena': False})
            eut.volt_watt(params={'Ena': False})
            eut.fixed_pf(params={'Ena': False})
            ts.log_debug(
                'Voltage trip parameters set to the widest range: v_min: {0} V, '
                'v_max: {1} V'.format(v_low, v_high))
            try:
                eut.vrt_stay_connected_high(
                    params={
                        'Ena': True,
                        'ActCrv': 0,
                        'Tms1': 3000,
                        'V1': v_high,
                        'Tms2': 0.16,
                        'V2': v_high
                    })
            except Exception, e:
                ts.log_error(
                    'Could not set VRT Stay Connected High curve. %s' % e)
            try:
                eut.vrt_stay_connected_low(
                    params={
                        'Ena': True,
                        'ActCrv': 0,
                        'Tms1': 3000,
                        'V1': v_low,
                        'Tms2': 0.16,
                        'V2': v_low
                    })
            except Exception, e:
                ts.log_error('Could not set VRT Stay Connected Low curve. %s' %
                             e)
예제 #8
0
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)
예제 #9
0
def volt_watt_mode_imbalanced_grid(imbalance_resp, vw_curves,
                                   vw_response_time):

    result = script.RESULT_FAIL
    daq = None
    p_rated = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None

    try:
        cat = ts.param_value('eut.cat')
        cat2 = ts.param_value('eut.cat2')
        p_rated = ts.param_value('eut.p_rated')
        s_rated = ts.param_value('eut.s_rated')

        # DC voltages
        v_in_nom = ts.param_value('eut.v_in_nom')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_min = ts.param_value('eut.v_low')
        v_max = ts.param_value('eut.v_high')
        p_min = ts.param_value('eut.p_min')
        phases = ts.param_value('eut.phases')
        imbalance_fix = ts.param_value('vw.imbalance_fix')

        # EUI Absorb capabilities
        absorb = {}
        absorb['ena'] = ts.param_value('eut_vw.sink_power')
        absorb['p_rated_prime'] = ts.param_value('eut_vw.p_rated_prime')
        absorb['p_min_prime'] = ts.param_value('eut_vw.p_min_prime')
        """
        A separate module has been create for the 1547.1 Standard
        """
        ActiveFunction = p1547.ActiveFunction(ts=ts,
                                              functions=[VW],
                                              script_name='Volt-Watt',
                                              criteria_mode=[True, True, True])
        ts.log_debug('1547.1 Library configured for %s' %
                     ActiveFunction.get_script_name())

        ActiveFunction.set_imbalance_config(imbalance_angle_fix=imbalance_fix)
        ts.log_debug('1547.1 Library configured for %s' %
                     ActiveFunction.get_script_name())
        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''
        ts.log_debug(15 * "*" + "HIL initialization" + 15 * "*")

        # initialize HIL environment, if necessary
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()
        ts.log_debug(15 * "*" + "GRIDSIM initialization" + 15 * "*")
        # grid simulator is initialized with test parameters and enabled
        grid = gridsim.gridsim_init(ts, support_interfaces={
            'hil': chil
        })  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)
        ts.log_debug(15 * "*" + "PVSIM initialization" + 15 * "*")
        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized
        ts.log_debug(15 * "*" + "DAS initialization" + 15 * "*")
        # DAS soft channels
        #das_points = {'sc': ('P_TARGET', 'P_TARGET_MIN', 'P_TARGET_MAX', 'P_MEAS', 'V_TARGET', 'V_MEAS', 'event')}
        das_points = ActiveFunction.get_sc_points()

        # initialize data acquisition system
        daq = das.das_init(ts,
                           sc_points=das_points['sc'],
                           support_interfaces={'hil': chil})

        if daq is not None:
            daq.sc['P_TARGET'] = p_rated
            daq.sc['P_TARGET_MIN'] = 100
            daq.sc['P_TARGET_MAX'] = 100
            daq.sc['V_TARGET'] = v_nom
            daq.sc['event'] = 'None'

        ts.log('DAS device: %s' % daq.info())
        '''
        b) Set all voltage trip parameters to the widest range of adjustability. Disable all reactive/active power
        control functions.
        '''
        ts.log_debug(15 * "*" + "EUT initialization" + 15 * "*")

        eut = der.der_init(ts, support_interfaces={'hil': chil})
        if eut is not None:
            eut.config()
            #Disable all functions on EUT
            #eut.deactivate_all_fct()
            ts.log_debug(eut.measurements())
            ts.log_debug(
                'L/HVRT and trip parameters set to the widest range : v_min: {0} V, v_max: {1} V'
                .format(v_min, v_max))
            try:
                eut.vrt_stay_connected_high(
                    params={
                        'Ena': True,
                        'ActCrv': 0,
                        'Tms1': 3000,
                        'V1': v_max,
                        'Tms2': 0.16,
                        'V2': v_max
                    })
            except Exception as e:
                ts.log_error(
                    'Could not set VRT Stay Connected High curve. %s' % e)
            try:
                eut.vrt_stay_connected_low(
                    params={
                        'Ena': True,
                        'ActCrv': 0,
                        'Tms1': 3000,
                        'V1': v_min,
                        'Tms2': 0.16,
                        'V2': v_min
                    })
            except Exception as e:
                ts.log_error('Could not set VRT Stay Connected Low curve. %s' %
                             e)
        else:
            ts.log_debug(
                'Set L/HVRT and trip parameters set to the widest range of adjustability possible.'
            )

        # Special considerations for CHIL ASGC/Typhoon startup
        if chil is not None:
            if eut is not None:
                inv_power = eut.measurements().get('W')
                timeout = 120.
                if inv_power <= p_rated * 0.85:
                    pv.irradiance_set(
                        995)  # Perturb the pv slightly to start the inverter
                    ts.sleep(3)
                    eut.connect(params={'Conn': True})
                while inv_power <= p_rated * 0.85 and timeout >= 0:
                    ts.log(
                        'Inverter power is at %0.1f. Waiting up to %s more seconds or until EUT starts...'
                        % (inv_power, timeout))
                    ts.sleep(1)
                    timeout -= 1
                    inv_power = eut.measurements().get('W')
                    if timeout == 0:
                        result = script.RESULT_FAIL
                        raise der.DERError('Inverter did not start.')
                ts.log('Waiting for EUT to ramp up')
                ts.sleep(8)
        '''
        c) Set all AC test source parameters to the nominal operating voltage and frequency.
        '''
        if grid is not None:
            grid.voltage(v_nom)

        # 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)
        result_summary.write(ActiveFunction.get_rslt_sum_col_name())
        '''
        d) Adjust the EUT's available active power to Prated. For an EUT with an input voltage range, set the input
        voltage to Vin_nom.
        '''
        if pv is not None:
            pv.iv_curve_config(pmp=p_rated, vmp=v_in_nom)
            pv.irradiance_set(1000.)

        for imbalance_response in imbalance_resp:
            for vw_curve in vw_curves:
                '''
                e) Set EUT volt-watt parameters to the values specified by Characteristic 1. All other function be
                turned off.
                '''
                if eut is not None:
                    #eut.deactivate_all_fct()
                    pass
                ts.log('Starting test with characteristic curve %s' %
                       (vw_curve))
                ActiveFunction.reset_curve(vw_curve)
                ActiveFunction.reset_time_settings(
                    tr=vw_response_time[vw_curve], number_tr=2)
                v_pairs = ActiveFunction.get_params(curve=vw_curve,
                                                    function=VW)

                # it is assumed the EUT is on
                eut = der.der_init(ts)
                if eut is not None:
                    vw_curve_params = {
                        'v': [
                            round(v_pairs['V1'] * (v_nom), 2),
                            round(v_pairs['V2'] * (v_nom), 2)
                        ],
                        'w': [
                            round(v_pairs['P1'] * (p_rated), 2),
                            round(v_pairs['P2'] * (p_rated), 2)
                        ],
                        'DeptRef':
                        'W_MAX_PCT'
                    }
                    vw_params = {
                        'Ena': True,
                        'ActCrv': 1,
                        'curve': vw_curve_params
                    }
                    '''
                    f) Verify volt-watt mode is reported as active and that the correct characteristic is reported
                    '''
                    eut.volt_watt(params=vw_params)
                    ts.log_debug('Initial EUT VW settings are %s' %
                                 eut.volt_watt())
                    ts.log_debug('curve points:  %s' % v_pairs)
                '''
                g) Once steady state is reached, begin the adjustment of phase voltages.
                '''
                """
                Test start
                """
                ActiveFunction.set_step_label('G')
                daq.sc['event'] = ActiveFunction.get_step_label()
                daq.data_sample()
                ts.log('Wait for steady state to be reached')
                ts.sleep(2 * vw_response_time[vw_curve])
                ts.log('Starting imbalance test with VW mode at %s (%s)' %
                       (imbalance_response, imbalance_fix))

                dataset_filename = 'VW_IMB_%s_%s' % (imbalance_response,
                                                     imbalance_fix)
                ts.log('------------{}------------'.format(dataset_filename))
                # Start the data acquisition systems
                daq.data_capture(True)
                '''
                Step h) For multiphase units, step the AC test source voltage to Case A from Table 24
                '''

                if grid is not None:
                    step_label = ActiveFunction.get_step_label()
                    ts.log(
                        'Voltage step: setting Grid simulator to case A (IEEE 1547.1-Table 24)(%s)'
                        % step_label)
                    ActiveFunction.start(daq=daq, step_label=step_label)
                    v_target = ActiveFunction.set_grid_asymmetric(
                        grid=grid, case='case_a')
                    step_dict = {'V': v_target}
                    ActiveFunction.record_timeresponse(daq=daq)
                    ActiveFunction.evaluate_criterias(daq=daq,
                                                      step_dict=step_dict)
                    result_summary.write(ActiveFunction.write_rslt_sum())
                '''
                Step i) For multiphase units, step the AC test source voltage to VN.
                '''
                if grid is not None:
                    step_label = ActiveFunction.get_step_label()
                    ts.log(
                        'Voltage step: setting Grid simulator voltage to %s (%s)'
                        % (v_nom, step_label))
                    ActiveFunction.start(daq=daq, step_label=step_label)
                    v_target = v_nom
                    grid.voltage(v_target)
                    step_dict = {'V': v_target}
                    ActiveFunction.record_timeresponse(daq=daq)
                    ActiveFunction.evaluate_criterias(daq=daq,
                                                      step_dict=step_dict)
                    result_summary.write(ActiveFunction.write_rslt_sum())
                '''
                Step j) For multiphase units, step the AC test source voltage to Case B from Table 24
                '''
                if grid is not None:
                    step_label = ActiveFunction.get_step_label()
                    ts.log(
                        'Voltage step: setting Grid simulator to case B (IEEE 1547.1-Table 24)(%s)'
                        % step_label)
                    ActiveFunction.start(daq=daq, step_label=step_label)
                    v_target = ActiveFunction.set_grid_asymmetric(
                        grid=grid, case='case_b')
                    step_dict = {'V': v_target}
                    ActiveFunction.record_timeresponse(daq=daq)
                    ActiveFunction.evaluate_criterias(daq=daq,
                                                      step_dict=step_dict)
                    result_summary.write(ActiveFunction.write_rslt_sum())
                '''
                Step k) For multiphase units, step the AC test source voltage to VN.
                '''
                if grid is not None:
                    step_label = ActiveFunction.get_step_label()
                    ts.log(
                        'Voltage step: setting Grid simulator voltage to %s (%s)'
                        % (v_nom, step_label))
                    ActiveFunction.start(daq=daq, step_label=step_label)
                    v_target = v_nom
                    grid.voltage(v_target)
                    step_dict = {'V': v_target}
                    ActiveFunction.record_timeresponse(daq=daq)
                    ActiveFunction.evaluate_criterias(daq=daq,
                                                      step_dict=step_dict)
                    result_summary.write(ActiveFunction.write_rslt_sum())

                # Get the rslt parameters for plot
                result_params = ActiveFunction.get_rslt_param_plot()
                ts.log('Sampling complete')
                dataset_filename = dataset_filename + ".csv"
                daq.data_capture(False)
                ds = daq.data_capture_dataset()
                ts.log('Saving file: %s' % dataset_filename)
                ds.to_csv(ts.result_file_path(dataset_filename))
                result_params['plot.title'] = dataset_filename.split('.csv')[0]
                ts.result_file(dataset_filename, params=result_params)
                result = script.RESULT_COMPLETE

    except script.ScriptFail as e:
        reason = str(e)
        if reason:
            ts.log_error(reason)

    finally:
        if daq is not None:
            daq.close()
        if pv is not None:
            if p_rated is not None:
                pv.power_set(p_rated)
            pv.close()
        if grid is not None:
            if v_nom is not None:
                grid.voltage(v_nom)
            grid.close()
        if chil is not None:
            chil.close()
        if eut is not None:
            eut.volt_var(params={'Ena': False})
            eut.volt_watt(params={'Ena': False})
            eut.close()
        if result_summary is not None:
            result_summary.close()

    return result
예제 #10
0
def volt_watt_mode_imbalanced_grid(imbalance_resp, vw_curves,
                                   vw_response_time):

    result = script.RESULT_FAIL
    daq = None
    p_rated = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None

    try:
        cat = ts.param_value('eut.cat')
        cat2 = ts.param_value('eut.cat2')
        p_rated = ts.param_value('eut.p_rated')
        s_rated = ts.param_value('eut.s_rated')

        # DC voltages
        v_in_nom = ts.param_value('eut.v_in_nom')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_min = ts.param_value('eut.v_low')
        v_max = ts.param_value('eut.v_high')
        p_min = ts.param_value('eut.p_min')
        phases = ts.param_value('eut.phases')
        imbalance_fix = ts.param_value('vw.imbalance_fix')

        # EUI Absorb capabilities
        absorb = {}
        absorb['ena'] = ts.param_value('eut_vw.sink_power')
        absorb['p_rated_prime'] = ts.param_value('eut_vw.p_rated_prime')
        absorb['p_min_prime'] = ts.param_value('eut_vw.p_min_prime')
        '''
        A separate module has been create for the 1547.1 Standard
        '''
        lib_1547 = p1547.module_1547(ts=ts,
                                     aif='VW',
                                     imbalance_angle_fix=imbalance_fix)
        ts.log_debug('1547.1 Library configured for %s' %
                     lib_1547.get_test_name())

        # Get the rslt parameters for plot
        result_params = lib_1547.get_rslt_param_plot()
        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''
        # 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)  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)

        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized

        # DAS soft channels
        # TODO : add to library 1547
        das_points = {
            'sc': ('P_TARGET', 'P_TARGET_MIN', 'P_TARGET_MAX', 'P_MEAS',
                   'V_TARGET', 'V_MEAS', 'event')
        }

        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'])
        if daq is not None:
            daq.sc['P_TARGET'] = 100
            daq.sc['P_TARGET_MIN'] = 100
            daq.sc['P_TARGET_MAX'] = 100
            daq.sc['V_TARGET'] = v_nom
            daq.sc['event'] = 'None'

            ts.log('DAS device: %s' % daq.info())
        '''
        b) Set all voltage trip parameters to the widest range of adjustability. Disable all reactive/active power
        control functions.
        '''
        eut = der.der_init(ts)
        if eut is not None:
            eut.config()
            ts.log_debug(
                'L/HVRT and trip parameters set to the widest range : v_min: {0} V, v_max: {1} V'
                .format(v_min, v_max))
            try:
                eut.vrt_stay_connected_high(
                    params={
                        'Ena': True,
                        'ActCrv': 0,
                        'Tms1': 3000,
                        'V1': v_max,
                        'Tms2': 0.16,
                        'V2': v_max
                    })
            except Exception, e:
                ts.log_error(
                    'Could not set VRT Stay Connected High curve. %s' % e)
            try:
                eut.vrt_stay_connected_low(
                    params={
                        'Ena': True,
                        'ActCrv': 0,
                        'Tms1': 3000,
                        'V1': v_min,
                        'Tms2': 0.16,
                        'V2': v_min
                    })
            except Exception, e:
                ts.log_error('Could not set VRT Stay Connected Low curve. %s' %
                             e)
예제 #11
0
def test_run():
    result = script.RESULT_FAIL
    grid = None
    pv = p_rated = None
    daq = None
    eut = None
    rs = None
    phil = None
    result_summary = None
    step = None
    q_initial = None
    dataset_filename = None

    try:
        sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        p_rated_prime = ts.param_value('eut.p_rated_prime')
        s_rated = ts.param_value('eut.s_rated')
        var_rated = ts.param_value('eut.var_rated')

        # DC voltages
        v_nom_in_enabled = ts.param_value('cpf.v_in_nom')
        v_min_in_enabled = ts.param_value('cpf.v_in_min')
        v_max_in_enabled = ts.param_value('cpf.v_in_max')

        v_nom_in = ts.param_value('eut.v_in_nom')
        v_min_in = ts.param_value('eut_cpf.v_in_min')
        v_max_in = ts.param_value('eut_cpf.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_min = ts.param_value('eut.v_low')
        v_max = ts.param_value('eut.v_high')
        f_nom = ts.param_value('eut.f_nom')
        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')

        # Pass/fail accuracies
        pf_msa = ts.param_value('eut.pf_msa')

        # EUI Absorb capabilities
        absorb = {}
        absorb['ena'] = ts.param_value('eut_cpf.sink_power')
        absorb['p_rated_prime'] = ts.param_value('eut_cpf.p_rated_prime')
        absorb['p_min_prime'] = ts.param_value('eut_cpf.p_min_prime')

        # initialize HIL environment, if necessary
        ts.log_debug(15 * "*" + "HIL initialization" + 15 * "*")

        phil = hil.hil_init(ts)
        if phil is not None:
            # return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name)
            open_proj = phil._param_value('hil_config_open')
            compilation = phil._param_value('hil_config_compile')
            stop_sim = phil._param_value('hil_config_stop_sim')
            load = phil._param_value('hil_config_load')
            execute = phil._param_value('hil_config_execute')
            model_name = phil._param_value('hil_config_model_name')
            phil.config()
        ''' RTLab OpWriteFile Math using worst case scenario of 160 seconds, 14 signals and Ts = 40e-6
        Duration of acquisition in number of points: Npoints = (Tend-Tstart)/(Ts*dec) = (350)/(0.000040*25) = 1350e3
        
        Acquisition frame duration: Tframe = Nbss * Ts * dec = 1000*0.000040*250 = 10 sec
        
        Number of buffers to be acquired: Nbuffers = Npoints / Nbss = (Tend - Tstart) / Tframe = 16
        
        Minimum file size: MinSize= Nbuffers x SizeBuf = [(Tend - Tstart) / Ts ] * (Nsig+1) * 8 * Nbss 
            = (160/40e-6)*(14+1)*8*1000 = 4.8e11
        
        SizeBuf = 1/Nbuffers * {[(Tend - Tstart) / Ts ]*(Nsig+1)*8*Nbss} = [(160/0.000040)*(14+1)*8*1e3]/16 = 30e9
        Size of one buffer in bytes (SizeBuf) = (Nsig+1) * 8 * Nbss (Minimum) = (14+1)*8*1000 = 120e3
        '''
        """
        Configure settings in 1547.1 Standard module for the Frequency Ride Through Tests
        """
        pwr = float(ts.param_value('frt.high_pwr_value'))
        repetitions = ts.param_value('frt.repetitions')
        if ts.param_value('frt.wav_ena') == "Yes":
            wav_ena = True
        else:
            wav_ena = False
        if ts.param_value('frt.data_ena') == "Yes":
            data_ena = True
        else:
            data_ena = False

        FreqRideThrough = p1547.FrequencyRideThrough(
            ts=ts, support_interfaces={"hil": phil})
        # result params
        # result_params = lib_1547.get_rslt_param_plot()
        # ts.log(result_params

        # grid simulator is initialized with test parameters and enabled
        ts.log_debug(15 * "*" + "Gridsim initialization" + 15 * "*")
        grid = gridsim.gridsim_init(ts, support_interfaces={
            "hil": phil
        })  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)
        # Set the grid simulator rocof to 3Hz/s
        grid.rocof(FreqRideThrough.get_rocof_dic())
        # pv simulator is initialized with test parameters and enabled
        ts.log_debug(15 * "*" + "PVsim initialization" + 15 * "*")
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized

        # initialize data acquisition
        ts.log_debug(15 * "*" + "DAS initialization" + 15 * "*")
        daq = das.das_init(ts, support_interfaces={"hil": phil, "pvsim": pv})
        daq.waveform_config({
            "mat_file_name":
            "WAV.mat",
            "wfm_channels":
            FreqRideThrough.get_wfm_file_header()
        })

        if daq is not None:
            daq.sc['F_MEAS'] = 100

        # 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)
        result_summary.write('Test Name, Waveform File, RMS File\n')
        """
        Set the frequency droop function and droop values to make the active power change with respect to
        frequency as small as possible.
        """
        # Wait to establish communications with the EUT after AC and DC power are provided
        eut = der.der_init(ts, support_interfaces={"hil": phil})
        if eut is not None:
            eut.config()

        # Default curve is characteristic curve 1
        fw_curve = 1
        ActiveFunction = p1547.ActiveFunction(ts=ts,
                                              script_name='Freq-Watt',
                                              functions=[FW],
                                              criteria_mode=[True, True, True])
        fw_param = ActiveFunction.get_params(function=FW, curve=fw_curve)
        ts.log_debug('fw_param:%s' % fw_param)

        if eut is not None:
            params = {
                'Ena': True,
                'curve': fw_curve,
                'dbf': fw_param['dbf'],
                'kof': fw_param['kof'],
                'RspTms': fw_param['tr']
            }
            settings = eut.freq_watt(params)
            ts.log_debug('Initial EUT FW settings are %s' % settings)
        """
        Set or verify that all frequency trip settings are set to not influence the outcome of the test.
        """
        # ts.log_debug('HFRT and trip parameters from EUT : {}'.format(eut.frt_stay_connected_high()))
        # ts.log_debug('LFRT and trip parameters from EUT : {}'.format(eut.frt_stay_connected_low()))
        """
        Operate the ac test source at nominal frequency ± 0.1 Hz.
        """
        # Configured in PHIL on startup

        # Initial loop for all mode that will be executed
        modes = FreqRideThrough.get_modes()  # Options: LFRT, HFRT
        ts.log(f"FRT modes tested : '{modes}'")
        for current_mode in modes:
            for repetition in range(1, repetitions + 1):
                dataset_filename = f'{current_mode}_{round(pwr*100)}PCT_{repetition}'
                ts.log_debug(15 * "*" + f"Starting {dataset_filename}" +
                             15 * "*")
                if data_ena:
                    daq.data_capture(True)
                """
                Setting up available power to appropriate power level 
                """
                if pv is not None:
                    ts.log_debug(f'Setting power level to {pwr}')
                    pv.iv_curve_config(pmp=p_rated, vmp=v_nom_in)
                    pv.irradiance_set(1000.)
                    pv.power_set(p_rated * pwr)
                """
                Initiating voltage sequence for FRT
                """
                frt_test_sequences = FreqRideThrough.set_test_conditions(
                    current_mode)
                ts.log_debug(frt_test_sequences)
                frt_stop_time = FreqRideThrough.get_frt_stop_time(
                    frt_test_sequences)
                if phil is not None:
                    # This adds 5 seconds of nominal behavior for EUT normal shutdown. This 5 sec is not recorded.
                    frt_stop_time = frt_stop_time + 5
                    ts.log('Stop time set to %s' %
                           phil.set_stop_time(frt_stop_time))

                    # The driver should take care of this by selecting "Yes" to "Load the model to target?"
                    phil.load_model_on_hil()
                    # You need to first load the model, then configure the parameters
                    # Now that we have all the test_sequences its time to sent them to the model.
                    FreqRideThrough.set_frt_model_parameters(
                        frt_test_sequences)

                    # The driver parameter "Execute the model on target?" should be set to "No"
                    phil.start_simulation()
                    ts.sleep(0.5)
                    sim_time = phil.get_time()
                    while (frt_stop_time - sim_time
                           ) > 1.0:  # final sleep will get to stop_time.
                        sim_time = phil.get_time()
                        ts.log(
                            'Sim Time: %0.3f.  Waiting another %0.3f sec before saving data.'
                            % (sim_time, frt_stop_time - sim_time))
                        ts.sleep(5)

                    rms_dataset_filename = "No File"
                    wave_start_filename = "No File"
                    if data_ena:
                        rms_dataset_filename = dataset_filename + "_RMS.csv"
                        daq.data_capture(False)

                        # complete data capture
                        ts.log(
                            'Waiting for Opal to save the waveform data: {}'.
                            format(dataset_filename))
                        ts.sleep(10)
                    if wav_ena:
                        # Convert and save the .mat file
                        ts.log('Processing waveform dataset(s)')
                        wave_start_filename = dataset_filename + "_WAV.csv"

                        ds = daq.waveform_capture_dataset(
                        )  # returns list of databases of waveforms (overloaded)
                        ts.log(f'Number of waveforms to save {len(ds)}')
                        if len(ds) > 0:
                            ds[0].to_csv(
                                ts.result_file_path(wave_start_filename))
                            ts.result_file(wave_start_filename)

                    if data_ena:
                        ds = daq.data_capture_dataset()
                        ts.log('Saving file: %s' % rms_dataset_filename)
                        ds.to_csv(ts.result_file_path(rms_dataset_filename))
                        ds.remove_none_row(
                            ts.result_file_path(rms_dataset_filename), "TIME")
                        result_params = {
                            'plot.title':
                            rms_dataset_filename.split('.csv')[0],
                            'plot.x.title': 'Time (sec)',
                            'plot.x.points': 'TIME',
                            'plot.y.points': 'AC_VRMS_1, AC_VRMS_2, AC_VRMS_3',
                            'plot.y.title': 'Voltage (V)',
                            'plot.y2.points':
                            'AC_IRMS_1, AC_IRMS_2, AC_IRMS_3',
                            'plot.y2.title': 'Current (A)',
                        }
                        ts.result_file(rms_dataset_filename,
                                       params=result_params)
                    result_summary.write(
                        '%s, %s, %s,\n' %
                        (dataset_filename, wave_start_filename,
                         rms_dataset_filename))

                    phil.stop_simulation()

        result = script.RESULT_COMPLETE

    except script.ScriptFail as e:
        reason = str(e)
        if reason:
            ts.log_error(reason)

    except Exception as e:
        ts.log_error((e, traceback.format_exc()))

        ts.log_error('Test script exception: %s' % traceback.format_exc())

    finally:
        if grid is not None:
            grid.close()
        if pv is not None:
            if p_rated is not None:
                pv.power_set(p_rated)
            pv.close()
        if daq is not None:
            daq.close()
        if eut is not None:
            # eut.fixed_pf(params={'Ena': False, 'PF': 1.0})
            eut.close()
        if rs is not None:
            rs.close()
        if phil is not None:
            if phil.model_state() == 'Model Running':
                phil.stop_simulation()
            phil.close()

        if result_summary is not None:
            result_summary.close()

        # create result workbook
        excelfile = ts.config_name() + '.xlsx'
        rslt.result_workbook(excelfile, ts.results_dir(), ts.result_dir())
        ts.result_file(excelfile)

    return result
예제 #12
0
파일: FW.py 프로젝트: jun-frea/svp_1547.1
def test_run():

    result = script.RESULT_FAIL
    daq = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None
    fw_curves = collections.OrderedDict()

    try:
        """
        Configuration
        """
        # EUT FW parameters
        p_rated = ts.param_value('eut_fw.p_rated')
        f_nom = ts.param_value('eut_fw.f_nom')
        f_min = ts.param_value('eut_fw.f_max')
        f_max = ts.param_value('eut_fw.f_min')
        p_small = ts.param_value('eut_fw.p_small')
        p_large = ts.param_value('eut_fw.p_large')
        phases = ts.param_value('eut_fw.phases')
        eut_absorb = ts.param_value('eut_fw.absorb')

        eff = {
            1.0: ts.param_value('eut_fw.efficiency_100') / 100,
            0.66: ts.param_value('eut_fw.efficiency_66') / 100,
            0.2: ts.param_value('eut_fw.efficiency_20') / 100,
        }
        # Test Parameters
        mode = ts.param_value('fw.mode')
        curves = ts.param_value('fw.curves')
        irr = ts.param_value('fw.irr')
        """
        Equipment Configuration
        """
        # initialize hardware-in-the-loop environment (if applicable)
        ts.log('Configuring HIL system...')
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()

        # DAS soft channels
        das_points = {
            'sc': ('P_TARGET', 'P_TARGET_MIN', 'P_TARGET_MAX', 'P_ACT',
                   'F_TARGET', 'F_ACT', 'event')
        }

        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'])
        daq.sc['P_TARGET'] = 100
        daq.sc['P_TARGET_MIN'] = 100
        daq.sc['P_TARGET_MAX'] = 100
        daq.sc['F_TARGET'] = f_nom
        daq.sc['event'] = 'None'
        """
        EUT Configuration
        """
        # Configure the EUT communications
        eut = der.der_init(ts)
        # 1547.1: b) Set all frequency trip parameters to the widest range of adjustability.
        if eut is not None:
            eut.config()
            ts.log_debug(eut.measurements())
            ts.log_debug(
                'L/HFRT and trip parameters set to the widest range : f_min:{0} Hz, f_max:{1} Hz'
                .format(f_min, f_max))
            eut_response = eut.frt_stay_connected_high(
                params={
                    'Ena': True,
                    'ActCrv': 0,
                    'Tms1': 3000,
                    'Hz1': f_max,
                    'Tms2': 160,
                    'Hz2': f_max
                })
            ts.log_debug(
                'HFRT and trip parameters from EUT : {}'.format(eut_response))
            eut_response = eut.frt_stay_connected_low(
                params={
                    'Ena': True,
                    'ActCrv': 0,
                    'Tms1': 3000,
                    'Hz1': f_min,
                    'Tms2': 160,
                    'Hz2': f_min
                })
            ts.log_debug(
                'LFRT and trip parameters from EUT : {}'.format(eut_response))

        else:
            ts.log_debug(
                'Set L/HFRT and trip parameters to the widest range of adjustability possible.'
            )

        # 1547.1: c)    Set all AC test source source parameters to the nominal operating voltage and frequency
        grid = gridsim.gridsim_init(ts)

        # 1547.1: d)    Adjust the EUT's active power to P_rated
        pv = pvsim.pvsim_init(ts)
        pv.power_set(p_rated)
        pv.power_on()
        """
        Test Configuration
        """
        if mode == 'Both':
            modes = ['Above', 'Below']
        elif mode == 'Above':
            modes = ['Above']
        elif mode == 'Below':
            modes = ['Below']

        # 1547.2018 : Using Category III as specified in Table B.1
        if curves == 'Characteristic Curve 1' or curves == 'Both':
            fw_curves[1] = {
                'dbf': 0.036,
                'kf': 0.05,
                'tr': ts.param_value('fw.tr_1'),
                'f_small': p_small * f_nom * 0.05
            }
        if curves == 'Characteristic Curve 2' or curves == 'Both':
            fw_curves[2] = {
                'dbf': 0.017,
                'kf': 0.02,
                'tr': ts.param_value('fw.tr_2'),
                'f_small': p_small * f_nom * 0.02
            }

        if irr == 'All':
            pv_powers = [1., 0.66, 0.2]
        elif irr == '100%':
            pv_powers = [1.]
        elif irr == '66%':
            pv_powers = [0.66]
        elif irr == '20%':
            pv_powers = [0.2]
        ts.log_debug("Power level tested : {}".format(pv_powers))

        if eut_absorb == "Yes":
            absorb_powers = [False, True]
        else:
            absorb_powers = [False]

        # 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)
        result_summary.write('Result,'
                             'Test Name,'
                             'Power Level,'
                             'Mode,'
                             'Freq_target,'
                             'Freq_actual,'
                             'Power_target,'
                             'Power_actual,'
                             'P_min,'
                             'P_max,'
                             'Dataset File\n')
        """
        Test start
        """
        for mode in modes:
            if mode == 'Below':
                # 1547.1 :  [5.15.3.2 Procedure] Remove the 66% and 20% power level since not required in 'Below' mode
                #           Set the unit to absorb power at –50% of P rated
                pv_powers = [1.]
                # 1547.1 :  [5.15.3.2 Procedure] Frequency is ramped at the ROCOF for the category of the EUT.
                #           In this case the ROCOF is based on table 21 of 1547.2018
                #           (Category III is use because of table B.1 of 1547.2018)
                #           The ROCOF unit : Hz/s
                ts.log('Set Grid simulator power to 3 Hz/s')
                grid.rocof(3.0)

            for absorb_power in absorb_powers:
                for fw_curve, fw_params in fw_curves.iteritems():
                    for power in pv_powers:
                        pv_power_setting = (p_rated * power) / eff[power]
                        ts.log(
                            'Set PV simulator power to {} with efficiency at {} %'
                            .format(p_rated * power, eff[power] * 100.))
                        pv.power_set(pv_power_setting)

                        result = normal_curve_test(
                            mode=mode,
                            fw_curve=fw_curve,
                            fw_params=fw_params,
                            power=power,
                            daq=daq,
                            eut=eut,
                            grid=grid,
                            result_summary=result_summary,
                            absorb_power=absorb_power)

        result = script.RESULT_COMPLETE
    except script.ScriptFail, e:
        reason = str(e)
        if reason:
            ts.log_error(reason)
예제 #13
0
            pv.iv_curve_config(pmp=p_rated, vmp=v_in_nom)
            pv.irradiance_set(1000.)

        for imbalance_response in imbalance_resp:
            for vw_curve in vw_curves:
                '''
                e) Set EUT volt-watt parameters to the values specified by Characteristic 1. All other function be
                turned off.
                '''
                if eut is not None:
                    eut.volt_var(params={'Ena': False})
                    eut.fixed_pf(params={'Ena': False})
                v_pairs = lib_1547.get_params(curve=vw_curve)

                # Assume the EUT is on
                eut = der.der_init(ts)
                if eut is not None:
                    vw_curve_params = {
                        'v': [
                            int(v_pairs['V1'] * (100. / v_nom)),
                            int(v_pairs['V2'] * (100. / v_nom))
                        ],
                        'w': [
                            int(v_pairs['P1'] * (100. / p_rated)),
                            int(v_pairs['P2'] * (100. / p_rated))
                        ],
                        'DeptRef':
                        'W_MAX_PCT'
                    }
                    vw_params = {
                        'Ena': True,
예제 #14
0
def vw_mode(vw_curves, mode=None):

    result = script.RESULT_FAIL
    daq = None
    v_nom = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None
    dataset_filename = None

    try:
        # Rated powers
        p_rated = ts.param_value('eut.p_rated')
        var_rated = ts.param_value('eut.var_rated')
        s_rated = ts.param_value('eut.s_rated')

        # DC power
        if ts.param_value(
                'pvsim.terrasas.pmp'
        ) is not None:  # TODO - REPLACE WITH CORRECT REFERENCE
            p_pvsim = ts.param_value('pvsim.terrasas.pmp')
        else:
            p_pvsim = p_rated

        # DC voltages
        v_in_nom = ts.param_value('eut.v_in_nom')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_low = ts.param_value('eut.v_low')
        v_high = ts.param_value('eut.v_high')
        phases = ts.param_value('eut.phases')

        vw_response_time = 0
        vw_timing = [
            ts.param_value('vw.commencement_time'),
            ts.param_value('vw.completion_time'),
            ts.param_value('vw.step_time_period')
        ]
        """
        A separate module has been create for the DR_AS_NZS_4777.2 Standard
        """
        pAus4777.VersionValidation(script_version=ts.info.version)

        if mode == 'Volt-Var':
            #VoltVar = pAus4777.VoltVar(ts=ts)
            Active_function = pAus4777.ActiveFunction(ts=ts,
                                                      functions=[VW, VV])
        else:
            Active_function = pAus4777.ActiveFunction(ts=ts, functions=[VW])
        #ts.log_debug(f"AUS4777,2 Library configured for {Active_function.script_complete_name}")
        #ts.log_debug(f"AUS4777,2 Library configured for {Active_function.VoltWatt.get_params()}")

        # result params
        x_axis_specs = {'min': v_low * 0.9}
        #result_params = VoltWatt.get_rslt_param_plot(x_axis_specs=x_axis_specs)
        result_params = Active_function.get_rslt_param_plot(
            x_axis_specs=x_axis_specs)

        ts.log_debug(result_params)
        '''
        Connect the EUT according to the instructions and specifications provided by the manufacturer 
        and initialisation of the chil, pvsim, das, eut/der and the gridsim
        '''

        # initialize HIL environment, if necessary
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()

        # initialize the pvsim
        pv = pvsim.pvsim_init(ts)

        # DAS soft channels
        das_points = Active_function.get_sc_points()
        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'])

        daq.sc['V_TARGET'] = v_nom
        daq.sc['TR_SS_TARGET'] = 10
        daq.sc['Q_TARGET'] = 100
        daq.sc['Q_TARGET_MIN'] = 100
        daq.sc['Q_TARGET_MAX'] = 100
        daq.sc['P_TARGET'] = 100
        daq.sc['P_TARGET_MIN'] = 100
        daq.sc['P_TARGET_MAX'] = 100
        daq.sc['event'] = 'None'

        ts.log(f'DAS device: {daq.info()}')

        # Setting the pvsim to the rated power of the eut
        if pv is not None:
            pv.iv_curve_config(pmp=p_pvsim, vmp=v_in_nom)
            #pv.iv_curve_config(pmp=p_rated, vmp=v_in_nom)
            #pv.irradiance_set(0.)
            #ts.log("PV simulator irradiance set to 0, sleeping for 15 seconds to allow EUT to shut down")
            #ts.sleep(15)
            pv.irradiance_set(1000.)
            pv.power_on()  # Turn on DC so the EUT can be initialized
            pvsim_sleeptime = 60
            ts.log(
                f"PV simulator enabled, sleeping for {pvsim_sleeptime} seconds to allow EUT to stabilise"
            )
            ts.sleep(pvsim_sleeptime)

        # initialize the eut
        eut = der.der_init(ts)
        if eut is not None:
            eut.config()
            # ts.log_debug(eut.measurements())

            #Deactivating all functions on EUT
            #eut.deactivate_all_fct()

        # initialize the GridSim
        grid = gridsim.gridsim_init(ts, support_interfaces={
            'hil': chil
        })  # Turn on AC so the EUT can be initialized
        gridsim_sleeptime = 120
        ts.log(
            f"Grid simulator enabled, sleeping for {gridsim_sleeptime} seconds to allow EUT to connect"
        )
        ts.sleep(gridsim_sleeptime)

        # 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)
        ts.log(f'col_name={Active_function.get_rslt_sum_col_name()}')
        result_summary.write(Active_function.get_rslt_sum_col_name())
        '''
        Repeat the test for each regions curves (Australia A, Australia B, Australia C, New Zealand and Allowed range)
        '''
        ts.log(f'curves={vw_curves}')
        for vw_curve in vw_curves:
            #ts.log(f'curves={vw_curve}')
            ts.log(f'Starting test with characteristic curve {vw_curve}')
            Active_function.reset_curve(vw_curve)
            Active_function.reset_time_settings(tr=vw_timing, number_tr=3)

            if mode == 'Volt-Var':
                vv_pairs = Active_function.get_params(function=VV,
                                                      region=vw_curve)
                ts.log_debug(f'volt-var_pairs:{vv_pairs}')

            vw_pairs = Active_function.get_params(function=VW, region=vw_curve)
            ts.log_debug(f'volt-watt_pairs:{vw_pairs}')
            '''
            (a) Enable the volt-watt and volt-var response modes.
            '''

            if eut is not None:
                # Activate volt-var function with following parameters
                # SunSpec convention is to use percentages for V and Q points.
                if mode == 'Volt-Var':
                    vv_curve_params = {
                        'v': [(vv_pairs['Vv1'] / v_nom) * 100,
                              (vv_pairs['Vv2'] / v_nom) * 100,
                              (vv_pairs['Vv3'] / v_nom) * 100,
                              (vv_pairs['Vv4'] / v_nom) * 100],
                        'var': [(vv_pairs['Q1'] / s_rated) * 100,
                                (vv_pairs['Q2'] / s_rated) * 100,
                                (vv_pairs['Q3'] / s_rated) * 100,
                                (vv_pairs['Q4'] / s_rated) * 100],
                        'vref':
                        round(v_nom, 2),
                        'RmpPtTms':
                        vw_response_time
                    }
                    ts.log_debug(f'Sending Volt-Var points: {vv_curve_params}')
                    eut.volt_var(params={
                        'Ena': True,
                        'ACTCRV': vw_curve,
                        'curve': vv_curve_params
                    })
                    ts.log_debug(
                        f'Initial EUT Volt-Var settings are {eut.volt_var()}')

                # Activate volt-watt function with following parameters
                # SunSpec convention is to use percentages for V and P points.
                vw_curve_params = {
                    'v': [(vw_pairs['Vw1'] / v_nom) * 100,
                          (vw_pairs['Vw2'] / v_nom) * 100],
                    'w': [(vw_pairs['P1'] / s_rated) * 100,
                          (vw_pairs['P2'] / s_rated) * 100]
                }
                ts.log_debug(f'Sending Volt-Watt points: {vw_curve_params}')
                eut.volt_watt(params={
                    'Ena': True,
                    'ACTCRV': vw_curve,
                    'curve': vw_curve_params
                })
                ts.log_debug(
                    f'Initial EUT Volt-Watt settings are {eut.volt_watt()}')
            """
             (b) Set the grid source equal to the grid test voltage. Vary the energy source until the a.c. output
                of the device under test equals 100 ± 5 % of its rated active power output.
            """
            # Setting grid to vnom before test
            if grid is not None:
                grid.voltage(v_nom)
            # Setting the pvsim to the rated power of the eut
            if pv is not None:
                pv.iv_curve_config(pmp=p_pvsim, vmp=v_in_nom)
                #pv.iv_curve_config(pmp=p_rated, vmp=v_in_nom)
                pv.irradiance_set(1000.)
            """
            Going trough step C to step N
            """
            #Construct the v_steps_dict from step c to step n

            if mode == 'Volt-Var':
                v_steps_dict = Active_function.create_vw_dict_steps(
                    mode=mode, secondary_pairs=vv_pairs)
            else:
                v_steps_dict = Active_function.create_vw_dict_steps(mode=mode)
            ts.log_debug(v_steps_dict)

            dataset_filename = f'VW_{vw_curve}'
            if mode == 'Volt-Var':
                dataset_filename += '_combined_VV'
            Active_function.reset_filename(filename=dataset_filename)
            # Start the data acquisition systems
            daq.data_capture(True)

            for step_label, v_step in v_steps_dict.items():
                ts.log(
                    f'Voltage step: setting Grid simulator voltage to {v_step} ({step_label})'
                )
                if 'C' in step_label or 'H' in step_label:
                    if grid is not None:
                        grid.voltage(v_step)
                else:
                    Active_function.start(daq=daq, step_label=step_label)

                    if grid is not None:
                        grid.voltage(v_step)

                    Active_function.record_timeresponse(daq=daq,
                                                        step_value=v_step)
                    Active_function.evaluate_criterias()
                    result_summary.write(Active_function.write_rslt_sum())
            """
            (o) Summarize results in a table from initial value to final voltage value showing voltage,
                apparent power, active power, reactive power and time to reach required reactive power level
                for each voltage step. Plot results on a graph of voltage versus apparent power, active power
                and reactive power.
            """

            ts.log('Sampling complete')
            dataset_filename = dataset_filename + ".csv"
            daq.data_capture(False)
            ds = daq.data_capture_dataset()
            ts.log(f'Saving file: {dataset_filename}')
            ds.to_csv(ts.result_file_path(dataset_filename))
            result_params['plot.title'] = dataset_filename.split('.csv')[0]
            ts.result_file(dataset_filename, params=result_params)
            result = script.RESULT_COMPLETE

    except script.ScriptFail as e:
        reason = str(e)
        if reason:
            ts.log_error(reason)

    except Exception as e:
        if dataset_filename is not None:
            dataset_filename = dataset_filename + ".csv"
            daq.data_capture(False)
            ds = daq.data_capture_dataset()
            ts.log(f'Saving file: {dataset_filename}')
            ds.to_csv(ts.result_file_path(dataset_filename))
            result_params['plot.title'] = dataset_filename.split('.csv')[0]
            ts.result_file(dataset_filename, params=result_params)
        ts.log_error(f'Test script exception: {traceback.format_exc()}')

    finally:
        if daq is not None:
            daq.close()
        if pv is not None:
            pv.close()
        if grid is not None:
            if v_nom is not None:
                grid.voltage(v_nom)
            grid.close()
        if chil is not None:
            chil.close()
        if eut is not None:
            eut.close()
        if result_summary is not None:
            result_summary.close()

    return result
예제 #15
0
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)
예제 #16
0
def watt_var_mode(wv_curves, wv_response_time, pwr_lvls):

    result = script.RESULT_FAIL
    daq = None
    v_nom = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None
    dataset_filename = None

    try:
        cat = ts.param_value('eut.cat')
        cat2 = ts.param_value('eut.cat2')
        sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        p_rated_prime = ts.param_value('eut.p_rated_prime')
        var_rated = ts.param_value('eut.var_rated')
        s_rated = ts.param_value('eut.s_rated')

        # DC voltages
        v_in_nom = ts.param_value('eut.v_in_nom')
        #v_min_in = ts.param_value('eut.v_in_min')
        #v_max_in = ts.param_value('eut.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_low = ts.param_value('eut.v_low')
        v_high = ts.param_value('eut.v_high')
        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')

        # EUI Absorb capabilities
        absorb = {}
        absorb['ena'] = ts.param_value('eut_cpf.sink_power')

        """
        A separate module has been create for the 1547.1 Standard
        """
        #lib_1547 = p1547.module_1547(ts=ts, aif='WV', criteria)
        ActiveFunction = p1547.ActiveFunction(ts=ts,
                                              functions=[WV],
                                              script_name='Watt-Var',
                                              criteria_mode=[True, True, True])
        ts.log_debug("1547.1 Library configured for %s" % ActiveFunction.get_script_name())

        # result params
        result_params = ActiveFunction.get_rslt_param_plot()

        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''

        # initialize HIL environment, if necessary
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()

        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized

        # DAS soft channels
        das_points = ActiveFunction.get_sc_points()

        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'])

        ts.log_debug(0.05 * ts.param_value('eut.s_rated'))
        daq.sc['P_TARGET'] = v_nom
        daq.sc['Q_TARGET'] = 100
        daq.sc['Q_TARGET_MIN'] = 100
        daq.sc['Q_TARGET_MAX'] = 100
        daq.sc['event'] = 'None'

        ts.log('DAS device: %s' % daq.info())

        '''
        b) Set all voltage trip parameters to the widest range of adjustability.  Disable all reactive/active power
        control functions.
        '''

        eut = der.der_init(ts)
        if eut is not None:
            eut.config()
            ts.log_debug(eut.measurements())

            #Disable all functions on EUT
            eut.deactivate_all_fct()

            ts.log_debug('Voltage trip parameters set to the widest range: v_min: {0} V, '
                         'v_max: {1} V'.format(v_low, v_high))
            try:
                eut.vrt_stay_connected_high(params={'Ena': True, 'ActCrv': 0, 'Tms1': 3000,
                                                    'V1': v_high, 'Tms2': 0.16, 'V2': v_high})
            except Exception as e:
                ts.log_error('Could not set VRT Stay Connected High curve. %s' % e)
            try:
                eut.vrt_stay_connected_low(params={'Ena': True, 'ActCrv': 0, 'Tms1': 3000,
                                                   'V1': v_low, 'Tms2': 0.16, 'V2': v_low})
            except Exception as e:
                ts.log_error('Could not set VRT Stay Connected Low curve. %s' % e)
        else:
            ts.log_debug('Set L/HVRT and trip parameters set to the widest range of adjustability possible.')

        # Special considerations for CHIL ASGC/Typhoon startup
        if chil is not None:
            inv_power = eut.measurements().get('W')
            timeout = 120.
            if inv_power <= p_rated * 0.85:
                pv.irradiance_set(995)  # Perturb the pv slightly to start the inverter
                ts.sleep(3)
                eut.connect(params={'Conn': True})
            while inv_power <= p_rated * 0.85 and timeout >= 0:
                ts.log('Inverter power is at %0.1f. Waiting up to %s more seconds or until EUT starts...' %
                       (inv_power, timeout))
                ts.sleep(1)
                timeout -= 1
                inv_power = eut.measurements().get('W')
                if timeout == 0:
                    result = script.RESULT_FAIL
                    raise der.DERError('Inverter did not start.')
            ts.log('Waiting for EUT to ramp up')
            ts.sleep(8)
            ts.log_debug('DAS data_read(): %s' % daq.data_read())

        '''
        c) Set all AC test source parameters to the nominal operating voltage and frequency.
        '''
        grid = gridsim.gridsim_init(ts, support_interfaces={'hil': chil})  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)

        # 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)
        result_summary.write(ActiveFunction.get_rslt_sum_col_name())

        '''
        d) Adjust the EUT's available active power to Prated. For an EUT with an input voltage range, set the input
        voltage to Vin_nom. The EUT may limit active power throughout the test to meet reactive power requirements.
        For an EUT with an input voltage range.
        '''

        if pv is not None:
            pv.iv_curve_config(pmp=p_rated, vmp=v_in_nom)
            pv.irradiance_set(1000.)

        '''
        dd) Repeat steps e) through dd) for characteristics 2 and 3.
        '''

        #TODO 1.Add absorb option possibility for EUT
        #TODO 2.Add communication with EUT

        for wv_curve in wv_curves:
            ts.log('Starting test with characteristic curve %s' % (wv_curve))
            ActiveFunction.reset_curve(wv_curve)
            ActiveFunction.reset_time_settings(tr=wv_response_time[wv_curve], number_tr=2)
            p_pairs = ActiveFunction.get_params(function=WV, curve=wv_curve)
            '''
            d2) Set EUT volt-var parameters to the values specified by Characteristic 1.
            All other function should be turned off. Turn off the autonomously adjusting reference voltage.
            '''
            if eut is not None:
                # Activate watt-var function with following parameters
                # SunSpec convention is to use percentages for P and Q points.
                wv_curve_params = {'w': [p_pairs['P0']*(100/p_rated),
                                         p_pairs['P1']*(100/p_rated),
                                         p_pairs['P2']*(100/p_rated),
                                         p_pairs['P3']*(100/p_rated)],
                                   'var': [p_pairs['Q0']*(100/var_rated),
                                           p_pairs['Q1']*(100/var_rated),
                                           p_pairs['Q2']*(100/var_rated),
                                           p_pairs['Q3']*(100/var_rated)]}
                ts.log_debug('Sending WV points: %s' % wv_curve_params)
                eut.watt_var(params={'Ena': True, 'curve': wv_curve_params})


                '''
                e) Verify volt-var mode is reported as active and that the correct characteristic is reported.
                '''
                ts.log_debug('Initial EUT VV settings are %s' % eut.watt_var())

            '''
            cc) Repeat test steps d) through cc) at EUT power set at 20% and 66% of rated power.
            '''
            for power in pwr_lvls:
                ActiveFunction.reset_pwr(pwr=power)
                if pv is not None:
                    pv_power_setting = (p_rated * power)
                    pv.iv_curve_config(pmp=pv_power_setting, vmp=v_in_nom)
                    pv.irradiance_set(1000.)

                # Special considerations for CHIL ASGC/Typhoon startup #
                if chil is not None:
                    inv_power = eut.measurements().get('W')
                    timeout = 120.
                    if inv_power <= pv_power_setting * 0.85:
                        pv.irradiance_set(995)  # Perturb the pv slightly to start the inverter
                        ts.sleep(3)
                        eut.connect(params={'Conn': True})
                    while inv_power <= pv_power_setting * 0.85 and timeout >= 0:
                        ts.log('Inverter power is at %0.1f. Waiting up to %s more seconds or until EUT starts...' %
                               (inv_power, timeout))
                        ts.sleep(1)
                        timeout -= 1
                        inv_power = eut.measurements().get('W')
                        if timeout == 0:
                            result = script.RESULT_FAIL
                            raise der.DERError('Inverter did not start.')
                    ts.log('Waiting for EUT to ramp up')
                    ts.sleep(8)

                #Create Watt-Var Dictionary
                p_steps_dict = ActiveFunction.create_wv_dict_steps()

                filename = 'WV_%s_PWR_%d' % (wv_curve, power * 100)
                ActiveFunction.reset_filename(filename=filename)
                ts.log('------------{}------------'.format(dataset_filename))

                # Start the data acquisition systems
                daq.data_capture(True)

                for step_label, p_step in p_steps_dict.items():
                    ts.log('Power step: setting Grid power to %s (W)(%s)' % (p_step, step_label))
                    ActiveFunction.start(daq=daq, step_label=step_label)
                    step_dict = {'V': v_nom, 'P': p_step}
                    if pv is not None:
                        pv.power_set(step_dict['P'])

                    ActiveFunction.record_timeresponse(daq=daq)
                    ActiveFunction.evaluate_criterias(daq=daq, step_dict=step_dict)
                    result_summary.write(ActiveFunction.write_rslt_sum())

                ts.log('Sampling complete')
                dataset_filename = filename + ".csv"
                daq.data_capture(False)
                ds = daq.data_capture_dataset()
                ts.log('Saving file: %s' % dataset_filename)
                ds.to_csv(ts.result_file_path(dataset_filename))
                result_params['plot.title'] = dataset_filename.split('.csv')[0]
                ts.result_file(dataset_filename, params=result_params)
                result = script.RESULT_COMPLETE

    except script.ScriptFail as e:
        reason = str(e)
        if reason:
            ts.log_error(reason)

    except Exception as e:
        if dataset_filename is not None:
            dataset_filename = dataset_filename + ".csv"
            daq.data_capture(False)
            ds = daq.data_capture_dataset()
            ts.log('Saving file: %s' % dataset_filename)
            ds.to_csv(ts.result_file_path(dataset_filename))
            result_params['plot.title'] = dataset_filename.split('.csv')[0]
            ts.result_file(dataset_filename, params=result_params)
        ts.log_error('Test script exception: %s' % traceback.format_exc())

    finally:
        if daq is not None:
            daq.close()
        if pv is not None:
            pv.power_set(p_rated)
            pv.close()
        if grid is not None:
            if v_nom is not None:
                grid.voltage(v_nom)
            grid.close()
        if chil is not None:
            chil.close()
        if eut is not None:
            eut.deactivate_all_fct()
            eut.close()
        if result_summary is not None:
            result_summary.close()

    return result
예제 #17
0
def test_run():
    result = script.RESULT_FAIL
    grid = None
    pv = p_rated = None
    daq = None
    eut = None
    rs = None
    phil = None
    result_summary = None
    step = None
    q_initial = None
    dataset_filename = None

    try:
        sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        p_rated_prime = ts.param_value('eut.p_rated_prime')
        s_rated = ts.param_value('eut.s_rated')
        var_rated = ts.param_value('eut.var_rated')

        # DC voltages
        v_nom_in_enabled = ts.param_value('cpf.v_in_nom')
        v_min_in_enabled = ts.param_value('cpf.v_in_min')
        v_max_in_enabled = ts.param_value('cpf.v_in_max')

        v_nom_in = ts.param_value('eut.v_in_nom')
        v_min_in = ts.param_value('eut_cpf.v_in_min')
        v_max_in = ts.param_value('eut_cpf.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_min = ts.param_value('eut.v_low')
        v_max = ts.param_value('eut.v_high')
        f_nom = ts.param_value('eut.f_nom')
        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')

        low_pwr_ena = ts.param_value('vrt.low_pwr_ena')
        high_pwr_ena = ts.param_value('vrt.high_pwr_ena')
        low_pwr_value = ts.param_value('vrt.low_pwr_value')
        high_pwr_value = ts.param_value('vrt.high_pwr_value')

        # Pass/fail accuracies
        pf_msa = ts.param_value('eut.pf_msa')

        # EUI Absorb capabilities
        absorb = {}
        absorb['ena'] = ts.param_value('eut_cpf.sink_power')
        absorb['p_rated_prime'] = ts.param_value('eut_cpf.p_rated_prime')
        absorb['p_min_prime'] = ts.param_value('eut_cpf.p_min_prime')

        startup_time = ts.param_value('eut.startup_time')

        # Following parameters are collected in p1547.VoltageRideThrough.set_vrt_params in init:
        # vrt.phase_comb, vrt.lv_ena, vrt.hv_ena, vrt.consecutive_ena, vrt.cat, vrt.range_steps

        # Functions to be enabled for test
        mode = []
        pwr_lvl = []
        steps_dict = {}
        timestep_dict = {}
        sequence_dict = {}
        parameters = []

        # initialize HIL environment, if necessary
        ts.log_debug(15 * "*" + "HIL initialization" + 15 * "*")

        phil = hil.hil_init(ts)
        if phil is not None:
            # return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name)
            open_proj = phil._param_value('hil_config_open')
            compilation = phil._param_value('hil_config_compile')
            stop_sim = phil._param_value('hil_config_stop_sim')
            load = phil._param_value('hil_config_load')
            execute = phil._param_value('hil_config_execute')
            model_name = phil._param_value('hil_config_model_name')
            phil.config()

        ''' RTLab OpWriteFile Math using worst case scenario of 160 seconds, 14 signals and Ts = 40e-6
        Duration of acquisition in number of points: Npoints = (Tend-Tstart)/(Ts*dec) = (160)/(0.000040*250) = 16e3
        
        Acquisition frame duration: Tframe = Nbss * Ts * dec = 1000*0.000040*250 = 10 sec
        
        Number of buffers to be acquired: Nbuffers = Npoints / Nbss = (Tend - Tstart) / Tframe = 16
        
        Minimum file size: MinSize= Nbuffers x SizeBuf = [(Tend - Tstart) / Ts ] * (Nsig+1) * 8 * Nbss 
            = (160/40e-6)*(14+1)*8*1000 = 4.8e11
        
        SizeBuf = 1/Nbuffers * {[(Tend - Tstart) / Ts ]*(Nsig+1)*8*Nbss} = [(160/0.000040)*(14+1)*8*1e3]/16 = 30e9
        Size of one buffer in bytes (SizeBuf) = (Nsig+1) * 8 * Nbss (Minimum) = (14+1)*8*1000 = 120e3
        '''

        if low_pwr_ena == 'Enabled':
            pwr_lvl.append(low_pwr_value)
        else:
            ts.log_debug('No low power chosen')
        if high_pwr_ena == 'Enabled':
            pwr_lvl.append(high_pwr_value)
        else:
            ts.log_debug('No high power chosen')
        if high_pwr_ena == 'Disabled' and low_pwr_ena == 'Disabled':
            ts.log_error('No power tests included in VRT test!')

        """
        Configure settings in 1547.1 Standard module for the Voltage Ride Through Tests
        """
        VoltRideThrough = p1547.VoltageRideThrough(ts=ts, support_interfaces={"hil": phil})
        # result params
        # result_params = lib_1547.get_rslt_param_plot()
        # ts.log(result_params

        # grid simulator is initialized with test parameters and enabled
        ts.log_debug(15 * "*" + "Gridsim initialization" + 15 * "*")
        grid = gridsim.gridsim_init(ts, support_interfaces={"hil": phil})  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)  # Setting the nominal voltage for the EUT in /SM_Source/SVP Commands/voltage_ph_x...

        # pv simulator is initialized with test parameters and enabled
        ts.log_debug(15 * "*" + "PVsim initialization" + 15 * "*")
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized

        # initialize data acquisition
        ts.log_debug(15 * "*" + "DAS initialization" + 15 * "*")
        daq = das.das_init(ts, support_interfaces={"hil": phil, "pvsim": pv})
        if daq is not None:
            daq.sc['V_MEAS'] = 100
            """
            daq.sc['P_MEAS'] = 100
            daq.sc['Q_MEAS'] = 100
            daq.sc['Q_TARGET_MIN'] = 100
            daq.sc['Q_TARGET_MAX'] = 100
            daq.sc['PF_TARGET'] = 1
            daq.sc['event'] = 'None'
            ts.log('DAS device: %s' % daq.info())
            """

        """
        This test doesn't have specific procedure steps. 
        """

        # 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)
        result_summary.write('Test Name, Waveform File, RMS File\n')

        """
        During the LVRT test, the settings for magnitude and duration of undervoltage tripping functions shall be
        disabled or set so as not to influence the outcome of the test. 
        
        If the EUT provides a voltage-active power control mode, that mode shall be disabled. 
        
        Connect the EUT according to the instructions and specifications provided by the manufacturer.
        """
        # Wait to establish communications with the EUT after AC and DC power are provided
        eut = der.der_init(ts)

        # start = time.time()
        # comm_wait_time = max(0.0, startup_time - 60.)
        # while time.time()-start < comm_wait_time - 1:
        #     ts.sleep(1)
        #     ts.log('Waiting another %0.2f seconds until communicating with EUT' %
        #            (comm_wait_time - (time.time()-start)))

        if eut is not None:
            eut.config()
        # if eut is not None:
        #     eut.deactivate_all_fct()

        """
        The voltage-reactive power control mode of the EUT shall be set to the default settings specified in Table 8
        of IEEE Std 1547-2018 for the applicable performance category, and enabled.
        """
        # Default curve is characteristic curve 1
        vv_curve = 1
        VoltVar = p1547.VoltVar(ts=ts, imbalance=True)
        v_pairs = VoltVar.get_params(curve=vv_curve)
        ts.log_debug('v_pairs:%s' % v_pairs)

        if eut is not None:
            # Set to: V = {92, 98, 102, 108}, Var = {44, 0 , 0 , -44}
            vv_curve_params = {'v': [round(v_pairs['V1'] * (100 / v_nom)),
                                     round(v_pairs['V2'] * (100 / v_nom)),
                                     round(v_pairs['V3'] * (100 / v_nom)),
                                     round(v_pairs['V4'] * (100 / v_nom))],
                               'q': [round(v_pairs['Q1'] * (100 / var_rated)),
                                     round(v_pairs['Q2'] * (100 / var_rated)),
                                     round(v_pairs['Q3'] * (100 / var_rated)),
                                     round(v_pairs['Q4'] * (100 / var_rated))],
                               'DeptRef': 'Q_MAX_PCT'}
            ts.log_debug('Setting VV points: %s' % vv_curve_params)
            # eut.volt_var(params={'Ena': True, 'curve': vv_curve_params})

        """
        The frequency-active power control mode of the EUT shall be set to the default settings.
        """
        # if eut is not None:
        #     params = {'Ena': True,
        #               'curve': 1,
        #               'dbf': fw_param['dbf'],
        #               'kof': fw_param['kof'],
        #               'RspTms': fw_param['tr']}
        #     ts.log_debug(params)
        #     eut.freq_watt(params)

        """
        Set or verify that all frequency trip settings are set to not influence the outcome of the test.
        """
        # ts.log_debug('HFRT and trip parameters from EUT : {}'.format(eut.frt_stay_connected_high()))
        # ts.log_debug('LFRT and trip parameters from EUT : {}'.format(eut.frt_stay_connected_low()))

        """
        Operate the ac test source at nominal frequency ± 0.1 Hz.
        """
        # Configured in PHIL on startup

        # Initial loop for all mode that will be executed
        modes = VoltRideThrough.get_modes()  # Options: LV_CAT_2, HV_CAT_2, LV_CAT_3, HV_CAT_3
        ts.log(f"VRT modes tested : '{modes}'")
        for current_mode in modes:
            # Configuring waveform timing blocks with offset in seconds
            # daq.waveform_config(vrt_lib_1547.get_waveform_config(current_mode,offset=5))

            ts.log_debug(f'Clearing old parameters if any')
            # parameters.clear()

            ts.log_debug(f'Initializing {current_mode}')

            """
            The ride-through tests shall be performed at two output power levels, high and low, and at any convenient
            power factor greater than 0.90. The output power levels shall be measured prior to the disturbance, i.e., in
            test condition A. High-power tests shall be performed at any active power level greater than 90% of the
            EUT nameplate active power rating at nominal voltage. ... Low-power tests shall be performed at any 
            convenient power level between 25% to 50% of EUT nameplate  apparent power rating at nominal voltage.
            """
            for pwr in pwr_lvl:  # Loop for all power levels
                dataset_filename = f'VRT_{current_mode}_{round(pwr*100)}PCT'
                ts.log(f'------------{dataset_filename}------------')
                daq.data_capture(True)

                """
                Setting up available power to appropriate power level 
                """
                if pv is not None:
                    ts.log_debug(f'Setting power level to {pwr}')
                    pv.iv_curve_config(pmp=p_rated, vmp=v_nom_in)
                    pv.irradiance_set(1000.)
                    pv.power_set(p_rated * pwr)

                """
                Initiating voltage sequence for VRT
                """
                vrt_parameters, vrt_start_time, vrt_stop_time = VoltRideThrough.get_model_parameters(current_mode)
                ts.log(f"The start time will be at {vrt_start_time}")
                ts.log(f"The stop time will be at {vrt_stop_time}")
                ts.log(f"Total VRT time is {vrt_stop_time-vrt_start_time}")
                VoltRideThrough.waveform_config(param={"pre_trigger": vrt_start_time - 5,
                                                       "post_trigger": vrt_stop_time + 5})

                if phil is not None:
                    # Set model parameters
                    phil.set_parameters(vrt_parameters)
                    vrt_stop_time = vrt_stop_time + 5
                    ts.sleep(0.5)
                    ts.log('Stop time set to %s' % phil.set_stop_time(vrt_stop_time))
                    phil.load_model_on_hil()
                    phil.start_simulation()

                    sim_time = phil.get_time()
                    while (vrt_stop_time - sim_time) > 1.0:  # final sleep will get to stop_time.
                        sim_time = phil.get_time()
                        ts.log('Sim Time: %0.3f.  Waiting another %0.3f sec before saving data.' % (
                            sim_time, vrt_stop_time - sim_time))
                        ts.sleep(5)

                ts.log('Sampling RMS complete')
                rms_dataset_filename = dataset_filename + "_RMS.csv"
                wave_start_filename = dataset_filename + "_WAV.csv"
                daq.data_capture(False)

                # complete data capture
                ts.log('Waiting for Opal to save the waveform data: {}'.format(dataset_filename))
                ts.sleep(10)
                # Convert and save the .mat file that contains the phase jump start
                ts.log('Processing waveform dataset(s)')
                ds = daq.waveform_capture_dataset()  # returns list of databases of waveforms (overloaded)
                ts.log(f'Number of waveforms to save {len(ds)}')
                if len(ds) > 0:
                    ds[0].to_csv(ts.result_file_path(wave_start_filename))
                    ts.result_file(wave_start_filename)

                ts.log('Sampling RMS complete')
                ds = daq.data_capture_dataset()
                ts.log('Saving file: %s' % rms_dataset_filename)
                ds.to_csv(ts.result_file_path(rms_dataset_filename))
                ds.remove_none_row(ts.result_file_path(rms_dataset_filename), "TIME")
                result_params = {
                    'plot.title': rms_dataset_filename.split('.csv')[0],
                    'plot.x.title': 'Time (sec)',
                    'plot.x.points': 'TIME',
                    'plot.y.points': 'AC_VRMS_1, AC_VRMS_2, AC_VRMS_3',
                    'plot.y.title': 'Voltage (V)',
                    'plot.y2.points': 'AC_IRMS_1, AC_IRMS_2, AC_IRMS_3',
                    'plot.y2.title': 'Current (A)',
                }

                # Remove the None in the dataset file
                ts.result_file(rms_dataset_filename, params=result_params)
                result_summary.write('%s, %s, %s,\n' % (dataset_filename, wave_start_filename,
                                                        rms_dataset_filename))

                phil.stop_simulation()

        result = script.RESULT_COMPLETE

    except script.ScriptFail as e:
        reason = str(e)
        if reason:
            ts.log_error(reason)

    except Exception as e:
        ts.log_error((e, traceback.format_exc()))

        ts.log_error('Test script exception: %s' % traceback.format_exc())

    finally:
        if grid is not None:
            grid.close()
        if pv is not None:
            if p_rated is not None:
                pv.power_set(p_rated)
            pv.close()
        if daq is not None:
            daq.close()
        if eut is not None:
            # eut.fixed_pf(params={'Ena': False, 'PF': 1.0})
            eut.close()
        if rs is not None:
            rs.close()
        if phil is not None:
            if phil.model_state() == 'Model Running':
                phil.stop_simulation()
            phil.close()

        if result_summary is not None:
            result_summary.close()

        # create result workbook
        excelfile = ts.config_name() + '.xlsx'
        rslt.result_workbook(excelfile, ts.results_dir(), ts.result_dir())
        ts.result_file(excelfile)

    return result
예제 #18
0
def volt_watt_mode(vw_curves, t_settling, pwr_lvls):

    result = script.RESULT_FAIL
    daq = None
    data = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None

    try:
        # result params
        result_params = {
            'plot.title': 'title_name',
            'plot.x.title': 'Time (sec)',
            'plot.x.points': 'TIME',
            'plot.y.points': 'V_TARGET,V_MEAS',
            'plot.y.title': 'Voltage (V)',
            'plot.V_TARGET.point': 'True',
            'plot.y2.points': 'P_TARGET,P_MEAS',
            'plot.P_TARGET.point': 'True',
            'plot.P_TARGET.min_error': 'P_TARGET_MIN',
            'plot.P_TARGET.max_error': 'P_TARGET_MAX',
        }

        cat = ts.param_value('eut.cat')
        cat2 = ts.param_value('eut.cat2')
        sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        p_rated_prime = ts.param_value('eut.p_rated_prime')
        s_rated = ts.param_value('eut.s_rated')
        eff = {
            1.00: ts.param_value('eut.efficiency_100') / 100,
            0.66: ts.param_value('eut.efficiency_66') / 100,
            0.20: ts.param_value('eut.efficiency_20') / 100
        }
        absorb_enable = ts.param_value('eut.abs_enabled')

        # DC voltages
        v_nom_in = ts.param_value('eut.v_in_nom')
        v_min_in = ts.param_value('eut.v_in_min')
        v_max_in = ts.param_value('eut.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_min = ts.param_value('eut.v_low')
        v_max = ts.param_value('eut.v_high')
        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')
        pf_settling_time = ts.param_value('eut.pf_settling_time')
        imbalance_resp = ts.param_value('eut.imbalance_resp')

        # Pass/fail accuracies
        pf_msa = ts.param_value('eut.pf_msa')
        # According to Table 3-Minimum requirements for manufacturers stated measured and calculated accuracy
        MSA_Q = 0.05 * s_rated
        MSA_P = 0.05 * s_rated
        MSA_V = 0.01 * v_nom
        a_v = 1.5 * MSA_V

        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''
        # 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)  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)

        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        pv.power_set(p_rated)
        pv.power_on()  # Turn on DC so the EUT can be initialized

        # DAS soft channels
        das_points = {'sc': ('P_TARGET', 'P_TARGET_MIN', 'P_TARGET_MAX', 'P_MEAS', 'V_TARGET','V_MEAS','event')}

        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'])
        daq.sc['P_TARGET'] = 100
        daq.sc['P_TARGET_MIN'] = 100
        daq.sc['P_TARGET_MAX'] = 100
        daq.sc['V_TARGET'] = v_nom
        daq.sc['event'] = 'None'

        ts.log('DAS device: %s' % daq.info())

        '''
        b) Set all voltage trip parameters to the widest range of adjustability. Disable all reactive/active power
        control functions.
        '''
        # it is assumed the EUT is on
        eut = der.der_init(ts)
        if eut is not None:
            vw_curve_params = {'v': [v_start, v_stop], 'w': [100., 0], 'DeptRef': 'W_MAX_PCT'}
            vw_params = {'Ena': True, 'ActCrv': 1, 'curve': vw_curve_params}
            eut.volt_watt(params=vw_params)
            ts.log_debug('Initial EUT VW settings are %s' % eut.volt_watt())
        '''
        c) Set all AC test source parameters to the nominal operating voltage and frequency.
        '''

        if grid is not None:
            grid.voltage(v_nom)

        # 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)

        result_summary.write('Result,Test Name,Power Level,Iteration,direction,V_target,V_actual,Power_target,Power_actual,P_min,P_max,Dataset File\n')


        '''
        d) Adjust the EUT's available active power to Prated. For an EUT with an input voltage range, set the input
        voltage to Vin_nom. The EUT may limit active power throughout the test to meet reactive power requirements.
        For an EUT with an input voltage range, repeat steps d) through o) for Vin_min and Vin_max.
        '''

        #if pv is not None:
            # TODO implement IV_curve_config
            #pv.iv_curve_config(pmp=p_rated, vpm=v_nom)
            #pv.iv_curve_config(pmp=p_rated, vpm=v_in)
            #pv.irradiance_set(1000.)
        '''
        e) Set EUT volt-watt parameters to the values specified by Characteristic 1. All other function be turned off.
        '''

        v_pairs = collections.OrderedDict()#{}

        v_pairs[1] = {'V1': round(1.06 * v_nom, 2),
                      'V2': round(1.10 * v_nom, 2),
                      'P1': round(p_rated, 2)}

        v_pairs[2] = {'V1': round(1.05 * v_nom, 2),
                      'V2': round(1.10 * v_nom, 2),
                      'P1': round(p_rated, 2)}

        v_pairs[3] = {'V1': round(1.09 * v_nom, 2),
                      'V2': round(1.10 * v_nom, 2),
                      'P1': round(p_rated, 2)}

        if absorb_enable == 'Yes':

            v_pairs[1].add('P2', 0)
            v_pairs[2].add('P2', p_rated_prime)
            v_pairs[3].add('P2', p_rated_prime)

        else:

            if p_min > (0.2 * p_rated):
                v_pairs[1]['P2'] = int(0.2 * p_rated)
                v_pairs[2]['P2'] = int(0.2 * p_rated)
                v_pairs[3]['P2'] = int(0.2 * p_rated)
            else:
                v_pairs[1]['P2'] = int(p_min)
                v_pairs[2]['P2'] = int(p_min)
                v_pairs[3]['P2'] = int(p_min)

        '''
        f) Verify volt-watt mode is reported as active and that the correct characteristic is reported.
        g) Begin the adjustment towards V_h. Step the AC test source voltage to a_v below V_1.
        t) Repeat steps d) through t) at EUT power set at 20% and 66% of rated power.
        u) Repeat steps d) through u) for characteristics 2 and 3.
        v) Test may be repeated for EUT's that can also absorb power using the P' values in the characteristic definition.
        '''

        """
        Test start
        """
        for test, vw_curve in vw_curves.iteritems():

            ts.log('Starting test with VW mode at %s' % (test))

            v_steps_dict = collections.OrderedDict()

            # 1547.1 :
            v_steps_up = [(v_pairs[vw_curve]['V1'] - a_v),  # step g
                          (v_pairs[vw_curve]['V1'] + a_v),  # step h
                          (v_pairs[vw_curve]['V2'] + v_pairs[vw_curve]['V1']) / 2,  # step i
                          v_pairs[vw_curve]['V2'] - a_v,  # step j
                          v_pairs[vw_curve]['V2'] + a_v,  # step k
                          v_max - a_v]  # step l

            v_steps_down = [v_pairs[vw_curve]['V2'] + a_v,  # step m
                            v_pairs[vw_curve]['V2'] - a_v,  # step n
                            (v_pairs[vw_curve]['V1'] + v_pairs[vw_curve]['V2']) / 2,  # step o
                            v_pairs[vw_curve]['V1'] + a_v,  # step p
                            v_pairs[vw_curve]['V1'] - a_v,  # step q
                            v_min + a_v]  # step s

            for i in range(len(v_steps_up)):
                if v_steps_up[i] > v_max:
                    v_steps_up[i] = v_max
                elif v_steps_up[i] < v_min:
                    v_steps_up[i] = v_min
            for i in range(len(v_steps_down)):
                if v_steps_down[i] > v_max:
                    v_steps_down[i] = v_max
                elif v_steps_down[i] < v_min:
                    v_steps_down[i] = v_min

            v_steps_dict['up'] = np.around(v_steps_up, decimals=2)
            v_steps_dict['down'] = np.around(v_steps_down, decimals=2)
            ts.log('Testing VW function at the following voltage(up) points %s' % v_steps_dict['up'])
            ts.log('Testing VW function at the following voltage(down) points %s' % v_steps_dict['down'])

            for power in pwr_lvls:
                if pv is not None:
                    # TODO implement IV_curve_config
                    pv.power_set(power)
                    #pv_power_setting = (p_rated * power) / eff[power]
                    #pv.iv_curve_config(pmp=pv_power_setting, vpm=v_in)
                    #pv.irradiance_set(1000.)
                    #ts.log('Set PV simulator power to {} with efficiency at {} %'.format(p_rated * power, eff[power] * 100.))



                ts.log_debug('curve points:  %s' % v_pairs[vw_curve])

                # Configure the data acquisition system
                ts.log('Starting data capture for power = %s' % power)
                dataset_filename = 'VW_curve_%s_pwr_%0.2f.csv' % (vw_curve, power)
                daq.data_capture(True)

                for direction, v_steps in v_steps_dict.iteritems():
                    for v_step in v_steps:

                        ts.log('        Recording power at voltage %0.2f V for 4*t_settling = %0.1f sec.' %
                               (v_step, 4 * t_settling[vw_curve]))
                        daq.sc['V_TARGET'] = v_step
                        daq.sc['event'] = 'v_step_{}'.format(direction)

                        p_targ = interpolation_v_p(value=v_step,
                                                   v_pairs=v_pairs[vw_curve])

                        grid.voltage(v_step)
                        for i in range(4):
                            daq.sc['event'] = 'v_step_{}'.format(direction)
                            ts.sleep(1 * t_settling[vw_curve])
                            daq.sc['event'] = 'TR_{}_done'.format(i + 1)
                            daq.data_sample()
                            data = daq.data_capture_read()

                        daq.sc['P_TARGET'] = p_targ

                        # Test result accuracy requirements per IEEE1547-4.2 for Q(V)
                        P_V_passfail = p_v_criteria(v_pairs=v_pairs[vw_curve], a_v=a_v, p_mra=MSA_P, daq=daq,
                                                    imbalance_resp=imbalance_resp)
                                                   #data=data)

                        # Test result accuracy requirements per IEEE1547-4.2 for Q(tr)
                        # TODO p_tr_criteria still needs to be implemented

                        ts.log('        Powers targ, min, max: %s, %s, %s' % (
                        daq.sc['P_TARGET'], daq.sc['P_TARGET_MIN'], daq.sc['P_TARGET_MAX']))

                        daq.sc['event'] = 'T_settling_done_{}'.format(direction)
                        daq.data_sample()



            result_summary.write('%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s \n' %
                                 (P_V_passfail,
                                  ts.config_name(),
                                  power * 100.,
                                  direction,
                                  daq.sc['V_TARGET'],
                                  daq.sc['V_MEAS'],
                                  daq.sc['P_TARGET'],
                                  daq.sc['P_MEAS'],
                                  daq.sc['P_TARGET_MIN'],
                                  daq.sc['P_TARGET_MAX'],
                                  dataset_filename))

        # create result workbook

        ts.log('Sampling complete')
        daq.data_capture(False)
        ds = daq.data_capture_dataset()
        ts.log('Saving file: %s' % dataset_filename)
        ds.to_csv(ts.result_file_path(dataset_filename))
        result_params['plot.title'] = os.path.splitext(dataset_filename)[0]
        ts.result_file(dataset_filename, params=result_params)
        result = script.RESULT_COMPLETE

        return result

    except script.ScriptFail, e:
        reason = str(e)
        if reason:
            ts.log_error(reason)
def test_run():

    result = script.RESULT_FAIL
    daq = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None
    dataset_filename = None
    v_nom = None

    try:

        settings_test = ts.param_value('iop.settings_test')
        monitoring_test = ts.param_value('iop.monitoring_test')

        v_nom = float(ts.param_value('eut.v_nom'))
        MSA_V = 0.01 * v_nom
        va_max = float(ts.param_value('eut.s_rated'))
        va_crg_max = va_max
        MSA_Q = 0.05 * float(ts.param_value('eut.s_rated'))
        MSA_P = 0.05 * float(ts.param_value('eut.s_rated'))
        MSA_F = 0.01
        f_nom = float(ts.param_value('eut.f_nom'))
        phases = ts.param_value('eut.phases')
        p_rated = float(ts.param_value('eut.p_rated'))
        w_max = p_rated
        p_min = p_rated
        w_crg_max = p_rated
        var_rated = float(ts.param_value('eut.var_rated'))
        var_max = float(ts.param_value('eut.var_rated'))

        # initialize DER configuration
        eut = der.der_init(ts)
        eut.config()

        das_points = {'sc': ('event')}
        daq = das.das_init(ts, sc_points=das_points['sc'])

        # initialize HIL environment, if necessary
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()

        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized

        # grid simulator is initialized with test parameters and enabled
        grid = gridsim.gridsim_init(
            ts)  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)

        lib_1547 = p1547.module_1547(ts=ts, aif='Interoperability Tests')
        ts.log_debug("1547.1 Library configured for %s" %
                     lib_1547.get_test_name())
        '''
        6.4 Nameplate data test
        a) Read from the DER each nameplate data item listed in Table 28 in IEEE Std 1547-2018.
        b) Compare each value received to the expected values from the manufacturer-provided expected values.

        Table 28 - Nameplate information
        ________________________________________________________________________________________________________________
        Parameter                                               Description
        ________________________________________________________________________________________________________________
        1. Active power rating at unity power factor            Active power rating in watts at unity power factor
           (nameplate active power rating)
        2. Active power rating at specified over-excited        Active power rating in watts at specified over-excited
           power factor                                         power factor
        3. Specified over-excited power factor                  Over-excited power factor as described in 5.2
        4. Active power rating at specified under-excited       Active power rating in watts at specified under-excited
           power factor                                         power factor
        5. Specified under-excited power factor                 Under-excited power factor as described in 5.2
        6. Apparent power maximum rating                        Maximum apparent power rating in voltamperes
        7. Normal operating performance category                Indication of reactive power and voltage/power control
                                                                capability. (Category A/B as described in 1.4)
        8. Abnormal operating performance category              Indication of voltage and frequency ride-through
                                                                capability Category I, II, or III, as described in 1.4
        9. Reactive power injected maximum rating               Maximum injected reactive power rating in vars
        10. Reactive power absorbed maximum rating              Maximum absorbed reactive power rating in vars
        11. Active power charge maximum rating                  Maximum active power charge rating in watts
        12. Apparent power charge maximum rating                Maximum apparent power charge rating in voltamperes. May
                                                                differ from the apparent power maximum rating
        13. AC voltage nominal rating                           Nominal AC voltage rating in RMS volts
        14. AC voltage maximum rating                           Maximum AC voltage rating in RMS volts
        15. AC voltage minimum rating                           Minimum AC voltage rating in RMS volts
        16. Supported control mode functions                    Indication of support for each control mode function
        17. Reactive susceptance that remains connected to      Reactive susceptance that remains connected to the Area
            the Area EPS in the cease to energize and trip      EPS in the cease to energize and trip state
            state
        18. Manufacturer                                        Manufacturer
        19. Model                                               Model
        20. Serial number                                       Serial number
        21. Version                                             Version
        '''

        ts.log('---')
        der_info = eut.info()
        nameplate = eut.nameplate()

        ts.log('DER Nameplate Information:')
        if nameplate is not None:
            ts.log(
                '  Active power rating at unity power factor (nameplate active power rating) [WRtg]: %s'
                % nameplate.get('WRtg'))
            ts.log(
                '  Active power rating at specified over-excited power factor: %s'
                % 'Unknown')
            ts.log('  Specified over-excited power factor [PFRtgQ1]: %s' %
                   nameplate.get('PFRtgQ1'))
            ts.log('  Specified under-excited power factor [PFRtgQ2]: %s' %
                   nameplate.get('PFRtgQ2'))
            ts.log('  Apparent power maximum rating: %s' %
                   nameplate.get('VARtg'))
            ts.log('  Normal operating performance category: %s' % 'Unknown')
            ts.log('  Abnormal operating performance category: %s' % 'Unknown')
            ts.log('  Reactive power injected maximum rating [VArRtgQ1]: %s' %
                   nameplate.get('VArRtgQ1'))
            ts.log('  Reactive power absorbed maximum rating [VArRtgQ4]: %s' %
                   nameplate.get('VArRtgQ4'))
            ts.log('  Apparent power charge maximum rating: %s' %
                   nameplate.get('MaxChrRte'))
            ts.log('  AC voltage nominal rating: %s' % 'Unknown')
            ts.log('  AC voltage maximum rating: %s' % 'Unknown')
            ts.log('  AC voltage minimum rating: %s' % 'Unknown')
        if der_info is not None:
            ts.log('  Supported control mode functions: %s' %
                   der_info.get('Options'))
        else:
            ts.log_warning('DER info not supported')
        if nameplate is not None:
            ts.log(
                '  Reactive susceptance that remains connected to the Area EPS in the cease to '
                'energize and trip state: %s' % 'Unknown')
        else:
            ts.log_warning('DER nameplate not supported')
        if der_info is not None:
            ts.log('  Manufacturer: %s' % (der_info.get('Manufacturer')))
            ts.log('  Model: %s' % (der_info.get('Model')))
            ts.log('  Serial Number: %s' % (der_info.get('SerialNumber')))
            ts.log('  Version: %s' % (der_info.get('Version')))
        else:
            ts.log_warning('DER info not supported')

        if settings_test:
            '''
            6.5 Basic settings information test

            a) Read from the DER each parameter identified in Table 42.
            b) For each, verify that the value reported matches the behavior of the DER measured though independent test
               equipment separate from the DER interface.
            c) Adjust values as identified in Table 42.
            d) Repeat steps a) and b) for the new values.
            e) Adjust parameters back to the initial values and verify that the value reported matches the initial
               values.

            Table 42 - Basic settings test levels
            ____________________________________________________________________________________________________________
            Parameter                           Adjustment required            Additional test instructions
            ____________________________________________________________________________________________________________
            Active Power Maximum                Set to 80% of Initial Value
            Apparent Power Maximum              Set to 80% of Initial Value
            Reactive Power Injected Maximum     Set to 80% of Initial Value
            Reactive Power Absorbed Maximum     Set to 80% of Initial Value
            Active Power Charge Maximum         Set to 80% of Initial Value     This test applies only to DER that
                                                                                include energy storage.
            Apparent Power Charge Maximum       Set to 80% of Initial Value     This test applies only to DER that
                                                                                include energy storage.
            AC Current Maximum                  Set to 80% of Initial Value
            Control Mode Functions              Not applicable
            Stated Energy Storage Capacity      Set to 80% of Initial Value     This test applies only to DER that
                                                                                include energy storage.
            Mode Enable Interval                Set to 5 s, set to 300 s
            '''

            # Special considerations for CHIL ASGC/Typhoon startup
            if chil is not None:
                inv_power = eut.measurements().get('W')
                timeout = 120.
                if inv_power <= p_rated * 0.85:
                    pv.irradiance_set(
                        995)  # Perturb the pv slightly to start the inverter
                    ts.sleep(3)
                    eut.connect(params={'Conn': True})
                while inv_power <= p_rated * 0.85 and timeout >= 0:
                    ts.log(
                        'Inverter power is at %0.1f. Waiting up to %s more seconds or until EUT starts...'
                        % (inv_power, timeout))
                    ts.sleep(1)
                    timeout -= 1
                    inv_power = eut.measurements().get('W')
                    if timeout == 0:
                        result = script.RESULT_FAIL
                        raise der.DERError('Inverter did not start.')
                ts.log('Waiting for EUT to ramp up')
                ts.sleep(8)
                # ts.log_debug('DAS data_read(): %s' % daq.data_read())

            settings = eut.settings()
            if settings is not None:
                # Active Power Maximum
                ts.log('  Active Power Maximum [WMax]: %s' %
                       (settings.get('WMax')))
                ts.log('  Setting WMax to %f.' % (0.8 * w_max))
                eut.settings(params={'WMax': 0.8 * w_max})
                ts.sleep(2)
                power = lib_1547.get_measurement_total(
                    data=daq.data_capture_read(), type_meas='P', log=True)
                ts.log('  Power was recorded to be: %f.' % power)
                ts.log('  Returning WMax to %f.' % w_max)
                eut.settings(params={'WMax': w_max})

                # Apparent Power Maximum
                ts.log('  Apparent Power Maximum [VAMax]: %s' %
                       (settings.get('VAMax')))
                ts.log('  Setting VAMax to %f.' % (0.8 * va_max))
                eut.settings(params={'VAMax': 0.8 * va_max})
                ts.sleep(2)
                va = lib_1547.get_measurement_total(
                    data=daq.data_capture_read(), type_meas='VA', log=True)
                ts.log('  Apparent Power was recorded to be: %f.' % va)
                ts.log('  Returning VAMax to %f.' % va_max)
                eut.settings(params={'VAMax': va_max})

                # Reactive Power Injected Maximum
                # TODO check on sign convention here
                ts.log('  Reactive Power Injected Maximum [VArMaxQ1]: %s' %
                       (settings.get('VArMaxQ1')))
                ts.log('  Setting VArMaxQ1 to %f.' % (0.8 * var_max))
                eut.settings(params={'VArMaxQ1': 0.8 * var_max})
                eut.reactive_power(params={
                    'Ena': True,
                    'VArPct_Mod': 'VArMax',
                    'VArMaxPct': 100
                })
                ts.sleep(2)
                q = lib_1547.get_measurement_total(
                    data=daq.data_capture_read(), type_meas='Q', log=True)
                ts.log('  Reactive Power Injected was recorded to be: %f.' % q)
                ts.log('  Returning VArMaxQ1 to %f.' % var_max)
                eut.settings(params={'VArMaxQ1': var_max})
                eut.reactive_power(params={'Ena': False})

                # Reactive Power Absorbed Maximum
                ts.log('  Reactive Power Absorbed Maximum [VArMaxQ4]: %s' %
                       (settings.get('VArMaxQ4')))
                ts.log('  Setting VArMaxQ4 to %f.' % (0.8 * var_max))
                eut.settings(params={'VArMaxQ4': 0.8 * var_max})
                eut.reactive_power(params={
                    'Ena': True,
                    'VArPct_Mod': 'VArMax',
                    'VArMaxPct': -100
                })
                ts.sleep(2)
                q = lib_1547.get_measurement_total(
                    data=daq.data_capture_read(), type_meas='Q', log=True)
                ts.log('  Reactive Power Absorbed was recorded to be: %f.' % q)
                ts.log('  Returning VArMaxQ4 to %f.' % var_max)
                eut.settings(params={'VArMaxQ4': var_max})
                eut.reactive_power(params={'Ena': False})

                # AC Current Maximum
                ts.log('  Apparent Power Maximum [VAMax]: %s' %
                       (settings.get('VAMax')))
                ts.log('  Setting VAMax to %f.' % (0.8 * va_max))
                eut.settings(params={'VAMax': 0.8 * va_max})
                ts.sleep(2)
                va = lib_1547.get_measurement_total(
                    data=daq.data_capture_read(), type_meas='VA', log=True)
                ts.log('  Apparent Power was recorded to be: %f.' % va)
                ts.log('  Returning VAMax to %f.' % va_max)
                eut.settings(params={'VAMax': va_max})

                # Mode Enable Interval
                # TODO add this assessment  {'ModeInterval': [5, 300]}

            else:
                ts.log_warning('DER settings not supported')

            storage = eut.storage()
            if storage is not None:
                # Active Power Charge Maximum
                ts.log('  Active Power Charge Maximum [WChaMax]: %s' %
                       (storage.get('WChaMax')))
                ts.log('  Setting WChaMax to %f.' % (0.8 * w_crg_max))
                eut.storage(params={'WChaMax': 0.8 * w_crg_max})
                ts.log('  Setting InWRte to %f %% of max charging rate.' %
                       100.)  # Percent of max charging rate.
                eut.storage(params={'InWRte': 100.})
                ts.sleep(2)
                power = lib_1547.get_measurement_total(
                    data=daq.data_capture_read(), type_meas='P', log=True)
                ts.log('  Apparent Power was recorded to be: %f.' % power)
                ts.log('  Returning WChaMax to %f.' % w_crg_max)
                eut.storage(params={'WChaMax': w_crg_max})
                eut.storage(params={'InWRte': 0.})

                # Apparent Power Charge Maximum
                ts.log('  Apparent Power Charge Maximum [VAChaMax]: %s' %
                       (storage.get('VAChaMax')))
                ts.log('  Setting WChaMax to %f.' % (0.8 * va_crg_max))
                eut.storage(params={'VAChaMax': 0.8 * va_crg_max})
                ts.log('  Setting InWRte to %f %% of max charging rate.' %
                       100.)  # Percent of max charging rate.
                eut.storage(params={'InWRte': 100.})
                ts.sleep(2)
                power = lib_1547.get_measurement_total(
                    data=daq.data_capture_read(), type_meas='VA', log=True)
                ts.log('  Apparent Power was recorded to be: %f.' % power)
                ts.log('  Returning VAChaMax to %f.' % va_crg_max)
                eut.storage(params={'VAChaMax': va_crg_max})
                eut.storage(params={'InWRte': 0.})

                # Stated Energy Storage Capacity
                # StorAval = State of charge (ChaState) minus storage reserve (MinRsvPct) times capacity rating (AhrRtg)
                # TODO add this assessment

            else:
                ts.log_warning('DER storage not supported')

        if monitoring_test:
            '''
            6.6 Monitoring information test

            a) Set the operating conditions of the DER to the values specified in the "Operating Point A" column in
               Table 43.
            b) Wait not less than 30 s, then read from the DER each monitoring information, and verify that the
               reported values match the operating conditions as identified.
            c) Change the operating conditions of the DER as specified in the "Operating Point B" column 16 in Table 43.
            d) Repeat step b).
            '''

            # Monitoring information parameter: Active Power
            # Operating Point A: 0 to 10% of DER "active power rating at unity power factor"
            # Operating Point B: 90 to 100% of DER "active power rating at unity power factor"
            # Pass/Fail Criteria: Reported values match test operating conditions within the accuracy requirements
            # specified in Table 3 in IEEE Std 1547-2018. (+/- 5% Srated)
            m = eut.measurements()
            if m is not None:
                ts.log('  Active Power reported from the EUT is: %s W' %
                       (m.get('W')))
                for setpoint in [5, 100]:
                    eut.limit_max_power(params={
                        'Ena': True,
                        'WMaxPct': setpoint
                    })  # curtial to 5% of power
                    inaccurate_measurement = True
                    while inaccurate_measurement:
                        power_pct = 100 * (eut.measurements().get('W') / w_max)
                        ts.log('    EUT power is currently %f%% Prated' %
                               power_pct)
                        if setpoint - 5. <= power_pct <= setpoint + 5.:  # +/- 5% Srated
                            ts.log(
                                'EUT has recorded power +/- 5%% Srated, as required by IEEE 1547-2018.'
                            )
                            ts.log('Returning EUT to rated power.')
                            inaccurate_measurement = False
                        ts.sleep(1)
                    eut.limit_max_power(params={'Ena': False})
            else:
                ts.log_warning('DER measurements not supported')
            ts.log('---')

            # Monitoring information parameter: Reactive Power
            # Operating Point A: 90 to 100% of DER "reactive power injected maximum rating"
            # Operating Point B: 90 to 100% of DER "reactive power absorbed maximum rating"
            # Pass/Fail Criteria: Reported values match test operating conditions within the accuracy requirements
            # specified in Table 3 in IEEE Std 1547-2018. (+/- 5% Srated)
            m = eut.measurements()
            if m is not None:
                ts.log('  Reactive Power reported from the EUT is: %f VAr' %
                       (m.get('VAr')))
                for setpoint in [5, 100]:
                    eut.reactive_power(params={
                        'Ena': True,
                        'VArPct_Mod': 'VArMax',
                        'VArMaxPct': 100
                    })
                    inaccurate_measurement = True
                    while inaccurate_measurement:
                        q_pct = 100 * (eut.measurements().get('VAr') / var_max)
                        ts.log(
                            '    EUT reactive power is currently %f%% Qrated' %
                            q_pct)
                        if setpoint - 5. <= q_pct <= setpoint + 5.:  # +/- 5% Srated
                            ts.log(
                                'EUT has recorded reactive power +/- 5%% Srated, as required by IEEE 1547-2018.'
                            )
                            ts.log('Returning EUT to rated power.')
                            inaccurate_measurement = False
                        ts.sleep(1)
                    eut.reactive_power(params={'Ena': False})
            else:
                ts.log_warning('DER measurements not supported')
            ts.log('---')

            # Monitoring information parameter: Voltage
            # Operating Point A: At or below 0.90x(AC voltage nominal rating)
            # Operating Point B: At or above 1.08x(AC voltage nominal rating)
            # Pass/Fail Criteria: Reported values match test operating conditions within the accuracy requirements
            # specified in Table 3 in IEEE Std 1547-2018. (+/-1% Vnom)

            for setpoint in [90, 108]:
                grid.voltage(setpoint)

                inaccurate_measurement = True
                while inaccurate_measurement:

                    voltages = []
                    if self.phases == 'Single phase':
                        voltages.append(eut.measurements()['PhVphA'])
                    elif self.phases == 'Split phase':
                        voltages.append(eut.measurements()['PhVphA'])
                        voltages.append(eut.measurements()['PhVphB'])
                    elif self.phases == 'Three phase':
                        voltages.append(eut.measurements()['PhVphB'] / v_nom)
                        voltages.append(eut.measurements()['PhVphB'] / v_nom)
                        voltages.append(eut.measurements()['PhVphC'] / v_nom)
                        # TODO: also check phase to phase voltages
                        voltages.append(eut.measurements()['PPVphAB'] /
                                        (v_nom * math.sqrt(3)))
                        voltages.append(eut.measurements()['PPVphBC'] /
                                        (v_nom * math.sqrt(3)))
                        voltages.append(eut.measurements()['PPVphCA'] /
                                        (v_nom * math.sqrt(3)))

                    ts.log('    EUT voltages are currently %s pu' % voltages)
                    pass_criteria = []
                    for voltage in voltages:
                        if setpoint / 100. - 0.01 <= voltage <= setpoint / 100. + 0.01:  # +/- 1% Vnom
                            pass_criteria.append(True)
                        else:
                            pass_criteria.append(True)

                    if all(pass_criteria):
                        ts.log(
                            'EUT has recorded voltage +/- 1%% Vnom, as required by IEEE 1547-2018.'
                        )
                        ts.log('Returning EUT to rated power.')
                        inaccurate_measurement = False
                    ts.sleep(1)

            grid.voltage(v_nom)

            # Monitoring information parameter: Frequency
            # Operating Point A: At or below 57.2Hz
            # Operating Point B: At or above 61.6Hz
            # Pass/Fail Criteria: Reported values match test operating conditions within the accuracy requirements
            # specified in Table 3 in IEEE Std 1547-2018. (10 mHz)

            # Monitoring information parameter: Operational State
            # Operating Point A: On
            # Operating Point B: Off
            # Pass/Fail Criteria: Reported Operational State matches the device present condition for on and off states.

            # Monitoring information parameter: Connection Status
            # Operating Point A: Connected: Enable Permit and AC conditions have been met to enter service as specified
            # in Table 39 of IEEE Std 1547-2018
            # Operating Point B: Disconnected: Permit service is disabled
            # Pass/Fail Criteria: Reported Connection Status matches the device present connection condition.
            status = eut.controls_status()
            if status is not None:
                ts.log('    Is Fixed_W enabled?: %s' % (status.get('Fixed_W')))
                ts.log('    Is Fixed_Var enabled?: %s' %
                       (status.get('Fixed_Var')))
                ts.log('    Is Fixed_PF enabled?: %s' %
                       (status.get('Fixed_PF')))
                ts.log('    Is Volt_Var enabled?: %s' %
                       (status.get('Volt_Var')))
                ts.log('    Is Freq_Watt_Param enabled?: %s' %
                       (status.get('Freq_Watt_Param')))
                ts.log('    Is Freq_Watt_Curve enabled?: %s' %
                       (status.get('Freq_Watt_Curve')))
                ts.log('    Is Dyn_Reactive_Power enabled?: %s' %
                       (status.get('Dyn_Reactive_Power')))
                ts.log('    Is LVRT enabled?: %s' % (status.get('LVRT')))
                ts.log('    Is HVRT enabled?: %s' % (status.get('HVRT')))
                ts.log('    Is Watt_PF enabled?: %s' % (status.get('Watt_PF')))
                ts.log('    Is Volt_Watt enabled?: %s' %
                       (status.get('Volt_Watt')))
                ts.log('    Is Scheduled enabled?: %s' %
                       (status.get('Scheduled')))
                ts.log('    Is LFRT enabled?: %s' % (status.get('LFRT')))
                ts.log('    Is HFRT enabled?: %s' % (status.get('HFRT')))

                ts.log('---')
                status = eut.conn_status()
                ts.log('    Is PV_Connected?: %s' %
                       (status.get('PV_Connected')))
                ts.log('    Is PV_Available?: %s' %
                       (status.get('PV_Available')))
                ts.log('    Is PV_Operating?: %s' %
                       (status.get('PV_Operating')))
                ts.log('    Is PV_Test?: %s' % (status.get('PV_Test')))
                ts.log('    Is Storage_Connected?: %s' %
                       (status.get('Storage_Connected')))
                ts.log('    Is Storage_Available?: %s' %
                       (status.get('Storage_Available')))
                ts.log('    Is Storage_Operating?: %s' %
                       (status.get('Storage_Operating')))
                ts.log('    Is Storage_Test?: %s' %
                       (status.get('Storage_Test')))
                ts.log('    Is EPC_Connected?: %s' %
                       (status.get('EPC_Connected')))
                ts.log('---')

            # Monitoring information parameter: Alarm Status
            # Operating Point A: Has alarms set
            # Operating Point B: No alarms set
            # Pass/Fail Criteria: Reported Alarm Status matches the device present alarm condition for alarm and no
            # alarm conditions. The DER manufacturer shall specify at least one way an alarm condition which is
            # supported in the protocol being tested can be set and cleared.

        return script.RESULT_COMPLETE

    except script.ScriptFail, e:
        reason = str(e)
        if reason:
            ts.log_error(reason)
예제 #20
0
def volt_watt_mode_imbalanced_grid(imbalance_resp, vw_curves = 1):

    result = script.RESULT_FAIL
    daq = None
    data = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None

    try:
        # result params
        result_params = {
            'plot.title': 'title_name',
            'plot.x.title': 'Time (sec)',
            'plot.x.points': 'TIME',
            'plot.y.points': 'V_TARGET,V_MEAS',
            'plot.y.title': 'Voltage (V)',
            'plot.V_TARGET.point': 'True',
            'plot.y2.points': 'P_TARGET,P_MEAS',
            'plot.P_TARGET.point': 'True',
            'plot.P_TARGET.min_error': 'P_TARGET_MIN',
            'plot.P_TARGET.max_error': 'P_TARGET_MAX',
        }

        cat = ts.param_value('eut.cat')
        cat2 = ts.param_value('eut.cat2')
        sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        p_rated_prime = ts.param_value('eut.p_rated_prime')
        s_rated = ts.param_value('eut.s_rated')
        eff = {
            1.00: ts.param_value('eut.efficiency_100') / 100,
            0.66: ts.param_value('eut.efficiency_66') / 100,
            0.20: ts.param_value('eut.efficiency_20') / 100
        }
        absorb_enable = ts.param_value('eut.abs_enabled')

        # DC voltages
        v_nom_in = ts.param_value('eut.v_in_nom')
        v_min_in = ts.param_value('eut.v_in_min')
        v_max_in = ts.param_value('eut.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_min = ts.param_value('eut.v_low')
        v_max = ts.param_value('eut.v_high')
        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')
        pf_settling_time = ts.param_value('eut.pf_settling_time')
        imbalance_resp = ts.param_value('eut.imbalance_resp')

        # Pass/fail accuracies
        pf_msa = ts.param_value('eut.pf_msa')
        # According to Table 3-Minimum requirements for manufacturers stated measured and calculated accuracy
        MSA_Q = 0.05 * s_rated
        MSA_P = 0.05 * s_rated
        MSA_V = 0.01 * v_nom
        a_v = 1.5 * MSA_V

        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''
        # 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)  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)

        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        pv.power_set(p_rated)
        pv.power_on()  # Turn on DC so the EUT can be initialized

        # DAS soft channels
        das_points = {'sc': ('P_TARGET', 'P_TARGET_MIN', 'P_TARGET_MAX', 'P_MEAS', 'V_TARGET', 'V_MEAS', 'event')}

        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'])
        daq.sc['P_TARGET'] = 100
        daq.sc['P_TARGET_MIN'] = 100
        daq.sc['P_TARGET_MAX'] = 100
        daq.sc['V_TARGET'] = v_nom
        daq.sc['event'] = 'None'

        ts.log('DAS device: %s' % daq.info())

        '''
        b) Set all voltage trip parameters to the widest range of adjustability. Disable all reactive/active power
        control functions.
        '''
        # it is assumed the EUT is on
        eut = der.der_init(ts)
        if eut is not None:
            vw_curve_params = {'v': [v_start, v_stop], 'w': [100., 0], 'DeptRef': 'W_MAX_PCT'}
            vw_params = {'Ena': True, 'ActCrv': 1, 'curve': vw_curve_params}
            eut.volt_watt(params=vw_params)
            ts.log_debug('Initial EUT VW settings are %s' % eut.volt_watt())
        '''
        c) Set all AC test source parameters to the nominal operating voltage and frequency.
        '''

        if grid is not None:
            grid.voltage(v_nom)

        # 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)

        result_summary.write(
            'Result,Test Name,Power Level,Iteration,direction,V_target,V_actual,Power_target,Power_actual,P_min,P_max,Dataset File\n')

        '''
        d) Adjust the EUT's available active power to Prated. For an EUT with an input voltage range, set the input
        voltage to Vin_nom. The EUT may limit active power throughout the test to meet reactive power requirements.
        For an EUT with an input voltage range, repeat steps d) through o) for Vin_min and Vin_max.
        '''

        # if pv is not None:
        # TODO implement IV_curve_config
        # pv.iv_curve_config(pmp=p_rated, vpm=v_nom)
        # pv.iv_curve_config(pmp=p_rated, vpm=v_in)
        # pv.irradiance_set(1000.)
        '''
        e) Set EUT volt-watt parameters to the values specified by Characteristic 1. All other function be turned off.
        '''

        v_pairs = collections.OrderedDict()  # {}

        v_pairs[1] = {'V1': round(1.06 * v_nom, 2),
                      'V2': round(1.10 * v_nom, 2),
                      'P1': round(p_rated, 2)}

        if absorb_enable == 'Yes':
            v_pairs[1].add('P2', 0)

        else:
            if p_min > (0.2 * p_rated):
                v_pairs[1]['P2'] = int(0.2 * p_rated)
            else:
                v_pairs[1]['P2'] = int(p_min)

        '''
        f) Verify volt-var mode is reported as active and that the correct characteristic is reported.
        g) Once steady state is reached, begin the adjustment of phase voltages.
        t) Repeat steps d) through t) at EUT power set at 20% and 66% of rated power.
        u) Repeat steps d) through u) for characteristics 2 and 3.
        v) Test may be repeated for EUT's that can also absorb power using the P' values in the characteristic definition.
        '''

        """
        Test start
        """
        for imbalance_response in imbalance_resp:

            ts.log('Starting imbalance test with VW mode at %s' % (imbalance_response))

            if pv is not None:
                # TODO implement IV_curve_config
                pv.power_set(power)
                # pv_power_setting = (p_rated * power) / eff[power]
                # pv.iv_curve_config(pmp=pv_power_setting, vpm=v_in)
                # pv.irradiance_set(1000.)
                # ts.log('Set PV simulator power to {} with efficiency at {} %'.format(p_rated * power, eff[power] * 100.))

            # Configure the data acquisition system
            ts.log('Starting data capture for power = %s' % power)
            dataset_filename = 'VW_curve_%s_pwr_%0.2f.csv' % (vw_curve, power)
            daq.data_capture(True)

            ts.log_debug('curve points:  %s' % v_pairs[vw_curve])

            '''
            l) For multiphase units, step the AC test source voltage to Case A from Table 23.

                                        Table 23 - Imbalanced Voltage Test Cases 12
                    +----------------------------------------------+-----------------------------------------------+
                    | Symmetrical Components                       | Phasor Components                             |
                    +----------------------------------------------+-----------------------------------------------+
                    | Zero Sequence | Positive Seq | Negative Seq  | Phase A      | Phase B       | Phase C        |
                    | Mag | Angle   | Mag | Angle  | Mag   | Angle | Mag   | Angle| Mag   | Angle | Mag   | Angle  |
            +-------+-----+---------+-----+--------+-------+-------+-------+------+-------+-------+-------+--------+
            |Case A | 0.0 | 0.0     | 1.0 | 0.0    | 0.07  | 0     | 1.070 | 0.0  | 0.967 | 123.6 | 0.967 | -123.6 |
            +-------+-----+---------+-----+--------+-------+-------+-------+------+-------+-------+-------+--------+
            |Case B | 0.0 | 0.0     | 1.0 | 0.0    | 0.09  | 180   | 0.910 | 0.0  | 1.048 | 115.7 | 1.048 | -115.7 |
            +-------+-----+---------+-----+--------+-------+-------+-------+------+-------+-------+-------+--------+
            |Case C | 0.0 | 0.0     | 1.0 | 0.0    | 0.05  | 0     | 1.050 | 0.0  | 0.976 | 122.5 | 0.976 | -122.5 |
            +-------+-----+---------+-----+--------+-------+-------+-------+------+-------+-------+-------+--------+
            |Case D | 0.0 | 0.0     | 1.0 | 0.0    | 0.05  | 180   | 0.950 | 0.0  | 1.026 | 117.6 | 1.026 | -117.6 |
            +-------+-----+---------+-----+--------+-------+-------+-------+------+-------+-------+-------+--------+

            For tests with imbalanced, three-phase voltages, the manufacturer shall state whether the EUT responds
            to individual phase voltages, or the average of the three-phase effective (RMS) values or the positive
            sequence of voltages. For EUTs that respond to individual phase voltages, the response of each
            individual phase shall be evaluated. For EUTs that response to the average of the three-phase effective
            (RMS) values mor the positive sequence of voltages, the total three-phase reactive and active power
            shall be evaluated.
            '''

            '''
            Step i) For multiphase units, step the AC test source voltage to Case A from Table 23
            '''

            if grid is not None:
                grid.config_asymmetric_phase_angles(mag=[1.07 * v_nom, 0.967 * v_nom, 0.967 * v_nom],
                                                    angle=[0., 123.6, -123.6])
                daq.sc['event'] = 'Case A'
                ts.sleep(4 * pf_settling_time)
                daq.sc['event'] = 'T_settling_done'

                # Test result accuracy for CPF
                daq.data_sample()
                data = daq.data_capture_read()

                # Test result accuracy requirements per IEEE1547-4.2 for Q(V)
                P_V_passfail = p_v_criteria(v_pairs=v_pairs[vw_curve], a_v=a_v, p_mra=MSA_P, daq=daq,
                                            imbalance_resp=imbalance_response)

                # Test result accuracy requirements per IEEE1547-4.2 for Q(tr)
                # TODO p_tr_criteria still needs to be implemented

                ts.log('        Powers targ, min, max: %s, %s, %s' % (
                    daq.sc['P_TARGET'], daq.sc['P_TARGET_MIN'], daq.sc['P_TARGET_MAX']))

                result_summary.write('%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s \n' %
                                     (P_V_passfail, ts.config_name(), power * 100., direction, daq.sc['V_TARGET'],
                                      daq.sc['V_MEAS'], daq.sc['P_TARGET'], daq.sc['P_MEAS'], daq.sc['P_TARGET_MIN'],
                                      daq.sc['P_TARGET_MAX'], dataset_filename))

            '''
            Step j) For multiphase units, step the AC test source voltage to VN.
            '''
            if grid is not None:
                grid.voltage(v_nom)
                daq.sc['event'] = 'Step J'
                ts.sleep(4 * pf_settling_time)
                daq.sc['event'] = 'T_settling_done'

                # Test result accuracy for CPF
                daq.data_sample()
                data = daq.data_capture_read()

                # Test result accuracy requirements per IEEE1547-4.2 for Q(V)
                P_V_passfail = p_v_criteria(v_pairs=v_pairs[vw_curve], a_v=a_v, p_mra=MSA_P, daq=daq,
                                            imbalance_resp=imbalance_response)

                # Test result accuracy requirements per IEEE1547-4.2 for Q(tr)
                # TODO p_tr_criteria still needs to be implemented

                ts.log('        Powers targ, min, max: %s, %s, %s' % (
                    daq.sc['P_TARGET'], daq.sc['P_TARGET_MIN'], daq.sc['P_TARGET_MAX']))

                result_summary.write('%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s \n' %
                                     (P_V_passfail, ts.config_name(), power * 100., direction, daq.sc['V_TARGET'],
                                      daq.sc['V_MEAS'], daq.sc['P_TARGET'], daq.sc['P_MEAS'],
                                      daq.sc['P_TARGET_MIN'],
                                      daq.sc['P_TARGET_MAX'], dataset_filename))

            '''
            Step k) For multiphase units, step the AC test source voltage to Case B from Table 23
            '''

            if grid is not None:
                grid.config_asymmetric_phase_angles(mag=[0.910 * v_nom, 1.048 * v_nom, 1.048 * v_nom],
                                                    angle=[0., 115.7, -115.7])
                daq.sc['event'] = 'Case B'
                ts.sleep(4 * pf_settling_time)
                daq.sc['event'] = 'T_settling_done'

                # Test result accuracy for CPF
                daq.data_sample()
                data = daq.data_capture_read()

                # Test result accuracy requirements per IEEE1547-4.2 for Q(V)
                P_V_passfail = p_v_criteria(v_pairs=v_pairs[vw_curve], a_v=a_v, p_mra=MSA_P, daq=daq,
                                            imbalance_resp=imbalance_response)

                # Test result accuracy requirements per IEEE1547-4.2 for Q(tr)
                # TODO p_tr_criteria still needs to be implemented

                ts.log('        Powers targ, min, max: %s, %s, %s' % (
                    daq.sc['P_TARGET'], daq.sc['P_TARGET_MIN'], daq.sc['P_TARGET_MAX']))

                result_summary.write('%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s \n' %
                                     (P_V_passfail, ts.config_name(), power * 100., direction, daq.sc['V_TARGET'],
                                      daq.sc['V_MEAS'], daq.sc['P_TARGET'], daq.sc['P_MEAS'], daq.sc['P_TARGET_MIN'],
                                      daq.sc['P_TARGET_MAX'], dataset_filename))

            '''
            Step l) For multiphase units, step the AC test source voltage to VN.
            '''
            if grid is not None:
                grid.voltage(v_nom)
                daq.sc['event'] = 'Step J'
                ts.sleep(4 * pf_settling_time)
                daq.sc['event'] = 'T_settling_done'

                # Test result accuracy for CPF
                daq.data_sample()
                data = daq.data_capture_read()

                # Test result accuracy requirements per IEEE1547-4.2 for Q(V)
                P_V_passfail = p_v_criteria(v_pairs=v_pairs[vw_curve], a_v=a_v, p_mra=MSA_P, daq=daq,
                                            imbalance_resp=imbalance_response)

                # Test result accuracy requirements per IEEE1547-4.2 for Q(tr)
                # TODO p_tr_criteria still needs to be implemented

                ts.log('        Powers targ, min, max: %s, %s, %s' % (
                    daq.sc['P_TARGET'], daq.sc['P_TARGET_MIN'], daq.sc['P_TARGET_MAX']))

                result_summary.write('%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s \n' %
                                     (P_V_passfail, ts.config_name(), power * 100., direction, daq.sc['V_TARGET'],
                                      daq.sc['V_MEAS'], daq.sc['P_TARGET'], daq.sc['P_MEAS'],
                                      daq.sc['P_TARGET_MIN'],
                                      daq.sc['P_TARGET_MAX'], dataset_filename))

        # create result workbook

        ts.log('Sampling complete')
        daq.data_capture(False)
        ds = daq.data_capture_dataset()
        ts.log('Saving file: %s' % dataset_filename)
        ds.to_csv(ts.result_file_path(dataset_filename))
        result_params['plot.title'] = os.path.splitext(dataset_filename)[0]
        ts.result_file(dataset_filename, params=result_params)
        result = script.RESULT_COMPLETE

        return result

    except script.ScriptFail, e:
        reason = str(e)
        if reason:
            ts.log_error(reason)
예제 #21
0
def test_run():
    eut = None
    chil = None
    grid = None
    pv = None

    try:

        # Initialize DER configuration
        eut = der.der_init(ts)
        eut.config()

        # Initialize CHIL environment, if necessary
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()

        # PV simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        pv.irradiance_set(1000)
        pv.power_on()

        # grid simulator is initialized with test parameters and enabled
        grid = gridsim.gridsim_init(ts)

        # Get EUT nameplate power
        eut_nameplate_power = eut.nameplate().get('WRtg')

        inv_power = eut.measurements().get('W')
        timeout = 20.
        if inv_power <= eut_nameplate_power / 10.:
            eut.connect(params={'Conn': True})
            pv.irradiance_set(995)  # Perturb the pv slightly to start the inverter
        while inv_power <= eut_nameplate_power / 10. and timeout >= 0:
            ts.log('Inverter power is at %0.1f. Waiting %s more seconds or until EUT starts...' % (inv_power, timeout))
            ts.sleep(1)
            timeout -= 1
            inv_power = eut.measurements().get('W')
            if timeout == 0:
                result = script.RESULT_FAIL
                raise der.DERError('Inverter did not start.')

        fw_mode = 'Pointwise'
        if fw_mode == 'Parameters':
            eut.freq_watt_param(params={'HysEna': False, 'HzStr': 50.2,
                                        'HzStop': 51.5, 'WGra': 140.})
        else:  # Pointwise
            eut.freq_watt(params={'ActCrv': 1})
            f_points = [50, 50.2, 51.5, 53]
            p_points = [100, 100, 0, 0]
            parameters = {'hz': f_points, 'w': p_points}
            # ts.log_debug(parameters)
            eut.freq_watt_curve(id=1, params=parameters)
            eut.freq_watt(params={'Ena': True})
            ts.log_debug(eut.freq_watt())

        # Create list of frequencies to iterate over
        freq_values = list(np.linspace(49.5, 53, num=50))
        sleep_time = 1.0
        for freq in freq_values:
            grid.freq(freq)  # set grid frequency
            ts.log('      f = %0.3f Hz. Sleeping for %0.2f seconds...' % (freq, sleep_time))
            ts.sleep(sleep_time)

        # Disable the FW function
        eut.freq_watt(params={'Ena': False})
        ts.log('FW Disabled')

        result = script.RESULT_COMPLETE

    except Exception, e:
        ts.log_error('Script failure: %s' % e)
예제 #22
0
def test_run():

    result = script.RESULT_FAIL
    eut = grid = load = pv = daq_rms = daq_wf = chil = None

    ### Correction as graph is not displayed
    ### <START>
    ###    sc_points = ['AC_IRMS_MIN']
    sc_points = ['TIME', 'AC_VRMS_1', 'AC_IRMS_1', 'SC_TRIG', 'AC_IRMS_MIN']
    ### <END>

    # result params
    result_params = {
        'plot.title': ts.name,
        'plot.x.title': 'Time (secs)',
        'plot.x.points': 'TIME',
        'plot.y.points': 'AC_VRMS_1',
        'plot.y.title': 'Voltage (V)',
        'plot.y2.points': 'AC_IRMS_1, AC_IRMS_MIN',
        'plot.y2.title': 'Current (A)'
    }

    try:
        test_label = ts.param_value('vrt.test_label')
        # get test parameters
        phases = ts.param_value('eut.phases')
        p_rated = ts.param_value('eut.p_rated')
        v_nom = ts.param_value('eut.v_nom')
        v_msa = ts.param_value('eut.v_msa')
        t_msa = ts.param_value('eut.t_msa')
        t_dwell = ts.param_value('eut.vrt_t_dwell')
        v_grid_min = ts.param_value('vrt.v_grid_min')
        v_grid_max = ts.param_value('vrt.v_grid_max')
        v_test = ts.param_value('vrt.v_test')
        t_hold = ts.param_value('vrt.t_hold')
        n_r = ts.param_value('vrt.n_r')

        # calculate voltage adjustment based on msa
        v_msa_adj = v_msa * 1.5
        if v_test > 100.0:
            # apply HVRT msa adjustments
            v_n = v_grid_min + v_msa_adj
            v_t = v_test - v_msa_adj
        else:
            # apply LVRT msa adjustments
            v_n = v_grid_max - v_msa_adj
            v_t = v_test + v_msa_adj

        # set power levels that are enabled
        power_levels = []
        if ts.param_value('vrt.p_100') == 'Enabled':
            power_levels.append((100.0, '100'))
        if ts.param_value('vrt.p_20') == 'Enabled':
            power_levels.append((20.0, '20'))

        # set phase tests that are enabled
        phase_tests = []
        # set single phase test voltages and test labels
        if phases == 'Single Phase':
            phase_tests.append(((v_t, v_n, v_n), 'Phase 1 Fault Test', 'p1'))
        # set 3-phase 3-wire/4-wire voltages and test label for each enabled test
        #??? calculation of 3/4 wire phase test levels
        if phases == '3-Phase 3-Wire' or phases == '3-Phase 4-Wire':
            if ts.param_value('vrt.phase_all') == 'Enabled':
                phase_tests.append(
                    ((v_t, v_t, v_t), 'All Phase Fault Test', 'all'))
            if ts.param_value('vrt.phase_1') == 'Enabled':
                phase_tests.append(
                    ((v_t, v_n, v_n), 'Phase 1 Fault Test', 'p1'))
            if ts.param_value('vrt.phase_2') == 'Enabled':
                phase_tests.append(
                    ((v_n, v_t, v_n), 'Phase 2 Fault Test', 'p2'))
            if ts.param_value('vrt.phase_3') == 'Enabled':
                phase_tests.append(
                    ((v_n, v_n, v_t), 'Phase 3 Fault Test', 'p3'))
            if phases == '3-Phase 4-Wire':
                if ts.param_value('vrt.phase_1_2') == 'Enabled':
                    phase_tests.append(
                        ((v_t, v_t, v_n), 'Phase 1-2 Fault Test', 'p12'))
                if ts.param_value('vrt.phase_2_3') == 'Enabled':
                    phase_tests.append(
                        ((v_n, v_t, v_t), 'Phase 2-3 Fault Test', 'p23'))
                if ts.param_value('vrt.phase_1_3') == 'Enabled':
                    phase_tests.append(
                        ((v_t, v_n, v_t), 'Phase 1-3 Fault Test', 'p13'))

        # 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)
        profile_supported = False

        # 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

        # load simulator initialization
        load = loadsim.loadsim_init(ts)
        if load is not None:
            ts.log('Load device: %s' % load.info())

        # pv simulator is initialized with test parameters and enabled
###        pv = pvsim.pvsim_init(ts)
###        pv.power_set(p_rated)
###        pv.power_on()

# initialize rms data acquisition
        daq_rms = das.das_init(ts, 'das_rms', sc_points=sc_points)
        if daq_rms is not None:
            ts.log('DAS RMS device: %s' % (daq_rms.info()))
###            daq_rms.sc['SC_TRIG'] = 0
###            daq_rms.sc['AC_IRMS_MIN'] = ''

# initialize waveform data acquisition
        daq_wf = das.das_init(ts, 'das_wf')
        if daq_wf is not None:
            ts.log('DAS Waveform device: %s' % (daq_wf.info()))

        # it is assumed the EUT is on
        eut = der.der_init(ts)
        if eut is not None:
            eut.config()

        # 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)
        result_summary.write('Result, Test Name, Power Level, Phase, Dataset File\n')
        '''

        # perform all power levels and phase tests
        for power_level in power_levels:
            # set test power level
            power = power_level[0] / 100 * p_rated
            ###            pv.power_set(power)
            grid.power_set(power)
            ts.log('Setting power level to %s%% of rated' % (power_level[0]))
            '''
            # initializing to nominal
            v = v_nom_grid
###            grid.voltage((v, v, v))
            grid.voltageRH(v, v, v)
            ts.log('Initializing to nominal voltage: v_1 = %s  v_2 = %s  v_3 = %s for %s seconds' % (v, v, v,
                                                                                                     t_dwell))
            ts.sleep(t_dwell)
            '''

            for phase_test in phase_tests:
                if daq_rms is not None:
                    ###                    daq_rms.sc['AC_IRMS_MIN'] = ''
                    data = grid.wt3000_data_capture_read(
                    )  # <- Since the graph is not displayed, it is added
                    daq_rms.sc['TIME'] = time.time(
                    )  # <- Since the graph is not displayed, it is added
                    daq_rms.sc['AC_VRMS_1'] = data.get(
                        'AC_VRMS_1'
                    )  # <- Since the graph is not displayed, it is added
                    daq_rms.sc['AC_IRMS_1'] = data.get(
                        'AC_IRMS_1'
                    )  # <- Since the graph is not displayed, it is added
                    daq_rms.sc[
                        'SC_TRIG'] = ''  # <- Since the graph is not displayed, it is added
                    irms = data.get(
                        'AC_IRMS_1'
                    )  # <- Since the graph is not displayed, it is added
                    daq_rms.sc['AC_IRMS_MIN'] = round(
                        irms * .8,
                        2)  # <- Since the graph is not displayed, it is added
                    ts.log('Starting RMS data capture')
                    daq_rms.data_capture(True)
                    ts.log('Waiting 5 seconds to start test')
                    ts.sleep(5)
                v_1, v_2, v_3 = phase_test[0]
                ts.log('Starting %s, v1 = %s%%  v2 = %s%%  v3 = %s%%' %
                       (phase_test[1], v_1, v_2, v_3))
                if profile_supported:
                    # create and execute test profile
                    profile = voltage_rt_profile(v1_t=v_1,
                                                 v2_t=v_2,
                                                 v3_t=v_3,
                                                 t_hold=t_hold,
                                                 t_dwell=t_dwell,
                                                 n=n_r)
                    grid.profile_load(profile=profile)
                    grid.profile_start()
                    # create 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)
                        sleep_time = min(remaining_time, 10)
                        ts.sleep(sleep_time)
                    grid.profile_stop()
                else:
                    # execute test sequence
                    ts.log('Test duration is %s seconds' %
                           ((float(t_dwell) + float(t_hold)) * float(n_r) +
                            float(t_dwell)))

                    # get initial current level to determine threshold
                    if daq_rms is not None:
                        daq_rms.data_sample()
                        ###                        data = daq_rms.data_capture_read()
                        data = grid.wt3000_data_capture_read(
                        )  # <- Since the graph is not displayed, it is added
                        irms = data.get('AC_IRMS_1')
                        if irms is not None:
                            daq_rms.sc['TIME'] = time.time(
                            )  # <- Since the graph is not displayed, it is added
                            daq_rms.sc['AC_VRMS_1'] = data.get(
                                'AC_VRMS_1'
                            )  # <- Since the graph is not displayed, it is added
                            daq_rms.sc['AC_IRMS_1'] = data.get(
                                'AC_IRMS_1'
                            )  # <- Since the graph is not displayed, it is added
                            daq_rms.sc[
                                'SC_TRIG'] = ''  # <- Since the graph is not displayed, it is added
                            daq_rms.sc['AC_IRMS_MIN'] = round(irms * .8, 2)

                    ts.sleep(t_hold)
                    for i in range(n_r):
                        v = (v_n / 100) * v_nom_grid
                        v1 = (v_1 / 100) * v_nom_grid
                        v2 = (v_2 / 100) * v_nom_grid
                        v3 = (v_3 / 100) * v_nom_grid

                        ###                        grid.voltage((v, v, v))
                        grid.voltageRH(v, v, v)
                        ts.log(
                            'Setting voltage: v_1 = %s  v_2 = %s  v_3 = %s for %s seconds'
                            % (v, v, v, t_dwell))
                        ts.sleep(t_dwell)
                        ###                        grid.voltage((v1, v2, v3))
                        grid.voltageRH(v1, v2, v3)
                        ts.log(
                            'Setting voltage: v_1 = %s  v_2 = %s  v_3 = %s for %s seconds'
                            % (v1, v2, v3, t_hold))
                        ts.sleep(t_hold)
###                    grid.voltage((v, v, v))
                    grid.voltageRH(v, v, v)
                    ts.log(
                        'Setting voltage: v_1 = %s  v_2 = %s  v_3 = %s for %s seconds'
                        % (v, v, v, t_dwell))
                    ts.sleep(t_dwell)
                if daq_rms is not None:
                    daq_rms.data_capture(False)
                    ds = daq_rms.data_capture_dataset()
                    test_name = '%s_rms_%s_%s' % (test_label, phase_test[2],
                                                  power_level[1])
                    filename = '%s.csv' % (test_name)
                    ds.to_csv(ts.result_file_path(filename))
                    result_params['plot.title'] = test_name
                    ts.result_file(filename, params=result_params)
                    ts.log('Saving data capture %s' % (filename))

        result = script.RESULT_COMPLETE
예제 #23
0
def test_run():
    result = script.RESULT_FAIL
    grid = None
    pv = p_rated = None
    daq = None
    eut = None
    rs = None
    phil = None
    result_summary = None
    step = None
    q_initial = None
    dataset_filename = None

    try:
        sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        p_rated_prime = ts.param_value('eut.p_rated_prime')
        s_rated = ts.param_value('eut.s_rated')
        var_rated = ts.param_value('eut.var_rated')

        # DC voltages
        v_nom_in_enabled = ts.param_value('cpf.v_in_nom')
        v_min_in_enabled = ts.param_value('cpf.v_in_min')
        v_max_in_enabled = ts.param_value('cpf.v_in_max')

        v_nom_in = ts.param_value('eut.v_in_nom')
        v_min_in = ts.param_value('eut_cpf.v_in_min')
        v_max_in = ts.param_value('eut_cpf.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_min = ts.param_value('eut.v_low')
        v_max = ts.param_value('eut.v_high')
        f_nom = ts.param_value('eut.f_nom')
        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')

        low_pwr_ena = ts.param_value('vrt.low_pwr_ena')
        high_pwr_ena = ts.param_value('vrt.high_pwr_ena')
        low_pwr_value = ts.param_value('vrt.low_pwr_value')
        high_pwr_value = ts.param_value('vrt.high_pwr_value')

        # Pass/fail accuracies
        pf_msa = ts.param_value('eut.pf_msa')

        # EUI Absorb capabilities
        absorb = {}
        absorb['ena'] = ts.param_value('eut_cpf.sink_power')
        absorb['p_rated_prime'] = ts.param_value('eut_cpf.p_rated_prime')
        absorb['p_min_prime'] = ts.param_value('eut_cpf.p_min_prime')

        # Following parameters are collected in p1547.VoltageRideThrough.set_vrt_params in init:
        # vrt.lv_ena, vrt.hv_ena, vrt.consecutive_ena, vrt.cat, vrt.range_steps
        consecutive_ena = ts.param_value('vrt.consecutive_ena')
        if consecutive_ena == "Enabled":
            consecutive_label = "CE"
        else:
            consecutive_label = "CD"

        phase_comb_list = []

        if ts.param_value('vrt.one_phase_mode') == "Enabled":
            phase_comb_list.append([ts.param_value('vrt.one_phase_value')])
        
        if ts.param_value('vrt.two_phase_mode') == "Enabled":
            phase_comb_list.append([ts.param_value('vrt.two_phase_value_1'),ts.param_value('vrt.two_phase_value_2')])

        if ts.param_value('vrt.three_phase_mode') == "Enabled":
            phase_comb_list.append(['A', 'B', 'C'])

        # Functions to be enabled for test
        mode = []
        pwr_lvl = []
        steps_dict = {}
        timestep_dict = {}
        sequence_dict = {}
        parameters = []

        # initialize HIL environment, if necessary
        ts.log_debug(15 * "*" + "HIL initialization" + 15 * "*")

        phil = hil.hil_init(ts)
        if phil is not None:
            # return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name)
            open_proj = phil._param_value('hil_config_open')
            compilation = phil._param_value('hil_config_compile')
            stop_sim = phil._param_value('hil_config_stop_sim')
            load = phil._param_value('hil_config_load')
            execute = phil._param_value('hil_config_execute')
            model_name = phil._param_value('hil_config_model_name')
            phil.config()

        ''' RTLab OpWriteFile Math using worst case scenario of 160 seconds, 14 signals and Ts = 40e-6
        Duration of acquisition in number of points: Npoints = (Tend-Tstart)/(Ts*dec) = (350)/(0.000040*25) = 1350e3
        
        Acquisition frame duration: Tframe = Nbss * Ts * dec = 1000*0.000040*250 = 10 sec
        
        Number of buffers to be acquired: Nbuffers = Npoints / Nbss = (Tend - Tstart) / Tframe = 16
        
        Minimum file size: MinSize= Nbuffers x SizeBuf = [(Tend - Tstart) / Ts ] * (Nsig+1) * 8 * Nbss 
            = (160/40e-6)*(14+1)*8*1000 = 4.8e11
        
        SizeBuf = 1/Nbuffers * {[(Tend - Tstart) / Ts ]*(Nsig+1)*8*Nbss} = [(160/0.000040)*(14+1)*8*1e3]/16 = 30e9
        Size of one buffer in bytes (SizeBuf) = (Nsig+1) * 8 * Nbss (Minimum) = (14+1)*8*1000 = 120e3
        '''

        if low_pwr_ena == 'Enabled':
            pwr_lvl.append(low_pwr_value)
        else:
            ts.log_debug('No low power chosen')
        if high_pwr_ena == 'Enabled':
            pwr_lvl.append(high_pwr_value)
        else:
            ts.log_debug('No high power chosen')
        if high_pwr_ena == 'Disabled' and low_pwr_ena == 'Disabled':
            ts.log_error('No power tests included in VRT test!')

        if ts.param_value('vrt.wav_ena') == "Yes" :
            wav_ena = True
        else :
            wav_ena = False
        if ts.param_value('vrt.data_ena') == "Yes" :
            data_ena = True
        else :
            data_ena = False
        """
        Configure settings in 1547.1 Standard module for the Voltage Ride Through Tests
        """
        VoltRideThrough = p1547.VoltageRideThrough(ts=ts, support_interfaces={"hil": phil})
        # result params
        # result_params = lib_1547.get_rslt_param_plot()
        # ts.log(result_params

        # grid simulator is initialized with test parameters and enabled
        ts.log_debug(15 * "*" + "Gridsim initialization" + 15 * "*")
        grid = gridsim.gridsim_init(ts, support_interfaces={"hil": phil})  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)  

        # pv simulator is initialized with test parameters and enabled
        ts.log_debug(15 * "*" + "PVsim initialization" + 15 * "*")
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized

        # initialize data acquisition
        ts.log_debug(15 * "*" + "DAS initialization" + 15 * "*")
        daq = das.das_init(ts, support_interfaces={"hil": phil, "pvsim": pv})
        daq.waveform_config({"mat_file_name":"Data.mat",
                            "wfm_channels": VoltRideThrough.get_wfm_file_header()})

        if daq is not None:
            daq.sc['V_MEAS'] = 100
            """
            daq.sc['P_MEAS'] = 100
            daq.sc['Q_MEAS'] = 100
            daq.sc['Q_TARGET_MIN'] = 100
            daq.sc['Q_TARGET_MAX'] = 100
            daq.sc['PF_TARGET'] = 1
            daq.sc['event'] = 'None'
            ts.log('DAS device: %s' % daq.info())
            """

        """
        This test doesn't have specific procedure steps. 
        """

        # 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)
        result_summary.write('Test Name, Waveform File, RMS File\n')

        """
        During the LVRT test, the settings for magnitude and duration of undervoltage tripping functions shall be
        disabled or set so as not to influence the outcome of the test. 
        
        If the EUT provides a voltage-active power control mode, that mode shall be disabled. 
        
        Connect the EUT according to the instructions and specifications provided by the manufacturer.
        """
        # Wait to establish communications with the EUT after AC and DC power are provided
        eut = der.der_init(ts, support_interfaces={'hil': phil}) 

        # start = time.time()
        # comm_wait_time = max(0.0, startup_time - 60.)
        # while time.time()-start < comm_wait_time - 1:
        #     ts.sleep(1)
        #     ts.log('Waiting another %0.2f seconds until communicating with EUT' %
        #            (comm_wait_time - (time.time()-start)))

        if eut is not None:
            eut.config()
            
        # if eut is not None:
        #     eut.deactivate_all_fct()

    

        # Initial loop for all mode that will be executed
        modes = VoltRideThrough.get_modes()  # Options: LV_CAT_2, HV_CAT_2, LV_CAT_3, HV_CAT_3
        ts.log(f"VRT modes tested : '{modes}'")
        ts.log(f"VRT power level tested : '{pwr_lvl}'")
        ts.log(f"VRT phase combination tested : '{phase_comb_list}'")
        for current_mode in modes:
            # Configuring waveform timing blocks with offset in seconds
            # daq.waveform_config(vrt_lib_1547.get_waveform_config(current_mode,offset=5))
            """
            The ride-through tests shall be performed at two output power levels, high and low, and at any convenient
            power factor greater than 0.90. The output power levels shall be measured prior to the disturbance, i.e., in
            test condition A. High-power tests shall be performed at any active power level greater than 90% of the
            EUT nameplate active power rating at nominal voltage. ... Low-power tests shall be performed at any 
            convenient power level between 25% to 50% of EUT nameplate  apparent power rating at nominal voltage.
            """
            for pwr in pwr_lvl:  
                for phase in phase_comb_list :  
             
                    phase_combination_label = "PH" + ''.join(phase)

                    dataset_filename = f'{current_mode}_{round(pwr*100)}PCT_{phase_combination_label}_{consecutive_label}'
                    ts.log_debug(15 * "*" + f"Starting {dataset_filename}" + 15 * "*")
                    if data_ena:
                        daq.data_capture(True)

                    """
                    Setting up available power to appropriate power level 
                    """
                    if pv is not None:
                        ts.log_debug(f'Setting power level to {pwr}')
                        pv.iv_curve_config(pmp=p_rated, vmp=v_nom_in)
                        pv.irradiance_set(1000.)
                        pv.power_set(p_rated * pwr)
                        
                    """
                    Initiating voltage sequence for VRT
                    """
                    vrt_test_sequences = VoltRideThrough.set_test_conditions(current_mode)
                    VoltRideThrough.set_phase_combination(phase)
                    vrt_stop_time = VoltRideThrough.get_vrt_stop_time(vrt_test_sequences)
                    if phil is not None:
                        # Set model parameters
                        #phil.set_parameters(vrt_parameters)
                        # This adds 5 seconds of nominal behavior for EUT normal shutdown. This 5 sec is not recorded.
                        vrt_stop_time = vrt_stop_time + 5
                        ts.log('Stop time set to %s' % phil.set_stop_time(vrt_stop_time))
                        # The driver should take care of this by selecting "Yes" to "Load the model to target?"
                        ts.sleep(2.0)
                        phil.load_model_on_hil()
                        # You need to first load the model, then configure the parameters
                        # Now that we have all the test_sequences its time to sent them to the model.
                        VoltRideThrough.set_vrt_model_parameters(vrt_test_sequences)
                                        
                        """
                        The voltage-reactive power control mode of the EUT shall be set to the default settings specified in Table 8
                        of IEEE Std 1547-2018 for the applicable performance category, and enabled.
                        """
                        # Default curve is characteristic curve 1
                        vv_curve = 1
                        ActiveFunction = p1547.ActiveFunction(ts=ts,
                                                            script_name='Volt-Var',
                                                            functions=[VV],
                                                            criteria_mode=[True, True, True])
                        # Don't need to be set to imbalance mode
                        #ActiveFunction.set_imbalance_config(imbalance_angle_fix="std")
                        #ActiveFunction.reset_curve(vv_curve)
                        #ActiveFunction.reset_time_settings(tr=10, number_tr=2)
                        v_pairs = ActiveFunction.get_params(function=VV, curve=vv_curve)
                        ts.log_debug('v_pairs:%s' % v_pairs)
                        if eut is not None:
                            # Set to: V = {92, 98, 102, 108}, Var = {44, 0 , 0 , -44}
                            vv_curve_params = {'v': [round(v_pairs['V1']/v_nom,2),
                                                    round(v_pairs['V2']/v_nom,2),
                                                    round(v_pairs['V3']/v_nom,2),
                                                    round(v_pairs['V4']/v_nom,2)],
                                            'var': [round(v_pairs['Q1']/p_rated,2),
                                                    round(v_pairs['Q2']/p_rated,2),
                                                    round(v_pairs['Q3']/p_rated,2),
                                                    round(v_pairs['Q4']/p_rated,2)],
                                            'vref': 1.0,
                                            'RmpPtTms': 1.0}
                            ts.log_debug('Setting VV points: %s' % vv_curve_params)
                            eut.volt_var(params={'Ena': True, 'ACTCRV': vv_curve, 'curve': vv_curve_params})
                            ts.log_debug('Initial EUT VV settings are %s' % eut.volt_var())

                        # The driver parameter "Execute the model on target?" should be set to "No"
                        phil.start_simulation() 
                        ts.sleep(0.5)
                        sim_time = phil.get_time()
                        while (vrt_stop_time - sim_time) > 1.0:  # final sleep will get to stop_time.
                            sim_time = phil.get_time()
                            ts.log('Sim Time: %0.3f.  Waiting another %0.3f sec before saving data.' % (
                                sim_time, vrt_stop_time - sim_time))
                            ts.sleep(5)

                    
                        rms_dataset_filename = "No File"   
                        wave_start_filename = "No File"        
                        if data_ena:
                            rms_dataset_filename = dataset_filename + "_RMS.csv"
                            daq.data_capture(False)

                            # complete data capture
                            ts.log('Waiting for Opal to save the waveform data: {}'.format(dataset_filename))
                            ts.sleep(10)
                        if wav_ena:
                            # Convert and save the .mat file 
                            ts.log('Processing waveform dataset(s)')
                            wave_start_filename = dataset_filename + "_WAV.csv"

                            ds = daq.waveform_capture_dataset()  # returns list of databases of waveforms (overloaded)
                            ts.log(f'Number of waveforms to save {len(ds)}')
                            if len(ds) > 0:
                                ds[0].to_csv(ts.result_file_path(wave_start_filename))
                                ts.result_file(wave_start_filename)

                        if data_ena:
                            ds = daq.data_capture_dataset()
                            ts.log('Saving file: %s' % rms_dataset_filename)
                            ds.to_csv(ts.result_file_path(rms_dataset_filename))
                            ds.remove_none_row(ts.result_file_path(rms_dataset_filename), "TIME")
                            result_params = {
                                'plot.title': rms_dataset_filename.split('.csv')[0],
                                'plot.x.title': 'Time (sec)',
                                'plot.x.points': 'TIME',
                                'plot.y.points': 'AC_VRMS_1, AC_VRMS_2, AC_VRMS_3',
                                'plot.y.title': 'Voltage (V)',
                                'plot.y2.points': 'AC_IRMS_1, AC_IRMS_2, AC_IRMS_3',
                                'plot.y2.title': 'Current (A)',
                            }
                            ts.result_file(rms_dataset_filename, params=result_params)
                        result_summary.write('%s, %s, %s,\n' % (dataset_filename, wave_start_filename,
                                                                rms_dataset_filename))

                        phil.stop_simulation()

                  

        result = script.RESULT_COMPLETE

    except script.ScriptFail as e:
        reason = str(e)
        if reason:
            ts.log_error(reason)

    except Exception as e:
        ts.log_error((e, traceback.format_exc()))

        ts.log_error('Test script exception: %s' % traceback.format_exc())

    finally:
        if grid is not None:
            grid.close()
        if pv is not None:
            if p_rated is not None:
                pv.power_set(p_rated)
            pv.close()
        if daq is not None:
            daq.close()
        if eut is not None:
            # eut.fixed_pf(params={'Ena': False, 'PF': 1.0})
            eut.close()
        if rs is not None:
            rs.close()
        if phil is not None:
            if phil.model_state() == 'Model Running':
                phil.stop_simulation()
            phil.close()

        if result_summary is not None:
            result_summary.close()

        # create result workbook
        excelfile = ts.config_name() + '.xlsx'
        rslt.result_workbook(excelfile, ts.results_dir(), ts.result_dir())
        ts.result_file(excelfile)

    return result
예제 #24
0
def test_run():

    result = script.RESULT_FAIL
    # Variables use in script
    daq = None
    data = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None
    dataset_filename = None
    fw_curves = []
    fw_response_time = [0, 0, 0]
    f_steps_dic = {}

    try:
        """
        Test Configuration
        """
        # Get all test script parameter
        mode = ts.param_value("fw.mode")
        eut_absorb = ts.param_value("eut_fw.absorb")
        """
        A separate module has been create for the 1547.1 Standard
        """
        lib_1547 = p1547.module_1547(ts=ts, aif='FW')
        ts.log_debug("1547.1 Library configured for %s" %
                     lib_1547.get_test_name())

        if eut_absorb == "Yes":
            absorb_powers = [False, True]
        else:
            absorb_powers = [False]
        p_rated = ts.param_value('eut.p_rated')
        s_rated = ts.param_value('eut.s_rated')
        # DC voltages
        v_nom_in = ts.param_value('eut.v_in_nom')
        irr = ts.param_value('fw.power_lvl')
        if mode == 'Above':
            if irr == 'All':
                pwr_lvls = [1., 0.66, 0.2]
            elif irr == '100%':
                pwr_lvls = [1.]
            elif irr == '66%':
                pwr_lvls = [0.66]
            elif irr == '20%':
                pwr_lvls = [0.2]
        else:
            pwr_lvls = [1.]
        # AC voltages
        f_nom = ts.param_value('eut.f_nom')
        f_min = ts.param_value('eut.f_min')
        f_max = ts.param_value('eut.f_max')
        p_min = ts.param_value('eut.p_min')
        phases = ts.param_value('eut.phases')
        # EUI FW parameters
        absorb_enable = ts.param_value('eut_fw.sink_power')
        p_rated_prime = ts.param_value('eut_fw.p_rated_prime')
        p_min_prime = ts.param_value('eut_fw.p_min_prime')
        p_small = ts.param_value('eut_fw.p_small')

        if ts.param_value('fw.test_1') == 'Enabled':
            fw_curves.append(1)
            fw_response_time[1] = float(ts.param_value('fw.test_1_tr'))
        if ts.param_value('fw.test_2') == 'Enabled':
            fw_curves.append(2)
            fw_response_time[2] = float(ts.param_value('fw.test_2_tr'))
        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''
        # initialize HIL environment, if necessary
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()

        # DAS soft channels
        # TODO : add to library 1547
        #das_points = {'sc': ('P_TARGET', 'P_TARGET_MIN', 'P_TARGET_MAX', 'P_MEAS', 'F_TARGET', 'F_MEAS', 'event')}
        das_points = lib_1547.get_sc_points()
        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'])
        if daq is not None:
            daq.sc['P_TARGET'] = 100
            daq.sc['P_TARGET_MIN'] = 100
            daq.sc['P_TARGET_MAX'] = 100
            daq.sc['P_MEAS'] = 100
            daq.sc['F_TARGET'] = f_nom
            daq.sc['P_TARGET'] = p_rated
            daq.sc['event'] = 'None'
            ts.log('DAS device: %s' % daq.info())

        # Configure the EUT communications
        eut = der.der_init(ts)
        '''
        b) Set all frequency trip parameters to the widest range of adjustability. 
            Disable all reactive/active power control functions.
        '''
        if eut is not None:
            eut.config()
            #eut.deactivate_all_fct(act_fct='FW')
            ts.log_debug(eut.measurements())
            ts.log_debug(
                'L/HFRT and trip parameters set to the widest range : f_min:{0} Hz, f_max:{1} Hz'
                .format(f_min, f_max))
            eut_response = eut.frt_stay_connected_high(
                params={
                    'Ena': True,
                    'ActCrv': 0,
                    'Tms1': 3000,
                    'Hz1': f_max,
                    'Tms2': 160,
                    'Hz2': f_max
                })
            ts.log_debug(
                'HFRT and trip parameters from EUT : {}'.format(eut_response))
            eut_response = eut.frt_stay_connected_low(
                params={
                    'Ena': True,
                    'ActCrv': 0,
                    'Tms1': 3000,
                    'Hz1': f_min,
                    'Tms2': 160,
                    'Hz2': f_min
                })
            ts.log_debug(
                'LFRT and trip parameters from EUT : {}'.format(eut_response))

        else:
            ts.log_debug(
                'Set L/HFRT and trip parameters to the widest range of adjustability possible.'
            )
        '''
        c) Set all AC test source parameters to the nominal operating voltage and frequency 
        '''
        grid = gridsim.gridsim_init(ts)
        if grid is not None:
            grid.freq(f_nom)
            if mode == 'Below':
                # 1547.1 :  Frequency is ramped at the ROCOF for the category of the EUT.
                #           In this case the ROCOF is based on table 21 of 1547.2018
                #           (Category III is use because of table B.1 of 1547.2018)
                #           The ROCOF unit : Hz/s
                ts.log('Set Grid simulator ROCOF to 3 Hz/s')
                grid.rocof(3.0)

        # result params
        result_params = lib_1547.get_rslt_param_plot()

        # 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)
        result_summary.write(lib_1547.get_rslt_sum_col_name())
        '''
        above_d) Adjust the EUT's available active power to Prated .
        below_d) ""         ""          "". Set the EUT's output power to 50% of P rated .
        '''
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.iv_curve_config(pmp=p_rated, vmp=v_nom_in)
            pv.irradiance_set(1000.)
        if mode == 'Below':
            if eut is not None:
                ts.log_debug(
                    "In Below mode, EUT's output power is set to 50%% of %s (Prated)"
                    % p_rated)
                eut.limit_max_power(params={
                    'MaxLimWEna': True,
                    'MaxLimW_PCT': 50
                })
        """
        Test start
        """
        '''
        above_r) For EUT's that can absorb power, rerun Characteristic 1 allowing the unit to absorb power by
        programing a negative Pmin . 

        below_p) ""                 ""                  "". Set the unit to absorb power at -50% of P rated . 
        '''
        for absorb_power in absorb_powers:
            if absorb_power:
                if eut is not None:
                    if mode == 'Below':
                        ts.log_debug(
                            "Config EUT's absorb power at -50%% of P rated")
                        eut.limit_max_power(
                            params={
                                'MaxLimWEna': True,
                                'MaxLimW_PCT': 50
                                #'MaxLimW': round(p_rated / 2.0, 2) * -1
                            })
                    else:
                        ts.log_debug(
                            "Config EUT's absorb power to %s (P\'min)" %
                            p_min_prime)
                        eut.limit_max_power(params={
                            'MaxLimWEna': True,
                            'MaxLimW': p_min_prime
                        })
            '''
              above_q) Repeat steps b) through p) for Characteristic 2. 

              below_o) ""           ""              ""
            '''
            for fw_curve in fw_curves:
                ts.log('Starting test with characteristic curve %s' %
                       (fw_curve))
                fw_param = lib_1547.get_params(curve=fw_curve)
                a_f = lib_1547.MRA_F * 1.5

                lib_1547.set_step_label(starting_label='G')
                f_steps_dic[mode] = collections.OrderedDict()
                if mode == 'Above':  # 1547.1 (5.15.2.2):
                    f_steps_dic[mode][lib_1547.get_step_label()] = (
                        f_nom + fw_param['dbf']) + a_f
                    f_steps_dic[mode][lib_1547.get_step_label()] = (
                        f_nom + fw_param['dbf']) - a_f
                    f_steps_dic[mode][lib_1547.get_step_label()] = (
                        f_nom + fw_param['dbf']) + a_f
                    f_steps_dic[mode][lib_1547.get_step_label(
                    )] = fw_param['f_small'] + f_nom + fw_param['dbf']
                    # STD_CHANGE : step k) should consider the accuracy
                    f_steps_dic[mode][lib_1547.get_step_label()] = f_max - a_f
                    f_steps_dic[mode][lib_1547.get_step_label(
                    )] = f_max - fw_param['f_small']
                    f_steps_dic[mode][lib_1547.get_step_label()] = (
                        f_nom + fw_param['dbf']) + a_f
                    f_steps_dic[mode][lib_1547.get_step_label()] = (
                        f_nom + fw_param['dbf']) - a_f
                    f_steps_dic[mode][lib_1547.get_step_label()] = f_nom

                    for step, frequency in f_steps_dic[mode].iteritems():
                        f_steps_dic[mode].update(
                            {step: np.around(frequency, 3)})
                        if frequency > f_max:
                            ts.log(
                                "{0} frequency step (value : {1}) changed to fH (f_max)"
                                .format(step, frequency))
                            f_steps_dic[mode].update({step: f_max})

                elif mode == 'Below':  # 1547.1 (5.15.3.2):
                    f_steps_dic[mode][lib_1547.get_step_label()] = (
                        f_nom + fw_param['dbf']) - a_f
                    f_steps_dic[mode][lib_1547.get_step_label()] = (
                        f_nom - fw_param['dbf']) - a_f
                    f_steps_dic[mode][lib_1547.get_step_label(
                    )] = f_nom - fw_param['f_small'] - fw_param['dbf']
                    # STD_CHANGE : step j) should consider the accuracy
                    f_steps_dic[mode][lib_1547.get_step_label()] = f_min + a_f
                    f_steps_dic[mode][lib_1547.get_step_label(
                    )] = f_min + fw_param['f_small']
                    f_steps_dic[mode][lib_1547.get_step_label()] = (
                        f_nom - fw_param['dbf']) - a_f
                    f_steps_dic[mode][lib_1547.get_step_label()] = (
                        f_nom - fw_param['dbf']) + a_f
                    f_steps_dic[mode][lib_1547.get_step_label()] = f_nom

                    for step, frequency in f_steps_dic[mode].iteritems():
                        f_steps_dic[mode].update(
                            {step: np.around(frequency, 3)})
                        if frequency < f_min:
                            ts.log(
                                "{0} frequency step (value : {1}) changed to fL (f_min)"
                                .format(step, frequency))
                            f_steps_dic[mode].update({step: f_min})
                '''
                p) Repeat test steps b) through o) with the EUT power set at 20% and 66% of rated power. 
                '''
                for power in pwr_lvls:
                    if pv is not None:
                        pv_power_setting = (p_rated * power)
                        pv.iv_curve_config(pmp=pv_power_setting, vmp=v_nom_in)
                        pv.irradiance_set(1000.)
                    '''
                    e) Set EUT freq-watt parameters to the values specified by Characteristic 1. 
                        All other functions should be turned off. 
                    '''

                    # STD_CHANGE : dbf and kf don't exist but dbof=dbuf and kof=kuf was the point of having two?
                    if eut is not None:
                        params = {
                            'Ena': True,
                            'curve': fw_curve,
                            'dbf': fw_param['dbf'],
                            'kof': fw_param['kof'],
                            'RspTms': fw_param['tr']
                        }
                        ts.log_debug(params)
                        settings = eut.freq_watt(params)
                        '''
                        f) Verify freq-watt mode is reported as active and that 
                            the correct characteristic is reported. 
                        '''
                        ts.log_debug('Initial EUT FW settings are %s' %
                                     settings)

                    ts.log_debug('Test parameters :  %s' % fw_param)
                    ts.log('Starting data capture for power = %s' % power)

                    dataset_filename = 'FW_{0}_PWR_{1}_{2}'.format(
                        fw_curve, power, mode)
                    if absorb_power:
                        dataset_filename = 'FW_{0}_PWR_{1}_{2}_ABSORB'.format(
                            fw_curve, power, mode)

                    ts.log(
                        '------------{}------------'.format(dataset_filename))
                    '''
                    g) Once steady state is reached, read and record the EUT's 
                    active power, reactive power, voltage,frequency, and current measurements. 
                    '''
                    # STD_CHANGE there should be a wait for steady state to be reached in both mode
                    step = 'Step F'
                    daq.sc['event'] = step
                    daq.data_sample()
                    ts.log('Wait for steady state to be reached')
                    ts.sleep(4 * fw_param['tr'])
                    daq.data_capture(True)

                    for step_label, f_step in f_steps_dic[mode].iteritems():
                        p_initial = lib_1547.get_initial_value(daq=daq,
                                                               step=step_label)
                        ts.log(
                            'Frequency step: setting Grid simulator frequency to %s (%s)'
                            % (f_step, step_label))
                        step_dict = {'F': f_step}
                        if grid is not None:
                            grid.freq(f_step)
                        lib_1547.process_data(
                            daq=daq,
                            tr=fw_param['tr'],
                            step=step_label,
                            initial_value=p_initial,
                            x_target=step_dict,
                            #y_target=None, #automatically calculated in p1547
                            curve=fw_curve,
                            pwr_lvl=power,
                            result_summary=result_summary,
                            filename=dataset_filename)

                    dataset_filename = dataset_filename + ".csv"
                    daq.data_capture(False)
                    ds = daq.data_capture_dataset()
                    ts.log('Saving file: %s' % dataset_filename)
                    ds.to_csv(ts.result_file_path(dataset_filename))
                    result_params['plot.title'] = os.path.splitext(
                        dataset_filename)[0]
                    ts.result_file(dataset_filename, params=result_params)

        result = script.RESULT_COMPLETE

        return result

    except script.ScriptFail, e:
        reason = str(e)
        if reason:
            ts.log_error(reason)
예제 #25
0
def volt_var_mode_imbalanced_grid(imbalance_resp, vv_curves, vv_response_time):

    result = script.RESULT_FAIL
    daq = None
    v_nom = None
    p_rated = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None
    dataset_filename = None

    try:
        #cat = ts.param_value('eut.cat')
        #cat2 = ts.param_value('eut.cat2')
        #sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        #p_rated_prime = ts.param_value('eut.p_rated_prime')
        var_rated = ts.param_value('eut.var_rated')
        s_rated = ts.param_value('eut.s_rated')

        #absorb_enable = ts.param_value('eut.abs_enabled')

        # DC voltages
        v_in_nom = ts.param_value('eut.v_in_nom')
        #v_min_in = ts.param_value('eut.v_in_min')
        #v_max_in = ts.param_value('eut.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_min = ts.param_value('eut.v_low')
        v_max = ts.param_value('eut.v_high')
        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')
        pf_response_time = ts.param_value('vv.test_1_t_r')

        imbalance_fix = ts.param_value('vv.imbalance_fix')

        """
        A separate module has been create for the 1547.1 Standard
        """
        ActiveFunction = p1547.ActiveFunction(ts=ts,
                                              script_name='Volt-Var',
                                              functions=[VV],
                                              criteria_mode=[True, True, True])
        ActiveFunction.set_imbalance_config(imbalance_angle_fix=imbalance_fix)
        ts.log_debug('1547.1 Library configured for %s' % ActiveFunction.get_script_name())

        # Get the rslt parameters for plot
        result_params = ActiveFunction.get_rslt_param_plot()

        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''
        # 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, support_interfaces={'hil': chil})  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)

        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts, support_interfaces={'hil': chil}) 
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized

        # DAS soft channels
        das_points = ActiveFunction.get_sc_points()

        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'], support_interfaces={'hil': chil}) 
        if daq is not None:
            daq.sc['Q_TARGET'] = 100
            daq.sc['Q_TARGET_MIN'] = 100
            daq.sc['Q_TARGET_MAX'] = 100
            daq.sc['V_TARGET'] = v_nom
            daq.sc['event'] = 'None'
            ts.log('DAS device: %s' % daq.info())

        '''
        b) Set all voltage trip parameters to the widest range of adjustability. Disable all reactive/active power
        control functions.
        '''
        # it is assumed the EUT is on
        eut = der.der_init(ts, support_interfaces={'hil': chil}) 
        if eut is not None:
            eut.config()
            ts.log_debug('If not done already, set L/HVRT and trip parameters to the widest range of adjustability.')

        '''
        c) Set all AC test source parameters to the nominal operating voltage and frequency.
        '''
        if grid is not None:
            grid.voltage(v_nom)

        # 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)

        result_summary.write(ActiveFunction.get_rslt_sum_col_name())

        '''
         d) Adjust the EUT's available active power to Prated. For an EUT with an input voltage range, set the input
        voltage to Vin_nom.
        '''
        if pv is not None:
            pv.iv_curve_config(pmp=p_rated, vmp=v_in_nom)
            pv.irradiance_set(1000.)

        '''
        h) Once steady state is reached, begin the adjustment of phase voltages.
        '''

        """
        Test start
        """
        ts.log_debug(f'imbalance_resp={imbalance_resp}')
        for imbalance_response in imbalance_resp:

            #Default 2 time responses cycles
            #ActiveFunction.reset_time_settings(tr=pf_response_time)

            for vv_curve in vv_curves:

                '''
                 e) Set EUT volt-watt parameters to the values specified by Characteristic 1. All other function be turned off.
                 '''
                ts.log('Starting test with characteristic curve %s' % (vv_curve))
                ActiveFunction.reset_curve(vv_curve)
                ActiveFunction.reset_time_settings(tr=vv_response_time[vv_curve], number_tr=2)
                v_pairs = ActiveFunction.get_params(function=VV, curve=vv_curve)
                ts.log_debug('v_pairs:%s' % v_pairs)
                #Setting up step label
                ActiveFunction.set_step_label(starting_label='G')


                # it is assumed the EUT is on
                if eut is not None:
                    vv_curve_params = {
                            'v': [(v_pairs['V1'] / v_nom) , (v_pairs['V2'] / v_nom) ,
                                  (v_pairs['V3'] / v_nom), (v_pairs['V4'] / v_nom) ],
                            'var': [(v_pairs['Q1'] / s_rated), (v_pairs['Q2'] / s_rated) ,
                                    (v_pairs['Q3'] / s_rated) , (v_pairs['Q4'] / s_rated)],
                            'vref': 1.0,
                            'RmpPtTms': vv_response_time[vv_curve]}
                    ts.log_debug('Sending VV points: %s' % vv_curve_params)
                    eut.volt_var(params={'Ena': True, 'curve': vv_curve_params})

                '''
                f) Verify volt-var mode is reported as active and that the correct characteristic is reported.
                '''
                if eut is not None:
                    ts.log_debug('Initial EUT VV settings are %s' % eut.volt_var())
                ts.log_debug('curve points:  %s' % v_pairs)
                if chil is not None:                        
                    ts.log('Start simulation of CHIL')  
                    chil.start_simulation()
                '''
                g) Wait for steady state to be reached.
    
                Every time a parameter is stepped or ramped, measure and record the time domain current and voltage
                response for at least 4 times the maximum expected response time after the stimulus, and measure or
                derive, active power, apparent power, reactive power, and power factor.
                '''

                step = ActiveFunction.get_step_label()

                daq.sc['event'] = step
                daq.data_sample()
                ts.log('Wait for steady state to be reached')
                ts.sleep(2 * vv_response_time[vv_curve])
                ts.log(imbalance_resp)

                ts.log('Starting imbalance test with VV mode at %s' % (imbalance_response))

                ActiveFunction.set_imbalance_config(imbalance_angle_fix=imbalance_fix)
                #ts.log_debug(f'{imbalance_response}')
                dataset_filename = f'VV_IMB_{imbalance_fix}_{imbalance_response}'

                ActiveFunction.reset_filename(filename=dataset_filename)
                ts.log('------------{}------------'.format(dataset_filename))
                # Start the data acquisition systems
                daq.data_capture(True)

                '''
                h) For multiphase units, step the AC test source voltage to Case A from Table 24.
                '''
                if grid is not None:
                    step_label = ActiveFunction.get_step_label()
                    ts.log('Voltage step: setting Grid simulator to case A (IEEE 1547.1-Table 24)(%s)' % step)
                    ActiveFunction.start(daq=daq, step_label=step_label)
                    v_target = ActiveFunction.set_grid_asymmetric(grid=grid, case='case_a', imbalance_resp=imbalance_response)
                    ts.log_debug(f'v_target={v_target}')
                    step_dict = {'V': v_target}
                    ActiveFunction.record_timeresponse(daq=daq)
                    ActiveFunction.evaluate_criterias(daq=daq, step_dict=step_dict)
                    result_summary.write(ActiveFunction.write_rslt_sum())

                '''
                i) For multiphase units, step the AC test source voltage to VN.
                '''
                if grid is not None:
                    step_label = ActiveFunction.get_step_label()
                    v_target = v_nom
                    ActiveFunction.start(daq=daq, step_label=step_label)
                    ts.log('Voltage step: setting Grid simulator voltage to %s (%s)' % (v_nom, step))
                    grid.voltage(v_target)
                    step_dict = {'V': v_target}
                    ActiveFunction.record_timeresponse(daq=daq)
                    ActiveFunction.evaluate_criterias(daq=daq, step_dict=step_dict)
                    result_summary.write(ActiveFunction.write_rslt_sum())

                """
                j) For multiphase units, step the AC test source voltage to Case B from Table 24.
                """
                if grid is not None:
                    step_label = ActiveFunction.get_step_label()
                    ActiveFunction.start(daq=daq, step_label=step_label)
                    ts.log('Voltage step: setting Grid simulator to case B (IEEE 1547.1-Table 24)(%s)' % step)
                    v_target = ActiveFunction.set_grid_asymmetric(grid=grid, case='case_b', imbalance_resp=imbalance_response)
                    step_dict = {'V': v_target}
                    ActiveFunction.record_timeresponse(daq=daq)
                    ActiveFunction.evaluate_criterias(daq=daq, step_dict=step_dict)
                    result_summary.write(ActiveFunction.write_rslt_sum())

                """
                k) For multiphase units, step the AC test source voltage to VN
                """
                if grid is not None:
                    step_label = ActiveFunction.get_step_label()
                    v_target = v_nom
                    ActiveFunction.start(daq=daq, step_label=step_label)
                    ts.log('Voltage step: setting Grid simulator voltage to %s (%s)' % (v_nom, step))
                    grid.voltage(v_nom)
                    step_dict = {'V': v_target}
                    ActiveFunction.record_timeresponse(daq=daq)
                    ActiveFunction.evaluate_criterias(daq=daq, step_dict=step_dict)
                    result_summary.write(ActiveFunction.write_rslt_sum())

                ts.log('Sampling complete')
                dataset_filename = dataset_filename + ".csv"
                daq.data_capture(False)
                ds = daq.data_capture_dataset()
                ts.log('Saving file: %s' % dataset_filename)
                ds.to_csv(ts.result_file_path(dataset_filename))
                result_params['plot.title'] = dataset_filename.split('.csv')[0]
                ts.result_file(dataset_filename, params=result_params)
                result = script.RESULT_COMPLETE

    except script.ScriptFail as e:
        reason = str(e)
        if reason:
            ts.log_error(reason)


    except Exception as e:

        if dataset_filename is not None:
            dataset_filename = dataset_filename + ".csv"
            daq.data_capture(False)
            ds = daq.data_capture_dataset()
            ts.log('Saving file: %s' % dataset_filename)
            ds.to_csv(ts.result_file_path(dataset_filename))
            result_params['plot.title'] = dataset_filename.split('.csv')[0]
            ts.result_file(dataset_filename, params=result_params)

        raise

    finally:
        if daq is not None:
            daq.close()
        if pv is not None:
            if p_rated is not None:
                pv.power_set(p_rated)
            pv.close()
        if grid is not None:
            if v_nom is not None:
                grid.voltage(v_nom)
            grid.close()
        if chil is not None:
            chil.close()
        if eut is not None:
            #eut.volt_var(params={'Ena': False})
            #eut.volt_watt(params={'Ena': False})
            eut.close()
        if result_summary is not None:
            result_summary.close()

    return result
예제 #26
0
def test_run():

    result = script.RESULT_FAIL
    daq = None
    data = None
    trigger = None
    grid = None
    pv = None
    eut = None
    chil = None
    rs = None

    try:
        # initialize hardware-in-the-loop environment (if applicable)
        ts.log('Configuring HIL system...')
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()

        # initialize grid simulator
        grid = gridsim.gridsim_init(ts)

        # initialize pv simulator
        pv = pvsim.pvsim_init(ts)
        p_rated = ts.param_value('fw.p_rated')
        pv.power_set(p_rated)
        pv.power_on()  # power on at p_rated

        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'])
        daq.sc['P_target_pct'] = 100
        daq.sc['P_min_pct'] = 100
        daq.sc['P_max_pct'] = 100
        daq.sc['eval_flag'] = 0

        # Configure the EUT communications
        eut = der.der_init(ts)
        eut.config()
        ts.log_debug(eut.measurements())
        ts.log_debug(
            'Set L/HFRT and trip parameters to the widest range of adjustability possible.'
        )

        fw_mode = ts.param_value('fw.fw_mode')
        f_nom = ts.param_value('fw.f_nom')
        f_min = ts.param_value('fw.f_min')
        f_max = ts.param_value('fw.f_max')
        MSAHz = ts.param_value('fw.MSAHz')
        MSAP = ts.param_value('fw.MSAP')
        t_settling = ts.param_value('fw.ts')
        fstart_min = ts.param_value('fw.fstart_min')
        fstart_max = ts.param_value('fw.fstart_max')
        k_pf_min = ts.param_value('fw.k_pf_min')
        k_pf_max = ts.param_value('fw.k_pf_max')
        k_pf = ts.param_value('fw.kpf')  # %Prated/Hz

        n_points = ts.param_value('test.n_points')
        irr = ts.param_value('test.irr')
        n_iterations = ts.param_value('test.n_iter')
        curves = ts.param_value('test.curves')

        if curves == 'Both':
            fw_curves = [1, 2]
        elif curves == 'Charactistic Curve 1':
            fw_curves = [1]
        else:  # Charactistic Curve 2
            fw_curves = [2]

        if irr == 'All':
            pv_powers = [1., 0.66, 0.33]
        elif irr == '100%':
            pv_powers = [1.]
        elif irr == '66%':
            pv_powers = [0.66]
        else:  #Charactistic Curve 2
            pv_powers = [0.33]

        # 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)
        result_summary.write(
            'Result, Test Name, Power Level, Iteration, direction, '
            'Freq, Power, P_min, P_max,  Dataset File\n')

        for fw_curve in fw_curves:
            if fw_curve == 1:  # characteristic curve 1
                hz_stop = fstart_max + 100. / k_pf_max
                hz_start = fstart_min
            else:  # characteristic curve 2
                hz_stop = fstart_min + 100. / k_pf_min
                hz_start = fstart_max

            if fw_mode == 'Parameters':
                eut.freq_watt_param(
                    params={
                        'HysEna': False,
                        'HzStr': hz_start,
                        'HzStop': hz_stop,
                        'WGra': k_pf_min
                    })
            else:  # pointwise
                eut.freq_watt(params={'ActCrv': 1})
                parameters = {
                    'hz': [fstart_min, fstart_min, hz_stop, hz_stop],
                    'w': [100, 100, 0, 0]
                }
                ts.log_debug(parameters)
                eut.freq_watt_curve(id=1, params=parameters)
                eut.freq_watt(params={'Ena': True})
                ts.log_debug(eut.freq_watt())

            # start and stop frequencies for the grid simulator steps
            f_start = fstart_min
            f_end = f_max - MSAHz

            for power in pv_powers:
                pv.power_set(p_rated * power)
                for n_iter in range(n_iterations):
                    # SA14.3.2(d) and (e)
                    daq.data_capture(True)
                    f_steps = list(np.linspace(f_start, f_end, n_points)) + \
                              list(np.linspace(f_end, f_start, n_points)) + [49.0]

                    filename = 'FW_curve_%s_power=%0.2f_iter=%s.csv' % (
                        fw_curve, power, n_iter + 1)
                    step_count = 0
                    for f_step in f_steps:
                        step_count += 1
                        grid.freq(f_step)
                        daq.sc['freq_set'] = f_step
                        ts.log(
                            '        Recording power at frequency %0.3f Hz for 2*t_settling = %0.1f sec.'
                            % (f_step, 2 * t_settling))
                        p_targ = p_target(f_step, f_nom, hz_start, hz_stop)
                        daq.sc['P_target_pct'] = p_targ
                        daq.sc['P_min_pct'] = p_targ - (MSAP / p_rated) * 100.
                        daq.sc['P_max_pct'] = p_targ + (MSAP / p_rated) * 100.
                        ts.sleep(t_settling)
                        daq.sc[
                            'eval_flag'] = 1  # flag the time in which the power will be analyzed, see Figure SA14.3
                        daq.data_capture()
                        ts.sleep(
                            t_settling * 1.5
                        )  # This time period will be analyzed for pass/fail criteria
                        data = daq.data_capture_read()
                        ts.log_debug(
                            'Powers targ, min, max: %s, %s, %s' %
                            (p_targ, daq.sc['P_min_pct'], daq.sc['P_max_pct']))
                        ts.log_debug('Powers are: %s, %s, %s' %
                                     (data.get('AC_P_1'), data.get('AC_P_2'),
                                      data.get('AC_P_3')))
                        AC_W = data.get('AC_P_1') + data.get(
                            'AC_P_2') + data.get('AC_P_3')
                        AC_W_pct = (AC_W / p_rated) * 100.
                        if daq.sc['P_min_pct'] <= AC_W_pct <= daq.sc[
                                'P_max_pct']:
                            passfail = 'Pass'
                        else:
                            passfail = 'Fail'
                        if step_count <= n_points:
                            direction = 'up'
                        else:
                            direction = 'down'
                        result_summary.write(
                            '%s, %s, %s, %s, %s, %s, %s, %s, %s, %s \n' %
                            (passfail, ts.config_name(), power * 100.,
                             n_iter + 1, direction, f_step, AC_W_pct,
                             daq.sc['P_min_pct'], daq.sc['P_max_pct'],
                             filename))
                        daq.sc['eval_flag'] = 0
                        daq.data_capture()

                    daq.data_capture(False)
                    ds = daq.data_capture_dataset()
                    ts.log('Saving file: %s' % filename)
                    ds.to_csv(ts.result_file_path(filename))
                    ts.result_file(filename)

        result = script.RESULT_COMPLETE

    except script.ScriptFail, e:
        reason = str(e)
        if reason:
            ts.log_error(reason)
예제 #27
0
def volt_var_mode_imbalanced_grid(imbalance_resp, vv_curves, vv_response_time):

    result = script.RESULT_FAIL
    daq = None
    v_nom = None
    p_rated = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None
    dataset_filename = None

    try:
        #cat = ts.param_value('eut.cat')
        #cat2 = ts.param_value('eut.cat2')
        #sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        #p_rated_prime = ts.param_value('eut.p_rated_prime')
        var_rated = ts.param_value('eut.var_rated')
        s_rated = ts.param_value('eut.s_rated')

        #absorb_enable = ts.param_value('eut.abs_enabled')

        # DC voltages
        v_in_nom = ts.param_value('eut.v_in_nom')
        #v_min_in = ts.param_value('eut.v_in_min')
        #v_max_in = ts.param_value('eut.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_min = ts.param_value('eut.v_low')
        v_max = ts.param_value('eut.v_high')
        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')
        pf_response_time = ts.param_value('vv.test_imbalanced_t_r')

        # Pass/fail accuracies
        pf_msa = ts.param_value('eut.pf_msa')
        # According to Table 3-Minimum requirements for manufacturers stated measured and calculated accuracy
        MSA_Q = 0.05 * s_rated
        MSA_P = 0.05 * s_rated
        MSA_V = 0.01 * v_nom

        imbalance_fix = ts.param_value('vv.imbalance_fix')
        """
        A separate module has been create for the 1547.1 Standard
        """
        lib_1547 = p1547.module_1547(ts=ts,
                                     aif='VV',
                                     imbalance_angle_fix=imbalance_fix)
        ts.log_debug('1547.1 Library configured for %s' %
                     lib_1547.get_test_name())

        # Get the rslt parameters for plot
        result_params = lib_1547.get_rslt_param_plot()
        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''
        # 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)  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)

        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        pv.power_set(p_rated)
        pv.power_on()  # Turn on DC so the EUT can be initialized

        # DAS soft channels
        # TODO : add to library 1547
        das_points = {
            'sc': ('Q_TARGET', 'Q_TARGET_MIN', 'Q_TARGET_MAX', 'Q_MEAS',
                   'V_TARGET', 'V_MEAS', 'event')
        }

        # initialize data acquisition system
        daq = das.das_init(ts, sc_points=das_points['sc'])
        if daq is not None:
            daq.sc['Q_TARGET'] = 100
            daq.sc['Q_TARGET_MIN'] = 100
            daq.sc['Q_TARGET_MAX'] = 100
            daq.sc['V_TARGET'] = v_nom
            daq.sc['event'] = 'None'
            ts.log('DAS device: %s' % daq.info())
        '''
        b) Set all voltage trip parameters to the widest range of adjustability. Disable all reactive/active power
        control functions.
        '''
        '''
        c) Set all AC test source parameters to the nominal operating voltage and frequency.
        '''
        if grid is not None:
            grid.voltage(v_nom)

        # 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)

        result_summary.write(lib_1547.get_rslt_sum_col_name())
        '''
         d) Adjust the EUT's available active power to Prated. For an EUT with an input voltage range, set the input
        voltage to Vin_nom.
        '''

        if pv is not None:
            pv.iv_curve_config(pmp=p_rated, vmp=v_in_nom)
            pv.irradiance_set(1000.)
        '''
        h) Once steady state is reached, begin the adjustment of phase voltages.
        '''
        """
        Test start
        """

        for imbalance_response in imbalance_resp:
            for vv_curve in vv_curves:
                '''
                 e) Set EUT volt-watt parameters to the values specified by Characteristic 1. All other function be turned off.
                 '''

                v_pairs = lib_1547.get_params(curve=vv_curve)

                # it is assumed the EUT is on
                eut = der.der_init(ts)
                if eut is not None:
                    vv_curve_params = {
                        'v': [
                            v_pairs['V1'] * (100 / v_nom),
                            v_pairs['V2'] * (100 / v_nom),
                            v_pairs['V3'] * (100 / v_nom),
                            v_pairs['V4'] * (100 / v_nom)
                        ],
                        'q': [
                            v_pairs['Q1'] * (100 / var_rated),
                            v_pairs['Q2'] * (100 / var_rated),
                            v_pairs['Q3'] * (100 / var_rated),
                            v_pairs['Q4'] * (100 / var_rated)
                        ],
                        'DeptRef':
                        'Q_MAX_PCT'
                    }
                    ts.log_debug('Sending VV points: %s' % vv_curve_params)
                    eut.volt_var(params={
                        'Ena': True,
                        'curve': vv_curve_params
                    })

                    # ASK @Jay about this loop. Necessary here ? Could go inside your driver...

                    for i in range(10):
                        if not eut.volt_var()['Ena']:
                            ts.log_error(
                                'EUT VV Enable register not set to True. Trying again...'
                            )
                            eut.volt_var(params={'Ena': True})
                            ts.sleep(1)
                        else:
                            break
                    # TODO autonomous vref adjustment to be included
                    # eut.autonomous_vref_adjustment(params={'Ena': False})
                '''
                f) Verify volt-var mode is reported as active and that the correct characteristic is reported.
                '''
                if eut is not None:
                    ts.log_debug('Initial EUT VV settings are %s' %
                                 eut.volt_var())
                ts.log_debug('curve points:  %s' % v_pairs)
                '''
                g) Wait for steady state to be reached.
    
                Every time a parameter is stepped or ramped, measure and record the time domain current and voltage
                response for at least 4 times the maximum expected response time after the stimulus, and measure or
                derive, active power, apparent power, reactive power, and power factor.
                '''
                """
                Test start
                """
                step = 'Step G'
                daq.sc['event'] = step
                daq.data_sample()
                ts.log('Wait for steady state to be reached')
                ts.sleep(4 * vv_response_time[vv_curve])
                ts.log(imbalance_resp)

                ts.log('Starting imbalance test with VV mode at %s' %
                       (imbalance_response))

                if imbalance_fix == "Yes":
                    dataset_filename = 'VV_IMB_%s_FIX' % (imbalance_response)
                else:
                    dataset_filename = 'VV_IMB_%s' % (imbalance_response)
                ts.log('------------{}------------'.format(dataset_filename))
                # Start the data acquisition systems
                daq.data_capture(True)
                '''
                h) For multiphase units, step the AC test source voltage to Case A from Table 24.
                '''
                if grid is not None:
                    step = 'Step H'
                    ts.log(
                        'Voltage step: setting Grid simulator to case A (IEEE 1547.1-Table 24)(%s)'
                        % step)
                    q_initial = lib_1547.get_initial(daq=daq, step=step)
                    lib_1547.set_grid_asymmetric(grid=grid, case='case_a')
                    q_v_analysis = lib_1547.criteria(
                        daq=daq,
                        tr=vv_response_time[vv_curve],
                        step=step,
                        initial_value=q_initial,
                        curve=vv_curve)

                    result_summary.write(
                        lib_1547.write_rslt_sum(analysis=q_v_analysis,
                                                step=step,
                                                filename=dataset_filename))
                '''
                w) For multiphase units, step the AC test source voltage to VN.
                '''
                if grid is not None:
                    # STD_CHANGE : This step is not following order
                    step = 'Step W'
                    ts.log(
                        'Voltage step: setting Grid simulator voltage to %s (%s)'
                        % (v_nom, step))
                    q_initial = lib_1547.get_initial(daq=daq, step=step)
                    grid.voltage(v_nom)
                    q_v_analysis = lib_1547.criteria(
                        daq=daq,
                        tr=vv_response_time[vv_curve],
                        step=step,
                        initial_value=q_initial,
                        curve=vv_curve,
                        target=v_nom)
                    result_summary.write(
                        lib_1547.write_rslt_sum(analysis=q_v_analysis,
                                                step=step,
                                                filename=dataset_filename))
                """
                i) For multiphase units, step the AC test source voltage to Case B from Table 24.
                """
                if grid is not None:
                    step = 'Step I'
                    ts.log(
                        'Voltage step: setting Grid simulator to case B (IEEE 1547.1-Table 24)(%s)'
                        % step)
                    q_initial = lib_1547.get_initial(daq=daq, step=step)
                    lib_1547.set_grid_asymmetric(grid=grid, case='case_b')
                    q_v_analysis = lib_1547.criteria(
                        daq=daq,
                        tr=vv_response_time[vv_curve],
                        step=step,
                        initial_value=q_initial,
                        curve=vv_curve)
                    result_summary.write(
                        lib_1547.write_rslt_sum(analysis=q_v_analysis,
                                                step=step,
                                                filename=dataset_filename))
                """
                j) For multiphase units, step the AC test source voltage to VN
                """
                if grid is not None:
                    ts.log(
                        'Voltage step: setting Grid simulator voltage to %s (%s)'
                        % (v_nom, step))
                    step = 'Step J'
                    q_initial = lib_1547.get_initial(daq=daq, step=step)
                    grid.voltage(v_nom)
                    q_v_analysis = lib_1547.criteria(
                        daq=daq,
                        tr=vv_response_time[vv_curve],
                        step=step,
                        initial_value=q_initial,
                        curve=vv_curve,
                        target=v_nom)
                    result_summary.write(
                        lib_1547.write_rslt_sum(analysis=q_v_analysis,
                                                step=step,
                                                filename=dataset_filename))

                ts.log('Sampling complete')
                dataset_filename = dataset_filename + ".csv"
                daq.data_capture(False)
                ds = daq.data_capture_dataset()
                ts.log('Saving file: %s' % dataset_filename)
                ds.to_csv(ts.result_file_path(dataset_filename))
                result_params['plot.title'] = dataset_filename.split('.csv')[0]
                ts.result_file(dataset_filename, params=result_params)
                result = script.RESULT_COMPLETE

    except script.ScriptFail, e:
        reason = str(e)
        if reason:
            ts.log_error(reason)
예제 #28
0
def test_run():
    result = script.RESULT_FAIL
    grid = None
    pv = p_rated = None
    daq = None
    eut = None
    rs = None
    chil = None
    result_summary = None
    step = None
    q_initial = None
    dataset_filename = None

    try:
        cat = ts.param_value('eut.cat')
        cat2 = ts.param_value('eut.cat2')
        sink_power = ts.param_value('eut.sink_power')
        p_rated = ts.param_value('eut.p_rated')
        p_rated_prime = ts.param_value('eut.p_rated_prime')
        s_rated = ts.param_value('eut.s_rated')
        var_rated = ts.param_value('eut.var_rated')

        # DC voltages
        v_nom_in_enabled = ts.param_value('cpf.v_in_nom')
        v_min_in_enabled = ts.param_value('cpf.v_in_min')
        v_max_in_enabled = ts.param_value('cpf.v_in_max')

        v_nom_in = ts.param_value('eut.v_in_nom')
        v_min_in = ts.param_value('eut_cpf.v_in_min')
        v_max_in = ts.param_value('eut_cpf.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_min = ts.param_value('eut.v_low')
        v_max = ts.param_value('eut.v_high')
        f_nom = ts.param_value('eut.f_nom')
        f_min = ts.param_value('eut.f_min')
        f_max = ts.param_value('eut.f_max')

        p_min = ts.param_value('eut.p_min')
        p_min_prime = ts.param_value('eut.p_min_prime')
        phases = ts.param_value('eut.phases')


        # RT test parameters
        lf_ena = ts.param_value('frt.lf_ena')
        hf_ena = ts.param_value('frt.hf_ena')
        freq_response_time = ts.param_value('frt.response_time')
        n_iter = ts.param_value('frt.n_iter')
        pwr_lvl = ts.param_value('frt.pwr_value')
        # Pass/fail accuracies
        pf_msa = ts.param_value('eut.pf_msa')

        # EUI Absorb capabilities
        absorb = {}
        absorb['ena'] = ts.param_value('eut_cpf.sink_power')
        absorb['p_rated_prime'] = ts.param_value('eut_cpf.p_rated_prime')
        absorb['p_min_prime'] = ts.param_value('eut_cpf.p_min_prime')

        # Functions to be enabled for test
        mode = []
        steps_dict = {}
        if lf_ena == 'Enabled':
            mode.append(LF)
            lf_value = ts.param_value('frt.lf_value')
            if not(isinstance(lf_value, float) or isinstance(lf_value, int)):
                #TODO if not numeric value inputed
                pass
            elif not (f_min <= lf_value <= 57.0):
                #TODO raise error if not between f_min and 57.0
                raise ValueError

            steps_dict[LF] = {'location': f'C:/', 'value': lf_value}

        if hf_ena == 'Enabled':
            mode.append(HF)
            hf_value = ts.param_value('frt.hf_value')
            if not(isinstance(hf_value, float) or isinstance(hf_value, int)):
                #TODO if not numeric value inputed
                pass
            elif not 61.7 <= hf_value <= f_max:
                #TODO raise error if not between 63.0 and f_max
                raise ValueError

            steps_dict[HF] = {'location': f'C:/', 'value': hf_value}

        if not (isinstance(freq_response_time, float) or isinstance(freq_response_time, int)):
            # TODO if not numeric value inputed
            pass
        elif 299 > freq_response_time:
            # TODO timedelay must be over 299 sec
            raise ValueError

        time_step = {'location': f'C:....', 'value': freq_response_time }
        """
        A separate module has been create for the 1547.1 Standard
        """

        lib_1547 = p1547.module_1547(ts=ts, aif='FW', absorb=absorb)
        ts.log_debug("1547.1 Library configured for %s" % lib_1547.get_test_name())

        # result params
        result_params = lib_1547.get_rslt_param_plot()
        ts.log(result_params)

        # initialize HIL environment, if necessary
        phil = hil.hil_init(ts)
        if phil is not None:
            phil.config()

        # grid simulator is initialized with test parameters and enabled
        grid = gridsim.gridsim_init(ts)  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)

        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized

        # DAS soft channels
        das_points = lib_1547.get_sc_points()

        # initialize data acquisition
        daq = das.das_init(ts, sc_points=das_points['sc'])

        """
        if daq is not None:
            daq.sc['V_MEAS'] = 100
            daq.sc['P_MEAS'] = 100
            daq.sc['Q_MEAS'] = 100
            daq.sc['Q_TARGET_MIN'] = 100
            daq.sc['Q_TARGET_MAX'] = 100
            daq.sc['PF_TARGET'] = 1
            daq.sc['event'] = 'None'
            ts.log('DAS device: %s' % daq.info())
        """

        """
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        """
        # it is assumed the EUT is on
        eut = der.der_init(ts)
        if eut is not None:
            eut.config()
            eut.deactivate_all_fct()

        # 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)
        result_summary.write(lib_1547.get_rslt_sum_col_name())

        """
        c) Set the frequency droop function and droop values to make the active power change with respect to
        frequency as small as possible.
        """
        if eut is not None:
            default_curve = 1
            fw_settings = lib_1547.get_params(aif=FW)
            fw_curve_params = {
                'Ena': True,
                'curve': default_curve,
                'dbf': fw_settings[default_curve]['dbf'],
                'kof': fw_settings[default_curve]['kof'],
                'RspTms': fw_settings[default_curve]['tr']
            }
            eut.freq_watt(fw_curve_params)
            ts.log_debug('Sending FW points: %s' % fw_curve_params)


        """
        d) Set or verify that all frequency trip settings are set to not influence the outcome of the test.
        """
        ts.log_debug('If not done already, set L/HVRT and trip parameters to the widest range of adjustability.')
        ts.log_debug(f'{mode}')


        #TODO Isolated Source mode??
        for current_mode in mode:
            ts.log_debug(f'Initializing {current_mode}')

            # TODO FIND A WAY TO SET ROCOF

            """
            e) Operate the ac test source at nominal frequency ± 0.1 Hz.
            """

            if grid is not None:
                grid.voltage(v_nom)
                ts.log(f'Setting Grid simulator voltage to {v_nom}')
                grid.freq(f_nom)
                ts.log(f'Setting Grid simulator frequency to {f_nom}')

            for i in range(1, n_iter+1):
                ts.log_debug('Starting mode = %s and %s' % (current_mode, current_mode == VV))
                daq.data_capture(True)
                dataset_filename = f'FRT_{current_mode}_{i}'
                ts.log('------------{}------------'.format(dataset_filename))
                #step_label = lib_1547.set_step_label(starting_label='F')
                #step = lib_1547.get_step_label()

                """
                f) Operate EUT at any convenient power level between 90% and 100% of EUT rating and at any
                convenient power factor. Record the output current of the EUT at the nominal frequency condition.
                """
                if pv is not None:
                    pv.iv_curve_config(pmp=p_rated, vmp=v_nom_in)
                    pv.irradiance_set(1000.)
                    pv.power_set(round(pwr_lvl*p_rated))

                """
                ***For High Frequency RT test mode***
                g) Adjust the source frequency from PN to PU where fU is greater than or equal to 61.8 Hz. The source
                shall be held at this frequency for period th, which shall be not less than 299 s.
                """
                # Set values for steps
                freq_step_location = steps_dict[current_mode]['location']
                freq_step_value = steps_dict[current_mode]['value']
                ts.log(f'Frequency step: setting Grid simulator frequency to {freq_step_value}Hz')
                ts.log(f'At frequency step location: {freq_step_location}')

                # Set timestep
                time_step_location = time_step['location']
                time_step_value = time_step['value']
                ts.log(f'Time setting: setting Grid simulator time setting to {time_step_value}sec')
                ts.log(f'At time step location: {time_step_location}')

                if phil is not None:
                    #Send commands to HIL
                    phil.set_params((freq_step_location, freq_step_value))
                    phil.set_params((time_step_location, time_step_value))

                    #TODO HIL SECTION TO BE COMPLETED
                    ts.log('Stop time set to %s' % phil.set_stop_time(stop_time))

                    if compilation == 'Yes':
                        ts.log("    Model ID: {}".format(phil.compile_model().get("modelId")))
                    if stop_sim == 'Yes':
                        ts.log("    {}".format(phil.stop_simulation()))
                    if load == 'Yes':
                        ts.log("    {}".format(phil.load_model_on_hil()))
                    if execute == 'Yes':
                        ts.log("    {}".format(phil.start_simulation()))

                    sim_time = phil.get_time()
                    while (stop_time - sim_time) > 1.0:  # final sleep will get to stop_time.
                        sim_time = phil.get_time()
                        ts.log('Sim Time: %s.  Waiting another %s sec before saving data.' % (
                            sim_time, stop_time - sim_time))
                        ts.sleep(1)

                """
                h) Decrease the frequency of the ac test source to the nominal frequency ± 0.1 Hz.
                """
                if grid is not None:
                    grid.freq(f_nom)
                    ts.log(f'Frequency step: setting Grid simulator frequency to {f_nom}')

                """
                i) Repeat steps f) and g) twice for a total of three tests.
                """
                """
                j) During all frequency transitions in steps f) through h), the ROCOF shall be greater than or equal to
                the ROCOF limit in Table 21 of IEEE Std 1547-2018 and shall be within the demonstrated ROCOF
                capability of the EUT.
                """


                ts.log('Sampling complete')
                dataset_filename = dataset_filename + ".csv"
                daq.data_capture(False)
                ds = daq.data_capture_dataset()
                ts.log('Saving file: %s' % dataset_filename)
                ds.to_csv(ts.result_file_path(dataset_filename))
                result_params['plot.title'] = dataset_filename.split('.csv')[0]
                ts.result_file(dataset_filename, params=result_params)
                result = script.RESULT_COMPLETE

    except script.ScriptFail as e:
        reason = str(e)
        if reason:
            ts.log_error(reason)

    except Exception as e:
        ts.log_error((e, traceback.format_exc()))
        if dataset_filename is not None:
            dataset_filename = dataset_filename + ".csv"
            daq.data_capture(False)
            ds = daq.data_capture_dataset()
            ts.log('Saving file: %s' % dataset_filename)
            ds.to_csv(ts.result_file_path(dataset_filename))
            result_params['plot.title'] = dataset_filename.split('.csv')[0]
            ts.result_file(dataset_filename, params=result_params)
        ts.log_error('Test script exception: %s' % traceback.format_exc())


    finally:

        if grid is not None:
            grid.close()
        if pv is not None:
            if p_rated is not None:
                pv.power_set(p_rated)
            pv.close()
        if daq is not None:
            daq.close()
        if eut is not None:
            eut.freq_watt(params={'Ena': False})
            eut.close()
        if rs is not None:
            rs.close()
        if chil is not None:
            chil.close()

        if result_summary is not None:
            result_summary.close()

        # create result workbook
        excelfile = ts.config_name() + '.xlsx'
        rslt.result_workbook(excelfile, ts.results_dir(), ts.result_dir())
        ts.result_file(excelfile)

    return result
예제 #29
0
def test_run():

    result = script.RESULT_FAIL
    eut = grid = load = pv = daq_rms = daq_wf = chil = None

    ### Correction as graph is not displayed
    ### <START>
    ###    sc_points = ['AC_IRMS_MIN']
    sc_points = ['TIME', 'AC_FREQ_1', 'AC_IRMS_1', 'AC_IRMS_MIN']
    ### <END>

    # result params
    result_params = {
        'plot.title': ts.name,
        'plot.x.title': 'Time (secs)',
        'plot.x.points': 'TIME',
        'plot.y.points': 'AC_FREQ_1',
        'plot.y.title': 'Frequency (Hz)',
        'plot.y2.points': 'AC_IRMS_1, AC_IRMS_MIN',
        'plot.y2.title': 'Current (A)'
    }

    try:
        test_label = ts.param_value('frt.test_label')
        # get test parameters
        freq_msa = ts.param_value('eut.freq_msa')
        p_rated = ts.param_value('eut.p_rated')
        v_nom = ts.param_value('eut.v_nom')
        t_msa = ts.param_value('eut.t_msa')
        t_dwell = ts.param_value('eut.frt_t_dwell')
        freq_nom = ts.param_value('eut.freq_nom')
        freq_grid_min = ts.param_value('frt.freq_grid_min')
        freq_grid_max = ts.param_value('frt.freq_grid_max')
        freq_test = ts.param_value('frt.freq_test')
        t_hold = ts.param_value('frt.t_hold')
        n_r = ts.param_value('frt.n_r')

        # calculate voltage adjustment based on msa
        freq_msa_adj = freq_msa * 1.5
        if freq_test > freq_nom:
            # apply HFRT msa adjustments
            freq_n = freq_grid_min + freq_msa_adj
            freq_t = freq_test - freq_msa_adj
        else:
            # apply LFRT msa adjustments
            freq_n = freq_grid_max - freq_msa_adj
            freq_t = freq_test + freq_msa_adj

        # set power levels that are enabled
        power_levels = []
        if ts.param_value('frt.p_100') == 'Enabled':
            power_levels.append((100, '100'))
        if ts.param_value('frt.p_20') == 'Enabled':
            power_levels.append((20, '20'))

        # 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)
        profile_supported = False

        # 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

###        grid.voltage((v_nom_grid, v_nom_grid, v_nom_grid))      <- Commented out because middleware is communicated using gridsim
        grid.voltageRH(v_nom_grid, v_nom_grid,
                       v_nom_grid)  # <- Change to control from grid

        # load simulator initialization
        load = loadsim.loadsim_init(ts)
        if load is not None:
            ts.log('Load device: %s' % load.info())

### Commented out because middleware is communicated using gridsim
### <START>
###        # pv simulator is initialized with test parameters and enabled
###        pv = pvsim.pvsim_init(ts)
###        pv.power_set(p_rated)
###        pv.power_on()
### <END>

# initialize rms data acquisition
        daq_rms = das.das_init(ts, 'das_rms', sc_points=sc_points)
        if daq_rms is not None:
            ts.log('DAS RMS device: %s' % (daq_rms.info()))
            daq_rms.sc['SC_TRIG'] = 0
            daq_rms.sc['AC_IRMS_MIN'] = ''

        # initialize waveform data acquisition
        daq_wf = das.das_init(ts, 'das_wf')
        if daq_wf is not None:
            ts.log('DAS Waveform device: %s' % (daq_wf.info()))

        # it is assumed the EUT is on
        eut = der.der_init(ts)
        if eut is not None:
            eut.config()

        # perform all power levels
        for power_level in power_levels:
            # set test power level
            power = float(power_level[0]) / 100 * p_rated
            ###            pv.power_set(power)                                                   <- Commented out because middleware is communicated using gridsim
            grid.power_set(power)  # <- Change to control from grid
            ts.log('Setting power level to %s%% of rated' % (power_level[0]))

            if daq_rms is not None:
                ###                daq_rms.sc['AC_IRMS_MIN'] = ''
                data = grid.wt3000_data_capture_read()
                daq_rms.sc['TIME'] = time.time(
                )  # <- Since the graph is not displayed, it is added
                daq_rms.sc['AC_FREQ_1'] = data.get(
                    'AC_FREQ_1'
                )  # <- Since the graph is not displayed, it is added
                daq_rms.sc['AC_IRMS_1'] = data.get(
                    'AC_IRMS_1'
                )  # <- Since the graph is not displayed, it is added
                irms = data.get(
                    'AC_IRMS_1'
                )  # <- Since the graph is not displayed, it is added
                daq_rms.sc['AC_IRMS_MIN'] = round(
                    irms * .8,
                    2)  # <- Since the graph is not displayed, it is added
                ts.log('Starting RMS data capture')
                daq_rms.data_capture(True)
                ts.log('Waiting 5 seconds to start test')
                ts.sleep(5)

            if profile_supported:
                # create and execute test profile
                profile = freq_rt_profile(v_nom=v_nom,
                                          freq_nom=freq_n / freq_nom,
                                          freq_t=freq_t / freq_nom,
                                          t_hold=t_hold,
                                          t_dwell=t_dwell,
                                          n=n_r)
                grid.profile_load(profile=profile)
                grid.profile_start()
                # create 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)
                    sleep_time = min(remaining_time, 10)
                    ts.sleep(sleep_time)
                grid.profile_stop()
            else:
                # execute test sequence
                ts.log('Test duration is %s seconds' %
                       ((float(t_dwell) + float(t_hold)) * float(n_r) +
                        float(t_dwell)))

                # get initial current level to determine threshold
                if daq_rms is not None:
                    daq_rms.data_sample()
                    ###                    data = daq_rms.data_capture_read()                  <- Commented out because middleware is communicated using gridsim
                    data = grid.wt3000_data_capture_read(
                    )  # <- Change to control from grid
                    daq_rms.sc['TIME'] = time.time(
                    )  # <- Since the graph is not displayed, it is added
                    daq_rms.sc['AC_FREQ_1'] = data.get(
                        'AC_FREQ_1'
                    )  # <- Since the graph is not displayed, it is added
                    daq_rms.sc['AC_IRMS_1'] = data.get(
                        'AC_IRMS_1'
                    )  # <- Since the graph is not displayed, it is added
                    irms = data.get('AC_IRMS_1')
                    if irms is not None:
                        daq_rms.sc['AC_IRMS_MIN'] = round(irms * .8, 2)

                for i in range(n_r):
                    grid.freq(freq=freq_n)
                    ts.log('Setting frequency: freq = %s for %s seconds' %
                           (freq_n, t_dwell))
                    ts.sleep(t_dwell)
                    grid.freq(freq=freq_t)
                    ts.log('Setting frequency: freq = %s for %s seconds' %
                           (freq_t, t_hold))
                    ts.sleep(t_hold)
                grid.freq(freq=freq_n)
                ts.log('Setting frequency: freq = %s for %s seconds' %
                       (freq_n, t_dwell))
                ts.sleep(t_dwell)
            if daq_rms is not None:
                daq_rms.data_capture(False)
                ds = daq_rms.data_capture_dataset()
                test_name = '%s_rms_%s' % (test_label, power_level[1])
                filename = '%s.csv' % (test_name)
                ds.to_csv(ts.result_file_path(filename))
                result_params['plot.title'] = test_name
                ts.result_file(filename, params=result_params)
                ts.log('Saving data capture %s' % (filename))

        result = script.RESULT_COMPLETE
예제 #30
0
def volt_watt_mode(vw_curves, vw_response_time, pwr_lvls):

    result = script.RESULT_FAIL
    daq = None
    data = None
    p_rated = None
    v_nom = None
    grid = None
    pv = None
    eut = None
    chil = None
    result_summary = None
    dataset_filename = None

    try:

        p_rated = ts.param_value('eut.p_rated')
        s_rated = ts.param_value('eut.s_rated')

        # DC voltages
        v_in_nom = ts.param_value('eut.v_in_nom')
        v_min_in = ts.param_value('eut.v_in_min')
        v_max_in = ts.param_value('eut.v_in_max')

        # AC voltages
        v_nom = ts.param_value('eut.v_nom')
        v_min = ts.param_value('eut.v_low')
        v_max = ts.param_value('eut.v_high')
        p_min = ts.param_value('eut.p_min')
        phases = ts.param_value('eut.phases')

        # EUI Absorb capabilities
        absorb = {}
        absorb['ena'] = ts.param_value('eut_vw.sink_power')
        absorb['p_rated_prime'] = ts.param_value('eut_vw.p_rated_prime')
        absorb['p_min_prime'] = ts.param_value('eut_vw.p_min_prime')
        """
        Version validation
        """
        p1547.VersionValidation(script_version=ts.info.version)
        """
        A separate module has been create for the 1547.1 Standard
        """
        ActiveFunction = p1547.ActiveFunction(ts=ts,
                                              functions=[VW],
                                              script_name='Volt-Watt',
                                              criteria_mode=[True, True, True])
        ts.log_debug("1547.1 Library configured for %s" %
                     ActiveFunction.get_script_name())

        # result params
        result_params = ActiveFunction.get_rslt_param_plot()
        '''
        a) Connect the EUT according to the instructions and specifications provided by the manufacturer.
        '''
        ts.log_debug(15 * "*" + "HIL initialization" + 15 * "*")

        # initialize HIL environment, if necessary
        chil = hil.hil_init(ts)
        if chil is not None:
            chil.config()
        ts.log_debug(15 * "*" + "PVSIM initialization" + 15 * "*")

        # pv simulator is initialized with test parameters and enabled
        pv = pvsim.pvsim_init(ts)
        if pv is not None:
            pv.power_set(p_rated)
            pv.power_on()  # Turn on DC so the EUT can be initialized

        ts.log_debug(15 * "*" + "DAS initialization" + 15 * "*")

        # DAS soft channels
        #das_points = {'sc': ('P_TARGET', 'P_TARGET_MIN', 'P_TARGET_MAX', 'P_MEAS', 'V_TARGET','V_MEAS','event')}
        das_points = ActiveFunction.get_sc_points()

        # initialize data acquisition system
        das_points = ActiveFunction.get_sc_points()
        daq = das.das_init(ts,
                           sc_points=das_points['sc'],
                           support_interfaces={'hil': chil})
        if daq is not None:
            daq.sc['P_TARGET'] = p_rated
            daq.sc['P_TARGET_MIN'] = 100
            daq.sc['P_TARGET_MAX'] = 100
            daq.sc['V_TARGET'] = v_nom
            daq.sc['event'] = 'None'
            ts.log('DAS device: %s' % daq.info())
        '''
        b) Set all voltage trip parameters to the widest range of adjustability. Disable all reactive/active power
        control functions.
        '''
        ts.log_debug(15 * "*" + "EUT initialization" + 15 * "*")

        eut = der.der_init(ts, support_interfaces={'hil': chil})
        if eut is not None:
            eut.config()
            #Disable all functions on EUT
            eut.deactivate_all_fct()
            ts.log_debug(eut.measurements())
            ts.log_debug(
                'L/HVRT and trip parameters set to the widest range : v_min: {0} V, v_max: {1} V'
                .format(v_min, v_max))
            try:
                eut.vrt_stay_connected_high(
                    params={
                        'Ena': True,
                        'ActCrv': 0,
                        'Tms1': 3000,
                        'V1': v_max,
                        'Tms2': 0.16,
                        'V2': v_max
                    })
            except Exception as e:
                ts.log_error(
                    'Could not set VRT Stay Connected High curve. %s' % e)
            try:
                eut.vrt_stay_connected_low(
                    params={
                        'Ena': True,
                        'ActCrv': 0,
                        'Tms1': 3000,
                        'V1': v_min,
                        'Tms2': 0.16,
                        'V2': v_min
                    })
            except Exception as e:
                ts.log_error('Could not set VRT Stay Connected Low curve. %s' %
                             e)
        else:
            ts.log_debug(
                'Set L/HVRT and trip parameters set to the widest range of adjustability possible.'
            )
        '''
        c) Set all AC test source parameters to the nominal operating voltage and frequency.
        '''
        ts.log_debug(15 * "*" + "GRIDSIM initialization" + 15 * "*")

        # grid simulator is initialized with test parameters and enabled
        grid = gridsim.gridsim_init(ts, support_interfaces={
            'hil': chil
        })  # Turn on AC so the EUT can be initialized
        if grid is not None:
            grid.voltage(v_nom)

        # 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)
        result_summary.write(ActiveFunction.get_rslt_sum_col_name())
        '''
        v) Test may be repeated for EUT's that can also absorb power using the P' values in the characteristic
        definition.
        '''
        # TODO: add P' tests (Like CPF -> for absorb_power in absorb_powers:)
        '''
        u) Repeat steps d) through u) for characteristics 2 and 3.
        '''
        for vw_curve in vw_curves:
            ts.log('Starting test with characteristic curve %s' % (vw_curve))
            ActiveFunction.reset_curve(vw_curve)
            ActiveFunction.reset_time_settings(tr=vw_response_time[vw_curve],
                                               number_tr=2)
            v_pairs = ActiveFunction.get_params(curve=vw_curve, function=VW)
            '''
            t) Repeat steps d) through t) at EUT power set at 20% and 66% of rated power.
            '''
            for power in pwr_lvls:
                ActiveFunction.reset_pwr(pwr=power)
                '''
                d) Adjust the EUT's available active power to Prated. For an EUT with an input voltage range, set the input
                voltage to Vin_nom. The EUT may limit active power throughout the test to meet reactive power requirements.
                For an EUT with an input voltage range.
                '''
                if pv is not None:
                    pv_power_setting = (p_rated * power)
                    pv.iv_curve_config(pmp=pv_power_setting, vmp=v_in_nom)
                    pv.irradiance_set(1000.)

                # Special considerations for CHIL ASGC/Typhoon startup #
                if chil is not None:
                    if eut is not None:
                        if eut.measurements() is not None:
                            inv_power = eut.measurements().get('W')
                            timeout = 120.
                            if inv_power <= pv_power_setting * 0.85:
                                pv.irradiance_set(
                                    995
                                )  # Perturb the pv slightly to start the inverter
                                ts.sleep(3)
                                eut.connect(params={'Conn': True})
                            while inv_power <= pv_power_setting * 0.85 and timeout >= 0:
                                ts.log(
                                    'Inverter power is at %0.1f. Waiting up to %s more seconds or until EUT starts...'
                                    % (inv_power, timeout))
                                ts.sleep(1)
                                timeout -= 1
                                inv_power = eut.measurements().get('W')
                                if timeout == 0:
                                    result = script.RESULT_FAIL
                                    raise der.DERError(
                                        'Inverter did not start.')
                            ts.log('Waiting for EUT to ramp up')
                            ts.sleep(8)
                '''
                e) Set EUT volt-watt parameters to the values specified by Characteristic 1. All other functions should
                   be turned off.
                '''
                if eut is not None:
                    vw_curve_params = {
                        'v': [v_pairs['V1'] / v_nom, v_pairs['V2'] / v_nom],
                        'w':
                        [v_pairs['P1'] / p_rated, v_pairs['P2'] / p_rated],
                        'DeptRef': 'W_MAX_PCT',
                        "RmpTms": vw_response_time[vw_curve]
                    }

                    vw_params = {
                        'Ena': True,
                        'ActCrv': 1,
                        'curve': vw_curve_params
                    }
                    ts.log_debug('Writing the following params to EUT: %s' %
                                 vw_params)
                    eut.volt_watt(params=vw_params)
                    '''
                    f) Verify volt-watt mode is reported as active and that the correct characteristic is reported.
                    '''
                    ts.log_debug('Initial EUT VW settings are %s' %
                                 eut.volt_watt())
                if chil is not None:
                    ts.log('Start simulation of CHIL')
                    chil.start_simulation()
                '''
                Refer to P1547 Library and IEEE1547.1 standard for steps 
                '''
                v_steps_dict = ActiveFunction.create_vw_dict_steps()

                # Configure the data acquisition system
                ts.log('Starting data capture for power = %s' % power)
                dataset_filename = ('VW_{0}_PWR_{1}'.format(vw_curve, power))
                ActiveFunction.reset_filename(filename=dataset_filename)
                ts.log('------------{}------------'.format(dataset_filename))
                daq.data_capture(True)

                for step_label, v_step in v_steps_dict.items():
                    ts.log(
                        'Voltage step: setting Grid simulator voltage to %s (%s)'
                        % (v_step, step_label))
                    ActiveFunction.start(daq=daq, step_label=step_label)

                    step_dict = {'V': v_step}
                    if grid is not None:
                        grid.voltage(step_dict['V'])

                    ActiveFunction.record_timeresponse(daq=daq)
                    ActiveFunction.evaluate_criterias(daq=daq,
                                                      step_dict=step_dict)
                    result_summary.write(ActiveFunction.write_rslt_sum())

                # create result workbook
                ts.log('Sampling complete')
                dataset_filename = dataset_filename + ".csv"
                daq.data_capture(False)
                ds = daq.data_capture_dataset()
                ts.log('Saving file: %s' % dataset_filename)
                ds.to_csv(ts.result_file_path(dataset_filename))
                result_params['plot.title'] = dataset_filename.split('.csv')[0]
                ts.result_file(dataset_filename, params=result_params)
                result = script.RESULT_COMPLETE

    except script.ScriptFail as e:
        reason = str(e)
        if reason:
            ts.log_error(reason)

    except Exception as e:
        if dataset_filename is not None:
            dataset_filename = dataset_filename + ".csv"
            daq.data_capture(False)
            ds = daq.data_capture_dataset()
            ts.log('Saving file: %s' % dataset_filename)
            ds.to_csv(ts.result_file_path(dataset_filename))
            result_params['plot.title'] = dataset_filename.split('.csv')[0]
            ts.result_file(dataset_filename, params=result_params)
        ts.log_error('Test script exception: %s' % traceback.format_exc())
        raise

    finally:
        if daq is not None:
            daq.close()
        if pv is not None:
            if p_rated is not None:
                pv.power_set(p_rated)
            pv.close()
        if grid is not None:
            if v_nom is not None:
                grid.voltage(v_nom)
            grid.close()
        if chil is not None:
            chil.close()
        if eut is not None:
            eut.close()
        if result_summary is not None:
            result_summary.close()

    return result