openquantumhardware/qick

Hardware loop frequency sweep ZCU216

Jalbanese02 opened this issue · 1 comments

I have been trying to implement a hardware level loop over varying frequencies in qick. However, I run into an issue when attempting to sweep over the frequency in the standard way by incrementing the 'freq' register. The following program demonstrates the problem I am facing:

from qick import *
from tqdm.notebook import tqdm
import matplotlib.pyplot as plt
import numpy as np
soc = QickSoc()
soccfg = soc

class SweepProgram(RAveragerProgram):
    def initialize(self):
        cfg=self.cfg   

        
        self.declare_gen(ch=cfg["res_ch"], nqz=1)      # set the nyquist zone
        self.r_rp=self.ch_page(self.cfg["res_ch"])     # get register page for res_ch
        self.r_freq=self.sreg(cfg["res_ch"], "freq")   #Get freq register for res_ch
        self.step = self.freq2reg(self.cfg["step"])
        
        #Note that freq=100
        self.declare_readout(ch=cfg["ro_ch"], length=self.cfg["readout_length"],
                             freq=100, gen_ch=cfg["res_ch"])
        
        #Begin frequency sweep from 80Mhz
        freq=self.freq2reg(80, gen_ch=cfg["res_ch"], ro_ch=cfg["ro_ch"])  # convert frequency to dac frequency (ensuring it is an available adc frequency)
        self.set_pulse_registers(ch=cfg["res_ch"], style="const", freq=freq, phase=0, gain=cfg["pulse_gain"], 
                                 length=cfg["length"])
        self.synci(200)  # give processor some time to configure pulses

    def body(self):        
        self.measure(pulse_ch=self.cfg["res_ch"], 
             adcs=[self.cfg["ro_ch"]],
             adc_trig_offset=self.cfg["adc_trig_offset"],
             wait=True,
             syncdelay=self.us2cycles(self.cfg["relax_delay"]))        
        
    def update(self):
        self.mathi(self.r_rp, self.r_freq, self.r_freq, '+', self.step) # update freq of the pulse
        
config={"res_ch":6, # --Fixed
        "ro_ch":0, # --Fixed
        "relax_delay":0.01, # --Fixed
        "res_phase":0, # --Fixed
        "pulse_style": "const", # --Fixed
        "length":100, # [Clock ticks]        
        "readout_length":100, # [Clock ticks]
        "pulse_gain":1000, # [DAC units]
        "pulse_freq": 100, # [MHz]
        "adc_trig_offset": 10, # [Clock ticks]
        "reps":1, 
        "expts": 400,
        "start":80, # [MHz]
        "step":0.1 # [MHz]
       }

prog = SweepProgram(soccfg, config)
print(prog)
expt, avg_i, avg_q = prog.acquire(soc, load_pulses=True)
plt.xlabel("Frequency (MHz)")
plt.ylabel("Amplitude")
plt.plot(expt, abs(np.squeeze(avg_i) + 1j *np.squeeze(avg_q)))

giving the following output
image

I understand that this is an issue relating to the downconversion frequency, which we set in declare_readout (in the example we set it as 100MHz). My question is: can changing the downconversion frequency be implemented in the hardware, as part of the qick program loop? I have been unable to find a relevant register which could be accessed in a hardware loop to implement this, and I am uncertain whether such an implementation would be as simple as I imagine.

In every example that I have found, frequency sweeping has been implemented in software, and I would like to know the reason for this.

meeg commented

No, it's not possible in the standard firmware - this is mentioned in the 02_Sweeping_variables.ipynb demo (albeit briefly).