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
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)
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)
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)