Ejemplo n.º 1
0
def scan2D_keysight(gate1,
                    swing1,
                    n_pt1,
                    gate2,
                    swing2,
                    n_pt2,
                    t_step,
                    pulse_lib,
                    dig_mode,
                    biasT_corr=False):

    segment = pulse_lib.mk_segment()

    segment.add_HVI_variable("t_measure", int(t_step))
    segment.add_HVI_variable("number_of_points", int(n_pt1 * n_pt2))
    segment.add_HVI_variable("averaging", True)

    sweep_channel = getattr(segment, gate1)
    step_channel = getattr(segment, gate2)

    # set up timing for the scan
    # 2us needed to re-arm digitizer
    # 100ns HVI waiting time
    # [SdS] Why is the value below 120 ns?
    if dig_mode == MODES.NORMAL:
        step_eff = 1800 + t_step
    else:
        step_eff = t_step + Hvi2VideoMode.get_acquisition_gap(
            dig, acquisition_delay_ns)

    # set up sweep voltages (get the right order, to compenstate for the biasT).
    vp1 = swing1 / 2
    vp2 = swing2 / 2

    # set point voltages
    voltages1_sp = np.linspace(-vp1, vp1, n_pt1)
    voltages2_sp = np.linspace(-vp2, vp2, n_pt2)

    if biasT_corr == True:
        voltages2 = np.zeros(n_pt2)
        voltages2[::2] = voltages2_sp[:len(voltages2[::2])]
        voltages2[1::2] = voltages2_sp[-len(voltages2[1::2]):][::-1]
    else:
        voltages2 = voltages2_sp

    sweep_channel.add_ramp_ss(0, step_eff * n_pt1, -vp1, vp1)
    sweep_channel.repeat(n_pt1)

    for voltage in voltages2:
        step_channel.add_block(0, step_eff * n_pt1, voltage)
        step_channel.reset_time()

    # 100 time points per step to make sure that everything looks good (this is more than needed).
    awg_t_step = t_step / 10
    sample_rate = 1 / (awg_t_step * 1e-9)

    # generate the sequence and upload it.
    my_seq = pulse_lib.mk_sequence([segment])
    my_seq.sample_rate = sample_rate

    return my_seq
Ejemplo n.º 2
0
def construct_2D_scan_fast(gate1,
                           swing1,
                           n_pt1,
                           gate2,
                           swing2,
                           n_pt2,
                           t_step,
                           biasT_corr,
                           pulse_lib,
                           digitizer,
                           channels,
                           dig_samplerate,
                           dig_vmax=2.0,
                           iq_mode=None,
                           acquisition_delay_ns=None,
                           enabled_markers=[],
                           channel_map=None,
                           pulse_gates={},
                           line_margin=0):
    """
    2D fast scan parameter constructor.

    Args:
        gates1 (str) : gate that you want to sweep on x axis.
        swing1 (double) : swing to apply on the AWG gates.
        n_pt1 (int) : number of points to measure (current firmware limits to 1000)
        gate2 (str) : gate that you want to sweep on y axis.
        swing2 (double) : swing to apply on the AWG gates.
        n_pt2 (int) : number of points to measure (current firmware limits to 1000)
        t_step (double) : time in ns to measure per point.
        biasT_corr (bool) : correct for biasT by taking data in different order.
        pulse_lib : pulse library object, needed to make the sweep.
        digitizer_measure : digitizer object
        iq_mode (str or dict): when digitizer is in MODE.IQ_DEMODULATION then this parameter specifies how the
                complex I/Q value should be plotted: 'I', 'Q', 'abs', 'angle', 'angle_deg'. A string applies to
                all channels. A dict can be used to speicify selection per channel, e.g. {1:'abs', 2:'angle'}
                Note: channel_map is a more generic replacement for iq_mode.
        acquisition_delay_ns (float):
                Time in ns between AWG output change and digitizer acquisition start.
                This also increases the gap between acquisitions.
        enable_markers (List[str]): marker channels to enable during scan
        channel_map (Dict[str, Tuple(int, Callable[[np.ndarray], np.ndarray])]):
            defines new list of derived channels to display. Dictionary entries name: (channel_number, func).
            E.g. {(ch1-I':(1, np.real), 'ch1-Q':(1, np.imag), 'ch3-Amp':(3, np.abs), 'ch3-Phase':(3, np.angle)}
            The default channel_map is:
                {'ch1':(1, np.real), 'ch2':(2, np.real), 'ch3':(3, np.real), 'ch4':(4, np.real)}
        pulse_gates (Dict[str, float]):
            Gates to pulse during scan with pulse voltage in mV.
            E.g. {'vP1': 10.0, 'vB2': -29.1}
        line_margin (int): number of points to add to sweep 1 to mask transition effects due to voltage step.
            The points are added to begin and end for symmetry (bias-T).

    Returns:
        Parameter (QCODES multiparameter) : parameter that can be used as input in a conversional scan function.
    """
    logging.info(f'Construct 2D: {gate1} {gate2}')

    # set up timing for the scan
    step_eff = t_step + Hvi2VideoMode.get_acquisition_gap(
        digitizer, acquisition_delay_ns)

    if step_eff < 200:
        msg = f'Measurement time too short. Minimum is {t_step + 200-step_eff}'
        logging.error(msg)
        raise Exception(msg)

    line_margin = int(line_margin)
    add_pulse_gate_correction = biasT_corr and len(pulse_gates) > 0

    # set up sweep voltages (get the right order, to compenstate for the biasT).
    vp1 = swing1 / 2
    vp2 = swing2 / 2

    voltages1_sp = np.linspace(-vp1, vp1, n_pt1)
    voltages2_sp = np.linspace(-vp2, vp2, n_pt2)

    n_ptx = n_pt1 + 2 * line_margin
    vpx = vp1 * (n_ptx - 1) / (n_pt1 - 1)

    if biasT_corr:
        m = (n_pt2 + 1) // 2
        voltages2 = np.zeros(n_pt2)
        voltages2[::2] = voltages2_sp[:m]
        voltages2[1::2] = voltages2_sp[m:][::-1]
    else:
        voltages2 = voltages2_sp

    start_delay = line_margin * step_eff
    if biasT_corr:
        # prebias: add half line with +vp2
        prebias_pts = (n_ptx) // 2
        t_prebias = prebias_pts * step_eff
        start_delay += t_prebias

    line_delay_pts = 2 * line_margin
    if add_pulse_gate_correction:
        line_delay_pts += n_ptx

    seg = pulse_lib.mk_segment()

    g1 = seg[gate1]
    g2 = seg[gate2]
    pulse_channels = []
    for ch, v in pulse_gates.items():
        pulse_channels.append((seg[ch], v))

    if biasT_corr:
        # pulse on fast gate to pre-charge bias-T
        g1.add_block(0, t_prebias, vpx * 0.35)
        # correct voltage to ensure average == 0.0 (No DC correction pulse needed at end)
        # Note that voltage on g2 ends center of sweep, i.e. (close to) 0.0 V
        total_duration = prebias_pts + n_ptx * n_pt2 * (
            2 if add_pulse_gate_correction else 1)
        g2.add_block(0, -1, -(prebias_pts * vp2) / total_duration)
        g2.add_block(0, t_prebias, vp2)
        for g, v in pulse_channels:
            g.add_block(0, t_prebias, -v)
        seg.reset_time()

    for v2 in voltages2:

        g1.add_ramp_ss(0, step_eff * n_ptx, -vpx, vpx)
        g2.add_block(0, step_eff * n_ptx, v2)
        for g, v in pulse_channels:
            g.add_block(0, step_eff * n_ptx, v)
        seg.reset_time()

        if add_pulse_gate_correction:
            # add compensation pulses of pulse_channels
            # sweep g1 onces more; best effect on bias-T
            # keep g2 on 0
            g1.add_ramp_ss(0, step_eff * n_ptx, -vpx, vpx)
            for g, v in pulse_channels:
                g.add_block(0, step_eff * n_ptx, -v)
            seg.reset_time()

    if biasT_corr:
        # pulses to discharge bias-T
        # Note: g2 is already 0.0 V
        g1.add_block(0, t_prebias, -vpx * 0.35)
        for g, v in pulse_channels:
            g.add_block(0, t_prebias, +v)
        seg.reset_time()

    end_time = seg.total_time[0]
    for marker in enabled_markers:
        marker_ch = seg[marker]
        marker_ch.reset_time(0)
        marker_ch.add_marker(0, end_time)

    # 20 time points per step to make sure that everything looks good (this is more than needed).
    awg_t_step = step_eff / 20
    # prescaler is limited to 255 when hvi_queueing_control is enabled.
    # Limit all cases to 800 kSa/s
    if awg_t_step > 5 * 250:
        awg_t_step = 5 * 250

    sample_rate = 1 / (awg_t_step * 1e-9)

    seg.add_HVI_variable("t_measure", int(t_step))
    seg.add_HVI_variable("start_delay", int(start_delay))
    if line_delay_pts > 0:
        seg.add_HVI_variable("number_of_points", int(n_pt1))
        seg.add_HVI_variable("number_of_lines", int(n_pt2))
        seg.add_HVI_variable("line_delay", int(line_delay_pts * step_eff))
    else:
        seg.add_HVI_variable("number_of_points", int(n_pt1 * n_pt2))
        seg.add_HVI_variable("number_of_lines", int(1))
        # Wait minimum time to satisfy HVI schedule
        seg.add_HVI_variable("line_delay", 500)
    seg.add_HVI_variable("averaging", True)

    # generate the sequence and upload it.
    my_seq = pulse_lib.mk_sequence([seg])
    logging.info(f'Add HVI')
    my_seq.set_hw_schedule(
        Hvi2ScheduleLoader(pulse_lib,
                           'VideoMode',
                           digitizer,
                           acquisition_delay_ns=acquisition_delay_ns))
    my_seq.n_rep = 1
    my_seq.sample_rate = sample_rate

    logging.info(f'Seq upload')
    my_seq.upload()

    return _digitzer_scan_parameter(digitizer,
                                    my_seq,
                                    pulse_lib,
                                    t_step, (n_pt2, n_pt1), (gate2, gate1),
                                    (tuple(voltages2_sp),
                                     (tuple(voltages1_sp), ) * n_pt2),
                                    biasT_corr,
                                    dig_samplerate,
                                    channels=channels,
                                    Vmax=dig_vmax,
                                    iq_mode=iq_mode,
                                    channel_map=channel_map)
Ejemplo n.º 3
0
def construct_1D_scan_fast(gate,
                           swing,
                           n_pt,
                           t_step,
                           biasT_corr,
                           pulse_lib,
                           digitizer,
                           channels,
                           dig_samplerate,
                           dig_vmax=2.0,
                           iq_mode=None,
                           acquisition_delay_ns=None,
                           enabled_markers=[],
                           channel_map=None):
    """
    1D fast scan object for V2.

    Args:
        gate (str) : gate/gates that you want to sweep.
        swing (double) : swing to apply on the AWG gates.
        n_pt (int) : number of points to measure (current firmware limits to 1000)
        t_step (double) : time in ns to measure per point.
        biasT_corr (bool) : correct for biasT by taking data in different order.
        pulse_lib : pulse library object, needed to make the sweep.
        digitizer_measure : digitizer object
        iq_mode (str or dict): when digitizer is in MODE.IQ_DEMODULATION then this parameter specifies how the
                complex I/Q value should be plotted: 'I', 'Q', 'abs', 'angle', 'angle_deg'. A string applies to
                all channels. A dict can be used to specify selection per channel, e.g. {1:'abs', 2:'angle'}.
                Note: channel_map is a more generic replacement for iq_mode.
        acquisition_delay_ns (float):
                Time in ns between AWG output change and digitizer acquisition start.
                This also increases the gap between acquisitions.
        enable_markers (List[str]): marker channels to enable during scan
        channel_map (Dict[str, Tuple(int, Callable[[np.ndarray], np.ndarray])]):
            defines new list of derived channels to display. Dictionary entries name: (channel_number, func).
            E.g. {(ch1-I':(1, np.real), 'ch1-Q':(1, np.imag), 'ch3-Amp':(3, np.abs), 'ch3-Phase':(3, np.angle)}
            The default channel_map is:
                {'ch1':(1, np.real), 'ch2':(2, np.real), 'ch3':(3, np.real), 'ch4':(4, np.real)}

    Returns:
        Paramter (QCODES multiparameter) : parameter that can be used as input in a conversional scan function.
    """

    charge_st_1D = pulse_lib.mk_segment()

    vp = swing / 2

    seg = getattr(charge_st_1D, gate)
    seg.add_HVI_variable("t_measure", int(t_step))
    seg.add_HVI_variable("digitizer", digitizer)
    seg.add_HVI_variable("number_of_points", int(n_pt))
    seg.add_HVI_variable("averaging", True)

    # set up timing for the scan
    if use_hvi2:
        step_eff = t_step + Hvi2VideoMode.get_acquisition_gap(
            digitizer, acquisition_delay_ns)
    else:
        # 2us needed to rearm digitizer
        # 120ns HVI waiting time
        step_eff = 2000 + 120 + t_step

    logging.info(f'Construct 1D: {gate}')

    # set up sweep voltages (get the right order, to compenstate for the biasT).
    voltages = np.zeros(n_pt)
    if biasT_corr == True:
        voltages[::2] = np.linspace(-vp, vp, n_pt)[:len(voltages[::2])]
        voltages[1::2] = np.linspace(-vp, vp, n_pt)[len(voltages[1::2]):][::-1]
    else:
        voltages = np.linspace(-vp, vp, n_pt)

    for voltage in voltages:
        seg.add_block(0, step_eff, voltage)
        seg.reset_time()

    for marker in enabled_markers:
        marker_seg = getattr(charge_st_1D, marker)
        marker_seg.add_marker(0, n_pt * step_eff)

    # 100 time points per step to make sure that everything looks good (this is more than needed).
    awg_t_step = t_step / 100
    # prescaler is limited to 255 when hvi_queueing_control is enabled. Limit other cases as well
    if awg_t_step > 5 * 255:
        awg_t_step = 5 * 255
    sample_rate = 1 / (awg_t_step * 1e-9)

    # generate the sequence and upload it.
    my_seq = pulse_lib.mk_sequence([charge_st_1D])
    if use_hvi2:
        my_seq.set_hw_schedule(
            Hvi2ScheduleLoader(pulse_lib,
                               'VideoMode',
                               digitizer,
                               acquisition_delay_ns=acquisition_delay_ns))
    else:
        my_seq.add_HVI(HVI_ID, load_HVI, set_and_compile_HVI, excute_HVI)
    my_seq.n_rep = 1
    my_seq.sample_rate = sample_rate

    logging.info(f'Upload')
    my_seq.upload([0])

    return _digitzer_scan_parameter(digitizer,
                                    my_seq,
                                    pulse_lib,
                                    t_step, (n_pt, ), (gate, ),
                                    (tuple(voltages), ),
                                    biasT_corr,
                                    dig_samplerate,
                                    channels=channels,
                                    Vmax=dig_vmax,
                                    iq_mode=iq_mode,
                                    channel_map=channel_map)
Ejemplo n.º 4
0
def construct_1D_scan_fast(gate,
                           swing,
                           n_pt,
                           t_step,
                           biasT_corr,
                           pulse_lib,
                           digitizer,
                           channels,
                           dig_samplerate,
                           dig_vmax=2.0,
                           iq_mode=None,
                           acquisition_delay_ns=None,
                           enabled_markers=[],
                           channel_map=None,
                           pulse_gates={},
                           line_margin=0):
    """
    1D fast scan parameter constructor.

    Args:
        gate (str) : gate/gates that you want to sweep.
        swing (double) : swing to apply on the AWG gates. [mV]
        n_pt (int) : number of points to measure (current firmware limits to 1000)
        t_step (double) : time in ns to measure per point. [ns]
        biasT_corr (bool) : correct for biasT by taking data in different order.
        pulse_lib : pulse library object, needed to make the sweep.
        digitizer : digitizer object
        channels : digitizer channels to read
        dig_samplerate : digitizer sample rate [Sa/s]
        iq_mode (str or dict): when digitizer is in MODE.IQ_DEMODULATION then this parameter specifies how the
                complex I/Q value should be plotted: 'I', 'Q', 'abs', 'angle', 'angle_deg'. A string applies to
                all channels. A dict can be used to specify selection per channel, e.g. {1:'abs', 2:'angle'}.
                Note: channel_map is a more generic replacement for iq_mode.
        acquisition_delay_ns (float):
                Time in ns between AWG output change and digitizer acquisition start.
                This also increases the gap between acquisitions.
        enable_markers (List[str]): marker channels to enable during scan
        channel_map (Dict[str, Tuple(int, Callable[[np.ndarray], np.ndarray])]):
            defines new list of derived channels to display. Dictionary entries name: (channel_number, func).
            E.g. {(ch1-I':(1, np.real), 'ch1-Q':(1, np.imag), 'ch3-Amp':(3, np.abs), 'ch3-Phase':(3, np.angle)}
            The default channel_map is:
                {'ch1':(1, np.real), 'ch2':(2, np.real), 'ch3':(3, np.real), 'ch4':(4, np.real)}
        pulse_gates (Dict[str, float]):
            Gates to pulse during scan with pulse voltage in mV.
            E.g. {'vP1': 10.0, 'vB2': -29.1}
        line_margin (int): number of points to add to sweep 1 to mask transition effects due to voltage step.
            The points are added to begin and end for symmetry (bias-T).

    Returns:
        Parameter (QCODES multiparameter) : parameter that can be used as input in a conversional scan function.
    """
    logging.info(f'Construct 1D: {gate}')

    vp = swing / 2
    line_margin = int(line_margin)
    if biasT_corr and line_margin > 0:
        print('Line margin is ignored with biasT_corr on')
        line_margin = 0

    add_line_delay = biasT_corr and len(pulse_gates) > 0

    # set up timing for the scan
    step_eff = t_step + Hvi2VideoMode.get_acquisition_gap(
        digitizer, acquisition_delay_ns)

    min_step_eff = 200 if not add_line_delay else 350
    if step_eff < min_step_eff:
        msg = f'Measurement time too short. Minimum is {t_step + min_step_eff-step_eff}'
        logging.error(msg)
        raise Exception(msg)

    n_ptx = n_pt + 2 * line_margin
    vpx = vp * (n_ptx - 1) / (n_pt - 1)

    # set up sweep voltages (get the right order, to compenstate for the biasT).
    voltages_sp = np.linspace(-vp, vp, n_pt)
    voltages_x = np.linspace(-vpx, vpx, n_ptx)
    if biasT_corr:
        m = (n_ptx + 1) // 2
        voltages = np.zeros(n_ptx)
        voltages[::2] = voltages_x[:m]
        voltages[1::2] = voltages_x[m:][::-1]
    else:
        voltages = voltages_x

    start_delay = line_margin * step_eff
    line_delay_pts = 1
    n_lines = n_pt if add_line_delay else 1

    if not biasT_corr:
        prebias_pts = (n_ptx) // 2
        t_prebias = prebias_pts * step_eff
        start_delay += t_prebias

    seg = pulse_lib.mk_segment()
    g1 = seg[gate]
    pulse_channels = []
    for ch, v in pulse_gates.items():
        pulse_channels.append((seg[ch], v))

    if not biasT_corr:
        # pre-pulse to condition bias-T
        g1.add_ramp_ss(0, t_prebias, 0, vpx)
        for gp, v in pulse_channels:
            gp.add_block(0, t_prebias, -v)
        seg.reset_time()

    for voltage in voltages:
        g1.add_block(0, step_eff, voltage)

        for gp, v in pulse_channels:
            gp.add_block(0, step_eff, v)
            # compensation for pulse gates
            if biasT_corr:
                gp.add_block(step_eff, 2 * step_eff, -v)
        seg.reset_time()

    if not biasT_corr:
        # post-pulse to discharge bias-T
        g1.add_ramp_ss(0, t_prebias, -vpx, 0)
        for gp, v in pulse_channels:
            gp.add_block(0, t_prebias, -v)
        seg.reset_time()

    end_time = seg.total_time[0]
    for marker in enabled_markers:
        marker_ch = seg[marker]
        marker_ch.reset_time(0)
        marker_ch.add_marker(0, end_time)

    # 100 time points per step to make sure that everything looks good (this is more than needed).
    awg_t_step = t_step / 100
    # prescaler is limited to 255 when hvi_queueing_control is enabled. Limit other cases as well
    if awg_t_step > 5 * 255:
        awg_t_step = 5 * 255
    sample_rate = 1 / (awg_t_step * 1e-9)

    seg.add_HVI_variable("t_measure", int(t_step))
    seg.add_HVI_variable("number_of_points",
                         int(n_pt) if not add_line_delay else 1)
    seg.add_HVI_variable("number_of_lines", n_lines)
    seg.add_HVI_variable("start_delay", int(start_delay))
    seg.add_HVI_variable(
        "line_delay",
        int(line_delay_pts * step_eff) if add_line_delay else 500)
    seg.add_HVI_variable("averaging", True)

    # generate the sequence and upload it.
    my_seq = pulse_lib.mk_sequence([seg])
    my_seq.set_hw_schedule(
        Hvi2ScheduleLoader(pulse_lib,
                           'VideoMode',
                           digitizer,
                           acquisition_delay_ns=acquisition_delay_ns))
    my_seq.n_rep = 1
    my_seq.sample_rate = sample_rate

    logging.info(f'Upload')
    my_seq.upload()

    return _digitzer_scan_parameter(digitizer,
                                    my_seq,
                                    pulse_lib,
                                    t_step, (n_pt, ), (gate, ),
                                    (tuple(voltages_sp), ),
                                    biasT_corr,
                                    dig_samplerate,
                                    channels=channels,
                                    Vmax=dig_vmax,
                                    iq_mode=iq_mode,
                                    channel_map=channel_map)