├── Lib └── svpelab │ ├── __init__.py │ ├── battsim.py │ ├── battsim_chroma.py │ ├── battsim_dc_load.py │ ├── battsim_manual.py │ ├── chroma_17040.py │ ├── chroma_61845.py │ ├── chroma_A800067.py │ ├── chromapv.py │ ├── das.py │ ├── das_chroma.py │ ├── das_manual.py │ ├── das_powerlogic_pm800.py │ ├── das_px8000.py │ ├── das_pz4000.py │ ├── das_sandia_dsm.py │ ├── das_sandia_ni_pcie.py │ ├── das_sim.py │ ├── das_typhoon.py │ ├── dataset.py │ ├── dcsim.py │ ├── dcsim_chroma_62000P.py │ ├── dcsim_manual.py │ ├── der.py │ ├── der_manual.py │ ├── der_pass.py │ ├── der_sim.py │ ├── der_sma.py │ ├── der_solaredge.py │ ├── der_sunspec.py │ ├── device_awg400.py │ ├── device_chroma_dpm.py │ ├── device_das_manual.py │ ├── device_das_powerlogic_pm800.py │ ├── device_das_sandia_ni_pcie.py │ ├── device_das_sim.py │ ├── device_das_typhoon.py │ ├── device_px8000.py │ ├── device_pz4000.py │ ├── device_sandia_dsm.py │ ├── device_switch_manual.py │ ├── device_wavegen_manual.py │ ├── grid_profiles.py │ ├── gridsim.py │ ├── gridsim_ametek.py │ ├── gridsim_chroma.py │ ├── gridsim_elgar704.py │ ├── gridsim_elgar704_3.py │ ├── gridsim_manual.py │ ├── gridsim_pacific.py │ ├── gridsim_pass.py │ ├── gridsim_rse.py │ ├── gridsim_sim.py │ ├── gridsim_sps.py │ ├── gridsim_typhoon.py │ ├── hil.py │ ├── hil_typhoon.py │ ├── loadsim.py │ ├── loadsim_chroma_63200.py │ ├── loadsim_chroma_A800067.py │ ├── loadsim_manual.py │ ├── loadsim_pass.py │ ├── loadsim_sandia.py │ ├── loadsimx_chroma.py │ ├── pv_profiles.py │ ├── pvsim.py │ ├── pvsim_chroma.py │ ├── pvsim_manual.py │ ├── pvsim_pass.py │ ├── pvsim_sim.py │ ├── pvsim_terrasas.py │ ├── pvsim_typhoon.py │ ├── result.py │ ├── rt_profile.py │ ├── svp_ext_result.py │ ├── switch.py │ ├── switch_manual.py │ ├── terrasas.py │ ├── vxi11.py │ ├── vxi11_rpc.py │ ├── waveform.py │ ├── waveform_analysis.py │ ├── wavegen.py │ ├── wavegen_awg400.py │ └── wavegen_manual.py ├── README.md ├── Scripts ├── battsim_test.py ├── das_test.py ├── gridsim_comm.py ├── gridsim_multi.py ├── loadsim_test.py ├── pvsim_comm.py ├── pvsim_multi.py ├── sunspec.gif ├── switch_test.py └── wavegen_test.py └── Tests ├── battsim_test.tst ├── das_test.tst ├── gridsim_comm_test.tst ├── gridsim_multi_test.tst ├── loadsim_test.tst ├── pvsim_comm_test.tst ├── pvsim_multi_test.tst └── wavegen_test.tst /Lib/svpelab/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | __version__ = '0.9.4' 3 | -------------------------------------------------------------------------------- /Lib/svpelab/battsim_dc_load.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | import dcsim 35 | import loadsim 36 | import battsim 37 | 38 | # This drive creates a battery simulator from a dc electronic load and dc power supply 39 | 40 | dc_load_info = { 41 | 'name': os.path.splitext(os.path.basename(__file__))[0], 42 | 'mode': 'DC Load and Power Supply' 43 | } 44 | 45 | 46 | def battsim_info(): 47 | return dc_load_info 48 | 49 | 50 | def params(info, group_name): 51 | gname = lambda name: group_name + '.' + name 52 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 53 | mode = dc_load_info['mode'] 54 | info.param_add_value(gname('mode'), mode) 55 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 56 | active=gname('mode'), active_value=mode, glob=True) 57 | 58 | # DC Load 59 | loadsim.params(info, group_name=group_name, active=gname('mode'), active_value=mode) 60 | 61 | # DC Power Supply 62 | dcsim.params(info, group_name=group_name, active=gname('mode'), active_value=mode) 63 | 64 | GROUP_NAME = 'dc_load' 65 | 66 | 67 | class BattSim(battsim.BattSim): 68 | 69 | def __init__(self, ts, group_name): 70 | battsim.BattSim.__init__(self, ts, group_name) 71 | 72 | # init the load simulator 73 | self.loadsim = loadsim.loadsim_init(ts, group_name=group_name) 74 | 75 | # init the DC power supply 76 | self.dcsim = loadsim.loadsim_init(ts, group_name=group_name) 77 | 78 | def _param_value(self, name): 79 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 80 | 81 | def info(self): 82 | """ 83 | Return information string for the device. 84 | """ 85 | load_str = self.loadsim.info() 86 | dc_str = self.dcsim.info() 87 | return 'Battery simulator consisting of ' + load_str + ' and ' + dc_str 88 | 89 | def config(self): 90 | """ 91 | Perform any configuration for the simulation based on the previously 92 | provided parameters. 93 | """ 94 | self.loadsim.config() 95 | self.dcsim.config() 96 | 97 | def open(self): 98 | """ 99 | Open the communications resources associated with the battery simulator. 100 | """ 101 | self.loadsim.open() 102 | self.dcsim.open() 103 | 104 | def close(self): 105 | """ 106 | Close any open communications resources associated with the battery simulator. 107 | """ 108 | self.loadsim.close() 109 | self.dcsim.close() 110 | -------------------------------------------------------------------------------- /Lib/svpelab/battsim_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | import battsim 35 | 36 | manual_info = { 37 | 'name': os.path.splitext(os.path.basename(__file__))[0], 38 | 'mode': 'Manual' 39 | } 40 | 41 | 42 | def battsim_info(): 43 | return manual_info 44 | 45 | 46 | def params(info, group_name): 47 | gname = lambda name: group_name + '.' + name 48 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 49 | mode = manual_info['mode'] 50 | info.param_add_value(gname('mode'), mode) 51 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 52 | active=gname('mode'), active_value=mode, glob=True) 53 | 54 | GROUP_NAME = 'manual' 55 | 56 | 57 | class BattSim(battsim.BattSim): 58 | 59 | def __init__(self, ts, group_name): 60 | battsim.BattSim.__init__(self, ts, group_name) 61 | 62 | def _param_value(self, name): 63 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 64 | 65 | def info(self): 66 | """ 67 | Return information string for the device. 68 | """ 69 | return 'Manual battery simulator' 70 | 71 | def config(self): 72 | """ 73 | Perform any configuration for the simulation based on the previously 74 | provided parameters. 75 | """ 76 | self.ts.confirm('Configure battery or battery simulator.') 77 | 78 | -------------------------------------------------------------------------------- /Lib/svpelab/chroma_17040.py: -------------------------------------------------------------------------------- 1 | # wanbin son 2 | 3 | import time 4 | 5 | TERMINATOR = "\n" 6 | TEST = None 7 | 8 | class ChromaBattSimError(Exception): 9 | pass 10 | 11 | class ChromaBattSim(object): 12 | def __init__(self,ts, visa_device, visa_path = None): #wanbin 13 | self.conn = None 14 | self.visa_device = visa_device 15 | self.visa_path = visa_path 16 | self.ts=ts 17 | 18 | def _query(self, cmd_str): 19 | """ 20 | Performs an SCPI Querry 21 | :param cmd_str: 22 | :return: 23 | """ 24 | if TEST is not None: 25 | print(cmd_str.strip()) 26 | return '0.0' 27 | try: 28 | if self.conn is None: 29 | raise ChromaBattSimError('GPIB connection not open') 30 | return self.conn.query(cmd_str.strip('\n')) 31 | 32 | except Exception, e: 33 | raise ChromaBattSimError(str(e)) 34 | 35 | def query(self, cmd_str): 36 | try: 37 | resp = self._query(cmd_str).strip() 38 | except Exception, e: 39 | raise ChromaBattSimError(str(e)) 40 | return resp 41 | 42 | 43 | def _cmd(self, cmd_str): 44 | """ 45 | Performs an SCPI Querry 46 | :param cmd_str: 47 | :return: 48 | """ 49 | if TEST is not None: 50 | print cmd_str.strip() 51 | return 52 | try: 53 | if self.conn is None: 54 | raise ChromaBattSimError('connection not open') 55 | return self.conn.write(cmd_str.strip('\n')) 56 | except Exception, e: 57 | raise ChromaBattSimError(str(e)) 58 | 59 | def cmd(self, cmd_str): 60 | try: 61 | self._cmd(cmd_str) 62 | resp = self._query('SYST:ERR?\n') #\r 63 | print 'resp\n' 64 | print resp 65 | if len(resp) > 0: 66 | if resp[0] != '0': 67 | raise ChromaBattSimError(resp + ' ' + cmd_str) 68 | 69 | except Exception, e: 70 | raise ChromaBattSimError(str(e)) 71 | 72 | 73 | def open(self): 74 | import visa 75 | """ 76 | Open the communications resources associated with the device. 77 | """ 78 | try: 79 | self.rm = visa.ResourceManager() 80 | self.conn = self.rm.open_resource(self.visa_device) 81 | # set terminator in pyvisa 82 | self.conn.write_termination = TERMINATOR 83 | self.conn.read_termination = TERMINATOR 84 | self.conn.timeout=10000 85 | self.cmd('OUTPut:MODe 1') 86 | except Exception, e: 87 | raise ChromaGridSimError('Cannot open VISA connection to %s' % (self.visa_device)) 88 | 89 | def protection_clear(self): 90 | self.cmd('PROTection:CLEar') 91 | 92 | def set_capacity(self, cap): 93 | self.cmd("BATTery:CAP %f" % cap) 94 | 95 | def set_curve(self,soc,vol,dcr_d,dcr_c): 96 | cmd_str="BATTery:CURVe 0, %d " % len(vol) 97 | for item in vol: 98 | cmd_str+=", %.2f" % item 99 | self.cmd(cmd_str) 100 | cmd_str="BATTery:CURVe 1, %d " % len(soc) 101 | for item in soc: 102 | cmd_str+=", %.1f" % item 103 | self.cmd(cmd_str) 104 | 105 | cmd_str="BATTery:CURVe 2, %d " % len(dcr_d) 106 | for item in dcr_d: 107 | cmd_str+=", %f" % item 108 | self.cmd(cmd_str) 109 | 110 | cmd_str="BATTery:CURVe 3, %d " % len(dcr_c) 111 | for item in dcr_c: 112 | cmd_str+=", %f" % item 113 | self.cmd(cmd_str) 114 | 115 | self.ts.log_debug("BATTery:VH %f" % max(vol)) 116 | self.cmd("BATTery:VH %f" % max(vol)) 117 | self.cmd("BATTery:VL %f" % min(vol)) 118 | 119 | 120 | def set_init_soc(self, soc): 121 | self.cmd("BATTery:INITial 0") 122 | self.cmd("BATTery:INITial:CAP %f" % soc) 123 | #self.query("BATTery:INITial:CAP?") 124 | 125 | def set_volt_alarm(self, low, high): 126 | self.cmd("BATTery:BVL %.2f" % low) 127 | self.cmd("BATTery:BVH %.2f" % high) 128 | 129 | 130 | def set_volt_protection(self, low, high): 131 | self.cmd("BATTery:VOLP %.2f" % low) # Low Voltage Protection 132 | self.cmd("BATTery:VOH %.2f" % high) # High Voltage Protection 133 | 134 | self.cmd("BATTery:BOH 110") # high soc protection 135 | self.cmd("BATTery:BOL -20") # low soc protection 136 | 137 | 138 | def set_current_protection(self, high): 139 | self.cmd("BATTery:OCP %.2f" % high) 140 | 141 | def set_esr(self, esr): 142 | self.cmd("BATTery:ESR %.3f" % esr) 143 | 144 | def set_efficiency(self, charge, discharge): 145 | self.cmd("BATTery:EFFCHG %.1f" % charge) 146 | self.cmd("BATTery:EFFDSG %.1f" % discharge) 147 | 148 | def power_on(self): 149 | #self.cmd("CHANnel:SOURce 1") 150 | self.cmd("BATTery:OUTPut 1") # mode A. consider mode B 151 | 152 | def power_off(self): 153 | self.cmd("BATTery:OUTPut OFF") # off 154 | 155 | def get_volt(self): 156 | return self.query("MEASure:VOLT?") 157 | 158 | def is_error(self): 159 | resp=self._query("MEAS:STATe?\n") 160 | if int(resp.split(",")[0])!=0: 161 | return True 162 | else: 163 | return False 164 | 165 | 166 | if __name__ == "__main__": 167 | TEST=True 168 | a=ChromaBattSim("TCPIP::192.168.1.100::60000::SOCKET") 169 | a.protection_clear() 170 | a.set_capacity(100) 171 | a.set_curve(range(10),range(10),range(10),range(10)) 172 | a.set_init_soc(50) 173 | pass 174 | -------------------------------------------------------------------------------- /Lib/svpelab/das_chroma.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import das 36 | import device_chroma_dpm 37 | 38 | chroma_info = { 39 | 'name': os.path.splitext(os.path.basename(__file__))[0], 40 | 'mode': 'Chroma' 41 | } 42 | 43 | def das_info(): 44 | return chroma_info 45 | 46 | def params(info, group_name=None): 47 | gname = lambda name: group_name + '.' + name 48 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 49 | mode = chroma_info['mode'] 50 | info.param_add_value(gname('mode'), mode) 51 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 52 | active=gname('mode'), active_value=mode, glob=True) 53 | info.param(pname('comm'), label='Communications Interface', default='VISA', values=['VISA']) 54 | info.param(pname('visa_device'), label='VISA Device String', active=pname('comm'), 55 | active_value=['VISA'], default='GPIB0::0::INSTR') 56 | info.param(pname('visa_path'), label='VISA Path', active=pname('comm'), 57 | active_value=['VISA'], default='') 58 | info.param(pname('sample_interval'), label='Sample Interval (ms)', default=1000) 59 | 60 | info.param(pname('chan_1'), label='Channel 1', default='AC', values=['AC', 'DC', 'Unused']) 61 | info.param(pname('chan_2'), label='Channel 2', default='AC', values=['AC', 'DC', 'Unused']) 62 | info.param(pname('chan_3'), label='Channel 3', default='AC', values=['AC', 'DC', 'Unused']) 63 | info.param(pname('chan_4'), label='Channel 4', default='DC', values=['AC', 'DC', 'Unused']) 64 | 65 | info.param(pname('chan_1_label'), label='Channel 1 Label', default='1', active=pname('chan_1'), 66 | active_value=['AC', 'DC']) 67 | info.param(pname('chan_2_label'), label='Channel 2 Label', default='2', active=pname('chan_2'), 68 | active_value=['AC', 'DC']) 69 | info.param(pname('chan_3_label'), label='Channel 3 Label', default='3', active=pname('chan_3'), 70 | active_value=['AC', 'DC']) 71 | info.param(pname('chan_4_label'), label='Channel 4 Label', default='', active=pname('chan_4'), 72 | active_value=['AC', 'DC']) 73 | 74 | GROUP_NAME = 'chroma' 75 | 76 | 77 | class DAS(das.DAS): 78 | def __init__(self, ts, group_name, points=None, sc_points=None): 79 | das.DAS.__init__(self, ts, group_name, points=points, sc_points=sc_points) 80 | self.params['visa_device'] = self._param_value('visa_device') 81 | visa_path = self._param_value('visa_path') 82 | if visa_path != 'None': 83 | self.params['visa_path'] = visa_path 84 | self.sample_interval = self._param_value('sample_interval') 85 | 86 | # create channel info for each channel from parameters 87 | channels = [None] 88 | for i in range(1, 5): 89 | chan_type = self._param_value('chan_%d' % (i)) 90 | chan_label = self._param_value('chan_%d_label' % (i)) 91 | if chan_label == 'None': 92 | chan_label = '' 93 | chan = {'type': chan_type, 'points': self.points.get(chan_type), 'label': chan_label} 94 | channels.append(chan) 95 | 96 | self.params['channels'] = channels 97 | 98 | self.device = device_chroma_dpm.Device(self.params) 99 | self.data_points = self.device.data_points 100 | 101 | # initialize soft channel points 102 | self._init_sc_points() 103 | 104 | def _param_value(self, name): 105 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 106 | 107 | if __name__ == "__main__": 108 | 109 | pass 110 | 111 | 112 | -------------------------------------------------------------------------------- /Lib/svpelab/das_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import device_das_manual 36 | import das 37 | 38 | manual_info = { 39 | 'name': os.path.splitext(os.path.basename(__file__))[0], 40 | 'mode': 'Manual' 41 | } 42 | 43 | def das_info(): 44 | return manual_info 45 | 46 | def params(info, group_name): 47 | gname = lambda name: group_name + '.' + name 48 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 49 | mode = manual_info['mode'] 50 | info.param_add_value(gname('mode'), mode) 51 | 52 | GROUP_NAME = 'manual' 53 | 54 | class DAS(das.DAS): 55 | 56 | def __init__(self, ts, group_name, points=None, sc_points=None): 57 | das.DAS.__init__(self, ts, group_name, points=points, sc_points=sc_points) 58 | self.device = device_das_manual.Device() 59 | self.data_points = self.device.data_points 60 | 61 | # initialize soft channel points 62 | self._init_sc_points() -------------------------------------------------------------------------------- /Lib/svpelab/das_powerlogic_pm800.py: -------------------------------------------------------------------------------- 1 | """ 2 | Communications to a EGX100 Gateway to the Schneider Electric PowerLogic PM800 Series Power Meters 3 | Communications use Modbus TCP/IP 4 | 5 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without modification, 9 | are permitted provided that the following conditions are met: 10 | 11 | Redistributions of source code must retain the above copyright notice, this 12 | list of conditions and the following disclaimer. 13 | 14 | Redistributions in binary form must reproduce the above copyright notice, this 15 | list of conditions and the following disclaimer in the documentation and/or 16 | other materials provided with the distribution. 17 | 18 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 26 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | 33 | Questions can be directed to support@sunspec.org 34 | """ 35 | 36 | import os 37 | 38 | import device_das_powerlogic_pm800 39 | import das 40 | 41 | pm_info = { 42 | 'name': os.path.splitext(os.path.basename(__file__))[0], 43 | 'mode': 'PowerLogic PM800' 44 | } 45 | 46 | def das_info(): 47 | return pm_info 48 | 49 | def params(info, group_name=None): 50 | gname = lambda name: group_name + '.' + name 51 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 52 | mode = pm_info['mode'] 53 | info.param_add_value(gname('mode'), mode) 54 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 55 | active=gname('mode'), active_value=mode, glob=True) 56 | info.param(pname('comm'), label='Communications Interface', default='Modbus TCP', values=['Modbus TCP']) 57 | info.param(pname('ip_addr'), label='IP Address', 58 | active=pname('comm'), active_value=['Modbus TCP'], default='134.253.170.243') 59 | info.param(pname('ip_port'), label='IP Port', active=pname('comm'), active_value=['Modbus TCP'], default=502) 60 | info.param(pname('ip_timeout'), label='IP Timeout', active=pname('comm'), active_value=['Modbus TCP'], default=5) 61 | info.param(pname('slave_id'), label='Slave Id', active=pname('comm'), active_value=['Modbus TCP'], default=22) 62 | #info.param(pname('wiring_system'), label='Wiring System', default='1 Phase', values=['1 Phase', '3 Phase']) 63 | 64 | # Note the update rate of the PM800 is only 1 second 65 | info.param(pname('sample_interval'), label='Sample Interval (ms)', default=1000) 66 | 67 | GROUP_NAME = 'powerlogic_pm800' 68 | 69 | 70 | class DAS(das.DAS): 71 | 72 | def __init__(self, ts, group_name, points=None, sc_points=None): 73 | das.DAS.__init__(self, ts, group_name, points=points, sc_points=sc_points) 74 | self.sample_interval = self._param_value('sample_interval') 75 | 76 | self.params['comm'] = self._param_value('comm') 77 | if self.params['comm'] == 'Modbus TCP': 78 | self.params['ip_addr'] = self._param_value('ip_addr') 79 | self.params['ip_port'] = self._param_value('ip_port') 80 | self.params['ip_timeout'] = self._param_value('ip_timeout') 81 | self.params['slave_id'] = self._param_value('slave_id') 82 | 83 | self.device = device_das_powerlogic_pm800.Device(self.params, ts) 84 | self.data_points = self.device.data_points 85 | 86 | # initialize soft channel points 87 | self._init_sc_points() 88 | 89 | if self.sample_interval < 50: 90 | raise das.DASError('Parameter error: sample interval must be at least 50ms') 91 | 92 | 93 | def _param_value(self, name): 94 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 95 | 96 | 97 | if __name__ == "__main__": 98 | 99 | pass 100 | 101 | 102 | -------------------------------------------------------------------------------- /Lib/svpelab/das_px8000.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import device_px8000 36 | import das 37 | 38 | px8000_info = { 39 | 'name': os.path.splitext(os.path.basename(__file__))[0], 40 | 'mode': 'Yokogawa PX8000' 41 | } 42 | 43 | def das_info(): 44 | return px8000_info 45 | 46 | def params(info, group_name): 47 | gname = lambda name: group_name + '.' + name 48 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 49 | mode = px8000_info['mode'] 50 | info.param_add_value(gname('mode'), mode) 51 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 52 | active=gname('mode'), active_value=mode, glob=True) 53 | info.param(pname('comm'), label='Communications Interface', default='Network', values=['Network']) 54 | info.param(pname('ip_addr'), label='IP Address', 55 | active=pname('comm'), active_value=['Network'], default='192.168.0.10') 56 | info.param(pname('sample_interval'), label='Sample Interval (ms)', default=1000) 57 | 58 | info.param(pname('chan_1'), label='Channel 1', default='AC', values=['AC', 'DC', 'Unused']) 59 | info.param(pname('chan_2'), label='Channel 2', default='AC', values=['AC', 'DC', 'Unused']) 60 | info.param(pname('chan_3'), label='Channel 3', default='AC', values=['AC', 'DC', 'Unused']) 61 | info.param(pname('chan_4'), label='Channel 4', default='DC', values=['AC', 'DC', 'Unused']) 62 | 63 | info.param(pname('chan_1_label'), label='Channel 1 Label', default='1', active=pname('chan_1'), 64 | active_value=['AC', 'DC']) 65 | info.param(pname('chan_2_label'), label='Channel 2 Label', default='2', active=pname('chan_2'), 66 | active_value=['AC', 'DC']) 67 | info.param(pname('chan_3_label'), label='Channel 3 Label', default='3', active=pname('chan_3'), 68 | active_value=['AC', 'DC']) 69 | info.param(pname('chan_4_label'), label='Channel 4 Label', default='', active=pname('chan_4'), 70 | active_value=['AC', 'DC']) 71 | 72 | ''' 73 | info.param(pname('wiring_system'), label='Wiring System', default='1P2W', values=['1P2W', '1P3W', '3P3W', 74 | '3P4W', '3P3W(3V3A)']) 75 | ''' 76 | # info.param(pname('ip_port'), label='IP Port', 77 | # active=pname('comm'), active_value=['Network'], default=4944) 78 | # info.param(pname('ip_timeout'), label='IP Timeout', 79 | # active=pname('comm'), active_value=['Network'], default=5) 80 | 81 | GROUP_NAME = 'px8000' 82 | 83 | 84 | class DAS(das.DAS): 85 | """ 86 | Template for data acquisition (DAS) implementations. This class can be used as a base class or 87 | independent data acquisition classes can be created containing the methods contained in this class. 88 | """ 89 | 90 | def __init__(self, ts, group_name, points=None, sc_points=None): 91 | das.DAS.__init__(self, ts, group_name, points=points, sc_points=sc_points) 92 | self.sample_interval = self._param_value('sample_interval') 93 | 94 | self.params['ip_addr'] = self._param_value('ip_addr') 95 | self.params['ipport'] = self._param_value('ip_port') 96 | self.params['timeout'] = self._param_value('ip_timeout') 97 | 98 | # create channel info for each channel from parameters 99 | channels = [None] 100 | for i in range(1, 5): 101 | chan_type = self._param_value('chan_%d' % (i)) 102 | chan_label = self._param_value('chan_%d_label' % (i)) 103 | if chan_label == 'None': 104 | chan_label = '' 105 | chan = {'type': chan_type, 'points': self.points.get(chan_type), 'label': chan_label} 106 | channels.append(chan) 107 | 108 | self.params['channels'] = channels 109 | 110 | self.device = device_px8000.Device(self.params) 111 | self.data_points = self.device.data_points 112 | 113 | # initialize soft channel points 114 | self._init_sc_points() 115 | 116 | def _param_value(self, name): 117 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 118 | 119 | 120 | if __name__ == "__main__": 121 | 122 | pass 123 | 124 | 125 | -------------------------------------------------------------------------------- /Lib/svpelab/das_pz4000.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import das 4 | import device_pz4000 5 | 6 | 7 | 8 | pz4000_info = { 9 | 'name': os.path.splitext(os.path.basename(__file__))[0], 10 | 'mode': 'Yokogawa PZ4000' 11 | } 12 | 13 | def das_info(): 14 | return pz4000_info 15 | 16 | def params(info, group_name=None): 17 | gname = lambda name: group_name + '.' + name 18 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 19 | mode = pz4000_info['mode'] 20 | info.param_add_value(gname('mode'), mode) 21 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode,active=gname('mode'), active_value=mode, glob=True) 22 | info.param(pname('comm'), label='Communications Interface', default='VISA', values=['VISA', 'GPIB']) 23 | info.param(pname('visa_address'), label='VISA address', default='GPIB0::6::INSTR') 24 | info.param(pname('sample_interval'), label='Sample Interval (ms)', default=1000) 25 | 26 | info.param(pname('chan_1'), label='Channel 1', default='AC', values=['AC', 'DC', 'Unused']) 27 | info.param(pname('chan_2'), label='Channel 2', default='AC', values=['AC', 'DC', 'Unused']) 28 | info.param(pname('chan_3'), label='Channel 3', default='AC', values=['AC', 'DC', 'Unused']) 29 | info.param(pname('chan_4'), label='Channel 4', default='DC', values=['AC', 'DC', 'Unused']) 30 | 31 | info.param(pname('chan_1_label'), label='Channel 1 Label', default='1', active=pname('chan_1'),active_value=['AC', 'DC']) 32 | info.param(pname('chan_2_label'), label='Channel 2 Label', default='2', active=pname('chan_2'),active_value=['AC', 'DC']) 33 | info.param(pname('chan_3_label'), label='Channel 3 Label', default='3', active=pname('chan_3'),active_value=['AC', 'DC']) 34 | info.param(pname('chan_4_label'), label='Channel 4 Label', default='', active=pname('chan_4'),active_value=['AC', 'DC']) 35 | 36 | ''' 37 | info.param(pname('wiring_system'), label='Wiring System', default='1P2W', values=['1P2W', '1P3W', '3P3W','3P4W', '3P3W(3V3A)']) 38 | ''' 39 | # info.param(pname('ip_port'), label='IP Port', 40 | # active=pname('comm'), active_value=['Network'], default=4944) 41 | # info.param(pname('ip_timeout'), label='IP Timeout', 42 | # active=pname('comm'), active_value=['Network'], default=5) 43 | 44 | GROUP_NAME = 'pz4000' 45 | 46 | 47 | class DAS(das.DAS): 48 | """ 49 | Template for data acquisition (DAS) implementations. This class can be used as a base class or 50 | independent data acquisition classes can be created containing the methods contained in this class. 51 | """ 52 | 53 | def __init__(self, ts, group_name, points=None, sc_points=None): 54 | 55 | das.DAS.__init__(self, ts, group_name, points=points, sc_points=sc_points) 56 | self.params['visa_address'] = self._param_value('visa_address') 57 | self.params['comm'] = self._param_value('comm') 58 | self.params['timeout'] = self._param_value('ip_timeout') 59 | # self.params['wiring_system'] = self._param_value('wiring_system') 60 | self.params['sample_interval'] = self._param_value('sample_interval') 61 | 62 | # create channel info for each channel from parameters 63 | channels = [None] 64 | for i in range(1,5): 65 | chan = None 66 | chan_type = self._param_value('chan_%d' % (i)) 67 | chan_label = self._param_value('chan_%d_label' % (i)) 68 | if chan_label == 'None': 69 | chan_label = '' 70 | if chan_type == 'AC': 71 | chan = {'type': 'ac', 'points': self.points['ac'], 'label': chan_label} 72 | elif chan_type == 'DC': 73 | chan = {'type': 'dc', 'points': self.points['dc'], 'label': chan_label} 74 | channels.append(chan) 75 | 76 | self.params['channels'] = channels 77 | 78 | self.device = device_pz4000.Device(self.params) 79 | 80 | #config here 81 | 82 | def _param_value(self, name): 83 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 84 | 85 | 86 | if __name__ == "__main__": 87 | 88 | pass 89 | 90 | 91 | -------------------------------------------------------------------------------- /Lib/svpelab/das_sandia_dsm.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import script 36 | import device_sandia_dsm 37 | import das 38 | 39 | sandia_info = { 40 | 'name': os.path.splitext(os.path.basename(__file__))[0], 41 | 'mode': 'Sandia DSM' 42 | } 43 | 44 | def das_info(): 45 | return sandia_info 46 | 47 | def params(info, group_name=None): 48 | gname = lambda name: group_name + '.' + name 49 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 50 | mode = sandia_info['mode'] 51 | info.param_add_value(gname('mode'), mode) 52 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 53 | active=gname('mode'), active_value=mode, glob=True) 54 | info.param(pname('dsm_method'), label='Data Acquisition Method', default='Sandia LabView DSM', 55 | values=['Sandia LabView DSM', 'Sandia LabView DSM UDP'], 56 | desc='Each lab will have different data acquisition methods. Sandia passes the data from the DAQ ' 57 | 'to python by writing the values locally or collecting them over the local network.') 58 | info.param(pname('das_comp'), label='Data Acquisition Computer', default='10 Node', 59 | values=['10 Node', 'DAS 3', 'DAS 5', 'DAS 8'], 60 | active=pname('dsm_method'), active_value=['Sandia LabView DSM UDP'], 61 | desc='Selection of the data acquisition system') 62 | info.param(pname('node'), label='Node at Sandia - Used to ID DAQ channel', default=10, 63 | desc='Selection of the EUT which will be used for the test (Sandia specific).') 64 | info.param(pname('sample_interval'), label='Sample Interval (ms)', default=1000) 65 | info.param(pname('file_path'), label='File Path', default='C:\\python_dsm', ptype=script.PTYPE_DIR) 66 | 67 | GROUP_NAME = 'sandia' 68 | 69 | 70 | class DAS(das.DAS): 71 | 72 | def __init__(self, ts, group_name, points=None, sc_points=None): 73 | das.DAS.__init__(self, ts, group_name, points=points, sc_points=sc_points) 74 | self.sample_interval = self._param_value('sample_interval') 75 | 76 | self.params['dsm_method'] = self._param_value('dsm_method') 77 | self.params['dsm_id'] = self._param_value('node') 78 | self.params['comp'] = self._param_value('comp') 79 | self.params['ts'] = ts 80 | 81 | # if not absolute path, use SVP 'Files' directory 82 | file_path = self._param_value('file_path') 83 | if not os.path.isabs(file_path): 84 | os.path.join(self.files_dir, file_path) 85 | self.params['file_path'] = file_path 86 | 87 | self.device = device_sandia_dsm.Device(self.params) 88 | self.data_points = self.device.data_points 89 | 90 | # initialize soft channel points 91 | self._init_sc_points() 92 | 93 | def _param_value(self, name): 94 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 95 | 96 | if __name__ == "__main__": 97 | 98 | pass -------------------------------------------------------------------------------- /Lib/svpelab/das_sandia_ni_pcie.py: -------------------------------------------------------------------------------- 1 | """ 2 | Communications to NI PCIe Cards 3 | 4 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | Redistributions in binary form must reproduce the above copyright notice, this 14 | list of conditions and the following disclaimer in the documentation and/or 15 | other materials provided with the distribution. 16 | 17 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | Questions can be directed to support@sunspec.org 33 | """ 34 | 35 | import os 36 | import device_das_sandia_ni_pcie 37 | import das 38 | 39 | ni_info = { 40 | 'name': os.path.splitext(os.path.basename(__file__))[0], 41 | 'mode': 'Sandia National Instruments PCIe' 42 | } 43 | 44 | def das_info(): 45 | return ni_info 46 | 47 | def params(info, group_name=None): 48 | gname = lambda name: group_name + '.' + name 49 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 50 | mode = ni_info['mode'] 51 | info.param_add_value(gname('mode'), mode) 52 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 53 | active=gname('mode'), active_value=mode, glob=True) 54 | info.param(pname('node'), label='Node at Sandia - Used to ID DAQ channel', default=10, 55 | desc='Selection of the EUT which will be used for the test (Sandia specific).') 56 | info.param(pname('sample_interval'), label='Sample Interval (ms)', default=1000) 57 | info.param(pname('sample_rate'), label='Sample rate of waveforms (Hz)', default=10000) 58 | info.param(pname('n_cycles'), label='Number of cycles to capture', default=6) 59 | 60 | GROUP_NAME = 'sandia_ni_pcie' 61 | 62 | 63 | class DAS(das.DAS): 64 | 65 | def __init__(self, ts, group_name, points=None, sc_points=None): 66 | das.DAS.__init__(self, ts, group_name, points=points, sc_points=sc_points) 67 | self.sample_interval = self._param_value('sample_interval') 68 | self.params['node'] = self._param_value('node') 69 | self.params['sample_interval'] = self._param_value('sample_interval') 70 | self.params['sample_rate'] = self._param_value('sample_rate') 71 | self.params['n_cycles'] = self._param_value('n_cycles') 72 | self.params['ts'] = ts 73 | 74 | self.device = device_das_sandia_ni_pcie.Device(self.params, ts) 75 | self.data_points = self.device.data_points 76 | 77 | # initialize soft channel points 78 | self._init_sc_points() 79 | 80 | def _param_value(self, name): 81 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 82 | 83 | 84 | if __name__ == "__main__": 85 | 86 | pass 87 | 88 | 89 | -------------------------------------------------------------------------------- /Lib/svpelab/das_sim.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | import device_das_sim 35 | import das 36 | import script 37 | 38 | sim_info = { 39 | 'name': os.path.splitext(os.path.basename(__file__))[0], 40 | 'mode': 'DAS Simulation' 41 | } 42 | 43 | def das_info(): 44 | return sim_info 45 | 46 | def params(info, group_name=None): 47 | gname = lambda name: group_name + '.' + name 48 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 49 | mode = sim_info['mode'] 50 | info.param_add_value(gname('mode'), mode) 51 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 52 | active=gname('mode'), active_value=mode) 53 | info.param(pname('data_file'), label='Data File (in SVP Files directory)', default='data.csv') 54 | info.param(pname('use_timestamp'), label='Use Data File Timestamp', default='Enabled', values=['Enabled', 55 | 'Disabled']) 56 | info.param(pname('at_end'), label='At End of Data', default='Repeat last record', values=['Loop to start', 57 | 'Repeat last record', 58 | 'Return an error']) 59 | 60 | GROUP_NAME = 'sim' 61 | 62 | 63 | class DAS(das.DAS): 64 | def __init__(self, ts, group_name, points=None, sc_points=None): 65 | das.DAS.__init__(self, ts, group_name, points=points, sc_points=sc_points) 66 | data_file = self._param_value('data_file') 67 | if data_file and data_file != 'None': 68 | data_file = os.path.join(self.files_dir, data_file) 69 | self.params['points'] = self.points 70 | self.params['data_file'] = data_file 71 | self.params['use_timestamp'] = self._param_value('use_timestamp') 72 | self.params['at_end'] = self._param_value('at_end') 73 | self.params['ts'] = self.ts 74 | 75 | self.ts.log('results_dir = %s' % (ts._results_dir)) 76 | 77 | self.device = device_das_sim.Device(self.params) 78 | self.data_points = self.device.data_points 79 | 80 | # initialize soft channel points 81 | self._init_sc_points() 82 | 83 | def _param_value(self, name): 84 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 85 | 86 | 87 | if __name__ == "__main__": 88 | 89 | pass 90 | 91 | 92 | -------------------------------------------------------------------------------- /Lib/svpelab/das_typhoon.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import device_das_typhoon 36 | import das 37 | 38 | typhoon_info = { 39 | 'name': os.path.splitext(os.path.basename(__file__))[0], 40 | 'mode': 'Typhoon' 41 | } 42 | 43 | def das_info(): 44 | return typhoon_info 45 | 46 | def params(info, group_name=None): 47 | gname = lambda name: group_name + '.' + name 48 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 49 | mode = typhoon_info['mode'] 50 | info.param_add_value(gname('mode'), mode) 51 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 52 | active=gname('mode'), active_value=mode, glob=True) 53 | info.param(pname('sample_interval'), label='Sample Interval (ms)', default=1000) 54 | 55 | GROUP_NAME = 'typhoon' 56 | 57 | 58 | class DAS(das.DAS): 59 | 60 | def __init__(self, ts, group_name, points=None, sc_points=None): 61 | das.DAS.__init__(self, ts, group_name, points=points, sc_points=sc_points) 62 | self.device = device_das_typhoon.Device() 63 | self.sample_interval = self._param_value('sample_interval') 64 | 65 | if self.sample_interval < 50: 66 | raise das.DASError('Parameter error: sample interval must be at least 50 ms') 67 | 68 | def _param_value(self, name): 69 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 70 | 71 | 72 | if __name__ == "__main__": 73 | 74 | pass 75 | 76 | 77 | -------------------------------------------------------------------------------- /Lib/svpelab/dataset.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | 34 | class DatasetError(Exception): 35 | """ 36 | Exception to wrap all das generated exceptions. 37 | """ 38 | pass 39 | 40 | """ 41 | Data AC/DC point names have three parts: 42 | 43 | - category (AC/DC) 44 | - type (V, I, VRMS, IRMS, P, Q, S, PF, FREQ) 45 | - id (optional) 46 | 47 | Example names: 48 | AC_V 49 | AC_I 50 | 51 | AC_V_1 52 | AC_I_1 53 | AC_VRMS_1 54 | 55 | DC_V 56 | DC_I 57 | 58 | A dataset consists of a set of time series points organized as parallel arrays and some 59 | additional optional properties. 60 | 61 | Optional roperties: 62 | Start time of dataset 63 | Sample rate of dataset (samples/sec) 64 | Trigger sample (record index into dataset) 65 | 66 | """ 67 | class Dataset(object): 68 | def __init__(self, points=None, data=None, start_time=None, sample_rate=None, trigger_sample=None, params=None): 69 | self.start_time = start_time # start time 70 | self.sample_rate = sample_rate # samples/second 71 | self.trigger_sample = trigger_sample # trigger sample 72 | self.points = points # point names 73 | self.data = data # data 74 | 75 | if points is None: 76 | self.points = [] 77 | if data is None: 78 | self.clear() 79 | 80 | def append(self, data): 81 | dlen = len(data) 82 | if len(data) != len(self.data): 83 | raise DatasetError('Append record point mismatch, dataset contains %s points,' 84 | ' appended data contains %s points' % (len(self.data), dlen)) 85 | for i in range(dlen): 86 | try: 87 | v = float(data[i]) 88 | except ValueError: 89 | v = data[i] 90 | self.data[i].append(v) 91 | 92 | def extend(self, data): 93 | dlen = len(data) 94 | if len(data) != len(self.data): 95 | raise DatasetError('Extend record point mismatch, dataset contains %s points,' 96 | ' appended data contains %s points' % (len(self.data), dlen)) 97 | for i in range(dlen): 98 | self.data[i].extend(data[i]) 99 | 100 | def clear(self): 101 | self.data = [] 102 | for i in range(len(self.points)): 103 | self.data.append([]) 104 | 105 | def to_csv(self, filename): 106 | cols = range(len(self.data)) 107 | if len(cols) > 0: 108 | f = open(filename, 'w') 109 | f.write('%s\n' % ', '.join(map(str, self.points))) 110 | for i in xrange(len(self.data[0])): 111 | d = [] 112 | for j in cols: 113 | d.append(self.data[j][i]) 114 | f.write('%s\n' % ', '.join(map(str, d))) 115 | f.close() 116 | 117 | def from_csv(self, filename, sep=','): 118 | self.clear() 119 | f = open(filename, 'r') 120 | ids = None 121 | while ids is None: 122 | line = f.readline().strip() 123 | if len(line) > 0 and line[0] != '#': 124 | ids = [e.strip() for e in line.split(sep)] 125 | self.points = ids 126 | for i in range(len(self.points)): 127 | self.data.append([]) 128 | for line in f: 129 | data = [float(e.strip()) for e in line.split(sep)] 130 | if len(data) > 0: 131 | self.append(data) 132 | f.close() 133 | 134 | 135 | if __name__ == "__main__": 136 | 137 | rms_points = ['TIME', 138 | 'AC_VRMS_1', 'AC_IRMS_1', 'AC_P_1', 'AC_S_1', 'AC_Q_1', 'AC_PF_1', 'AC_FREQ_1', 139 | 'AC_VRMS_2', 'AC_IRMS_2', 'AC_P_2', 'AC_S_2', 'AC_Q_2', 'AC_PF_2', 'AC_FREQ_2', 140 | 'AC_VRMS_3', 'AC_IRMS_3', 'AC_P_3', 'AC_S_3', 'AC_Q_3', 'AC_PF_3', 'AC_FREQ_3', 141 | 'DC_V', 'DC_I', 'DC_P'] 142 | 143 | rms_data = [[0.0, 144 | 220.1, 10.1, 2100.1, 2200, 0.011, 0.991, 60.1, 145 | 220.2, 10.2, 2100.2, 2200, 0.012, 0.992, 60.2, 146 | 220.3, 10.3, 2100.3, 2200, 0.013, 0.993, 60.3, 147 | 440, 5, 2200], 148 | [1.0, 149 | 220.1, 10.1, 2100.1, 2200, 0.011, 0.991, 60.1, 150 | 220.2, 10.2, 2100.2, 2200, 0.012, 0.992, 60.2, 151 | 220.3, 10.3, 2100.3, 2200, 0.013, 0.993, 60.3, 152 | 440, 5, 2200], 153 | [2.0, 154 | 220.1, 10.1, 2100.1, 2200, 0.011, 0.991, 60.1, 155 | 220.2, 10.2, 2100.2, 2200, 0.012, 0.992, 60.2, 156 | 220.3, 10.3, 2100.3, 2200, 0.013, 0.993, 60.3, 157 | 440, 5, 2200]] 158 | 159 | ds = Dataset(points=rms_points) 160 | for i in range(len(rms_data)): 161 | ds.append(rms_data[i]) 162 | ds.to_csv('xyz') 163 | -------------------------------------------------------------------------------- /Lib/svpelab/dcsim_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | import time 35 | import dcsim 36 | 37 | chroma_info = { 38 | 'name': os.path.splitext(os.path.basename(__file__))[0], 39 | 'mode': 'Manual' 40 | } 41 | 42 | def dc_info(): 43 | return chroma_info 44 | 45 | def params(info, group_name=None): 46 | gname = lambda name: group_name + '.' + name 47 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 48 | mode = chroma_info['mode'] 49 | info.param_add_value(gname('mode'), mode) 50 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 51 | active=gname('mode'), active_value=mode, glob=True) 52 | 53 | GROUP_NAME = 'manual' 54 | 55 | class DCSim(dcsim.DCSim): 56 | 57 | """ 58 | Implementation for manual 59 | """ 60 | def __init__(self, ts, group_name): 61 | dcsim.DCSim.__init__(self, ts, group_name) 62 | 63 | def _param_value(self, name): 64 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 65 | 66 | def info(self): 67 | """ 68 | Return information string for the device. 69 | """ 70 | return 'Manual DC Power Supply' 71 | 72 | def config(self): 73 | """ 74 | Perform any configuration for the simulation based on the previously 75 | provided parameters. 76 | """ 77 | self.ts.confirm('Configure DC Power Supply.') 78 | 79 | def output(self, start=None): 80 | """ 81 | Start/stop power supply output 82 | 83 | start: if False stop output, if True start output 84 | """ 85 | if start is not None: 86 | if start is True: 87 | self.ts.confirm('Start DC Power Supply.') 88 | else: 89 | self.ts.confirm('Stop DC Power Supply.') 90 | else: # get output state 91 | return self.ts.prompt('What is the DC Power Supply status ("on"/"off")?') 92 | 93 | def output_mode(self, mode=None): 94 | """ 95 | Start/stop power supply output 96 | """ 97 | pass 98 | 99 | def current(self, current=None): 100 | """ 101 | Set the value for current if provided. If none provided, obtains the value for current. 102 | """ 103 | if current is not None: 104 | self.ts.confirm('Set DC Power Supply current to %s.' % current) 105 | else: 106 | current = self.ts.prompt('What is the DC Power Supply current (A)?') 107 | return current 108 | 109 | def current_max(self, current=None): 110 | """ 111 | Set the value for max current if provided. If none provided, obtains 112 | the value for max current. 113 | """ 114 | if current is not None: 115 | self.ts.confirm('Set DC Power Supply max current to %s.' % current) 116 | else: 117 | current = self.ts.prompt('What is the DC Power Supply max current (A)?') 118 | return current 119 | 120 | def voltage(self, voltage=None): 121 | """ 122 | Set the value for voltage if provided. If none provided, obtains 123 | the value for voltage. 124 | """ 125 | if voltage is not None: 126 | self.ts.confirm('Set DC Power Supply voltage to %s.' % voltage) 127 | else: 128 | voltage = self.ts.prompt('What is the DC Power Supply voltage (V)?') 129 | return voltage 130 | 131 | def voltage_max(self, voltage=None): 132 | """ 133 | Set the value for max voltage if provided. If none provided, obtains 134 | the value for max voltage. 135 | """ 136 | if voltage is not None: 137 | self.ts.confirm('Set DC Power Supply max voltage to %s.' % voltage) 138 | else: 139 | voltage = self.ts.prompt('What is the DC Power Supply max voltage (V)?') 140 | return voltage 141 | 142 | def voltage_min(self, voltage=None): 143 | """ 144 | Set the value for min voltage if provided. If none provided, obtains 145 | the value for min voltage. 146 | """ 147 | if voltage is not None: 148 | self.ts.confirm('Set DC Power Supply min voltage to %s.' % voltage) 149 | else: 150 | voltage = self.ts.prompt('What is the DC Power Supply min voltage (V)?') 151 | return voltage 152 | 153 | def relay(self, state=None): 154 | """ 155 | Set the state of the relay if provided. Valid states are: RELAY_OPEN, 156 | RELAY_CLOSED. If none is provided, obtains the state of the relay. 157 | """ 158 | if state is not None: 159 | self.ts.confirm('Set DC Power Supply relay to %s.' % state) 160 | else: 161 | state = self.ts.prompt('What is the DC Power Supply relay state ("open"/"closed"/"unknown")?') 162 | return state 163 | -------------------------------------------------------------------------------- /Lib/svpelab/device_awg400.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import time 34 | 35 | import vxi11 36 | 37 | 38 | class DeviceError(Exception): 39 | """ 40 | Exception to wrap all das generated exceptions. 41 | """ 42 | pass 43 | 44 | 45 | class Device(object): 46 | 47 | def __init__(self, params): 48 | self.params = params 49 | self.vx = None 50 | # Resource Manager for VISA 51 | self.rm = None 52 | # Connection to instrument for VISA-GPIB 53 | self.conn = None 54 | self.open() 55 | 56 | 57 | def open(self): 58 | 59 | try: 60 | if self.params['comm'] == 'Network': 61 | try: 62 | self.vx = vxi11.Instrument(self.params['ip_addr']) 63 | except Exception, e: 64 | raise DeviceError('AWG400 communication error: %s' % str(e)) 65 | elif self.params['comm'] == 'GPIB': 66 | raise NotImplementedError('The driver for plain GPIB is not implemented yet. ' + 67 | 'Please use VISA which supports also GPIB devices') 68 | elif self.params['comm'] == 'VISA': 69 | try: 70 | # sys.path.append(os.path.normpath(self.visa_path)) 71 | import visa 72 | self.rm = visa.ResourceManager() 73 | self.conn = self.rm.open_resource(self.params['visa_address']) 74 | 75 | except Exception, e: 76 | raise DeviceError('AWG400 communication error: %s' % str(e)) 77 | 78 | else: 79 | raise ValueError('Unknown communication type %s. Use GPIB or VISA' % self.params['comm']) 80 | 81 | except Exception, e: 82 | raise DeviceError(str(e)) 83 | pass 84 | 85 | def close(self): 86 | if self.params['comm'] == 'Network': 87 | if self.vx is not None: 88 | self.vx.close() 89 | self.vx = None 90 | elif self.params['comm'] == 'GPIB': 91 | raise NotImplementedError('The driver for plain GPIB is not implemented yet.') 92 | elif self.params['comm'] == 'VISA': 93 | try: 94 | if self.rm is not None: 95 | if self.conn is not None: 96 | self.conn.close() 97 | self.rm.close() 98 | except Exception, e: 99 | raise DeviceError('AWG400 communication error: %s' % str(e)) 100 | else: 101 | raise ValueError('Unknown communication type %s. Use Serial, GPIB or VISA' % self.params['comm']) 102 | 103 | def cmd(self, cmd_str): 104 | if self.params['comm'] == 'Network': 105 | try: 106 | self.vx.write(cmd_str) 107 | except Exception, e: 108 | raise DeviceError('AWG400 communication error: %s' % str(e)) 109 | 110 | elif self.params['comm'] == 'VISA': 111 | try: 112 | self.conn.write(cmd_str) 113 | except Exception, e: 114 | raise DeviceError('AWG400 communication error: %s' % str(e)) 115 | 116 | def query(self, cmd_str): 117 | resp = '' 118 | if self.params['comm'] == 'Network': 119 | try: 120 | resp = self.vx.ask(cmd_str) 121 | except Exception, e: 122 | raise DeviceError('AWG400 communication error: %s' % str(e)) 123 | elif self.params['comm'] == 'VISA': 124 | self.cmd(cmd_str) 125 | resp = self.conn.read() 126 | 127 | return resp 128 | 129 | def info(self): 130 | return self.query('*IDN?') 131 | 132 | def load_config(self, params): 133 | """ 134 | Enable channels 135 | :param params: dict containing following possible elements: 136 | 'sequence_filename': 137 | :return: 138 | """ 139 | pass 140 | 141 | def start(self): 142 | """ 143 | Start sequence execution 144 | :return: 145 | """ 146 | pass 147 | 148 | def stop(self): 149 | """ 150 | Start sequence execution 151 | :return: 152 | """ 153 | pass 154 | 155 | def chan_enable(self, chans): 156 | """ 157 | Enable channels 158 | :param chans: list of channels to enable 159 | :return: 160 | """ 161 | pass 162 | 163 | def chan_disable(self, chans): 164 | """ 165 | Disable channels 166 | :param chans: list of channels to disable 167 | :return: 168 | """ 169 | pass 170 | 171 | 172 | if __name__ == "__main__": 173 | 174 | pass 175 | -------------------------------------------------------------------------------- /Lib/svpelab/device_das_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | class Device(object): 34 | 35 | def __init__(self, params=None): 36 | self.data_points = [] 37 | 38 | def info(self): 39 | return 'DAS Manual - 1.0' 40 | 41 | def open(self): 42 | pass 43 | 44 | def close(self): 45 | pass 46 | 47 | def data_capture(self, enable=True): 48 | pass 49 | 50 | def data_read(self): 51 | return [] 52 | -------------------------------------------------------------------------------- /Lib/svpelab/device_das_sim.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | import time 35 | import dataset 36 | 37 | 38 | class DeviceError(Exception): 39 | """ 40 | Exception to wrap all das generated exceptions. 41 | """ 42 | pass 43 | 44 | 45 | class Device(object): 46 | 47 | def __init__(self, params=None): 48 | self.ts = params['ts'] 49 | self.points = params['points'] 50 | self.data_points = [] 51 | self.data_file = params['data_file'] 52 | self.at_end = params['at_end'] 53 | self.file_= None 54 | self.use_timestamp = params['use_timestamp'] 55 | self.ds = dataset.Dataset() 56 | self.index = 0 57 | 58 | if self.data_file: 59 | self.ds.from_csv(self.data_file) 60 | self.data_points = list(self.ds.points) 61 | else: 62 | raise DeviceError('No data file specified') 63 | 64 | def info(self): 65 | return 'DAS Simulator - 1.0' 66 | 67 | def open(self): 68 | pass 69 | 70 | def close(self): 71 | pass 72 | 73 | def data_capture(self, enable=True): 74 | pass 75 | 76 | def data_read(self): 77 | data = [] 78 | if len(self.ds.points) > 0: 79 | count = len(self.ds.data[0]) 80 | if count > 0: 81 | if self.index >= count: 82 | if self.at_end == 'Loop to start': 83 | self.index = 0 84 | elif self.at_end == 'Repeat last record': 85 | self.index = count - 1 86 | else: 87 | raise DeviceError('End of data reached') 88 | 89 | for i in range(len(self.ds.points)): 90 | data.append(self.ds.data[i][self.index]) 91 | 92 | return data 93 | 94 | def waveform_config(self, params): 95 | pass 96 | 97 | def waveform_capture(self, enable=True, sleep=None): 98 | """ 99 | Enable/disable waveform capture. 100 | """ 101 | pass 102 | 103 | def waveform_status(self): 104 | # mm-dd-yyyy hh_mm_ss waveform trigger.txt 105 | # mm-dd-yyyy hh_mm_ss.wfm 106 | # return INACTIVE, ACTIVE, COMPLETE 107 | return 'COMPLETE' 108 | 109 | def waveform_force_trigger(self): 110 | pass 111 | 112 | def waveform_capture_dataset(self): 113 | return self.ds 114 | 115 | if __name__ == "__main__": 116 | 117 | pass 118 | 119 | 120 | -------------------------------------------------------------------------------- /Lib/svpelab/device_pz4000.py: -------------------------------------------------------------------------------- 1 | 2 | import time 3 | 4 | # map data points to query points 5 | query_points = { 6 | 'AC_VRMS': 'URMS', 7 | 'AC_IRMS': 'IRMS', 8 | 'AC_P': 'P', 9 | 'AC_S': 'S', 10 | 'AC_Q': 'Q', 11 | 'AC_PF': 'LAMBDA', 12 | 'AC_FREQ': 'FU', 13 | 'DC_V': 'UDC', 14 | 'DC_I': 'IDC', 15 | 'DC_P': 'P' 16 | } 17 | 18 | class DeviceError(Exception): 19 | """ 20 | Exception to wrap all das generated exceptions. 21 | """ 22 | pass 23 | 24 | class Device(object): 25 | 26 | def __init__(self, params): 27 | self.params = params 28 | self.channels = params.get('channels') 29 | self.data_points = ['TIME'] 30 | # Resource Manager for VISA 31 | self.rm = None 32 | # Connection to instrument for VISA-GPIB 33 | self.conn = None 34 | 35 | # create query string for configured channels 36 | query_chan_str = '' 37 | item = 0 38 | for i in range(1,5): 39 | chan = self.channels[i] 40 | if chan is not None: 41 | chan_type = chan.get('type') 42 | points = chan.get('points') 43 | chan_label = chan.get('label') 44 | if chan_type is None: 45 | raise DeviceError('No channel type specified') 46 | if points is None: 47 | raise DeviceError('No points specified') 48 | for p in points: 49 | item += 1 50 | point_str = '%s_%s' % (chan_type, p) 51 | chan_str = query_points.get(point_str) 52 | query_chan_str += ':NUMERIC:NORMAL:ITEM%d %s,%d;' % (item, chan_str, i) 53 | if chan_label: 54 | point_str = '%s_%s' % (point_str, chan_label) 55 | self.data_points.append(point_str) 56 | query_chan_str += '\n:NUMERIC:NORMAL:VALUE?' 57 | 58 | self.query_str = ':NUMERIC:FORMAT ASCII\nNUMERIC:NORMAL:NUMBER %d\n' % (item) + query_chan_str 59 | 60 | self.open() 61 | 62 | def open(self): 63 | try: 64 | if self.params['comm'] == 'GPIB': 65 | raise NotImplementedError('The driver for plain GPIB is not implemented yet. ' + 66 | 'Please use VISA which supports also GPIB devices') 67 | elif self.params['comm'] == 'VISA': 68 | try: 69 | # sys.path.append(os.path.normpath(self.visa_path)) 70 | import visa 71 | self.rm = visa.ResourceManager() 72 | self.conn = self.rm.open_resource(self.params['visa_address']) 73 | 74 | except Exception, e: 75 | raise DeviceError('PZ4000 communication error: %s' % str(e)) 76 | 77 | else: 78 | raise ValueError('Unknown communication type %s. Use GPIB or VISA' % self.params['comm']) 79 | 80 | except Exception, e: 81 | raise DeviceError(str(e)) 82 | 83 | 84 | def close(self): 85 | """ 86 | Close any open communications resources associated with the grid 87 | simulator. 88 | """ 89 | if self.params['comm'] == 'GPIB': 90 | raise NotImplementedError('The driver for plain GPIB is not implemented yet.') 91 | elif self.params['comm'] == 'VISA': 92 | try: 93 | if self.rm is not None: 94 | if self.conn is not None: 95 | self.conn.close() 96 | self.rm.close() 97 | 98 | 99 | except Exception, e: 100 | raise DeviceError('PZ4000 communication error: %s' % str(e)) 101 | else: 102 | raise ValueError('Unknown communication type %s. Use Serial, GPIB or VISA' % self.params['comm']) 103 | 104 | def cmd(self, cmd_str): 105 | try: 106 | self.conn.write(cmd_str) 107 | 108 | except Exception, e: 109 | raise DeviceError('PZ4000 communication error: %s' % str(e)) 110 | 111 | def query(self, cmd_str): 112 | self.cmd(cmd_str) 113 | resp = self.conn.read() 114 | return resp 115 | 116 | def info(self): 117 | return self.query('*IDN?') 118 | 119 | def data_capture(self, enable=True): 120 | pass 121 | 122 | def data_read(self): 123 | data = [float(i) for i in self.query(self.query_str).split(',')] 124 | data.insert(0, time.time()) 125 | return data 126 | 127 | if __name__ == "__main__": 128 | 129 | pass 130 | -------------------------------------------------------------------------------- /Lib/svpelab/device_switch_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | class Device(object): 34 | 35 | def __init__(self, params=None): 36 | pass 37 | 38 | def info(self): 39 | return 'Switch Controller Manual - 1.0' 40 | 41 | def open(self): 42 | pass 43 | 44 | def close(self): 45 | pass 46 | 47 | def switch_open(self): 48 | pass 49 | 50 | def switch_close(self): 51 | pass 52 | 53 | def switch_state(self): 54 | pass 55 | -------------------------------------------------------------------------------- /Lib/svpelab/device_wavegen_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | class Device(object): 34 | 35 | def __init__(self, params=None): 36 | pass 37 | 38 | def info(self): 39 | return 'Waveform Generator Manual - 1.0' 40 | 41 | def open(self): 42 | pass 43 | 44 | def close(self): 45 | pass 46 | 47 | def start(self): 48 | """ 49 | Start sequence execution 50 | :return: 51 | """ 52 | pass 53 | 54 | def stop(self): 55 | """ 56 | Start sequence execution 57 | :return: 58 | """ 59 | pass 60 | 61 | def chan_enable(self, chans): 62 | """ 63 | Enable channels 64 | :param chans: list of channels to enable 65 | :return: 66 | """ 67 | pass 68 | 69 | def chan_disable(self, chans): 70 | """ 71 | Disable channels 72 | :param chans: list of channels to disable 73 | :return: 74 | """ 75 | pass 76 | -------------------------------------------------------------------------------- /Lib/svpelab/grid_profiles.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | # (time offset in seconds, % nominal voltage 1, % nominal voltage 2, % nominal voltage 3, % nominal frequency) 34 | vv_voltage_profile = [ 35 | (0, 100, 100, 100, 100), 36 | (30, 100, 100, 100, 100), 37 | (30, 106, 106, 106, 100), 38 | (60, 106, 106, 106, 100), 39 | (60, 94, 94, 94, 100), 40 | (90, 94, 94, 94, 100), 41 | (90, 100, 100, 100, 100), 42 | (120, 100, 100, 100, 100), 43 | (135, 106, 106, 106, 100), 44 | (150, 106, 106, 106, 100), 45 | (180, 94, 94, 94, 100), 46 | (195, 94, 94, 94, 100), 47 | (210, 100, 100, 100, 100), 48 | (240, 100, 100, 100, 100), 49 | (245, 106, 106, 106, 100), 50 | (250, 106, 106, 106, 100), 51 | (260, 94, 94, 94, 100), 52 | (265, 94, 94, 94, 100), 53 | (270, 100, 100, 100, 100), 54 | (300, 100, 100, 100, 100) 55 | ] 56 | 57 | vrt_50v_2s = [ 58 | (0, 50, 50, 50, 100), 59 | (2, 50, 50, 50, 100), 60 | (2, 100, 100, 100, 100) 61 | ] 62 | 63 | # (time offset in seconds, % nominal voltage, % nominal frequency) 64 | fw_freq_profile = [ 65 | (0, 100.0, 100.0, 100.0, 100.0), 66 | (30, 100.0, 100.0, 100.0, 100.0), 67 | (30, 100.0, 100.0, 100.0, 103.0), 68 | (60, 100.0, 100.0, 100.0, 103.0), 69 | (60, 100.0, 100.0, 100.0, 97.0), 70 | (90, 100.0, 100.0, 100.0, 97.0), 71 | (90, 100.0, 100.0, 100.0, 103.0), 72 | (95, 100.0, 100.0, 100.0, 103.0), 73 | (95, 100.0, 100.0, 100.0, 100.0), 74 | (125, 100.0, 100.0, 100.0, 100.0), 75 | (155, 100.0, 100.0, 100.0, 102.0), 76 | (185, 100.0, 100.0, 100.0, 102.0), 77 | (215, 100.0, 100.0, 100.0, 98.0), 78 | (245, 100.0, 100.0, 100.0, 98.0), 79 | (260, 100.0, 100.0, 100.0, 102.0), 80 | (275, 100.0, 100.0, 100.0, 102.0), 81 | (280, 100.0, 100.0, 100.0, 100.0), 82 | (295, 100.0, 100.0, 100.0, 100.0), 83 | (310, 100.0, 100.0, 100.0, 100.3), 84 | (325, 100.0, 100.0, 100.0, 100.3), 85 | (340, 100.0, 100.0, 100.0, 100.0), 86 | (360, 100.0, 100.0, 100.0, 100.0) 87 | ] 88 | 89 | profiles = { 90 | 'FW Profile': fw_freq_profile, 91 | 'VV Profile': vv_voltage_profile, 92 | 'VRT Test Profile': vrt_50v_2s 93 | } 94 | 95 | if __name__ == "__main__": 96 | 97 | pass 98 | -------------------------------------------------------------------------------- /Lib/svpelab/gridsim_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import gridsim 36 | 37 | manual_info = { 38 | 'name': os.path.splitext(os.path.basename(__file__))[0], 39 | 'mode': 'Manual' 40 | } 41 | 42 | def gridsim_info(): 43 | return manual_info 44 | 45 | def params(info, group_name): 46 | gname = lambda name: group_name + '.' + name 47 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 48 | mode = manual_info['mode'] 49 | info.param_add_value(gname('mode'), mode) 50 | 51 | GROUP_NAME = 'manual' 52 | 53 | 54 | class GridSim(gridsim.GridSim): 55 | 56 | def __init__(self, ts, group_name, params=None): 57 | gridsim.GridSim.__init__(self, ts, group_name, params) 58 | 59 | if ts.confirm('Please run the grid simulator profile.') is False: 60 | raise gridsim.GridSimError('Aborted grid simulation') 61 | -------------------------------------------------------------------------------- /Lib/svpelab/gridsim_sim.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import gridsim 36 | 37 | sim_info = { 38 | 'name': os.path.splitext(os.path.basename(__file__))[0], 39 | 'mode': 'Grid Simulator Simulation' 40 | } 41 | 42 | def gridsim_info(): 43 | return sim_info 44 | 45 | def params(info, group_name): 46 | gname = lambda name: group_name + '.' + name 47 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 48 | mode = sim_info['mode'] 49 | info.param_add_value(gname('mode'), mode) 50 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 51 | active=gname('mode'), active_value=mode, glob=True) 52 | info.param_add_value(gname('mode'), sim_info['mode']) 53 | 54 | GROUP_NAME = 'sim' 55 | 56 | 57 | class GridSim(gridsim.GridSim): 58 | 59 | def __init__(self, ts, group_name, params=None): 60 | gridsim.GridSim.__init__(self, ts, group_name, params) 61 | -------------------------------------------------------------------------------- /Lib/svpelab/hil.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | import sys 33 | import os 34 | import glob 35 | import importlib 36 | 37 | # Import all hardware-in-the-loop extensions in current directory. 38 | # A hil extension has a file name of hil_*.py and contains a function hil_params(info) that contains 39 | # a dict with the following entries: name, init_func. 40 | 41 | # dict of modules found, entries are: name : module_name 42 | 43 | hil_modules = {} 44 | 45 | def params(info): 46 | info.param_group('hil', label='HIL Parameters', glob=True) 47 | info.param('hil.mode', label='HIL Environment', default='Disabled', values=['Disabled']) 48 | for mode, m in hil_modules.iteritems(): 49 | m.params(info) 50 | 51 | 52 | def hil_init(ts): 53 | """ 54 | Function to create specific HIL implementation instances. 55 | 56 | Each supported HIL type should have an entry in the 'mode' parameter conditional. 57 | Module import for the simulator is done within the conditional so modules only need to be 58 | present if used. 59 | """ 60 | mode = ts.param_value('hil.mode') 61 | sim = None 62 | if mode != 'Disabled': 63 | hil_module = hil_modules.get(mode) 64 | if hil_module is not None: 65 | sim = hil_module.HIL(ts) 66 | else: 67 | raise HILError('Unknown grid simulation mode: %s' % mode) 68 | 69 | return sim 70 | 71 | 72 | class HILError(Exception): 73 | """ 74 | Exception to wrap all HIL generated exceptions. 75 | """ 76 | pass 77 | 78 | 79 | class HIL(object): 80 | """ 81 | Template for HIL implementations. This class can be used as a base class or 82 | independent HIL classes can be created containing the methods contained in this class. 83 | """ 84 | 85 | def __init__(self, ts, params=None): 86 | self.ts = ts 87 | self.params = params 88 | 89 | if self.params is None: 90 | self.params = {} 91 | 92 | def config(self): 93 | """ 94 | Perform any configuration for the simulation based on the previously 95 | provided parameters. 96 | """ 97 | pass 98 | 99 | def open(self): 100 | """ 101 | Open the communications resources associated with the HIL. 102 | """ 103 | pass 104 | 105 | def close(self): 106 | """ 107 | Close any open communications resources associated with the HIL. 108 | """ 109 | self.stop_simulation() 110 | 111 | def info(self): 112 | pass 113 | 114 | def control_panel_info(self): 115 | pass 116 | 117 | def load_schematic(self): 118 | pass 119 | 120 | def compile_model(self): 121 | pass 122 | 123 | def load_model_on_hil(self): 124 | pass 125 | 126 | def init_sim_settings(self): 127 | pass 128 | 129 | def init_control_panel(self): 130 | pass 131 | 132 | def voltage(self, voltage=None): 133 | pass 134 | 135 | def stop_simulation(self): 136 | pass 137 | 138 | def start_simulation(self): 139 | pass 140 | 141 | 142 | def hil_scan(): 143 | global hil_modules 144 | # scan all files in current directory that match hil_*.py 145 | package_name = '.'.join(__name__.split('.')[:-1]) 146 | files = glob.glob(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'hil_*.py')) 147 | for f in files: 148 | module_name = None 149 | try: 150 | module_name = os.path.splitext(os.path.basename(f))[0] 151 | if package_name: 152 | module_name = package_name + '.' + module_name 153 | m = importlib.import_module(module_name) 154 | if hasattr(m, 'hil_info'): 155 | info = m.hil_info() 156 | mode = info.get('mode') 157 | # place module in module dict 158 | if mode is not None: 159 | hil_modules[mode] = m 160 | else: 161 | if module_name is not None and module_name in sys.modules: 162 | del sys.modules[module_name] 163 | except Exception, e: 164 | if module_name is not None and module_name in sys.modules: 165 | del sys.modules[module_name] 166 | raise HILError('Error scanning module %s: %s' % (module_name, str(e))) 167 | 168 | # scan for hil modules on import 169 | hil_scan() 170 | 171 | if __name__ == "__main__": 172 | pass 173 | -------------------------------------------------------------------------------- /Lib/svpelab/loadsim.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import sys 34 | import os 35 | import glob 36 | import importlib 37 | 38 | loadsim_modules = {} 39 | 40 | def params(info, id=None, label='Load Simulator', group_name=None, active=None, active_value=None): 41 | if group_name is None: 42 | group_name = LOADSIM_DEFAULT_ID 43 | else: 44 | group_name += '.' + LOADSIM_DEFAULT_ID 45 | if id is not None: 46 | group_name = group_name + '_' + str(id) 47 | print 'group_name = %s' % group_name 48 | name = lambda name: group_name + '.' + name 49 | info.param_group(group_name, label='%s Parameters' % label, active=active, active_value=active_value, glob=True) 50 | print 'name = %s' % name('mode') 51 | info.param(name('mode'), label='Mode', default='Disabled', values=['Disabled']) 52 | for mode, m in loadsim_modules.iteritems(): 53 | m.params(info, group_name=group_name) 54 | 55 | LOADSIM_DEFAULT_ID = 'loadsim' 56 | 57 | def loadsim_init(ts, id=None, group_name=None): 58 | """ 59 | Function to create specific loadsim implementation instances. 60 | """ 61 | if group_name is None: 62 | group_name = LOADSIM_DEFAULT_ID 63 | else: 64 | group_name += '.' + LOADSIM_DEFAULT_ID 65 | if id is not None: 66 | group_name = group_name + '_' + str(id) 67 | mode = ts.param_value(group_name + '.' + 'mode') 68 | sim = None 69 | if mode != 'Disabled': 70 | sim_module = loadsim_modules.get(mode) 71 | if sim_module is not None: 72 | sim = sim_module.LoadSim(ts, group_name) 73 | else: 74 | raise LoadSimError('Unknown loadsim system mode: %s' % mode) 75 | 76 | return sim 77 | 78 | 79 | class LoadSimError(Exception): 80 | """ 81 | Exception to wrap all loadsim generated exceptions. 82 | """ 83 | pass 84 | 85 | 86 | class LoadSim(object): 87 | """ 88 | Template for grid simulator implementations. This class can be used as a base class or 89 | independent grid simulator classes can be created containing the methods contained in this class. 90 | """ 91 | 92 | def __init__(self, ts, group_name): 93 | self.ts = ts 94 | self.group_name = group_name 95 | 96 | 97 | def info(self): 98 | """ 99 | Get device information. 100 | """ 101 | pass 102 | 103 | def open(self): 104 | """ 105 | Open any open communications resources associated with the load simulator. 106 | """ 107 | pass 108 | 109 | def close(self): 110 | """ 111 | Close any open communications resources associated with the load simulator. 112 | """ 113 | pass 114 | 115 | def resistance(self, r=None, ph = None): 116 | pass 117 | 118 | def inductance(self, i=None, ph=None): 119 | pass 120 | 121 | def capacitance(self, c=None, ph=None): 122 | pass 123 | 124 | def capacitor_q(self, q=None, ph=None): 125 | pass 126 | 127 | def inductor_q(self, q=None, ph=None): 128 | pass 129 | 130 | def resistance_p(self, p=None, ph=None): 131 | pass 132 | 133 | def tune_current(self, i=None, ph=None): 134 | pass 135 | 136 | 137 | def loadsim_scan(): 138 | global loadsim_modules 139 | # scan all files in current directory that match loadsim_*.py 140 | package_name = '.'.join(__name__.split('.')[:-1]) 141 | files = glob.glob(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'loadsim_*.py')) 142 | for f in files: 143 | module_name = None 144 | try: 145 | module_name = os.path.splitext(os.path.basename(f))[0] 146 | if package_name: 147 | module_name = package_name + '.' + module_name 148 | m = importlib.import_module(module_name) 149 | if hasattr(m, 'loadsim_info'): 150 | info = m.loadsim_info() 151 | mode = info.get('mode') 152 | # place module in module dict 153 | if mode is not None: 154 | loadsim_modules[mode] = m 155 | else: 156 | if module_name is not None and module_name in sys.modules: 157 | del sys.modules[module_name] 158 | except Exception, e: 159 | if module_name is not None and module_name in sys.modules: 160 | del sys.modules[module_name] 161 | raise LoadSimError('Error scanning module %s: %s' % (module_name, str(e))) 162 | 163 | # scan for loadsim modules on import 164 | loadsim_scan() 165 | 166 | if __name__ == "__main__": 167 | pass 168 | -------------------------------------------------------------------------------- /Lib/svpelab/loadsim_chroma_A800067.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | import loadsim 35 | import chroma_A800067 as chroma 36 | 37 | chroma_info = { 38 | 'name': os.path.splitext(os.path.basename(__file__))[0], 39 | 'mode': 'Chroma A800067' 40 | } 41 | 42 | def loadsim_info(): 43 | return chroma_info 44 | 45 | def params(info, group_name=None): 46 | gname = lambda name: group_name + '.' + name 47 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 48 | mode = chroma_info['mode'] 49 | info.param_add_value(gname('mode'), mode) 50 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 51 | active=gname('mode'), active_value=mode, glob=True) 52 | 53 | info.param(pname('comm'), label='Communications Interface', default='VISA', values=['VISA']) 54 | info.param(pname('visa_device'), label='VISA Device String', active=pname('comm'), 55 | active_value=['VISA'], default='GPIB0::0::INSTR') 56 | info.param(pname('visa_path'), label='VISA Path', active=pname('comm'), 57 | active_value=['VISA'], default='') 58 | info.param(pname('volts'), label='Voltage', default=220) 59 | info.param(pname('freq'), label='Frequency', default=50) 60 | 61 | GROUP_NAME = 'chroma_A800067' 62 | 63 | 64 | class LoadSim(loadsim.LoadSim): 65 | """ 66 | Chroma loadsim class. 67 | """ 68 | def __init__(self, ts, group_name): 69 | loadsim.LoadSim.__init__(self, ts, group_name) 70 | self.visa_device = self._param_value('visa_device') 71 | self.visa_path = self._param_value('visa_path') 72 | self.volts = self._param_value('volts') 73 | self.freq = self._param_value('freq') 74 | 75 | self.rlc = chroma.ChromaRLC(visa_device=self.visa_device, visa_path=self.visa_path, volts=self.volts, 76 | freq=self.freq) 77 | self.rlc.open() 78 | 79 | def _param_value(self, name): 80 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 81 | 82 | def resistance(self, ph=None, r=None): 83 | self.rlc.resistance(ph, r) 84 | 85 | def voltset(self, v): 86 | return self.rlc.voltset(v) 87 | 88 | def freqset(self, f): 89 | return self.rlc.freqset(f) 90 | 91 | def inductance(self, ph, i=None): 92 | if i is not None: 93 | return self.rlc.inductance(ph, i) 94 | 95 | def capacitance(self, ph, i=None): 96 | if i is not None: 97 | return self.rlc.capacitance(ph, i) 98 | else: 99 | self.ts.log('Enter the capacitive load in F.') 100 | 101 | """def capacitor_q(self, q=None): 102 | if q is not None: 103 | self.ts.log('Adjust the capacitive load of the fundamental freq to %0.3f VAr.' % q) 104 | else: 105 | self.ts.log('Enter the capacitor reactive power in VAr.') 106 | 107 | def inductor_q(self, q=None): 108 | if q is not None: 109 | self.ts.log('Adjust the inductive load of the fundamental freq to %0.3f VAr.' % q) 110 | else: 111 | self.ts.log('Enter the inductor reactive power in VAr.') 112 | 113 | def resistance_p(self, p=None): 114 | if p is not None: 115 | self.ts.log('Adjust the resistive load of the fundamental freq to %0.3f W.' % p) 116 | else: 117 | self.ts.log('Enter the resistor power in W.') 118 | 119 | def tune_current(self, i=None): 120 | if c is not None: 121 | self.ts.log('Adjust R, L, and C until the fundamental frequency current through switch S3 is ' 122 | 'less than %0.2f' % i) 123 | else: 124 | pass 125 | """ -------------------------------------------------------------------------------- /Lib/svpelab/loadsim_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | import loadsim 35 | 36 | manual_info = { 37 | 'name': os.path.splitext(os.path.basename(__file__))[0], 38 | 'mode': 'Manual' 39 | } 40 | 41 | def loadsim_info(): 42 | return manual_info 43 | 44 | def params(info, group_name=None): 45 | gname = lambda name: group_name + '.' + name 46 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 47 | mode = manual_info['mode'] 48 | info.param_add_value(gname('mode'), mode) 49 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 50 | active=gname('mode'), active_value=mode, glob=True) 51 | 52 | GROUP_NAME = 'manual' 53 | 54 | 55 | class LoadSim(loadsim.LoadSim): 56 | """ 57 | Template for RLC load implementations. This class can be used as a base class or 58 | independent RLC load classes can be created containing the methods contained in this class. 59 | """ 60 | 61 | def __init__(self, ts, group_name): 62 | loadsim.LoadSim.__init__(self, ts, group_name) 63 | 64 | def resistance(self, r=None): 65 | if r is not None: 66 | self.ts.confirm('Adjust the resistive load to R = %0.3f Ohms.' % r) 67 | else: 68 | self.ts.log('Enter the resistive load in Ohms.') 69 | 70 | def inductance(self, i=None): 71 | if i is not None: 72 | self.ts.confirm('Adjust the inductive load to L = %0.6f H.' % i) 73 | else: 74 | self.ts.log('Enter the inductive load in H.') 75 | 76 | def capacitance(self, c=None): 77 | if c is not None: 78 | self.ts.confirm('Adjust the capacitive load to C = %0.6f F.' % c) 79 | else: 80 | self.ts.log('Enter the capacitive load in F.') 81 | 82 | def capacitor_q(self, q=None): 83 | if q is not None: 84 | self.ts.confirm('Adjust the capacitive load of the fundamental freq to %0.3f VAr.' % q) 85 | else: 86 | self.ts.log('Enter the capacitor reactive power in VAr.') 87 | 88 | def inductor_q(self, q=None): 89 | if q is not None: 90 | self.ts.confirm('Adjust the inductive load of the fundamental freq to %0.3f VAr.' % q) 91 | else: 92 | self.ts.log('Enter the inductor reactive power in VAr.') 93 | 94 | def resistance_p(self, p=None): 95 | if p is not None: 96 | self.ts.confirm('Adjust the resistive load of the fundamental freq to %0.3f W.' % p) 97 | else: 98 | self.ts.log('Enter the resistor power in W.') 99 | 100 | def tune_current(self, i=None): 101 | if c is not None: 102 | self.ts.confirm('Adjust R, L, and C until the fundamental frequency current through switch S3 is ' 103 | 'less than %0.2f' % i) 104 | else: 105 | pass 106 | 107 | def switch_s3(self, switch_state=None): 108 | if switch_state is not None: 109 | if switch_state == loadsim.S3_CLOSED: 110 | self.ts.confirm('Close S3 switch (switch to the utility). ' 111 | 'Verify that the EUT output current is zero before closing.') 112 | elif switch_state == loadsim.S3_OPEN: 113 | self.ts.confirm('Open S3 switch (switch to the utility).') 114 | else: 115 | self.ts.log_warning('Unknown S3 switch state.') 116 | else: 117 | self.ts.log_warning('No switch state given for the RLC Load S3 switch.') 118 | 119 | -------------------------------------------------------------------------------- /Lib/svpelab/loadsim_pass.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | import loadsim 35 | 36 | pass_info = { 37 | 'name': os.path.splitext(os.path.basename(__file__))[0], 38 | 'mode': 'Pass' 39 | } 40 | 41 | def load_info(): 42 | return pass_info 43 | 44 | def params(info, group_name=None): 45 | gname = lambda name: group_name + '.' + name 46 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 47 | mode = pass_info['mode'] 48 | info.param_add_value(gname('mode'), mode) 49 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 50 | active=gname('mode'), active_value=mode, glob=True) 51 | 52 | GROUP_NAME = 'pass' 53 | 54 | 55 | class LoadSim(loadsim.LoadSim): 56 | """ 57 | Template for RLC load implementations. This class can be used as a base class or 58 | independent RLC load classes can be created containing the methods contained in this class. 59 | """ 60 | 61 | def __init__(self, ts, group_name): 62 | loadsim.LoadSim.__init__(self, ts, group_name) 63 | 64 | def resistance(self, r=None): 65 | if r is not None: 66 | self.ts.log('Adjust the resistive load to R = %0.3f Ohms.' % r) 67 | else: 68 | self.ts.log('Enter the resistive load in Ohms.') 69 | 70 | def inductance(self, i=None): 71 | if i is not None: 72 | self.ts.log('Adjust the inductive load to L = %0.6f H.' % i) 73 | else: 74 | self.ts.log('Enter the inductive load in H.') 75 | 76 | def capacitance(self, c=None): 77 | if c is not None: 78 | self.ts.log('Adjust the capacitive load to C = %0.6f F.' % c) 79 | else: 80 | self.ts.log('Enter the capacitive load in F.') 81 | 82 | def capacitor_q(self, q=None): 83 | if q is not None: 84 | self.ts.log('Adjust the capacitive load of the fundamental freq to %0.3f VAr.' % q) 85 | else: 86 | self.ts.log('Enter the capacitor reactive power in VAr.') 87 | 88 | def inductor_q(self, q=None): 89 | if q is not None: 90 | self.ts.log('Adjust the inductive load of the fundamental freq to %0.3f VAr.' % q) 91 | else: 92 | self.ts.log('Enter the inductor reactive power in VAr.') 93 | 94 | def resistance_p(self, p=None): 95 | if p is not None: 96 | self.ts.log('Adjust the resistive load of the fundamental freq to %0.3f W.' % p) 97 | else: 98 | self.ts.log('Enter the resistor power in W.') 99 | 100 | def tune_current(self, i=None): 101 | if c is not None: 102 | self.ts.log('Adjust R, L, and C until the fundamental frequency current through switch S3 is ' 103 | 'less than %0.2f' % i) 104 | else: 105 | pass 106 | 107 | def switch_s3(self, switch_state=None): 108 | if switch_state is not None: 109 | if switch_state == loadsim.S3_CLOSED: 110 | self.ts.log('Closing S3 switch (switch to the utility).') 111 | elif switch_state == loadsim.S3_OPEN: 112 | self.ts.log('Opening S3 switch (switch to the utility).') 113 | else: 114 | self.ts.log_warning('Unknown S3 switch state.') 115 | else: 116 | self.ts.log_warning('No switch state given for the RLC Load S3 switch.') 117 | 118 | -------------------------------------------------------------------------------- /Lib/svpelab/loadsim_sandia.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | import loadsim 35 | 36 | sandia_info = { 37 | 'name': os.path.splitext(os.path.basename(__file__))[0], 38 | 'mode': 'Sandia' 39 | } 40 | 41 | def load_info(): 42 | return sandia_info 43 | 44 | def params(info, group_name=None): 45 | gname = lambda name: group_name + '.' + name 46 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 47 | mode = sandia_info['mode'] 48 | info.param_add_value(gname('mode'), mode) 49 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 50 | active=gname('mode'), active_value=mode, glob=True) 51 | 52 | # RTU parameters 53 | info.param(pname('ifc_name'), label='Interface Name', default='COM3', active=pname('ifc_type'), 54 | active_value=['RTU'], 55 | desc='Select the communication port from the UMS computer to the EUT.') 56 | info.param(pname('baudrate'), label='Baud Rate', default=9600, values=[9600, 19200], active=pname('ifc_type'), 57 | active_value=['RTU']) 58 | info.param(pname('parity'), label='Parity', default='N', values=['N', 'E'], active=pname('ifc_type'), 59 | active_value=['RTU']) 60 | # TCP parameters 61 | info.param(pname('ipaddr'), label='IP Address', default='192.168.0.170', active=pname('ifc_type'), 62 | active_value=['TCP']) 63 | info.param(pname('ipport'), label='IP Port', default=502, active=pname('ifc_type'), active_value=['TCP']) 64 | 65 | info.param(pname('relay_ifc_type'), label='Relay Interface Type', default='VISA', values=['VISA', 'RTU', 'TCP']) 66 | # VISA parameters 67 | info.param(pname('relay_ifc_name'), label='VISA String', default='ASRL1::INSTR', active=pname('relay_ifc_type'), 68 | active_value=['VISA'], desc='Enter VISA string.') 69 | # Need to change /Dev1/port0/line17 70 | # u'ASRL1::INSTR', u'ASRL2::INSTR', u'ASRL3::INSTR', u'ASRL4::INSTR', u'ASRL7::INSTR' 71 | 72 | GROUP_NAME = 'sandia' 73 | 74 | 75 | class LoadSim(loadsim.LoadSim): 76 | """ 77 | Template for RLC load implementations. This class can be used as a base class or 78 | independent RLC load classes can be created containing the methods contained in this class. 79 | """ 80 | 81 | def __init__(self, ts, group_name): 82 | loadsim.LoadSim.__init__(self, ts, group_name) 83 | 84 | def resistance(self, r=None): 85 | if r is not None: 86 | self.ts.confirm('Adjust the resistive load to R = %0.3f Ohms.' % r) 87 | else: 88 | self.ts.log('Enter the resistive load in Ohms.') 89 | 90 | def inductance(self, i=None): 91 | if i is not None: 92 | self.ts.confirm('Adjust the inductive load to L = %0.6f H.' % i) 93 | else: 94 | self.ts.log('Enter the inductive load in H.') 95 | 96 | def capacitance(self, c=None): 97 | if c is not None: 98 | self.ts.confirm('Adjust the capacitive load to C = %0.6f F.' % c) 99 | else: 100 | self.ts.log('Enter the capacitive load in F.') 101 | 102 | def capacitor_q(self, q=None): 103 | if q is not None: 104 | self.ts.confirm('Adjust the capacitive load of the fundamental freq to %0.3f VAr.' % q) 105 | else: 106 | self.ts.log('Enter the capacitor reactive power in VAr.') 107 | 108 | def inductor_q(self, q=None): 109 | if q is not None: 110 | self.ts.confirm('Adjust the inductive load of the fundamental freq to %0.3f VAr.' % q) 111 | else: 112 | self.ts.log('Enter the inductor reactive power in VAr.') 113 | 114 | def resistance_p(self, p=None): 115 | if p is not None: 116 | self.ts.confirm('Adjust the resistive load of the fundamental freq to %0.3f W.' % p) 117 | else: 118 | self.ts.log('Enter the resistor power in W.') 119 | 120 | def tune_current(self, i=None): 121 | if c is not None: 122 | self.ts.confirm('Adjust R, L, and C until the fundamental frequency current through switch S3 is ' 123 | 'less than %0.2f' % i) 124 | else: 125 | pass 126 | 127 | def switch_s3(self, switch_state=None): 128 | if switch_state is not None: 129 | if switch_state == loadsim.S3_CLOSED: 130 | self.ts.confirm('Preparing to close S3 switch (switch to the utility). ' 131 | 'Verify that the inverter output current is zero.') 132 | elif switch_state == loadsim.S3_OPEN: 133 | self.ts.log('Opening S3 switch (switch to the utility).') 134 | else: 135 | self.ts.log_warning('Unknown S3 switch state.') 136 | else: 137 | self.ts.log_warning('No switch state given for the RLC Load S3 switch.') 138 | -------------------------------------------------------------------------------- /Lib/svpelab/loadsimx_chroma.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | import loadsim 35 | import chroma_A800067 as chroma 36 | 37 | chroma_info = { 38 | 'name': os.path.splitext(os.path.basename(__file__))[0], 39 | 'mode': 'Chroma' 40 | } 41 | 42 | def loadsim_info(): 43 | return chroma_info 44 | 45 | def params(info, group_name=None): 46 | gname = lambda name: group_name + '.' + name 47 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 48 | mode = chroma_info['mode'] 49 | info.param_add_value(gname('mode'), mode) 50 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 51 | active=gname('mode'), active_value=mode, glob=True) 52 | info.param(pname('comm'), label='Communications Interface', default='VISA', values=['VISA']) 53 | info.param(pname('visa_device'), label='VISA Device String', active=pname('comm'), 54 | active_value=['VISA'], default='GPIB0::0::INSTR') 55 | info.param(pname('visa_path'), label='VISA Path', active=pname('comm'), 56 | active_value=['VISA'], default='') 57 | info.param(pname('volts'), label='Voltage', default=220) 58 | info.param(pname('freq'), label='Frequency', default=50) 59 | 60 | GROUP_NAME = 'chroma' 61 | 62 | 63 | class LoadSim(loadsim.LoadSim): 64 | """ 65 | Chroma loadsim class. 66 | """ 67 | def __init__(self, ts, group_name): 68 | loadsim.LoadSim.__init__(self, ts, group_name) 69 | self.visa_device = self._param_value('visa_device') 70 | self.visa_path = self._param_value('visa_path') 71 | self.volts = self._param_value('volts') 72 | self.freq = self._param_value('freq') 73 | 74 | self.rlc = chroma.ChromaRLC(visa_device=self.visa_device, visa_path=self.visa_path, volts = self.volts, 75 | freq = self.freq) 76 | self.rlc.open() 77 | 78 | def _param_value(self, name): 79 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 80 | 81 | def resistance(self, ph = None, r=None): 82 | self.rlc.resistance(ph,r) 83 | 84 | def voltset(self,v): 85 | return self.rlc.voltset(v) 86 | 87 | def freqset(self,f): 88 | return self.rlc.freqset(f) 89 | 90 | def inductance(self, ph,i=None): 91 | if i is not None: 92 | return self.rlc.inductance(ph,i) 93 | 94 | 95 | def capacitance(self, ph, i=None): 96 | if i is not None: 97 | return self.rlc.capacitance(ph,i) 98 | else: 99 | self.ts.log('Enter the capacitive load in F.') 100 | 101 | """def capacitor_q(self, q=None): 102 | if q is not None: 103 | self.ts.log('Adjust the capacitive load of the fundamental freq to %0.3f VAr.' % q) 104 | else: 105 | self.ts.log('Enter the capacitor reactive power in VAr.') 106 | 107 | def inductor_q(self, q=None): 108 | if q is not None: 109 | self.ts.log('Adjust the inductive load of the fundamental freq to %0.3f VAr.' % q) 110 | else: 111 | self.ts.log('Enter the inductor reactive power in VAr.') 112 | 113 | def resistance_p(self, p=None): 114 | if p is not None: 115 | self.ts.log('Adjust the resistive load of the fundamental freq to %0.3f W.' % p) 116 | else: 117 | self.ts.log('Enter the resistor power in W.') 118 | 119 | def tune_current(self, i=None): 120 | if c is not None: 121 | self.ts.log('Adjust R, L, and C until the fundamental frequency current through switch S3 is ' 122 | 'less than %0.2f' % i) 123 | else: 124 | pass 125 | """ -------------------------------------------------------------------------------- /Lib/svpelab/pv_profiles.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | # time offset in seconds, Irriadiance (W/m^2) 34 | STPsIrradiance = [ 35 | (0, 200), 36 | (15, 200), 37 | (95, 1000), 38 | (130, 1000), 39 | (134, 200), 40 | (154, 200), 41 | (156, 600), 42 | (191, 600), 43 | (193, 200), 44 | (213, 200), 45 | (217.5, 1100), 46 | (253, 1100), 47 | (353, 200), 48 | (360, 200), 49 | ] 50 | 51 | # time offset in seconds, Available Power (% of nameplate) 52 | STPsIrradianceNorm = [ 53 | (0, 20), 54 | (15, 20), 55 | (95, 100), 56 | (130, 100), 57 | (134, 20), 58 | (154, 20), 59 | (156, 60), 60 | (191, 60), 61 | (193, 20), 62 | (213, 20), 63 | (217.5, 110), 64 | (253, 110), 65 | (353, 20), 66 | (360, 20), 67 | ] 68 | 69 | profiles = { 70 | 'STPsIrradiance': STPsIrradiance, 71 | 'STPsIrradianceNorm': STPsIrradianceNorm, 72 | } 73 | 74 | if __name__ == "__main__": 75 | 76 | pass 77 | -------------------------------------------------------------------------------- /Lib/svpelab/pvsim.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import sys 34 | import os 35 | import glob 36 | import importlib 37 | 38 | pvsim_modules = {} 39 | 40 | def params(info, id=None, label='PV Simulator', group_name=None, active=None, active_value=None): 41 | if group_name is None: 42 | group_name = PVSIM_DEFAULT_ID 43 | else: 44 | group_name += '.' + PVSIM_DEFAULT_ID 45 | if id is not None: 46 | group_name = group_name + '_' + str(id) 47 | name = lambda name: group_name + '.' + name 48 | info.param_group(group_name, label='%s Parameters' % label, active=active, active_value=active_value, glob=True) 49 | info.param(name('mode'), label='Mode', default='Disabled', values=['Disabled']) 50 | for mode, m in pvsim_modules.iteritems(): 51 | m.params(info, group_name=group_name) 52 | 53 | PVSIM_DEFAULT_ID = 'pvsim' 54 | 55 | def pvsim_init(ts, id=None, group_name=None): 56 | """ 57 | Function to create specific pv simulator implementation instances. 58 | 59 | Each supported pv simulator type should have an entry in the 'mode' parameter conditional. 60 | Module import for the simulator is done within the conditional so modules only need to be 61 | present if used. 62 | """ 63 | if group_name is None: 64 | group_name = PVSIM_DEFAULT_ID 65 | else: 66 | group_name += '.' + PVSIM_DEFAULT_ID 67 | if id is not None: 68 | group_name = group_name + '_' + str(id) 69 | mode = ts.param_value(group_name + '.' + 'mode') 70 | sim = None 71 | if mode != 'Disabled': 72 | sim_module = pvsim_modules.get(mode) 73 | if sim_module is not None: 74 | sim = sim_module.PVSim(ts, group_name) 75 | else: 76 | raise PVSimError('Unknown PV simulation mode: %s' % mode) 77 | 78 | return sim 79 | 80 | 81 | class PVSimError(Exception): 82 | pass 83 | 84 | class PVSim(object): 85 | 86 | def __init__(self, ts, group_name, params=None): 87 | self.ts = ts 88 | self.group_name = group_name 89 | 90 | def close(self): 91 | pass 92 | 93 | def info(self): 94 | pass 95 | 96 | def irradiance_set(self, irradiance=1000): 97 | pass 98 | 99 | def power_set(self, power): 100 | pass 101 | 102 | def profile_load(self, profile_name): 103 | # use pv_profiles.py to create profile 104 | pass 105 | 106 | def power_on(self): 107 | pass 108 | 109 | def profile_start(self): 110 | pass 111 | 112 | 113 | def pvsim_scan(): 114 | global pvsim_modules 115 | # scan all files in current directory that match gridsim_*.py 116 | package_name = '.'.join(__name__.split('.')[:-1]) 117 | files = glob.glob(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'pvsim_*.py')) 118 | for f in files: 119 | module_name = None 120 | try: 121 | module_name = os.path.splitext(os.path.basename(f))[0] 122 | if package_name: 123 | module_name = package_name + '.' + module_name 124 | m = importlib.import_module(module_name) 125 | if hasattr(m, 'pvsim_info'): 126 | info = m.pvsim_info() 127 | mode = info.get('mode') 128 | # place module in module dict 129 | if mode is not None: 130 | pvsim_modules[mode] = m 131 | else: 132 | if module_name is not None and module_name in sys.modules: 133 | del sys.modules[module_name] 134 | except Exception, e: 135 | if module_name is not None and module_name in sys.modules: 136 | del sys.modules[module_name] 137 | raise PVSimError('Error scanning module %s: %s' % (module_name, str(e))) 138 | 139 | # scan for gridsim modules on import 140 | pvsim_scan() 141 | 142 | 143 | if __name__ == "__main__": 144 | pass -------------------------------------------------------------------------------- /Lib/svpelab/pvsim_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import pvsim 36 | 37 | manual_info = { 38 | 'name': os.path.splitext(os.path.basename(__file__))[0], 39 | 'mode': 'Manual' 40 | } 41 | 42 | def pvsim_info(): 43 | return manual_info 44 | 45 | def params(info, group_name): 46 | gname = lambda name: group_name + '.' + name 47 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 48 | mode = manual_info['mode'] 49 | info.param_add_value(gname('mode'), mode) 50 | 51 | GROUP_NAME = 'manual' 52 | 53 | 54 | class PVSim(pvsim.PVSim): 55 | 56 | def __init__(self, ts, group_name): 57 | pvsim.PVSim.__init__(self, ts, group_name) 58 | 59 | def irradiance_set(self, irradiance=1000): 60 | if self.ts.confirm('Please change the irradiance to %0.1f W/m^2.' % irradiance) is False: 61 | raise pvsim.PVSimError('Aborted PV simulation') 62 | 63 | def power_set(self, power): 64 | if self.ts.confirm('Please change the power to %0.1f%% power.' % power) is False: 65 | raise pvsim.PVSimError('Aborted PV simulation') 66 | 67 | def power_on(self): 68 | if self.ts.confirm('Please turn on PV simulator to give EUT DC power.') is False: 69 | raise pvsim.PVSimError('Aborted PV simulation') 70 | 71 | def profile_start(self): 72 | if self.ts.confirm('Please run the PV simulator profile.') is False: 73 | raise pvsim.PVSimError('Aborted PV simulation') 74 | 75 | if __name__ == "__main__": 76 | pass 77 | 78 | -------------------------------------------------------------------------------- /Lib/svpelab/pvsim_pass.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import pvsim 36 | 37 | pass_info = { 38 | 'name': os.path.splitext(os.path.basename(__file__))[0], 39 | 'mode': 'Pass' 40 | } 41 | 42 | def pvsim_info(): 43 | return pass_info 44 | 45 | def params(info, group_name): 46 | gname = lambda name: group_name + '.' + name 47 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 48 | mode = pass_info['mode'] 49 | info.param_add_value(gname('mode'), mode) 50 | 51 | GROUP_NAME = 'pass' 52 | 53 | 54 | class PVSim(pvsim.PVSim): 55 | 56 | def __init__(self, ts, group_name): 57 | pvsim.PVSim.__init__(self, ts, group_name) 58 | 59 | def irradiance_set(self, irradiance=1000): 60 | if self.ts.log('Please change the irradiance to %0.1f W/m^2.' % irradiance) is False: 61 | raise pvsim.PVSimError('Aborted PV simulation') 62 | 63 | def power_set(self, power): 64 | if self.ts.log('Please change the power to %0.1f W.' % power) is False: 65 | raise pvsim.PVSimError('Aborted PV simulation') 66 | 67 | def power_on(self): 68 | if self.ts.log('Please turn on PV simulator to give EUT DC power.') is False: 69 | raise pvsim.PVSimError('Aborted PV simulation') 70 | 71 | def profile_start(self): 72 | if self.ts.log('Please run the PV simulator profile.') is False: 73 | raise pvsim.PVSimError('Aborted PV simulation') 74 | 75 | if __name__ == "__main__": 76 | pass 77 | 78 | -------------------------------------------------------------------------------- /Lib/svpelab/pvsim_sim.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import pvsim 36 | 37 | sim_info = { 38 | 'name': os.path.splitext(os.path.basename(__file__))[0], 39 | 'mode': 'PV Simulator Simulation' 40 | } 41 | 42 | def pvsim_info(): 43 | return sim_info 44 | 45 | def params(info, group_name): 46 | gname = lambda name: group_name + '.' + name 47 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 48 | mode = sim_info['mode'] 49 | info.param_add_value(gname('mode'), mode) 50 | 51 | GROUP_NAME = 'sim' 52 | 53 | 54 | class PVSim(pvsim.PVSim): 55 | 56 | def __init__(self, ts, group_name): 57 | pvsim.PVSim.__init__(self, ts, group_name) 58 | 59 | def irradiance_set(self, irradiance=1000): 60 | self.ts.log('Setting PV irradiance to %0.1f W/m^2.' % irradiance) 61 | 62 | def power_set(self, power): 63 | self.ts.log('Setting PV power to %0.1f W.' % power) 64 | 65 | def power_on(self): 66 | self.ts.log('Powering on PV simulator to give EUT DC power.') 67 | 68 | def profile_start(self): 69 | self.ts.log('Starting PV simulator profile.') 70 | 71 | if __name__ == "__main__": 72 | pass 73 | 74 | -------------------------------------------------------------------------------- /Lib/svpelab/rt_profile.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | vv_voltage_profile = [ 34 | (0, 100, 100), 35 | (30, 100, 100), 36 | (30, 106, 100), 37 | (60, 106, 100), 38 | (60, 94, 100), 39 | (90, 94, 100), 40 | (90, 100, 100), 41 | (120, 100, 100), 42 | (135, 106, 100), 43 | (150, 106, 100), 44 | (180, 94, 100), 45 | (195, 94, 100), 46 | (210, 100, 100), 47 | (240, 100, 100), 48 | (245, 106, 100), 49 | (250, 106, 100), 50 | (260, 94, 100), 51 | (265, 94, 100), 52 | (270, 100, 100), 53 | (300, 100, 100) 54 | ] 55 | 56 | ''' 57 | Create voltage ride-through profile based on UL 1741 SA ride-through test step function 58 | 59 | v_n - starting voltage(PUT) value 60 | v_t - test voltage(PUT) value 61 | t_f - fall time 62 | t_h - hold time 63 | t_r - rise time 64 | t_d - dwell time 65 | n - number of iterations 66 | ''' 67 | 68 | def voltage_rt_profile(v_n, v_t, t_f, t_h, t_r, t_d, n): 69 | profile = [] 70 | t = 0 71 | for i in range(1, n+1): 72 | profile.append((t, v_n, 100)) # (time offset, starting voltage (%), freq (100%)) 73 | t += t_d # hold for dwell time 74 | profile.append((t, v_n, 100)) # (time offset, starting voltage (%), freq (100%)) 75 | t += t_f # ramp over fall time 76 | profile.append((t, v_t, 100)) # (time offset, test voltage (%), freq (100%)) 77 | t += t_h # hold for hold time 78 | profile.append((t, v_t, 100)) # (time offset, test voltage (%), freq (100%)) 79 | t += t_r # ramp over rise time 80 | profile.append((t, v_n, 100)) # (time offset, starting voltage (%), freq (100%)) 81 | t += t_d # hold for dwell time 82 | profile.append((t, v_n, 100)) # (time offset, starting voltage (%), freq (100%)) 83 | 84 | return profile 85 | 86 | def freq_rt_profile(p_n, p_t, t_f, t_h, t_r, t_d, n): 87 | profile = [] 88 | t = 0 89 | for i in range(1, n+1): 90 | profile.append((t, 100, p_n)) # (time offset, voltage (100%), starting freq) 91 | t += t_d # hold for dwell time 92 | profile.append((t, 100, p_n)) # (time offset, voltage (100%), starting freq) 93 | t += t_f # ramp over fall time 94 | profile.append((t, 100, p_t)) # (time offset, voltage (100%), test freq) 95 | t += t_h # hold for hold time 96 | profile.append((t, 100, p_t)) # (time offset, voltage (100%), test freq) 97 | t += t_r # ramp over rise time 98 | profile.append((t, 100, p_n)) # (time offset, voltage (100%), starting freq) 99 | t += t_d # hold for dwell time 100 | profile.append((t, 100, p_n)) # (time offset, voltage (100%), starting freq) 101 | 102 | return profile 103 | 104 | print voltage_rt_profile(100, 80, 2, 5, 2, 5, 1) 105 | print freq_rt_profile(100, 80, 2, 5, 2, 5, 3) 106 | 107 | ''' 108 | Each region shall have the applicable ride-through magnitudes and durations verified. 109 | In the case of Rule 21 L/HVRT, four ride-through magnitudes will be verified: the upper bound of HV1, 110 | lower bound of LV1, lower bound of LV2, and lower bound of LV3. 111 | 112 | HV1 = 110%, 120%, 12s 113 | LV1 = 70, 88, 20s 114 | LV2 = 50, 70, 10s 115 | LV3 = 49, 50, 1s 116 | 117 | Inputs: 118 | v_msa 119 | v_max 120 | v_min 121 | duration 122 | dwell_time 123 | freq 124 | iterations 125 | rt = 'HVRT, LVRT' 126 | 127 | 128 | For high voltage tests (HV1): 129 | v_n = lowest voltage of the region + (v_msa * 1.5) 130 | v_t = highest voltage of the region - (v_msa * 1.5) 131 | 132 | The t_r and t_f values shall each be less than or equal to the larger of 1 cycle or 1% of the ride-through region 133 | duration. 134 | 135 | t_ex = duration 136 | t_d = dwell_time 137 | count = iterations 138 | t_f = t_r = max(1/freq, duration/100) 139 | t_h = t_ex - t_f - t_r 140 | 141 | if rt == 'HVRT': 142 | v_n = v_min + (v_msa * 1.5) 143 | v_t = v_max - (v_msa * 1.5) 144 | elif rt == 'LVRT': 145 | v_n = v_max - (v_msa * 1.5) 146 | v_t = v_min + (v_msa * 1.5) 147 | 148 | profile = voltage_rt_profile(v_n, v_t, t_f, t_h, t_r, t_d, count) 149 | 150 | start das 151 | start profile 152 | profile_duration = profile[-1][0] 153 | sleep(profile_duration + 5) 154 | stop das 155 | save das 156 | 157 | ''' 158 | -------------------------------------------------------------------------------- /Lib/svpelab/svp_ext_result.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import wxmplot 4 | import numpy 5 | 6 | def menu(result, result_dir, result_name): 7 | if result is not None and result.filename is not None: 8 | ext = os.path.splitext(result.filename)[1] 9 | if ext == '.csv': 10 | rm = ResultMenu(result, result_dir, result_name) 11 | return rm.menu_items 12 | 13 | 14 | class ResultMenu(object): 15 | 16 | def __init__(self, result, result_dir, result_name): 17 | self.result = result 18 | self.result_dir = result_dir 19 | self.result_name = result_name 20 | 21 | self.menu_open_items = [('WXMPlot', '', None, self.plot_wxmplot, None), 22 | ('Pyplot', '', None, self.plot_pyplot, None)] 23 | 24 | self.menu_items = [('Open with', '', self.menu_open_items, None, None), 25 | ('', '', None, None, None), 26 | ('Other', '', None, None, None)] 27 | 28 | 29 | def result_other(self, arg=None): 30 | pass 31 | 32 | def plot_wxmplot(self, arg=None): 33 | frame = wxmplot.PlotFrame() 34 | filename = os.path.join(self.result_dir, self.result_name, self.result.filename) 35 | f = open(filename, 'r') 36 | names = f.readline().split(',') 37 | columns = len(names) 38 | value_arrays = [] 39 | for i in range(columns): 40 | value_arrays.append([]) 41 | 42 | base_time = None 43 | for line in f: 44 | values = line.split(',') 45 | if base_time is None: 46 | base_time = float(values[0]) 47 | t = round(float(values[0]) - base_time, 2) 48 | value_arrays[0].append(t) 49 | for i in range(1, columns): 50 | try: 51 | v = float(values[i]) 52 | value_arrays[i].append(v) 53 | except Exception, e: 54 | value_arrays[i].append('nan') 55 | pass 56 | 57 | time_array = numpy.array(value_arrays[0]) 58 | for i in range(1, columns): 59 | value_array = numpy.array(value_arrays[i]) 60 | frame.oplot(time_array, value_array, label=names[i]) 61 | 62 | ''' 63 | r = numpy.recfromcsv(filename, case_sensitive=True) 64 | print(repr(r)) 65 | print r.dtype 66 | names = r.dtype.names 67 | x = names[0] 68 | print r[x] 69 | for name in names[1:]: 70 | # print name, r[x], r[name] 71 | frame.oplot(r[x], r[name]) 72 | ''' 73 | # pframe.plot(x, y1, title='Test 2 Axes with different y scales', 74 | # xlabel='x (mm)', ylabel='y1', ymin=-0.75, ymax=0.75) 75 | # pframe.oplot(x, y2, y2label='y2', side='right', ymin=0) 76 | 77 | frame.SetTitle(self.result.name) 78 | frame.Show() 79 | 80 | def plot_pyplot(self, arg=None): 81 | print 'plot_pyplot' 82 | 83 | 84 | -------------------------------------------------------------------------------- /Lib/svpelab/switch_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | import switch 35 | import device_switch_manual 36 | 37 | manual_info = { 38 | 'name': os.path.splitext(os.path.basename(__file__))[0], 39 | 'mode': 'Manual' 40 | } 41 | 42 | def switch_info(): 43 | return manual_info 44 | 45 | def params(info, group_name): 46 | gname = lambda name: group_name + '.' + name 47 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 48 | mode = manual_info['mode'] 49 | info.param_add_value(gname('mode'), mode) 50 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode, 51 | active=gname('mode'), active_value=mode, glob=True) 52 | info.param(pname('name'), label='Switch Name', default='Switch') 53 | 54 | GROUP_NAME = 'manual' 55 | 56 | class Switch(switch.Switch): 57 | 58 | def __init__(self, ts, group_name): 59 | switch.Switch.__init__(self, ts, group_name) 60 | self.device = device_switch_manual.Device() 61 | self.name = self._param_value('name') 62 | 63 | def _param_value(self, name): 64 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 65 | 66 | def switch_open(self): 67 | state = self.ts.confirm('Open the %s' % (self.name)) 68 | if state == True: 69 | self.switch_state = switch.SWITCH_OPEN 70 | else: 71 | raise switch.SwitchError('Manual Abort') 72 | return state 73 | 74 | def switch_close(self): 75 | state = self.ts.confirm('Close the %s' % (self.name)) 76 | if state == True: 77 | self.switch_state = switch.SWITCH_CLOSED 78 | else: 79 | raise switch.SwitchError('Manual Abort') 80 | return state -------------------------------------------------------------------------------- /Lib/svpelab/waveform.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import math 34 | 35 | class WaveformError(Exception): 36 | """ 37 | Exception to wrap all waveform generated exceptions. 38 | """ 39 | pass 40 | 41 | 42 | class Waveform(object): 43 | 44 | def __init__(self): 45 | self.start_time = 0 # waveform start time 46 | self.sample_count = 0 # size of waveform/per channel 47 | self.sample_rate = 0 # samples/second 48 | self.trigger_sample = 0 # trigger sample 49 | self.channels = [] # channel names 50 | self.channel_data = [] # waveform curves 51 | self.rms_data = {} # rms data calculated from waveform data 52 | 53 | def from_csv(self, filename, sep=','): 54 | f = open(filename, 'r') 55 | ids = f.readline().split(sep) 56 | chans = [] 57 | chan_count = len(ids) 58 | for i in range(chan_count): 59 | self.channels.append(ids[i].strip()) 60 | chans.append([]) 61 | # print self.channels 62 | line = 1 63 | for data in f: 64 | line += 1 65 | values = data.split(sep) 66 | if len(values) != chan_count: 67 | raise WaveformError('Channel data error: line %s' % (line)) 68 | for i in range(chan_count): 69 | chans[i].append(float(values[i])) 70 | 71 | for i in range(chan_count): 72 | self.channel_data.append(chans[i]) 73 | 74 | def to_csv(self, filename): 75 | f = open(filename, 'w') 76 | chan_count = len(self.channels) 77 | f.write('%s\n' % ','.join(self.channels)) 78 | for i in xrange(len(self.channel_data[0])): 79 | data = [] 80 | for c in range(chan_count): 81 | data.append(self.channel_data[c][i]) 82 | f.write('%s\n' % ','.join(str(v) for v in data)) 83 | 84 | def compute_rms(self, data): 85 | tmp = 0 86 | size = len(data) 87 | for i in range(size): 88 | v = data[i] 89 | tmp += v * v 90 | tmp /= float(size) 91 | return math.sqrt(tmp) 92 | 93 | def compute_cycle_rms(self, chan_id): 94 | c = None 95 | try: 96 | c = 'Time' 97 | time_index = self.channels.index(c) 98 | c = chan_id 99 | chan_index = self.channels.index(c) 100 | except Exception: 101 | raise WaveformError('Channel not found: %s' % (c)) 102 | time_chan = self.channel_data[time_index] 103 | data_chan = self.channel_data[chan_index] 104 | scanning = False 105 | calculating = False 106 | neg = False 107 | start_index = 0 108 | rms_time = [] 109 | rms_data = [] 110 | 111 | for i in range(len(data_chan)): 112 | pos = data_chan[i] >= 0 113 | if calculating: 114 | if not pos: 115 | neg = True 116 | elif neg: 117 | # calculate rms [start_index:i] 118 | rms_time.append(time_chan[i]) 119 | rms = self.compute_rms(data_chan[start_index:i]) 120 | rms_data.append(rms) 121 | start_index = i 122 | neg = False 123 | elif scanning: 124 | if pos: 125 | start_index = i 126 | calculating = True 127 | else: 128 | if not pos: 129 | scanning = True 130 | 131 | return rms_time, rms_data 132 | 133 | def compute_rms_data(self, phase): 134 | phase = str(phase) 135 | chan_v = 'AC_V_%s' % phase 136 | chan_i = 'AC_I_%s' % phase 137 | rms_time_v, rms_data_v = self.compute_cycle_rms(chan_v) 138 | rms_time_i, rms_data_i = self.compute_cycle_rms(chan_i) 139 | count = min(len(rms_time_v), len(rms_time_i)) 140 | self.rms_data[phase] = [rms_time_v[:count], rms_data_v[:count], rms_data_i[:count]] 141 | 142 | if __name__ == "__main__": 143 | 144 | wf= Waveform() 145 | wf.from_csv('c:\users\\bob\\waveforms\\sandia\\capture_1.csv') 146 | ''' 147 | rms_time, rms_data = wf.compute_cycle_rms('AC_V_1') 148 | print rms_time 149 | print rms_data 150 | ''' 151 | wf.compute_rms_data(1) 152 | print wf.rms_data 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /Lib/svpelab/wavegen_awg400.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import script 36 | import device_awg400 37 | import wavegen 38 | 39 | awg400_info = { 40 | 'name': os.path.splitext(os.path.basename(__file__))[0], 41 | 'mode': 'Tektronix AWG400' 42 | } 43 | 44 | def wavegen_info(): 45 | return awg400_info 46 | 47 | def params(info, group_name): 48 | gname = lambda name: group_name + '.' + name 49 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 50 | mode = awg400_info['mode'] 51 | info.param_add_value(gname('mode'), mode) 52 | info.param_group(gname(GROUP_NAME), label='%s Parameters' % mode,active=gname('mode'), active_value=mode, glob=True) 53 | info.param(pname('comm'), label='Communications Interface', default='VISA', values=['Network','VISA', 'GPIB']) 54 | 55 | info.param(pname('visa_address'), label='VISA address', active=pname('comm'), active_value=['VISA'],default='GPIB0::10::INSTR') 56 | 57 | info.param(pname('ip_addr'), label='IP Address',active=pname('comm'), active_value=['Network'], default='192.168.0.10') 58 | 59 | info.param(pname('sequence_filename'), label='Sequence File', default='') 60 | 61 | info.param(pname('chan_1'), label='Channel 1', default='Enabled', values=['Enabled', 'Disabled']) 62 | info.param(pname('chan_2'), label='Channel 2', default='Enabled', values=['Enabled', 'Disabled']) 63 | info.param(pname('chan_3'), label='Channel 3', default='Enabled', values=['Enabled', 'Disabled']) 64 | 65 | GROUP_NAME = 'awg400' 66 | 67 | 68 | class Wavegen(wavegen.Wavegen): 69 | """ 70 | Template for waveform generator (wavegen) implementations. This class can be used as a base class or 71 | independent data acquisition classes can be created containing the methods contained in this class. 72 | """ 73 | 74 | def __init__(self, ts, group_name, points=None): 75 | wavegen.Wavegen.__init__(self, ts, group_name) 76 | 77 | self.params['ip_addr'] = self._param_value('ip_addr') 78 | self.params['visa_address'] = self._param_value('visa_address') 79 | self.params['sequence_filename'] = self._param_value('sequence_filename') 80 | self.params['chan_1'] = self._param_value('chan_1') 81 | self.params['chan_2'] = self._param_value('chan_2') 82 | self.params['chan_3'] = self._param_value('chan_3') 83 | 84 | self.device = device_awg400.Device(self.params) 85 | 86 | def _param_value(self, name): 87 | return self.ts.param_value(self.group_name + '.' + GROUP_NAME + '.' + name) 88 | 89 | 90 | 91 | if __name__ == "__main__": 92 | 93 | pass 94 | 95 | 96 | -------------------------------------------------------------------------------- /Lib/svpelab/wavegen_manual.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import os 34 | 35 | import device_wavegen_manual 36 | import wavegen 37 | 38 | manual_info = { 39 | 'name': os.path.splitext(os.path.basename(__file__))[0], 40 | 'mode': 'Manual' 41 | } 42 | 43 | def wavegen_info(): 44 | return manual_info 45 | 46 | def params(info, group_name): 47 | gname = lambda name: group_name + '.' + name 48 | pname = lambda name: group_name + '.' + GROUP_NAME + '.' + name 49 | mode = manual_info['mode'] 50 | info.param_add_value(gname('mode'), mode) 51 | 52 | GROUP_NAME = 'manual' 53 | 54 | class Wavegen(wavegen.Wavegen): 55 | 56 | def __init__(self, ts, group_name, points=None): 57 | wavegen.Wavegen.__init__(self, ts, group_name) 58 | self.device = device_wavegen_manual.Device() 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # svp_energy_lab 2 | SVP library that enables communication with energy lab equipment. 3 | -------------------------------------------------------------------------------- /Scripts/battsim_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import sys 34 | import os 35 | import traceback 36 | 37 | # needed if running script stand alone 38 | lib_path = os.path.join(os.path.dirname(__file__), '..', 'Lib') 39 | if lib_path not in sys.path: 40 | sys.path.append(lib_path) 41 | print sys.path 42 | 43 | # place script library imports here 44 | from svpelab import battsim 45 | import script 46 | import openpyxl 47 | 48 | def test_run(): 49 | 50 | result = script.RESULT_FAIL 51 | daq = None 52 | batt = None 53 | 54 | try: 55 | batt = battsim.battsim_init(ts) 56 | ts.log('Battery device: %s' % batt.info()) 57 | 58 | result = script.RESULT_COMPLETE 59 | 60 | except script.ScriptFail, e: 61 | reason = str(e) 62 | if reason: 63 | ts.log_error(reason) 64 | finally: 65 | if batt is not None: 66 | batt.close() 67 | if daq is not None: 68 | daq.close() 69 | 70 | return result 71 | 72 | def run(test_script): 73 | 74 | try: 75 | global ts 76 | ts = test_script 77 | rc = 0 78 | result = script.RESULT_COMPLETE 79 | 80 | ts.log_debug('') 81 | ts.log_debug('************** Starting %s **************' % (ts.config_name())) 82 | ts.log_debug('Script: %s %s' % (ts.name, ts.info.version)) 83 | ts.log_active_params() 84 | 85 | result = test_run() 86 | 87 | ts.result(result) 88 | if result == script.RESULT_FAIL: 89 | rc = 1 90 | 91 | except Exception, e: 92 | ts.log_error('Test script exception: %s' % traceback.format_exc()) 93 | rc = 1 94 | 95 | sys.exit(rc) 96 | 97 | info = script.ScriptInfo(name=os.path.basename(__file__), run=run, version='1.0.0') 98 | 99 | # battsim parameters 100 | battsim.params(info) 101 | 102 | def script_info(): 103 | 104 | return info 105 | 106 | 107 | if __name__ == "__main__": 108 | 109 | # stand alone invocation 110 | config_file = None 111 | if len(sys.argv) > 1: 112 | config_file = sys.argv[1] 113 | 114 | # config_file = os.path.join(os.path.dirname(__file__), '..', 'Tests', 'das test.tst') 115 | 116 | params = None 117 | 118 | test_script = script.Script(info=script_info(), config_file=config_file, params=params) 119 | test_script.log('log it') 120 | 121 | run(test_script) 122 | 123 | 124 | -------------------------------------------------------------------------------- /Scripts/das_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import sys 34 | import os 35 | import traceback 36 | 37 | # needed if running script stand alone 38 | lib_path = os.path.join(os.path.dirname(__file__), '..', 'Lib') 39 | if lib_path not in sys.path: 40 | sys.path.append(lib_path) 41 | print sys.path 42 | 43 | # place script library imports here 44 | from svpelab import das 45 | from svpelab import hil 46 | import script 47 | import openpyxl 48 | 49 | def test_run(): 50 | 51 | result = script.RESULT_FAIL 52 | daq = None 53 | 54 | try: 55 | 56 | # In the case of measuring HIL data 57 | chil = hil.hil_init(ts) 58 | 59 | # initialize data acquisition system 60 | daq = das.das_init(ts) 61 | ts.log('DAS device: %s' % daq.info()) 62 | 63 | # ts.log('Waiting 30 sec to start inverter') 64 | # ts.sleep(30) 65 | 66 | # run data capture 67 | ts.log('Running capture 1') 68 | daq.data_capture(True) 69 | ts.sleep(5) 70 | ts.log('current data: %s' % daq.data_capture_read()) 71 | ts.sleep(5) 72 | ts.log('current data: %s' % daq.data_capture_read()) 73 | ts.sleep(5) 74 | ts.log('current data: %s' % daq.data_capture_read()) 75 | ts.sleep(5) 76 | daq.data_capture(False) 77 | ds = daq.data_capture_dataset() 78 | 79 | # save captured data set to capture file in SVP result directory 80 | filename = 'capture_1.csv' 81 | ds.to_csv(ts.result_file_path(filename)) 82 | ts.result_file(filename) 83 | 84 | chil.stop_simulation() 85 | 86 | result = script.RESULT_COMPLETE 87 | 88 | except script.ScriptFail, e: 89 | reason = str(e) 90 | if reason: 91 | ts.log_error(reason) 92 | finally: 93 | if daq is not None: 94 | daq.close() 95 | 96 | return result 97 | 98 | def run(test_script): 99 | 100 | try: 101 | global ts 102 | ts = test_script 103 | rc = 0 104 | result = script.RESULT_COMPLETE 105 | 106 | ts.log_debug('') 107 | ts.log_debug('************** Starting %s **************' % (ts.config_name())) 108 | ts.log_debug('Script: %s %s' % (ts.name, ts.info.version)) 109 | ts.log_active_params() 110 | 111 | result = test_run() 112 | 113 | ts.result(result) 114 | if result == script.RESULT_FAIL: 115 | rc = 1 116 | 117 | except Exception, e: 118 | ts.log_error('Test script exception: %s' % traceback.format_exc()) 119 | rc = 1 120 | 121 | sys.exit(rc) 122 | 123 | info = script.ScriptInfo(name=os.path.basename(__file__), run=run, version='1.0.0') 124 | 125 | 126 | # DAS 127 | das.params(info) 128 | 129 | # HIL 130 | hil.params(info) 131 | 132 | def script_info(): 133 | 134 | return info 135 | 136 | 137 | if __name__ == "__main__": 138 | 139 | # stand alone invocation 140 | config_file = None 141 | if len(sys.argv) > 1: 142 | config_file = sys.argv[1] 143 | 144 | # config_file = os.path.join(os.path.dirname(__file__), '..', 'Tests', 'das test.tst') 145 | 146 | params = None 147 | 148 | test_script = script.Script(info=script_info(), config_file=config_file, params=params) 149 | test_script.log('log it') 150 | 151 | run(test_script) 152 | 153 | 154 | -------------------------------------------------------------------------------- /Scripts/gridsim_comm.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import sys 34 | import os 35 | import traceback 36 | 37 | from svpelab import gridsim 38 | 39 | import script 40 | 41 | def test_run(): 42 | 43 | result = script.RESULT_FAIL 44 | gsim = None 45 | 46 | try: 47 | # initialize grid simulation 48 | gsim = gridsim.gridsim_init(ts) 49 | ts.log(gsim.info()) 50 | 51 | result = script.RESULT_PASS 52 | 53 | except script.ScriptFail, e: 54 | reason = str(e) 55 | if reason: 56 | ts.log_error(reason) 57 | finally: 58 | if gsim: 59 | gsim.close() 60 | 61 | return result 62 | 63 | 64 | def run(test_script): 65 | try: 66 | global ts 67 | ts= test_script 68 | rc = 0 69 | result = script.RESULT_COMPLETE 70 | 71 | ts.log_debug('') 72 | ts.log_debug('************** Starting %s **************' % (ts.config_name())) 73 | ts.log_debug('Script: %s %s' % (ts.name, ts.info.version)) 74 | ts.log_active_params() 75 | 76 | result = test_run() 77 | 78 | ts.result(result) 79 | if result == script.RESULT_FAIL: 80 | rc = 1 81 | 82 | except Exception, e: 83 | ts.log_error('Test script exception: %s' % traceback.format_exc()) 84 | rc = 1 85 | 86 | sys.exit(rc) 87 | 88 | info = script.ScriptInfo(name=os.path.basename(__file__), run=run, version='1.0.0') 89 | 90 | info.param_group('profile', label='FW Profile') 91 | info.param('profile.profile_name', label='Simulation profile', default='FW Profile', 92 | values=['FW Profile', 'VV Profile', 'Manual'], 93 | desc='"Manual" is reserved for not running a profile.') 94 | 95 | #Grid simulator 96 | gridsim.params(info) 97 | 98 | def script_info(): 99 | return info 100 | 101 | 102 | if __name__ == "__main__": 103 | 104 | 105 | # stand alone invocation 106 | config_file = None 107 | if len(sys.argv) > 1: 108 | config_file = sys.argv[1] 109 | 110 | test_script = script.Script(info=script_info(), config_file=config_file) 111 | 112 | run(test_script) 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /Scripts/gridsim_multi.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | """ 33 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 34 | All rights reserved. 35 | 36 | Redistribution and use in source and binary forms, with or without modification, 37 | are permitted provided that the following conditions are met: 38 | 39 | Redistributions of source code must retain the above copyright notice, this 40 | list of conditions and the following disclaimer. 41 | 42 | Redistributions in binary form must reproduce the above copyright notice, this 43 | list of conditions and the following disclaimer in the documentation and/or 44 | other materials provided with the distribution. 45 | 46 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 47 | contributors may be used to endorse or promote products derived from 48 | this software without specific prior written permission. 49 | 50 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 51 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 52 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 53 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 54 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 55 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 56 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 57 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 58 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 59 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 | 61 | Questions can be directed to support@sunspec.org 62 | """ 63 | 64 | import sys 65 | import os 66 | import traceback 67 | 68 | from svpelab import gridsim 69 | import script 70 | 71 | def test_run(): 72 | 73 | result = script.RESULT_FAIL 74 | gsim_1 = gsim_2 = None 75 | 76 | try: 77 | # initialize grid simulation 78 | gsim_1 = gridsim.gridsim_init(ts, '1') 79 | ts.log('Grid Simulation 1: %s' % gsim_1.info()) 80 | 81 | gsim_2 = gridsim.gridsim_init(ts, '2') 82 | ts.log('Grid Simulation 2: %s' % gsim_2.info()) 83 | 84 | result = script.RESULT_PASS 85 | 86 | except script.ScriptFail, e: 87 | reason = str(e) 88 | if reason: 89 | ts.log_error(reason) 90 | finally: 91 | if gsim_1: 92 | gsim_1.close() 93 | if gsim_2: 94 | gsim_2.close() 95 | 96 | return result 97 | 98 | 99 | def run(test_script): 100 | try: 101 | global ts 102 | ts= test_script 103 | rc = 0 104 | result = script.RESULT_COMPLETE 105 | 106 | ts.log_debug('') 107 | ts.log_debug('************** Starting %s **************' % (ts.config_name())) 108 | ts.log_debug('Script: %s %s' % (ts.name, ts.info.version)) 109 | ts.log_active_params() 110 | 111 | result = test_run() 112 | 113 | ts.result(result) 114 | if result == script.RESULT_FAIL: 115 | rc = 1 116 | 117 | except Exception, e: 118 | ts.log_error('Test script exception: %s' % traceback.format_exc()) 119 | rc = 1 120 | 121 | sys.exit(rc) 122 | 123 | info = script.ScriptInfo(name=os.path.basename(__file__), run=run, version='1.0.0') 124 | 125 | info.param_group('profile', label='FW Profile') 126 | info.param('profile.profile_name', label='Simulation profile', default='FW Profile', 127 | values=['FW Profile', 'VV Profile', 'Manual'], 128 | desc='"Manual" is reserved for not running a profile.') 129 | 130 | #Grid simulator 131 | gridsim.params(info, '1', 'Grid Simulation 1') 132 | gridsim.params(info, '2', 'Grid Simulation 2') 133 | 134 | def script_info(): 135 | return info 136 | 137 | 138 | if __name__ == "__main__": 139 | 140 | 141 | # stand alone invocation 142 | config_file = None 143 | if len(sys.argv) > 1: 144 | config_file = sys.argv[1] 145 | 146 | test_script = script.Script(info=script_info(), config_file=config_file) 147 | 148 | run(test_script) 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /Scripts/loadsim_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import sys 34 | import os 35 | import traceback 36 | 37 | # needed if running script stand alone 38 | lib_path = os.path.join(os.path.dirname(__file__), '..', 'Lib') 39 | if lib_path not in sys.path: 40 | sys.path.append(lib_path) 41 | print sys.path 42 | 43 | # place script library imports here 44 | from svpelab import loadsim 45 | import script 46 | 47 | def test_run(): 48 | 49 | result = script.RESULT_FAIL 50 | load = None 51 | 52 | try: 53 | load = loadsim.loadsim_init(ts) 54 | ts.log('Load device: %s' % load.info()) 55 | 56 | result = script.RESULT_COMPLETE 57 | 58 | except script.ScriptFail, e: 59 | reason = str(e) 60 | if reason: 61 | ts.log_error(reason) 62 | finally: 63 | if load is not None: 64 | load.close() 65 | 66 | return result 67 | 68 | def run(test_script): 69 | 70 | try: 71 | global ts 72 | ts = test_script 73 | rc = 0 74 | result = script.RESULT_COMPLETE 75 | 76 | ts.log_debug('') 77 | ts.log_debug('************** Starting %s **************' % (ts.config_name())) 78 | ts.log_debug('Script: %s %s' % (ts.name, ts.info.version)) 79 | ts.log_active_params() 80 | 81 | result = test_run() 82 | 83 | ts.result(result) 84 | if result == script.RESULT_FAIL: 85 | rc = 1 86 | 87 | except Exception, e: 88 | ts.log_error('Test script exception: %s' % traceback.format_exc()) 89 | rc = 1 90 | 91 | sys.exit(rc) 92 | 93 | info = script.ScriptInfo(name=os.path.basename(__file__), run=run, version='1.0.0') 94 | 95 | # loadsim parameters 96 | loadsim.params(info) 97 | 98 | def script_info(): 99 | 100 | return info 101 | 102 | 103 | if __name__ == "__main__": 104 | 105 | # stand alone invocation 106 | config_file = None 107 | if len(sys.argv) > 1: 108 | config_file = sys.argv[1] 109 | 110 | # config_file = os.path.join(os.path.dirname(__file__), '..', 'Tests', 'das test.tst') 111 | 112 | params = None 113 | 114 | test_script = script.Script(info=script_info(), config_file=config_file, params=params) 115 | test_script.log('log it') 116 | 117 | run(test_script) 118 | 119 | 120 | -------------------------------------------------------------------------------- /Scripts/pvsim_comm.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import sys 34 | import os 35 | import math 36 | import time 37 | import traceback 38 | import script 39 | 40 | from svpelab import pvsim 41 | 42 | def test_run(): 43 | 44 | result = script.RESULT_FAIL 45 | pv = None 46 | 47 | try: 48 | # initialize pv simulation 49 | pv = pvsim.pvsim_init(ts) 50 | ts.log(pv.info()) 51 | 52 | result = script.RESULT_PASS 53 | 54 | except script.ScriptFail, e: 55 | reason = str(e) 56 | if reason: 57 | ts.log_error(reason) 58 | finally: 59 | if pv: 60 | pv.close() 61 | 62 | return result 63 | 64 | 65 | def run(test_script): 66 | try: 67 | global ts 68 | ts= test_script 69 | rc = 0 70 | result = script.RESULT_COMPLETE 71 | 72 | ts.log_debug('') 73 | ts.log_debug('************** Starting %s **************' % (ts.config_name())) 74 | ts.log_debug('Script: %s %s' % (ts.name, ts.info.version)) 75 | ts.log_active_params() 76 | 77 | result = test_run() 78 | 79 | ts.result(result) 80 | if result == script.RESULT_FAIL: 81 | rc = 1 82 | 83 | except Exception, e: 84 | ts.log_error('Test script exception: %s' % traceback.format_exc()) 85 | rc = 1 86 | 87 | sys.exit(rc) 88 | 89 | info = script.ScriptInfo(name=os.path.basename(__file__), run=run, version='1.0.0') 90 | 91 | #Grid simulator 92 | pvsim.params(info) 93 | 94 | def script_info(): 95 | return info 96 | 97 | 98 | if __name__ == "__main__": 99 | 100 | 101 | # stand alone invocation 102 | config_file = None 103 | if len(sys.argv) > 1: 104 | config_file = sys.argv[1] 105 | 106 | test_script = script.Script(info=script_info(), config_file=config_file) 107 | 108 | run(test_script) 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Scripts/pvsim_multi.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import sys 34 | import os 35 | import math 36 | import time 37 | import traceback 38 | import script 39 | 40 | from svpelab import pvsim 41 | 42 | def test_run(): 43 | 44 | result = script.RESULT_FAIL 45 | pv_1 = pv_2 = None 46 | 47 | try: 48 | # initialize pv simulation 49 | pv_1 = pvsim.pvsim_init(ts, '1') 50 | ts.log('PV 1: %s' % pv_1.info()) 51 | 52 | pv_2 = pvsim.pvsim_init(ts, '2') 53 | ts.log('PV 2: %s' % pv_2.info()) 54 | 55 | result = script.RESULT_PASS 56 | 57 | except script.ScriptFail, e: 58 | reason = str(e) 59 | if reason: 60 | ts.log_error(reason) 61 | finally: 62 | if pv_1: 63 | pv_1.close() 64 | if pv_2: 65 | pv_2.close() 66 | 67 | return result 68 | 69 | 70 | def run(test_script): 71 | try: 72 | global ts 73 | ts= test_script 74 | rc = 0 75 | result = script.RESULT_COMPLETE 76 | 77 | ts.log_debug('') 78 | ts.log_debug('************** Starting %s **************' % (ts.config_name())) 79 | ts.log_debug('Script: %s %s' % (ts.name, ts.info.version)) 80 | ts.log_active_params() 81 | 82 | result = test_run() 83 | 84 | ts.result(result) 85 | if result == script.RESULT_FAIL: 86 | rc = 1 87 | 88 | except Exception, e: 89 | ts.log_error('Test script exception: %s' % traceback.format_exc()) 90 | rc = 1 91 | 92 | sys.exit(rc) 93 | 94 | info = script.ScriptInfo(name=os.path.basename(__file__), run=run, version='1.0.0') 95 | 96 | # PV simulator 97 | pvsim.params(info, '1', 'PV Simulator 1') 98 | pvsim.params(info, '2', 'PV Simulator 2') 99 | 100 | def script_info(): 101 | return info 102 | 103 | 104 | if __name__ == "__main__": 105 | 106 | 107 | # stand alone invocation 108 | config_file = None 109 | if len(sys.argv) > 1: 110 | config_file = sys.argv[1] 111 | 112 | test_script = script.Script(info=script_info(), config_file=config_file) 113 | 114 | run(test_script) 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /Scripts/sunspec.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunspec/svp_energy_lab/4937ce7509a0d027e54f44edd4e4568242e17419/Scripts/sunspec.gif -------------------------------------------------------------------------------- /Scripts/switch_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import sys 34 | import os 35 | import traceback 36 | 37 | # needed if running script stand alone 38 | lib_path = os.path.join(os.path.dirname(__file__), '..', 'Lib') 39 | if lib_path not in sys.path: 40 | sys.path.append(lib_path) 41 | print sys.path 42 | 43 | # place script library imports here 44 | from svpelab import switch 45 | import script 46 | import openpyxl 47 | 48 | def test_run(): 49 | 50 | result = script.RESULT_FAIL 51 | daq = None 52 | 53 | try: 54 | 55 | # Module test init 56 | sw = switch.switch_init(ts) 57 | ts.log('Switch device: %s' % sw.info()) 58 | 59 | result = script.RESULT_COMPLETE 60 | 61 | except script.ScriptFail, e: 62 | reason = str(e) 63 | if reason: 64 | ts.log_error(reason) 65 | finally: 66 | if daq is not None: 67 | daq.close() 68 | 69 | return result 70 | 71 | def run(test_script): 72 | 73 | try: 74 | global ts 75 | ts = test_script 76 | rc = 0 77 | result = script.RESULT_COMPLETE 78 | 79 | ts.log_debug('') 80 | ts.log_debug('************** Starting %s **************' % (ts.config_name())) 81 | ts.log_debug('Script: %s %s' % (ts.name, ts.info.version)) 82 | ts.log_active_params() 83 | 84 | result = test_run() 85 | 86 | ts.result(result) 87 | if result == script.RESULT_FAIL: 88 | rc = 1 89 | 90 | except Exception, e: 91 | ts.log_error('Test script exception: %s' % traceback.format_exc()) 92 | rc = 1 93 | 94 | sys.exit(rc) 95 | 96 | info = script.ScriptInfo(name=os.path.basename(__file__), run=run, version='1.0.0') 97 | 98 | 99 | # Module test 100 | switch.params(info) 101 | 102 | 103 | def script_info(): 104 | 105 | return info 106 | 107 | 108 | if __name__ == "__main__": 109 | 110 | # stand alone invocation 111 | config_file = None 112 | if len(sys.argv) > 1: 113 | config_file = sys.argv[1] 114 | 115 | # config_file = os.path.join(os.path.dirname(__file__), '..', 'Tests', 'das test.tst') 116 | 117 | params = None 118 | 119 | test_script = script.Script(info=script_info(), config_file=config_file, params=params) 120 | test_script.log('log it') 121 | 122 | run(test_script) 123 | 124 | 125 | -------------------------------------------------------------------------------- /Scripts/wavegen_test.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright (c) 2017, Sandia National Labs and SunSpec Alliance 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | 8 | Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright notice, this 12 | list of conditions and the following disclaimer in the documentation and/or 13 | other materials provided with the distribution. 14 | 15 | Neither the names of the Sandia National Labs and SunSpec Alliance nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | Questions can be directed to support@sunspec.org 31 | """ 32 | 33 | import sys 34 | import os 35 | import traceback 36 | 37 | # needed if running script stand alone 38 | lib_path = os.path.join(os.path.dirname(__file__), '..', 'Lib') 39 | if lib_path not in sys.path: 40 | sys.path.append(lib_path) 41 | print sys.path 42 | 43 | # place script library imports here 44 | from svpelab import wavegen 45 | import script 46 | import openpyxl 47 | 48 | def test_run(): 49 | 50 | result = script.RESULT_FAIL 51 | daq = None 52 | 53 | try: 54 | 55 | # Module test init 56 | wg = wavegen.wavegen_init(ts) 57 | ts.log('Waveform generator device: %s' % wg.info()) 58 | 59 | result = script.RESULT_COMPLETE 60 | 61 | except script.ScriptFail, e: 62 | reason = str(e) 63 | if reason: 64 | ts.log_error(reason) 65 | finally: 66 | if daq is not None: 67 | daq.close() 68 | 69 | return result 70 | 71 | def run(test_script): 72 | 73 | try: 74 | global ts 75 | ts = test_script 76 | rc = 0 77 | result = script.RESULT_COMPLETE 78 | 79 | ts.log_debug('') 80 | ts.log_debug('************** Starting %s **************' % (ts.config_name())) 81 | ts.log_debug('Script: %s %s' % (ts.name, ts.info.version)) 82 | ts.log_active_params() 83 | 84 | result = test_run() 85 | 86 | ts.result(result) 87 | if result == script.RESULT_FAIL: 88 | rc = 1 89 | 90 | except Exception, e: 91 | ts.log_error('Test script exception: %s' % traceback.format_exc()) 92 | rc = 1 93 | 94 | sys.exit(rc) 95 | 96 | info = script.ScriptInfo(name=os.path.basename(__file__), run=run, version='1.0.0') 97 | 98 | 99 | # wavegen test 100 | wavegen.params(info) 101 | 102 | 103 | def script_info(): 104 | 105 | return info 106 | 107 | 108 | if __name__ == "__main__": 109 | 110 | # stand alone invocation 111 | config_file = None 112 | if len(sys.argv) > 1: 113 | config_file = sys.argv[1] 114 | 115 | # config_file = os.path.join(os.path.dirname(__file__), '..', 'Tests', 'das test.tst') 116 | 117 | params = None 118 | 119 | test_script = script.Script(info=script_info(), config_file=config_file, params=params) 120 | test_script.log('log it') 121 | 122 | run(test_script) 123 | 124 | 125 | -------------------------------------------------------------------------------- /Tests/battsim_test.tst: -------------------------------------------------------------------------------- 1 | 2 | 3 | Disabled 4 | Disabled 5 | Disabled 6 | Manual 7 | Manual 8 | Manual 9 | Manual 10 | 11 | 12 | -------------------------------------------------------------------------------- /Tests/das_test.tst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1000 4 | 5 | 1 6 | 2 7 | 3 8 | AC 9 | AC 10 | AC 11 | DAS Simulation 12 | DC 13 | Unused 14 | data.csv 15 | 16 | 17 | -------------------------------------------------------------------------------- /Tests/gridsim_comm_test.tst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 60.0 5 | 100.0 6 | 277.2 7 | 300.0 8 | Ametek 9 | Disabled 10 | FW Profile 11 | Serial 12 | com1 13 | 14 | 15 | -------------------------------------------------------------------------------- /Tests/gridsim_multi_test.tst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 1 5 | 60.0 6 | 60.0 7 | 100.0 8 | 100.0 9 | 277.2 10 | 277.2 11 | 300.0 12 | 300.0 13 | Ametek 14 | Ametek 15 | Disabled 16 | Disabled 17 | FW Profile 18 | Serial 19 | Serial 20 | com1 21 | com1 22 | 23 | 24 | -------------------------------------------------------------------------------- /Tests/loadsim_test.tst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10.0 4 | Chroma 63200 5 | Constant Current 6 | Serial 7 | com7 8 | 9 | 10 | -------------------------------------------------------------------------------- /Tests/pvsim_comm_test.tst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 460.0 4 | 3000.0 5 | 1 6 | 192.168.0.167 7 | TerraSAS 8 | 9 | 10 | -------------------------------------------------------------------------------- /Tests/pvsim_multi_test.tst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 460.0 4 | 460.0 5 | 3000.0 6 | 3000.0 7 | 1 8 | 1 9 | 192.168.0.167 10 | 192.168.0.167 11 | TerraSAS 12 | TerraSAS 13 | 14 | 15 | -------------------------------------------------------------------------------- /Tests/wavegen_test.tst: -------------------------------------------------------------------------------- 1 | 2 | 3 | 192.168.0.10 4 | Network 5 | Tektronix AWG400 6 | 7 | 8 | --------------------------------------------------------------------------------