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
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) # 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+')
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)
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)
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
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
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
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)
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') # 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') 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('cpf.pf_response_time') # Imbalance configuration imbalance_fix = ts.param_value('cpf.imbalance_fix') # 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') """ A separate module has been create for the 1547.1 Standard """ lib_1547 = p1547.module_1547(ts=ts, aif='CPF', 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() # get target power factors pf_targets = {} if ts.param_value('cpf.pf_min_inj') == 'Enabled': pf_targets['cpf_min_ind'] = float( ts.param_value('cpf.pf_min_inj_value')) if ts.param_value('cpf.pf_mid_inj') == 'Enabled': pf_targets['cpf_mid_ind'] = float( ts.param_value('cpf.pf_mid_inj_value')) if ts.param_value('cpf.pf_min_ab') == 'Enabled': pf_targets['cpf_min_cap'] = float( ts.param_value('cpf.pf_min_ab_value')) if ts.param_value('cpf.pf_mid_ab') == 'Enabled': pf_targets['cpf_mid_cap'] = float( ts.param_value('cpf.pf_mid_ab_value')) v_in_targets = {} if v_nom_in_enabled == 'Enabled': v_in_targets['v_nom_in'] = v_nom_in if v_min_in != v_nom_in and v_min_in_enabled == 'Enabled': v_in_targets['v_min_in'] = v_min_in if v_max_in != v_nom_in and v_max_in_enabled == 'Enabled': v_in_targets['v_max_in'] = v_max_in if not v_in_targets: ts.log_error('No V_in target specify. Please select a V_IN test') raise """ 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 #das_points = {'sc': ('V_MEAS', 'P_MEAS', 'Q_MEAS', 'Q_TARGET_MIN', 'Q_TARGET_MAX', 'PF_TARGET', 'event')} 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'] = 120 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()) """ 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: eut.config() # disable volt/var curve #eut.volt_var(params={'Ena': False}) ts.log_debug( 'If not done already, set L/HVRT and trip parameters to the widest range of adjustability.' ) # 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) """ 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. The EUT may limit active power throughout the test to meet reactive power requirements. s) For an EUT with an input voltage range, repeat steps d) through o) for Vin_min and Vin_max. """ # TODO: Include step t) """ t) Steps d) through q) may be repeated to test additional communication protocols - Run with another test. """ # For PV systems, this requires that Vmpp = Vin_nom and Pmpp = Prated. for v_in_label, v_in in v_in_targets.iteritems(): ts.log('Starting test %s at v_in = %s' % (v_in_label, v_in)) a_v = lib_1547.MRA_V * 1.5 if pv is not None: pv.iv_curve_config(pmp=p_rated, vmp=v_in) pv.irradiance_set(1000.) """ e) Enable constant power factor mode and set the EUT power factor to PFmin,inj. r) Repeat steps d) through o) for additional power factor settings: PFmin,ab, PFmid,inj, PFmid,ab. Only the user-selected PF setting will be tested. """ for pf_test_name, pf_target in pf_targets.iteritems(): if grid is not None: grid.voltage(v_nom) #Setting up step label lib_1547.set_step_label(starting_label='F') ts.log('Starting data capture for pf = %s' % pf_target) if imbalance_fix == "Yes": dataset_filename = ('{0}_{1}_FIX'.format( v_in_label.upper(), pf_test_name.upper())) else: dataset_filename = ('{0}_{1}'.format( v_in_label.upper(), pf_test_name.upper())) ts.log('------------{}------------'.format(dataset_filename)) # Start the data acquisition systems daq.data_capture(True) daq.sc['PF_TARGET'] = pf_target if eut is not None: parameters = {'Ena': True, 'PF': pf_target} ts.log('PF set: %s' % parameters) eut.fixed_pf(params=parameters) pf_setting = eut.fixed_pf() ts.log('PF setting read: %s' % pf_setting) """ f) 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 = lib_1547.get_step_label() daq.sc['event'] = step daq.data_sample() ts.log('Wait for steady state to be reached') ts.sleep(2 * pf_response_time) """ g) Step the EUT's active power to Pmin. """ if pv is not None: step = lib_1547.get_step_label() ts.log( 'Power step: setting PV simulator power to %s (%s)' % (p_min, step)) initial_values = lib_1547.get_initial_value(daq=daq, step=step) step_dict = {'V': v_nom, 'P': p_min, 'PF': pf_target} pv.power_set(step_dict['P']) lib_1547.process_data( daq=daq, tr=pf_response_time, step=step, #curve=vw_curve, pwr_lvl=1.0, x_target=step_dict, initial_value=initial_values, result_summary=result_summary, filename=dataset_filename) """ h) Step the EUT's available active power to Prated. """ if pv is not None: step = lib_1547.get_step_label() ts.log( 'Power step: setting PV simulator power to %s (%s)' % (p_rated, step)) initial_values = lib_1547.get_initial_value(daq=daq, step=step) step_dict = {'V': v_nom, 'P': p_rated, 'PF': pf_target} pv.power_set(step_dict['P']) lib_1547.process_data( daq=daq, tr=pf_response_time, step=step, #curve=vw_curve, pwr_lvl=1.0, x_target=step_dict, initial_value=initial_values, result_summary=result_summary, filename=dataset_filename) if grid is not None: # i) Step the AC test source voltage to (VL + av) step = lib_1547.get_step_label() ts.log( 'Voltage step: setting Grid simulator voltage to %s (%s)' % ((v_min + a_v), step)) #q_initial = lib_1547.get_initial(daq=daq,step=step) initial_values = lib_1547.get_initial_value(daq=daq, step=step) step_dict = { 'V': v_min + a_v, 'P': p_rated, 'PF': pf_target } grid.voltage(step_dict['V']) lib_1547.process_data(daq=daq, tr=pf_response_time, step=step, pwr_lvl=1.0, x_target=step_dict, initial_value=initial_values, result_summary=result_summary, filename=dataset_filename) # j) Step the AC test source voltage to (VH - av) step = lib_1547.get_step_label() ts.log( 'Voltage step: setting Grid simulator voltage to %s (%s)' % ((v_max - a_v), step)) initial_values = lib_1547.get_initial_value(daq=daq, step=step) step_dict = { 'V': v_min - a_v, 'P': p_rated, 'PF': pf_target } grid.voltage(step_dict['V']) lib_1547.process_data( daq=daq, tr=pf_response_time, step=step, #curve=vw_curve, pwr_lvl=1.0, x_target=step_dict, initial_value=initial_values, result_summary=result_summary, filename=dataset_filename) # k) Step the AC test source voltage to (VL + av) step = lib_1547.get_step_label() ts.log( 'Voltage step: setting Grid simulator voltage to %s (%s)' % (v_nom, step)) #q_initial = lib_1547.get_initial(daq=daq,step=step) initial_values = lib_1547.get_initial_value(daq=daq, step=step) step_dict = { 'V': v_min + a_v, 'P': p_rated, 'PF': pf_target } grid.voltage(step_dict['V']) lib_1547.process_data( daq=daq, tr=pf_response_time, step=step, #curve=vw_curve, pwr_lvl=1.0, x_target=step_dict, initial_value=initial_values, result_summary=result_summary, filename=dataset_filename) if grid is not None and phases is 'Three phase': """ l) For multiphase units, step the AC test source voltage to Vnom. """ step = lib_1547.get_step_label() ts.log( 'Voltage step: setting Grid simulator voltage to %s (%s)' % (v_nom, step)) initial_values = lib_1547.get_initial_value(daq=daq, step=step) step_dict = {'V': v_nom, 'P': p_rated, 'PF': pf_target} grid.voltage(step_dict['V']) lib_1547.process_data(daq=daq, tr=pf_response_time, step=step, pwr_lvl=1.0, x_target=step_dict, initial_value=initial_values, result_summary=result_summary, filename=dataset_filename) if grid is not None and phases is 'Three phase': """ m) For multiphase units, step the AC test source voltage to Case A from Table 24. """ step = lib_1547.get_step_label() ts.log( 'Voltage step: setting Grid simulator voltage to %s (%s)' % (v_nom, step)) initial_values = lib_1547.get_initial_value(daq=daq, step=step) step_dict = { 'V': v_nom * (1.07 + 0.91 + 0.91) / 3, 'P': p_rated, 'PF': pf_target } lib_1547.set_grid_asymmetric(grid=grid, case='case_a') #grid.voltage(step_dict['V']) lib_1547.process_data(daq=daq, tr=pf_response_time, step=step, pwr_lvl=1.0, x_target=step_dict, initial_value=initial_values, result_summary=result_summary, filename=dataset_filename) """ n) For multiphase units, step the AC test source voltage to VN. """ if grid is not None and phases is 'Three phase': step = lib_1547.get_step_label() ts.log( 'Voltage step: setting Grid simulator voltage to %s (%s)' % (v_nom, step)) initial_values = lib_1547.get_initial_value(daq=daq, step=step) step_dict = {'V': v_nom, 'P': p_rated, 'PF': pf_target} grid.voltage(step_dict['V']) lib_1547.process_data(daq=daq, tr=pf_response_time, step=step, pwr_lvl=1.0, x_target=step_dict, initial_value=initial_values, result_summary=result_summary, filename=dataset_filename) ''' o) For multiphase units, step the AC test source voltage to Case B from Table 24. ''' if grid is not None and phases is 'Three phase': step = lib_1547.get_step_label() ts.log( 'Voltage step: setting Grid simulator to case B (IEEE 1547.1-Table 24)(%s)' % step) initial_values = lib_1547.get_initial_value(daq=daq, step=step) # TODO READJUST WITH INVERTER CALCULATION WITH IMBALANCED GRID step_dict = { 'V': v_nom * (0.91 + 1.07 + 1.07) / 3, 'P': p_rated, 'PF': pf_target } lib_1547.set_grid_asymmetric(grid=grid, case='case_b') lib_1547.process_data(daq=daq, tr=pf_response_time, step=step, pwr_lvl=1.0, x_target=step_dict, initial_value=initial_values, result_summary=result_summary, filename=dataset_filename) """ p) For multiphase units, step the AC test source voltage to Vnom. """ if grid is not None and phases is 'Three phase': step = lib_1547.get_step_label() ts.log( 'Voltage step: setting Grid simulator voltage to %s (%s)' % (v_nom, step)) initial_values = lib_1547.get_initial_value(daq=daq, step=step) step_dict = {'V': v_nom, 'P': p_rated, 'PF': pf_target} grid.voltage(step_dict['V']) lib_1547.process_data(daq=daq, tr=pf_response_time, step=step, pwr_lvl=1.0, x_target=step_dict, initial_value=initial_values, result_summary=result_summary, filename=dataset_filename) """ q) Disable constant power factor mode. Power factor should return to unity. """ if eut is not None: #parameters = {'Ena': False, 'PF': 1.0} #ts.log('PF set: %s' % parameters) #eut.fixed_pf(params=parameters) step = lib_1547.get_step_label() pf_setting = eut.fixed_pf() ts.log('PF setting read: %s' % pf_setting) daq.sc['event'] = 'Step %s' % step daq.data_sample() ts.sleep(2 * pf_response_time) daq.sc['event'] = 'T_settling_done' daq.data_sample() """ r) Verify all reactive/active power control functions are disabled. """ if eut is not None: ts.log( 'Reactive/active power control functions are disabled.' ) # TODO Implement ts.prompt functionality? #meas = eut.measurements() #ts.log('EUT PF is now: %s' % (data.get('AC_PF_1'))) #ts.log('EUT Power: %s, EUT Reactive Power: %s' % (meas['W'], meas['VAr'])) 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)
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
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 fw_curves = [] fw_response_time = [0, 0, 0] filename = None result_params = 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') # 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') 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') # 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')) # VW parameters absorb = {} absorb['ena'] = ts.param_value('eut_vw.sink_power') """ A separate module has been create for the 1547.1 Standard """ ActiveFunction = p1547.ActiveFunction(ts=ts, functions=[LAP, FW, VW], script_name='Limit Active Power', 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() # Set Test parameter act_pwrs = ts.param_value('lap.act_pwr') # List of power level for tests ts.log_debug('%s' % (act_pwrs)) if act_pwrs == '0%': act_pwrs_limits = [0.0] elif act_pwrs == '33%': act_pwrs_limits = [0.33] elif act_pwrs == '66%': act_pwrs_limits = [0.66] else: act_pwrs_limits = [0.66, 0.33, 0.0] # 5.13.2 Procedure asks for three repetitions n_iters = list(range(1, int(ts.param_value('lap.iter')) + 1)) # Take the highest value for the steady state wait time tr_min = min(ts.param_value('lap.test_vw_1_tr'), ts.param_value('lap.test_fw_1_tr')) tr_vw = ts.param_value('lap.test_vw_1_tr') """ a) - Connect the EUT according to the instructions and specifications provided by the manufacturer. - Apply the default settings from IEEE std 1547 for voltage-active power mode (Minimum setting of table 10 of IEEE 1547) - Apply the default settings from frequency droop response in IEE std 1547 for abnormal operating perfomance category of the DER - Enable voltage active power mode """ # 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) 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() ts.log(das_points) # initialize data acquisition daq = das.das_init(ts, sc_points=das_points['sc'], support_interfaces={ 'pvsim': pv, 'hil': chil }) if daq is not None: ts.log('DAS device: %s' % daq.info()) eut = der.der_init(ts, support_interfaces={'hil': chil}) if eut is not None: eut.config() # Enable volt/watt curve and configure default settings v_pairs = ActiveFunction.get_params(curve=1, function=VW) 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', 'RmpTms': tr_vw } vw_params = {'Ena': True, 'ActCrv': 1, 'curve': vw_curve_params} eut.volt_watt(params=vw_params) # Enable freq/watt curve and configure default settings fw_curve_params = ActiveFunction.get_params(function=FW, curve=1) fw_params = { 'Ena': True, 'curve': 1, 'dbf': fw_curve_params['dbf'], 'kof': fw_curve_params['kof'], 'RspTms': fw_curve_params['TR'] } eut.freq_watt(fw_params) 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.frt_stay_connected_high( params={ 'Ena': True, 'ActCrv': 0, 'Tms1': 3000, 'Hz1': f_max, 'Tms2': 160, 'Hz2': f_max }) except Exception as e: ts.log_error( 'Could not set FRT 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) try: eut.frt_stay_connected_low( params={ 'Ena': True, 'ActCrv': 0, 'Tms1': 3000, 'Hz1': f_min, 'Tms2': 160, 'Hz2': f_min }) except Exception as e: ts.log_error('Could not set FRT Stay Connected Low curve. %s' % e) ts.log_debug( 'If not done already, set L/HVRT and trip parameters to the widest range of adjustability.' ) # 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) # Configure Grid simulator 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()) """ g) Repeat steps b) through f using active power limits of 33% and zero h) Repeat steps b) through g) twice for a total of three repetitions """ if chil is not None: ts.log('Start simulation of CHIL') chil.start_simulation() for n_iter in n_iters: for act_pwrs_limit in act_pwrs_limits: """ b) - Establish nominal operating conditions as specified by the manufacturer at the terminals of the EUT. - Make available sufficient input power for the EUT to reach its rated active power. - Allow (or command) the EUT to reach steady-state output at its rated active power - Begin recording EUT active power """ ts.log('Starting test no. %s with active power limit to %s ' % (n_iter, act_pwrs_limit)) ActiveFunction.reset_pwr(pwr=act_pwrs_limit) ActiveFunction.reset_time_settings(tr=tr_min) # For PV systems, this requires that Vmpp = Vin_nom and Pmpp = Prated. if pv is not None: pv.iv_curve_config(pmp=p_rated, vmp=v_nom_in) pv.irradiance_set(1000.) ts.log('EUT Config: setting Active Power Limit to 100%') if eut is not None: # limit maximum power eut.limit_max_power( params={ 'Ena': True, 'WMaxPct': 100, 'WinTms': 0, 'RmpTms': 0, 'RvrtTms': 0.0 }) ts.sleep(2 * tr_min) daq.data_capture(True) filename = ('LAP_{0}_{1}'.format(act_pwrs_limit, n_iter)) ActiveFunction.reset_filename(filename=filename) ts.log('------------{}------------'.format(filename)) """ c) - Apply an active power limit to the EUT of 66% of its rated power. - Wait until the EUT active power reaches a new steady state """ # Setting up step label ActiveFunction.set_step_label(starting_label='C') step_label = ActiveFunction.get_step_label() daq.sc['event'] = step ActiveFunction.start(daq=daq, step_label=step_label) #initial_values = ActiveFunction.get_initial_value(daq=daq, step=step) ts.log('EUT Config: setting Active Power Limit to %s (%s)' % (act_pwrs_limit, step)) if eut is not None: # limit maximum power eut.limit_max_power( params={ 'MaxLimWEna': True, 'MaxLimW_PCT': act_pwrs_limit * 100, 'WinTms': 0, 'RmpTms': 0, 'RvrtTms': 0.0 }) step_dict = {'V': v_nom, 'F': f_nom, 'P': act_pwrs_limit} #target_dict = {'P': act_pwrs_limit} ActiveFunction.record_timeresponse(daq=daq) ts.log_debug(f'daq={daq}') ActiveFunction.evaluate_criterias(daq=daq, step_dict=step_dict, y_criterias_mod={'P': LAP}) result_summary.write(ActiveFunction.write_rslt_sum()) """ d) - Reduce the frequency of the AC test to 59 Hz and hold until EUT active power reaches a new steady state - Return AC test frequency to nominal and Hold until new states reached """ f_steps = [59.0, f_nom] step_label = ActiveFunction.get_step_label() if grid is not None: for f_step in f_steps: step_ = step_label + "_" + str(f_step) ts.log( 'Frequency step: setting Grid simulator frequency to %s (%s)' % (f_step, step_)) ActiveFunction.start(daq=daq, step_label=step_) #initial_values = ActiveFunction.get_initial_value(daq=daq,step=step_) grid.freq(f_step) step_dict = { 'V': v_nom, 'F': f_step, 'P': act_pwrs_limit } ActiveFunction.record_timeresponse(daq=daq) ActiveFunction.evaluate_criterias( daq=daq, step_dict=step_dict, y_criterias_mod={'P': FW}) result_summary.write(ActiveFunction.write_rslt_sum()) """ e) - Increase the frequency of the AC test to 61 Hz and hold until EUT active power reaches a new steady state - Return AC test frequency to nominal and Hold until new states reached """ f_steps = [61.0, f_nom] step_label = ActiveFunction.get_step_label() if grid is not None: for f_step in f_steps: step_ = step_label + "_" + str(f_step) ts.log( 'Frequency step: setting Grid simulator frequency to %s (%s)' % (f_step, step_)) ActiveFunction.start(daq=daq, step_label=step_) #initial_values = ActiveFunction.get_initial_value(daq=daq,step=step_) grid.freq(f_step) step_dict = { 'V': v_nom, 'F': f_step, 'P': act_pwrs_limit } ActiveFunction.record_timeresponse(daq=daq) ActiveFunction.evaluate_criterias( daq=daq, step_dict=step_dict, y_criterias_mod={'P': FW}) result_summary.write(ActiveFunction.write_rslt_sum()) """ f) - Increase the voltage of the AC test to 1.08 times nominal and hold until EUT active power reaches a new steady state - Return AC test voltage to nominal and Hold until new states reached """ v_steps = [1.08 * v_nom, v_nom] step_label = ActiveFunction.get_step_label() if grid is not None: for v_step in v_steps: step_ = step_label + "_" + str(v_step) ts.log( 'Voltage step: setting Grid simulator voltage to %s (%s)' % (v_step, step_)) #initial_values = ActiveFunction.get_initial_value(daq=daq,step=step_) ActiveFunction.start(daq=daq, step_label=step_) grid.voltage(v_step) step_dict = { 'V': v_step, 'F': f_nom, 'P': act_pwrs_limit } ActiveFunction.record_timeresponse(daq=daq) ActiveFunction.evaluate_criterias( daq=daq, step_dict=step_dict, y_criterias_mod={'P': VW}) 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 = 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.fixed_pf(params={'Ena': False, 'PF': 1.0}) 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
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_label = 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('crp.v_in_nom') v_min_in_enabled = ts.param_value('crp.v_in_min') v_max_in_enabled = ts.param_value('crp.v_in_max') v_nom_in = ts.param_value('eut.v_in_nom') v_min_in = ts.param_value('eut_crp.v_in_min') v_max_in = ts.param_value('eut_crp.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('crp.pf_response_time') # Pass/fail accuracies pf_msa = ts.param_value('eut.pf_msa') # Imbalance configuration imbalance_fix = ts.param_value('crp.imbalance_fix') # EUI Absorb capabilities absorb = {} absorb['ena'] = ts.param_value('eut_crp.sink_power') absorb['p_rated_prime'] = ts.param_value('eut_crp.p_rated_prime') absorb['p_min_prime'] = ts.param_value('eut_crp.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='CRP', script_name='Constant Reactive Power', criteria_mode=[True, False, False]) ActiveFunction.set_imbalance_config(imbalance_angle_fix=imbalance_fix) ts.log_debug("1547.1 Library configured for %s" % ActiveFunction.get_script_name()) # result params result_params = ActiveFunction.get_rslt_param_plot() #get target q relative value q_targets = {} if ts.param_value('crp.q_max_abs_enable') == 'Enabled': q_targets['crp_q_max_abs'] = float( ts.param_value('crp.q_max_abs_value')) if ts.param_value('crp.q_max_inj_enable') == 'Enabled': q_targets['crp_q_max_inj'] = float( ts.param_value('crp.q_max_inj_value')) if ts.param_value('crp.half_q_max_abs_enable') == 'Enabled': q_targets['crp_half_q_max_abs'] = 0.5 * float( ts.param_value('crp.q_max_abs_value')) if ts.param_value('crp.half_q_max_inj_enable') == 'Enabled': q_targets['crp_half_q_max_inj'] = 0.5 * float( ts.param_value('crp.q_max_inj_value')) #get q max value #q_max_value = ts.param_value('crp.q_max_value') v_in_targets = {} if v_nom_in_enabled == 'Enabled': v_in_targets['v_nom_in'] = v_nom_in if v_min_in != v_nom_in and v_min_in_enabled == 'Enabled': v_in_targets['v_min_in'] = v_min_in if v_max_in != v_nom_in and v_max_in_enabled == 'Enabled': v_in_targets['v_max_in'] = v_max_in if not v_in_targets: ts.log_error('No V_in target specify. Please select a V_IN test') """ 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) 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 = {'sc': ('V_MEAS', 'P_MEAS', 'Q_MEAS', 'Q_TARGET_MIN', 'Q_TARGET_MAX', 'PF_TARGET', 'event')} das_points = ActiveFunction.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()) """ 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: eut.config() # disable volt/var curve #eut.volt_var(params={'Ena': False}) ts.log_debug( 'If not done already, set L/HVRT and trip parameters to the widest range of adjustability.' ) # 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) """ 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. The EUT may limit active power throughout the test to meet reactive power requirements. s) For an EUT with an input voltage range, repeat steps d) through o) for Vin_min and Vin_max. """ # TODO: Include step t) """ t) Steps d) through q) may be repeated to test additional communication protocols - Run with another test. """ # For PV systems, this requires that Vmpp = Vin_nom and Pmpp = Prated. for v_in_label, v_in in v_in_targets.items(): ts.log('Starting test %s at v_in = %s' % (v_in_label, v_in)) a_v = ActiveFunction.MRA['V'] * 1.5 #Set response time recording ActiveFunction.reset_time_settings(tr=pf_response_time) if pv is not None: pv.iv_curve_config(pmp=p_rated, vmp=v_in) pv.irradiance_set(1000.) """ e) Enable constant power factor mode and set the EUT power factor to PFmin,inj. r) Repeat steps d) through o) for additional power factor settings: PFmin,ab, PFmid,inj, PFmid,ab. Only the user-selected PF setting will be tested. """ for q_test_name, q_target in q_targets.items(): # Setting up step label ActiveFunction.set_step_label(starting_label='F') q_target *= var_rated ts.log('Starting data capture for fixed Q relative = %s' % q_target) if imbalance_fix == "Yes": dataset_filename = ('{0}_{1}_FIX'.format( v_in_label.upper(), q_test_name.upper())) else: dataset_filename = ('{0}_{1}'.format( v_in_label.upper(), q_test_name.upper())) ts.log('------------{}------------'.format(dataset_filename)) ActiveFunction.reset_filename(filename=dataset_filename) # Start the data acquisition systems daq.data_capture(True) daq.sc['Q_TARGET'] = q_target if eut is not None: parameters = {'Ena': True, 'Q': q_target, 'Wmax': p_rated} ts.log('Parameters set: %s' % parameters) eut.reactive_power(params=parameters) vars_setting = eut.reactive_power(params=parameters) ts.log('fixed vars setting read: %s' % vars_setting) """ f) Verify Constant Var mode is reported as active and that the power factor setting is reported as Qmax,inj. """ step_label = ActiveFunction.get_step_label() daq.sc['event'] = step_label daq.data_sample() ts.log('Wait for steady state to be reached') ts.sleep(2 * pf_response_time) """ g) Step the EUT's active power to 20% of Prated or Pmin, whichever is less. """ if pv is not None: step_label = ActiveFunction.get_step_label() ts.log( 'Power step: setting PV simulator power to %s (%s)' % (p_min, step_label)) ActiveFunction.start(daq=daq, step_label=step_label) if p_rated * 0.2 > p_min: p_target = p_min else: p_target = p_rated * 0.2 step_dict = { 'V': v_nom, 'P': round(p_target, 2), 'Q': q_target } 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()) """ h) Step the EUT's active power to 5% of Prated or Pmin, whichever is less. """ if pv is not None: step_label = ActiveFunction.get_step_label() ts.log( 'Power step: setting PV simulator power to %s (%s)' % (p_min, step_label)) ActiveFunction.start(daq=daq, step_label=step_label) if p_rated * 0.05 > p_min: p_target = p_min else: p_target = p_rated * 0.05 step_dict = { 'V': v_nom, 'P': round(p_target, 2), 'Q': q_target } 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()) """ i) Step the EUT's available active power to Prated. """ if pv is not None: step_label = ActiveFunction.get_step_label() ts.log( 'Power step: setting PV simulator power to %s (%s)' % (p_rated, step_label)) ActiveFunction.start(daq=daq, step_label=step_label) step_dict = {'V': v_nom, 'P': p_rated, 'Q': q_target} 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()) if grid is not None: # J) Step the AC test source voltage to (VL + av) step_label = ActiveFunction.get_step_label() ts.log( 'Voltage step: setting Grid simulator voltage to %s (%s)' % ((v_min + a_v), step_label)) ActiveFunction.start(daq=daq, step_label=step_label) step_dict = {'V': v_min + a_v, 'P': p_rated, 'Q': q_target} 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()) # k) Step the AC test source voltage to (VH - av) step_label = ActiveFunction.get_step_label() ts.log( 'Voltage step: setting Grid simulator voltage to %s (%s)' % ((v_max - a_v), step_label)) ActiveFunction.start(daq=daq, step_label=step_label) step_dict = {'V': v_max - a_v, 'P': p_rated, 'Q': q_target} 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()) # l) Step the AC test source voltage to (VL + av) step_label = ActiveFunction.get_step_label() ts.log( 'Voltage step: setting Grid simulator voltage to %s (%s)' % ((v_min + a_v), step_label)) ActiveFunction.start(daq=daq, step_label=step_label) step_dict = {'V': v_min + a_v, 'P': p_rated, 'Q': q_target} 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()) if phases == 'Three phase': # m) For multiphase units, step the AC test source voltage to VN 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) step_dict = {'V': v_nom, 'P': p_rated, 'Q': q_target} 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()) ''' n) For multiphase units, step the AC test source voltage to Case A from Table 24. ''' if grid is not None and phases == 'Three phase': 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, 'P': p_rated, 'Q': q_target } ActiveFunction.record_timeresponse(daq=daq) ActiveFunction.evaluate_criterias(daq=daq, step_dict=step_dict) result_summary.write(ActiveFunction.write_rslt_sum()) """ o) For multiphase units, step the AC test source voltage to VN. """ if grid is not None and phases == 'Three phase': 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) step_dict = {'V': v_nom, 'P': p_rated, 'Q': q_target} 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()) """ p) For multiphase units, step the AC test source voltage to Case B from Table 24. """ if grid is not None and phases == 'Three phase': 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, 'P': p_rated, 'Q': q_target } ActiveFunction.record_timeresponse(daq=daq) ActiveFunction.evaluate_criterias(daq=daq, step_dict=step_dict) result_summary.write(ActiveFunction.write_rslt_sum()) """ q) For multiphase units, step the AC test source voltage to VN """ if grid is not None and phases == 'Three phase': 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) step_dict = {'V': v_nom, 'P': p_rated, 'Q': q_target} 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()) """ r) Disable constant power factor mode. Power factor should return to unity. """ if eut is not None: parameters = {'Ena': False} #ts.log('PF set: %s' % parameters) eut.fixed_var(params=parameters) var_setting = eut.fixed_var() ts.log('Reactive Power setting read: %s' % vars_setting) daq.sc['event'] = ActiveFunction.get_step_label() daq.data_sample() ts.sleep(4 * pf_response_time) daq.sc['event'] = 'T_settling_done' daq.data_sample() """ q) Verify all reactive/active power control functions are disabled. """ if eut is not None: ts.log( 'Reactive/active power control functions are disabled.' ) # TODO Implement ts.prompt functionality? # meas = eut.measurements() # ts.log('EUT PF is now: %s' % (data.get('AC_PF_1'))) # ts.log('EUT Power: %s, EUT Reactive Power: %s' % (meas['W'], meas['VAr'])) 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 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.reactive_power(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
def test_run(): eut = None chil = None pv = None result = script.RESULT_FAIL try: # Get the parameters for the test from the UI pf_start = ts.param_value('test.pf_start') pf_end = ts.param_value('test.pf_stop') steps = ts.param_value('test.pf_steps_per_side') sleep_time = ts.param_value('test.wait_time') # 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(800) pv.power_on() # Print information from the DER 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('---') fixed_pf = eut.fixed_pf() if fixed_pf is not None: ts.log('DER fixed_pf:') ts.log(' Ena: %s' % (fixed_pf.get('Ena'))) ts.log(' PF: %s' % (fixed_pf.get('PF'))) ts.log(' WinTms: %s' % (fixed_pf.get('WinTms'))) ts.log(' RmpTms: %s' % (fixed_pf.get('RmpTms'))) ts.log(' RvrtTms: %s' % (fixed_pf.get('RvrtTms'))) else: ts.log_warning('DER fixed_pf not supported') ts.log('---') # Get EUT nameplate power eut_nameplate_power = eut.nameplate().get('WRtg') # disable volt/var, VW, FW eut.volt_var(params={'Ena': False}) eut.volt_watt(params={'Ena': False}) eut.freq_watt(params={'Ena': False}) inv_power = eut.measurements().get('W') timeout = 120. if inv_power <= eut_nameplate_power / 10.: pv.irradiance_set(800) # Perturb the pv slightly to start the inverter ts.sleep(3) eut.connect(params={'Conn': True}) 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.') # Create list of the power factor values to iterate over pf_values = list(np.linspace(pf_start, 1.0, num=steps)) + list(np.linspace(-1.0, pf_end, num=steps)[1:]) # ts.log('Setting DER to the following PF values: %s' % pf_values) # Run the test for 3 different irradiance values for irr in [1000, 600, 300]: pv.irradiance_set(irr) # Set irradiance of the PV simulator for pf in pf_values: # Send PF setting to the equipment under test (EUT) eut.fixed_pf(params={'Ena': True, 'PF': pf, 'WinTms': 0, 'RmpTms': 0, 'RvrtTms': 0}) ts.log('Power Factor set to %0.3f. Sleeping for %0.2f seconds...' % (pf, sleep_time)) ts.sleep(sleep_time) # Disable the PF function eut.fixed_pf(params={'Ena': False}) ts.log('Power Factor Disabled') result = script.RESULT_COMPLETE except Exception, e: ts.log_error('Script failure: %s' % e)
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 result_params = 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('crp.v_in_nom') v_min_in_enabled = ts.param_value('crp.v_in_min') v_max_in_enabled = ts.param_value('crp.v_in_max') v_nom_in = ts.param_value('eut.v_in_nom') v_min_in = ts.param_value('eut_crp.v_in_min') v_max_in = ts.param_value('eut_crp.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') response_time = ts.param_value('crp.response_time') # Imbalance configuration imbalance_fix = ts.param_value('crp.imbalance_fix') # EUI Absorb capabilities absorb = {} absorb['ena'] = ts.param_value('eut_crp.sink_power') absorb['p_rated_prime'] = ts.param_value('eut_crp.p_rated_prime') absorb['p_min_prime'] = ts.param_value('eut_crp.p_min_prime') """ A separate module has been create for the 1547.1 Standard """ lib_1547 = p1547.module_1547(ts=ts, aif='CRP', 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() # get target q relative value q_targets = {} if ts.param_value('crp.q_max_abs_enable') == 'Enabled': q_targets['crp_q_max_abs'] = float( ts.param_value('crp.q_max_abs_value')) if ts.param_value('crp.q_max_inj_enable') == 'Enabled': q_targets['crp_q_max_inj'] = float( ts.param_value('crp.q_max_inj_value')) if ts.param_value('crp.half_q_max_abs_enable') == 'Enabled': q_targets['crp_half_q_max_abs'] = 0.5 * float( ts.param_value('crp.q_max_abs_value')) if ts.param_value('crp.half_q_max_inj_enable') == 'Enabled': q_targets['crp_half_q_max_inj'] = 0.5 * float( ts.param_value('crp.q_max_inj_value')) ts.log('Evaluating the following Reactive Power Targets: %s' % q_targets) v_in_targets = {} if v_nom_in_enabled == 'Enabled': v_in_targets['v_nom_in'] = v_nom_in if v_min_in != v_nom_in and v_min_in_enabled == 'Enabled': v_in_targets['v_min_in'] = v_min_in if v_max_in != v_nom_in and v_max_in_enabled == 'Enabled': v_in_targets['v_max_in'] = v_max_in if not v_in_targets: raise ts.log_error( 'No V_in target specify. Please select a V_IN test') """ 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) if pv is not None: pv.power_set(p_rated) pv.power_on() # Turn on DC so the EUT can be initialized start_up = 60 ts.log('Waiting for EUT to power up. Sleeping %s sec.' % start_up) ts.sleep(start_up) das_points = lib_1547.get_sc_points() # DAS soft channels # initialize data acquisition daq = das.das_init(ts, sc_points=das_points['sc'], support_interfaces={ 'pvsim': pv, 'hil': chil }) if daq is not None: daq.sc['V_MEAS'] = None daq.sc['P_MEAS'] = None daq.sc['Q_MEAS'] = None daq.sc['Q_TARGET_MIN'] = None daq.sc['Q_TARGET_MAX'] = None daq.sc['PF_TARGET'] = None 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: eut.config() eut.volt_var(params={'Ena': False}) # disable volt/var curve eut.watt_var(params={'Ena': False}) eut.volt_watt(params={'Ena': False}) ts.log_debug( 'If not done already, set L/HVRT and trip parameters to the widest range of adjustability.' ) # 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) """ 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()) """ v) Steps d) through s) may be repeated to test additional protocols methods. (Rerun script in those cases) u) For an EUT with an input voltage range, repeat steps d) through t) for Vin_min and Vin_max """ # For PV systems, this requires that Vmpp = Vin_nom and Pmpp = Prated. for v_in_label, v_in in v_in_targets.iteritems(): ts.log('Starting test %s at v_in = %s' % (v_in_label, v_in)) a_v = lib_1547.MRA_V * 1.5 if pv is not None: pv.iv_curve_config(pmp=p_rated, vmp=v_in) pv.irradiance_set(1000.) ts.sleep(60.) # Give EUT time to track new I-V Curve """ t) Repeat steps d) through s) for additional reactive power settings: Qmax,ab, 0.5Qmax,inj, 0.5Qmax,ab. d) Adjust the EUT's active power to Prated. For an EUT with an input voltage range, set the input voltage to Vin_nom. (previously completed) e) Enable constant power factor mode and set the EUT power factor to PFmin,inj. """ for q_test_name, q_target in q_targets.iteritems(): dataset_filename = '%s_v=%0.1f' % (q_test_name, v_in) ts.log('------------{}------------'.format(dataset_filename)) q_target *= var_rated ts.log('Starting data capture for fixed Q relative = %s' % q_target) daq.data_capture(True) # Start the data acquisition systems daq.sc['Q_TARGET'] = q_target if eut is not None: parameters = { 'Ena': True, 'VArPct_Mod': 1, # 1 = WMax percentage 'VArWMaxPct': (100. * q_target) / var_rated } ts.log('Parameters set: %s' % parameters) eut.reactive_power(params=parameters) """ f) Verify Constant Var mode is reported as active and that the reactive power setting is reported as Qmax,inj. """ ts.log('Waiting 15 seconds before reading back parameters') ts.sleep(15) vars_setting = eut.reactive_power() ts.log('fixed vars setting read: %s' % vars_setting) """ g) Step the EUT's active power to 20% of Prated or Pmin, whichever is less. h) Step the EUT's active power to 5% of Prated or Pmin, whichever is less. i) Step the EUT's available active power to Prated. j) Step the AC test source voltage to (VL + av). k) Step the AC test source voltage to (VH - av). l) Step the AC test source voltage to (VL + av). m) For multiphase units, step the AC test source voltage to VN. n) For multiphase units, step the AC test source voltage to Case A from Table 24. o) For multiphase units, step the AC test source voltage to VN. p) For multiphase units, step the AC test source voltage to Case B from Table 24. q) For multiphase units, step the AC test source voltage to VN. """ lib_1547.set_step_label(starting_label='G') crp_dict = collections.OrderedDict() crp_dict[lib_1547.get_step_label()] = { 'p_pv': min(0.2 * p_rated, p_min) } # G crp_dict[lib_1547.get_step_label()] = { 'p_pv': min(0.05 * p_rated, p_min) } # H crp_dict[lib_1547.get_step_label()] = {'p_pv': p_rated} # I crp_dict[lib_1547.get_step_label()] = {'V': v_min + a_v} # J crp_dict[lib_1547.get_step_label()] = {'V': v_max - a_v} # K crp_dict[lib_1547.get_step_label()] = {'V': v_min + a_v} # L crp_dict[lib_1547.get_step_label()] = {'V': v_nom} # M if imbalance_fix == "Yes": crp_dict[lib_1547.get_step_label()] = { 'V': [v_nom * 1.07, v_nom * 0.91, v_nom * 0.91] } # N crp_dict[lib_1547.get_step_label()] = {'V': v_nom} # O crp_dict[lib_1547.get_step_label()] = { 'V': [v_nom * 0.91, v_nom * 1.07, v_nom * 1.07] } # P crp_dict[lib_1547.get_step_label()] = {'V': v_nom} # Q for step_label, step_change in crp_dict.iteritems(): daq.data_sample() initial_values = lib_1547.get_initial_value( daq=daq, step=step_label) if pv is not None and step_change.get('p_pv') is not None: pwr_lvl = step_change.get('p_pv') ts.log( 'Power step: setting PV simulator power to %s (%s)' % (pwr_lvl, step)) pv.power_set(pwr_lvl) if grid is not None and step_change.get('V') is not None: volt = step_change.get('V') ts.log( 'Voltage step: setting grid simulator voltage to %s (%s)' % (volt, step)) grid.voltage(volt) lib_1547.process_data(daq=daq, tr=response_time, step=step_label, pwr_lvl=1.0, y_target=q_target, initial_value=initial_values, result_summary=result_summary, filename=dataset_filename, number_of_tr=1) """ r) Disable constant reactive power mode. Reactive power should return to zero. s) Verify all reactive/active power control functions are disabled. """ if eut is not None: ts.log('Reactive Power disabled. Readback: %s' % eut.reactive_power(params={'Ena': False})) step_label = lib_1547.get_step_label() ts.log( 'Waiting %s seconds to get the next Tr data for analysis...' % response_time) ts.sleep(response_time) daq.data_sample() # sample new data data = daq.data_capture_read( ) # Return dataset created from last data capture q_meas = lib_1547.get_measurement_total(data=data, type_meas='Q', log=False) daq.sc['Q_MEAS'] = q_meas daq.sc['Q_TARGET'] = 0.0 daq.sc['EVENT'] = "{0}_TR_1".format(step_label) daq.sc[ 'Q_TARGET_MIN'] = daq.sc['Q_TARGET'] - 1.5 * lib_1547.MRA_Q daq.sc[ 'Q_TARGET_MAX'] = daq.sc['Q_TARGET'] + 1.5 * lib_1547.MRA_Q if daq.sc['Q_TARGET_MIN'] <= daq.sc['Q_MEAS'] <= daq.sc[ 'Q_TARGET_MAX']: daq.sc['90%_BY_TR=1'] = 'Pass' else: daq.sc['90%_BY_TR=1'] = 'Fail' ts.log_debug( 'Disabled CRP: q_min [%s] <= q_meas [%s] <= q_max [%s] = %s' % (daq.sc['Q_TARGET_MIN'], daq.sc['Q_MEAS'], daq.sc['Q_TARGET_MAX'], daq.sc['90%_BY_TR=1'])) daq.data_sample() # 90%_BY_TR=1, V_MEAS, V_TARGET, P_MEAS, P_TARGET, Q_MEAS, Q_TARGET, Q_TARGET_MIN, # Q_TARGET_MAX, PF_MEAS, STEP, FILENAME row_data = [] row_data.append(str(daq.sc['90%_BY_TR=1'])) row_data.append( str( lib_1547.get_measurement_total(data=data, type_meas='V', log=False))) row_data.append('None') row_data.append( str( lib_1547.get_measurement_total(data=data, type_meas='P', log=False))) row_data.append('None') row_data.append(str(daq.sc['Q_MEAS'])) row_data.append(str(daq.sc['Q_TARGET'])) row_data.append(str(daq.sc['Q_TARGET_MIN'])) row_data.append(str(daq.sc['Q_TARGET_MAX'])) row_data.append( str( lib_1547.get_measurement_total(data=data, type_meas='PF', log=False))) row_data.append(str(step_label)) row_data.append(str(dataset_filename)) row_data_str = ','.join(row_data) + '\n' result_summary.write(row_data_str) 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)
def test_run(): eut = None chil = None grid = None pv = None result_summary = None result = script.RESULT_FAIL try: v_nom = ts.param_value('test.v_nom') # 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(800) pv.power_on() # grid simulator is initialized with test parameters and enabled grid = gridsim.gridsim_init(ts) # sometimes when there's a xfmr between the gridsim and EUT, V_nom at EUT != V_nom_grid (gridsim nominal) try: v_nom_grid = grid.v_nom_param except Exception, e: v_nom_grid = v_nom # Get EUT nameplate power eut_nameplate_power = eut.nameplate().get('WRtg') inv_power = eut.measurements().get('W') timeout = 120. if inv_power <= eut_nameplate_power/10.: eut.connect(params={'Conn': True}) pv.irradiance_set(800) # 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.') eut.volt_var_curve(1, params={'v': [95, 98, 102, 105], 'var': [100, 0, 0, -100]}) eut.volt_var(params={'ActCrv': 1, 'Ena': True}) parameters = eut.volt_var() ts.log_debug('EUT VV settings (readback): %s' % parameters) # Create list of voltages to iterate over voltage_values = list(np.linspace(95, 105, num=50)) sleep_time = 1. for voltage in voltage_values: v = ((voltage/100.) * v_nom_grid) grid.voltage(v) # set grid voltage ts.log(' V = %0.3f V (%0.3f%%). Sleeping for %0.2f seconds...' % (v, voltage, sleep_time)) ts.sleep(sleep_time) # Disable the VV function eut.volt_var(params={'Ena': False}) ts.log('VV Disabled') # Close the connection to the CHIL if chil is not None: chil.close() result = script.RESULT_COMPLETE