def __init__(self, devices, pcb, structures, ivcurves_max_bias=150, max_current=5e-6): self.iv = IVscan(devices=devices, max_current=max_current, live=False) self.relay = Silab_relay() #dut_fridge = Dut('binder.yaml') #dut_fridge.init() #self.fridge = dut_fridge['Climatechamber'] self.devices = devices self.pcb = pcb self.structures = structures self.nchan = len(self.structures) self.ivcurves_max_bias = ivcurves_max_bias self.data = []
class automated_scans(object): ''' Class of fully automated IV and source scans using the SilabRelay and qMCA setups. ''' def __init__(self, devices, pcb, structures, ivcurves_max_bias=150, max_current=5e-6): self.iv = IVscan(devices=devices, max_current=max_current, live=False) self.relay = Silab_relay() #dut_fridge = Dut('binder.yaml') #dut_fridge.init() #self.fridge = dut_fridge['Climatechamber'] self.devices = devices self.pcb = pcb self.structures = structures self.nchan = len(self.structures) self.ivcurves_max_bias = ivcurves_max_bias self.data = [] #self.iv.reset() def _get_current(self, device, channel='all', fast=False): ''' Gets a current measurement for a specific channel or all channels using the IVScan.measure_current method. ''' if type(channel) == int: self.relay.switch_to(channel) if fast: return self.iv.get_current_reading(device) else: return self.iv.measure_current(device) else: data = [] for c in range(0, self.nchan): self.relay.switch_to(c) if fast: current = self.iv.get_current_reading(device) else: current = self.iv.measure_current(device) data.append(current) return data def _go_to_temperature(self, temp, wait_for=600, timeout=1800): ''' Sets new temperature target value and wait for reported just value to reach target value. Then wait an additional time to let DUT cool to air temperature. ''' logging.info('Setting temperature to %iC' % temp) self.fridge.set_temperature(temp) timeout = int(timeout/5) count = 0 logging.debug('Starting loop') while True: count += 1 time.sleep(5) just = float(self.fridge.get_temperature()) logging.debug('Target value is %1.2f, just value is %1.2f' % (temp, just)) if just == temp or (just < temp and just > (temp - 0.05*temp)) or (just > temp and just < (temp + 0.05*temp)): logging.debug('Target value reached!') time.sleep(wait_for) return True if count >= timeout: logging.debug('Target value not reached but ran into timeout!') return False def _take_source_scan(self, qmca_channel, threshold=3000, duration=600, file_name='', max_events=1000000, adc_differential_voltage=1.5): ''' Take a single source scan using qMCA setup / class ''' if not file_name: file_name = 'source_scan_%s' % (self.pcb) elif file_name.split('.')[-1] == 'h5': file_name = file_name.split('.')[:-1] with qmca.qmca(channel=qmca_channel, threshold=threshold, adc_differential_voltage=adc_differential_voltage) as my_qmca: start_time = time.time() actual_time = start_time my_qmca.start(out_filename=file_name) while ((actual_time < (start_time + duration)) and (my_qmca.event_count <= max_events)): if self.pbar.currval < 100: self.pbar.update(self.pbar.currval + 0.5) actual_time = time.time() time.sleep(1) def take_ivcurve(self, device='auto', channel='all', file_name=''): ''' Take simple IV curve for either one specific channel or all connected channels ''' if type(device) == str and device == 'auto': device = self.devices[self.devices.keys()[0]] if type(channel) == int: if not file_name: file_name = 'ivcurve_%s_structure%s_nwellFloating.csv' % (self.pcb, self.structures[channel]) elif not file_name.split('.')[-1] == 'csv': file_name = file_name + '.csv' logging.debug('Switching to channel %i' % channel) self.relay.switch_to(channel) logging.info('Take IV curve for structure%s' % self.structures[channel]) self.iv.scan_iv(file_name=file_name, max_bias_voltage=self.ivcurves_max_bias) elif channel == 'all' or channel == 'All': for c in range(0, self.nchan): if not file_name: file_name_set = 'ivcurve_%s_structure%s_nwellFloating.csv' % (self.pcb, self.structures[c]) elif not file_name.split('.')[-1] == 'csv': file_name_set = '%s_structure%s.csv' % (file_name, self.structures[c]) elif file_name.split('.')[-1] == 'csv': file_name_set = '%s_structure%s.csv' % (file_name.split('.')[:-1], self.structures[c]) logging.debug('Switching to channel %i' % c) self.relay.switch_to(c) logging.info('Take IV curve for structure%s' % self.structures[c]) self.iv.scan_iv(file_name=file_name_set, max_bias_voltage=self.ivcurves_max_bias) def take_iv_with_nwell(self, device='auto', channel='all', file_name='', source_bias=False): ''' Take simple IV curve for either one specific channel or all connected channels ''' if type(device) == str and device == 'auto': device = self.devices[self.devices.keys()[0]] if type(channel) == int: if not file_name: file_name = 'ivcurve_%s_structure%s_nwell=HV.csv' % (self.pcb, self.structures[channel]) elif not file_name.split('.')[-1] == 'csv': file_name = file_name + '.csv' logging.debug('Switching to channel %i' % channel) self.relay.switch_to(channel) logging.info('Take IV curve for structure%s' % self.structures[channel]) self.iv.scan_iv_with_nwell(file_name=file_name, max_bias_voltage=self.ivcurves_max_bias, max_nwell_voltage=-1, source_bias=source_bias) elif channel == 'all' or channel == 'All': for c in range(0, self.nchan): if not file_name: file_name_set = 'ivcurve_%s_structure%s_nwell=HV.csv' % (self.pcb, self.structures[c]) elif not file_name.split('.')[-1] == 'csv': file_name_set = '%s_structure%s.csv' % (file_name, self.structures[c]) elif file_name.split('.')[-1] == 'csv': file_name_set = '%s_structure%s.csv' % (file_name.split('.')[:-1], self.structures[c]) logging.debug('Switching to channel %i' % c) self.relay.switch_to(c) logging.info('Take IV curve for structure%s' % self.structures[c]) self.iv.scan_iv_with_nwell(file_name=file_name_set, max_bias_voltage=self.ivcurves_max_bias, max_nwell_voltage=-1, source_bias=source_bias) def take_ivcurve_with_potential(self, potential_name, potential_device_name, device='auto', channel='all', file_name=''): ''' Take simple IV curve with additional potential for either one specific channel or all connected channels ''' if type(device) == str and device == 'auto': device = self.devices[self.devices.keys()[0]] print device if type(channel) == int: if not file_name: file_name = 'ivcurve_%s_structure%s_nwellFloating.csv' % (self.pcb, self.structures[channel]) elif not file_name.split('.')[-1] == 'csv': file_name = file_name + '.csv' logging.debug('Switching to channel %i' % channel) self.relay.switch_to(channel) logging.info('Take IV curve for structure%s' % self.structures[channel]) self.iv.scan_iv_with_potential(file_name=file_name, max_bias_voltage=self.ivcurves_max_bias, potential_name=potential_name, potential_device_name=potential_device_name) elif channel == 'all' or channel == 'All': for c in range(0, self.nchan): if not file_name: file_name_set = 'ivcurve_%s_structure%s_nwellFloating.csv' % (self.pcb, self.structures[c]) elif not file_name.split('.')[-1] == 'csv': file_name_set = '%s_structure%s.csv' % (file_name, self.structures[c]) elif file_name.split('.')[-1] == 'csv': file_name_set = '%s_structure%s.csv' % (file_name.split('.')[:-1], self.structures[c]) logging.debug('Switching to channel %i' % c) self.relay.switch_to(c) logging.info('Take IV curve for structure%s' % self.structures[c]) self.iv.scan_iv_with_potential(file_name=file_name_set, max_bias_voltage=self.ivcurves_max_bias, potential_name=potential_name, potential_device_name=potential_device_name) def anneal(self, device, voltage=3, annealing_time=60*80, temperature=60, t_reset=-20, file_name=''): ''' Set fridge to annealing temperature and record warmup currents. Stay at annealing temperature for specified time and record currents of all structures every minute. Then go back to rest temperature and record cooldown currents. ''' if not file_name: file_name_warmup = 'annealing_%s_HV=%i_t=%i_T=%i_warmup.csv' % (self.pcb, voltage, annealing_time, temperature) file_name_cooldown = 'annealing_%s_HV=%i_t=%i_T=%i_cooldown.csv' % (self.pcb, voltage, annealing_time, temperature) file_name = 'annealing_%s_HV=%i_t=%i_T=%i.csv' % (self.pcb, voltage, annealing_time, temperature) elif not file_name.split('.')[-1] == 'csv': file_name_warmup = file_name + '_warmup.csv' file_name_cooldown = file_name + '_cooldown.csv' file_name = file_name + '.csv' '''Warmup''' logging.info('Start warmup phase. Set temperature to %iC, apply %iV and record current every minute.' % (temperature, voltage)) with open(file_name_warmup, 'wb') as outfile: f = csv.writer(outfile ,quoting=csv.QUOTE_NONNUMERIC) header = ['Timestamp', 'Temperature [C]'] for s in self.structures: header.append('Strucutre %s [A]' % s) f.writerow(header) self.fridge.set_temperature(temperature) device.set_voltage(voltage) device.on() count, wait = 0, 600 while True: count += 1 time.sleep(1) just = float(self.fridge.get_temperature()) logging.debug('Target value is %1.2f, just value is %1.2f' % (temperature, just)) if (count % 60) == 0: row = [time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), just] row.extend(self._get_current(device, fast=True)) f.writerow(row) outfile.flush() if just >= (temperature - (temperature * 0.05)): wait -= 1 if wait == 0: break '''Annealing''' logging.info('Target temperature of %iC reached, start annealing for %imin, apply %iV and record current every minute.' % (temperature, annealing_time/60, voltage)) with open(file_name, 'wb') as outfile: f = csv.writer(outfile ,quoting=csv.QUOTE_NONNUMERIC) header = ['Timestamp', 't [min]'] for s in self.structures: header.append('Strucutre %s [A]' % s) f.writerow(header) row = [time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), 0] row.extend(self._get_current(device)) f.writerow(row) start_time = time.time() actual_time = start_time last_measure_time = start_time while True: time.sleep(1) actual_time = time.time() if (actual_time - last_measure_time) >= 60: just = float(self.fridge.get_temperature()) logging.debug('Target value is %1.2f, just value is %1.2f' % (temperature, just)) row = [time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), int(count/60)] row.extend(self._get_current(device)) f.writerow(row) outfile.flush() last_measure_time = time.time() if (actual_time-start_time) >= annealing_time: break row = [time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), int(count/60)] row.extend(self._get_current(device)) f.writerow(row) outfile.flush() '''Cooldown''' logging.info('Annealing done! Start cooldown phase. Set temperature to %iC, apply %iV and record current every minute.' % (t_reset, voltage)) with open(file_name_cooldown, 'wb') as outfile: f = csv.writer(outfile ,quoting=csv.QUOTE_NONNUMERIC) header = ['Timestamp', 'Temperature [C]'] for s in self.structures: header.append('Strucutre %s [A]' % s) f.writerow(header) self.fridge.set_temperature(t_reset) count, wait = 0, 600 while True: count += 1 time.sleep(1) just = float(self.fridge.get_temperature()) logging.debug('Target value is %1.2f, just value is %1.2f' % (temperature, just)) if (count % 60) == 0: row = [time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), just] row.extend(self._get_current(device, fast=True)) f.writerow(row) outfile.flush() if just <= (t_reset + (t_reset * 0.05)): wait -= 1 if wait == 0: break def measure_arrhenius(self, device='auto', voltage=20, temp_range=range(-30, 61, 5), file_name=''): ''' Apply constant voltage and measure current of all structures for different temperatures ''' logging.info('Measure Arrhenius plot at %iV bias from %i to %iC' % (voltage, min(temp_range), max(temp_range))) pbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=len(temp_range), poll=10, term_width=80).start() if type(device) == str and device == 'auto': device = self.devices[self.devices.keys()[0]] if not file_name: file_name = 'arrhenius_%s_HV=%i.csv' % (self.pcb, voltage) elif not file_name.split('.')[-1] == 'csv': file_name = file_name + '.csv' self.iv.ramp_to(device, voltage) with open(file_name, 'wb') as outfile: f = csv.writer(outfile ,quoting=csv.QUOTE_NONNUMERIC) header = ['Temperature [C]'] for s in self.structures: header.append('Strucutre %s [A]' % s) f.writerow(header) outfile.flush() logging.info('Start Arrhenius measurement') for temp in temp_range: self._go_to_temperature(temp) row = [temp] row.extend(self._get_current(device)) f.writerow(row) outfile.flush() pbar.update(pbar.currval + 1) def source_scan_temp_sweep(self, qmca_channel, bias_device, structure, source, t_range=range(-30, 41, 10), bias=10, threshold=3000, duration=600, max_events=1000000): if (not type(bias) == int and not type(bias) == list) or (type(bias) == list and not len(bias) == len(t_range)): raise ValueError('bias has to be either constant int or list with same length as t_range') if type(bias) == int: bias_value = bias bias = [] for _ in range(len(t_range)): bias.append(bias_value) print t_range print bias bias_device.on() self.pbar = progressbar.ProgressBar(widgets=['', progressbar.Percentage(), ' ', progressbar.Bar(marker='*', left='|', right='|'), ' ', progressbar.AdaptiveETA()], maxval=duration*len(t_range), poll=10, term_width=80).start() with open('source_scan_temp_sweep_bias_currents_structure%s.csv' % structure, 'wb') as outfile: f = csv.writer(outfile ,quoting=csv.QUOTE_NONNUMERIC) header = ['Temperature [C]', 'Bias Current [A]'] f.writerow(header) for self.i, t in enumerate(t_range): file_name = 'source_scan_%s_%s_structure%s_HV=%i_T=%i' % (source, self.pcb, structure, bias[self.i], t) self._go_to_temperature(t) print "_got_to_temperature returned True..." self.iv.ramp_to(bias_device, bias[self.i]) f.writerow([t, self.iv.measure_current(bias_device)]) outfile.flush() self._take_source_scan(qmca_channel=qmca_channel, threshold=threshold, duration=duration, file_name=file_name, max_events=max_events) self.pbar.finish()