class Driver(BaseDriver): support_models = ['E8257D', 'SMF100A', 'SMB100A', 'SGS100A'] quants = [ QReal('Frequency', unit='Hz', set_cmd=':FREQ %(value).13e%(unit)s', get_cmd=':FREQ?'), QReal('Power', unit='dBm', set_cmd=':POWER %(value).8e%(unit)s', get_cmd=':POWER?'), QOption('Output', set_cmd=':OUTP %(option)s', options=[('OFF', 'OFF'), ('ON', 'ON')]), ]
class Driver(BaseDriver): support_models = ['DPO4104B'] quants = [ QReal('X Scale', set_cmd='HOR:SCA %(value)e', get_cmd='HOR:SCA?'), QInteger('Bytes per Point', set_cmd='WFMI:BYT_N?', get_cmd='WFMI:BYT_N?'), QReal('X Step', set_cmd=':WFMI:XIN %(value)e', get_cmd=':WFMI:XIN?'), QReal('X Zero', set_cmd=':WFMI:XZER %(value)e', get_cmd=':WFMI:XZER?'), QReal('Y Scale', set_cmd=':CH%(ch)d:SCA %(value)e', get_cmd=':CH%(ch)d:SCA?'), QReal('Y Position', set_cmd=':CH%(ch)d:POS %(value)e', get_cmd=':CH%(ch)d:POS?'), QReal('Y Mult', set_cmd=':WFMI:YMU %(value)e', get_cmd=':WFMI:YMU?'), QReal('Y Offset', set_cmd=':WFMI:YOF %(value)e', get_cmd=':WFMI:YOF?'), QReal('Y Zero', set_cmd=':WFMI:YZER %(value)e', get_cmd=':WFMI:YZER?'), QVector('Histogram', get_cmd='HIStogram:DATa?'), QReal('Histogram Start', get_cmd='HIStogram:STARt?'), QReal('Histogram End', get_cmd='HIStogram:END?') ] def resetHist(self): self.write('HIStogram:COUNt RESET') def get_Trace(self, ch=1, start=1, stop=100000): self.write(':DAT:SOU CH%d' % ch) self.write(':DAT:START %d' % start) self.write(':DAT:STOP %d' % stop) y = np.array(self.query_ascii_values('CURV?')) y_offset = self.getValue('Y Offset') y_scale = self.getValue('Y Mult') y_zero = self.getValue('Y Zero') y = (y - y_offset) * y_scale + y_zero x = np.arange(start - 1, stop, 1) * self.getValue('X Step') + self.getValue('X Zero') return x, (y * 10 - self.getValue( 'Y Position', ch=ch)) * self.getValue('Y Scale', ch=ch)
class Driver(BaseDriver): support_models = ['PG_AWG'] quants = [ QReal( 'Offset', unit='V', ch=1, ), QReal( 'Amplitude', unit='VPP', ch=1, ), ] def __init__(self, **kw): BaseDriver.__init__(self, **kw) self.model = 'PG_AWG' self.ip = kw['IP'] def performOpen(self): awg = AWGBoard() awg.connect(self.ip) # 初始化AWG awg.InitBoard() self.awg = awg def performSetValue(self, quant, value, ch=1, **kw): if quant.name == 'Offset': self.awg.SetOffsetVolt(channel=ch, offset_volt=value) if quant.name == 'Amplitude': self.awg.set_channel_gain(ch=ch, gain=value) def AWG_run(self, array, ch=1): wave_list = [] wave_list.append(self.awg.gen_wave_unit(array, '触发', 0)) self.awg.wave_compile(ch, wave_list) self.awg.Start(ch)
class Driver(BaseDriver): support_models = ['GS200'] quants = [ QOption('Mode', set_cmd=':SOUR:FUNC %(option)s', get_cmd=':SOUR:FUNC?', options=[('voltage', 'VOLT'), ('current', 'CURR')]), QOption('Range', set_cmd=':SOUR:RANG %(option)s', get_cmd=':SOUR:RANG?', options=[('0.001', 1E-3), ('0.01', 10E-3), ('0.1', 100E-3), ('0.2', 200E-3), ('1', 1E+0), ('10', 10E+0), ('30', 30E+0)]), QReal('Level', value=0, unit='V or A', set_cmd=':SOUR:LEV %(value).8f', get_cmd=':SOUR:LEV?'), QReal('LevelAuto', value=0, unit='V or A', set_cmd=':SOUR:LEV:AUTO %(value).8f', get_cmd=':SOUR:LEV?'), QReal('ProtectVolt', value=0, unit='V', set_cmd=':SOUR:PROT:VOLT %(value)d', get_cmd=':SOUR:PROT:VOLT?'), QReal('ProtectCurr', value=0, unit='A', set_cmd=':SOUR:PROT:CURR %(value).8f', get_cmd=':SOUR:PROT:CURR?'), QOption('Output', set_cmd=':OUTP %(option)s', options=[('OFF', 'OFF'), ('ON', 'ON')]), ]
class Driver(BaseDriver): support_models = ['DP832'] '''Rigol DP800 series DC source''' quants = [ QReal('Offset', value=0, unit='V', ch=1, set_cmd=':SOUR%(ch)d:VOLT %(value).2f', get_cmd=':SOUR%(ch)d:VOLT?'), QOption('Output', ch=1, set_cmd=':OUTP CH%(ch)d,%(option)s', get_cmd=':OUTP? CH%(ch)d', options=[('OFF', 'OFF'), ('ON', 'ON')]), ]
class Driver(BaseDriver): support_models = ['DG1062Z'] quants = [ # Set the waveform offset voltage of the specified channel. # Query the waveform offset voltage of the specified channel. # QReal('Voltage_Offset', unit='VDC', # set_cmd=':SOUR1:VOLT:OFFS %(value).8e%(unit)s', # get_cmd=':SOUR1:VOLT:OFFS?'), # Set the waveform of the specified channel to DC with the specified offset. QReal('Offset', unit='VDC', set_cmd=':SOUR1:APPL:DC 1,1, %(value).8e%(unit)s', get_cmd=':VOLT?'), # QOption('Output', # set_cmd=':OUTP %(option)s', options=[('OFF', 'OFF'), ('ON', 'ON')]), ]
class Driver(BaseDriver): support_models = ['PG_DC'] CHs=[1,2,3,4] quants = [ QReal('Offset', value=0, unit='V', ch=1), ] def __init__(self, **kw): ''' addr: ip, e.g. '192.168.1.6' ''' super().__init__(**kw) self.model = 'PG_DC' def performOpen(self): self.handle = Voltage(self.addr) def performSetValue(self, quant, value, ch=1, **kw): if quant.name == 'Offset': # ch: 1,2,3,4 -> 0,1,2,3 self.handle.setVoltage(value,ch=ch-1)
class Driver(BaseDriver): error_command = '' support_models = ['33120A', '33220A'] quants = [ QReal('Frequency', unit='Hz', set_cmd='FREQ %(value).11E %(unit)s', get_cmd='FREQ?'), QReal('Vpp', unit='VPP', set_cmd='VOLT %(value).5E %(unit)s', get_cmd='VOLT?'), QReal('Offset', unit='V', set_cmd='VOLT:OFFS %(value).5E %(unit)s', get_cmd='VOLT:OFFS?'), QVector('Waveform', unit='V'), QString('Trigger', set_cmd='TRIG:SOUR %(value)s', get_cmd='TRIG:SOUR?') ] def performOpen(self): self.write('FORM:BORD NORM') self.waveform_list = self.query('DATA:CAT?')[1:-1].split('","') self.current_waveform = self.query('FUNC:SHAP?') if self.current_waveform == 'USER': self.current_waveform = self.query('FUNC:USER?') self.arb_waveforms = self.query('DATA:NVOL:CAT?')[1:-1].split('","') self.trigger_source = self.query('TRIG:SOUR?') self.inner_waveform = ["SINC","NEG_RAMP","EXP_RISE","EXP_FALL","CARDIAC"] if self.model == '33120A': self.max_waveform_size = 16000 self.trigger_count = int(float(self.query('BM:NCYC?'))) elif self.model == '33220A': self.max_waveform_size = 16384 self.trigger_count = int(float(self.query("BURS:NCYC?"))) def performSetValue(self, quant, value, **kw): if quant.name == 'Waveform': if len(value) > self.max_waveform_size: value = value[:self.max_waveform_size] value = np.array(value) vpp = value.max() - value.min() offs = (value.max() + value.min())/2.0 if vpp == 0: self.DC(offs) return name = kw['name'] if 'name' in kw.keys() else 'ABS' freq = kw['freq'] if 'freq' in kw.keys() else None self.update_waveform(2*(value-offs)/vpp, name=name) self.use_waveform(name, vpp=vpp, offs=offs, freq=freq) else: BaseDriver.performSetValue(self, quant, value, **kw) def __del_func(self, name): if name in self.arb_waveforms: if name == self.current_waveform: self.DC(0) self.write('DATA:DEL %s' % name) self.arb_waveforms.remove(name) self.waveform_list.remove(name) def update_waveform(self, values, name='ABS'): if self.model == '33120A': clip = lambda x: (2047*x).clip(-2047,2047).astype(int) elif self.model == '33220A': clip = lambda x: (8191*x).clip(-8191,8191).astype(int) values = clip(values) self.write_binary_values('DATA:DAC VOLATILE,', values, datatype='h', is_big_endian=True) if len(name) > 8: name = name[:8] name = name.upper() if len(self.arb_waveforms) >= 4: for wf in self.arb_waveforms: if wf != self.current_waveform: self.__del_func(wf) self.write('DATA:COPY %s,VOLATILE' % name) def use_waveform(self, name, freq=None, vpp=None, offs=None, ch=1): freq_s = ("%.11E" % freq) if freq != None else "DEF" vpp_s = ("%.5E" % vpp) if vpp != None else "DEF" offs_s = ("%.5E" % offs) if offs != None else "DEF" name = name.upper() if name in self.inner_waveform: self.write('APPL:%s %s,%s,%s' % (name, freq_s, vpp_s, offs_s)) else: self.write('FUNC:USER %s' % name) self.write('APPL:USER %s,%s,%s' % (freq_s, vpp_s, offs_s)) if self.trigger_source != 'IMM': self.set_trigger(source = self.trigger_source, count = self.trigger_count) self.current_waveform = name time.sleep(1) def DC(self, v): """输出直流电压""" self.write('APPL:DC DEF,DEF,%.5E' % v) self.current_waveform = 'DC' def off(self): self.DC(0) def set_trigger(self, source='IMM', count=1): """设置触发 source : 触发源,可设为'IMM', 'EXT' 或 'BUS' count : 脉冲串的个数 """ if source not in ['IMM', 'EXT', 'BUS']: return if count < 1 or count > 50000: return self.trigger_source = source self.write("TRIG:SOUR %s" % source) self.trigger_count = count if count != 1: self.write("BM:NCYC %d" % count) if source != 'IMM': self.write("BM:STAT ON") def refresh(self): """刷新波形""" if self.current_waveform == "DC": return if self.current_waveform not in self.inner_waveform: self.write("FUNC:SHAP USER") else: self.write("FUNC:SHAP %s" % self.current_waveform)
class Driver(BaseDriver): error_command = '*ESR?' support_models = ['AFG3102'] quants = [ QOption('Output', ch=1, set_cmd='OUTP%(ch)d %(option)s', get_cmd='OUTP%(ch)d?', options=[('OFF', 'OFF'), ('ON', 'ON')]), # must set chanel QOption('Function', ch=1, set_cmd='SOUR%(ch)d:FUNC %(option)s', get_cmd='SOUR%(ch)d:FUNC?', options=[('Sin', 'SIN'), ('Square', 'SQU'), ('Pulse', 'PULS'), ('Ramp', 'RAMP'), ('PRNoise', 'PRN'), ('DC', 'DC'), ('SINC', 'SINC'), ('Gaussian', 'GAUS'), ('Lorentz', 'LOR'), ('Erise', 'ERIS'), ('Edecay', 'EDEC'), ('Haversine', 'HAV'), ('User', 'USER'), ('User2', 'USER2')]), QReal('Frequency', unit='Hz', ch=1, set_cmd='SOUR%(ch)d:FREQ %(value)e%(unit)s', get_cmd='SOUR%(ch)d:FREQ?'), QReal('Phase', unit='rad', ch=1, set_cmd='SOUR%(ch)d:PHAS %(value)f%(unit)s', get_cmd='SOUR%(ch)d:PHAS?'), QReal('Pulse Delay', unit='s', ch=1, set_cmd='SOUR%(ch)d:PULS:DEL %(value).9e%(unit)s', get_cmd='SOUR%(ch)d:PULS:DEL?'), QReal('Pulse Period', unit='s', ch=1, set_cmd='SOUR%(ch)d:PULS:PER %(value).9e%(unit)s', get_cmd='SOUR%(ch)d:PULS:PER?'), QReal('Pulse Width', unit='s', ch=1, set_cmd='SOUR%(ch)d:PULS:WIDT %(value).9e%(unit)s', get_cmd='SOUR%(ch)d:PULS:WIDT?'), #Burst Mode QReal('Burst Tdelay', unit='s', ch=1, set_cmd='SOUR%(ch)d:BURS:TDEL %(value).9e%(unit)s', get_cmd='SOUR%(ch)d:BURS:TDEL?'), QReal('Burst Ncycles', ch=1, set_cmd='SOUR%(ch)d:BURS:NCYC %(value)d', get_cmd='SOUR%(ch)d:BURS:NCYC?'), ## QReal('Frequency', unit='Hz', ch=1, set_cmd='SOUR%(ch)d:FREQ %(value)e%(unit)s', get_cmd='SOUR%(ch)d:FREQ?'), QReal('Phase', unit='DEG', ch=1, set_cmd='SOUR%(ch)d:PHAS %(value)f%(unit)s', get_cmd='SOUR%(ch)d:PHAS?'), QReal('High Level', unit='V', ch=1, set_cmd='SOUR%(ch)d:VOLT:HIGH %(value)f%(unit)s', get_cmd='SOUR%(ch)d:VOLT:HIGH?'), QReal('Low Level', unit='V', ch=1, set_cmd='SOUR%(ch)d:VOLT:LOW %(value)f%(unit)s', get_cmd='SOUR%(ch)d:VOLT:LOW?'), QReal('Offset', unit='V', ch=1, set_cmd='SOUR%(ch)d:VOLT:OFFS %(value)f%(unit)s', get_cmd='SOUR%(ch)d:VOLT:OFFS?'), QReal('Amplitude', unit='VPP', ch=1, set_cmd='SOUR%(ch)d:VOLT:AMPL %(value)f%(unit)s', get_cmd='SOUR%(ch)d:VOLT:AMPL?'), ] def reset(self, delay1=0, delay2=0): #init self.write('*CLS') self.write('*RST') #set external clock;external source;burst mode&cycle=1&trigdelay=0 self.write('SOURce:ROSCillator:SOURce EXT') self.write('TRIGger:SEQuence:SOURce EXTernal') self.write('SOURce1:BURSt:STATe ON') self.write('SOURce1:BURSt:NCYCles 1') self.write('SOURce1:BURSt:MODE TRIGgered') self.write('SOURce1:BURSt:DELay %fus' % delay1) self.write('SOURce2:BURSt:STATe ON') self.write('SOURce2:BURSt:NCYCles 1') self.write('SOURce2:BURSt:MODE TRIGgered') self.write('SOURce2:BURSt:TDELay %fns' % delay2) #在创建好的波形文件中,写入或者更新具体波形 def upwave(self, points, ch=1, T0=100): pointslen = len(points) pointslen2 = 2 * pointslen #写入波形数据 self.write('DATA:DEFine EMEMory,%d' % pointslen) self.write('DATA:POINts EMEMory, %d' % pointslen) message = ':DATA:DATA EMEMory,' # % (len(str(pointslen2)),pointslen2) points = points.clip(-1, 1) values = np.zeros(pointslen).astype(np.uint16) #乘积选用8191是为了防止最终值大于16383 values = (points * 8191).astype(np.uint16) + 8192 #.astype(np.uint16) byte = np.zeros(pointslen2).astype(np.uint8) #将原先的两比特数据点,分割为高低两个比特 byte[1:pointslen2:2] = (values & 0b11111111).astype(np.uint8) byte[0:pointslen2:2] = ((values & 0b11111100000000) >> 8).astype( np.uint8) #write_binary_value中的message参数不要包括#42048的信息,因为pyvisa可以自动算出结果。详见pyvisa中util.py内的to_binary_block #AFG3102选用big_endian。这表示程序按照我给的顺序将二进制包写进去 self.write_binary_values(message, byte, datatype='B', is_big_endian=False, termination=None, encoding=None) # self.write('enable' ) self.write('TRAC:COPY USER%d,EMEM' % ch) self.write('SOURce%d:FUNCTION USER%d' % (ch, ch)) #set frequency:because the wave total length is set by this parameter,typical for 1Mhz means the wave length is set to 1us!! self.write('SOURce%d:FREQuency:FIXed %fkHz' % (ch, 1e3 / T0)) self.write('OUTPut%d:STATe ON' % ch)
class Driver(BaseDriver): support_models = ['MF_AWG',] CHs=[1,2,3,4] quants = [ QReal('Offset',value=0,unit='V',ch=1,), QReal('Amplitude',value=1,unit='V',ch=1,), QInteger('Output',value=0,ch=1,), ] def __init__(self, **kw): super().__init__(**kw) def __del__(self): self.handle.disconnect() def performOpen(self): self.handle = AWGboard.AWGBoard() self.handle.connect(self.addr) self.handle.InitBoard() self._output_status = [0, 0, 0, 0] super().performOpen() def performClose(self): self.handle.disconnect() super().performClose() def performSetValue(self, quant, value, ch=1, **kw): if quant.name == 'Offset': self.setOffset(value, ch) elif quant.name == 'Amplitude': self.setVpp(value,ch) elif quant.name == 'Output': if value==1: self.on(ch) elif value==0: self.off(ch) else: raise Error('Wrong Value!') def on(self, ch=1): self.handle.Start(ch) self._output_status[ch - 1] = 1 def off(self, ch=1): self.handle.Stop(ch) self._output_status[ch - 1] = 0 def setWaveform(self, points, mark=[], ch=1, wtype='trig', delay=0, is_continue=False): if len(mark): self.handle.mark_is_in_wave = True else: self.handle.mark_is_in_wave = False wlist = [self.handle.gen_wave_unit(points, wtype, delay, mark)] self.handle.wave_compile(ch, wlist, is_continue=is_continue) for index, on in enumerate(self._output_status): if on: self.handle.Start(index + 1) def setVpp(self, vpp, ch=1): vpp = min(abs(vpp), 1.351) volt = 1.351 gain = vpp / volt self.handle.set_channel_gain(ch, gain) self.handle._SetDACMaxVolt(ch, volt) def setOffset(self, offs, ch=1): self.handle.SetOffsetVolt(ch, offs)
class Driver(BaseDriver): support_models = [ 'RSA5126B', ] quants = [ # add/select/delete general measurement view QOption('Add_general_measurement', set_cmd='DISP:GEN:MEAS:NEW %(option)s', options=[('Spectrum', 'SPEC'), ('IQ_vs_Time', 'IQVT'), ('Amp_vs_Time', 'AVT'), ('Freq_vs_Time', 'FVT'), ('Pha_vs_Time', 'PHVT'), ('DPX', 'DPX'), ('TimeOverview', 'TOVerview'), ('SGRam', 'SGR')]), QOption('Select_general_measurement', set_cmd='DISP:GEN:MEAS:SEL %(option)s', options=[('Spectrum', 'SPEC'), ('IQ_vs_Time', 'IQVT'), ('Amp_vs_Time', 'AVT'), ('Freq_vs_Time', 'FVT'), ('Pha_vs_Time', 'PHVT'), ('DPX', 'DPX'), ('TimeOverview', 'TOVerview'), ('SGRam', 'SGR')]), QOption('Delete_general_measurement', set_cmd='DISP:GEN:MEAS:DEL %(option)s', options=[('Spectrum', 'SPEC'), ('IQ_vs_Time', 'IQVT'), ('Amp_vs_Time', 'AVT'), ('Freq_vs_Time', 'FVT'), ('Pha_vs_Time', 'PHVT'), ('DPX', 'DPX'), ('TimeOverview', 'TOVerview'), ('SGRam', 'SGR')]), QReal('Get_general_measurement', value=[], get_cmd='DISP:WIND:ACT:MEAS?'), # set spectrum analyzer parameter QReal('Frequency center', value=5e9, unit='Hz', set_cmd='SENS:SPEC:FREQ:CENT %(value)f', get_cmd='SENS:SPEC:FREQ:CENT?'), QReal('Frequency span', value=1e6, unit='Hz', set_cmd='SENS:SPEC:FREQ:SPAN %(value)f', get_cmd='SENS:SPEC:FREQ:SPAN?'), QOption('Points', set_cmd='SENS:SPEC:POIN:COUN %(option)s', get_cmd='SENS:SPEC:POIN:COUN?', options=[('801', 'P801'), ('1601', 'P1601'), ('2401', 'P2401'), ('3201', 'P3201'), ('4001', 'P4001'), ('6401', 'P6401'), ('8001', 'P8001'), ('10401', 'P10401'), ('64001', 'P64001')]), QReal('Bandwidth', value=1e3, unit='Hz', set_cmd='SENS:SPEC:BAND:RES %(value)f', get_cmd='SENS:SPEC:BAND:RES?'), QReal('Acquire_Bandwidth', value=1e3, unit='Hz', set_cmd='SENS:ACQ:BAND %(value)f'), QOption('Acquire_mode', set_cmd='SENS:ACQ:MODE %(option)s', options=[('samples', 'SAMP'), ('length', 'LENG')]), QReal('Acquire_length', value=1e-3, unit='s', set_cmd='SENS:ACQ:SEC %(value)f', get_cmd='SENS:ACQ:SEC?'), QReal('Analysis_length', value=1e-3, unit='s', set_cmd='SENS:ANAL:LENG %(value)f', get_cmd='SENS:ANAL:LENG?'), QReal('Spectrum_length', value=1e-3, unit='s', set_cmd='SENS:SPEC:LENG %(value)f', get_cmd='SENS:SPEC:LENG?'), QOption('IQ_points', set_cmd='SENS:IQVT:MAXT %(option)s', options=[('1k', 'ONEK'), ('10k', 'TENK'), ('100k', 'HUND'), ('max', 'NEV')]), QOption('Mode', set_cmd='INIT:CONT %(option)s', get_cmd='INIT:CONT?', options=[('Continus', 'ON'), ('Single', 'OFF')]), # get spectrum trace and I/Q trace QReal('Spectrum_trace', value=[], unit='dBm', ch=1, get_cmd='FETCh:SPECtrum:TRACe%(ch)d?'), QReal('I_trace', value=[], unit='V', get_cmd='FETC:IQVT:I?'), QReal('Q_trace', value=[], unit='V', get_cmd='FETC:IQVT:Q?'), QReal('Amp_trace', value=[], unit='V', get_cmd='FETC:AVT?'), QReal('Freq_trace', value=[], unit='Hz', get_cmd='FETC:FVT?'), ] def init(self): self.write('SYSTem:PRESet') def performSetValue(self, quant, value, **kw): if quant.name == '': return else: return BaseDriver.performSetValue(self, quant, value, **kw) def performGetValue(self, quant, **kw): if quant.name in [ 'Spectrum_trace', 'I_trace', 'Q_trace', 'Amp_trace', 'Freq_trace' ]: if '%(ch)d' in quant.get_cmd: get_cmd = quant.get_cmd % dict(ch=quant.ch) else: get_cmd = quant.get_cmd value = self.query_binary_values(get_cmd) else: value = quant.getValue() return value def get_spectrum_trace(self, timeout=10): self.set_timeout(timeout) self.ins.write('INIT') center = self.getValue('Frequency center') span = self.getValue('Frequency span') points = int(self.getValue('Points')[1:]) freq = np.linspace(center - span / 2, center + span / 2, points) spectrum = self.getValue('Spectrum_trace', ch=1) return [freq, spectrum] def get_IQ_trace(self): self.setValue('Add_general_measurement', 'Freq_vs_Time') freq = np.average(self.getValue('Freq_trace')) I = self.getValue('I_trace') Q = self.getValue('Q_trace') time_list = np.linspace(1, len(I), len(I)) / 5 fit = Sin_Fit((time_list, I)) A, B, w, phi = fit._popt #print(freq) #print(0.5*w/np.pi) time_list = time_list * (0.5 * w / np.pi / freq) return [time_list, I, Q]
class Driver(BaseDriver): error_command = ':SYST:ERR?' support_models = ['DSA875'] quants = [ QOption('Sweep', value='ON', set_cmd='INIT:CONT %(option)s', options=[('OFF', 'OFF'), ('ON', 'ON')]), QOption('Trace Mode', value='WRIT',ch=1, set_cmd='TRAC%(ch)d:MODE %(option)s',get_cmd='TRAC%(ch)d:MODE?', options=[('Write', 'WRIT'), ('Maxhold', 'MAXH'),('Minhold','MINH'), ('View','VIEW'),('Blank','BLAN'),('Videoavg','VID'),('Poweravg','POW')]), QReal('Frequency Start', unit='Hz', set_cmd='SENS:FREQ:STAR %(value)e%(unit)s', get_cmd='SENS:FREQ:STAR?'), QReal('Frequency Stop', unit='Hz', set_cmd='SENS:FREQ:STOP %(value)e%(unit)s', get_cmd='SENS:FREQ:STOP?'), QInteger('Sweep Points',value=601, set_cmd=':SWE:POIN %(value)d',get_cmd=':SWE:POIN?') ] def get_Trace(self, average=1, ch=1): '''Get the Trace Data ''' points=self.getValue('Sweep Points') #Stop the sweep self.setValue('Sweep', 'OFF') if average==1: self.setValue('Trace Mode','Write',ch=ch) self.write(':SWE:COUN 1') else: self.setValue('Trace Mode','Poweravg',ch=ch) self.write(':TRAC:AVER:COUN %d' % average) self.write(':SWE:COUN %d' % average) self.write(':TRAC:AVER:RES') #Begin a measurement self.write('INIT:IMM') self.write('*WAI') count=float(self.query('SWE:COUN:CURR?')) while count < average: count=float(self.query('SWE:COUN:CURR?')) time.sleep(0.01) #Get the data self.write('FORMAT:BORD NORM') self.write('FORMAT ASCII') data_raw = self.query("TRAC:DATA? TRACE%d" % ch).strip('\n') _data = re.split(r",",data_raw[11:]) data=[] for d in _data[:points]: data.append(float(d)) #Start the sweep self.setValue('Sweep', 'ON') return np.array(data) def get_Frequency(self): """Return the frequency of DSA measurement""" freq_star=self.getValue('Frequency Start') freq_stop=self.getValue('Frequency Stop') sweep_point=self.getValue('Sweep Points') return np.array(np.linspace(freq_star,freq_stop,sweep_point)) def get_SNR(self,signalfreqlist=[],signalbandwidth=10e6,average=1, ch=1): '''get SNR_dB ''' Y_unit =self.query(':UNIT:POW?;:UNIT:POW W').strip('\n') Frequency=self.get_Frequency() Spectrum=self.get_Trace(average=average, ch=ch) Signal_power=0 Total_power=sum(Spectrum) for sf in signalfreqlist: for f in Frequency : if f > (sf-signalbandwidth/2) and f < (sf+signalbandwidth/2): index = np.where(Frequency==f) Signal_power = Signal_power + Spectrum[index] self.write(':UNIT:POW %s'%Y_unit) _SNR=Signal_power/(Total_power-Signal_power) SNR = 10*np.log10(_SNR) return SNR
class Driver(BaseDriver): support_models = [ 'M3202A', ] quants = [ QReal('Amplitude', value=1, unit='V', ch=0), #DC WaveShape QReal('Offset', value=0, unit='V', ch=0), #Function Generators(FGs) mode QReal('Frequency', unit='Hz', ch=0), QReal('Phase', value=0, unit='deg', ch=0), QOption('WaveShape', ch=0, value='HIZ', options=[('HIZ', -1), ('NoSignal', 0), ('Sin', 1), ('Triangular', 2), ('Square', 4), ('DC', 5), ('AWG', 6), ('PartnerCH', 8)]), #clock QReal('clockFrequency', unit='Hz'), QReal('clockSyncFrequency', unit='Hz'), # 板卡向外输出的时钟,默认状态关闭 QOption('clockIO', value='OFF', options=[('OFF', 0), ('ON', 1)]), QOption('triggerIO', value='SyncIN', options=[('noSyncOUT', (0, 0)), ('SyncOUT', (0, 1)), ('noSyncIN', (1, 0)), ('SyncIN', (1, 1))]), QOption('triggerMode', value='ExternalCycle', ch=0, options=[('Auto', 0), ('SWtri', 1), ('SWtriCycle', 5), ('External', 2), ('ExternalCycle', 6)]), QOption('triExtSource', value='EXTERN', ch=0, options=[('EXTERN', 0), ('PXI0', 4000), ('PXI1', 4001), ('PXI2', 4002), ('PXI3', 4003), ('PXI4', 4004), ('PXI5', 4005), ('PXI6', 4006), ('PXI7', 4007)]), QOption('triggerBehavior', value='RISE', ch=0, options=[('NONE', 0), ('HIGH', 1), ('LOW', 2), ('RISE', 3), ('FALL', 4)]), # Defines the delay between the trigger and the waveform launch in tens of ns QInteger( 'startDelay', value=0, unit='ns', ch=0, ), # Number of times the waveform is repeated once launched (negative means infinite) QInteger( 'cycles', value=0, ch=0, ), # Waveform prescaler value, to reduce the effective sampling rate QInteger( 'prescaler', value=0, ch=0, ), QOption('Output', ch=0, value='Close', options=[('Stop', 0), ('Run', 1), ('Pause', 2), ('Resume', 3), ('Close', -1)]), QList('WList', value=[]), QList('SList', value=[], ch=0), ] #CHs : 仪器通道 CHs = [0, 1, 2, 3] # config : 用来存储参数配置,防止由于多通道引起的混乱 config = {} def __init__(self, **kw): BaseDriver.__init__(self, **kw) self.chassis = kw['CHASSIS'] self.slot = kw['SLOT'] def newcfg(self): self.config = {} for q in self.quants: _cfg = {q.name: {}} if q.ch is not None: for i in self.CHs: _cfg[q.name].update( {i: { 'value': q.value, 'unit': q.unit }}) else: _cfg[q.name].update({0: {'value': q.value, 'unit': q.unit}}) self.config.update(_cfg) log.info('new config!') def loadcfg(self, file=None): if file == None: file = self.caches_file with open(file, 'r', encoding='utf-8') as f: self.config = yaml.load(f) log.info('load config: %s', file) def savecfg(self, file=None): if file == None: file = self.caches_file with open(file, 'w', encoding='utf-8') as f: yaml.dump(self.config, f) log.info('save config: %s', file) def performOpen(self): #SD_AOU module self.AWG = keysightSD1.SD_AOU() self.model = self.AWG.getProductNameBySlot(self.chassis, self.slot) moduleID = self.AWG.openWithSlot(self.model, self.chassis, self.slot) if moduleID < 0: print("Module open error:", moduleID) self.caches_file = caches_dir() / (self.model + '_config_caches.yaml') try: self.loadcfg() except Exception: log.exception(Exception) self.newcfg() self.savecfg() def performClose(self): """Perform the close instrument connection operation""" # refer labber driver keysight_pxi_awg.py # do not check for error if close was called with an error try: self.setValue('clockIO', 'OFF') # clear old waveforms and stop awg self.waveformFlush() for ch in self.CHs: self.closeCh(ch) # close instrument # self.AWG.close() self.savecfg() except Exception: # never return error here pass def closeCh(self, ch=0): self.AWG.AWGstop(ch) self.AWG.AWGflush(ch) self.config['SList'][ch]['value'] = [] self.AWG.channelWaveShape(ch, -1) self.config['WaveShape'][ch]['value'] = 'HIZ' self.config['Output'][ch]['value'] = 'Close' def performSetValue(self, quant, value, ch=0, **kw): _cfg = {} if quant.name == 'Amplitude': self.AWG.channelAmplitude(ch, value) elif quant.name == 'Offset': self.AWG.channelOffset(ch, value) elif quant.name == 'Frequency': self.AWG.channelFrequency(ch, value) elif quant.name == 'Phase': self.phaseReset(ch) self.AWG.channelPhase(ch, value) elif quant.name == 'WaveShape': options = dict(quant.options) self.AWG.channelWaveShape(ch, options[value]) elif quant.name == 'clockFrequency': mode = kw.get('mode', 1) self.AWG.clockSetFrequency(value, mode) ch = 0 elif quant.name == 'clockIO': options = dict(quant.options) self.AWG.clockIOconfig(options[value]) ch = 0 elif quant.name == 'triggerIO': options = dict(quant.options) self.AWG.triggerIOconfigV5(*options[value]) ch = 0 elif quant.name == 'Output': if value == 'Stop': self.AWG.AWGstop(ch) elif value == 'Run': self.AWG.AWGstart(ch) elif value == 'Pause': self.AWG.AWGpause(ch) elif value == 'Resume': self.AWG.AWGresume(ch) elif value == 'Close': self.closeCh(ch) elif quant.name == 'clockSyncFrequency': print("clockSyncFrequency can't be set") return _cfg['value'] = value self.config[quant.name][ch].update(_cfg) def performGetValue(self, quant, ch=0, **kw): _cfg = {} if quant.name == 'clockFrequency': value = self.AWG.clockGetFrequency() ch = 0 _cfg['value'] = value elif quant.name == 'clockSyncFrequency': value = self.AWG.clockGetSyncFrequency() ch = 0 _cfg['value'] = value elif quant.name in ['clockIO', 'triggerIO']: ch = 0 self.config[quant.name][ch].update(_cfg) return self.config[quant.name][ch]['value'] def phaseReset(self, ch=0): self.AWG.channelPhaseReset(ch) _cfg = {'value': 0} self.config['Phase'][ch].update(_cfg) def clockResetPhase(self): # self.AWG.clockResetPhase(triggerBehavior, triggerSource, skew = 0.0) pass def newWaveform(self, file_arrayA, arrayB=None, waveformType=0): '''Memory usage: Waveforms created with New are stored in the PC RAM, not in the module onboard RAM. Therefore, the limitation in the number of waveforms and their sizes is given by the amount of PC RAM.''' # waveformType 0: Analog 16Bits, Analog normalized waveforms (-1..1) defined with doubles # please refer AWG Waveform types about others wave = keysightSD1.SD_Wave() if isinstance(file_arrayA, str): wave.newFromFile(file_arrayA) return wave else: # 5: DigitalType, Digital waveforms defined with integers if waveformType == 5: wave.newFromArrayInteger(waveformType, file_arrayA, arrayB) else: wave.newFromArrayDouble(waveformType, file_arrayA, arrayB) return wave def waveformLoad(self, waveform, num, paddingMode=0): '''num: waveform_num, 在板上内存的波形编号''' if num in self.config['WList'][0]['value']: self.AWG.waveformReLoad(waveform, num, paddingMode) else: # This function replaces a waveform located in the module onboard RAM. # The size of the newwaveform must be smaller than or equal to the existing waveform. self.AWG.waveformLoad(waveform, num, paddingMode) self.config['WList'][0]['value'].append(num) # def waveformReLoad(self, waveform, num, paddingMode = 0): # '''This function replaces a waveform located in the module onboard RAM. # The size of the newwaveform must be smaller than or equal to the existing waveform.''' # self.AWG.waveformReLoad(waveform, num, paddingMode) def waveformFlush(self): '''This function deletes all the waveforms from the module onboard RAM and flushes all the AWG queues''' self.AWG.waveformFlush() self.config['WList'][0]['value'] = [] self.config['SList'][0]['value'] = [] def AWGflush(self, ch=0): '''This function empties the queue of the selected Arbitrary Waveform Generator, Waveforms are not removed from the module onboard RAM.''' self.AWG.AWGflush(ch) self.config['SList'][0]['value'] = [] def _getParams(self, ch): triggerModeIndex = self.getValue('triggerMode', ch=ch) triggerModeOptions = self.quantities['triggerMode'].options triggerMode = dict(triggerModeOptions)[triggerModeIndex] if triggerModeIndex in ['External', 'ExternalCycle']: triExtSourceIndex = self.getValue('triExtSource', ch=ch) triExtSourceOptions = self.quantities['triExtSource'].options triExtSource = dict(triExtSourceOptions)[triExtSourceIndex] if triExtSourceIndex in ['EXTERN']: # 若未设置过,则从config读取默认配置;若已设置,则结果不变 triggerIO = self.getValue('triggerIO') self.setValue('triggerIO', triggerIO) triggerBehaviorIndex = self.getValue('triggerBehavior', ch=ch) triggerBehaviorOptions = self.quantities['triggerBehavior'].options triggerBehavior = dict( triggerBehaviorOptions)[triggerBehaviorIndex] self.AWG.AWGtriggerExternalConfig(ch, triExtSource, triggerBehavior) startDelay = self.getValue('startDelay', ch=ch) cycles = self.getValue('cycles', ch=ch) prescaler = self.getValue('prescaler', ch=ch) return triggerMode, startDelay, cycles, prescaler def AWGqueueWaveform(self, ch=0, waveform_num=0): self.setValue('WaveShape', 'AWG', ch=ch) Amplitude = self.getValue('Amplitude', ch=ch) self.setValue('Amplitude', Amplitude, ch=ch) triggerMode, startDelay, cycles, prescaler = self._getParams(ch) self.AWG.AWGqueueWaveform(ch, waveform_num, triggerMode, startDelay, cycles, prescaler) self.config['SList'][ch]['value'].append(waveform_num) def AWGrun(self, file_arrayA, arrayB=None, ch=0, waveformType=0, paddingMode=0): '''从文件或序列快速产生波形''' self.setValue('WaveShape', 'AWG', ch=ch) Amplitude = self.getValue('Amplitude', ch=ch) self.setValue('Amplitude', Amplitude, ch=ch) triggerMode, startDelay, cycles, prescaler = self._getParams(ch) if isinstance(file_arrayA, str): # AWGFromFile 有bug self.AWG.AWGFromFile(ch, file_arrayA, triggerMode, startDelay, cycles, prescaler, paddingMode) else: self.AWG.AWGfromArray(ch, triggerMode, startDelay, cycles, prescaler, waveformType, file_arrayA, arrayB, paddingMode) self.config['Output'][ch]['value'] = 'Run'
class Driver(BaseDriver): support_models = ['AWG70001A', 'AWG70002A'] quants = [ # Sample Rate set_cmd is block cmd # QReal('Sample Rate', unit='S/s', set_cmd='CLOC:SRAT %(value).10e; *WAI;', get_cmd='CLOC:SRAT?'), QOption('Run Mode', value='CONT', ch=1, set_cmd='SOUR%(ch)d:RMOD %(option)s', get_cmd='SOUR%(ch)d:RMOD?', options = [ ('Continuous', 'CONT'), ('Triggered', 'TRIG'), ('TContinuous','TCON')]), QOption('Clock Source', value='INT', set_cmd='CLOC:SOUR %(option)s', get_cmd='CLOC:SOUR?', options = [('Internal', 'INT'), ('External', 'EXT'), ('Efixed', 'EFIX'), ('Evariable','EVAR')]), # QOption('Reference Source', set_cmd='SOUR:ROSC:SOUR %(option)s', get_cmd='SOUR:ROSC:SOUR?', # options = [('Internal', 'INT'), ('External', 'EXT')]), QReal('Multiplier Rate ', value=1, set_cmd='CLOC:EREF:MULT %(value)d', get_cmd='CLOC:EREF:MULT?'), QReal('Divider Rate ', value=1, set_cmd='CLOC:EREF:DIV %(value)d', get_cmd='CLOC:EREF:DIV?'), # 以下四种只在 output path 为 Direct 时有效 # Vpp range: 250-500mVpp QReal('Vpp', unit='Vpp', ch=1, set_cmd='SOUR%(ch)d:VOLT %(value)f%(unit)s', get_cmd='SOUR%(ch)d:VOLT?'), QReal('Offset', unit='V', ch=1, set_cmd='SOUR%(ch)d:VOLT:OFFS %(value)f%(unit)s', get_cmd='SOUR%(ch)d:VOLT:OFFS?'), QReal('Volt Low', unit='V', ch=1, set_cmd='SOUR%(ch)d:VOLT:LOW %(value)f%(unit)s', get_cmd='SOUR%(ch)d:VOLT:LOW?'), QReal('Volt High', unit='V', ch=1, set_cmd='SOUR%(ch)d:VOLT:HIGH %(value)f%(unit)s', get_cmd='SOUR%(ch)d:VOLT:HIGH?'), # output delay in time QReal('timeDelay', unit='s', ch=1, set_cmd='SOUR%(ch)d:DEL:ADJ %(value)f%(unit)s', get_cmd='SOUR%(ch)d:DEL:ADJ?'), # output delay in point QReal('timeDelay', unit='point', ch=1, set_cmd='SOUR%(ch)d:DEL:POIN %(value)d', get_cmd='SOUR%(ch)d:DELy:POIN?'), QOption('Run', value = 'Play', set_cmd='AWGC:%(option)s; *WAI;', get_cmd='AWGC:RST?', options = [('Play', 'RUN'), ('Stop', 'STOP')]), QOption('Output', ch=1, set_cmd='OUTP%(ch)d %(option)s', get_cmd='OUTP%(ch)d?', options = [('ON', 1), ('OFF', 0), (1, 'ON'), (0, 'OFF')]), QList('WList'), QList('SList'), # INSTrument MODE : AWG or FG QOption('instMode', value='AWG', set_cmd = 'INST:MODE %(option)s', get_cmd = 'INST:MODE?', options = [('AWG','AWG'), ('FG','FGEN'), ]), QOption('FG Type', ch=1, value='Sin', set_cmd = 'FGEN:CHAN%(ch)d:TYPE %(option)s', get_cmd = 'FGEN:CHAN%(ch)d:TYPE?', options = [('Sin','SINE'), ('Square','SQU'), ('Triangle','TRI'), ('Noise','NOIS'), ('DC','DC'), ('Gaussian','GAUS'), ('ExpRise','EXPR'), ('ExpDecay','EXPD'), ('None','NONE'), ]), QReal('FG Amplitude', ch=1, value=0.5, unit='V', set_cmd = 'FGEN:CHAN%(ch)d:AMPL:VOLT %(value)f%(unit)s', get_cmd = 'FGEN:CHAN%(ch)d:AMPL:VOLT?'), #FG Offset -150mV~150mV, min Unit 1mV QReal('FG Offset', ch=1, value=0, unit='V', set_cmd = 'FGEN:CHAN%(ch)d:OFFS %(value)f%(unit)s', get_cmd = 'FGEN:CHAN%(ch)d:OFFS?'), QReal('FG Phase', ch=1, value=0, unit='deg', set_cmd = 'FGEN:CHAN%(ch)d:PHAS %(value)f', get_cmd = 'FGEN:CHAN%(ch)d:PHAS?'), QReal('FG Frequency', ch=1, value=1e6, unit='Hz', set_cmd = 'FGEN:CHAN%(ch)d:FREQ %(value)f%(unit)s', get_cmd = 'FGEN:CHAN%(ch)d:FREQ?'), QReal('FG Period', ch=1, unit='s', # 周期与频率绑定,无法设置周期,但可读 set_cmd ='', get_cmd = 'FGEN:CHAN%(ch)d:PER?'), # DC Level Range: –250 mV to 250 mV QReal('FG DC', ch=1, value=0, unit='V', set_cmd = 'FGEN:CHAN%(ch)d:DCL %(value)f%(unit)s', get_cmd = 'FGEN:CHAN%(ch)d:DCL?'), QReal('FG High', ch=1, value=0.25, unit='V', set_cmd = 'FGEN:CHAN%(ch)d:HIGH %(value)f%(unit)s', get_cmd = 'FGEN:CHAN%(ch)d:HIGH?'), QReal('FG Low', ch=1, value=-0.25, unit='V', set_cmd = 'FGEN:CHAN%(ch)d:LOW %(value)f%(unit)s', get_cmd = 'FGEN:CHAN%(ch)d:LOW?'), #coupling mode: DIR, DCAM, AC QOption('FG Path', ch=1, value='Direct', set_cmd = 'FGEN:CHAN%(ch)d:PATH %(option)s', get_cmd = 'FGEN:CHAN%(ch)d:PATH?', options = [('Direct','DIR'), ('DCAmplified','DCAM'), ('AC','AC'), ]), ] def performOpen(self): self.waveform_list = self.get_waveform_list() try: #没有sequence模块的仪器会产生一个错误 self.sequence_list = self.get_sequence_list() except: self.sequence_list = None def performSetValue(self, quant, value, **kw): if quant.name == '': return else: return BaseDriver.performSetValue(self, quant, value, **kw) def performGetValue(self, quant, **kw): if quant.name == 'WList': self.waveform_list = self.get_waveform_list() return self.waveform_list elif quant.name == 'SList': self.sequence_list = self.get_sequence_list() return self.sequence_list else: return BaseDriver.performGetValue(self, quant, **kw) def get_waveform_list(self): return self.query('WLIS:LIST?').strip("\"\n' ").split(',') def get_sequence_list(self): ret = [] slist_size = int(self.query("SLIS:SIZE?")) for i in range(slist_size): ret.append(self.query("SLIS:NAME? %d" % i).strip("\"\n '")) return ret def create_waveform(self, name, length, format='REAL'): '''format: REAL or IQ''' if name in self.waveform_list: return self.write('WLIS:WAV:NEW "%s",%d,%s;*WAI;' % (name, length, format)) self.waveform_list = self.get_waveform_list() def remove_waveform(self, name=None, all=False): if all: self.write('WLIS:WAV:DEL ALL; *WAI;') self.waveform_list.clear() elif name not in self.waveform_list: return else: self.write('WLIS:WAV:DEL "%s"; *WAI;' % name) self.waveform_list = self.get_waveform_list() def get_waveform_length(self,name): size = int(self.query('WLIS:WAV:LENGTH? "%s"' % name)) return size def use_waveform(self, name, ch=1, type=None): '''type: I or Q''' if type is not None: self.write('SOUR%d:CASS:WAV "%s",%s' % (ch, name, type)) else: self.write('SOUR%d:CASS:WAV "%s"' % (ch, name)) self.write('*WAI;') # 关于RUN的设置和状态询问,建议使用Quantity:Run的方法 def run_state(self): return int(self.query('AWGC:RST?')) def run(self): self.write('AWGC:RUN') self.write('*WAI') def stop(self): self.write('AWGC:STOP') # 关于Output的设置和状态询问,建议使用Quantity:Output的方法 def output_on(self, ch=1): self.write('OUTP%d:STAT 1' % ch) def output_off(self, ch=1): self.write('OUTP%d:STAT 0' % ch) def get_current_asset(self, ch=1): current_type = self.query('SOUR%d:CASS:TYPE?' % ch) current_asset = self.query('SOUR%d:CASS?' % ch) return current_type, current_asset def update_waveform(self, points, name='ABS', IQ='I', start=0, size=None): w_type = self.query('WLIS:WAV:TYPE? "%s"' % name).strip() if w_type == 'REAL': self._update_waveform_float(points, name, IQ, start, size) elif w_type == 'IQ': self._update_waveform_float(points[0], name, 'I', start, size) self._update_waveform_float(points[1], name, 'Q', start, size) self.write('*WAI;') # else: # self._update_waveform_int(points, name, start, size) # def _update_waveform_int(self, points, name='ABS', start=0, size=None): # """ # points : a 1D numpy.array which values between -1 and 1. # """ # message = 'WLIST:WAVEFORM:DATA "%s",%d,' % (name, start) # if size is not None: # message = message + ('%d,' % size) # points = points.clip(-1,1) # values = (points * 0x1fff).astype(int) + 0x1fff # self.write_binary_values(message, values, datatype=u'H', # is_big_endian=False, # termination=None, encoding=None) def _update_waveform_float(self, points, name='ABS', IQ='I', start=0, size=None): message = 'WLIST:WAVEFORM:DATA:%s "%s",%d,' % (IQ, name, start) if size is not None: message = message + ('%d,' % size) values = points.clip(-1,1) self.write_binary_values(message, values, datatype=u'f', is_big_endian=False, termination=None, encoding=None) # def update_marker(self, name, mk1, mk2=None, mk3=None, mk4=None, start=0, size=None): # def format_marker_data(markers, bits): # values = 0 # for i, v in markers: # v = 0 if v is None else np.asarray(v) # values += v << bits[i] # return values # # if self.model in ['AWG5014C']: # values = format_marker_data([mk1, mk2], [5,6]) # elif self.model in ['AWG5208']: # values = format_marker_data([mk1, mk2, mk3, mk4], [7,6,5,4]) # if size is None: # message = 'WLIST:WAVEFORM:MARKER:DATA "%s",%d,' % (name, start) # else: # message = 'WLIST:WAVEFORM:MARKER:DATA "%s",%d,%d,' % (name, start, size) # self.write_binary_values(message, values, datatype=u'B', # is_big_endian=False, # termination=None, encoding=None) def create_sequence(self, name, steps, tracks=1): if name in self.sequence_list: return self.write('SLIS:SEQ:NEW "%s", %d, %d; *WAI;' % (name, steps, tracks)) self.sequence_list = self.get_sequence_list() def remove_sequence(self, name=None, all=False): if all: self.write('SLIS:SEQ:DEL ALL; *WAI;') self.sequence_list.clear() elif name not in self.sequence_list: return else: self.write('SLIS:SEQ:DEL "%s"; *WAI;' % name) self.sequence_list = self.get_sequence_list() # # def set_sequence_step(self, name, sub_name, step, wait='OFF', goto='NEXT', repeat=1, jump=None): # """set a step of sequence # # name: sequence name # sub_name: subsequence name or list of waveforms for every tracks # wait: ATRigger | BTRigger | ITRigger | OFF # goto: <NR1> | LAST | FIRSt | NEXT | END # repeat: ONCE | INFinite | <NR1> # jump: a tuple (jump_input, jump_to) # jump_input: ATRigger | BTRigger | OFF | ITRigger # jump_to: <NR1> | NEXT | FIRSt | LAST | END # """ # if isinstance(sub_name, str): # self.write('SLIS:SEQ:STEP%d:TASS:SEQ "%s","%s"' % (step, name, sub_name)) # else: # for i, wav in enumerate(sub_name): # self.write('SLIS:SEQ:STEP%d:TASS%d:WAV "%s","%s"' % (step, i+1, name, wav)) # self.write('SLIS:SEQ:STEP%d:WINP "%s", %s' % (step, name, wait)) # self.write('SLIS:SEQ:STEP%d:GOTO "%s", %s' % (step, name, goto)) # self.write('SLIS:SEQ:STEP%d:RCO "%s", %s' % (step, name, repeat)) # if jump is not None: # self.write('SLIS:SEQ:STEP%d:EJIN "%s", %s' % (step, name, jump[0])) # self.write('SLIS:SEQ:STEP%d:EJUM "%s", %s' % (step, name, jump[1])) def use_sequence(self, name, ch=1, track=1, type=None): '''type: I or Q''' if type is not None: self.write('SOUR%d:CASS:SEQ "%s", %d, %s' % (ch, name, track, type)) else: self.write('SOUR%d:CASS:SEQ "%s", %d' % (ch, name, track)) self.write('*WAI;')
class Driver(BaseDriver): support_models = ['E8363B', 'E8363C', 'E5071C', 'ZNB20-2Port', 'N5232A'] quants = [ QReal('Power', value=-20, unit='dBm', set_cmd='SOUR:POW %(value)e%(unit)s', get_cmd='SOUR:POW?'), QReal('Frequency center', value=5e9, unit='Hz', set_cmd='SENS:FREQ:CENT %(value).13e%(unit)s', get_cmd='SENS:FREQ:CENT?'), QReal('Frequency span', value=2e9, unit='Hz', set_cmd='SENS:FREQ:SPAN %(value)e%(unit)s', get_cmd='SENS:FREQ:SPAN?'), QReal('Frequency start', value=4e9, unit='Hz', set_cmd='SENS:FREQ:STAR %(value)e%(unit)s', get_cmd='SENS:FREQ:STAR?'), QReal('Frequency stop', value=6e9, unit='Hz', set_cmd='SENS:FREQ:STOP %(value)e%(unit)s', get_cmd='SENS:FREQ:STOP?'), QReal('Bandwidth', value=1e3, unit='Hz', set_cmd='SENS:BAND %(value)e%(unit)s', get_cmd='SENS:BAND?'), QVector('Frequency', unit='Hz'), QVector('Trace'), QVector('S'), QOption('Sweep', value='ON', set_cmd='INIT:CONT %(option)s', options=[('OFF', 'OFF'), ('ON', 'ON')]), QOption('Output', value='ON', set_cmd='OUTP %(option)s', options=[('OFF', 'OFF'), ('ON', 'ON')]), QInteger('Number of points', value=201, unit='', set_cmd='SENS:SWE:POIN %(value)d', get_cmd='SENS:SWE:POIN?'), QOption('Format', value='MLOG', set_cmd='CALC:FORM %(option)s', get_cmd='CALC:FORM?', options=[('Mlinear', 'MLIN'), ('Mlog', 'MLOG'), ('Phase', 'PHAS'), ('Unwrapped phase', 'UPH'), ('Imag', 'IMAG'), ('Real', 'REAL'), ('Polar', 'POL'), ('Smith', 'SMIT'), ('SWR', 'SWR'), ('Group Delay', 'GDEL')]), QOption('SweepType', value='', set_cmd='SENS:SWE:TYPE %(option)s', get_cmd='SENS:SWE:TYPE?', options=[('Linear', 'LIN'), ('Log', 'LOG'), ('Power', 'POW'), ('CW', 'CW'), ('Segment', 'SEGM'), ('Phase', 'PHAS')]) ] ''' def performSetValue(self, quant, value, **kw): if quant.name == 'Power': self.setValue('Power:Start', value) self.setValue('Power:Center', value) self.setValue('Power:Stop', value) else: super(Driver, self).performSetValue(quant, value, **kw) ''' def performGetValue(self, quant, **kw): get_vector_methods = { 'Frequency': self.get_Frequency, 'Trace': self.get_Trace, 'S': self.get_S, } if quant.name in get_vector_methods.keys(): return get_vector_methods[quant.name](ch=kw.get('ch', 1)) else: return super(Driver, self).performGetValue(quant, **kw) def get_Trace(self, ch=1): '''Get trace''' return self.get_S(ch, formated=True) def get_S(self, ch=1, formated=False): '''Get the complex value of S paramenter or formated data''' #Select the measurement self.pna_select(ch) #Stop the sweep self.setValue('Sweep', 'OFF') #Begin a measurement self.write('INIT:IMM') self.write('*WAI') #Get the data self.write('FORMAT:BORD NORM') if self.model in ['E5071C']: self.write(':FORM:DATA ASC') else: self.write('FORMAT ASCII') cmd = ("CALC%d:DATA? FDATA" % ch) if formated else ("CALC%d:DATA? SDATA" % ch) data = np.asarray(self.query_ascii_values(cmd)) if formated: if self.model in ['E5071C']: data = data[::2] else: data = data[::2] + 1j * data[1::2] #Start the sweep self.setValue('Sweep', 'ON') return data def pna_select(self, ch=1): '''Select the measurement''' if self.model in ['E5071C']: return if self.model in ['E8363C', 'E8363B', 'N5232A']: quote = '" ' elif self.model in ['ZNB20-2Port']: quote = "' " msg = self.query('CALC%d:PAR:CAT?' % ch).strip(quote) measname = msg.split(',')[0] self.write('CALC%d:PAR:SEL "%s"' % (ch, measname)) def get_Frequency(self, ch=1): """Return the frequency of pna measurement""" #Select the measurement self.pna_select(ch) if self.model == 'E8363C': cmd = 'CALC:X?' return np.asarray(self.query_ascii_values(cmd)) if self.model in ['E8363B', 'N5232A']: freq_star = self.getValue('Frequency start') freq_stop = self.getValue('Frequency stop') num_of_point = self.getValue('Number of points') return np.array(np.linspace(freq_star, freq_stop, num_of_point)) elif self.model in ['ZNB20-2Port']: cmd = 'CALC:DATA:STIM?' return np.asarray(self.query_ascii_values(cmd)) def set_segments(self, segments=[], form='Start Stop'): self.write('SENS:SEGM:DEL:ALL') if form == 'Start Stop': cmd = ['SENS:SEGM:LIST SSTOP,%d' % len(segments)] for kw in segments: data = '1,%(num)d,%(start)g,%(stop)g,%(IFBW)g,0,%(power)g' % kw cmd.append(data) else: cmd = ['SENS:SEGM:LIST CSPAN,%d' % len(segments)] for kw in segments: data = '1,%(num)d,%(center)g,%(span)g,%(IFBW)g,0,%(power)g' % kw cmd.append(data) self.write('FORMAT ASCII') self.write(','.join(cmd))
class Driver(BaseDriver): support_models = ['SLFS0218F'] quants = [ QReal('Frequency', ch=1, unit='Hz', set_cmd='FREQ %(value).13e %(unit)s', get_cmd='FREQ?'), QReal('Power', ch=1, unit='dBm', set_cmd='LEVEL %(value).5e %(unit)s', get_cmd='LEVEL?'), QOption('Output', ch=1, set_cmd='LEVEL:STATE %(option)s', options=[('OFF', 'OFF'), ('ON', 'ON')]), QOption('Reference', set_cmd='REF_10M:STATE %(option)s', options=[('INT', 'EXT'), ('INT', 'EXT')]), ] CHs = [1] def __init__(self, addr, **kw): super().__init__(addr=addr, **kw) #self.port = kw.get('port', 2000) self.port = 2000 def performOpen(self, **kw): try: IDN = self.query("*IDN?\n").split(',') # company = IDN[0].strip() model = IDN[1].strip() # version = IDN[3].strip() self.model = model except: raise IOError('query IDN error!') @contextmanager def _socket(self): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((self.addr, self.port)) yield s def write(self, cmd): if isinstance(cmd, str): cmd = cmd.encode() with self._socket() as s: s.send(cmd) log.debug(f"{self.addr}:{self.port} << {cmd}") # 返回字符串格式,QReal无法用getValue def query(self, cmd): if isinstance(cmd, str): cmd = cmd.encode() with self._socket() as s: s.send(cmd) log.debug(f"{self.addr}:{self.port} << {cmd}") ret = s.recv(1024).decode() log.debug(f"{self.addr}:{self.port} >> {ret}") return ret
class Driver(BaseDriver): support_models = [ 'UHFAWG', ] quants = [ QOption('SampleRate', ch=0, get_cmd='/awgs/0/time', options=[('1.8G', 0), ('900M', 1), ('450M', 2), ('225M', 3), ('112.5M', 4), ('56.25M', 5), ('28.12M', 6)]), QOption('Output', ch=0, get_cmd='/sigouts/%(ch)d/on', options=[('ON', 1), ('OFF', 0)]), QOption('Imp50', ch=0, get_cmd='/sigouts/%(ch)d/imp50', options=[('ON', 1), ('OFF', 0)]), QOption('MaxRange', ch=0, get_cmd='/sigouts/%(ch)d/range', options=[('0.075', 0.075), ('0.75', 0.75)]), QReal('Offset', value=0, unit='V', ch=0, get_cmd='/sigouts/%(ch)d/offset'), QReal('Amplitude', value=1.0, unit='1', ch=0, get_cmd='/awgs/0/outputs/%(ch)d/amplitude'), QOption('RunMode', get_cmd='/awgs/0/single', options=[('Continuous', 1), ('Triggered', 0)]), QOption('TrigChannel', get_cmd='/awgs/0/auxtriggers/0/channel', options=[('TrigIn1', 0), ('TrigIn2', 1), ('TrigIn3', 2), ('TrigIn4', 3)]), QOption('TrigSlope', get_cmd='/awgs/0/auxtriggers/0/slope', options=[('Level', 0), ('Rise', 1), ('Fall', 2), ('Both', 3)]), # AWG modulation,Plain means no,Modulation means yes, # ch=0, ch=1 can only be modulated by the following Sig~3、Sig~7, QOption('Modulation', ch=0, get_cmd='/awgs/0/outputs/%(ch)d/mode', options=[('Plain', 0), ('Modulation', 1)]), # set oscillator freq,max is 600e6Hz, 'ch' is oscillator index, should be within(0~7) QReal('OscFreq', value=10e6, unit='Hz', ch=0, get_cmd='/oscs/%(ch)d/freq'), # set the corresponding oscillator of every inter signal, 'ch' is Sig index(0~7),'value' is oscillator index(0~7) QReal('SigOsc', value=0, ch=0, get_cmd='/demods/%(ch)d/oscselect'), # set the amp of inter signal(index=0), and it will be add to output channel 'ch', unit='V',limitted by ’MaxRange‘ QReal('Sig0Amp', value=0., unit='V', ch=0, get_cmd='/sigouts/%(ch)d/amplitudes/0'), # set the amp of inter signal(index=1), and it will be add to output channel 'ch', unit='V',limitted by ’MaxRange‘ QReal('Sig1Amp', value=0., unit='V', ch=0, get_cmd='/sigouts/%(ch)d/amplitudes/1'), # enable adding signal(index=0) to output channel 'ch' QOption('Sig0Enable', ch=0, get_cmd='/sigouts/%(ch)d/enables/0', options=[('enable', 1), ('disable', 0)]), # enable adding signal(index=1) to output channel 'ch' QOption('Sig1Enable', ch=0, get_cmd='/sigouts/%(ch)d/enables/1', options=[('enable', 1), ('disable', 0)]), # set signal input info, ch means signal index(0、1) QOption('Sig_In_Channel', ch=0, get_cmd='/scopes/0/channels/%(ch)d/inputselect', options=[('signalinput1', 0), ('signalinput2', 1), ('trigger1', 2), ('trigger2', 3)]), QOption('Sig_In_SampleRate', ch=0, get_cmd='/scopes/0/time', options=[('1.8G', 0), ('900M', 1), ('450M', 2), ('225M', 3), ('112M', 4), ('56M', 5), ('28M', 6), ('14M', 7)]), QOption('Sig_In_RunMode', get_cmd='/scopes/0/single', options=[('Continuous', 1), ('Triggered', 0)]), QOption('Sig_In_TrigChannel', get_cmd='/scopes/0/trigchannel', options=[('TrigIn1', 0), ('TrigIn2', 3)]), QOption('Sig_In_TrigEnable', get_cmd='/scopes/0/trigenable', options=[('enable', 1), ('disable', 0)]), QReal('Record_length', value=1000, unit='point', ch=0, get_cmd='/scopes/0/length'), QOption('Sig_In_Imp50', ch=0, get_cmd='/sigins/%(ch)d/imp50', options=[('ON', 1), ('OFF', 0)]), QOption('Sig_In_AC', ch=0, get_cmd='/sigins/%(ch)d/ac', options=[('ON', 1), ('OFF', 0)]), QReal('Sig_In_Range', value=1.0, unit='V', ch=0, get_cmd='/sigins/%(ch)d/range'), QOption('Sig_In_Diffmode', ch=0, get_cmd='/sigins/%(ch)d/diff', options=[('OFF', 0), ('Sig1-Sig2', 2), ('Sig2-Sig1', 3)]), QOption('Sig_In_TrigSlope', get_cmd='/scopes/0/trigslope', options=[('Level', 0), ('Rise', 1), ('Fall', 2), ('Both', 3)]), QReal('Sig_In_TrigLevel', value=0.5, unit='V', ch=0, get_cmd='/scopes/0/triglevel'), QReal('Sig_In_TrigDelay', value=100e-9, unit='s', ch=0, get_cmd='/scopes/0/trigdelay'), # set aux channel QOption('Aux_output_select', ch=0, get_cmd='/auxouts/%(ch)d/outputselect', options=[('AWG', 4), ('Manual', -1)]), QOption('Aux_demod_select', ch=0, get_cmd='/auxouts/%(ch)d/demodselect', options=[('aux_ch0', 0), ('aux_ch1', 1), ('aux_ch2', 2), ('aux_ch3', 3)]), QReal('Aux_output_scale', value=2.0, unit='V', ch=0, get_cmd='/auxouts/%(ch)d/scale'), QReal('Aux_output_offset', value=0.0, unit='V', ch=0, get_cmd='/auxouts/%(ch)d/offset'), ] def __init__(self, **kw): BaseDriver.__init__(self, **kw) self.deviceID = kw['deviceID'] self.n_ch = 2 self.wave = {} self._node_datatypes = {} self.aux_n_ch = 4 self.aux_out = False def performOpen(self, **kw): """Perform the operation of opening the instrument connection""" # connect through deviceID apilevel = 6 # The API level supported by this driver (daq, device, props) = zhinst.utils.create_api_session(self.deviceID, apilevel, required_devtype='UHF', required_options=['AWG']) zhinst.utils.api_server_version_check(daq) # Create a base configuration: Disable all available outputs, awgs, demods, scopes,... zhinst.utils.disable_everything(daq, device) self.daq = daq self.device = device self.props = props def performClose(self, **kw): """Perform the close instrument connection operation""" # do not check for error if close was called with an error try: base = '/%s/awgs/0/' % self.device self.daq.setInt(base + 'enable', 0) except Exception: # never return error here pass def init(self): # Create a base configuration: Disable all available outputs, awgs, demods, scopes,... zhinst.utils.disable_everything(self.daq, self.device) def performSetValue(self, quant, value, ch=0): """Perform the Set Value instrument operation. This function should return the actual value set by the instrument""" # update value, necessary since we later use getValue to get config quant.setValue(value) quant.ch = ch # set node parameters if quant.get_cmd != '': if quant.type == 'Option': value_set = self._set_node_value(quant, dict(quant.options)[value]) else: value_set = self._set_node_value(quant, value) return value_set def create_waveform(self, length=0, aux_length=0): # re_init AWG for clearing the wave in used #self.init() # map wave to channel self._map_wave_to_channel() # proceed depending on run mode run_mode = self._get_node_value(self.quantities['RunMode']) # create waveforms, one per channel awg_program = '' for channel in range(self.n_ch): awg_program += textwrap.dedent("""\ wave w%d = zeros(_N_)+1; """) % (channel) # if needs aux output, create aux waveform for aux channel if self.aux_out: for channel in range(self.aux_n_ch): awg_program += textwrap.dedent("""\ wave aux_w%d = zeros(_AUX_N_); """) % (channel) # continue mode (internal trigger mode) if run_mode == 1: awg_program += textwrap.dedent("""\ setUserReg(0, 0); while(true){ while(getUserReg(0) == 0){ playWave(%s); playAuxWave(%s); } }""") % (self.wave_to_channel, self.aux_wave_to_channel) elif run_mode == 0: awg_program += textwrap.dedent("""\ setUserReg(0, 0); while(true){ waitDigTrigger(1,1); playWave(%s); playAuxWave(%s); }""") % (self.wave_to_channel, self.aux_wave_to_channel) # Replace the placeholder with the length of points. awg_program = awg_program.replace('_AUX_N_', str(aux_length)) else: # continue mode (internal trigger mode) if run_mode == 1: awg_program += textwrap.dedent("""\ setUserReg(0, 0); while(true){ while(getUserReg(0) == 0){ playWave(%s); } }""") % (self.wave_to_channel) elif run_mode == 0: awg_program += textwrap.dedent("""\ setUserReg(0, 0); while(true){ waitDigTrigger(1,1); playWave(%s); }""") % (self.wave_to_channel) # Replace the placeholder with the length of points. awg_program = awg_program.replace('_N_', str(length)) # stop current AWG base = '/%s/awgs/0/' % (self.device) self.daq.setInt(base + 'enable', 0) # compile and upload self._upload_awg_program(awg_program, core=0) def update_waveform(self, points, name='ABC'): self.wave[name] = points def use_waveform(self, name): # 'name' should be the type of name=['name0','name1','aux_name0','aux_name1',...] # 'name0' and 'name1' should be the same as in 'update_waveform' and will map to ch=0 and ch=1 # 'aux_name0' and 'aux_name1' ... should be the same as in 'update_waveform' and will map to aux_ch=0 and aux_ch=1 ... # stop current AWG base = '/%s/awgs/0/' % (self.device) self.daq.setInt(base + 'enable', 0) # get waveform wave_length = len(self.wave[name[0]]) waveform = np.zeros(wave_length * self.n_ch) for n in range(self.n_ch): waveform[n:wave_length * self.n_ch:self.n_ch] = self.wave[name[n]] # Replace the waveform with 'points'. waveform_native = zhinst.utils.convert_awg_waveform(waveform) waveform_node_path = '/%s/awgs/0/waveform/waves/0' % (self.device) self.daq.setVector(waveform_node_path, waveform_native) # if needs aux output, use aux waveform for aux channel if self.aux_out: # set aux channel for ch in range(self.aux_n_ch): self.setValue('Aux_output_select', 'AWG', ch=ch) self.setValue('Aux_demod_select', 'aux_ch%d' % (ch), ch=ch) self.setValue('Aux_output_scale', 2.0, ch=ch) self.setValue('Aux_output_offset', 0.0, ch=ch) # get aux waveform aux_wave_length = len(self.wave[name[self.n_ch]]) aux_waveform = np.zeros(aux_wave_length * self.aux_n_ch) for n in range(self.aux_n_ch): aux_waveform[n:aux_wave_length * self.aux_n_ch:self.aux_n_ch] = self.wave[name[ n + self.n_ch]] # Replace the aux waveform with 'points'. aux_waveform_native = zhinst.utils.convert_awg_waveform( aux_waveform) aux_waveform_node_path = '/%s/awgs/0/waveform/waves/1' % ( self.device) self.daq.setVector(aux_waveform_node_path, aux_waveform_native) # Start the AWG in single-shot mode. # This is the preferred method of using the AWG: Run in single mode continuous waveform playback is best achieved by # using an infinite loop (e.g., while (true)) in the sequencer program. self.daq.setInt(base + 'single', 1) self.daq.setInt(base + 'enable', 1) self.daq.sync() def performGetValue(self, quant, **kw): """Perform the Set Value instrument operation. This function should return the actual value set by the instrument""" if quant.get_cmd != '': value = self._get_node_value(quant) else: # for all others, return local value value = quant.getValue() return value def _map_wave_to_channel(self): """Create map between waveform in use and corresponding output channels""" x = [] for n in range(self.n_ch): x.append('w%d' % (n)) self.wave_to_channel = ', '.join(x) aux = [] for n in range(self.aux_n_ch): aux.append('aux_w%d' % (n)) self.aux_wave_to_channel = ', '.join(aux) def _upload_awg_program(self, awg_program, core=0): # Transfer the AWG sequence program. Compilation starts automatically. # Create an instance of the AWG Module awgModule = self.daq.awgModule() awgModule.set('awgModule/device', self.device) awgModule.set('awgModule/index', int(core)) awgModule.execute() awgModule.set('awgModule/compiler/sourcestring', awg_program) while awgModule.getInt('awgModule/compiler/status') == -1: time.sleep(0.1) if awgModule.getInt('awgModule/compiler/status') == 1: # compilation failed, raise an exception assert True, 'Upload failed:\n' + awgModule.getString( 'awgModule/compiler/statusstring') # Wait for the waveform upload to finish time.sleep(0.1) while ((awgModule.getDouble('awgModule/progress') < 1.0) and (awgModule.getInt('awgModule/elf/status') != 1)): time.sleep(0.1) if awgModule.getInt('awgModule/elf/status') == 1: assert True, 'Uploading the AWG program failed.' def _get_node_value(self, quant): """Get instrument value using ZI node hierarchy""" # get node definition node = self._get_node(quant) dtype = self._get_node_datatype(node) # read data from ZI d = self.daq.get(node, True) if len(d) == 0: assert True, 'No value defined at node %s.' % node # extract and return data data = next(iter(d.values())) # if returning dict, strip timing information (API level 6) if isinstance(data, dict) and 'value' in data: data = data['value'] value = dtype(data[0]) return value def _set_node_value(self, quant, value): """Set value of quantity using ZI node hierarchy""" # get node definition and datatype node = self._get_node(quant) dtype = self._get_node_datatype(node) self._set_parameter(node, dtype(value)) # read actual value set by the instrument value = self._get_node_value(quant) return value def _set_parameter(self, node, value): """Set value for given node""" if isinstance(value, float): # self.daq.setDouble(node, value) self.daq.asyncSetDouble(node, value) elif isinstance(value, int): # self.daq.setInt(node, value) self.daq.asyncSetInt(node, value) elif isinstance(value, str): # self.daq.setString(node, value) self.daq.asyncSetString(node, value) elif isinstance(value, complex): self.daq.setComplex(node, value) def _get_node(self, quant): """Get node string for quantity""" if '%(ch)d' in quant.get_cmd: get_cmd = quant.get_cmd % dict(ch=quant.ch) else: get_cmd = quant.get_cmd return '/' + self.device + get_cmd def _get_node_datatype(self, node): """Get datatype for object at node""" # used cached value, if available if node in self._node_datatypes: return self._node_datatypes[node] # find datatype from returned data d = self.daq.get(node, True) if len(d) == 0: assert True, 'No value defined at node %s.' % node data = next(iter(d.values())) # if returning dict, strip timing information (API level 6) if isinstance(data, dict) and 'value' in data: data = data['value'] # get first item, if python list assume string if isinstance(data, list): dtype = str # not string, should be np array, check dtype elif data.dtype in (int, np.int_, np.int64, np.int32, np.int16): dtype = int elif data.dtype in (float, np.float_, np.float64, np.float32): dtype = float elif data.dtype in (complex, np.complex_, np.complex64, np.complex128): dtype = complex else: assert True, 'Undefined datatype for node %s.' % node # keep track of datatype for future use self._node_datatypes[node] = dtype return dtype def data_acquire_set(self, length=4096, samplerate='900M', trigdelay=0, trigchannel='TrigIn1', singnalrange=1.0, signaldict={ 'signalinput1': 0, 'signalinput2': 1 }, mode='Triggered', **kw): # length should be multiple of 4096 # set Sig input self.daq.setInt('/%s/scopes/0/channel' % (self.device), 3) # '1' for only one input, '3' for two inputs for sig in signaldict: self.setValue('Sig_In_Channel', sig, ch=signaldict[sig]) self.setValue('Sig_In_Imp50', 'ON', ch=signaldict[sig]) self.setValue('Sig_In_AC', 'ON', ch=signaldict[sig]) self.setValue('Sig_In_Range', singnalrange, ch=signaldict[sig]) self.setValue('Sig_In_SampleRate', samplerate) self.setValue('Sig_In_RunMode', mode) self.setValue('Sig_In_Diffmode', 'OFF') # Disable the scope. self.daq.setInt('/%s/scopes/0/enable' % self.device, 0) # set record length self.setValue('Record_length', length) # set trigger self.setValue('Sig_In_TrigEnable', 'enable') self.setValue('Sig_In_TrigChannel', trigchannel) self.setValue('Sig_In_TrigSlope', 'Rise') self.setValue('Sig_In_TrigLevel', 0.1) self.setValue('Sig_In_TrigDelay', trigdelay) # set trighysteresis in case of noise self.daq.setDouble('/%s/scopes/0/trighysteresis/mode' % self.device, 0) self.daq.setDouble( '/%s/scopes/0/trighysteresis/relative' % self.device, 0.025) def acquire_single_record(self): # Set up the Scope Module. scopeModule = self.daq.scopeModule() scopeModule.set('mode', 1) scopeModule.subscribe('/%s/scopes/0/wave' % self.device) self.daq.setInt('/%s/scopes/0/single' % self.device, 1) scopeModule.execute() # Start the scope... self.daq.setInt('/%s/scopes/0/enable' % self.device, 1) self.daq.sync() time.sleep(0.005) # Read the scope data with timeout. local_timeout = 1.0 records = 0 while (records < 1) and (local_timeout > 0): time.sleep(0.05) local_timeout -= 0.05 records = scopeModule.getInt("records") # Disable the scope. self.daq.setInt('/%s/scopes/0/enable' % self.device, 0) data_read = scopeModule.read(True) wave_nodepath = '/{}/scopes/0/wave'.format(self.device) assert wave_nodepath in data_read, "Error: The subscribed data `{}` was returned.".format( wave_nodepath) data = data_read[wave_nodepath][0][0] # all result data is in data['wave'] # get record data as real time, it is not necessary """ f_s = 0.9e9 # sampling rate of scope and AWG for n in range(0, len(data['channelenable'])): p = data['channelenable'][n] if p: y_measured = data['wave'][n] x_measured = np.arange(-data['totalsamples'], 0)*data['dt'] + \ (data['timestamp'] - data['triggertimestamp'])/f_s """ return data['wave']
class Driver(BaseDriver): support_models = ['AWG5014C', 'AWG5208'] quants = [ QReal('Sample Rate', unit='S/s', set_cmd='SOUR:FREQ %(value)f', get_cmd='SOUR:FREQ?'), QOption('Run Mode', set_cmd='AWGC:RMOD %(option)s', get_cmd='AWGC:RMOD?', options = [ ('Continuous', 'CONT'), ('Triggered', 'TRIG'), ('Gated', 'GAT'), ('Sequence', 'SEQ')]), QOption('Clock Source', set_cmd='AWGC:CLOC:SOUR %(option)s', get_cmd='AWGC:CLOC:SOUR?', options = [('Internal', 'INT'), ('External', 'EXT')]), QOption('Reference Source', set_cmd='SOUR:ROSC:SOUR %(option)s', get_cmd='SOUR:ROSC:SOUR?', options = [('Internal', 'INT'), ('External', 'EXT')]), QReal('Vpp', unit='V', ch=1, set_cmd='SOUR%(ch)d:VOLT %(value)f', get_cmd='SOUR%(ch)d:VOLT?'), QReal('Offset', unit='V', ch=1, set_cmd='SOUR%(ch)d:VOLT:OFFS %(value)f', get_cmd='SOUR%(ch)d:VOLT:OFFS?'), QReal('Volt Low', unit='V', ch=1, set_cmd='SOUR%(ch)d:VOLT:LOW %(value)f', get_cmd='SOUR%(ch)d:VOLT:LOW?'), QReal('Volt High', unit='V', ch=1, set_cmd='SOUR%(ch)d:VOLT:HIGH %(value)f', get_cmd='SOUR%(ch)d:VOLT:HIGH?'), # output delay in time QReal('timeDelay', unit='s', ch=1, set_cmd='SOUR%(ch)d:DEL:ADJ %(value)f%(unit)s', get_cmd='SOUR%(ch)d:DEL:ADJ?'), # output delay in point QReal('pointDelay', unit='point', ch=1, set_cmd='SOUR%(ch)d:DEL:POIN %(value)d', get_cmd='SOUR%(ch)d:DEL:POIN?'), QList('WList'), QList('SList'), ] def performOpen(self): self.waveform_list = self.get_waveform_list() try: #没有sequence模块的仪器会产生一个错误 self.sequence_list = self.get_sequence_list() except: self.sequence_list = None def performSetValue(self, quant, value, **kw): if quant.name == '': return else: return BaseDriver.performSetValue(self, quant, value, **kw) def performGetValue(self, quant, **kw): if quant.name == 'WList': quant.value = self.waveform_list return self.waveform_list elif quant.name == 'SList': quant.value = self.sequence_list return self.sequence_list else: return BaseDriver.performGetValue(self, quant, **kw) def get_waveform_list(self): if self.model in ['AWG5208']: return self.query('WLIS:LIST?').strip("\"\n' ").split(',') elif self.model in ['AWG5014C']: ret = [] wlist_size = int(self.query("WLIS:SIZE?")) for i in range(wlist_size): ret.append(self.query("WLIS:NAME? %d" % i).strip("\"\n '")) return ret else: return [] def get_sequence_list(self): if self.model in ['AWG5208']: ret = [] slist_size = int(self.query("SLIS:SIZE?")) for i in range(slist_size): ret.append(self.query("SLIS:NAME? %d" % (i+1)).strip("\"\n '")) return ret else: return [] def create_waveform(self, name, length, format=None): ''' format: REAL, INT or IQ ''' if name in self.waveform_list: return if format is None: if self.model in ['AWG5208']: format = 'REAL' else: format = 'INT' self.write('WLIS:WAV:NEW "%s",%d,%s;' % (name, length, format)) self.waveform_list.append(name) def remove_waveform(self, name): if name not in self.waveform_list: return self.write(':WLIS:WAV:DEL "%s"; *CLS' % name) self.waveform_list.remove(name) def clear_waveform_list(self): wavs_to_delete = self.waveform_list.copy() for name in wavs_to_delete: self.remove_waveform(name) def use_waveform(self, name, ch=1): self.write('SOURCE%d:WAVEFORM "%s"' % (ch, name)) def run_state(self): return int(self.query('AWGC:RST?')) def run(self): self.write('AWGC:RUN') self.write('*WAI') def stop(self): self.write('AWGC:STOP') def output_on(self, ch=1): self.write('OUTP%d:STAT 1' % ch) def output_off(self, ch=1): self.write('OUTP%d:STAT 0' % ch) def get_current_waveforms(self): current_waveforms = [] current_waveform_size = 0 for i in [1,2,3,4]: wn = self.query('SOUR%d:WAV?' % i)[1:-2] current_waveforms.append(wn) if wn != '' and current_waveform_size == 0: current_waveform_size = self.query_ascii_values('WLIS:WAV:LENGTH? "%s"' % wn, 'd')[0] return current_waveform_size, current_waveforms def update_waveform(self, points, name='ABS', IQ='I', start=0, size=None): w_type = self.query('WLISt:WAVeform:TYPE? "%s"' % name).strip() if w_type == 'REAL': self._update_waveform_float(points, name, IQ, start, size) elif w_type == 'IQ': self._update_waveform_float(points[0], name, 'I', start, size) self._update_waveform_float(points[1], name, 'Q', start, size) else: self._update_waveform_int(points, name, start, size) def _update_waveform_int(self, points, name='ABS', start=0, size=None): """ points : a 1D numpy.array which values between -1 and 1. """ message = 'WLIST:WAVEFORM:DATA "%s",%d,' % (name, start) if size is not None: message = message + ('%d,' % size) points = points.clip(-1,1) values = (points * 0x1fff).astype(int) + 0x1fff self.write_binary_values(message, values, datatype=u'H', is_big_endian=False, termination=None, encoding=None) def _update_waveform_float(self, points, name='ABS', IQ='I', start=0, size=None): if self.model == 'AWG5208': message = 'WLIST:WAVEFORM:DATA:%s "%s",%d,' % (IQ, name, start) else: message = 'WLIST:WAVEFORM:DATA "%s",%d,' % (name, start) if size is not None: message = message + ('%d,' % size) values = points.clip(-1,1) self.write_binary_values(message, values, datatype=u'f', is_big_endian=False, termination=None, encoding=None) def update_marker(self, name, mk1, mk2=None, mk3=None, mk4=None, start=0, size=None): def format_marker_data(markers, bits): values = 0 for i, v in enumerate(markers): v = 0 if v is None else np.asarray(v) values += v << bits[i] return values if self.model in ['AWG5014C']: values = format_marker_data([mk1, mk2], [6, 7]) elif self.model in ['AWG5208']: values = format_marker_data([mk1, mk2, mk3, mk4], [7,6,5,4]) if size is None: message = 'WLIST:WAVEFORM:MARKER:DATA "%s",%d,' % (name, start) else: message = 'WLIST:WAVEFORM:MARKER:DATA "%s",%d,%d,' % (name, start, size) self.write_binary_values(message, values, datatype=u'B', is_big_endian=False, termination=None, encoding=None) def create_sequence(self, name, steps, tracks): if name in self.sequence_list: return self.write('SLIS:SEQ:NEW "%s", %d, %d' % (name, steps, tracks)) self.sequence_list.append(name) def remove_sequence(self, name): if name not in self.sequence_list: return self.write('SLIS:SEQ:DEL "%s"' % name) self.sequence_list.remove(name) def clear_sequence_list(self): self.write('SLIS:SEQ:DEL ALL') self.sequence_list.clear() def set_sequence_step(self, name, sub_name, step, wait='OFF', goto='NEXT', repeat=1, jump=None): """set a step of sequence name: sequence name sub_name: subsequence name or list of waveforms for every tracks wait: ATRigger | BTRigger | ITRigger | OFF goto: <NR1> | LAST | FIRSt | NEXT | END repeat: ONCE | INFinite | <NR1> jump: a tuple (jump_input, jump_to) jump_input: ATRigger | BTRigger | OFF | ITRigger jump_to: <NR1> | NEXT | FIRSt | LAST | END """ if isinstance(sub_name, str): self.write('SLIS:SEQ:STEP%d:TASS:SEQ "%s","%s"' % (step, name, sub_name)) else: for i, wav in enumerate(sub_name): self.write('SLIS:SEQ:STEP%d:TASS%d:WAV "%s","%s"' % (step, i+1, name, wav)) self.write('SLIS:SEQ:STEP%d:WINP "%s", %s' % (step, name, wait)) self.write('SLIS:SEQ:STEP%d:GOTO "%s", %s' % (step, name, goto)) self.write('SLIS:SEQ:STEP%d:RCO "%s", %s' % (step, name, repeat)) if jump is not None: self.write('SLIS:SEQ:STEP%d:EJIN "%s", %s' % (step, name, jump[0])) self.write('SLIS:SEQ:STEP%d:EJUM "%s", %s' % (step, name, jump[1])) def use_sequence(self, name, channels=[1,2]): for i, ch in enumerate(channels): self.write('SOUR%d:CASS:SEQ "%s", %d' % (ch, name, i+1))
class Driver(BaseDriver): support_models = ['wx2184'] quants = [ QReal('Sample Rate', unit='S/s', set_cmd=':FREQ:RAST %(value)g', get_cmd=':FREQ:RAST?'), QReal('Amp', unit='V', set_cmd=':VOLT:LEV:AMPL %(value)f', get_cmd=':VOLT:LEV:AMPL?'), QReal('Offset', unit='V', set_cmd=':VOLT:LEV:OFFS %(value)f', get_cmd=':VOLT:LEV:OFFS?'), QReal('Frequency', unit='Hz', set_cmd=':FREQ %(value)f', get_cmd=':FREQ?'), QReal('Phase', unit='Deg', set_cmd=':SIN:PHAS %(value)f', get_cmd=':SIN:PHAS?'), QOption('Output', set_cmd=':OUTP %(option)s', get_cmd=':OUTP?', options=[('OFF', 'OFF'), ('ON', 'ON')]), QInteger( 'Select_ch', value=1, unit='', set_cmd=':INST:SEL %(value)d', get_cmd=':INST:SEL?', ), #options=[('1', '1'), ('2', '2'), ('3', '3'), ('4', '4')] QInteger('Select_trac', value=1, unit='', set_cmd=':TRAC:SEL %(value)d', get_cmd=':TRAC:SEL?'), ] def dc(self, ch=1, offs=1.0): self.write(':INST:SEL CH%d' % ch) self.write(':FUNC:MODE FIX') self.write(':FUNC:SHAP DC') self.write(':DC %f' % offs) self.write(':OUTP ON') def sin(self, ch=1, freq=2e8, amp=0.5, offs=0.0, phas=0): self.write(':INST:SEL CH%d' % ch) self.write(':FUNC:MODE FIX') self.write(':FUNC:SHAP SIN') self.write(':FREQ %f' % freq) self.write(':VOLT:LEV:AMPL %f' % amp) self.write(':VOLT:LEV:OFFS %f' % offs) self.write(':SIN:PHAS %f' % phas) self.write(':OUTP ON') def reset(self, samplerate=2.3e9): self.write('*CLS') self.write('*RST') #选择特定function self.write(':FUNC:MODE USER') #设置采样率 self.write(':FREQ:RAST %d' % samplerate) #设置外部时钟 self.write(':ROSCillator:SOURce EXTernal') #清除原有波形 self.write(':INST:SEL CH1') self.write(':TRAC:DEL:ALL') self.write(':INST:SEL CH3') self.write(':TRAC:DEL:ALL') #将几个通道的设置设为同一个,详见manual # self.write(':INST:COUPle:STATe ON') # self.write(':INIT:CONT OFF') # self.write(':TRIG:COUN 1') # self.write('enable') #创建波形文件 def crwave(self, segment_num, sample_num): self.write(':TRAC:DEF %d,%d' % (segment_num, sample_num)) #在创建好的波形文件中,写入或者更新具体波形 def upwave(self, points, ch=1, trac=1): pointslen = len(points) pointslen2 = 2 * pointslen #选择特定function self.write(':FUNC:MODE USER') #选择特定channel self.write(':INST:SEL %d' % ch) #定义特定的segment self.write(':TRAC:DEF %d,%d' % (trac, pointslen)) #选择特定的segment self.write(':TRAC:SEL %d' % trac) #选择模式为SINGLE,(包括DUPLicate,SINGle等,详见manual) self.write(':TRAC:MODE SING') #写入波形数据 message = ':TRAC:DATA' # % (len(str(pointslen2)),pointslen2) points = points.clip(-1, 1) values = np.zeros(pointslen).astype(np.uint16) #乘积选用8191是为了防止最终值大于16383 values = (points * 8191).astype(np.uint16) + 8192 #.astype(np.uint16) byte = np.zeros(pointslen2).astype(np.uint8) #将原先的两比特数据点,分割为高低两个比特 byte[0:pointslen2:2] = (values & 0b11111111).astype(np.uint8) byte[1:pointslen2:2] = ((values & 0b11111100000000) >> 8).astype( np.uint8) #write_binary_value中的message参数不要包括#42048的信息,因为pyvisa可以自动算出结果。详见pyvisa中util.py内的to_binary_block #wx2184选用little_endian。这表示程序按照我给的顺序将二进制包写进去 self.write_binary_values(message, byte, datatype='B', is_big_endian=False, termination=None, encoding=None) # self.write('enable' ) #运行波形 def ruwave(self, amp=2, offset=0, ch=1, trac=1, trigdelay=0): self.write(':INST:SEL %d' % ch) self.write(':VOLT:LEV:AMPL %f' % amp) self.write(':VOLT:LEV:OFFS %f' % offset) self.write(':TRAC:SEL %d' % trac) self.write(':OUTP ON') self.write(':INIT:CONT OFF') self.write(':TRIG:COUN 1') self.write(':TRIG:DEL %d' % trigdelay) def ruwave1(self, amp=2, offset=0, ch=1, trac=1): self.write(':INST:SEL %d' % ch) self.write(':VOLT:LEV:AMPL %f' % amp) self.write(':VOLT:LEV:OFFS %f' % offset) self.write(':TRAC:SEL %d' % trac) self.write(':OUTP ON') self.write(':INIT:CONT ON') def ruwave2(self, amp=2, ch=1, trac=1): self.write(':INST:SEL %d' % ch) self.write(':VOLT:LEV:AMPL %f' % amp) self.write(':TRAC:SEL %d' % trac) self.write(':OUTP ON') self.write(':INIT:CONT OFF') self.write(':TRIG:COUN 1')
class Driver(BaseDriver): error_command = '' support_models = ['SR620'] quants = [ QVector('Data', unit=''), QReal('Ext Level', unit='V', set_cmd='LEVL 0,%(value)f', get_cmd='LEVL? 0'), QReal('A Level', unit='V', set_cmd='LEVL 1,%(value)f', get_cmd='LEVL? 1'), QReal('B Level', unit='V', set_cmd='LEVL 2,%(value)f', get_cmd='LEVL? 2'), QOption('Ext Term', set_cmd='TERM 0,%(option)s', get_cmd='TERM? 0', options=[('50 Ohm', '0'), ('1 MOhm', '1')]), QOption('A Term', set_cmd='TERM 1,%(option)s', get_cmd='TERM? 1', options=[('50 Ohm', '0'), ('1 MOhm', '1')]), QOption('B Term', set_cmd='TERM 2,%(option)s', get_cmd='TERM? 2', options=[('50 Ohm', '0'), ('1 MOhm', '1')]), QOption('Ext Slope', set_cmd='TSLP 0,%(option)s', get_cmd='TSLP? 0', options=[('Positive', '0'), ('Negative', '1')]), QOption('A Slope', set_cmd='TSLP 1,%(option)s', get_cmd='TSLP? 1', options=[('Positive', '0'), ('Negative', '1')]), QOption('B Slope', set_cmd='TSLP 2,%(option)s', get_cmd='TSLP? 2', options=[('Positive', '0'), ('Negative', '1')]), QOption('A Coupling', set_cmd='TCPL 1,%(option)s', get_cmd='TCPL? 1', options=[('DC', '0'), ('AC', '1')]), QOption('B Coupling', set_cmd='TCPL 2,%(option)s', get_cmd='TCPL? 2', options=[('DC', '0'), ('AC', '1')]), QOption('Mode', set_cmd='MODE %(option)s', get_cmd='MODE?', options = [ ('time', '0'), ('width', '1'), ('tr/tf', '2'), ('freq', '3'), ('period', '4'), ('phase', '5'), ('count', '6'), ]), QOption('Arming Mode', set_cmd='ARMM %s', get_cmd='ARMM?', options = [ ('+- time', '0'), ('+ time', '1'), ('1 period', '2'), ('0.01 s gate', '3'), ('0.1 s gate', '4'), ('1.0 s gate', '5'), ('ext trig +- time', '6'), ('ext trig + time', '7'), ('ext gate/trig holdoff', '8'), ('ext 1 period', '9'), ('ext 0.01 s gate', '10'), ('ext 0.1 s gate', '11'), ('ext 1.0 s gate', '12'), ]), ] def performGetValue(self, quant, **kw): if quant.name == 'Data': if 'count' in kw.keys(): count = kw['count'] else: count = 100 return self.get_Data(count) else: return BaseDriver.performGetValue(self, quant, **kw) def get_Data(self, count=100): block = b'' max = 5000 loop = int(count/max) last = count % max self.write('*CLS') try: if last < count: for i in range(loop): self.write('BDMP %d' % max) block += self.__read(8*max) self.write('BDMP %d' % last) block += self.__read(8*last) except: raise mode = int(self.query('MODE?')) expd = int(self.query('EXPD?')) self.write('AUTM 1') factors=[1.05963812934E-14, 1.05963812934E-14, 1.05963812934E-14, 1.24900090270331E-9, 1.05963812934E-14, 8.3819032E-8, 0.00390625] ret = np.array(list(struct.unpack('<%dq' % count, block))) * factors[mode] if expd != 0: ret = ret*1e-3 return ret def __read(self, size): try: buff = self.ins.visalib.read(self.ins.session, size)[0] except VisaIOWarning: pass return buff
class Driver(BaseDriver): support_models = ['IT6302'] quants = [ QReal( 'CH1 Voltage', unit='V', #set_cmd='SYST:REM;INST CH1;VOLT %(value).13e' set_cmd='INST CH1;VOLT %(value).13e', get_cmd='MEAS? CH1'), QReal( 'CH1 Current', unit='A', #set_cmd='SYST:REM;INST CH1;CURR %(value).13e' set_cmd='INST CH1;CURR %(value).13e', get_cmd='MEAS:CURR? CH1'), QReal( 'CH2 Voltage', unit='V', #set_cmd='SYST:REM;INST CH2;VOLT %(value).13e' set_cmd='INST CH2;VOLT %(value).13e', get_cmd='MEAS? CH2'), QReal( 'CH2 Current', unit='A', #set_cmd='SYST:REM;INST CH2;CURR %(value).13e' set_cmd='INST CH2;CURR %(value).13e', get_cmd='MEAS:CURR? CH2'), QReal( 'CH3 Voltage', unit='V', #set_cmd='SYST:REM;INST CH3;VOLT %(value).13e' set_cmd='INST CH3;VOLT %(value).13e', get_cmd='MEAS? CH3'), QReal( 'CH3 Current', unit='A', #set_cmd='SYST:REM;INST CH3;CURR %(value).13e' set_cmd='INST CH3;CURR %(value).13e', get_cmd='MEAS:CURR? CH3'), QReal( 'Voltage', unit='V', #set_cmd='SYST:REM;INST CH3;VOLT %(value).13e' set_cmd='INST CH%(ch)d;VOLT %(value).13e', get_cmd='MEAS? CH%(ch)d'), QReal( 'Current', unit='A', #set_cmd='SYST:REM;INST CH3;CURR %(value).13e' set_cmd='INST CH%(ch)d;CURR %(value).13e', get_cmd='MEAS:CURR? CH%(ch)d'), QReal('Voltage Limit', unit='V', set_cmd='INST CH%(ch)d;VOLT %(value).13e', get_cmd='INST CH%(ch)d;VOLT?'), QReal('Current Limit', unit='A', set_cmd='INST CH%(ch)d;CURR %(value).13e', get_cmd='INST CH%(ch)d;CURR?'), QOption('Output', set_cmd='OUTP %(option)s', get_cmd='OUTP:STAT?', options=[('OFF', '0'), ('ON', '1')]), QOption('Combine', set_cmd='INST:COM:%(option)s', get_cmd='INST:COM?', options=[('Parallel', 'Parallel'), ('Series', 'Series'), ('OFF', 'OFF')]), ] def performOpen(self): self.write('SYST:REM') def performClose(self): self.write('SYST:LOC')