class Measurement(MeasurementBase): params = { 'Vgs': Sweep([0.]), 'Vchucks': Sweep([0.]), 'Rg': 100e3, 'stabilise_time': 5., 'stab_chuck_time': 5., 'comment': String(''), 'data_dir': Folder(r'D:\MeasurementJANIS\Holger\test'), 'use_vna': Boolean( True ), # when switched off, this script is basically just a leak test 'init_bilt': Boolean( False ), # when switched on, the Bilt sources will be initialised, this might be dangerous for the sample } observables = ['Vg', 'Vchuck', 'Vgm', 'Ileak'] alarms = [['np.abs(Ileak) > 1e-8', MeasurementBase.ALARM_CALLCOPS]] def measure(self, data_dir, Vgs, Vchucks, Rg, comment, stabilise_time, stab_chuck_time, use_vna, init_bilt, **kwargs): print("===================================") print("Starting acquisition script...") chuck_string = '' vna_string = '' # initialise instruments print("Setting up DC sources and voltmeters...") bilt = Bilt('TCPIP0::192.168.0.2::5025::SOCKET') if init_bilt: # source (bilt, channel, range, filter, slope in V/ms, label): self.sourceVg = sourceVg = BiltVoltageSource( bilt, "I1", "12", "1", 0.005, "Vg") else: self.sourceVg = sourceVg = BiltVoltageSource(bilt, "I1", initialise=False) # voltmeter (bilt, channel, filt, label=None) self.meterVg = meterVg = BiltVoltMeter(bilt, "I5;C1", "2", "Vgm") print("DC sources and voltmeters are set up.") print("Setting up Yokogawa for chuck voltage...") # connect to the Yoko without initialising, this will lead to # an exception if the Yoko is not properly configured (voltage # source, range 30V, output ON) self.yoko = yoko = Yoko7651('GPIB::3::INSTR', initialise=False, rang=30, slope=1.) print("Yokogawa is set up.") if use_vna: print("Setting up VNA...") vna = AnritsuVNA('GPIB::6::INSTR') sweeptime = vna.get_sweep_time() if vna.get_sweep_type() != 'FSEGM': raise Exception('Please use segmented frequency sweep') # check if the RF power is the same on both ports and for all # frequency segments count = int(vna.query(':SENS:FSEGM:COUN?')) vna_pow = None for i in range(1, count + 1): port1pow = float( vna.query(':SENS:FSEGM{}:POW:PORT1?'.format(i))) port2pow = float( vna.query(':SENS:FSEGM{}:POW:PORT2?'.format(i))) if vna_pow is None and port1pow == port2pow: vna_pow = port1pow elif vna_pow is not None and port1pow == port2pow and port1pow == vna_pow: continue else: raise Exception( "Please select the same power for all ports and frequency segments" ) port1att = vna.get_source_att(1) port2att = vna.get_source_att(2) if port1att == port2att: vna_pow -= port1att else: raise Exception( "Please select the same attenuators for both ports") vna_string = '_pwr={:.0f}'.format(vna_pow) print("VNA is set up.") # prepare saving DC data timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') filename = timestamp + vna_string + ('_' + comment if comment else '') self.prepare_saving(os.path.join(data_dir, filename + '.txt')) if use_vna: # prepare saving RF data spectra_fol = os.path.join(data_dir, filename) create_path(spectra_fol) # save segmented frequency sweep data to file with open(os.path.join(spectra_fol, 'VNAconfig'), 'w') as f: vna.dump_freq_segments(f) for Vchuck in Vchucks: print("Setting Vchuck = {}".format(Vchuck)) # set Vchuck yoko.set_voltage(Vchuck) # wait time.sleep(stab_chuck_time) for Vg in Vgs: if self.flags['quit_requested']: print("Stopping acquisition.") return locals() print("Setting Vg = {}".format(Vg)) # set Vg sourceVg.set_voltage(Vg) # wait time.sleep(stabilise_time) # read voltages Vgm = meterVg.get_voltage() # do calculations Ileak = (Vg - Vgm) / Rg # save DC data self.save_row(locals()) if use_vna: # save VNA data print("Getting VNA spectra...") vna.single_sweep(wait=False) # display sweep progress progressbar_wait(sweeptime) # make sure sweep is really done while not vna.is_sweep_done(): time.sleep(0.5) table = vna.get_table([1, 2, 3, 4]) timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') spectrum_file = timestamp + '_Vg={:.3f}_Vchuck={:.1f}.txt'.format( Vg, Vchuck) np.savetxt(os.path.join(spectra_fol, spectrum_file), np.transpose(table)) print("Acquisition done.") return locals() def tidy_up(self): self.end_saving() print("Driving all voltages back to zero...") self.sourceVg.set_voltage(0.) self.yoko.set_voltage(0.)
class Measurement(MeasurementBase): params = { 'Vgs': Sweep([0.]), 'stabilise_time': 0.3, 'init': Boolean(True), 'use_vna': Boolean(True), 'comment': String(''), 'data_dir': Folder(r'D:\MeasurementJANIS\Holger\test') } observables = ['Vg', 'Ileak'] alarms = [ ['np.abs(Ileak) > 1e-8', MeasurementBase.ALARM_CALLCOPS] # is applied between the two gates ] def measure(self, Vgs, stabilise_time, init, use_vna, data_dir, comment, **kwargs): print("===================================") print("Starting acquisition script...") vna_string = '' # initialise instruments try: print("----------------------------------------") print("Setting up Keithley DC sources...") self.sourceVg = sourceVg = K2400('GPIB::24::INSTR', sourcemode='v', vrang=200, irang=10e-6, slope=1, initialise=init) print("DC sources are set up.") except: print("There has been an error setting up DC sources.") raise if use_vna: print("Setting up VNA...") vna = AnritsuVNA('GPIB::6::INSTR') sweeptime = vna.get_sweep_time() if vna.get_sweep_type() != 'FSEGM': raise Exception('Please use segmented frequency sweep') # check if the RF power is the same on both ports and for all # frequency segments count = int(vna.query(':SENS:FSEGM:COUN?')) vna_pow = None for i in range(1,count+1): port1pow = float(vna.query(':SENS:FSEGM{}:POW:PORT1?'.format(i))) port2pow = float(vna.query(':SENS:FSEGM{}:POW:PORT2?'.format(i))) if vna_pow is None and port1pow == port2pow: vna_pow = port1pow elif vna_pow is not None and port1pow == port2pow and port1pow == vna_pow: continue else: raise Exception("Please select the same power for all ports and frequency segments") port1att = vna.get_source_att(1) port2att = vna.get_source_att(2) if port1att == port2att: vna_pow -= port1att else: raise Exception("Please select the same attenuators for both ports") vna_string = '_pwr={:.0f}'.format(vna_pow) print("VNA is set up.") # define name timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') filename = timestamp + vna_string + ('_'+comment if comment else '') # prepare saving RF data spectra_fol = os.path.join(data_dir, filename) create_path(spectra_fol) # prepare saving DC data self.prepare_saving(os.path.join(data_dir, filename + '.txt')) if use_vna: # prepare saving RF data spectra_fol = os.path.join(data_dir, filename) create_path(spectra_fol) # save segmented frequency sweep data to file with open(os.path.join(spectra_fol, 'VNAconfig'), 'w') as f: vna.dump_freq_segments(f) # loop for Vg in Vgs: if self.flags['quit_requested']: return locals() print('Setting Vg='+str(Vg)+' V...') sourceVg.set_voltage(Vg) time.sleep(stabilise_time) # measure Vgm = sourceVg.get_voltage() Ileak = sourceVg.get_current() # save data self.save_row(locals()) # save VNA data if use_vna: # save VNA data print("Getting VNA spectra...") vna.single_sweep(wait=False) # display sweep progress progressbar_wait(sweeptime) # make sure sweep is really done while not vna.is_sweep_done(): time.sleep(0.5) table = vna.get_table([1,2,3,4]) timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') spectrum_file = timestamp+'_Vg={:.3f}.txt'.format(Vg) np.savetxt(os.path.join(spectra_fol, spectrum_file), np.transpose(table)) print("Acquisition done.") return locals() def tidy_up(self): self.end_saving() print("Driving all voltages back to zero...") self.sourceVg.set_voltage(0.)
class Measurement(MeasurementBase): params = { 'Vgs': Sweep([0.]), 'Rg': 100e3, 'stabilise_time': 0.3, 'comment': String(''), 'data_dir': Folder(r'D:\MeasurementJANIS\Holger\test'), 'use_vna': Boolean(True), 'use_chuck': Boolean( True ), # we are not controlling the chuck here, just recording the value of the chuck voltage 'init_bilt': Boolean(False) } observables = ['Vg', 'Vgm', 'Ileak'] alarms = [['np.abs(Ileak) > 1e-8', MeasurementBase.ALARM_CALLCOPS]] def measure(self, data_dir, Vgs, Rg, comment, stabilise_time, use_vna, use_chuck, init_bilt, **kwargs): print("===================================") print("Starting acquisition script...") chuck_string = '' vna_string = '' # initialise instruments print("Setting up DC sources and voltmeters...") bilt = Bilt('TCPIP0::192.168.0.2::5025::SOCKET') if init_bilt: # source (bilt, channel, range, filter, slope in V/ms, label): self.sourceVg = sourceVg = BiltVoltageSource( bilt, "I1", "12", "1", 0.005, "Vg") else: self.sourceVg = sourceVg = BiltVoltageSource(bilt, "I1", initialise=False) # voltmeter (bilt, channel, filt, label=None) self.meterVg = meterVg = BiltVoltMeter(bilt, "I5;C1", "2", "Vgm") print("DC sources and voltmeters are set up.") if use_chuck: print("Setting up Yokogawa for chuck voltage...") # connect to the Yoko without initialising, this will lead to # an exception if the Yoko is not properly configured (voltage # source, range 30V, output ON) yoko = Yoko7651('GPIB::3::INSTR', initialise=False, rang=30) chuck_string = '_Vchuck={:.1f}'.format(yoko.get_voltage()) print("Yokogawa is set up.") if use_vna: print("Setting up VNA") self.vna = vna = RohdeSchwarzVNA() vna.open('GPIB', '20') c1 = vna.channel(1) sweeptime = c1.total_sweep_time_ms c1.manual_sweep = True c1.s_parameter_group = c1.to_logical_ports((1, 2)) # cf: https://www.rohde-schwarz.com/webhelp/webhelp_zva/program_examples/basic_tasks/typical_stages_of_a_remote_control_program.htm#Command_Synchronization vna.write("*SRE 32") vna.write("*ESE 1") if not c1.sweep_type == 'SEGM': # need to use not == because != is not implemented in Rohde Schwarz library raise Exception('Please use segmented frequency sweep') # check if the RF power is the same on both ports and for all # frequency segments count = int(vna.query(':SENS:SEGM:COUN?').strip()) vna_pow = None for i in range(1, count + 1): seg_pow = float(vna.query(':SENS:SEGM{}:POW?'.format(i))) if vna_pow is None: vna_pow = seg_pow elif vna_pow is not None and seg_pow == vna_pow: continue else: raise Exception( "Please select the same power for all ports and frequency segments" ) port1autoatt = int(vna.query(':SOUR:POW1:ATT:AUTO?').strip()) port2autoatt = int(vna.query(':SOUR:POW2:ATT:AUTO?').strip()) if port1autoatt or port2autoatt: raise Exception("Please do not use automatic attenuators") port1att = float(vna.query(':SOUR:POW1:ATT?').strip()) port2att = float(vna.query(':SOUR:POW2:ATT?').strip()) if port1att == port2att: vna_pow -= port1att else: raise Exception( "Please select the same attenuators for both ports") vna_string = '_pwr={:.0f}'.format(vna_pow) print("VNA is set up.") # prepare saving DC data timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') filename = timestamp + vna_string + chuck_string + ('_' + comment if comment else '') self.prepare_saving(os.path.join(data_dir, filename + '.txt')) if use_vna: # prepare saving RF data spectra_fol = os.path.join(data_dir, filename) create_path(spectra_fol) with open(os.path.join(spectra_fol, 'VNAconfig'), 'w') as f: f.write( '# Frequency based segmented sweep setup of Rohde&Schwarz ZVA 67\n' ) f.write('# Attenuator Port 1: {}\n'.format(port1att)) f.write('# Attenuator Port 2: {}\n'.format(port2att)) f.write('# Seg no.\tfstart\tfstop\tpoints\tbwidth\tpow\n') count = int(vna.query(':SENS:SEGM:COUN?').strip()) for i in range(1, count + 1): seg_pow = float( vna.query(':SENS:SEGM{}:POW?'.format(i)).strip()) bwidth = float( vna.query(':SENS:SEGM{}:BWID?'.format(i)).strip()) fstart = float( vna.query(':SENS:SEGM{}:FREQ:STAR?'.format(i)).strip()) fstop = float( vna.query(':SENS:SEGM{}:FREQ:STOP?'.format(i)).strip()) points = int( vna.query(':SENS:SEGM{}:SWE:POIN?'.format(i)).strip()) f.write('{:d}\t{:f}\t{:f}\t{:d}\t{:f}\t{:f}\n'.format( i, fstart, fstop, points, bwidth, seg_pow)) for Vg in Vgs: if self.flags['quit_requested']: print("Stopping acquisition.") return locals() print("Setting Vg = {}".format(Vg)) # set Vg sourceVg.set_voltage(Vg) # wait time.sleep(stabilise_time) # read voltages Vgm = meterVg.get_voltage() # do calculations Ileak = (Vg - Vgm) / Rg # save DC data self.save_row(locals()) if use_vna: # save VNA data print("Getting VNA spectra...") vna.write("INIT1:IMM; *OPC") # display sweep progress progressbar_wait(sweeptime / 1e3) # make sure sweep is really done while not int(vna.query("*ESR?").strip()): time.sleep(0.5) timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') spectrum_file = timestamp + '_Vg=%2.4f' % (Vg) #vna.channel(1).save_measurement_locally(os.path.join(spectra_fol, spectrum_file), (1,2)) spectrum_file = os.path.join(spectra_fol, spectrum_file + '.s2p') unique_filename = unique_alphanumeric_string() + '.s2p' scpi = ":MMEM:STOR:TRAC:PORT {0},'{1}',{2},{3}" scpi = scpi.format(1, \ unique_filename, \ 'COMP', \ '1,2') vna.write(scpi) # this saves the file on the ZVA in the folder # C:\Rohde&Schwarz\Nwa\ vna.pause(5000) vna.file.download_file(unique_filename, spectrum_file) vna.file.delete(unique_filename) print("Acquisition done.") return locals() def tidy_up(self): self.vna.close() self.end_saving() print("Driving all voltages back to zero...") self.sourceVg.set_voltage(0.)
class Measurement(MeasurementBase): params = { 'Vg1s': Sweep([0.0]), 'Vg2s': Sweep([0.0]), 'commongate': Boolean(False), 'Rg1': 100e3, 'Rg2': 100e3, 'Rds': 2.2e3, 'stabilise_time': 0.5, 'comment': String(''), 'data_dir': Folder(r'D:\meso\Desktop\testdata') } observables = [ 'Vg1', 'Vg1m', 'Ileak1', 'Vg2', 'Vg2m', 'Ileak2', 'Vds', 'Vdsm', 'Vdsm_std', 'Rs' ] alarms = [ ['np.abs(Ileak1) > 1e-8', MeasurementBase.ALARM_CALLCOPS], ['np.abs(Ileak2) > 1e-8', MeasurementBase.ALARM_CALLCOPS], ['np.abs(Vg1-Vg2)', MeasurementBase.ALARM_SHOWVALUE ] # useful if we just want to know how much voltage # is applied between the two gates ] def measure(self, data_dir, Vg1s, Vg2s, commongate, Rg1, Rg2, Rds, stabilise_time, **kwargs): print("===================================") print("Starting acquisition script...") # initialise instruments try: print("Setting up DC sources and voltmeters...") bilt = Bilt('TCPIP0::192.168.0.2::5025::SOCKET') self.sourceVg1 = sourceVg1 = BiltVoltageSource( bilt, "I2", "12", "1", 0.01, "Vg1") self.sourceVg2 = sourceVg2 = BiltVoltageSource( bilt, "I3", "12", "1", 0.01, "Vg2") self.meterVg1 = meterVg1 = BiltVoltMeter(bilt, "I5;C2", "2", "Vg1m") self.meterVg2 = meterVg2 = BiltVoltMeter(bilt, "I5;C3", "2", "Vg2m") print("DC sources and voltmeters are set up.") except: print( "There has been an error setting up DC sources and voltmeters." ) raise try: print("Setting up lock-in amplifier") self.lockin = lockin = ZILockin() print("Lock in amplifier is set up.") except: print("There has been an error setting up the lock-in amplifier.") raise timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') # save lock in settings (in case we need to check something later) lockin.save_settings( os.path.join(data_dir, 'ZIsettings', timestamp + '.ZIsettings.txt')) # prepare saving data filename = timestamp + '.txt' self.prepare_saving(os.path.join(data_dir, filename)) # loops Vds = lockin.rms_amp for Vg2 in Vg2s: sourceVg2.set_voltage(Vg2) for Vg1 in Vg1s: if self.flags['quit_requested']: return locals() sourceVg1.set_voltage(Vg1) # stabilise time.sleep(stabilise_time) # measure Vg1m = meterVg1.get_voltage() Vg2m = meterVg2.get_voltage() Vdsm, Vdsm_std = lockin.poll_data() # do calculations Ileak1 = (Vg1 - Vg1m) / Rg1 Ileak2 = (Vg2 - Vg2m) / Rg2 Rs = Rds * Vdsm / (Vds - Vdsm) # save data self.save_row(locals()) print("Acquisition done.") return locals() def tidy_up(self): self.end_saving() print("Driving all voltages back to zero...") self.sourceVg1.set_voltage(0.) self.sourceVg2.set_voltage(0.) self.lockin.tidy_up()
class Measurement(MeasurementBase): params = { 'Vgs': Sweep([0.]), 'Rg': 100e3, 'stabilise_time': 0.3, 'comment': String(''), 'data_dir': Folder(r'D:\MeasurementJANIS\Holger\test'), 'use_vna': Boolean(True), 'use_chuck': Boolean( True ), # we are not controlling the chuck here, just recording the value of the chuck voltage 'init_bilt': Boolean(False) } observables = ['Vg', 'Vgm', 'Ileak'] alarms = [['np.abs(Ileak) > 1e-8', MeasurementBase.ALARM_CALLCOPS]] def measure(self, data_dir, Vgs, Rg, comment, stabilise_time, use_vna, use_chuck, init_bilt, **kwargs): print("===================================") print("Starting acquisition script...") chuck_string = '' vna_string = '' # initialise instruments print("Setting up DC sources and voltmeters...") bilt = Bilt('TCPIP0::192.168.0.5::5025::SOCKET') if init_bilt: # source (bilt, channel, range, filter, slope in V/ms, label): self.sourceVg = sourceVg = BiltVoltageSource( bilt, "I3;C1", "12", "1", 0.005, "Vg") else: self.sourceVg = sourceVg = BiltVoltageSource(bilt, "I3;C1", initialise=False) # voltmeter (bilt, channel, filt, label=None) self.meterVg = meterVg = BiltVoltMeter(bilt, "I1;C1", "2", "Vgm") print("DC sources and voltmeters are set up.") if use_chuck: print("Setting up Yokogawa for chuck voltage...") # connect to the Yoko without initialising, this will lead to # an exception if the Yoko is not properly configured (voltage # source, range 30V, output ON) yoko = Yoko7651('GPIB::10::INSTR', initialise=False, rang=30) chuck_string = '_Vchuck={:.1f}'.format(yoko.get_voltage()) print("Yokogawa is set up.") if use_vna: print("Setting up VNA") self.vna = vna = RohdeSchwarzVNA() vna.open('TCPIP', '192.168.0.3') c1 = vna.channel(1) sweeptime = c1.total_sweep_time_ms c1.init_nonblocking_sweep((1, 2)) if not c1.is_corrected(): raise Exception('Please calibrate or switch on correction.') if c1.sweep_type != 'SEGM': raise Exception('Please use segmented frequency sweep') # check if the RF power is the same on both ports and for all # frequency segments vna_pow = np.unique(np.asarray(c1.get_frequency_segments())[:, 5]) if len(vna_pow) > 1: raise Exception( "Please select the same power for all ports and frequency segments" ) vna_pow = vna_pow[0] if c1.is_auto_attenuator(1) or c1.is_auto_attenuator(2): raise Exception("Please do not use automatic attenuators") port1att = c1.get_attenuator(1) if port1att == c1.get_attenuator(2): vna_pow -= port1att else: raise Exception( "Please select the same attenuators for both ports") vna_string = '_pwr={:.0f}'.format(vna_pow) print("VNA is set up.") # prepare saving DC data timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') filename = timestamp + vna_string + chuck_string + ('_' + comment if comment else '') self.prepare_saving(os.path.join(data_dir, filename + '.txt')) if use_vna: # prepare saving RF data spectra_fol = os.path.join(data_dir, filename) create_path(spectra_fol) c1.save_frequency_segments(os.path.join(spectra_fol, 'VNAconfig')) for Vg in Vgs: if self.flags['quit_requested']: print("Stopping acquisition.") return locals() print("Setting Vg = {}".format(Vg)) # set Vg sourceVg.set_voltage(Vg) # wait time.sleep(stabilise_time) # read voltages Vgm = meterVg.get_voltage() # do calculations Ileak = (Vg - Vgm) / Rg # save DC data self.save_row(locals()) if use_vna: # save VNA data print("Getting VNA spectra...") c1.start_nonblocking_sweep() # display sweep progress progressbar_wait(sweeptime / 1e3) # make sure sweep is really done while not c1.isdone_nonblocking_sweep(): time.sleep(0.5) timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') spectrum_file = timestamp + '_Vg=%2.4f' % (Vg) spectrum_file = os.path.join(spectra_fol, spectrum_file + '.s2p') c1.save_nonblocking_sweep(spectrum_file, (1, 2)) print("Acquisition done.") return locals() def tidy_up(self): self.vna.close() self.end_saving() print("Driving all voltages back to zero...") self.sourceVg.set_voltage(0.)
class Measurement(MeasurementBase): params = { 'Vds': 10e-3, 'Vgs': Sweep([0.]), 'Rg': 100e3, 'stabilise_time': 0.05, 'init': Boolean(True), 'comment': String(''), 'data_dir': Folder('D:\Manip13\Desktop\Holger') } observables = ['Vg', 'Vgm', 'Ileak', 'Vds', 'Vdsm', 'Ids', 'Rds'] alarms = [['np.abs(Ileak) > 1e-8', MeasurementBase.ALARM_CALLCOPS ] # is applied between the two gates ] def measure(self, Vds, Vgs, Rg, stabilise_time, init, data_dir, comment, **kwargs): print("===================================") print("Starting acquisition script...") # initialise instruments try: print("Setting up DC sources...") self.sourceVg = sourceVg = K2400('GPIB::24::INSTR', sourcemode='v', vrang=200, irang=10e-6, slope=1, initialise=init) self.sourceVds = sourceVds = K2600('GPIB::26::INSTR', slope=0.005, initialise=init) print("DC sources and voltmeters are set up.") except: print( "There has been an error setting up DC sources and voltmeters." ) raise timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') # prepare saving data filename = timestamp + '_' + (comment if comment else '') + '.txt' self.prepare_saving(os.path.join(data_dir, filename)) # loop sourceVds.set_voltage(Vds) for Vg in Vgs: if self.flags['quit_requested']: return locals() print('Setting Vg=' + str(Vg) + ' V...') sourceVg.set_voltage(Vg) time.sleep(stabilise_time) # measure Vgm = sourceVg.get_voltage() Ileak = sourceVg.get_current() Vdsm = sourceVds.get_voltage() Ids = sourceVds.get_current() # do calculations Rds = Vds / Ids # save data self.save_row(locals()) print("Acquisition done.") return locals() def tidy_up(self): self.end_saving() print("Driving all voltages back to zero...") self.sourceVds.set_voltage(0.) self.sourceVg.set_voltage(0.)
class Measurement(MeasurementBase): params = { 'Vgs': Sweep([0.]), 'stabilise_time': 0.3, 'init': Boolean(True), 'use_vna': Boolean(True), 'comment': String(''), 'data_dir': Folder(r'D:\MeasurementJANIS\David M') } observables = ['Vg', 'Ileak'] alarms = [['np.abs(Ileak) > 1e-8', MeasurementBase.ALARM_CALLCOPS ] # is applied between the two gates ] def measure(self, Vgs, stabilise_time, init, use_vna, data_dir, comment, **kwargs): print("===================================") print("Starting acquisition script...") vna_string = '' # initialise instruments try: print("----------------------------------------") print("Setting up Keithley DC sources...") self.sourceVg = sourceVg = K2400('GPIB::24::INSTR', sourcemode='v', vrang=200, irang=10e-6, slope=1, initialise=init) print("DC sources are set up.") except: print("There has been an error setting up DC sources.") raise if use_vna: try: print("----------------------------------------") print("Setting up VNA") self.vna = vna = RohdeSchwarzVNA() vna.open('TCPIP', '192.168.0.3') c1 = vna.channel(1) #check if we used a segmented sweep c1.manual_sweep = True c1.s_parameter_group = c1.to_logical_ports((1, 2)) vna.write("*SRE 32") vna.write("*ESE 1") if not c1.sweep_type == 'SEGM': raise Exception('Please use segmented frequency sweep') # check if the RF power is the same on both ports and for all frequency segments count = int(vna.query(':SENS:SEGM:COUN?').strip()) vna_pow = None for i in range(1, count + 1): seg_pow = float(vna.query(':SENS:SEGM{}:POW?'.format(i))) if vna_pow is None: vna_pow = seg_pow elif vna_pow is not None and seg_pow == vna_pow: continue else: raise Exception( "Please select the same power for all ports and frequency segments" ) port1autoatt = int(vna.query(':SOUR:POW1:ATT:AUTO?').strip()) port2autoatt = int(vna.query(':SOUR:POW2:ATT:AUTO?').strip()) if port1autoatt or port2autoatt: raise Exception("Please do not use automatic attenuators") port1att = float(vna.query(':SOUR:POW1:ATT?').strip()) port2att = float(vna.query(':SOUR:POW2:ATT?').strip()) if port1att == port2att: vna_pow -= port1att else: raise Exception( "Please select the same attenuators for both ports") vna_string = '_pwr={:.0f}'.format(vna_pow) print("VNA is set up.") except: print("There has been an error setting up the VNA.") raise # define name timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') filename = timestamp + vna_string + ('_' + comment if comment else '') # prepare saving RF data spectra_fol = os.path.join(data_dir, filename) create_path(spectra_fol) # prepare saving DC data self.prepare_saving(os.path.join(data_dir, filename + '.txt')) # save config if use_vna: try: with open(os.path.join(spectra_fol, 'VNAconfig'), 'w') as f: f.write( '# Frequency based segmented sweep setup of Rohde&Schwarz ZVA 67\n' ) f.write('# Attenuator Port 1: {}\n'.format(port1att)) f.write('# Attenuator Port 2: {}\n'.format(port2att)) f.write('# Seg no.\tfstart\tfstop\tpoints\tbwidth\tpow\n') count = int(vna.query(':SENS:SEGM:COUN?').strip()) for i in range(1, count + 1): seg_pow = float( vna.query(':SENS:SEGM{}:POW?'.format(i)).strip()) bwidth = float( vna.query(':SENS:SEGM{}:BWID?'.format(i)).strip()) fstart = float( vna.query( ':SENS:SEGM{}:FREQ:STAR?'.format(i)).strip()) fstop = float( vna.query( ':SENS:SEGM{}:FREQ:STOP?'.format(i)).strip()) points = int( vna.query( ':SENS:SEGM{}:SWE:POIN?'.format(i)).strip()) f.write('{:d}\t{:f}\t{:f}\t{:d}\t{:f}\t{:f}\n'.format( i, fstart, fstop, points, bwidth, seg_pow)) except: print("There has been an error setting up the VNA.") raise # loop for Vg in Vgs: if self.flags['quit_requested']: return locals() print('Setting Vg=' + str(Vg) + ' V...') sourceVg.set_voltage(Vg) time.sleep(stabilise_time) # measure Vgm = sourceVg.get_voltage() Ileak = sourceVg.get_current() # save data self.save_row(locals()) # save VNA data if use_vna: print("Getting VNA spectra...") #save data timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') spectrum_file = timestamp + '_Vg=%2.4f' % (Vg) c1.save_measurement_locally( os.path.join(spectra_fol, spectrum_file), (1, 2)) print("Acquisition done.") return locals() def tidy_up(self): self.end_saving() print("Driving all voltages back to zero...") self.sourceVg.set_voltage(0.)
class Measurement(MeasurementBase): params = { 'data_dir': Folder('/home/holger'), 'Vg1s': Sweep(np.linspace(-1., 1., 101)), 'Vg2s': Sweep([0.]), 'Vds': 10e-3, 'commongate': Boolean(False), 'Rg1': 100e3, 'Rg2': 100e3, 'Rds': 2.2e3, 'stabilise_time': 5, 'comment': String('comment') } observables = [ 'Vg1', 'Vg1m', 'Ileak1', 'Vg2', 'Vg2m', 'Ileak2', 'Vds', 'Vdsm', 'Rs' ] alarms = [ ['np.abs(Ileak1) > 1e-8', MeasurementBase.ALARM_CALLCOPS], ['np.abs(Ileak2) > 1e-8', MeasurementBase.ALARM_CALLCOPS], ['np.abs(Vg1-Vg2)', MeasurementBase.ALARM_SHOWVALUE ] # useful if we just want to know how much voltage # is applied between the two gates ] def __init__(self, redirect_console=False, parent=None): super(Measurement, self).__init__(redirect_console=redirect_console, parent=parent) time.sleep(0.5) # take some time to load def measure(self, data_dir, Vg1s, Vg2s, Vds, commongate, Rg1, Rg2, Rds, stabilise_time, **kwargs): print("Starting acquisition script...") print( "Because I need to save my data somewhere, I will save it in the following directory:" ) print(data_dir) # initialise instruments try: self.sourceVg1 = sourceVg1 = VoltageSource( ) # here we should add safety limits self.sourceVg2 = sourceVg2 = VoltageSource() self.sourceVds = sourceVds = VoltageSource() self.meterVg1 = meterVg1 = VoltMeter() self.meterVg2 = meterVg2 = VoltMeter() self.meterVds = meterVds = VoltMeter() except: print("There has been an error setting up one of the instruments.") raise # prepare saving data filename = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') + '.txt' self.prepare_saving('testdata/' + filename) # loops sourceVds.set_voltage(Vds) for Vg2 in Vg2s: sourceVg2.set_voltage(Vg2) for Vg1 in Vg1s: if self.flags['quit_requested']: return locals() sourceVg1.set_voltage(Vg1) # stabilise progressbar_wait(stabilise_time) # measure Vg1m = meterVg1.get_voltage() Vg2m = meterVg2.get_voltage() Vdsm = meterVds.get_voltage() # do calculations Ileak1 = (Vg1 - Vg1m) / Rg1 Ileak2 = (Vg2 - Vg2m) / Rg2 Rs = Rds * Vdsm / (Vds - Vdsm) # save data self.save_row(locals()) print("Acquisition done.") return locals() def tidy_up(self): self.end_saving() print("Driving all voltages back to zero...") self.sourceVg1.set_voltage(0.) self.sourceVg2.set_voltage(0.) self.sourceVds.set_voltage(0.)
class Measurement(MeasurementBase): params = { 'Vdss': Sweep([10e-3]), 'Vg1s': Sweep([0.1]), 'Vg2s': Sweep([0.]), 'commongate': Boolean(False), 'Rg2': 100e3, 'Rds': 2.2e3, 'stabilise_time': 0.05, 'comment': String(''), 'data_dir': Folder(r'D:\MeasurementJANIS\Holger\test'), 'useVNA': Boolean(False), } observables = [ 'Vg1', 'Vg2', 'Vg2m', 'Ileak2', 'Vds', 'Vdsm', 'Rs', 'Ta', 'Tb' ] alarms = [ ['np.abs(Ileak2) > 1e-8', MeasurementBase.ALARM_CALLCOPS], ['np.abs(Vg1-Vg2)', MeasurementBase.ALARM_SHOWVALUE ] # useful if we just want to know how much voltage # is applied between the two gates ] def measure(self, data_dir, comment, Vdss, Vg1s, Vg2s, commongate, Rg2, Rds, stabilise_time, useVNA, **kwargs): print("===================================") print("Starting acquisition script...") # initialise instruments try: print("Setting up DC sources and voltmeters...") bilt = Bilt('TCPIP0::192.168.0.2::5025::SOCKET') self.sourceVds = sourceVds = BiltVoltageSource(bilt, "I1", initialise=False) self.sourceVg1 = sourceVg1 = BiltVoltageSource(bilt, "I2", initialise=False) self.sourceVg2 = sourceVg2 = BiltVoltageSource(bilt, "I3", initialise=False) self.meterVds = meterVds = BiltVoltMeter(bilt, "I5;C1", "2", "Vdsm") self.meterVg2 = meterVg2 = BiltVoltMeter(bilt, "I5;C3", "2", "Vg2m") print("DC sources and voltmeters are set up.") except: print( "There has been an error setting up DC sources and voltmeters." ) raise if useVNA: try: print("Setting up VNA") vna = AnritsuVNA('GPIB::6::INSTR') self.freqs = vna.get_freq_list() # get frequency list print("VNA is set up.") except: print("There has been an error setting up the VNA.") raise try: print("Setting up temperature controller...") tc = SI9700('GPIB::14::INSTR') print("Temperature controller is set up.") except: print( "There has been an error setting up the temperature controller." ) raise timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') # prepare saving DC data filename = timestamp + ('_' + comment if comment else '') self.prepare_saving(os.path.join(data_dir, filename + '.txt')) # prepare saving RF data if useVNA: spectra_fol = os.path.join(data_dir, filename) try: os.makedirs(spectra_fol) except OSError as e: if e.errno != errno.EEXIST: raise # loops for Vds in Vdss: sourceVds.set_voltage(Vds) for Vg2 in Vg2s: if not commongate: sourceVg2.set_voltage(Vg2) for Vg1 in Vg1s: if self.flags['quit_requested']: return locals() sourceVg1.set_voltage(Vg1) if commongate: Vg2 = Vg1 sourceVg2.set_voltage(Vg1) # stabilise time.sleep(stabilise_time) # measure Vdsm = meterVds.get_voltage() Vg2m = meterVg2.get_voltage() Ta = tc.get_temp('a') Tb = tc.get_temp('b') # do calculations Ileak2 = (Vg2 - Vg2m) / Rg2 Rs = Rds * Vdsm / (Vds - Vdsm) # save data self.save_row(locals()) # save VNA data if useVNA: print("Getting VNA spectra...") vna.single_sweep() table = vna.get_table(range(1, 5)) timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') spectrum_file = timestamp + '_Vg1=%2.4f' % ( Vg1) + '_Vg2=%2.4f' % (Vg2) + '_Vds=%2.4f' % ( Vds) + '.txt' np.savetxt(os.path.join(spectra_fol, spectrum_file), np.transpose(table)) print("Acquisition done.") return locals() def tidy_up(self): self.end_saving() print("Driving all voltages back to zero...") self.sourceVds.set_voltage(0.) self.sourceVg1.set_voltage(0.) self.sourceVg2.set_voltage(0.)
class Measurement(MeasurementBase): params = { 'Vgs': Sweep([0.]), 'Vg0': 0., 'Vchuck0': 10., 'Vchuckmax': 30., 'CapaRatio': 10., 'Rg': 100e3, 'stabilise_time': 0.3, 'comment': String(''), 'data_dir': Folder(r''), 'use_vna': Boolean(True), 'init_bilt': Boolean(False), 'init_yoko': Boolean(False) } observables = ['Vg', 'Vgm', 'Vchuck', 'Ileak'] alarms = [ ['np.abs(Ileak) > 1e-8', MeasurementBase.ALARM_CALLCOPS] ] def measure(self, data_dir, Vgs, Vg0, Vchuck0, Vchuckmax, CapaRatio, Rg, comment, stabilise_time, use_vna, init_bilt, init_yoko, **kwargs): print("===================================") print("Starting acquisition script...") # initialise instruments try: print("Setting up DC sources and voltmeters...") bilt = Bilt('TCPIP0::192.168.0.2::5025::SOCKET') if init_bilt: # source (bilt, channel, range, filter, slope in V/ms, label): self.sourceVg = sourceVg = BiltVoltageSource(bilt, "I1", "12", "1", 0.005, "Vg") else: self.sourceVg = sourceVg = BiltVoltageSource(bilt, "I1", initialise=False) # voltmeter (bilt, channel, filt, label=None) self.meterVg = meterVg = BiltVoltMeter(bilt, "I5;C1", "2", "Vgm") # voltage source for chuck self.yoko = yoko = Yoko7651("GPIB::3::INSTR", func="VOLT", rang=30., slope=1., initialise=init_yoko, verbose=True) print("DC sources and voltmeters are set up.") except: print("There has been an error setting up DC sources and voltmeters:") raise try: print("Setting up VNA...") vna = AnritsuVNA('GPIB::6::INSTR') sweeptime = vna.get_sweep_time() print("VNA is set up.") except: print("There has been an error setting up the VNA:") raise timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') # prepare saving DC data filename = timestamp + ('_'+comment if comment else '') self.prepare_saving(os.path.join(data_dir, filename+'.txt')) if use_vna: # prepare saving RF data spectra_fol = os.path.join(data_dir, filename) try: os.makedirs(spectra_fol) except OSError as e: if e.errno != errno.EEXIST: raise if vna.get_sweep_type() == 'FSEGM': with open(os.path.join(spectra_fol, 'VNAconfig'), 'w') as f: vna.dump_freq_segments(f) for Vg in Vgs: if self.flags['quit_requested']: print("Stopping acquisition.") return locals() print("Setting Vg = {}".format(Vg)) # calculate new chuck voltage to keep field constant # set Vg sourceVg.set_voltage(Vg) Vchuck = Vchuck0+CapaRatio*(Vg-Vg0) if np.abs(Vchuck) <= Vchuckmax: print("Set chuck voltage:", Vchuck) yoko.set_voltage(Vchuck) else: print("Chuck voltage too high:", Vchuck) print("Not changing chuck voltage.") Vchuck = yoko.get_voltage() # wait time.sleep(stabilise_time) # read voltages Vgm = meterVg.get_voltage() # do calculations Ileak = (Vg-Vgm)/Rg # save DC data self.save_row(locals()) if use_vna: # save VNA data print("Getting VNA spectra...") vna.single_sweep(wait=False) # display sweep progress progressbar_wait(sweeptime) # make sure sweep is really done while not vna.is_sweep_done(): time.sleep(0.5) table = vna.get_table([1,2,3,4]) timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') spectrum_file = timestamp+'_Vg=%2.4f_Vchuck=%2.4f'%(Vg, Vchuck)+'.txt' np.savetxt(os.path.join(spectra_fol, spectrum_file), np.transpose(table)) print("Acquisition done.") return locals() def tidy_up(self): self.end_saving() print("Driving all voltages back to zero...") self.sourceVg.set_voltage(0.) self.yoko.set_voltage(0.)
class Measurement(MeasurementBase): params = { 'Vdss': Sweep([0.0]), 'Vg1s': Sweep([0.0]), 'Vg2s': Sweep([0.0]), 'commongate': Boolean(False), 'Rg1': 100e3, 'Rg2': 100e3, 'Rds': 22e3, 'stabilise_time': 0.05, 'comment': String(''), 'data_dir': Folder(r'D:\MeasurementJANIS\Holger\KTW H5 2x3\2017-11-09 LHe') } observables = [ 'Vg1', 'Vg1m', 'Ileak1', 'Vg2', 'Vg2m', 'Ileak2', 'Vds', 'Vdsm', 'Rs' ] alarms = [ ['np.abs(Ileak1) > 1e-8', MeasurementBase.ALARM_CALLCOPS], ['np.abs(Ileak2) > 1e-8', MeasurementBase.ALARM_CALLCOPS], ['np.abs(Vg1-Vg2)', MeasurementBase.ALARM_SHOWVALUE ] # useful if we just want to know how much voltage # is applied between the two gates ] def measure(self, data_dir, comment, Vdss, Vg1s, Vg2s, commongate, Rg1, Rg2, Rds, stabilise_time, **kwargs): print("===================================") print("Starting acquisition script...") # initialise instruments try: print("Setting up DC sources and voltmeters...") bilt = Bilt('TCPIP0::192.168.0.2::5025::SOCKET') self.sourceVds = sourceVds = BiltVoltageSource(bilt, "I1", initialise=False) self.sourceVg1 = sourceVg1 = BiltVoltageSource(bilt, "I2", initialise=False) self.sourceVg2 = sourceVg2 = BiltVoltageSource(bilt, "I3", initialise=False) self.meterVds = meterVds = BiltVoltMeter(bilt, "I5;C1", "2", "Vdsm") self.meterVg1 = meterVg1 = BiltVoltMeter(bilt, "I5;C2", "2", "Vg1m") self.meterVg2 = meterVg2 = BiltVoltMeter(bilt, "I5;C3", "2", "Vg2m") print("DC sources and voltmeters are set up.") except: print( "There has been an error setting up DC sources and voltmeters." ) raise timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') # prepare saving data filename = timestamp + '_' + (comment if comment else '') + '.txt' self.prepare_saving(os.path.join(data_dir, filename)) # loops for Vds in Vdss: sourceVds.set_voltage(Vds) for Vg2 in Vg2s: if not commongate: sourceVg2.set_voltage(Vg2) for Vg1 in Vg1s: if self.flags['quit_requested']: return locals() sourceVg1.set_voltage(Vg1) if commongate: Vg2 = Vg1 sourceVg2.set_voltage(Vg1) # stabilise time.sleep(stabilise_time) # measure Vdsm = meterVds.get_voltage() Vg1m = meterVg1.get_voltage() Vg2m = meterVg2.get_voltage() # do calculations Ileak1 = (Vg1 - Vg1m) / Rg1 Ileak2 = (Vg2 - Vg2m) / Rg2 Rs = Rds * Vdsm / (Vds - Vdsm) # save data self.save_row(locals()) print("Acquisition done.") return locals() def tidy_up(self): self.end_saving() print("Driving all voltages back to zero...") self.sourceVds.set_voltage(0.) self.sourceVg1.set_voltage(0.) self.sourceVg2.set_voltage(0.)
class Measurement(MeasurementBase): params = { 'sweep': Boolean(False), 'startpoint': 0., 'direction': 1., 'step': 1., 'Ithresh': 3e-7, 'Vmax': 30, 'stabilise_time': 10, 'init': Boolean(True), 'use_vna': Boolean(True), 'comment': String(''), 'data_dir': Folder(r'D:\MeasurementJANIS\Holger\test') } observables = ['Vg', 'Vgm', 'Ileak'] alarms = [] def measure(self, step, startpoint, direction, Ithresh, Vmax, sweep, stabilise_time, init, use_vna, data_dir, comment, **kwargs): print("===================================") print("Starting acquisition script...") vna_string = '' # initialise instruments try: print("----------------------------------------") print("Setting up Keithley DC sources...") self.sourceVg = sourceVg = K2400('GPIB::24::INSTR', sourcemode='v', vrang=200, irang=10e-6, slope=1, initialise=init) print("DC sources are set up.") except: print("There has been an error setting up DC sources.") raise if use_vna: print("Setting up VNA...") vna = AnritsuVNA('GPIB::6::INSTR') sweeptime = vna.get_sweep_time() if vna.get_sweep_type() != 'FSEGM': raise Exception('Please use segmented frequency sweep') # check if the RF power is the same on both ports and for all # frequency segments count = int(vna.query(':SENS:FSEGM:COUN?')) vna_pow = None for i in range(1, count + 1): port1pow = float( vna.query(':SENS:FSEGM{}:POW:PORT1?'.format(i))) port2pow = float( vna.query(':SENS:FSEGM{}:POW:PORT2?'.format(i))) if vna_pow is None and port1pow == port2pow: vna_pow = port1pow elif vna_pow is not None and port1pow == port2pow and port1pow == vna_pow: continue else: raise Exception( "Please select the same power for all ports and frequency segments" ) port1att = vna.get_source_att(1) port2att = vna.get_source_att(2) if port1att == port2att: vna_pow -= port1att else: raise Exception( "Please select the same attenuators for both ports") vna_string = '_pwr={:.0f}'.format(vna_pow) print("VNA is set up.") # define name timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') filename = timestamp + vna_string + ('_' + comment if comment else '') # prepare saving RF data spectra_fol = os.path.join(data_dir, filename) create_path(spectra_fol) # prepare saving DC data self.prepare_saving(os.path.join(data_dir, filename + '.txt')) if use_vna: # prepare saving RF data spectra_fol = os.path.join(data_dir, filename) create_path(spectra_fol) # save segmented frequency sweep data to file with open(os.path.join(spectra_fol, 'VNAconfig'), 'w') as f: vna.dump_freq_segments(f) Vg = startpoint def measure_point(Ithresh=np.inf): print('Setting Vg=' + str(Vg) + ' V...') sourceVg.set_voltage(Vg) print('Stabilising...') progressbar_wait(stabilise_time) # measure Vgm = sourceVg.get_voltage() Ileak = sourceVg.get_current() # save data self.save_row(locals()) # save VNA data if use_vna: # save VNA data print("Getting VNA spectra...") vna.single_sweep(wait=False) # display sweep progress progressbar_wait(sweeptime) # make sure sweep is really done while not vna.is_sweep_done(): time.sleep(0.5) table = vna.get_table([1, 2, 3, 4]) timestamp = time.strftime('%Y-%m-%d_%Hh%Mm%Ss') spectrum_file = timestamp + '_Vg={:.3f}.txt'.format(Vg) np.savetxt(os.path.join(spectra_fol, spectrum_file), np.transpose(table)) return np.abs(Ileak) > Ithresh # measure at 0 V measure_point() # sweep if requested #╦direction = 1. # up if direction not in [1., -1.]: raise Exception("select valid direction 1. or -1.") back_to_zero = False decimals = int(max(1., -np.log10(step) + 1.)) while sweep: if self.flags['quit_requested']: return locals() Vg = np.around(Vg + step * direction, decimals) if np.abs(Vg) > Vmax: print("Reached maximum voltage! Inverting sweep direction.") if direction < 0. and Vg < 0.: back_to_zero = True direction = -direction continue leak = measure_point(Ithresh) if leak: if direction * Vg < 0.: continue if direction < 0. and Vg < 0.: back_to_zero = True direction = -direction if np.abs(Vg) < 1e-12 and back_to_zero: break print("Acquisition done.") return locals() def tidy_up(self): self.end_saving() print("Driving all voltages back to zero...") self.sourceVg.set_voltage(0.)