Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/topics/example.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Example code
=============


## Other examples of QICK measurement code, shared by QICK collaborators
tProc V1 base

* [IEEE Quantum Week 2023 QICK tutorial](https://github.com/openquantumhardware/QCE2023_public)

* [Connie Miao, Schuster Lab](https://github.com/conniemiao/slab_rfsoc_expts)

* [Chao Zhou, Hatlab](https://github.com/PITT-HATLAB/Hatlab_RFSOC)

tProc V2 base

* [Jay, SQL Lab](https://github.com/JayChien04717/QickworksaceV2_proj)
11 changes: 11 additions & 0 deletions docs/topics/index.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
Specific topics
===============

This section collects focused explanations of concepts that come up when
writing QICK programs. Use these pages when you need background on timing,
frequency placement, pulse playback, generator configuration, units, clocking,
or the differences between assembly interfaces.

For first-time setup and hardware bring-up, start with the :doc:`../quick_start`
guide instead. For class and function details, use the :doc:`../modules` API
reference.

.. toctree::
:maxdepth: 1

Expand All @@ -12,3 +21,5 @@ Specific topics
units
changing_fs
reference_clock
tprocv2
example
128 changes: 128 additions & 0 deletions docs/topics/tprocv2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
tProc v2
========

tProc v2 is the latest generation of the QICK timed processor. It keeps the
same basic role as tProc v1--sequencing pulses, triggers, readout windows, and
feedback--but reorganizes both the firmware interface and the Python programming
model.

This page is a short migration guide for users who already know tProc v1 and
want to understand the most important changes before writing tProc v2 programs.


Hardware sweeping
------------------

In tProc v1 programs, hardware sweeps often required an ``update()`` method
with explicit register math. For example, a gain sweep might update the
generator gain register with ``mathi()`` after each shot:

.. code-block:: python

class Program(RAveragerProgram):
def initialize(self):
self.q_rp = self.ch_page(self.cfg["qubit_ch"])
self.r_gain = self.sreg(self.cfg["qubit_ch"], "gain")

def body(self):
...

def update(self):
self.mathi(self.q_rp, self.r_gain, self.r_gain, "+", self.cfg["step"])

gain_list, avgi, avgq = prog.acquire(soc)

tProc v2 provides higher-level sweep helpers. A program can declare a loop,
attach a swept parameter to that loop, and then query the compiled program for
the actual sweep points:

.. code-block:: python

class Program(AveragerProgramV2):
def _initialize(self, cfg):
self.add_loop("gainloop", cfg["steps"])
self.add_pulse(
ch=cfg["qubit_ch"],
name="qubit_pulse",
style="const",
freq=cfg["freq"],
phase=0,
gain=QickSweep1D("gainloop", cfg["gain_start"], cfg["gain_stop"]),
length=cfg["length"],
)

def _body(self, cfg):
self.pulse(ch=cfg["qubit_ch"], name="qubit_pulse", t=0)

iq_list = prog.acquire(soc, rounds=avg, progress=False)
gains = prog.get_pulse_param("qubit_pulse", "gain", as_array=True)

Common swept parameters include:

* Frequency
* Length
* Time
* Gain

For frequency, length, and gain sweeps, use ``get_pulse_param()`` to query the
compiled sweep points:

.. code-block:: python

freqs = prog.get_pulse_param("qubit_pulse", "freq", as_array=True)
lengths = prog.get_pulse_param("qubit_pulse", "length", as_array=True)
gains = prog.get_pulse_param("qubit_pulse", "gain", as_array=True)

For timing sweeps, tag the timed instruction and use ``get_time_param()``:

.. code-block:: python

times = prog.get_time_param("time_tag", "t", as_array=True)

Timing
-------

In tProc v2, pulse and trigger times are written in user-facing units, usually
microseconds. The Python API converts these values to tProc timing-clock cycles
when the program is compiled.

Some tProc v1 timing names have also changed:

* ``sync_all`` is now ``delay_auto()``.
* ``synci`` is now ``delay()``.
* ``wait_auto()`` keeps the same basic purpose, but works with the tProc v2
timing model.


Play pulse
----------

In tProc v1, pulse parameters were often loaded into generator registers before
playing a pulse. In tProc v2, pulse settings are stored as waveforms in waveform
memory. A pulse can contain one or more waveforms, and playing a pulse sends the
corresponding waveform memory entry to the generator.

This makes it easier to define several pulses during initialization and choose
which one to play in the program body.

For example, a typical tProc v2 program does the following:

* Declare the generator and readout channels.
* Add pulse definitions in ``_initialize()``.
* Play those pulses in ``_body()`` with ``pulse()``.
* Use ``trigger()`` and acquisition methods when readout data is needed.

Units
-----

tProc v2 APIs generally use natural units:

* Times and pulse lengths are in microseconds.
* Frequencies are in MHz.
* Phases are in degrees.
* Gains are normalized values, usually from ``-1`` to ``1``.

The compiler rounds these values to the nearest supported hardware
representation. To inspect the rounded values actually used by a compiled
program, use helper methods such as ``get_pulse_param()`` and
``get_time_param()``.
2 changes: 1 addition & 1 deletion qick_lib/qick/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.2.406
0.2.412