From f4d397a6338be4c23797cdea1f70c8d0824ec5dc Mon Sep 17 00:00:00 2001 From: Clelandlab1 Ygritte <30175757+phantomlsh@users.noreply.github.com> Date: Mon, 28 Oct 2024 13:08:43 -0500 Subject: [PATCH] Version 0.3.2 Support mux --- docs/Tutorials/mercator.md | 16 ++++++++++++++++ quick/VERSION | 2 +- quick/mercator.py | 37 +++++++++++++++++++++++++++---------- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/docs/Tutorials/mercator.md b/docs/Tutorials/mercator.md index 3e42ded..b67ae6d 100644 --- a/docs/Tutorials/mercator.md +++ b/docs/Tutorials/mercator.md @@ -74,6 +74,7 @@ p0_style: const # [const|gaussian|DRAG|flat_top|arb] pulse style p0_phase: 0 # [deg] phase p0_length: 2 # [us] length p0_delta: -200 # [MHz] anharmonicity used in DRAG pulse +p0_mask: None # [list] mask used in multiplexed pulse (mux) p0_idata: None # [-1, 1] used in arb pulse, in DAC sample rates p0_qdata: None # [-1, 1] used in arb pulse, in DAC sample rates ``` @@ -86,6 +87,21 @@ p0_sigma: 0.05 # [us] gaussian std in flat_top/gaussian/DRAG pulse. # Its default value is 1/5 of p0_length ``` +**multiplexed Pulse (mux)**: + +Passing list to `freq`, `gain`, and `phase`. The list lengths must match each other. Multiplexed pulse is configurated on generator level. Therefore all pulses on the mux generator must share the same mux settings. You can change `length` and `mask` for individual pulse. + +The gain value range shrinks with more tones. It takes `[-1, 1]` for 1 tone, `[-0.5, 0.5]` for 2 tones, `[-0.25, 0.25]` for 3 or 4 tones, and `[-0.125, 0.125]` for 5 to 8 tones. + +```yaml +p0_style: const # only support const +p0_freq: [5500, 6000, 6500] +p0_gain: [0.25, 0.25, 0.25] +p0_phase: [0, 0, 0] +p0_length: 2 +p0_mask: [0, 1, 2] # defaulted to all +``` + ## Readout Channel Setup In this section, you can prepare your readout (ADC) channels. All properties in this section have prefix `rx_`, where `x` represents the readout channel number. This document use `r0_` as an example. diff --git a/quick/VERSION b/quick/VERSION index 9e11b32..d15723f 100644 --- a/quick/VERSION +++ b/quick/VERSION @@ -1 +1 @@ -0.3.1 +0.3.2 diff --git a/quick/mercator.py b/quick/mercator.py index 704a16d..2cc6102 100644 --- a/quick/mercator.py +++ b/quick/mercator.py @@ -4,6 +4,8 @@ import matplotlib.pyplot as plt import matplotlib.patches as patches +listType = (list, np.ndarray) + def generate_waveform(o, soccfg): f_fabric = soccfg["gens"][o["g"]]["f_fabric"] samps_per_clk = soccfg["gens"][o["g"]]["samps_per_clk"] @@ -63,11 +65,12 @@ def parse(soccfg, cfg): c["g"][o["g"]]["freq"] = o["freq"] o["mode"] = cfg.get(f"p{p}_mode", "oneshot") o["style"] = cfg.get(f"p{p}_style", "const") - o["phase"] = cfg.get(f"p{p}_phase", 0) o["length"] = cfg.get(f"p{p}_length", 2) o["sigma"] = cfg.get(f"p{p}_sigma", o["length"] / 5) o["delta"] = cfg.get(f"p{p}_delta", -200) o["gain"] = cfg.get(f"p{p}_gain", 0) + o["mask"] = cfg.get(f"p{p}_mask", list(range(len(o["freq"]))) if isinstance(o["freq"], listType) else None) + o["phase"] = cfg.get(f"p{p}_phase", list(np.zeros(len(o["freq"]))) if isinstance(o["freq"], listType) else 0) o["idata"] = cfg.get(f"p{p}_idata", None) o["qdata"] = cfg.get(f"p{p}_qdata", None) if f"p{p}_power" in cfg: @@ -95,20 +98,33 @@ class Mercator(AveragerProgramV2): """General class for preparing and sending a pulse sequence.""" def _initialize(self, cfg): c = self.c + mux_gain_factor = { 1: 1, 2: 2, 3: 4, 4: 4, 5: 8, 6: 8, 7: 8, 8: 8 } for g, o in c["g"].items(): # Declare Generator Channels kwargs = {} if self.soccfg["gens"][g]["has_mixer"]: kwargs["mixer_freq"] = o["freq"] kwargs["ro_ch"] = o["r"] + if isinstance(o["freq"], listType): # mux + kwargs["mixer_freq"] = np.mean(o["freq"]) + kwargs["mux_freqs"] = o["freq"] + kwargs["mux_gains"] = np.array(c["p"][o["p"]]["gain"]) * mux_gain_factor[len(o["freq"])] + kwargs["mux_phases"] = c["p"][o["p"]]["phase"] self.declare_gen(ch=g, nqz=o["nqz"], **kwargs) for r, o in c["r"].items(): # Declare Readout Channels - self.declare_readout(ch=r, length=o["length"]) - self.add_readoutconfig(ch=r, name=f"r{r}", freq=o['freq'], gen_ch=o["g"], phase=o["phase"]) - self.send_readoutconfig(ch=r, name=f"r{r}", t=0) + if "tproc_ctrl" in self.soccfg["readouts"][r]: + self.declare_readout(ch=r, length=o["length"]) + self.add_readoutconfig(ch=r, name=f"r{r}", freq=o["freq"], gen_ch=o["g"], phase=o["phase"]) + self.send_readoutconfig(ch=r, name=f"r{r}", t=0) + else: # mux readout + self.declare_readout(ch=r, length=o["length"], freq=o["freq"], phase=o["phase"], gen_ch=o["g"]) for p, o in c["p"].items(): # Setup pulses - kwargs = { "style": o["style"] } + kwargs = { "style": o["style"], "ro_ch": o["r"], "freq": o["freq"], "phase": o["phase"], "gain": o["gain"] } if o["style"] == "const": kwargs["mode"] = o["mode"] + if o["mask"] is not None: # mux mask + kwargs["mask"] = o["mask"] + for k in ["freq", "ro_ch", "mode", "phase", "gain"]: + kwargs.pop(k, None) else: # non-const pulse kwargs["envelope"] = f"e{p}" maxv = self.soccfg.get_maxv(o["g"]) @@ -119,7 +135,7 @@ def _initialize(self, cfg): kwargs["length"] = o["length"] else: kwargs["style"] = "arb" - self.add_pulse(ch=o["g"], name=f"p{p}", ro_ch=o["r"], freq=o["freq"], phase=o["phase"], gain=o["gain"], **kwargs) + self.add_pulse(ch=o["g"], name=f"p{p}", **kwargs) if cfg["rep"] > 0: self.add_loop("rep", cfg["rep"]) self.delay(0.5) @@ -174,18 +190,19 @@ def light(self): def add_pulse(p, g, start, first=True): us = self.cycles2us(1, gen_ch=g) / self.soccfg["gens"][g]["samps_per_clk"] o = c["p"][p] + gain = o["gain"][0] if isinstance(o["gain"], listType) else o["gain"] if first: data[g].append([start, 0]) - ax.annotate(f"p{p}", (start, o["gain"] + 0.05)) + ax.annotate(f"p{p}", (start, gain + 0.05)) if o["idata"] is not None: l = o["length"] if o["style"] == "flat_top" else 0 end = start + l + len(o["idata"]) * us h = len(o["idata"]) // 2 - data[g].extend(list(zip(np.arange(h)*us + start, o["gain"] * np.array(o["idata"])[:h]))) - data[g].extend(list(zip(np.arange(h)*us + start + l + h*us, o["gain"] * np.array(o["idata"])[h:]))) + data[g].extend(list(zip(np.arange(h)*us + start, gain * np.array(o["idata"])[:h]))) + data[g].extend(list(zip(np.arange(h)*us + start + l + h*us, gain * np.array(o["idata"])[h:]))) else: end = start + o["length"] - data[g].extend([[start, o["gain"]], [end, o["gain"]]]) + data[g].extend([[start, gain], [end, gain]]) if o["mode"] != "periodic": data[g].append([end, 0]) periodic[g] = (o["mode"] == "periodic")