qick.qick_asm
The interface for writing QICK programs. This contains tools for managing the board configuration and the base class for QICK programs. The assembly language for QICK programs is defined separately for the v1 and v2 tProcessors.
Classes
|
Generic QICK program, including support for generator and readout configuration but excluding tProc-specific code. |
|
Adds acquire() and acquire_decimated() methods for acquiring readout data, and run_rounds() for running repeatedly without acquisition. |
|
Uses the QICK configuration to convert frequencies and clock delays. |
- class qick.qick_asm.QickConfig(cfg=None)[source]
Bases:
objectUses the QICK configuration to convert frequencies and clock delays. If running on the QICK, you don’t need to use this class - the QickSoc class has all of the same methods. If running remotely, you may want to initialize a QickConfig from a JSON file.
- description()[source]
Generate a printable description of the QICK configuration.
- Returns:
description
- Return type:
- get_cfg()[source]
Return the QICK configuration dictionary. This contains everything you need to recreate the QickConfig.
- Returns:
configuration dictionary
- Return type:
- dump_cfg()[source]
Generate a JSON description of the QICK configuration. You can save this string to a file and load it to recreate the QickConfig.
- Returns:
configuration in JSON format
- Return type:
- calc_fstep_int(dict1, other_dicts)[source]
Finds the multiplier that needs to be applied to a channel’s frequency step size to allow this channel to be frequency-matched with another channel.
- calc_fstep(dicts)[source]
Finds the least common multiple of the frequency steps of one or more channels (typically two, a generator and a readout) For proper frequency matching, you should only use frequencies that are evenly divisible by this value. The order of the parameters does not matter.
- roundfreq(f, dicts)[source]
Round a frequency to the LCM of the frequency steps of one or more channels (typically two, a generator and a readout).
- Parameters:
f (float or numpy.ndarray) – frequency (MHz)
- Returns:
rounded frequency (MHz)
- Return type:
- freq2int(f, thisch, otherch=None)[source]
Converts frequency in MHz to integer value suitable for writing to a register. This method works for both generators and readouts. If a gen will be connected to an RO, the two channels must have exactly the same frequency, and you must supply the config for the other channel.
- int2freq(r, thisch)[source]
Converts register value to MHz. This method works for both generators and readouts.
- freq2reg(f, gen_ch=0, ro_ch=None)[source]
Converts frequency in MHz to tProc generator register value.
- adcfreq(f, gen_ch=0, ro_ch=0)[source]
Takes a frequency and trims it to the closest DDS frequency valid for both channels.
- deg2int(deg, thisch)[source]
Converts phase in degrees to integer value suitable for writing to a register. This method works for both generators and readouts.
- int2deg(r, thisch)[source]
Converts register value to degrees. This method works for both generators and readouts.
- deg2reg(deg, gen_ch=0, ro_ch=None)[source]
Converts degrees into phase register values; numbers greater than 360 will effectively be wrapped.
- cycles2us(cycles, gen_ch=None, ro_ch=None)[source]
Converts clock cycles to microseconds. Uses tProc clock frequency by default. If gen_ch or ro_ch is specified, uses that generator/readout channel’s fabric clock.
- us2cycles(us, gen_ch=None, ro_ch=None, as_float=False)[source]
Converts microseconds to integer number of clock cycles. Uses tProc clock frequency by default. If gen_ch or ro_ch is specified, uses that generator/readout channel’s fabric clock.
- calc_mixer_freq(gen_ch, mixer_freq, nqz, ro_ch)[source]
Set the NCO frequency that will be mixed with the generator output.
The RFdc driver does its own math to convert a frequency to a register value. (see XRFdc_SetMixerSettings in xrfdc_mixer.c, and “NCO Frequency Conversion” in PG269) This is what it does: 1. Add/subtract fs to get the frequency in the range of [-fs/2, fs/2]. 2. If the original frequency was not in [-fs/2, fs/2] and the DAC is configured for 2nd Nyquist zone, multiply by -1. 3. Convert to a 48-bit register value, rounding using C integer casting (i.e. round towards 0).
Step 2 is not desirable for us, so we must undo it.
The rounding gives unexpected results sometimes: it’s hard to tell if a freq will get rounded up or down. This is important if the demanded frequency was rounded to a valid frequency for frequency matching. The safest way to get consistent behavior is to always round to a valid NCO frequency. We are trusting that the floating-point math is exact and a number we rounded here is still a round number in the RFdc driver.
- calc_muxgen_regs(gen_ch, freqs, gains, phases, ro_ch, absolute_freqs, mixer_freq)[source]
Calculate the register values to program into a multiplexed generator. mixer_freq will have been rounded appropriately in declare_gen, and will be 0 if there’s no mixer
- calc_ro_regs(rocfg, phase, sel)[source]
Calculate the settings to configure a readout.
- Returns:
settings for QickSoc.config_readout()
- Return type:
- calc_ro_freq(rocfg, ro_pars, ro_regs, absolute_freqs, mixer_freq, flip_freq=False)[source]
Calculate the readout frequency and registers.
- check_pfb_collisions(rocfg, cfg1, cfgs)[source]
Check whether the specified PFB config collides or interefers with any others. If this PFB block can’t put two readouts on the same channel, this method will raise an error on collisions. Possible crosstalk will be identified in warnings.
- class qick.qick_asm.AbsQickProgram(soccfg)[source]
Bases:
ABCGeneric QICK program, including support for generator and readout configuration but excluding tProc-specific code. QickProgram/QickProgramV2 are the concrete subclasses for tProc v1/v2.
The tProc executes binary machine code; you write declarations and ASM code (or macros that get expanded to ASM). So before a program gets run, you need to fill it with declarations and ASM, and they need to get compiled (converted to machine code). There are three ways to prepare a QickProgram for running:
1. External initialization: Create an empty program object. Write the program by calling declaration and ASM methods of the program object. The program will be compiled when you try to run, dump, or print it.
2. Internal initialization: Create a subclass which calls declaration and ASM methods as part of __init__(). When you create an instance of the subclass, it will automatically fill itself. Typically you won’t subclass QickProgram directly, you will subclass something like AveragerProgram which does a lot of the work for you. The program will be compiled when you try to run, dump, or print.
3. Loading a dump: Create an empty program object. Call QickProgram.load_prog() to load the program definition from a dump. The program will be compiled as part of load_prog().
- dump_prog()[source]
Dump the program to a dictionary. This output contains all the information necessary to run the program. In other words, it will have the low-level ASM and pulse+envelope data, but not higher-level structures. Caution: don’t modify the sub-dictionaries of this dict! You will be modifying the original program (this is not a deep copy).
- config_all(soc, load_envelopes=True, reset=False, load_mem=True)[source]
Load the waveform memory, gens, ROs, and program memory as specified for this program. The decimated+accumulated buffers are not configured, since those should be re-configured for each acquisition. The tProc is set to internal start before any other configuration is done, to prevent spurious external starts.
- Parameters:
reset (bool) – Force-stop the tProc before loading the program. This option only affects tProc v1, where the reset takes several ms. For tProc v2, where reset is easy, we always do the reset.
- run(soc, load_prog=True, load_envelopes=True, start_src='internal')[source]
Load the program into the tProcessor and start it. Because there is in general no way to tell when a program is done running, there is no guarantee that the program will be done before this method returns. If you want that guarantee, use run_rounds().
- Parameters:
soc (QickSoc) – The QickSoc that will execute this program.
load_prog (bool) – Load the program before starting the tProc.
load_envelopes (bool) – Load the generator envelopes before starting the tProc. If load_prog is False, load_envelopes is ignored.
start_src (str) – “internal” (tProc starts immediately) or “external” (each round waits for an external trigger).
- declare_readout(ch, length, freq=None, phase=0, sel='product', gen_ch=None, edge_counting=False, high_threshold=0, low_threshold=0, weights=None)[source]
Add a channel to the program’s list of readouts. Duration units depend on the program type: tProc v1 programs use integer number of samples, tProc v2 programs use float us.
- Parameters:
ch (int) – readout channel number (index in ‘readouts’ list)
freq (float) – downconverting frequency (MHz)
phase (float) – phase (degrees)
length (int or float) – readout length (number of decimated samples for tProc v1, us for tProc v2)
sel (str) – output select (‘product’, ‘dds’, ‘input’)
gen_ch (int) – generator channel (use None if you don’t want the downconversion frequency to be rounded to a valid DAC frequency or be offset by the DAC mixer frequency)
edge_counting (bool) – Sets edge counting mode on or off
high_threshold (int) – Sets the edge counting threshold level to go above to trigger a single count
low_threshold (int) – Sets the edge counting threshold level to go below to reset the trigger for next count
weights (numpy.ndarray) – Array of int16, shape (N, 2), representing an IQ array by which to multiply the readout window. Can only be used if this readout channel has a weighted buffer. If left as None, the weights will be set to [2**15-2, 0] (the maximum positive real value). If used, N must equal the number of decimated samples in the readout window.
- config_readouts(soc)[source]
Configure the readout channels specified in this program. This is usually called as part of an acquire() method.
- Parameters:
soc (QickSoc) – the QickSoc that will execute this program
- config_bufs(soc, enable_avg=True, enable_buf=True)[source]
Configure the readout buffers specified in this program. This is usually called as part of an acquire() method.
- declare_gen(ch, nqz=1, mixer_freq=None, mux_freqs=None, mux_gains=None, mux_phases=None, ro_ch=None)[source]
Add a channel to the program’s list of signal generators.
If this is a generator with a mixer (interpolated or muxed generator), you may define a mixer frequency.
If this is a muxed generator, the mux_freqs list must be long enough to define all the tones you will play. (in other words, if your mask list ever enables tone 2 you must define at least 3 freqs+gains) If your mux gen supports gains and/or phases and you define them, those lists must be the same length. If you don’t define gains or phases, they will be set to defaults (max positive gain, zero phase).
- Parameters:
ch (int) – generator channel (index in ‘gens’ list)
nqz (int, optional) – Nyquist zone (must be 1 or 2). Setting the NQZ to 2 increases output power in the 2nd/3rd Nyquist zones.
mixer_freq (float, optional) – Mixer frequency (in MHz)
mux_freqs (list of float, optional) – Tone frequencies for the muxed generator (in MHz). For tProc v1 programs these should be given as offsets relative to the digital mixer frequency. For tProc v2 they should be given as absolute frequencies. Positive and negative values are allowed.
mux_gains (list of float, optional) – Tone amplitudes for the muxed generator (in range -1 to 1).
mux_phases (list of float, optional) – Phases for the muxed generator (in degrees).
ro_ch (int, optional) – readout channel for frequency-matching mixer and mux freqs
- config_gens(soc)[source]
Configure the signal generators specified in this program. This is usually called as part of an acquire() method.
- Parameters:
soc (QickSoc) – the QickSoc that will execute this program
- add_envelope(ch, name, idata=None, qdata=None)[source]
Adds a waveform to the list of envelope waveforms available for this channel. The I and Q arrays must be of equal length, and the length must be divisible by the samples-per-clock of this generator. If either array is omitted, zeros will be used for that component.
If this channel uses a real-only envelope, qdata must be omitted or all zeros.
- Parameters:
ch (int) – generator channel (index in ‘gens’ list)
name (str) – Name of the pulse
idata (numpy.ndarray or None) – I data
qdata (numpy.ndarray or None) – Q data
- add_cosine(ch, name, length, maxv=None, even_length=False)[source]
Adds a cosine to the envelope library. The envelope will peak at length/2. Duration units depend on the program type: tProc v1 programs use integer number of fabric clocks, tProc v2 programs use float us.
- Parameters:
ch (int) – generator channel (index in ‘gens’ list)
name (str) – Name of the envelope
length (int) – Total envelope length (in fabric clocks or us)
maxv (float) – Value at the peak (if None, the max value for this generator will be used)
even_length (bool) – If length is in us, round the envelope length to an even number of fabric clock cycles. This is useful for flat_top pulses, where the envelope gets split into two halves.
- add_gauss(ch, name, sigma, length, maxv=None, even_length=False)[source]
Adds a Gaussian to the envelope library. The envelope will peak at length/2. Duration units depend on the program type: tProc v1 programs use integer number of fabric clocks, tProc v2 programs use float us.
- Parameters:
ch (int) – generator channel (index in ‘gens’ list)
name (str) – Name of the envelope
sigma (float) – Standard deviation of the Gaussian (in fabric clocks or us)
length (int or float) – Total envelope length (in fabric clocks or us)
maxv (float) – Value at the peak (if None, the max value for this generator will be used)
even_length (bool) – If length is in us, round the envelope length to an even number of fabric clock cycles. This is useful for flat_top pulses, where the envelope gets split into two halves.
- add_DRAG(ch, name, sigma, length, delta, alpha=0.5, det=0, maxv=None, even_length=False)[source]
Adds a DRAG pulse to the envelope library. DRAG with constant detuning is implemented as defined in https://doi.org/10.1103/PhysRevLett.116.020501.
The envelope will peak at length/2.
- Parameters:
ch (int) – generator channel (index in ‘gens’ list)
name (str) – Name of the envelope
sigma (float or float) – Standard deviation of the Gaussian (in fabric clocks or us)
length (int or float) – Total envelope length (in fabric clocks or us)
delta (float) – anharmonicity of the qubit, the difference between f_ge and f_ef (units of MHz)
alpha (float) – alpha parameter of DRAG (order-1 scale factor)
det (float) – constant detuning (units of MHz)
maxv (float) – Value at the peak (if None, the max value for this generator will be used)
even_length (bool) – If length is in us, round the envelope length to an even number of fabric clock cycles. This is useful for flat_top pulses, where the envelope gets split into two halves.
- add_triangle(ch, name, length, maxv=None, even_length=False)[source]
Adds a triangle to the envelope library. The envelope will peak at length/2. Duration units depend on the program type: tProc v1 programs use integer number of fabric clocks, tProc v2 programs use float us.
- Parameters:
ch (int) – generator channel (index in ‘gens’ list)
name (str) – Name of the envelope
length (int or float) – Total envelope length (in fabric clocks or us)
maxv (float) – Value at the peak (if None, the max value for this generator will be used)
even_length (bool) – If length is in us, round the envelope length to an even number of fabric clock cycles. This is useful for flat_top pulses, where the envelope gets split into two halves.
- load_envelopes(soc)[source]
Loads envelopes that were added using add_envelope into the SoC’s signal generator memories. Also load weight arrays for weighted buffers.
- Parameters:
soc (QickSoc) – Qick object
- class qick.qick_asm.AcquireMixin(*args, **kwargs)[source]
Bases:
objectAdds acquire() and acquire_decimated() methods for acquiring readout data, and run_rounds() for running repeatedly without acquisition. Program classes that use this mixin must call setup_acquire() after _init_prog() and before acquire()/acquire_decimated().
- setup_counter(counter_addr, loop_dims)[source]
Set the parameters needed to track the progress of the program. This is a subset of setup_acquire(), appropriate for programs where you have no readouts. You should use this if you’re updating a tProc counter and want to use it to track program progress.
- setup_acquire(counter_addr, loop_dims, avg_level)[source]
Set the parameters needed to define the data acquisition. Since the number of readouts per shot is set based on calls to trigger(), this should be called after the program has been fully defined.
- set_reads_per_shot(reads_per_shot)[source]
Override the default count of readout triggers per shot. This should be called after setup_acquire(). You probably shouldn’t be using this method; the default value is usually correct.
- get_rounds()[source]
Get the results from each round, before averaging over rounds. This can be called after acquire() or acquire_decimated().
- Returns:
Array of I/Q values for each readout channel. Same dimensions as the return value from acquire()/acquire_decimated().
- Return type:
- get_raw()[source]
Get the raw integer I/Q values (before normalizing to the readout window, averaging across reps, removing the readout offset, or thresholding). This can be called after acquire().
- Returns:
Array of I/Q values for each readout channel. The array dimensions correspond to the loop dimensions, data is in time order.
- Return type:
- get_shots()[source]
Get the shot-by-shot threshold decisions. This can be called after acquire().
- Returns:
Array of shots for each readout channel.
- Return type:
- get_time_axis(ro_index, length_only=False)[source]
Get an array usable as the time axis for plotting decimated data.
- Parameters:
- Returns:
An array starting at 0 and spaced by the time (in us) per decimated sample. If length_only=True, an int is returned.
- Return type:
numpy.ndarray of float, or int
- get_time_axis_ddr4(ro_ch, data)[source]
Get an array usable as the time axis for plotting DDR4 data.
- Parameters:
ro_ch (int) – readout channel (index in ‘readouts’ list)
data (numpy.ndarray) – DDR4 data array, the returned array will have the same length.
- Returns:
An array starting at 0 and spaced by the time (in us) per decimated sample.
- Return type:
- get_time_axis_mr(ro_ch, data)[source]
Get an array usable as the time axis for plotting MR data.
- Parameters:
ro_ch (int) – readout channel (index in ‘readouts’ list)
data (numpy.ndarray) – MR data array, the returned array will have the same length.
- Returns:
An array starting at 0 and spaced by the time (in us) per MR sample.
- Return type:
- acquire(soc, rounds=1, load_envelopes=True, start_src='internal', threshold=None, angle=None, progress=True, remove_offset=True, step_rounds=False, extra_args=None)[source]
Acquire data using the accumulated readout.
- Parameters:
soc (QickSoc) – Qick object
rounds (int) – number of times to rerun the program, averaging results in software (aka “soft averages”)
load_envelopes (bool) – if True, load pulse envelopes
start_src (str) – “internal” (tProc starts immediately) or “external” (each round waits for an external trigger)
threshold (float or list of float) – The threshold(s) to apply to the I values after rotation. Length-normalized units (same units as the output of acquire()). If scalar, the same threshold will be applied to all readout channels. A list must have length equal to the number of declared readout channels.
angle (float or list of float) – The angle to rotate the I/Q values by before applying the threshold. Units of radians. If scalar, the same angle will be applied to all readout channels. A list must have length equal to the number of declared readout channels.
progress (bool) – if true, displays progress bar
remove_offset (bool) – Some readouts (muxed and tProc-configured) introduce a small fixed offset to the I and Q values of every decimated sample. This subtracts that offset, if any, before returning the averaged IQ values or rotating to apply software thresholding.
step_rounds (bool) – Return after setting up the acquisition and preparing the first round. You will need to step through and complete the acquisition with prepare_round(), finish_round(), and finish_acquire().
extra_args (dict or None) – If the data-processing methods have been overriden and need extra arguments, those are supplied here and will be added to acquire_params.
- Returns:
averaged IQ values (float) divided by the length of the RO window, and averaged over reps and rounds if threshold is defined, the I values will be the fraction of points over threshold dimensions for a simple averaging program: (n_ch, n_reads, 2) dimensions for a program with multiple expts/steps: (n_ch, n_reads, n_expts, 2)
- Return type:
- run_rounds(soc, rounds=1, load_envelopes=True, start_src='internal', progress=True, step_rounds=False)[source]
Run the program and wait until it completes, once or multiple times. No data will be saved.
- Parameters:
soc (QickSoc) – Qick object
rounds (int) – number of times to rerun the program
load_envelopes (bool) – if True, load pulse envelopes and buffer weights
start_src (str) – “internal” (tProc starts immediately) or “external” (each round waits for an external trigger)
progress (bool) – if true, displays progress bar
step_rounds (bool) – Return after setting up and preparing the first round. You will need to step through and complete the acquisition with prepare_round(), finish_round(), and finish_acquire().
- acquire_decimated(soc, rounds=1, load_envelopes=True, start_src='internal', progress=True, remove_offset=True, step_rounds=False, extra_args=None)[source]
Acquire data using the decimating readout.
- Parameters:
soc (QickSoc) – Qick object
rounds (int) – number of times to rerun the program, averaging results in software (aka “soft averages”)
load_envelopes (bool) – if True, load pulse envelopes and buffer weights
start_src (str) – “internal” (tProc starts immediately) or “external” (each round waits for an external trigger)
progress (bool) – if true, displays progress bar
remove_offset (bool) – Subtract the readout’s IQ offset, if any.
step_rounds (bool) – Return after setting up the acquisition and preparing the first round. You will need to step through and complete the acquisition with prepare_round(), finish_round(), and finish_acquire().
extra_args (dict or None) – If the data-processing methods have been overriden and need extra arguments, those are supplied here and will be added to acquire_params.
- Returns:
decimated values, averaged over rounds (float) dimensions for a single-rep, single-read program : (length, 2) multi-rep or multi-read: (n_reps*n_reads, length, 2) multi-rep and multi-read: (n_reps, n_reads, length, 2)
- Return type:
- prepare_round()[source]
Used with the step_rounds argument to acquire()/acquire_decimated()/run_rounds().
This sets up the round by preparing data structures and configuring the firmware, including arming the tProc for external start (if used).
The first round is prepared for you by acquire()/acquire_decimated()/run_rounds().
- finish_round()[source]
Used with the step_rounds argument to acquire()/acquire_decimated()/run_rounds().
This runs the round by starting the tProc (if using internal start), then collecting and processing the data.
- Returns:
True if more rounds remain to be run. This is meant to be used to control a while loop.
- Return type:
- finish_acquire()[source]
Used with the step_rounds argument to acquire()/acquire_decimated()/run_rounds().
- Returns:
Data in the same format that would be returned by acquire()/acquire_decimated().
- Return type: