Mixer tunning code: Difference between revisions

From QT5201U wiki
Jump to navigation Jump to search
Yifan (talk | contribs)
No edit summary
Yifan (talk | contribs)
No edit summary
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
 
{{code|
<nowiki>class MixerTuner(object):
class MixerTuner(object):
     def __init__(self, qm, sa, element, lo_freq, if_freq, ref_power):
     def __init__(self, qm, sa, element, lo_freq, if_freq, ref_power):
         self.qm = qm
         self.qm = qm
Line 98: Line 97:


         else:
         else:
             raise ValueError(result.message)
             raise ValueError(result.message)</nowiki>
}}

Latest revision as of 12:48, 27 April 2021

class MixerTuner(object):
    def __init__(self, qm, sa, element, lo_freq, if_freq, ref_power):
        self.qm = qm
        self.element = element
        self.sa = sa 
        self.lo_freq = lo_freq
        self.if_freq = if_freq
        self.ref_power = ref_power
        self.job = self.init_qm()  
    def init_qm(self):
        with program() as cw:
            with infinite_loop_():
                play("CW", element)
        self.job = self.qm.execute(cw)
        return self.job
    
    def close(self):
        self.job.halt()
    
    def no_dc_offset_correction(self):
        self.qm.set_output_dc_offset_by_element(self.element, "I", float(0)) 
        self.qm.set_output_dc_offset_by_element(self.element, "Q", float(0))
        self.qm.set_mixer_correction("mixer_qubit", qubit_IF, qubit_LO, IQ_imbalance(0, 0))
        freqs, amps = self.sa.sweep(center=self.lo_freq, span= 250e6, ref_power = self.ref_power)
        plt.figure()
        plt.plot(freqs, amps)
        
    def offset_lo_leakage(self, fatol=1):  
        # fatol = 1dB
        print('Offset Lo leakage')
        freq_i, amps_i = sa.sweep(center=self.lo_req, span= 250e6, ref_power = self.ref_power)
        plt.plot(freqs_i, amps_i)
        
        def objective_func(offset_I, offset_Q):
            self.qm.set_output_dc_offset_by_element(self.element, "I", float(offset_I)) 
            self.qm.set_output_dc_offset_by_element(self.element, "Q", float(offset_Q))
        
            freqs, amps = self.sa.sweep(center=self.lo_req, span= 250e6, ref_power = self.ref_power)
            
            # around postion of lo, required_sideband, removed_sideband
            # np.searchsorted(list, threshold, side='right') most fast way 
            # index_required_sideband = np.argmax(freq>= (self.lo_freq+self.if_freq))
            # index_removed_sideband = np.argmax(freq>= (self.lo_freq-self.if_freq))
            
            threshold = np.mean(amps)
            index_lo = np.argmax(freq>= self.lo_freq)
            lo_peak_amps = amps[index_lo]
            contrast = lo_peak_amps - threshold
            return np.abs(contrast) 
        
        result = sc.optimize.minimize(objective_func, [0, 0], method='Nelder-Mead', fatol= fatol)
        
        if result.success:
            fitted_params = result.x
            print("The I Q offsets are ",fitted_params)

            self.qm.set_output_dc_offset_by_element(self.element, "I", float(fitted_params[0])) 
            self.qm.set_output_dc_offset_by_element(self.element, "Q", float(fitted_params[1]))
            freqs_f, amps_f = self.sa.sweep(center=self.lo_req, span= 250e6, ref_power = self.ref_power)
            plt.plot(freqs_f, amps_f)
        else:
            raise ValueError(result.message)
        
    def offset_iq_imbalance(self, fatol=1):  
        # fatol = 1dB
        print('Offset IQ imbalance')
        freq_i, amps_i = sa.sweep(center=self.lo_req, span= 250e6, ref_power = self.ref_power)
        plt.plot(freqs_i, amps_i)
        
        
        def objective_func(gain, phase):
            self.qm.set_mixer_correction("mixer_"+element, int(self.if_freq), int(self.lo_freq), IQ_imbalance(gain, phase))
        
            freqs, amps = self.sa.sweep(center=self.lo_req, span= 250e6, ref_power = self.ref_power)
            
            # around postion of lo, required_sideband, removed_sideband
            # np.searchsorted(list, threshold, side='right') most fast way 
            # index_required_sideband = np.argmax(freq>= (self.lo_freq+self.if_freq))
            index_removed_sideband = np.argmax(freq>= (self.lo_freq-self.if_freq))
            
            threshold = np.mean(amps)
            removed_sideband_peak_amps = amps[index_removed_sideband]
            contrast = removed_sideband_peak_amps - threshold
            return np.abs(contrast) 
        
        result = sc.optimize.minimize(objective_func, [0, 0], method='Nelder-Mead', fatol= fatol)
        
        if result.success:
            fitted_params = result.x
            print("The mixer correction is ",fitted_params)
            fitted_params
            self.qm.set_mixer_correction("mixer_"+element, int(self.if_freq), int(self.lo_freq), IQ_imbalance(fitted_params[0], fitted_params[0]))
            
            freqs_f, amps_f = self.sa.sweep(center=self.lo_req, span= 200e6, ref_power = self.ref_power)
            plt.plot(freqs_f, amps_f)

        else:
            raise ValueError(result.message)