Skip to content

Amplitude and Phase of Pulses

The phase and amplitude of microwave pulses that are seen by the quantum circuits need to be precise and deterministic. This chapter explains the various means which LabOne Q offers the users to control the phase and amplitude of microwave pulses that are sent out by the instruments.

Pulse Playback

Pulses can be played with arbitrary phase and amplitude using the play() command in LabOne Q.

exp.play(signal=my_signal, pulse=my_pulse, amplitude=0.8, phase=pi/2)

The line above schedules the playback of the pulse my_pulse on the signal line my_signal with the parameters amplitude=0.8 and phase=pi/2.

Real-valued Amplitude in the play() Command

When defining a pulse instance using the pulse_library, one can specify an overall amplitude, or so-called pulse amplitude, in the range from -1 to 1 which maps to the full scale range (FSR). Here is an example for a pulse instance with constant amplitude at 0.5 FSR.

my_pulse = pulse_library.const(amplitude=0.5)

The amplitude in the play() command is a relative amplitude value with respect to the pulse amplitude. LabOne Q will use the product of the amplitude in the play() command and the pulse amplitude to create the baseband waveform.

my_pulse = pulse_library.const(amplitude=0.5)
exp.play(signal=my_signal, pulse=my_pulse, amplitude=0.8)

The code snippet above schedules the playback of the pulse my_pulse on the signal line my_signal with an output amplitude that is 0.5 × 0.8 = 0.4 of the FSR. The relative amplitude only takes effect within the current play() command.

Phase in the play() Command

A phase can also be specified in the play() command. A baseband waveform is rotated by an angle of \(\phi\). Mathematically, the rotation is performed by the multiplication of the baseband waveform with the factor

\[ \exp\left(-j\phi\right), \]

where \(\phi\) is the phase in radian. The negative sign in the exponent is in accordance with the mixer sign convention employed in LabOne Q.

Complex-valued Amplitude in the play() Command

The amplitude in the play() command can be a complex number with an absolute value smaller than 1. Specifying a complex amplitude will modify both the amplitude and phase of the baseband waveform. Here is an example to demonstrate the use of complex amplitudes.

phase = np.pi / 6.0
phasor = np.exp(-1.0j * phase)  # Note the sign!

exp.play(..., amplitude=phasor) # play a pulse with a complex amplitude
exp.play(..., phase=phase) #  play the same pulse with a specified phase

The two play() commands schedule pulse playbacks with the same modification, which shifts the phase of the baseband waveform by \(\pi/6\).

Additional Parameters in the play() Command

In addition to the parameters amplitude and phase, the play() command also accepts two other parameters to allow advanced phase control of the oscillators: increment_oscillator_phase and set_oscillator_phase. The implementation of the advanced phase control parameters depends on the modulation_type of the Oscillator object.

Note

The Oscillator object defines the carrier for the baseband signal that oscillates at the intermediate frequency \(\omega_\mathrm{IF}\). It takes two parameters: frequency and modulation_type. While the parameter frequency determines \(\omega_\mathrm{IF}\), the parameter modulation_type specifies how the carrier is generated on the instrument. A hardware modulated oscillator (HW oscillator) uses a continuously running digital oscillator on the instrument to generate the carrier at \(\omega_\mathrm{IF}\). This mode is often used in combination with waveforms that only contain the pulse envelope. A software modulated oscillator (SW oscillator) instructs LabOne Q to write both the carrier and the pulse envelope point by point in the waveforms. The HW oscillator is activated by setting modulation_type=ModulationType.HARDWARE while the SW oscillator is activated by setting modulation_type=ModulationType.SOFTWARE.

Increment Oscillator Phase

The parameter increment_oscillator_phase applies an increment to the oscillator phase at the beginning of the associated pulse playback. The phase of the oscillator is advanced by the specified value in radian on the relevant signal line.

For SW oscillators, all phase increments are programmed into the sample points of the waveforms that are uploaded to the instruments. When using HW oscillators, LabOne Q attempts to use baseband waveforms and employs phase increments acting on the digital oscillators as much as possible. In the case that phase increments act on the digital oscillators, the same baseband waveform can be reused for playbacks with different phase increments.

Real-time conditional phase increments using the match-case syntax are possible on a signal line with HW oscillators, because it uses a digital oscillator on the instrument. When using SW oscillators however, conditional real-time phase increments are not allowed. Here is an example to showcase the use of conditional phase increment by \(\pi\).

with exp.match(...):
    with exp.case(0):
        exp.play(signal="the_signal", pulse=None, increment_oscillator_phase=np.pi)
    with exp.case(1):
        pass

Set Oscillator Phase

The parameter set_oscillator_phase in the play() command sets the absolute phase of the oscillator at the beginning of the pulse playback. Please note the difference to the parameter phase in the play() command, which only changes the phase of a pulse in the associated play() command. For SW oscillators, the phase change is programmed in the associated and all subsequent baseband waveforms. The parameter set_oscillator_phase is not allowed and not effective on signal lines with HW oscillators.

Phase Resets in Averaging Loops

Having a stable and reproducible oscillator phase from shot to shot may be essential for quantum experiments. Resetting the oscillator phase at the beginning of a shot is one way to ensure the reproducibility of the phase from one shot to the next shot.

LabOne Q allows the use of the parameter reset_oscillator_phase for both averaging loops acquire_loop_rt() and parameter sweeps sweep(). When setting reset_oscillator_phase=True for an averaging loop, LabOne Q ensures that the phase of an oscillator always starts at the same value for every shot of the averaging loop.

In the case of SW oscillators, resetting oscillator phase at the beginning of every shot is mandatory. This behavior cannot be changed with reset_oscillator_phase. Here is an example.

# The oscillator for the signal line "the_signal" is SW modulated
exp.signals["the_signal"].oscillator.modulation_type = ModulationType.SOFTWARE

with exp.acquire_loop_rt(count):
    # The phase is reset for every shot of the averaging loop.
    # Every shot will appear identical on an oscilloscope.
    exp.play("the_signal", the_pulse)

For HW oscillators, a continuously running phase over the entire averaging loop is possible because of the use of a digital oscillator. It can be enabled by setting reset_oscillator_phase=False. On the contrary, setting reset_oscillator_phase=True ensures that pulses are played with identical phases from one shot to the next shot:

# The oscillator for the signal line "the_signal" is HW modulated
exp.signals["the_signal"].oscillator.modulation_type = ModulationType.HARDWARE

with exp.acquire_loop_rt(count, reset_oscillator_phase=True):
    # The phase is reset for every shot of the averaging loop.
    # Every shot will appear identical on an oscilloscope.
    exp.play("the_signal", the_pulse)

The phase of HW oscillators is reset by issuing the corresponding commands to the digital oscillators and takes some finite time until completion. This completion time is deterministic and instrument-specific. LabOne Q takes this into account when compiling experiments. Because the completion time does not explicitly appear in the definition of the Experiment object, the actual shot length can be longer than the designed shot length. These delays to configure a digital oscillator are added at the end of the designed pulse sequence and do not modify the relative timing of any pulses within the sequence. To illustrate the prolonged shot length, consider the following example.

# The oscillator for the signal line "the_signal" is HW modulated
exp.signals["the_signal"].oscillator.modulation_type = ModulationType.HARDWARE

with exp.acquire_loop_rt(count, reset_oscillator_phase=True):
    # Oscillator phase reset happens here and takes time until completion, before entering the `body` section
    with exp.section(uid="body"):
        exp.delay("the_signal", time=1e-6)

When running the example on a HDAWG, the length of each shot is 1 μs + 80 ns, with the 80 ns delay added at the end of the pulse sequence as the time necessary to reset the oscillator phase for each shot.

Note

LabOne Q guarantees the total phase reproducibility from shot to shot. In addition to resetting the oscillator phase, each shot then has to be commensurate with the timing grids of all instruments in use. This requirement can extend the actual shot length over the designed shot length, but does not affect the relative timing of any pulses within the sequence. The extension is experiment- and setup-specific, and can be up to 200 ns.

Phase Resets in Parameter Sweeps

By default, the phase of both SW or HW oscillators is continuous over an entire parameter sweep. The phase can be reset at the beginning of each sweep step by passing reset_oscillator_phase=True to the sweep() command.

# The oscillator for the signal line "the_signal" is SW modulated
exp.signals["the_signal"].oscillator.modulation_type = ModulationType.SOFTWARE

with exp.acquire_loop_rt(count):
    with exp.sweep(...,reset_oscillator_phase=True):
        # Oscillator phase is reset for every sweep step. Using 
        # `reset_oscillator_phase=False` would change the behavior to let 
        # the oscillator continuously accumlate phase across sweep steps.
        with exp.section(uid="body"):
            exp.delay("the_signal", time=1e-6)

Explicit Phase Resets in DSL

In addition to the reset_oscillator_phase parameter in the sweep() and acquire_loop_rt() commands, LabOne Q also allows explicit phase resets in the DSL. The reset_oscillator_phase command can be used to reset the phase of an oscillator at any point in the pulse sequence. Also here, for hardware modulated signals, the timing is adapted to allow enough time for the phase reset and may deviate from the definition in the experiment. The argument can be a single signal or None. If the argument is None (the default), all signals in the section are reset where possible.

with exp.acquire_loop_rt(count):
    with exp.section():
        exp.play("the_signal", the_pulse)
        exp.reset_oscillator_phase("the_signal")
        exp.play("the_signal", another_pulse)
        exp.play("another_signal", another_pulse)

Hardware modulated RF signals should not be reset using the reset_oscillator_phase command. Please note that in the example above, the play command for another_signal is not affected by the phase reset of the_signal and will be played at the same time as the very first play() command for the_signal. Also, depending on the instrument and modulation type, the command introduces a delay for the affected signal(s) only. For better control over the timing, wrapping the reset_oscillator_phase command in a section and explicitly specifying the signals to reset is recommended.

When using None as the argument, the phase reset will occur on the system grid after each of the previously scheduled pulses have played. Since it affects all signals, it acts like a barrier - all pulses specified after the phase reset will only be scheduled after all phase resets have completed, even if they were never specified before the phase reset command.