diff --git a/docs/conf.py b/docs/conf.py index af98825d4b14976517cd8c63be081212c0bd4c0b..b751183b4770f5fa41aa79debed0016ac6353d53 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,6 +16,7 @@ import os import sys sys.path.insert(0, os.path.abspath('../')) +#import sphinx_rtd_theme # -- Project information ----------------------------------------------------- @@ -24,9 +25,9 @@ copyright = '2019, Stephan Philips' author = 'Stephan Philips' # The short X.Y version -version = '' +version = '1.3' # The full version, including alpha/beta/rc tags -release = '0.2 alpha' +release = '1.3' # -- General configuration --------------------------------------------------- @@ -44,6 +45,8 @@ extensions = [ 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', 'sphinx.ext.githubpages', + 'sphinx.ext.napoleon', + #'sphinx_rtd_theme', ] # Add any paths that contain templates here, relative to this directory. @@ -80,6 +83,7 @@ pygments_style = None # a list of builtin themes. # html_theme = 'sphinx_rtd_theme' +#html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/docs/img/DC_compensation_pulses.png b/docs/img/DC_compensation_pulses.png new file mode 100644 index 0000000000000000000000000000000000000000..558efdbac42966743e75ad06a239123e12e7640f Binary files /dev/null and b/docs/img/DC_compensation_pulses.png differ diff --git a/docs/img/Drawings.pptx b/docs/img/Drawings.pptx new file mode 100644 index 0000000000000000000000000000000000000000..7033cc6f6c335c33dae6d4c278b5cf86f42b376f Binary files /dev/null and b/docs/img/Drawings.pptx differ diff --git a/docs/img/IQ_gain_error.png b/docs/img/IQ_gain_error.png new file mode 100644 index 0000000000000000000000000000000000000000..361f817374ef90cb6757a46b82ae1d22bfa67dbb Binary files /dev/null and b/docs/img/IQ_gain_error.png differ diff --git a/docs/img/IQ_mixing.png b/docs/img/IQ_mixing.png new file mode 100644 index 0000000000000000000000000000000000000000..fa409944808d8c110454b9e9802c8dc3cade3f6a Binary files /dev/null and b/docs/img/IQ_mixing.png differ diff --git a/docs/img/IQ_offset_error.png b/docs/img/IQ_offset_error.png new file mode 100644 index 0000000000000000000000000000000000000000..a7d1b6701b0069f5b7c8645376b48269bdfc0284 Binary files /dev/null and b/docs/img/IQ_offset_error.png differ diff --git a/docs/img/bias_T.png b/docs/img/bias_T.png new file mode 100644 index 0000000000000000000000000000000000000000..5b2a5a938a1a21b8040c34d27ac8b059813c3de8 Binary files /dev/null and b/docs/img/bias_T.png differ diff --git a/docs/img/bias_T_block_pulse.png b/docs/img/bias_T_block_pulse.png new file mode 100644 index 0000000000000000000000000000000000000000..4acac2997e341485dacd923475e83342cb2e6816 Binary files /dev/null and b/docs/img/bias_T_block_pulse.png differ diff --git a/docs/img/bias_T_sequence.png b/docs/img/bias_T_sequence.png new file mode 100644 index 0000000000000000000000000000000000000000..52c624dc6fadccba498956777a379fc428765488 Binary files /dev/null and b/docs/img/bias_T_sequence.png differ diff --git a/docs/img/ideal_modulation.png b/docs/img/ideal_modulation.png new file mode 100644 index 0000000000000000000000000000000000000000..d1646b0c4e135087c4149d21c6bb51b1f15be339 Binary files /dev/null and b/docs/img/ideal_modulation.png differ diff --git a/docs/img/long_pulses.png b/docs/img/long_pulses.png new file mode 100644 index 0000000000000000000000000000000000000000..a7e29b74e18bb1eb4a2288e2f9b134c0b55a8193 Binary files /dev/null and b/docs/img/long_pulses.png differ diff --git a/docs/img/long_pulses_with_compensation.png b/docs/img/long_pulses_with_compensation.png new file mode 100644 index 0000000000000000000000000000000000000000..3962820a22476a9708bb1e5b8f95672705efa745 Binary files /dev/null and b/docs/img/long_pulses_with_compensation.png differ diff --git a/docs/img/real_modulation.png b/docs/img/real_modulation.png new file mode 100644 index 0000000000000000000000000000000000000000..c3a82ae723388397cf4d39305a8a26c76acb6d72 Binary files /dev/null and b/docs/img/real_modulation.png differ diff --git a/docs/index.rst b/docs/index.rst index 81efd7c614d3d3c96d6d045d22ace1cbf6317ab8..1989e1dba234531435caa0183b1872dcb9f6f236 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,28 +3,81 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to pulse lib's documentation -==================================== -This is a pulse library designed to provide all the control signals that are needed control spin qubits coherenly. -A lot of attention is given to performance, structure and ease of use. +Pulse_lib +========= -Features now include: - - Support for arbitrary pulse/sine wave based sequences (phase coherent atm). - - Fully multidimensional. Execute any command as a loop in any dimension. - - Short and clean syntax. No sympy. - - Native support for virtual gates. - - IQ toolkit and IQ virtual channels -- Full suppport for single sideband modulation (Along with PM/AM/FM). - - Automatic compenstation for DC offsets. - - High speed uploader for Keysight PXI systems which supports upload during playback. +Pulse_lib is a library to control multi-channel AWG pulse sequences and digitizer acquisitions +with a simple API using physical units. It is designed to control qubit experiments, especially quantum dot +and spin qubit experiments. -Getting started: +Sequences can contain direct voltage pulses, phase coherent microwave (MW) pulses, digital markers, triggers, +and digitizer acquisitions. Parameters of the pulses in a sequence can be swept across a range of values. This turns the sequence in a +multi-dimensional measurement. - - :ref:`struct_lib` - - :ref:`init_lib` - - :ref:`simple_pulse` +Pulse_lib translates the specified pulse sequence to output signals of the AWG. It takes care of: + +* Phase coherence of pulses per qubit +* Capacitive coupling of plunger and barrier gates of quantum dots using a virtual matrix +* Signal delays due to vector signal generator and cables +* MW up conversion by vector signal generator +* Attenuators between AWG and target device +* DC charging of bias-T, which acts as a high pass filter for AWG signals + +Pulses can be conditional on a measurement in the same sequence. However, this feature +is currently only supported by the QuTech QuantumSequencer for Keysight PXI. + +Pulse_lib supports the following hardware: + +* Keysight PXI M3202A AWG and M3201A digitizer +* Tektronix AWG5014 with Spectrum M4i digitizer +* Qblox Pulsar QCM and QRM +* QuTech QuantumSequencer for Keysight PXI + + +.. toctree:: + :maxdepth: 2 + :caption: Getting started + :name: getting_started + + introduction + installation + tutorials/basic_example + +.. toctree:: + :maxdepth: 2 + :caption: Signal physics + + signals/delays + signals/attenuation + signals/bias_T + signals/cross_capacitance + signals/iq_modulation + +.. toctree:: + :maxdepth: 1 + :caption: User Guide + + user/configuration + user/segments + user/timeline + user/voltage_channels + user/mw_channels + user/marker_channels + user/digitizer_channels + user/parameter_sweep + user/plotting_segments + user/acquisition_parameter + user/executing_sequence + +*TODO:* + + +.. Getting started: + +.. - :ref:`struct_lib` +.. - :ref:`init_lib` +.. - :ref:`simple_pulse` -.. :caption: Getting started -.. :titlesonly: .. struct .. tutorials/init_lib @@ -36,23 +89,6 @@ Getting started: .. tutorials/example_PT .. tutorials/example_RB -When using the library in combination with the keysight PXI AWG's, playback of the waveforms is also supported: - - How does a upload work? What are the different steps? - - Your first simple upload. - - Integrating HVI. - - More advanced upload options, running uploads at high speeds. - -An overview of all the functions in the classes can be found at - - sequence - - segment containers - - segment base - - segment IQ - -API documentation for developers - - Requesting data from the sequence object. - - - Indices and tables ================== diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000000000000000000000000000000000000..d1b663fda4d5518cd981f5a737a1d538eb4e7123 --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,62 @@ +.. title:: Installation + +Installation +============ + +Pulse_lib +--------- + +Clone the `sources of Pulse_lib <https://github.com/stephanlphilips/pulse_lib>`_ from GitHub. + +.. code-block:: console + + pip install ./pulse_lib + +or + +.. code-block:: console + + python3 setup.py install + +Pulse_lib uses the packages qcodes and qcodes_contrib_drivers. + + +Keysight PXI +------------ + +To use pulse_lib with Keysight M3202A AWG and M3102A digitizer you have to install: + +* Keysight SD1 software +* Keysight FPGA Test Sync Executive +* Git clone `hvi2-script <https://github.com/QuTech-Delft/hvi2_script>`_ branch SD1_3.1 +* Git clone `core tools <https://github.com/stephanlphilips/core_tools>`_ + +The core tools package contains the HVI2 schedules required to trigger the AWGs and digitzers. +It contains the schedules for video mode and single shot measurements. + +The core tools package also contains a driver for the M3102A digitizer. + + +Tektronix AWG5014 +----------------- + +No additional software is needed to use pulse_lib with AWG5014. + +A schedule to use AWG5014 with Spectrum M4i digitizer and Zurich Instruments UHFLI is included in pulse_lib. + + +Qblox Pulsar QCM and QRM +------------------------ + +Note: Support for Qblox is still in development on a separate branch of pulse_lib. + +To use pulse_lib with Qblox you have to install: + +* package qblox_instruments (available on PyPi) +* `Q1Pulse<https://github.com/sldesnoo-Delft/q1pulse>`_ + + +QuTech QuantumSequencer +----------------------- + +The QuantumSequencer uses QuTech developed FPGA images for Keysight M3202A and M3102A. diff --git a/docs/introduction.rst b/docs/introduction.rst new file mode 100644 index 0000000000000000000000000000000000000000..01f81b4e2f9c0c9a70abb06da6c25f9f548f0856 --- /dev/null +++ b/docs/introduction.rst @@ -0,0 +1,122 @@ +.. title:: Introduction + +Introduction +============ + +Pulse_lib is a library to control multi-channel AWG pulse sequences and digitizer acquisitions +with a simple API using physical units. It is designed to control qubit experiments, especially quantum dot +and spin qubit experiments. + + +Pulses are specified on user-defined channels. A channel can be used for either voltage pulses, +microwave (MW) pulses, marker on-off pulses, or digitizer acquisition. + + +Gates (voltage channels) +------------------------ + +A gate is used to apply voltage pulses on the target device. The pulses are output to one AWG channel, or in +the case of a virtual gate to multiple AWG channels. +A virtual gate is a combination of channels that can be used to compensate capacitive coupling. +A virtual gate can also be a combination of other virtual gates, e.g. to define a detuning voltage. + +Voltage pulses are additive, i.e. pulses which overlap in time are summed. +The following pulses can be added to a sequence on a (virtual) gate: + +* block pulses +* ramps +* sinusoidal pulses +* custom pulses of arbitrary shape + +The pulse_lib configuration has settings to compensate the voltage pulses for: + +* Signal delays due to cables and filters +* Attenuation between AWG and target device +* DC charging of bias-T, which acts as a high pass filter for AWG signals +* Capacitive coupling of plunger and barrier gates of quantum dots using a virtual matrix + + +Qubit (MW) channels +------------------- + +A qubit channel is used to apply phase coherent MW pulses to the target device. +It should be assigned to an IQ output pair of the AWG. Multiple qubit channels can be assigned +to one IQ output pair. (See hardware for limitations.) + +Every qubit channel has a reference frequency (or resonance frequency) used track the +signal phase between pulses. + +The following pulses can be added to a sequence on a qubit channel: + +* MW pulse with optional envelope for amplitude and phase modulation +* phase shift for virual-Z gates or phase correction after another gate +* Frequency chirps + +The pulse_lib configuration has settings to compensate the MW pulses for: + +* Signal delays due to vector signal generator and cables +* MW up conversion by vector signal generator +* IQ mixer phase and amplitude errors + + +Marker channels +--------------- + +A marker channel is a digital I/O or an AWG output channel used for example to trigger +another instrument or to mute/unmute a signal. + +A marker channel can be linked to a MW channel to automatically mute/unmute the output of the MW source. +It can be offset in time to unmute the MW source ahead of the MW pulse. + + +Acquisition channels +-------------------- + +Acquisition channels are used to add acquisitions to a sequence. The input for the acquisition channel +can be single digitizer input channel, or an input pair representing I and Q inputs. +The input can be demodulated and phase shifted. + +The acquisition can specify to return averaged the data or a down-sampled time trace. +A threshold can be set on the averaged value to convert it to a qubit state measurement. + + +Physical units +-------------- + +Pulses in pulse_lib are specified in physical units like they should arrive on the target device: + +* Amplitudes are specified in millivolts +* Time is specified in nanoseconds +* MW pulses are specified for a specific qubit and resonance and drive frequency in Hz +* Channels are identified with a logical name + +Parameter sweeps +---------------- + +Parameters of the pulses in a sequence can be swept across a range of values. This turns the sequence in a +multi-dimensional measurement. + +Conditional pulses +------------------ + +Pulses can be made conditional on one or more measurements in the same sequence. +The conditional pulses can be used to create classical controlled qubit gates. + +This feature is currently only supported by the QuTech QuantumSequencer for Keysight PXI. + +Supported hardware +------------------ + +Pulse_lib supports the following hardware: + +* Keysight PXI M3202A AWG and M3201A digitizer +* Tektronix AWG5014 with Spectrum M4i digitizer, AlazarTech ATS or Zurich Instruments UHFLI +* Qblox Pulsar QCM and QRM +* QuTech QuantumSequencer for Keysight PXI + +See the hardware specific sections for supported features and limitations. + +The communication with the AWGs has been optimized to minimize the overhead between measurements. +The compilation of pulse sequences and the communication with the AWGs will be further optimized +with every new release of the software. + diff --git a/docs/signals/attenuation.rst b/docs/signals/attenuation.rst new file mode 100644 index 0000000000000000000000000000000000000000..b83b31fa148bbc67cf03e5bff3740fb63cf57a63 --- /dev/null +++ b/docs/signals/attenuation.rst @@ -0,0 +1,19 @@ +.. title: Attenuation + +Signal attenuation +================== + +The signal from AWG to device is electrically attenuated to reduce the amount of noise on the device. +The signal-to-noise ratio of the AWG is high when the signal has a high amplitude. On the device the +required signal amplitude is much lower and must be attenuated. + +Pulselib compensates for this attenuation. The value should be specified as the fraction of the signal +transmitted to the device. + +Example: + If the attenuation is 12 dB, then the amplitude at the device will be 0.25 of the amplitude at the AWG. + An attenuation of 0.25 should be specified for the channel. + + .. code-block:: python + + pl.add_channel_attenuation('P1', 0.25) diff --git a/docs/signals/bias_T.rst b/docs/signals/bias_T.rst new file mode 100644 index 0000000000000000000000000000000000000000..758c3556edc05f8b1a4cbc8966f296c1b774c9c3 --- /dev/null +++ b/docs/signals/bias_T.rst @@ -0,0 +1,90 @@ +.. title: Bias-T + +Bias-T +====== + +The plunger and barrier gates of quantum dots have a DC voltage offset to maintain the desired operational regime. +The gates are pulsed for the initialization, manipulation and readout of the qubit state. +The DC voltage source and the AWG-generated pulses are combined by means of a bias-T. + +.. figure:: /img/bias_T.png + :scale: 50% + + Bias-T connecting the high frequency AWG and the low frequency DAC to the device. + +The bias-T is a T-like component which acts as a high-pass filter for the AWG pulses and as a low-pass filter +for the DC voltage. It consists of a resistor and a capacitor with values in the order of 1 MOhm and 100 nF +giving an RC-time in the order of 0.1 s. +The a cut-off frequency :math:`f_c = 1/2\pi R C` is in the order of a few Hz. + +he high-pass filter on the AWG signal results in amplitude decays for long pulses and +accumulation of an offset when the average voltage of a sequence is not zero. +This offset will grow with every repetition of the sequence until the offset is has the negative voltage +of the average of the sequence. + +.. figure:: /img/bias_T_block_pulse.png + :scale: 75% + + Decay of the amplitude of a long block pulse due to the bias-T high pass filtering with RC-time = 0.1 s. + + +.. figure:: /img/bias_T_sequence.png + :scale: 90% + + The deviation after 2 pulses of ~0.5 ms is only 1.6 mV. After 100 repetitions the deviation is > 50 mV. + + +DC-compensation +--------------- + +The average voltage of a sequence should be 0.0 V to avoid a growing voltage offset due to the bias-T +high pass filtering. +Pulse_lib will automatically add a DC-compensation pulse when the average of a sequence is not zero. +This DC-compensation is enabled for all channels where the channel compensation limits are set. + +Note: Contrary to all other settings, the compensation limits are set in AWG voltage, not the device voltage. + +Example: + Enable DC-compensation for channels P1 and P2 with limits of -200 and +500 mV. + + .. code-block:: python + + pl.add_channel_compensation_limit('P1', (-200, 500)) + pl.add_channel_compensation_limit('P2', (-200, 500)) + +.. figure:: /img/DC_compensation_pulses.png + :scale: 75% + + DC compensation with automatically added pulses of -200 mV at the end of the sequence. + + +Bias-T compensation +------------------- + +Sequences with long pulses or long sequences with the average voltage not equal to zero will +be distorted by the bias-T when the duration exceeds a few percent of the RC-time. +Pulse_lib will compensate for the bias-T high-pass filtering when the bias-T time compensation is +configured. +This bias-T correction will increase the sequence compilation time with a small percentage. + +The bias-T compensation can correct pulses with a duration in the order of the RC-time. +Pulses that are longer than a few times the RC-time will eventually hit the limits of the AWG output range, +because the bias-T compensation increases the amplitude of the signal. +A good correction of long pulses is only possible when the configured RC-time is accurate enough. +An error of 2% in the configured RC-time gives an error of 10% in the amplitude at the end of a pulse +with a duration of 5 times the RC-time. + +Note: The time of the bias-T is specified in seconds! + +Example: + Enable bias-T compensation for channels P1 and P2. + + .. code-block:: python + + pulse.add_channel_bias_T_compensation('P1', 0.102) + pulse.add_channel_bias_T_compensation('P2', 0.106) + +.. figure:: /img/long_pulses_with_compensation.png + :scale: 75% + + Bias-T compensated pulses. The dashed lines show the signal after bias-T with the desired rectangular pulses. diff --git a/docs/signals/cross_capacitance.rst b/docs/signals/cross_capacitance.rst new file mode 100644 index 0000000000000000000000000000000000000000..8cbc09d6b2fe1732ad0e1111a4b2a1d8bc747034 --- /dev/null +++ b/docs/signals/cross_capacitance.rst @@ -0,0 +1,91 @@ +.. title: Cross-capacitance + +Cross-capacitance +================= +The chemical potential of the quantum dots used in spin-qubit devices determines the amount of electrons that +will be loaded in the quantum dot. The chemical potential is controlled by a plunger gate close to the quantum dot. +However, due to the small distance between quantum dots the potential of a quantum dot is also affected +by neighbouring plunger and barrier gates. This is the capacitive cross-talk, or cross-capacitance, from a gate to +other quantum dots. This cross-capacitance is classical in nature and can be corrected by pulse_lib using +"virtual gates". + +A virtual gate is a pulse_lib channel that outputs a pulse sequence on multiple AWG channels +such that only a single chemical potential or single tunnel coupling will be affected by the pulses. +Virtual gates are defined by a virtual gate matrix. + + +Virtual Gate Matrix +=================== + +A virtual gate matrix is a matrix that relates the virtual gate voltages to the real voltages. + + :math:`\begin{pmatrix} vP1 \\ vP2 \\ vP3 \end{pmatrix} = M \begin{pmatrix} P1 \\ P2 \\ P3 \end{pmatrix}` + +When there would me no cross effects, this matrix would look like: + + :math:`M = \begin{pmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{pmatrix}` + +Which gives a one to one map of the virtual gate voltages to the real voltages. +In reality, this will not be the case. There will be cross-capacitances. + + :math:`M = \begin{pmatrix} 1 & C_{12} & C_{13} \\ C_{21} & 1 & C_{23} \\ C_{31} & C_{32} & 1 \end{pmatrix}` + +The values on the diagonal are kept equal to 1. The lever arm of :math:`vP1` will then be equal to the lever +arm of :math:`P1`. +A correct virtual matrix will remove the slant from the lines in the charge stability diagram without stretching it. + +See *Loading a quantum-dot based "Qubyte" register*, C. Volk (2019), for a detailed description +of cross-capacitance and virtual gates. + + +Virtual gate matrix in pulse_lib +-------------------------------- + +Pulse_lib inverts cross-capacitance matrix :math:`M` to calculate the voltages on the output channels. + + :math:`\begin{pmatrix} P1 \\ P2 \\ P3 \end{pmatrix} = M^{-1} \begin{pmatrix} vP1 \\ vP2 \\ vP3 \end{pmatrix}` + +The cross-capacitance matrix (real-to-virtual) can be passed to pulse_lib, but also the inverted +matrix (virtual-to-real) can be passed. The cross-capacitance matrix has to be a square matrix, because it +must be invertible. The virtual-to-real matrix doesn't have to be square. + +Example: + .. code-block:: python + + pl.add_virtual_matrix( + name='virtual-gates', + real_gate_names=['B0', 'P1', 'B1', 'P2', 'B2'], + virtual_gate_names=['vB0', 'vP1', 'vB1', 'vP2', 'vB2'], + matrix=[ + [1.00, 0.25, 0.05, 0.00, 0.00], + [0.14, 1.00, 0.12, 0.02, 0.00], + [0.05, 0.16, 1.00, 0.11, 0.01], + [0.02, 0.09, 0.18, 1.00, 0.16], + [0.00, 0.01, 0.013 0.21, 1.00] + ], + real2virtual=True) + + +Combining virtual gates to a combined parameter +----------------------------------------------- + +The use of the virtual matrix is not restricted to the definition of virtual gates to compensate +for the cross-capacitance. It can also be used to define a new channel for voltage pulses that is +a linear combination of virtual gates, e.g. to define a detuning parameter. + +Example: + A detuning parameter e12 and a energy parameter U12 is defined using a virtual-to-real matrix. + + .. code-block:: python + + pl.add_virtual_matrix( + name='detuning12', + real_gate_names=['vP1', 'vP2'], + virtual_gate_names=['e12', 'U12'], + matrix=[ + [+0.5, +1.0], + [-0.5, +1.0], + ], + real2virtual=False) + + diff --git a/docs/signals/delays.rst b/docs/signals/delays.rst new file mode 100644 index 0000000000000000000000000000000000000000..54c32b617a57791c98ddbf31c5c205a6fe7411fa --- /dev/null +++ b/docs/signals/delays.rst @@ -0,0 +1,36 @@ +.. title: Signal delay + +Signal delays +============= + +It takes time for a signal to get from the AWG to the target device and from the device to the digitizer. +Pulses with equal start time but on different channels should arrive at the same time on the target device. +This is not by default true, because signals travel along different paths with different travel times. +Pulse_lib can compensate for these difference in signal delays. + +Signal delays in pulse and acquisition paths are caused by: + +* propagation through cables, which is approximately 3 ns / m. +* propagation through vector signal generator, which takes 20 - 50 ns. +* propagation through RF up-convertor, down-converter. +* processing time in AWG +* processing time in digitizer + +The delay can be specified per channel. It is specified as the delay added to the channel. + +Example: + If the MW signal is delayed by the VSG and arrives 45 ns later than the signals of gates P1 and P2, + then you can add 45 ns to the gates P1 and P2. + + .. code-block:: python + + pl.add_channel_delay('P1', 45) + pl.add_channel_delay('P2', 45) + + Alternatively, you can also subtract 45 ns for the I and Q channel. + + .. code-block:: python + + pl.add_channel_delay('I1', -45) + pl.add_channel_delay('Q1', -45) + diff --git a/docs/signals/iq_modulation.rst b/docs/signals/iq_modulation.rst new file mode 100644 index 0000000000000000000000000000000000000000..5fc5498b9f06631e85acacc4c593ce2fc2b50235 --- /dev/null +++ b/docs/signals/iq_modulation.rst @@ -0,0 +1,152 @@ +.. title: IQ modulation + +IQ Modulation +============= + +Spin qubit resonant frequencies are typically 2 to 20 GHz. This is much higher than the bandwidth of the AWGs. +In experiments microwave (MW) sources are used to manipulate the qubits. The microwave signals must be amplitude +and phase modulated for full qubit control. +A common solution for this modulation of MW signals is in-phase and quadrature (IQ) modulation. +The in-phase and quadrature MW sinusoids are mixed with an IQ modulation pair from the AWG. +See `In-phase and quadrature components <https://en.wikipedia.org/wiki/In-phase_and_quadrature_components>`_. + + .. figure:: /img/IQ_mixing.png + :scale: 80 % + + IQ mixing with carrier frequency :math:`f_c` + +The output of this mixer is: + + :math:`y(t) = I(t) cos(\omega_c t) - Q(t) sin(\omega_c t)` + + +IQ modulation can be used to create a single frequency output signal which is higher of lower in frequency +than the MW source. For this the IQ modulation signals should be sinusoids with a 90 degrees shift. + + :math:`I(t) = A(t) cos(\omega_m t + \phi(t))` + + :math:`Q(t) = A(t) sin(\omega_m t + \phi(t))` + + :math:`y(t) = A(t) [cos(\omega_m t + \phi(t)) cos(\omega_c t) - sin(\omega_m t + \phi(t)) sin(\omega_c t)]` + + :math:`y(t) = A(t) cos((\omega_c + \omega_m) t + \phi(t))` + + +IQ modulation allows frequency multiplexing, because it is a linear operation. The I and Q components can +contain multiple frequencies which will all be shifted with :math:`f_c`. +IQ modulation can also be used for fast chirps (frequency sweeps), because phase and frequency of the +I and Q components can be swiftly changed by the AWG. + + +IQ modulation in pulse_lib +-------------------------- +Users of pulse_lib don't have to care about the calculation of I and Q outputs. +They can specify the desired MW pulses after IQ modulation and pulse_lib calculates the I and Q output signals +for the AWG. + +The user has to specify the I and Q output channels of the AWG as an IQ pair and pass the frequency of the +vector signal generator, the LO frequency. +For coherent qubit control every qubit needs a channel with the resonant frequency of the qubit. + +Example: + .. code-block:: python + + pl.define_channel('I1','AWG1', 3) + pl.define_channel('Q1','AWG1', 4) + + # define IQ output pair + IQ_pair_1 = IQ_channel_constructor(pl) + IQ_pair_1.add_IQ_chan("I1", "I") + IQ_pair_1.add_IQ_chan("Q1", "Q") + # frequency of the MW source + IQ_pair_1.set_LO(2.40e9) + + # add 1 qubit: q1 + IQ_pair_1.add_virtual_IQ_channel("q1", 2.415e6) + + +IQ modulation errors +-------------------- + +Idealy the IQ mixer creates single side-band signal. + +.. figure:: /img/ideal_modulation.png + + Ideal IQ modulation + +In practice the signals and electrical components are not perfect. Small differences between amplifiers, +filters and path length result in small errors in the IQ output. + +The I and Q output of the AWG can have a voltage offset, a (frequency dependent) gain difference and +a (frequency dependent) phase difference. The output signal after modulation will contain the carrier frequency +and the mirror side-band. + +.. figure:: /img/real_modulation.png + + IQ modulation in practice with remainder of the carrier frequency and a mirrored side-band. + +Offset error +~~~~~~~~~~~~ + +A voltage offset in the AWG output results in the output of the carrier frequency. + + :math:`y(t) = [a+cos(\omega_m t)] cos(\omega_c t) - [b + sin(\omega_m t)] sin(\omega_c t)]` + + :math:`y(t) = cos((\omega_c + \omega_m) t) + a \cdot cos(\omega_c t) - b \cdot sin(\omega_c t)` + +.. figure:: /img/IQ_offset_error.png + + Remainder of carrier frequency due to offset error. + + +Gain error +~~~~~~~~~~ + +A difference in gain between I and Q components add the mirrored side-band frequency, +:math:`f_c - f_m`, to the output. + + :math:`y(t) = (1 + a) cos(\omega_m t) cos(\omega_c t) - sin(\omega_m t) sin(\omega_c t)` + + :math:`y(t) = (1+\frac{a}{2}) cos((\omega_c + \omega_m) t) + \frac{a}{2} cos((\omega_c - \omega_m) t)` + + +.. figure:: /img/IQ_gain_error.png + + Mirrored side-band due to gain error. + +Phase error +~~~~~~~~~~~ + +When the phase difference between the I and Q components is not exactly 90 degrees then the mirrored +side-band frequency is output as well. The resulting output is similar to the output with a gain error. + + :math:`y(t) = cos(\omega_m t + \frac{a}{2}) cos(\omega_c t) - sin(\omega_m t - \frac{a}{2}) sin(\omega_c t)` + + :math:`y(t) = cos(\frac{a}{2}) cos((\omega_c + \omega_m) t) - sin(\frac{a}{2}) sin((\omega_c - \omega_m) t)` + + + +IQ corrections in pulse_lib +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A vector signal generator will have options to correct the offset, phase and gain error of the IQ input, but +only with a frequency independent correction. +Pulse_lib can also correct for these errors, where gain and phase corrections are frequency dependent. + +Example: + Add offset correction to I and Q components. + + .. code-block:: python + + pl.add_channel_offset('I1', 10) + pl.add_channel_offset('Q1', -5) + + Add gain and phase offset to qubit channels. + + .. code-block:: python + + IQ_pair_1.add_virtual_IQ_channel("q2", 2.421e9, + correction_gain=(1.0, 0.9)) + IQ_pair_1.add_virtual_IQ_channel("q3", 2.473e9, + correction_gain=(0.98, 1.0), + correction_phase=0.3) diff --git a/docs/tutorials/basic_example.rst b/docs/tutorials/basic_example.rst new file mode 100644 index 0000000000000000000000000000000000000000..4c09bada5d37e97663d67a501f10fef5a119a030 --- /dev/null +++ b/docs/tutorials/basic_example.rst @@ -0,0 +1,106 @@ +.. title: Basic example + +Basic example +============= + + + +Configure pulse_lib +------------------- + +Create a pulse_lib object with gates for voltage pulses and 2 qubit channels for MW pulses. + +.. code-block:: python + + pl = pulse_lib(backend='Keysight') + + # add AWGs and digitizers + pl.add_awg(awg1) + p1.add_digitizer(digitizer) + + # gates (voltage channels) + pl.define_channel('P1', awg1, 1) + pl.define_channel('P2', awg1, 2) + + # IQ output pair + pl.define_channel('I1', awg1, 3) + pl.define_channel('Q1', awg1, 4) + IQ_pair_1 = IQ_channel_constructor(pl) + IQ_pair_1.add_IQ_chan("I1", "I") + IQ_pair_1.add_IQ_chan("Q1", "Q") + + # set frequency of the MW source for down-conversion + IQ_pair_1.set_LO(mw_source.freq) + + # add qubit channels + IQ_pair_1.add_virtual_IQ_channel("q1", q1_freq) + IQ_pair_1.add_virtual_IQ_channel("q2", q2_freq) + + # acquisition channel + pl.define_digitizer_channel('S1', digitizer, 1) + + pl.finish_init() + + +Create a sequence +----------------- + +A sequence is made of one or more segments. Here we use a single segment. + +.. code-block:: python + + seg = pl.create_segment() + +Initialize the qubit with a voltage pulse on the gates. +After the pulse the voltage returns to (0.0, 0.0) + +Voltage pulses on multiple channels can be added with ``add_block`` and ``add_ramp`` on the segment. +The start and end time of a pulse are relative to a reference time in the segment. +The reference time is moved to the end of the last pulse with reset_time. + +.. code-block:: python + + gates = ['P1','P2'] + # initialize qubit with 200 ns pulse of P1,P2 to v_init + v_init = (46.0, 25.5) + seg.add_block(0, 200, gates, v_init, reset_time=True) + seg.wait(40, reset_time=True) + +Generate a Ramsey pulse sequence with two MW pulses for qubit 1 with a wait time in between. +Channels can be accessed as an attribute of the segment (``seg.q1``), and as an index in the segment (``seg['q1']``). + +.. code-block:: python + + seg.q1.add_MW_pulse(0, q1_X90_t, q1_X90_amplitude) + seg.q1.wait(t_wait, reset_time=True) + seg.q1.add_MW_pulse(0, q1_X90_t, q1_X90_amplitude) + seg.wait(20, reset_time=True) + +Move the qubit to the readout point and start measurement 140 ns after start of the block pulse. + +.. code-block:: python + + v_readout = (46.0, 25.5) + seg.add_ramp(0, 200, gates, (0.0, 0.0), v_readout, reset_time=True) + seg.S1.acquire(140, t_measure=1500) + seg.add_block(0, 1700, gates, v_readout, reset_time=True) + +Execute the sequence +-------------------- + +The segments have to be compiled to a sequence. The sequence has to be uploaded to the AWGs before execution. +The acquired data can be retrieved with the acquisition parameter. This is a qcodes MultiParameter. + +.. code-block:: python + + seq = pl.make_sequence([seg]) + acq_param = seq.get_acquisition_param() + + # upload sequence data to AWG + seq.upload() + # play the sequence + seq.play() + + # retrieve measurement data + data = acq_param() + diff --git a/docs/user/configuration.rst b/docs/user/configuration.rst new file mode 100644 index 0000000000000000000000000000000000000000..b39293066a2b03db6a3cd0ec74ade282f216a385 --- /dev/null +++ b/docs/user/configuration.rst @@ -0,0 +1,142 @@ +.. title: pulse_lib configuration + +Configuration +============= + +The configuration of pulse_lib is stored in a pulselib object. +This object is needed to create segments and sequences. + +Create pulselib object with specific backend +--------------------------------------------- + +A pulselib object must created for a specific backend for the hardware. + +.. code-block:: python + + from pulse_lib.base_pulse import pulselib + + pl = pulselib('Keysight') + + # Add channels ... + # Configure channels .... + +At the end, after adding and configuring all channels, ``pl.finish_init()`` +must be called to complete the initialization. + + +Add AWGs and digitizers +----------------------- + +.. code-block:: python + + pl.add_awg(awg1) + pl.add_awg(awg2) + pl.add_digitizer(digitizer) + +Note: Qblox QRM should be added as a digitizer. See @@@ + +Gates (voltage channels) +------------------------ + +Gates (voltage channels) should be defined with a name for the channel and +a name and channel number of the AWG. + +The channel delay specifies the amount of delay that should be added to the signal. +The channel attenuation is expressed in the fraction of the amplitude after attenuation. +The DC compensation limits are specified in AWG voltage before attenuation. + +.. code-block:: python + + pl.add_channel("P1', awg1.name, 1) + pl.add_channel_delay('P1', 17) + + # 0.01 = -20 dB attenuation + pl.add_channel_attenuation('P1', 0.01) + + # Add limits on voltages for DC channel compensation. + # When no limit is specified then no DC compensation is performed. + # Limits are specified in AWG voltage before attenuation. + pl.add_channel_compensation_limit('P1', (-200, 500)) + + # Add compensation for bias-T with RC-time of 0.109 s + pl.add_channel_bias_T_compensation('P1', 0.109) + +Virtual matrix +-------------- + +``keep_square`` and @@@ are optional parameters that can only be set when ``real2virtual=True``. ??? + +.. code-block:: python + + pl.add_virtual_matrix( + name='virtual-gates', + real_gate_names=['B0', 'P1', 'B1', 'P2', 'B2'], + virtual_gate_names=['vB0', 'vP1', 'vB1', 'vP2', 'vB2'], + matrix=[ + [1.00, 0.25, 0.05, 0.00, 0.00], + [0.14, 1.00, 0.12, 0.02, 0.00], + [0.05, 0.16, 1.00, 0.11, 0.01], + [0.02, 0.09, 0.18, 1.00, 0.16], + [0.00, 0.01, 0.013 0.21, 1.00] + ], + real2virtual=True, + keep_square=Tue, + @@@) + + pl.add_virtual_matrix( + name='detuning12', + real_gate_names=['vP1', 'vP2'], + virtual_gate_names=['e12', 'U12'], + matrix=[ + [+0.5, +1.0], + [-0.5, +1.0], + ], + real2virtual=False) + +Qubit channels (MW channels) +---------------------------- + +.. code-block:: python + + from pulse_lib.virtual_channel_constructors import IQ_channel_constructor + + pl.add_channel("I1', awg2.name, 3) + pl.add_channel("Q1', awg2.name, 4) + pl.add_channel_delay('I1', -52) + pl.add_channel_delay('Q1', -52) + + # define IQ output pair + IQ_pair_1 = IQ_channel_constructor(pulse) + IQ_pair_1.add_IQ_chan("I1", "I") + IQ_pair_1.add_IQ_chan("Q1", "Q") + + # frequency of the MW source + IQ_pair_1.set_LO(lo_freq) + + # add channel for qubit q1 + IQ_pair_1.add_virtual_IQ_channel("q1", 3.213e9) + +IQ phase-gain compensation +Offset +add marker + + +Marker channels +--------------- + +delay + + +Digitizer channels +------------------ + +Note: Digitizers triggers + +.. code-block:: python + + pl.define_digitizer_channel('SD1', digitizer.name, 1) + +IQ input pair + +RF-source +