Example #1
0
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('-------------------------')
Example #2
0
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))
Example #3
0
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)
Example #4
0
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
Example #5
0
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
Example #6
0
    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)
Example #7
0
    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
Example #8
0
    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