Esempio n. 1
0
def sweep_awg_chans(meas_param,
                    awg_ch_1,
                    awg_ch_2,
                    start,
                    stop,
                    step,
                    delay=0.01,
                    do_plots=True):
    """
    Sweeps two awg channels at once and is otherwise the same as sweep1d

    Args:
        meas_param: parameter which we want the value of at each point
        awg_ch_1: one of the awg channels to vary
        awg_ch_2: one of the awg channels to vary
        start: starting value for awg channels
        stop: final value for awg channels
        step: value to step awg channels
        delay (default 0.01): mimimum time to spend on each point
        do_plots: Default True: If False no plots are produced.
            Data is still saved and can be displayed with show_num.

    Returns:
        data (qcodes dataset)
        plot: QT plot
    """
    loop = qc.Loop(awg_ch_1.sweep(start, stop, step)).each(
        qc.Task(awg_ch_2.set, awg_ch_1.get), meas_param)
    set_params = ((awg_ch_1, start, stop, step), )
    meas_params = _select_plottables(meas_param)

    plot, data = _do_measurement(loop,
                                 set_params,
                                 meas_params,
                                 do_plots=do_plots)

    return data, plot
Esempio n. 2
0
def do1dDiagonal(inst_set, inst2_set, start, stop, num_points,
                 delay, start2, slope, *inst_meas, do_plots=True):
    """
    Perform diagonal sweep in 1 dimension, given two instruments

    Args:
        inst_set:  Instrument to sweep over
        inst2_set: Second instrument to sweep over
        start:  Start of sweep
        stop:  End of sweep
        num_points:  Number of steps to perform
        delay:  Delay at every step
        start2:  Second start point
        slope:  slope of the diagonal cut
        *inst_meas:  any number of instrument to measure
        do_plots: Default True: If False no plots are produced.
            Data is still saved and can be displayed with show_num.

    Returns:
        plot, data : returns the plot and the dataset

    """

    # (WilliamHPNielsen) If I understand do1dDiagonal correctly, the inst2_set
    # is supposed to be varied secretly in the background
    set_params = ((inst_set, start, stop),)
    meas_params = _select_plottables(inst_meas)

    slope_task = qc.Task(inst2_set, (inst_set)*slope+(slope*start-start2))

    loop = qc.Loop(inst_set.sweep(start, stop, num=num_points),
                   delay).each(slope_task, *inst_meas, inst2_set)

    plot, data = _do_measurement(loop, set_params, meas_params,
                                 do_plots=do_plots)

    return plot, data
def pb(diff):
    pulse_builder.averages(int(pulse_builder.averages() + diff))
    print(pulse_builder.averages())
    
def QubitPower(pulse_builder,qubit,pwr):
    qubit.power(pwr)    
​
def compensate_cutter(cutter_gate, plunger_gate, slope, offset):
    current_plunger_voltage = plunger_gate()
    compensated_cutter_voltage = -slope * current_plunger_voltage + offset
    cutter_gate(compensated_cutter_voltage)
   
# def set_localos(localos, cavity, USE_DEMOD_FREQ):
#     localos.frequency(cavity.frequency()+USE_DEMOD_FREQ)
​
Alazar_Cavset_Task = qc.Task(partial(Alazar_Cavset,cal_traces,pulse_builder,switch,qubit,cavity,detuning=0.3e6))
Alazar_SingleCavset_Task = qc.Task(partial(Alazar_SingleCavset,vna.S21_1.trace,pulse_builder.readout_freq_1,switch,qubit,cavity,detuning=0.3e6))
CavPrep_Task = qc.Task(partial(CavPrep,switch,qubit,cavity))
# LocalosPrep_taks = qc.Task(partial(set_localos,localos, cavity, USE_DEMOD_FREQ))
​
​
​
​
​
​
#%%
#Example measurement: Non overlapping spectroscopy with Alazar and AWG; we assume that we did spectroscopy with the VNA beforehand and know the resonator frequency and a range for the qubit frequency
#In this measurement a qubit pulse is sent out first and directly afterwards a readout tone. If the qubit lifetime is sufficiently high we should see a peak in I and Q and knowing that the qubit didn't decay immediately back to the groundstate after the qubit drive
​
#prepare switches and instruments
​
Esempio n. 4
0
def twod_param_sweep(SetParam1,
                     SetArray1,
                     SetParam2,
                     SetArray2,
                     *MeasParams,
                     SetDelay1=0,
                     SetDelay2=0,
                     Param2_SetBetween=None,
                     DataName='',
                     ZParam=None,
                     plot_results=True,
                     save_plots=True):
    """ Single parameter sweep, single measure (for more measurements, add
    parameters to the .each() part). Includes live plot. Note: if the SetParam1
    array is nonuniform, the y axis of the plot will be messed up. Try MatPlot
    instead of QtPlot in that situation.

    Returns: data (a qcodes DataSet object), plot

    Arguments:
    SetParam1: The outer parameter to sweep (such as a temperature)
    SetArray1: should be a list or numpy array of values you want to set
                SetParam1 to. This array will be run through once
    SetParam2: The inner parameter to sweep (such as a voltage)
    Param2_SetBetween: Sets parameter 2 to this value at the end of each
                sweep of the parameter (completion of one row) and before
                changing parameter 1.
    SetArray1: should be a list or numpy array of values you want to set
                SetParam2 to. This array will be run through for each value of
                SetArray1
    MeasParams: The parameter(s) you want to measure at each setpoint
    Keyword Arguments:
    SetDelay1: The delay time between when SetParam1 is set till the SetParam2
                is set to its first value (0 by default)
    SetDelay2: Delay time between when SetParam2 is set and the MeasParam
                is measured (0 by default)
    DataName: A name to tag the data (defaults to nothing)
    ZParam: Allows you to pick only a few parameters to plot out of those
                measured. (if not mentioned, will plot all *MeasParams)
    plot_results: True by default, if false, suppresses plotting
    save_plots: True by default. If false, doesn't save plots at the end of the
                sweep
    """

    if Param2_SetBetween is None:

        def between_func():
            pass
    else:

        def between_func():
            SetParam2(Param2_SetBetween)
            return

    innerloop = qc.Loop(SetParam2[SetArray2],
                        delay=SetDelay2).each(*MeasParams)
    twodloop = qc.Loop(SetParam1[SetArray1],
                       delay=SetDelay1).each(innerloop, qc.Task(between_func))
    data = twodloop.get_data_set(name=DataName)
    plot = []

    def _plot_update():
        if type(plot) is list:
            for p in plot:
                p.update()
        else:
            plot.update()

    def _plot_save():
        if type(plot) is list:
            for i in range(len(plot)):
                fname = '{}_{}.png'.format(plot[i].get_default_title(),
                                           str(ZParam[i]))
                plot[i].save(filename=fname)
        else:
            fname = '{}_{}.png'.format(plot.get_default_title(),
                                       str(*MeasParams))
            plot.save(filename=fname)

    if plot_results:
        if len(MeasParams) == 1:
            plot = qc.QtPlot(getattr(data, str(*MeasParams)),
                             window_title=str(*MeasParams))
            twodloop.with_bg_task(plot.update)
        else:
            if ZParam is None:
                ZParam = MeasParams
            if type(ZParam) is not list and type(ZParam) is not tuple:
                ZParam = [ZParam]

            for zp in ZParam:
                plot.append(
                    qc.QtPlot(getattr(data, str(zp)), window_title=str(zp)))

            twodloop.with_bg_task(_plot_update)

    try:
        twodloop.run()
        if save_plots and plot_results:
            _plot_save()
        return data, plot
    except KeyboardInterrupt:
        if plot_results:
            _plot_update()
            if save_plots:
                _plot_save()
        print('Keyboard Interrupt')
        return data, plot
    vna.channels[i].format('Linear Magnitude')
    cal_traces.append(vna.channels[i].trace)
#vna.display_grid(2,2)
vna.rf_power(1)
switch.all(2)
time.sleep(2)
vna.channels.autoscale()
vna.channels.status(0)

from scripts.Task_functions import Alazar_Cavset, CavPrep
from functools import partial

Alazar_Cavset_Task = qc.Task(
    partial(Alazar_Cavset,
            cal_traces,
            pulse_builder,
            switch,
            qubit,
            detuning=-1e6))
CavPrep_Task = qc.Task(partial(CavPrep, switch, qubit))

#%% Stuff added by OE

# Short-hand measurement handles
twotone = [
    CavPrep_Task, vna.S21_1.trace, Alazar_Cavset_Task,
    alazar_ctrl.channels[12:14].data
]
vnat = [vna.S21_1.trace]

Esempio n. 6
0
    def scan_surface(self, scan_params: Dict[str, Any]) -> None:
        """
        Scan the current surface while acquiring data in the channels defined in
        measurement configuration file (e.g. MAG, SUSCX, SUSCY, CAP).
        
        Args:
            scan_params: Dict of scan parameters as defined
                in measuremnt configuration file.
        Returns:
            None
        """
        if not self.atto.surface_is_current:
            raise RuntimeError('Surface is not current. Aborting scan.')
        surface_type = scan_params['surface_type'].lower()
        if surface_type not in ['plane', 'surface']:
            raise ValueError('surface_type must be "plane" or "surface".')

        old_pos = self.scanner.position()

        daq_config = self.config['instruments']['daq']
        ao_channels = daq_config['channels']['analog_outputs']
        ai_channels = daq_config['channels']['analog_inputs']
        meas_channels = scan_params['channels']
        channels = {}
        for ch in meas_channels:
            channels.update({ch: ai_channels[ch]})
        nchannels = len(channels.keys())

        daq_name = daq_config['name']
        #: DAQ AI sampling rate is divided amongst all active AI channels
        daq_rate = self.Q_(daq_config['rate']).to('Hz').magnitude / nchannels

        fast_ax = scan_params['fast_ax'].lower()
        slow_ax = 'x' if fast_ax == 'y' else 'y'

        pix_per_line = scan_params['scan_size'][fast_ax]
        line_duration = pix_per_line * self.ureg('pixels') / self.Q_(
            scan_params['scan_rate'])
        pts_per_line = int(daq_rate * line_duration.to('s').magnitude)
        height = self.Q_(scan_params['height']).to('V').magnitude

        if 1 / self.Q_(scan_params['scan_rate']).to(
                'pixels/s').magnitude < self.SUSC_lockin.time_constant():
            warning = 'Averaging time per pixel is less than the SUSC_lockin time constant. '
            warning += 'For reliable susceptibility data, averaging time per pixel should be '
            warning += 'significantly greater than the SUSC_lockin time constant.'
            log.warning(warning)

        scan_vectors = utils.make_scan_vectors(scan_params, self.ureg)
        #scan_grids = utils.make_scan_grids(scan_vectors, slow_ax, fast_ax,
        #                                   pts_per_line, plane, height)
        plane = self.scanner.metadata['plane']
        if surface_type == 'plane':
            scan_grids = utils.make_scan_surface(surface_type, scan_vectors,
                                                 slow_ax, fast_ax,
                                                 pts_per_line, plane, height)
        else:
            scan_grids = utils.make_scan_surface(
                surface_type,
                scan_vectors,
                slow_ax,
                fast_ax,
                pts_per_line,
                plane,
                height,
                interpolator=self.scanner.surface_interp)
        utils.validate_scan_params(self.scanner.metadata, scan_params,
                                   scan_grids, pix_per_line, pts_per_line,
                                   self.temp, self.ureg, log)
        self.scanner.goto([scan_grids[axis][0][0] for axis in ['x', 'y', 'z']])
        self.set_lockins(scan_params)
        #: get channel prefactors in pint Quantity form
        prefactors = self.get_prefactors(scan_params)
        #: get channel prefactors in string form so they can be saved in metadata
        prefactor_strs = {}
        for ch, prefac in prefactors.items():
            unit = scan_params['channels'][ch]['unit']
            pre = prefac.to('{}/V'.format(unit))
            prefactor_strs.update(
                {ch: '{} {}'.format(pre.magnitude, pre.units)})
        ai_task = nidaqmx.Task('scan_plane_ai_task')
        self.remove_component('daq_ai')
        if hasattr(self, 'daq_ai'):
            #self.daq_ai.clear_instances()
            self.daq_ai.close()
        self.daq_ai = DAQAnalogInputs(
            'daq_ai',
            daq_name,
            daq_rate,
            channels,
            ai_task,
            samples_to_read=pts_per_line,
            target_points=pix_per_line,
            #: Very important to synchronize AOs and AIs
            clock_src='ao/SampleClock')
        self.add_component(self.daq_ai)
        slow_ax_position = getattr(self.scanner, 'position_{}'.format(slow_ax))
        slow_ax_start = scan_vectors[slow_ax][0]
        slow_ax_end = scan_vectors[slow_ax][-1]
        slow_ax_step = scan_vectors[slow_ax][1] - scan_vectors[slow_ax][0]
        #: There is probably a counter built in to qc.Loop, but I couldn't find it
        loop_counter = utils.Counter()
        scan_plot = ScanPlot(scan_params, self.ureg)
        loop = qc.Loop(
            slow_ax_position.sweep(start=slow_ax_start,
                                   stop=slow_ax_end,
                                   step=slow_ax_step),
            delay=0.1
        ).each(
            #: Create AO task and queue data to be written to AOs
            qc.Task(self.scanner.scan_line, scan_grids, ao_channels, daq_rate,
                    loop_counter),
            #: Start AI task; acquisition won't start until AO task is started
            qc.Task(ai_task.start),
            #: Start AO task
            qc.Task(self.scanner.control_ao_task, 'start'),
            #: Acquire voltage from all active AI channels
            self.daq_ai.voltage,
            qc.Task(ai_task.wait_until_done),
            qc.Task(self.scanner.control_ao_task, 'wait_until_done'),
            qc.Task(ai_task.stop),
            #: Stop and close AO task so that AOs can be used for goto
            qc.Task(self.scanner.control_ao_task, 'stop'),
            qc.Task(self.scanner.control_ao_task, 'close'),
            qc.Task(self.scanner.goto_start_of_next_line, scan_grids,
                    loop_counter),
            #: Update and save plot
            qc.Task(scan_plot.update, qc.loops.active_data_set, loop_counter),
            qc.Task(scan_plot.save),
            qc.Task(loop_counter.advance)
        ).then(
            qc.Task(ai_task.stop),
            qc.Task(ai_task.close),
            qc.Task(self.daq_ai.close),
            #qc.Task(self.daq_ai.clear_instances),
            qc.Task(self.scanner.goto, old_pos),
            #qc.Task(self.CAP_lockin.amplitude, 0.004),
            #qc.Task(self.SUSC_lockin.amplitude, 0.004)
        )
        #: loop.metadata will be saved in DataSet
        loop.metadata.update(scan_params)
        loop.metadata.update({'prefactors': prefactor_strs})
        for idx, ch in enumerate(meas_channels):
            loop.metadata['channels'][ch].update({'idx': idx})
        data = loop.get_data_set(name=scan_params['fname'])
        #: Run the loop
        try:
            loop.run()
            log.info('Scan completed. DataSet saved to {}.'.format(
                data.location))
        #: If loop is aborted by user:
        except KeyboardInterrupt:
            log.warning(
                'Scan aborted by user. Going to [0,0,0] V. DataSet saved to {}.'
                .format(data.location))
        finally:
            try:
                #: Stop 'scan_plane_ai_task' so that we can read our current position
                ai_task.stop()
                ai_task.close()
                #: If there's an active AO task, close it so that we can use goto
                self.scanner.control_ao_task('stop')
                self.scanner.control_ao_task('close')
                self.remove_component('daq_ai')
            except:
                pass
        self.scanner.goto([0, 0, 0])
        #self.CAP_lockin.amplitude(0.004)
        #self.SUSC_lockin.amplitude(0.004)
        utils.scan_to_mat_file(data,
                               real_units=True,
                               interpolator=self.scanner.surface_interp)
Esempio n. 7
0
    def td_cap(self,
               tdc_params: Dict[str, Any],
               update_snap: bool = True) -> Tuple[Any]:
        """Performs a capacitive touchdown.

        Args:
            tdc_params: Dict of capacitive touchdown parameters as defined
                in measurement configuration file.
            update_snap: Whether to update the microscope snapshot. Default True.
                (You may want this to be False when getting a plane or approaching.)
        Returns:
            Tuple[qcodes.DataSet, plots.TDCPlot]: data, tdc_plot
                DataSet and plot generated by the touchdown Loop.
        """
        old_pos = self.scanner.position()
        constants = tdc_params['constants']
        daq_config = self.config['instruments']['daq']
        daq_name = daq_config['name']
        ai_channels = daq_config['channels']['analog_inputs']
        meas_channels = tdc_params['channels']
        channels = {}
        for ch in meas_channels:
            channels.update({ch: ai_channels[ch]})
        nchannels = len(channels.keys())
        daq_rate = self.Q_(daq_config['rate']).to('Hz').magnitude / nchannels
        self.set_lockins(tdc_params)
        self.snapshot(update=update_snap)
        #: z position voltage step
        dV = self.Q_(tdc_params['dV']).to('V').magnitude
        #: Start and end z position voltages
        startV, endV = sorted(
            [self.Q_(lim).to('V').magnitude for lim in tdc_params['range']])
        delay = constants['wait_factor'] * max(
            self.CAP_lockin.time_constant(), self.SUSC_lockin.time_constant())
        prefactors = self.get_prefactors(tdc_params)
        #: get channel prefactors in string form so they can be saved in metadata
        prefactor_strs = {}
        for ch, prefac in prefactors.items():
            unit = tdc_params['channels'][ch]['unit']
            pre = prefac.to('{}/V'.format(unit))
            prefactor_strs.update(
                {ch: '{} {}'.format(pre.magnitude, pre.units)})
        ai_task = nidaqmx.Task('td_cap_ai_task')
        self.remove_component('daq_ai')
        if hasattr(self, 'daq_ai'):
            #self.daq_ai.clear_instances()
            self.daq_ai.close()
        self.daq_ai = DAQAnalogInputs('daq_ai', daq_name, daq_rate, channels,
                                      ai_task)
        loop_counter = utils.Counter()
        tdc_plot = TDCPlot(tdc_params, self.ureg)
        loop = qc.Loop(self.scanner.position_z.sweep(startV, endV, dV)).each(
            qc.Task(time.sleep, delay), self.daq_ai.voltage,
            qc.Task(self.scanner.check_for_td, tdc_plot,
                    qc.loops.active_data_set, loop_counter),
            qc.Task(self.scanner.get_td_height, tdc_plot),
            qc.BreakIf(lambda scanner=self.scanner: scanner.break_loop or
                       scanner.td_has_occurred), qc.Task(loop_counter.advance)
        ).then(
            qc
            .Task(ai_task.stop),
            qc.
            Task(ai_task.close
                 ),
            #qc.Task(self.CAP_lockin.amplitude, 0.004),
            #qc.Task(self.SUSC_lockin.amplitude, 0.004),
            qc.Task(self.scanner.retract),
            qc.Task(tdc_plot.fig.show),
            qc.Task(tdc_plot.save))
        #: loop.metadata will be saved in DataSet
        loop.metadata.update(tdc_params)
        loop.metadata.update({'prefactors': prefactor_strs})
        for idx, ch in enumerate(meas_channels):
            loop.metadata['channels'][ch].update({'idx': idx})
        data = loop.get_data_set(name=tdc_params['fname'], write_period=None)
        try:
            log.info('Starting capacitive touchdown.')
            loop.run()
            if self.scanner.td_height is not None:
                data.metadata['loop']['metadata'].update(
                    {'td_height': self.scanner.td_height})
                if abs(old_pos[0]) < 0.01 and abs(old_pos[1]) < 0.01:
                    self.scanner.metadata['plane'].update(
                        {'z': self.scanner.td_height})
        except KeyboardInterrupt:
            log.warning(
                'Touchdown interrupted by user. Retracting scanner. DataSet saved to {}.'
                .format(data.location))
            #: Set break_loop = True so that get_plane() and approach() will be aborted
            self.scanner.break_loop = True
        finally:
            try:
                #: Stop 'td_cap_ai_task' so that we can read our current position
                ai_task.stop()
                ai_task.close()
                self.scanner.retract()
                #self.CAP_lockin.amplitude(0.004)
                tdc_plot.fig.show()
                tdc_plot.save()
            except:
                pass
        utils.td_to_mat_file(data, real_units=True)
        return data, tdc_plot
Esempio n. 8
0
step_param.set = step_setter


def make_things_right():
    prepareZIUHFLI(zi,
                   demod_freq,
                   npts,
                   SRstring,
                   no_of_avgs,
                   meastime,
                   outputpwr,
                   single_channel=single_channel)
    zi.Scope.prepare_scope()


resetTask = qc.Task(make_things_right)
make_things_right()
awg.ch1_state(1)
awg.run()

p1 = hightimes[0]
p2 = hightimes[-1]
num = len(hightimes)

try:
    #innerloop = qc.Loop(step_param.sweep(p1, p2, num=num), delay=0.01).each(zi.scope_full_avg_ch1,
    #             resetTask)
    #outerloop = qc.Loop(qdac.ch48.v.sweep(-2.658, -2.64, num=50), delay=1).each(innerloop)
    #data = outerloop.get_data_set(name='testsweep')
    #plot = qc.QtPlot()
    #plot.add(data.arrays['ziuhfli_scope_full_avg_ch1'])  # add a graph to the plot
def do2Dconductance(outer_param: Parameter,
                    outer_start: Union[float, int],
                    outer_stop: Union[float, int],
                    outer_npts: int,
                    inner_param: Parameter,
                    inner_start: Union[float, int],
                    inner_stop: Union[float, int],
                    inner_npts: int,
                    lockin: SR830_T3,
                    delay: Optional[float]=None):
    """
    Function to perform a sped-up 2D conductance measurement

    Args:
        outer_param: The outer loop voltage parameter
        outer_start: The outer loop start voltage
        outer_stop: The outer loop stop voltage
        outer_npts: The number of points in the outer loop
        inner_param: The inner loop voltage parameter
        inner_start: The inner loop start voltage
        inner_stop: The inner loop stop voltage
        inner_npts: The number of points in the inner loop
        lockin: The lock-in amplifier to use
        delay: Delay to wait after setting inner parameter before triggering lockin.
          If None will use default delay, otherwise used the supplied.
    """
    station = qc.Station.default

    sr = lockin

    # Validate the instruments
    if sr.name not in station.components:
        raise KeyError('Unknown lock-in! Refusing to proceed until the '
                       'lock-in has been added to the station.')
    if (outer_param._instrument.name not in station.components and
        outer_param._instrument._parent.name not in station.components):
        raise KeyError('Unknown instrument for outer parameter. '
                       'Please add that instrument to the station.')
    if (inner_param._instrument.name not in station.components and
        inner_param._instrument._parent.name not in station.components):
        raise KeyError('Unknown instrument for inner parameter. '
                       'Please add that instrument to the station.')

    tau = sr.time_constant()
    min_delay = 0.002  # what's the physics behind this number?
    if delay is None:
        delay = tau + min_delay
    # Prepare for the first iteration
    # Some of these things have to be repeated during the loop
    sr.buffer_reset()
    sr.buffer_start()
    #sr.buffer_trig_mode('ON')
    sr.buffer_SR('Trigger')
    sr.conductance.shape = (inner_npts,)
    sr.conductance.setpoint_names = (inner_param.name,)
    sr.conductance.setpoint_labels = (inner_param.label,)
    sr.conductance.setpoint_units = ('V',)
    sr.conductance.setpoints = (tuple(np.linspace(inner_start,
                                                  inner_stop,
                                                  inner_npts)),)

    def trigger():
        sleep(delay)
        sr.send_trigger()

    def prepare_buffer():
        # here it should be okay to call ch1_databuffer... I think...
        sr.ch1_databuffer.prepare_buffer_readout()
        # For the dataset/plotting, put in the correct setpoints
        sr.conductance.setpoint_names = (inner_param.name,)
        sr.conductance.setpoint_labels = (inner_param.label,)
        sr.conductance.setpoint_units = ('V',)
        sr.conductance.setpoints = (tuple(np.linspace(inner_start,
                                                      inner_stop,
                                                      inner_npts)),)

    def start_buffer():
        sr.buffer_start()
        sr.conductance.shape = (inner_npts,)  # This is something

    def reset_buffer():
        sr.buffer_reset()

    trig_task = qc.Task(trigger)
    reset_task = qc.Task(reset_buffer)
    start_task = qc.Task(start_buffer)
    inner_loop = qc.Loop(inner_param.sweep(inner_start,
                                           inner_stop,
                                           num=inner_npts)).each(trig_task)
    outer_loop = qc.Loop(outer_param.sweep(outer_start,
                                           outer_stop,
                                           num=outer_npts)).each(start_task,
                                                                 inner_loop,
                                                                 sr.conductance,
                                                                 reset_task)

    set_params = ((inner_param, inner_start, inner_stop),
                  (outer_param, outer_start, outer_stop))
    meas_params = (sr.conductance,)
    prepare_buffer()
    qdac = None
    # ensure that any waveform generator is unbound from the qdac channels that we step if
    # we are stepping the qdac
    if isinstance(inner_param._instrument, QDacch):
        qdacch = inner_param._instrument
        qdacch.slope('Inf')
    if isinstance(outer_param._instrument, QDacch):
        qdacch = outer_param._instrument
        qdacch.slope('Inf')
    if qdac:
        qdac.fast_voltage_set(True)  # now that we have unbound the function generators
                                     # we don't need to do it in the loop
        qdac.voltage_set_dont_wait(False)  # this is un safe and highly experimental
    plot, data = _do_measurement(outer_loop, set_params, meas_params, do_plots=True)
    return plot, data