Skip to content

Commit

Permalink
Add StandardReadoutPulse, change ConstantReadoutPulse to `SquareR…
Browse files Browse the repository at this point in the history
…eadoutPulse`
  • Loading branch information
nulinspiratie committed Mar 2, 2024
1 parent 10518d5 commit 9667a4e
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 37 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Added InOutSingleChannel
- Add optional `config_settings` property to quam components indicating that they should be called before/after other components when generating QUA configuration
- Added `InOutIQChannel.measure_accumulated/sliced`
- Added `StandardReadoutPulse`. All readout pulses can now be created simply by inheriting from the `StandardReadoutPulse` and the non-readout variant.

### Changed
- Changed `InOutIQChannel.input_offset_I/Q` to `InOutIQChannel.opx_input_offset_I/Q`
Expand Down
75 changes: 46 additions & 29 deletions quam/components/pulses.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from abc import ABC, abstractmethod
import numbers
import warnings
from typing import Any, ClassVar, Dict, List, Union, Tuple
import numpy as np

Expand All @@ -10,11 +11,13 @@
__all__ = [
"Pulse",
"ReadoutPulse",
"ConstantReadoutPulse",
"StandardReadoutPulse",
"DragPulse",
"SquarePulse",
"SquareReadoutPulse",
"GaussianPulse",
"FlatTopGaussianPulse",
"ConstantReadoutPulse",
]


Expand Down Expand Up @@ -52,6 +55,7 @@ class Pulse(QuamComponent):
The digital marker label is defined as `"{channel_name}.{pulse_name}.dm"`.
"""

operation: ClassVar[str] = "control"
length: int
id: str = None
Expand Down Expand Up @@ -340,28 +344,7 @@ def apply_to_config(self, config: dict) -> None:


@quam_dataclass
class ConstantReadoutPulse(ReadoutPulse):
"""QuAM component for a constant readout pulse.
Args:
length (int): The length of the pulse in samples.
digital_marker (str, list, optional): The digital marker to use for the pulse.
Default is "ON".
amplitude (float): The constant amplitude of the pulse.
axis_angle (float, optional): IQ axis angle of the output pulse in radians.
If None (default), the pulse is meant for a single channel.
If not None, the pulse is meant for an IQ channel (0 is X, pi/2 is Y).
integration_weights (list[float], list[tuple[float, int]], optional): The
integration weights, can be either
- a list of floats (one per sample), the length must match the pulse length
- a list of tuples of (weight, length) pairs, the sum of the lengths must
match the pulse length
integration_weights_angle (float, optional): The rotation angle for the
integration weights in radians.
"""

amplitude: float
axis_angle: float = 0
class StandardReadoutPulse(ReadoutPulse, ABC):
integration_weights: Union[List[float], List[Tuple[float, int]]] = None
integration_weights_angle: float = 0

Expand All @@ -384,12 +367,6 @@ def integration_weights_function(self) -> List[Tuple[Union[complex, float], int]
"minus_imag": [(-phase.imag * w, l) for w, l in integration_weights],
}

def waveform_function(self):
if self.axis_angle is None:
return self.amplitude
else:
return self.amplitude * np.exp(1.0j * self.axis_angle)


@quam_dataclass
class DragPulse(Pulse):
Expand Down Expand Up @@ -470,6 +447,46 @@ def waveform_function(self):
return waveform


@quam_dataclass
class SquareReadoutPulse(StandardReadoutPulse, SquarePulse):
"""QuAM component for a constant readout pulse.
Args:
length (int): The length of the pulse in samples.
digital_marker (str, list, optional): The digital marker to use for the pulse.
Default is "ON".
amplitude (float): The constant amplitude of the pulse.
axis_angle (float, optional): IQ axis angle of the output pulse in radians.
If None (default), the pulse is meant for a single channel.
If not None, the pulse is meant for an IQ channel (0 is X, pi/2 is Y).
integration_weights (list[float], list[tuple[float, int]], optional): The
integration weights, can be either
- a list of floats (one per sample), the length must match the pulse length
- a list of tuples of (weight, length) pairs, the sum of the lengths must
match the pulse length
integration_weights_angle (float, optional): The rotation angle for the
integration weights in radians.
"""

amplitude: float
axis_angle: float = 0

def waveform_function(self):
if self.axis_angle is None:
return self.amplitude
else:
return self.amplitude * np.exp(1.0j * self.axis_angle)


class ConstantReadoutPulse(SquareReadoutPulse):
def __post_init__(self) -> None:
warnings.warn(
"ConstantReadoutPulse is deprecated. Use SquareReadoutPulse instead.",
DeprecationWarning,
)
return super().__post_init__()


@quam_dataclass
class GaussianPulse(Pulse):
"""Gaussian pulse QuAM component.
Expand Down
6 changes: 3 additions & 3 deletions tests/components/channels/test_in_out_IQ_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def test_readout_resonator_with_readout():
mixer=Mixer(), local_oscillator=LocalOscillator(frequency=5e9)
),
)
readout_resonator.operations["readout"] = pulses.ConstantReadoutPulse(
readout_resonator.operations["readout"] = pulses.SquareReadoutPulse(
amplitude=0.1, length=1000
)

Expand All @@ -138,7 +138,7 @@ def test_readout_resonator_with_readout():
"id": 1,
"operations": {
"readout": {
"__class__": "quam.components.pulses.ConstantReadoutPulse",
"__class__": "quam.components.pulses.SquareReadoutPulse",
"amplitude": 0.1,
"length": 1000,
}
Expand Down Expand Up @@ -246,7 +246,7 @@ def test_channel_measure(mocker):
mixer=Mixer(), local_oscillator=LocalOscillator(frequency=5e9)
),
)
readout_resonator.operations["readout"] = pulses.ConstantReadoutPulse(
readout_resonator.operations["readout"] = pulses.SquareReadoutPulse(
amplitude=0.1, length=1000
)

Expand Down
10 changes: 5 additions & 5 deletions tests/components/pulses/test_pulse_weights.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def compare_integration_weights(expected_weights, weights):


def test_constant_readout_pulse_integration_weights_default():
pulse = pulses.ConstantReadoutPulse(length=100, amplitude=1)
pulse = pulses.SquareReadoutPulse(length=100, amplitude=1)

weights = pulse.integration_weights_function()
expected_weights = {
Expand All @@ -25,7 +25,7 @@ def test_constant_readout_pulse_integration_weights_default():


def test_constant_readout_pulse_integration_weights_phase_shift():
pulse = pulses.ConstantReadoutPulse(
pulse = pulses.SquareReadoutPulse(
length=100, amplitude=1, integration_weights_angle=np.pi / 2
)

Expand All @@ -40,7 +40,7 @@ def test_constant_readout_pulse_integration_weights_phase_shift():


def test_constant_readout_pulse_integration_weights_custom_uncompressed():
pulse = pulses.ConstantReadoutPulse(
pulse = pulses.SquareReadoutPulse(
length=100,
amplitude=1,
integration_weights=[0.4] * 10 + [0.6] * 15, # units of clock cycle
Expand All @@ -57,7 +57,7 @@ def test_constant_readout_pulse_integration_weights_custom_uncompressed():


def test_constant_readout_pulse_integration_weights_custom_compressed():
pulse = pulses.ConstantReadoutPulse(
pulse = pulses.SquareReadoutPulse(
length=100, amplitude=1, integration_weights=[(0.4, 40), (0.6, 60)]
)

Expand All @@ -72,7 +72,7 @@ def test_constant_readout_pulse_integration_weights_custom_compressed():


def test_constant_readout_pulse_integration_weights_custom_compressed_phase():
pulse = pulses.ConstantReadoutPulse(
pulse = pulses.SquareReadoutPulse(
length=100,
amplitude=1,
integration_weights=[(0.4, 40), (0.6, 60)],
Expand Down

0 comments on commit 9667a4e

Please sign in to comment.