def set_data_location(): """ Sets location for qcodes to save data based on the qcodes.config.user.data_location value, the qc.config.user.data_format and the sample name and sets data_loc_fmt in global_settings.files_setup dictionary to True. """ sample_name = get_sample_name() try: dat_loc = qc.config.user.data_location.format(sample_name=sample_name) dat_fmt = qc.config.user.data_format dat_loc_fmt = dat_loc + dat_fmt except KeyError: raise KeyError('data_location or data_format not set in config, see ' '"https://github.com/QCoDeS/Qcodes/blob/master' '/docs/examples/Configuring_QCoDeS.ipynb"') if exp.files_setup['data_loc_fmt']: print('Data location already set at {}.\n' 'Data file format already set as {}.'.format(dat_loc, dat_fmt)) print('-------------------------') else: if not os.path.exists(dat_loc): os.makedirs(dat_loc) loc_provider = qc.FormatLocation(fmt=dat_loc_fmt) qc.data.data_set.DataSet.location_provider = loc_provider exp.files_setup['data_loc_fmt'] = True logging.info('Set data location: {}'.format(dat_loc)) print('Set data location: {}'.format(dat_loc)) print('-------------------------') logging.info('Set data file format: {}'.format(dat_fmt)) print('Set data file format: {}'.format(dat_fmt)) print('-------------------------')
def _set_up_exp_file(sample_name: str, mainfolder: str= None): """ Makes Args: mainfolder: base location for the data sample_name: name of the sample """ if sep in sample_name: raise TypeError("Use Relative names. That is without {}".format(sep)) if mainfolder is None: try: mainfolder = qc.config.user.mainfolder except KeyError: raise KeyError('mainfolder not set in qc.config, see ' '"https://github.com/QCoDeS/Qcodes/blob/master' '/docs/examples/Configuring_QCoDeS.ipynb"') # always remove trailing sep in the main folder if mainfolder[-1] == sep: mainfolder = mainfolder[:-1] mainfolder = abspath(mainfolder) CURRENT_EXPERIMENT["mainfolder"] = mainfolder CURRENT_EXPERIMENT["sample_name"] = sample_name CURRENT_EXPERIMENT['init'] = True path_to_experiment_folder = sep.join([mainfolder, sample_name, ""]) CURRENT_EXPERIMENT["exp_folder"] = path_to_experiment_folder try: makedirs(path_to_experiment_folder) except FileExistsError: pass loc_provider = qc.FormatLocation( fmt=path_to_experiment_folder + '{counter}') qc.data.data_set.DataSet.location_provider = loc_provider CURRENT_EXPERIMENT["provider"] = loc_provider log.info("experiment started at {}".format(path_to_experiment_folder))
def init(mainfolder: str, sample_name: str, station, plot_x_position=0.66, annotate_image=True, display_pdf=True, display_individual_pdf=False): """ Args: mainfolder: base location for the data sample_name: name of the sample plot_x_position: fractional of screen position to put QT plots. 0 is all the way to the left and 1 is all the way to the right. """ pdfdisplay['individual'] = display_individual_pdf pdfdisplay['combined'] = display_pdf if sep in sample_name: raise TypeError("Use Relative names. That is without {}".format(sep)) # always remove trailing sep in the main folder if mainfolder[-1] == sep: mainfolder = mainfolder[:-1] mainfolder = abspath(mainfolder) CURRENT_EXPERIMENT["mainfolder"] = mainfolder CURRENT_EXPERIMENT["sample_name"] = sample_name CURRENT_EXPERIMENT['init'] = True CURRENT_EXPERIMENT['plot_x_position'] = plot_x_position path_to_experiment_folder = sep.join([mainfolder, sample_name, ""]) CURRENT_EXPERIMENT["exp_folder"] = path_to_experiment_folder CURRENT_EXPERIMENT['pdf_subfolder'] = 'pdf' try: makedirs(path_to_experiment_folder) except FileExistsError: pass try: makedirs( sep.join( [mainfolder, sample_name, CURRENT_EXPERIMENT['pdf_subfolder']])) except FileExistsError: pass log.info("experiment started at {}".format(path_to_experiment_folder)) loc_provider = qc.FormatLocation(fmt=path_to_experiment_folder + '{counter}') qc.data.data_set.DataSet.location_provider = loc_provider CURRENT_EXPERIMENT["provider"] = loc_provider CURRENT_EXPERIMENT['station'] = station ipython = get_ipython() # turn on logging only if in ipython # else crash and burn if ipython is None: raise RuntimeWarning("History can't be saved. " "-Refusing to proceed (use IPython/jupyter)") else: logfile = "{}{}".format(path_to_experiment_folder, "commands.log") CURRENT_EXPERIMENT['logfile'] = logfile if not CURRENT_EXPERIMENT["logging_enabled"]: log.debug("Logging commands to: t{}".format(logfile)) ipython.magic("%logstart -t -o {} {}".format(logfile, "append")) CURRENT_EXPERIMENT["logging_enabled"] = True else: log.debug("Logging already started at {}".format(logfile)) # Annotate image if wanted and necessary if annotate_image: _init_device_image(station)
def fft_noise(dev_name: str, channel: Dict[str, int], unit: str, prefactor: Any, samplerate: int, sampleduration: Union[float, int], navg: int, fmax: Union[float, int]): """Noise measurement of a single channel. Args: dev_name: DAQ device name (e.g. 'Dev1'). channel: Dict of {channel_name: analog_input} (e.g. {'MAG': 0}). unit: Physical unit of the channel (e.g. 'Phi0'). prefactor: Pint Quantity with dimenions of unit/V, from microscope.get_prefactors(). samplerate: DAQ sampling rate in Hz. sampleduration: Sampling time in seconds. navg: Number of times to average the spectrum. fmax: Maximum frequency up to which the spectrum will be saved. Returns: Dict: mdict """ loc_provider = qc.FormatLocation( fmt='./data/{date}/#{counter}_{name}_{time}') loc = loc_provider(DiskIO('.'), record={'name': 'fft_noise'}) pathlib.Path(loc).mkdir(parents=True, exist_ok=True) prefactor_str = {} prefactor.ito('{}/V'.format(unit)) prefactor_str.update({ list(channel.keys())[0]: '{} {}'.format(prefactor.magnitude, prefactor.units) }) mdict = { 'metadata': { 'channel': channel, 'unit': unit, 'prefactor': prefactor_str, 'samplerate': samplerate, 'sampleduration': sampleduration, 'navg': navg, 'fmax': fmax, 'location': loc } } nsamples = int(samplerate * sampleduration) v_fft_avg = np.zeros((nsamples // 2, )) with nidaqmx.Task('fft_noise_ai_task') as ai_task: for inst in DAQAnalogInputs.instances(): inst.close() daq_ai = DAQAnalogInputs('daq_ai', dev_name, samplerate, channel, ai_task, samples_to_read=nsamples, timeout=sampleduration + 10) for i in range(navg): data_v = daq_ai.voltage()[0].T Fs = nsamples / sampleduration v_fft = np.fft.fft(data_v) / (nsamples / np.sqrt(2 * sampleduration)) v_fft_abs = np.abs(v_fft[:nsamples // 2]) freqs = np.fft.fftfreq(nsamples, d=1 / Fs)[:nsamples // 2] v_fft_avg += v_fft_abs daq_ai.close() v_fft_avg = v_fft_avg / navg sig_fft_avg = prefactor.magnitude * v_fft_avg mdict.update({ 'v_fft_avg': v_fft_avg[freqs < fmax], 'sig_fft_avg': sig_fft_avg[freqs < fmax], 'freqs': freqs[freqs < fmax] }) fig, ax = plt.subplots(1, 2, figsize=(8, 4), tight_layout=True) ax[0].loglog(freqs, v_fft_avg, lw=1) ax[0].set_ylabel('V/$\\sqrt{Hz}$') ax[1].loglog(freqs, sig_fft_avg, lw=1) ax[1].set_ylabel('{}/$\\sqrt{Hz}$'.format(unit)) fig.suptitle(loc, x=0.5, y=1) for i in [0, 1]: ax[i].set_xlabel('Frequency [Hz]') ax[i].grid() plt.savefig(loc + '/fft_noise.png') io.savemat(loc + '/fft_noise.mat', mdict) return mdict
def time_trace(dev_name: str, channels: Dict[str, int], units: Dict[str, str], prefactors: Dict[str, Any], samplerate: int, sampleduration: Union[float, int]): """Records a time trace of data from DAQ analog input channels, converts data to desired units. Args: dev_name: DAQ device name (e.g. 'Dev1'). channel: Dict of {channel_name: analog_input} (e.g. {'MAG': 0, 'SUSCX': 1}). unit: Physical unit of the channel (e.g. {'MAG': 'Phi0', 'SUSCX': 'Phi0/A'}). prefactor: Dict of {channel_name: Pint Quantity} from microscope.get_prefactors(). samplerate: DAQ sampling rate (for each channel) in Hz. sampleduration: Sampling time in seconds. Returns: Dict: mdict """ loc_provider = qc.FormatLocation( fmt='./data/{date}/#{counter}_{name}_{time}') loc = loc_provider(DiskIO('.'), record={'name': 'time_trace'}) pathlib.Path(loc).mkdir(parents=True, exist_ok=True) prefactor_strs = {} for ch in channels: unit = units[ch] prefactors[ch].ito('{}/V'.format(unit)) prefactor_strs.update({ ch: '{} {}'.format(prefactors[ch].magnitude, prefactors[ch].units) }) nsamples = int(samplerate * sampleduration) time = np.linspace(0, sampleduration, nsamples) mdict = { 'time': { 'array': time, 'unit': 's' }, 'metadata': { #'channels': channels, #'units': units, #'prefactors': prefactor_strs, 'samplerate': samplerate, 'sampleduration': sampleduration, 'location': loc } } nsamples = int(samplerate * sampleduration) time = np.linspace(0, sampleduration, nsamples) with nidaqmx.Task('time_trace_ai_task') as ai_task: for inst in DAQAnalogInputs.instances(): inst.close() daq_ai = DAQAnalogInputs('daq_ai', dev_name, samplerate, channels, ai_task, samples_to_read=nsamples, timeout=sampleduration + 10) data_v = daq_ai.voltage() daq_ai.close() for i, ch in enumerate(channels): mdict.update({ ch: { 'array': data_v[i] * prefactors[ch].magnitude, 'unit': units[ch], 'prefactor': prefactor_strs[ch] } }) io.savemat(loc + '/time_trace.mat', mdict) return mdict
def get_surface(self, x_vec: np.ndarray, y_vec: np.ndarray, tdc_params: Dict[str, Any]) -> None: """Performs touchdowns on a grid and fits a plane to the resulting surface. Args: x_vec: 1D array of x positions (must be same length as y_vec). y_vec: 1D array of y positions (must be same length as x_vec). tdc_params: Dict of capacitive touchdown parameters as defined in measurement configuration file. """ old_pos = self.scanner.position() #: True if touchdown doesn't occur for any point in the grid out_of_range = False #: True if the loop is exited before finishing premature_exit = False self.scanner.break_loop = False self.scanner.td_has_occurred = False self.snapshot(update=True) x_grid, y_grid = np.meshgrid(x_vec, y_vec, indexing='ij') td_grid = np.full((len(x_vec), len(y_vec)), np.nan, dtype=np.double) log.info('Aqcuiring a plane.') v_retract = self.scanner.voltage_retract[self.temp].to('V').magnitude fig = plt.figure(figsize=(8, 3)) ax0 = fig.add_subplot(121, projection='3d') ax1 = fig.add_subplot(122, projection='3d') for ax in [ax0, ax1]: ax.set_xlabel('x position [V]') ax.set_ylabel('y position [V]') ax.set_zlabel('z position [V]') ax0.set_title('Sample Plane') ax1.set_title('Sample Surface') fig.canvas.draw() fig.show() for i in range(len(x_vec)): for j in range(len(y_vec)): #: If any of the safety limits in td_cap() are exceeded, #: or the loop is interrupted by the user. if self.scanner.break_loop and not self.scanner.td_has_occurred: log.warning('Aborting get_surface().') premature_exit = True break #: goes to outer break statement else: self.scanner.goto([x_grid[i, j], y_grid[i, j], v_retract]) data, tdc_plot = self.td_cap(tdc_params, update_snap=False) td_grid[i, j] = self.scanner.td_height clear_output(wait=True) if self.scanner.td_height is None: out_of_range = True premature_exit = True log.warning( 'Touchdown out of range. Stopping get_surface().') self.scanner.goto(old_pos) break #: goes to outer break statement plt.close(fig) fig = plt.figure(figsize=(8, 3)) ax0 = fig.add_subplot(121, projection='3d') ax1 = fig.add_subplot(122, projection='3d') for ax in [ax0, ax1]: ax.scatter(x_grid[np.isfinite(td_grid)], y_grid[np.isfinite(td_grid)], td_grid[np.isfinite(td_grid)], cmap='viridis') ax.set_xlabel('x position [V]') ax.set_ylabel('y position [V]') ax.set_zlabel('z position [V]') ax0.set_title('Sample Plane') ax1.set_title('Sample Surface') fig.canvas.draw() fig.show() plt.close(tdc_plot.fig) continue #: skips outer break statement break #: occurs only if out_of_range or loop is broken self.scanner.goto(old_pos) if not out_of_range and not premature_exit: self.scanner.metadata.update( {'td_grid': { 'x': x_grid, 'y': y_grid, 'z': td_grid }}) # Create spline function to interpolate over surface: self.scanner.surface_interp = Rbf(x_grid, y_grid, td_grid, function='cubic') #: Fit a plane to the td_grid x = np.reshape(x_grid, (-1, 1)) y = np.reshape(y_grid, (-1, 1)) td = np.reshape(td_grid, (-1, 1)) z = np.column_stack((x, y, np.ones_like(x))) plane, res, _, _ = lstsq(z, td) log.info('New plane : {}.'.format([plane[i][0] for i in range(3)])) ax0.plot_surface(x_grid, y_grid, plane[0] * x_grid + plane[1] * y_grid + plane[2], cmap='viridis', alpha=0.5) ax1.plot_surface(x_grid, y_grid, self.scanner.surface_interp(x_grid, y_grid), cmap='viridis', alpha=0.5) for i, axis in enumerate(['x', 'y', 'z']): self.scanner.metadata['plane'].update({axis: plane[i][0]}) self.atto.surface_is_current = True loc_provider = qc.FormatLocation( fmt='./data/{date}/#{counter}_{name}_{time}') loc = loc_provider(DiskIO('.'), record={'name': 'surface'}) pathlib.Path(loc).mkdir(parents=True, exist_ok=True) fig.suptitle(loc) fig.canvas.draw() fig.show() plt.savefig(loc + '/surface.png') mdict = { 'plane': { ax: self.scanner.metadata['plane'][ax] for ax in ['x', 'y', 'z'] }, 'td_grid': { ax: self.scanner.metadata['td_grid'][ax] for ax in ['x', 'y', 'z'] } } io.savemat(loc + '/surface.mat', mdict)
def iv_tek_mod_daq(self, ivm_params: Dict[str, Any]) -> None: """Performs digital feedback on mod coil to measure flux vs. delay. AFG ch1 is used for pulse generator bias. AFG ch2 is used for comparator bias. DG ch1 is used for pulse generator trigger. Args: ivm_params: Dict of measurement parameters as definted in config_measurements json file. Returns: Tuple[Dict]: data_dict, metadict Dictionaries containing data arrays and instrument metadata. """ data_dict = {} meta_dict = {} daq_config = self.config['instruments']['daq'] ai_channels = daq_config['channels']['analog_inputs'] meas_channels = ivm_params['channels'] channels = {} for ch in meas_channels: channels.update({ch: ai_channels[ch]}) vmod = self.Q_(ivm_params['vmod_initial']).to('V').magnitude vcomp_set = self.Q_(ivm_params['vcomp_set']).to('V').magnitude vmod_low = self.Q_(ivm_params['vmod_low']).to('V').magnitude vmod_high = self.Q_(ivm_params['vmod_high']).to('V').magnitude tsettle = self.Q_(ivm_params['tsettle']).to('s').magnitude tavg = self.Q_(ivm_params['tavg']).to('s').magnitude time_constant = self.Q_(ivm_params['time_constant']) period = self.Q_(ivm_params['afg']['ch1']['period']) delay0, delay1 = [self.Q_(val).to('s').magnitude for val in ivm_params['dg']['range']] delay_vec = np.linspace(delay0, delay1, ivm_params['dg']['nsteps']) vmod_vec = np.full_like(delay_vec, np.nan, dtype=np.double) #: Set AFG pulse parameters for ch in [1, 2]: p = ivm_params['afg']['ch{}'.format(ch)] getattr(self.afg, 'voltage_high{}'.format(ch))('{}V'.format(self.Q_(p['high']).to('V').magnitude)) getattr(self.afg, 'voltage_low{}'.format(ch))('{}V'.format(self.Q_(p['low']).to('V').magnitude)) getattr(self.afg, 'pulse_period{}'.format(ch))('{}us'.format(self.Q_(p['period']).to('us').magnitude)) getattr(self.afg, 'pulse_width{}'.format(ch))('{}us'.format(self.Q_(p['width']).to('us').magnitude)) getattr(self.afg, 'pulse_trans_lead{}'.format(ch))('{}us'.format(self.Q_(p['lead']).to('us').magnitude)) getattr(self.afg, 'pulse_trans_trail{}'.format(ch))('{}us'.format(self.Q_(p['trail']).to('us').magnitude)) getattr(self.afg, 'pulse_delay{}'.format(ch))('{}us'.format(self.Q_(p['delay']).to('us').magnitude)) #: Set delay generator parameters p = ivm_params['dg'] self.dg.delay_B('A, {:e}'.format(delay0)) self.dg.delay_C('T0, {:e}'.format(self.Q_(p['ch2']['delay']).to('s').magnitude)) self.dg.delay_D('C, {:e}'.format(self.Q_(p['ch2']['width']).to('s').magnitude)) self.dg.amp_out_AB(self.Q_(p['ch1']['voltage']).to('V').magnitude) self.dg.offset_out_AB(self.Q_(p['ch1']['offset']).to('V').magnitude) self.dg.amp_out_CD(self.Q_(p['ch2']['voltage']).to('V').magnitude) self.dg.offset_out_CD(self.Q_(p['ch2']['offset']).to('V').magnitude) self.MAG_lockin.time_constant(self.Q_(ivm_params['time_constant']).to('s').magnitude) #: Get instrument metadata and prefactors lockin_snap = self.MAG_lockin.snapshot(update=True) lockin_meta = {} for param in ['time_constant', 'sensitivity', 'phase', 'reserve', 'filter_slope']: lockin_meta.update({param: lockin_snap['parameters'][param]}) meta_dict.update({'metadata': {'lockin': lockin_meta, 'afg': self.afg.snapshot(update=True), 'dg': self.dg.snapshot(update=True), 'ivm_params': ivm_params} }) #prefactor = 1 / (10 / lockin_snap['parameters']['sensitivity']['value']) #prefactor /= ivm_params['channels']['lockinX']['gain'] with nidaqmx.Task('ai_task') as ai_task, nidaqmx.Task('ao_task') as ao_task: ao = '{}/ao{}'.format(daq_config['name'], daq_config['channels']['analog_outputs']['mod']) ao_task.ao_channels.add_ao_voltage_chan(ao, 'mod') for ch, idx in channels.items(): channel = '{}/ai{}'.format(daq_config['name'], idx) ai_task.ai_channels.add_ai_voltage_chan(channel, ch) figM = plt.figure(figsize=(4,3)) axM = plt.gca() plt.xlim(min(delay_vec), max(delay_vec)) plt.xlabel(r'Delay time [$\mu$s]') plt.ylabel('Modulation Voltage [V]') figT = plt.figure(figsize=(4,3)) axT = plt.gca() plt.xlabel('Iteration number') plt.ylabel('Modulation Voltage [V]') log.info('Starting iv_tek_mod_daq.') try: #: Sweep delay time for j in range(len(delay_vec)): self.dg.delay_A('T0, {:e}'.format(delay_vec[j])) self.dg.delay_B('A, {:e}'.format(period.to('s').magnitude - delay_vec[j])) elapsed_time = 0 nsamples = 0 vmod_time = np.array([]) t0 = time.time() time.sleep(0.01) #: Do digital PID control while elapsed_time < tsettle + tavg: ai_data = ai_task.read() vcomp = ai_data[0] err = vcomp - vcomp_set vmod += P * err vmod = np.mod(vmod, vmod_high) #vmod = max(vmod, vmod_low) if vmod < 0 else min(vmod, vmod_high) ao_task.write(vmod) elapsed_time = time.time() - t0 nsamples += 1 vmod_time = np.append(vmod_time, vmod) avg_start_pt = int(nsamples * tavg // (tsettle + tavg)) vmod_vec[j] = np.mean(vmod_time[avg_start_pt:]) clear_artists(axM) axM.plot(delay_vec, vmod_vec, 'bo-') plt.tight_layout() figM.canvas.draw() clear_artists(axT) axT.plot(vmod_time, 'bo') plt.tight_layout() figT.canvas.draw() time.sleep(0.05) except KeyboardInterrupt: log.warning('Measurement aborted by user.') data_dict.update({ 'delay_vec': {'array': delay_vec, 'unit': 's'}, 'vmod_vec': {'array': vmod_vec, 'unit': 'V'} }) if ivm_params['save']: #: Get/create data location loc_provider = qc.FormatLocation(fmt='{date}/#{counter}_{name}_{time}') loc = loc_provider(DiskIO('.'), record={'name': ivm_params['fname']}) pathlib.Path(loc).mkdir(parents=True, exist_ok=True) #: Save arrays to mat io.savemat('{}/{}'.format(loc, ivm_params['fname']), data_dict) #: Save metadata to json with open(loc + '/metadata.json', 'w') as f: try: json.dump(meta_dict, f, sort_keys=True, indent=4, skipkeys=True) except TypeError: pass #: Save figures to png figM.suptitle(loc) figM.tight_layout(rect=[0, 0.03, 1, 0.95]) figM.savefig('{}/{}mod_d.png'.format(loc, ivm_params['fname'])) figT.suptitle(loc) figT.tight_layout(rect=[0, 0.03, 1, 0.95]) figT.savefig('{}/{}mod_t.png'.format(loc, ivm_params['fname'])) log.info('Data saved to {}.'.format(loc)) return data_dict, meta_dict
def iv_mod_tek(self, ivm_params: Dict[str, Any]) -> Tuple[Dict[str, Any]]: """Measures IV characteristic at different mod coil voltages. Args: ivm_params: Dict of measurement parameters as definted in config_measurements json file. Returns: Tuple[Dict]: data_dict, metadict Dictionaries containing data arrays and instrument metadata. """ data_dict = {} meta_dict = {} mod_range = [self.Q_(value).to('V').magnitude for value in ivm_params['mod_range']] bias_range = [self.Q_(value).to('V').magnitude for value in ivm_params['bias_range']] mod_vec = np.linspace(mod_range[0], mod_range[1], ivm_params['ntek2']) bias_vec = np.linspace(bias_range[0], bias_range[1], ivm_params['ntek1']) mod_grid, bias_grid = np.meshgrid(mod_vec, bias_vec) data_dict.update({ 'mod_vec': {'array': mod_vec, 'unit': 'V'}, 'bias_vec': {'array': bias_vec, 'unit': 'V'}, 'mod_grid': {'array': mod_grid, 'unit': 'V'}, 'bias_grid': {'array': bias_grid, 'unit': 'V'} }) ivmX = np.full_like(mod_grid, np.nan, dtype=np.double) ivmY = np.full_like(mod_grid, np.nan, dtype=np.double) #: Set AFG output channels self.afg.voltage_low1('0V') self.afg.voltage_high1('{}V'.format(bias_range[0])) self.afg.voltage_low2('0V') self.afg.voltage_high2('{}V'.format(mod_range[0])) self.afg.voltage_offset2('0V') #: Set pulse parameters for ch in [1, 2]: p = ivm_params['afg']['ch{}'.format(ch)] getattr(self.afg, 'pulse_period{}'.format(ch))('{}us'.format(self.Q_(p['period']).to('us').magnitude)) getattr(self.afg, 'pulse_width{}'.format(ch))('{}us'.format(self.Q_(p['width']).to('us').magnitude)) getattr(self.afg, 'pulse_trans_lead{}'.format(ch))('{}us'.format(self.Q_(p['lead']).to('us').magnitude)) getattr(self.afg, 'pulse_trans_trail{}'.format(ch))('{}us'.format(self.Q_(p['trail']).to('us').magnitude)) getattr(self.afg, 'pulse_delay{}'.format(ch))('{}us'.format(self.Q_(p['delay']).to('us').magnitude)) #: Get instrument metadata and prefactors lockin_snap = self.MAG_lockin.snapshot(update=True) lockin_meta = {} for param in ['time_constant', 'sensitivity', 'phase', 'reserve', 'filter_slope']: lockin_meta.update({param: lockin_snap['parameters'][param]}) meta_dict.update({'metadata': {'lockin': lockin_meta, 'afg': self.afg.snapshot(update=True), 'ivm_params': ivm_params} }) prefactor = 1 / (10 / lockin_snap['parameters']['sensitivity']['value']) prefactor /= ivm_params['channels']['lockinX']['gain'] delay = ivm_params['delay_factor'] * lockin_snap['parameters']['time_constant']['value'] fig, ax = plt.subplots(1, figsize=(4,3)) ax.set_xlim(min(bias_range), max(bias_range)) ax.set_xlabel('Bias [V]') ax.set_ylabel('Voltage [V]') ax.set_title(ivm_params['channels']['lockinX']['label']) log.info('Starting iv_mod_tek.') try: for j in range(len(mod_vec)): dataX, dataY, dataX_avg, dataY_avg = (np.zeros(len(mod_vec)), ) * 4 self.afg.voltage_offset2('{}V'.format(mod_vec[j])) for _ in range(ivm_params['navg']): for i in range(len(bias_vec)): self.afg.voltage_high1('{}V'.format(bias_vec[i])) time.sleep(delay) dataX[i] = self.MAG_lockin.X() dataY[i] = self.MAG_lockin.Y() dataX_avg += dataX dataY_avg += dataY dataX_avg /= ivm_params['navg'] dataY_avg /= ivm_params['navg'] ivmX[:,j] = prefactor * dataX_avg ivmY[:,j] = prefactor * dataY_avg clear_artists(ax) ax.plot(bias_vec, prefactor * dataX_avg, 'bo-') plt.tight_layout() fig.canvas.draw() fig.show() except KeyboardInterrupt: log.warning('Measurement aborted by user.') figX = plt.figure(figsize=(4,3)) plt.pcolormesh(mod_grid, bias_grid, ivmX) plt.xlabel('Modulation [V]') plt.ylabel('Bias [V]') plt.title(ivm_params['channels']['lockinX']['label']) figX.tight_layout(rect=[0, 0.03, 1, 0.95]) cbarX = plt.colorbar() cbarX.set_label('Voltage [V]') figY = plt.figure(figsize=(4,3)) plt.pcolormesh(mod_grid, bias_grid, ivmY) plt.xlabel('Modulation [V]') plt.ylabel('Bias [V]') plt.title(ivm_params['channels']['lockinY']['label']) figY.tight_layout(rect=[0, 0.03, 1, 0.95]) cbarY = plt.colorbar() cbarY.set_label('Voltage [V]') data_dict.update({ 'lockinX': {'array': ivmX, 'unit': 'V'}, 'lockinY': {'array': ivmY, 'unit': 'V'} }) if ivm_params['save']: #: Get/create data location loc_provider = qc.FormatLocation(fmt='{date}/#{counter}_{name}_{time}') loc = loc_provider(DiskIO('.'), record={'name': ivm_params['fname']}) pathlib.Path(loc).mkdir(parents=True, exist_ok=True) #: Save arrays to mat io.savemat('{}/{}'.format(loc, ivm_params['fname']), data_dict) #: Save metadata to json with open(loc + '/metadata.json', 'w') as f: try: json.dump(meta_dict, f, sort_keys=True, indent=4, skipkeys=True) except TypeError: pass #: Save figures to png figX.suptitle(loc) figX.savefig('{}/{}X.png'.format(loc, ivm_params['fname'])) figY.suptitle(loc) figY.savefig('{}/{}Y.png'.format(loc, ivm_params['fname'])) log.info('Data saved to {}.'.format(loc)) return data_dict, meta_dict