def __init__(self, major_sweep_function, minor_sweep_function, major_values, name=None, parameter_name=None, unit=None): super().__init__() self.major_sweep_function = \ mc_parameter_wrapper.wrap_par_to_swf(major_sweep_function) \ if isinstance(major_sweep_function, qcodes.Parameter) \ else major_sweep_function self.minor_sweep_function = \ mc_parameter_wrapper.wrap_par_to_swf(minor_sweep_function) \ if isinstance(minor_sweep_function, qcodes.Parameter) \ else minor_sweep_function if self.major_sweep_function.sweep_control != 'soft' or \ self.minor_sweep_function.sweep_control != 'soft': raise ValueError('Offset_Sweep: Only software sweeps supported') self.sweep_control = 'soft' self.major_values = np.array(major_values) self.parameter_name = self.major_sweep_function.parameter_name \ if parameter_name is None else parameter_name self.name = self.major_sweep_function.name if name is None else name self.unit = self.major_sweep_function.unit if unit is None else unit
def measure_pulsed_spectroscopy(self, freqs, mode='ROGated_SpecGate', MC=None, analyze=True, close_fig=True, force_load=False): # This is a trick so I can reuse the heterodyne instr # to do pulsed-spectroscopy self.heterodyne_instr._disable_auto_seq_loading = True if mode=='ROMod_SpecGated': if ('Pulsed_spec_with_RF_mod' not in self.AWG.setup_filename.get()) or force_load: st_seqs.Pulsed_spec_seq_RF_mod( IF=self.f_RO_mod.get(), spec_pulse_length=spec_pulse_length, marker_interval=30e-6, RO_pulse_delay=self.RO_pulse_delay.get()) elif mode=='ROGated_SpecGate': if ('Pulsed_spec_with_RF_gated' not in self.AWG.setup_filename.get()) or force_load: st_seqs.Pulsed_spec_seq_RF_gated(self.RO_pars, self.pulse_pars) else: NotImplementedError('Pulsed Spec mode not supported. Only ROMod_SpecGated and ROGated_SpecGate are avaible right now.\n') self.cw_source.pulsemod_state.set('on') self.cw_source.power.set(self.spec_pow_pulsed.get()) self.AWG.start() if hasattr(self.heterodyne_instr, 'mod_amp'): self.heterodyne_instr.set('mod_amp', self.mod_amp_cw.get()) else: self.heterodyne_instr.RF.power(self.RO_power_cw()) MC.set_sweep_function(pw.wrap_par_to_swf( self.cw_source.frequency)) MC.set_sweep_points(freqs) MC.set_detector_function(det.Heterodyne_probe(self.heterodyne_instr)) MC.run(name='pulsed-spec'+self.msmt_suffix) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig)
def measure_spectroscopy(self, freqs, pulsed=False, MC=None, analyze=True, close_fig=True, mode='ROGated_SpecGate', force_load=False): self.prepare_for_continuous_wave() self.cw_source.on() if MC is None: MC = self.MC if pulsed: # Redirect to the pulsed spec function return self.measure_pulsed_spectroscopy(freqs=freqs, MC=MC, analyze=analyze, close_fig=close_fig, mode=mode, force_load=force_load) MC.set_sweep_function(pw.wrap_par_to_swf(self.cw_source.frequency)) MC.set_sweep_points(freqs) MC.set_detector_function( det.Heterodyne_probe(self.heterodyne_instr, trigger_separation=2.8e-6)) MC.run(name='spectroscopy' + self.msmt_suffix) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig) self.cw_source.off()
def measure_spectroscopy(self, freqs, pulsed=False, MC=None, analyze=True, close_fig=True, mode='ROGated_SpecGate', force_load=True, use_max=False, update=True): self.prepare_for_continuous_wave() self.cw_source.on() if MC is None: MC = self.MC if pulsed: # Redirect to the pulsed spec function return self.measure_pulsed_spectroscopy(freqs=freqs, MC=MC, analyze=analyze, close_fig=close_fig, update=update, upload=force_load) MC.set_sweep_function(pw.wrap_par_to_swf( self.cw_source.frequency)) MC.set_sweep_points(freqs) MC.set_detector_function( det.Heterodyne_probe(self.heterodyne_instr, trigger_separation=2.8e-6)) MC.run(name='spectroscopy'+self.msmt_suffix) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig) self.cw_source.off()
def measure_spectroscopy(self, freqs, pulsed=False, MC=None, analyze=True, close_fig=True, force_load=True, use_max=False, update=True): self.prepare_for_continuous_wave() self.cw_source.get_instr().on() if MC is None: MC = self.MC.get_instr() if pulsed: # Redirect to the pulsed spec function return self.measure_pulsed_spectroscopy(freqs=freqs, MC=MC, analyze=analyze, close_fig=close_fig, update=update, upload=force_load) MC.set_sweep_function(pw.wrap_par_to_swf( self.cw_source.get_instr().frequency, retrieve_value=True)) MC.set_sweep_points(freqs) MC.set_detector_function( det.Heterodyne_probe( self.heterodyne_instr.get_instr(), trigger_separation=5e-6 + self.RO_acq_integration_length(), RO_length=self.RO_acq_integration_length())) MC.run(name='spectroscopy'+self.msmt_suffix) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig) self.cw_source.get_instr().off()
def measure_spectroscopy(self, freqs=None, MC=None, analyze=True, close_fig=True, update=False): """ Varies qubit drive frequency and measures the resonator transmittance """ if freqs is None: raise ValueError("Unspecified frequencies for " "measure_spectroscopy and no previous value") if MC is None: MC = self.MC self.prepare_for_continuous_wave() self.cw_source.on() MC.set_sweep_function(pw.wrap_par_to_swf(self.cw_source.frequency)) MC.set_sweep_points(freqs) MC.set_detector_function( det.Heterodyne_probe(self.heterodyne_instr, trigger_separation=2.8e-6, demod_mode='single')) MC.run(name='spectroscopy' + self.msmt_suffix) self.cw_source.off() if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig)
def measure_heterodyne_spectroscopy(self, freqs=None, MC=None, analyze=True, close_fig=True): """ Varies the frequency of the microwave source to the resonator and measures the transmittance """ if freqs is None: raise ValueError("Unspecified frequencies for measure_heterodyne_" "spectroscopy") if MC is None: MC = self.MC previous_freq = self.heterodyne_instr.frequency() self.prepare_for_continuous_wave() MC.set_sweep_function( pw.wrap_par_to_swf(self.heterodyne_instr.frequency)) MC.set_sweep_points(freqs) MC.set_detector_function( det.Heterodyne_probe(self.heterodyne_instr, trigger_separation=5e-6, demod_mode='single')) MC.run(name='resonator_scan' + self.msmt_suffix) self.heterodyne_instr.frequency(previous_freq) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig)
def measure_rabi(self, amps, n=1, MC=None, analyze=True, close_fig=True, verbose=False): self.prepare_for_timedomain() if MC is None: MC = self.MC cal_points = [0, 0] amps = cal_points + list(amps) self.CBox.AWG0_mode('Codeword-trigger mode') self.CBox.AWG1_mode('Codeword-trigger mode') self.CBox.AWG2_mode('Codeword-trigger mode') self.CBox.set_master_controller_working_state(0, 0, 0) self.CBox.load_instructions('CBox_v3_test_program\Rabi.asm') self.CBox.set_master_controller_working_state(1, 0, 0) MC.set_sweep_function(pw.wrap_par_to_swf(self.LutMan.amp180)) MC.set_sweep_points(amps) MC.set_detector_function( det.CBox_v3_single_int_avg_with_LutReload( self.CBox, self.LutMan, awg_nrs=[self.awg_nr.get()])) MC.run('Rabi-n{}'.format(n) + self.msmt_suffix) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig)
def measure_resonator_dac(self, freqs, dac_voltages, MC=None, analyze=True, close_fig=True): self.prepare_for_continuous_wave() if MC is None: MC = self.MC MC.set_sweep_functions( [pw.wrap_par_to_swf(self.heterodyne_instr.frequency), pw.wrap_par_to_swf( self.IVVI['dac{}'.format(self.dac_channel.get())]) ]) MC.set_sweep_points(freqs) MC.set_sweep_points_2D(dac_voltages) MC.set_detector_function(det.Heterodyne_probe(self.heterodyne_instr)) MC.run(name='Resonator_dac_scan'+self.msmt_suffix, mode='2D') if analyze: ma.MeasurementAnalysis(auto=True, TwoD=True, close_fig=close_fig)
def measure_resonator_power(self, freqs, powers, MC=None, analyze=True, close_fig=True): ''' N.B. This one does not use powers but varies the mod-amp. Need to find a way to keep this function agnostic to that ''' self.prepare_for_continuous_wave() if MC is None: MC = self.MC MC.set_sweep_functions( [pw.wrap_par_to_swf(self.heterodyne_instr.frequency), pw.wrap_par_to_swf(self.heterodyne_instr.RF_power)]) MC.set_sweep_points(freqs) MC.set_sweep_points_2D(powers) MC.set_detector_function(det.Heterodyne_probe(self.heterodyne_instr)) MC.run(name='Resonator_power_scan'+self.msmt_suffix, mode='2D') if analyze: ma.MeasurementAnalysis(auto=True, TwoD=True, close_fig=close_fig)
def measure_resonator_power(self, freqs, mod_amps, MC=None, analyze=True, close_fig=True): ''' N.B. This one does not use powers but varies the mod-amp. Need to find a way to keep this function agnostic to that ''' self.prepare_for_continuous_wave() if MC is None: MC = self.MC MC.set_sweep_functions( [pw.wrap_par_to_swf(self.heterodyne_instr.frequency), pw.wrap_par_to_swf(self.heterodyne_instr.mod_amp)]) MC.set_sweep_points(freqs) MC.set_sweep_points_2D(mod_amps) MC.set_detector_function(det.Heterodyne_probe(self.heterodyne_instr)) MC.run(name='Resonator_power_scan'+self.msmt_suffix, mode='2D') if analyze: ma.MeasurementAnalysis(auto=True, TwoD=True, close_fig=close_fig)
def set_sweep_function(self, sweep_function): ''' Used if only 1 sweep function is set. ''' # If it is not a sweep function, assume it is a qc.parameter # and try to auto convert it it if not isinstance(sweep_function, swf.Sweep_function): sweep_function = wrap_par_to_swf(sweep_function) self.sweep_functions = [sweep_function] self.set_sweep_function_names( [str(sweep_function.name)])
def measure_heterodyne_spectroscopy(self, freqs, MC=None, analyze=True, close_fig=True): self.prepare_for_continuous_wave() if MC is None: MC = self.MC MC.set_sweep_function(pw.wrap_par_to_swf( self.heterodyne_instr.frequency)) MC.set_sweep_points(freqs) MC.set_detector_function(det.Heterodyne_probe(self.heterodyne_instr, trigger_separation=2.8e-6)) MC.run(name='Resonator_scan'+self.msmt_suffix) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig)
def set_sweep_function_2D(self, sweep_function): # If it is not a sweep function, assume it is a qc.parameter # and try to auto convert it it if not isinstance(sweep_function, swf.Sweep_function): sweep_function = wrap_par_to_swf(sweep_function) if len(self.sweep_functions) != 1: raise KeyError( 'Specify sweepfunction 1D before specifying sweep_function 2D') else: self.sweep_functions.append(sweep_function) self.sweep_function_names.append( str(sweep_function.__class__.__name__))
def set_sweep_functions(self, sweep_functions): ''' Used to set an arbitrary number of sweep functions. ''' sweep_function_names = [] for i, sweep_func in enumerate(sweep_functions): # If it is not a sweep function, assume it is a qc.parameter # and try to auto convert it it if not hasattr(sweep_func, 'sweep_control'): sweep_func = wrap_par_to_swf(sweep_func) sweep_functions[i] = sweep_func sweep_function_names.append(str(swf.__class__.__name__)) self.sweep_functions = sweep_functions self.set_sweep_function_names(sweep_function_names)
def measure_pulsed_spectroscopy(self, freqs, MC=None, analyze=True, return_detector=False, close_fig=True, upload=True, update=True, use_max=False): """ Measure pulsed spec with the qubit. Accepts a manual sequence parameters, which has to be a call to a pulse generation allowing for alternative sequences to be played instead of the standard one """ self.prepare_for_pulsed_spec() self.heterodyne_instr.get_instr()._disable_auto_seq_loading = True self.cw_source.get_instr().pulsemod_state.set('On') self.cw_source.get_instr().power.set(self.spec_pow_pulsed.get()) self.cw_source.get_instr().on() if MC is None: MC = self.MC.get_instr() spec_pars, RO_pars = self.get_spec_pars() # Upload the AWG sequence sq.Pulsed_spec_seq(spec_pars, RO_pars) self.AWG.get_instr().start() if return_detector: return det.Heterodyne_probe(self.heterodyne_instr.get_instr()) else: MC.set_sweep_function(pw.wrap_par_to_swf( self.cw_source.get_instr().frequency, retrieve_value=True)) MC.set_sweep_points(freqs) MC.set_detector_function( det.Heterodyne_probe(self.heterodyne_instr.get_instr())) MC.run(name='pulsed-spec'+self.msmt_suffix) if analyze or update: ma_obj = ma.Qubit_Spectroscopy_Analysis( auto=True, label='pulsed', close_fig=close_fig) if use_max: f_qubit = ma_obj.peaks['peak'] else: f_qubit = ma_obj.fitted_freq if update: self.f_qubit(f_qubit) self.cw_source.get_instr().off() return f_qubit
def __init__(self, sweep_functions: list, parameter_name=None, name=None, **kw): self.set_kw() self.sweep_functions = [mc_parameter_wrapper.wrap_par_to_swf(s) if isinstance(s, qcodes.Parameter) else s for s in sweep_functions] self.sweep_control = 'soft' self.name = name or 'multi_sweep' self.unit = sweep_functions[0].unit self.parameter_name = parameter_name or 'multiple_parameters' for i, sweep_function in enumerate(sweep_functions): if self.unit.lower() != sweep_function.unit.lower(): raise ValueError('units of the sweepfunctions are not equal')
def measure_heterodyne_spectroscopy(self, freqs, MC=None, analyze=True, close_fig=True): self.prepare_for_continuous_wave() # sqts.Pulsed_spec_seq(spec_pars, RO_pars) if MC is None: MC = self.MC.get_instr() MC.set_sweep_function(pw.wrap_par_to_swf( self.heterodyne_instr.get_instr().frequency, retrieve_value=True)) MC.set_sweep_points(freqs) MC.set_detector_function( det.Heterodyne_probe(self.heterodyne_instr.get_instr(), trigger_separation=self.RO_acq_integration_length()+5e-6, RO_length=self.RO_acq_integration_length())) MC.run(name='Resonator_scan'+self.msmt_suffix) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig)
def measure_heterodyne_spectroscopy(self, freqs, MC=None, analyze=True, close_fig=True, RO_length=2000e-9): self.prepare_for_continuous_wave() if MC is None: MC = self.MC MC.set_sweep_function( pw.wrap_par_to_swf(self.heterodyne_instr.frequency)) MC.set_sweep_points(freqs) MC.set_detector_function( det.Heterodyne_probe(self.heterodyne_instr, trigger_separation=2.8e-6, RO_length=2274e-9)) MC.run(name='Resonator_scan' + self.msmt_suffix) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig)
def measure_pulsed_spectroscopy(self, freqs, mode='ROGated_SpecGate', MC=None, analyze=True, close_fig=True, force_load=False): # This is a trick so I can reuse the heterodyne instr # to do pulsed-spectroscopy self.heterodyne_instr._disable_auto_seq_loading = True if mode == 'ROMod_SpecGated': if ('Pulsed_spec_with_RF_mod' not in self.AWG.setup_filename.get()) or force_load: st_seqs.Pulsed_spec_seq_RF_mod( IF=self.f_RO_mod.get(), spec_pulse_length=spec_pulse_length, marker_interval=30e-6, RO_pulse_delay=self.RO_pulse_delay.get()) elif mode == 'ROGated_SpecGate': if ('Pulsed_spec_with_RF_gated' not in self.AWG.setup_filename.get()) or force_load: st_seqs.Pulsed_spec_seq_RF_gated(self.RO_pars, self.pulse_pars) else: NotImplementedError( 'Pulsed Spec mode not supported. Only ROMod_SpecGated and ROGated_SpecGate are avaible right now.\n' ) self.cw_source.pulsemod_state.set('on') self.cw_source.power.set(self.spec_pow_pulsed.get()) self.AWG.start() if hasattr(self.heterodyne_instr, 'mod_amp'): self.heterodyne_instr.set('mod_amp', self.mod_amp_cw.get()) else: self.heterodyne_instr.RF.power(self.RO_power_cw()) MC.set_sweep_function(pw.wrap_par_to_swf(self.cw_source.frequency)) MC.set_sweep_points(freqs) MC.set_detector_function(det.Heterodyne_probe(self.heterodyne_instr)) MC.run(name='pulsed-spec' + self.msmt_suffix) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig)
def __init__(self, sweep_function, transformation, name=None, parameter_name=None, unit=None): super().__init__() if isinstance(sweep_function, qcodes.Parameter): sweep_function = mc_parameter_wrapper.wrap_par_to_swf( sweep_function) if sweep_function.sweep_control != 'soft': raise ValueError(f'{self.__class__.__name__}: Only software ' f'sweeps supported') self.sweep_function = sweep_function self.transformation = transformation self.sweep_control = sweep_function.sweep_control self.name = self.sweep_function.name if name is None else name self.unit = self.sweep_function.unit if unit is None else unit self.parameter_name = self.default_param_name() \ if parameter_name is None else parameter_name
def measure_rabi(self, amps, n=1, MC=None, analyze=True, close_fig=True, verbose=False): self.prepare_for_timedomain() if MC is None: MC = self.MC cal_points = [0, 0] amps = cal_points + list(amps) self.CBox.AWG0_mode('Codeword-trigger mode') self.CBox.AWG1_mode('Codeword-trigger mode') self.CBox.AWG2_mode('Codeword-trigger mode') self.CBox.set_master_controller_working_state(0, 0, 0) self.CBox.load_instructions('CBox_v3_test_program\Rabi.asm') self.CBox.set_master_controller_working_state(1, 0, 0) MC.set_sweep_function(pw.wrap_par_to_swf(self.LutMan.amp180)) MC.set_sweep_points(amps) MC.set_detector_function(det.CBox_v3_single_int_avg_with_LutReload( self.CBox, self.LutMan, awg_nrs=[self.awg_nr.get()])) MC.run('Rabi-n{}'.format(n)+self.msmt_suffix) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig)
def measure_homodyne_acqusition_delay(self, delays=None, MC=None, analyze=True, close_fig=True): """ Varies the delay between the homodyne modulation signal and acquisition. Measures the transmittance. """ if delays is None: raise ValueError("Unspecified delays for measure_homodyne_" "acquisition_delay") if MC is None: MC = self.MC # set number of averages to 1 due to a readout bug previous_nr_averages = self.heterodyne_instr.nr_averages() self.heterodyne_instr.nr_averages(1) previous_delay = self.heterodyne_instr.acquisition_delay() self.prepare_for_continuous_wave() MC.set_sweep_function( pw.wrap_par_to_swf(self.heterodyne_instr.acquisition_delay)) MC.set_sweep_points(delays) MC.set_detector_function( det.Heterodyne_probe(self.heterodyne_instr, trigger_separation=5e-6, demod_mode='single')) MC.run(name='acquisition_delay_scan' + self.msmt_suffix) self.heterodyne_instr.acquisition_delay(previous_delay) self.heterodyne_instr.nr_averages(previous_nr_averages) if analyze: ma.MeasurementAnalysis(auto=True, close_fig=close_fig)
def calibrate_pulse_parameters(self, method='resetless_rb', nr_cliff=10, parameters=['amp', 'motzoi', 'frequency'], amp_guess=None, motzoi_guess=None, frequency_guess=None, a_step=30, m_step=.1, f_step=20e3, MC=None, nested_MC=None, update=False, close_fig=True, verbose=True): ''' Calibrates single qubit pulse parameters currently only using the resetless rb method (requires reasonable (80%+?) discrimination fidelity) If it there is only one parameter to sweep it will use brent's method instead. The function returns the values it found for the optimization. ''' if method is not 'resetless_rb': raise NotImplementedError() self.prepare_for_timedomain() if MC is None: MC = self.MC if nested_MC is None: nested_MC = self.nested_MC d = self.get_resetless_rb_detector(nr_cliff=nr_cliff, MC=nested_MC) name = 'RB_{}cl_numerical'.format(nr_cliff) MC.set_detector_function(d) if amp_guess is None: amp_guess = self.amp180.get() if motzoi_guess is None: motzoi_guess = self.motzoi.get() if frequency_guess is None: frequency_guess = self.f_qubit.get() # Because we are sweeping the source and not the qubit frequency start_freq = frequency_guess - self.f_pulse_mod.get() sweep_functions = [] x0 = [] init_steps = [] if 'amp' in parameters: sweep_functions.append(cb_swf.LutMan_amp180_90(self.LutMan)) x0.append(amp_guess) init_steps.append(a_step) if 'motzoi' in parameters: sweep_functions.append( pw.wrap_par_to_swf(self.LutMan.motzoi_parameter)) x0.append(motzoi_guess) init_steps.append(m_step) if 'frequency' in parameters: sweep_functions.append(pw.wrap_par_to_swf( self.td_source.frequency)) x0.append(start_freq) init_steps.append(f_step) if len(sweep_functions) == 0: raise ValueError( 'parameters "{}" not recognized'.format(parameters)) MC.set_sweep_functions(sweep_functions) if len(sweep_functions) != 1: # noise ensures no_improv_break sets the termination condition ad_func_pars = { 'adaptive_function': nelder_mead, 'x0': x0, 'initial_step': init_steps, 'no_improv_break': 10, 'minimize': False, 'maxiter': 500 } elif len(sweep_functions) == 1: # Powell does not work for 1D, use brent instead brack = (x0[0] - 5 * init_steps[0], x0[0]) # Ensures relative change in parameter is relevant if parameters == ['frequency']: tol = 1e-9 else: tol = 1e-3 print('Tolerance:', tol, init_steps[0]) print(brack) ad_func_pars = { 'adaptive_function': brent, 'brack': brack, 'tol': tol, # Relative tolerance in brent 'minimize': False } MC.set_adaptive_function_parameters(ad_func_pars) MC.run(name=name, mode='adaptive') if len(sweep_functions) != 1: a = ma.OptimizationAnalysis(auto=True, label=name, close_fig=close_fig) if verbose: # Note printing can be made prettier print('Optimization converged to:') print('parameters: {}'.format(parameters)) print(a.optimization_result[0]) if update: for i, par in enumerate(parameters): if par == 'amp': self.amp180.set(a.optimization_result[0][i]) elif par == 'motzoi': self.motzoi.set(a.optimization_result[0][i]) elif par == 'frequency': self.f_qubit.set(a.optimization_result[0][i] + self.f_pulse_mod.get()) return a else: a = ma.MeasurementAnalysis(label=name, close_fig=close_fig) print('Optimization for {} converged to: {}'.format( parameters[0], a.sweep_points[-1])) if update: if parameters == ['amp']: self.amp180.set(a.sweep_points[-1]) elif parameters == ['motzoi']: self.motzoi.set(a.sweep_points[-1]) elif parameters == ['frequency']: self.f_qubit.set(a.sweep_points[-1] + self.f_pulse_mod.get()) return a.sweep_points[-1]
def mixer_skewness_calibration_5014(SH, source, station, MC=None, QI_amp_ratio=None, IQ_phase=None, frequency=None, f_mod=10e6, I_ch=1, Q_ch=2, name='mixer_skewness_calibration_5014'): ''' Loads a cos and sin waveform in the specified I and Q channels of the tektronix 5014 AWG (taken from station.pulsar.AWG). By looking at the frequency corresponding with the spurious sideband the phase_skewness and amplitude skewness that minimize the signal correspond to the mixer skewness. Inputs: SH (instrument) Source (instrument) MW-source used for driving station (qcodes station) Contains the AWG and pulasr sequencer QI_amp_ratio (parameter) qcodes parameter IQ_phase (parameter) frequency (float Hz) Spurious SB freq: f_source - f_mod f_mod (float Hz) Modulation frequency I_ch/Q_ch (int or str) Specifies the AWG channels returns: alpha, phi the coefficients that go in the predistortion matrix For the spurious sideband: alpha = 1/QI_amp_optimal phi = -IQ_phase_optimal For details, see Leo's notes on mixer skewness calibration in the docs ''' if frequency is None: # Corresponds to the frequency where to minimize with the SH frequency = source.frequency.get() - f_mod if QI_amp_ratio is None: QI_amp_ratio = ManualParameter('QI_amp', initial_value=1) if IQ_phase is None: IQ_phase = ManualParameter('IQ_phase', unit='deg', initial_value=0) if MC is None: MC = station.MC if type(I_ch) is int: I_ch = 'ch{}'.format(I_ch) if type(Q_ch) is int: Q_ch = 'ch{}'.format(Q_ch) d = det.SH_mixer_skewness_det(frequency, QI_amp_ratio, IQ_phase, SH, f_mod=f_mod, I_ch=I_ch, Q_ch=Q_ch, station=station) S1 = pw.wrap_par_to_swf(QI_amp_ratio) S2 = pw.wrap_par_to_swf(IQ_phase) ad_func_pars = {'adaptive_function': nelder_mead, 'x0': [1.0, 0.0], 'initial_step': [.15, 10], 'no_improv_break': 12, 'minimize': True, 'maxiter': 500} MC.set_sweep_functions([S1, S2]) MC.set_detector_function(d) MC.set_adaptive_function_parameters(ad_func_pars) MC.run(name=name, mode='adaptive') a = ma.OptimizationAnalysis() # phi and alpha are the coefficients that go in the predistortion matrix alpha = 1/a.optimization_result[0][0] phi = -1*a.optimization_result[0][1] return phi, alpha
def mixer_skewness_calibration_5014(SH, source, station, MC=None, QI_amp_ratio=None, IQ_phase=None, frequency=None, f_mod=10e6, I_ch=1, Q_ch=2, name='mixer_skewness_calibration_5014'): ''' Loads a cos and sin waveform in the specified I and Q channels of the tektronix 5014 AWG (taken from station.pulsar.AWG). By looking at the frequency corresponding with the spurious sideband the phase_skewness and amplitude skewness that minimize the signal correspond to the mixer skewness. Inputs: SH (instrument) Source (instrument) MW-source used for driving station (qcodes station) Contains the AWG and pulasr sequencer QI_amp_ratio (parameter) qcodes parameter IQ_phase (parameter) frequency (float Hz) Spurious SB freq: f_source - f_mod f_mod (float Hz) Modulation frequency I_ch/Q_ch (int or str) Specifies the AWG channels returns: alpha, phi the coefficients that go in the predistortion matrix For the spurious sideband: alpha = 1/QI_amp_optimal phi = -IQ_phase_optimal For details, see Leo's notes on mixer skewness calibration in the docs ''' if frequency is None: # Corresponds to the frequency where to minimize with the SH frequency = source.frequency.get() - f_mod if QI_amp_ratio is None: QI_amp_ratio = ManualParameter('QI_amp', initial_value=1) if IQ_phase is None: IQ_phase = ManualParameter('IQ_phase', units='deg', initial_value=0) if MC is None: MC = station.MC if type(I_ch) is int: I_ch = 'ch{}'.format(I_ch) if type(Q_ch) is int: Q_ch = 'ch{}'.format(Q_ch) d = det.SH_mixer_skewness_det(frequency, QI_amp_ratio, IQ_phase, SH, f_mod=f_mod, I_ch=I_ch, Q_ch=Q_ch, station=station) S1 = pw.wrap_par_to_swf(QI_amp_ratio) S2 = pw.wrap_par_to_swf(IQ_phase) ad_func_pars = {'adaptive_function': nelder_mead, 'x0': [1.0, 0.0], 'initial_step': [.15, 10], 'no_improv_break': 10, 'minimize': True, 'maxiter': 500} MC.set_sweep_functions([S1, S2]) MC.set_detector_function(d) MC.set_adaptive_function_parameters(ad_func_pars) MC.run(name=name, mode='adaptive') a = MA.OptimizationAnalysis() # phi and alpha are the coefficients that go in the predistortion matrix alpha = 1/a.optimization_result[0][0] phi = -1*a.optimization_result[0][1] return phi, alpha
def mixer_carrier_cancellation_5014(AWG, SH, source, MC, frequency=None, AWG_channel1=1, AWG_channel2=2, voltage_grid=[.1, 0.05, 0.02], xtol=0.001, **kw): ''' Varies the mixer offsets to minimize leakage at the carrier frequency. this is the version for a tektronix AWG. station: QCodes station object that contains the instruments source: the source for which carrier leakage must be minimized frequency: frequency in Hz on which to minimize leakage, if None uses the current frequency of the source returns: ch_1_min, ch_2_min voltage_grid defines the ranges for the preliminary coarse sweeps. If the range is too small, add another number infront of -0.12 Note: Updated for QCodes ''' ch_1_min = 0 # Initializing variables used later on ch_2_min = 0 last_ch_1_min = 1 last_ch_2_min = 1 ii = 0 min_power = 0 source.on() if frequency is None: frequency = source.get('frequency') else: source.set('frequency', frequency) ''' Make coarse sweeps to approximate the minimum ''' if type(AWG_channel1) is int: ch1_offset = AWG['ch{}_offset'.format(AWG_channel1)] else: ch1_offset = AWG[AWG_channel1+'_offset'] if type(AWG_channel2) is int: ch2_offset = AWG['ch{}_offset'.format(AWG_channel2)] else: ch2_offset = AWG[AWG_channel2+'_offset'] ch1_swf = pw.wrap_par_to_swf(ch1_offset) ch2_swf = pw.wrap_par_to_swf(ch2_offset) for voltage_span in voltage_grid: # Channel 1 MC.set_sweep_function(ch1_swf) MC.set_detector_function( det.Signal_Hound_fixed_frequency(signal_hound=SH, frequency=frequency)) MC.set_sweep_points(np.linspace(ch_1_min + voltage_span, ch_1_min - voltage_span, 11)) MC.run(name='Mixer_cal_Offset_%s' % AWG_channel1, sweep_delay=.1, debug_mode=True) Mixer_Calibration_Analysis = MA.Mixer_Calibration_Analysis( label='Mixer_cal', auto=True) ch_1_min = Mixer_Calibration_Analysis.fit_results[0] ch1_offset.set(ch_1_min) # Channel 2 MC.set_sweep_function(ch2_swf) MC.set_sweep_points(np.linspace(ch_2_min + voltage_span, ch_2_min - voltage_span, 11)) MC.run(name='Mixer_cal_Offset_ch%s' % AWG_channel2, sweep_delay=.1, debug_mode=True) Mixer_Calibration_Analysis = MA.Mixer_Calibration_Analysis( label='Mixer_cal', auto=True) ch_2_min = Mixer_Calibration_Analysis.fit_results[0] ch2_offset.set(ch_2_min) # Refine and repeat the sweeps to find the minimum while(abs(last_ch_1_min - ch_1_min) > xtol and abs(last_ch_2_min - ch_2_min) > xtol): ii += 1 dac_resolution = 0.001 # channel 1 finer sweep MC.set_sweep_function(ch1_swf) MC.set_sweep_points(np.linspace(ch_1_min - dac_resolution*6, ch_1_min + dac_resolution*6, 13)) MC.run(name='Mixer_cal_Offset_%s' % AWG_channel1, sweep_delay=.1, debug_mode=True) Mixer_Calibration_Analysis = MA.Mixer_Calibration_Analysis( label='Mixer_cal', auto=True) last_ch_1_min = ch_1_min ch_1_min = Mixer_Calibration_Analysis.fit_results[0] ch1_offset.set(ch_1_min) # Channel 2 finer sweep MC.set_sweep_function(ch2_swf) MC.set_sweep_points(np.linspace(ch_2_min - dac_resolution*6, ch_2_min + dac_resolution*6, 13)) MC.run(name='Mixer_cal_Offset_%s' % AWG_channel2, sweep_delay=.1, debug_mode=True) Mixer_Calibration_Analysis = MA.Mixer_Calibration_Analysis( label='Mixer_cal', auto=True) last_ch_2_min = ch_2_min min_power = min(Mixer_Calibration_Analysis.measured_powers) ch_2_min = Mixer_Calibration_Analysis.fit_results[0] ch2_offset.set(ch_2_min) if ii > 10: logging.error('Mixer calibration did not converge') break print(ch_1_min, ch_2_min) return ch_1_min, ch_2_min
def calibrate_pulse_parameters(self, method='resetless_rb', nr_cliff=10, parameters=['amp', 'motzoi', 'frequency'], amp_guess=None, motzoi_guess=None, frequency_guess=None, a_step=30, m_step=.1, f_step=20e3, MC=None, nested_MC=None, update=False, close_fig=True, verbose=True): ''' Calibrates single qubit pulse parameters currently only using the resetless rb method (requires reasonable (80%+?) discrimination fidelity) If it there is only one parameter to sweep it will use brent's method instead. The function returns the values it found for the optimization. ''' if method is not 'resetless_rb': raise NotImplementedError() self.prepare_for_timedomain() if MC is None: MC = self.MC if nested_MC is None: nested_MC = self.nested_MC d = self.get_resetless_rb_detector(nr_cliff=nr_cliff, MC=nested_MC) name = 'RB_{}cl_numerical'.format(nr_cliff) MC.set_detector_function(d) if amp_guess is None: amp_guess = self.amp180.get() if motzoi_guess is None: motzoi_guess = self.motzoi.get() if frequency_guess is None: frequency_guess = self.f_qubit.get() # Because we are sweeping the source and not the qubit frequency start_freq = frequency_guess - self.f_pulse_mod.get() sweep_functions = [] x0 = [] init_steps = [] if 'amp' in parameters: sweep_functions.append(cb_swf.LutMan_amp180_90(self.LutMan)) x0.append(amp_guess) init_steps.append(a_step) if 'motzoi' in parameters: sweep_functions.append( pw.wrap_par_to_swf(self.LutMan.motzoi_parameter)) x0.append(motzoi_guess) init_steps.append(m_step) if 'frequency' in parameters: sweep_functions.append( pw.wrap_par_to_swf(self.td_source.frequency)) x0.append(start_freq) init_steps.append(f_step) if len(sweep_functions) == 0: raise ValueError( 'parameters "{}" not recognized'.format(parameters)) MC.set_sweep_functions(sweep_functions) if len(sweep_functions) != 1: # noise ensures no_improv_break sets the termination condition ad_func_pars = {'adaptive_function': nelder_mead, 'x0': x0, 'initial_step': init_steps, 'no_improv_break': 10, 'minimize': False, 'maxiter': 500} elif len(sweep_functions) == 1: # Powell does not work for 1D, use brent instead brack = (x0[0]-5*init_steps[0], x0[0]) # Ensures relative change in parameter is relevant if parameters == ['frequency']: tol = 1e-9 else: tol = 1e-3 print('Tolerance:', tol, init_steps[0]) print(brack) ad_func_pars = {'adaptive_function': brent, 'brack': brack, 'tol': tol, # Relative tolerance in brent 'minimize': False} MC.set_adaptive_function_parameters(ad_func_pars) MC.run(name=name, mode='adaptive') if len(sweep_functions) != 1: a = ma.OptimizationAnalysis(auto=True, label=name, close_fig=close_fig) if verbose: # Note printing can be made prettier print('Optimization converged to:') print('parameters: {}'.format(parameters)) print(a.optimization_result[0]) if update: for i, par in enumerate(parameters): if par == 'amp': self.amp180.set(a.optimization_result[0][i]) elif par == 'motzoi': self.motzoi.set(a.optimization_result[0][i]) elif par == 'frequency': self.f_qubit.set(a.optimization_result[0][i] + self.f_pulse_mod.get()) return a else: a = ma.MeasurementAnalysis(label=name, close_fig=close_fig) print('Optimization for {} converged to: {}'.format( parameters[0], a.sweep_points[-1])) if update: if parameters == ['amp']: self.amp180.set(a.sweep_points[-1]) elif parameters == ['motzoi']: self.motzoi.set(a.sweep_points[-1]) elif parameters == ['frequency']: self.f_qubit.set(a.sweep_points[-1]+self.f_pulse_mod.get()) return a.sweep_points[-1]