Skip to content

Commit

Permalink
Merge pull request #6 from qua-platform/feat/stick-channel-addon
Browse files Browse the repository at this point in the history
feat/Add sticky channel option
  • Loading branch information
nulinspiratie authored Aug 23, 2024
2 parents 6b0f3fb + e632165 commit 6ac1c33
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 2 deletions.
10 changes: 10 additions & 0 deletions docs/components/channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,14 @@ A digital pulse can also be played without a corresponding analog pulse.
This can be done by directly using the base [pulses.Pulse][quam.components.pulses.Pulse] class:
```python
channel.operations["digital"] = pulses.Pulse(length=100, digital_marker=[(1, 20, 0, 10)])
```

## Sticky channels
A channel can be set to be sticky, meaning that the voltage after a pulse will remain at the last value of the pulse.
Details can be found in the [Sticky channel QUA documentation](https://docs.quantum-machines.co/latest/docs/Guides/features/#sticky-element).
Any channel can be made sticky by adding the [channels.StickyChannelAddon][quam.components.channels.StickyChannelAddon] to it:
```python
from quam.components.channels import StickyChannelAddon

channel.sticky = StickyChannelAddon(duration=...)
```
53 changes: 52 additions & 1 deletion quam/components/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@


__all__ = [
"DigitalOutputChannel",
"Channel",
"DigitalOutputChannel",
"StickyChannelAddon",
"SingleChannel",
"InSingleChannel",
"IQChannel",
Expand Down Expand Up @@ -152,6 +153,52 @@ def apply_to_config(self, config: dict) -> None:
digital_output_port.apply_to_config(config)


@quam_dataclass
class StickyChannelAddon(QuamComponent):
"""Addon to make channels sticky.
Args:
duration (int): The ramp to zero duration, in ns.
enabled (bool, optional): If False, the sticky parameters are not applied.
Default is True.
analog (bool, optional): If False, the sticky parameters are not applied to
analog outputs. Default is True.
digital (bool, optional): If False, the sticky parameters are not applied to
digital outputs. Default is True.
"""

duration: int
enabled: bool = True
analog: bool = True
digital: bool = True

@property
def channel(self) -> Optional["Channel"]:
"""If the parent is a channel, returns the parent, otherwise returns None."""
if isinstance(self.parent, Channel):
return self.parent
else:
return

@property
def config_settings(self):
if self.channel is not None:
return {"after": [self.channel]}

def apply_to_config(self, config: dict) -> None:
if self.channel is None:
return

if not self.enabled:
return

config["elements"][self.channel.name]["sticky"] = {
"analog": self.analog,
"digital": self.digital,
"duration": self.duration,
}


@quam_dataclass
class Channel(QuamComponent):
"""Base QuAM component for a channel, can be output, input or both.
Expand All @@ -162,6 +209,9 @@ class Channel(QuamComponent):
id (str, int): The id of the channel, used to generate the name.
Can be a string, or an integer in which case it will add
`Channel._default_label`.
sticky (Sticky): Optional sticky parameters for the channel, i.e. defining
whether successive pulses are applied w.r.t the previous pulse or w.r.t 0 V.
If not specified, this channel is not sticky.
"""

operations: Dict[str, Pulse] = field(default_factory=dict)
Expand All @@ -170,6 +220,7 @@ class Channel(QuamComponent):
_default_label: ClassVar[str] = "ch" # Used to determine name from id

digital_outputs: Dict[str, DigitalOutputChannel] = field(default_factory=dict)
sticky: Optional[StickyChannelAddon] = None

@property
def name(self) -> str:
Expand Down
3 changes: 2 additions & 1 deletion tests/components/channels/test_in_IQ_out_single_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def test_in_single_channel_attr_annotations():
"opx_input_Q",
}
assert set(attr_annotations["optional"]) == {
"sticky",
"operations",
"filter_fir_taps",
"filter_iir_taps",
Expand Down Expand Up @@ -82,7 +83,7 @@ def test_generate_config_ports(qua_config):
},
"analog_outputs": {1: {"delay": 0, "shareable": False}},
}
}
}

assert qua_config["elements"] == {
"in_out_channel": {
Expand Down
1 change: 1 addition & 0 deletions tests/components/channels/test_in_single_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ def test_in_single_channel_attr_annotations():
assert set(attr_annotations["required"]) == {"opx_input"}
assert set(attr_annotations["optional"]) == {
"operations",
"sticky",
"id",
"digital_outputs",
"opx_input_offset",
Expand Down
1 change: 1 addition & 0 deletions tests/components/channels/test_in_single_out_IQ_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def test_in_single_channel_attr_annotations():
}
assert set(attr_annotations["optional"]) == {
"operations",
"sticky",
"intermediate_frequency",
"LO_frequency",
"RF_frequency",
Expand Down
52 changes: 52 additions & 0 deletions tests/components/channels/test_sticky_channel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import pytest
from quam.components.channels import IQChannel, StickyChannelAddon
from quam.core.quam_classes import QuamRoot, quam_dataclass


def test_sticky_channel_no_duration_error():
with pytest.raises(TypeError):
StickyChannelAddon()

StickyChannelAddon(duration=20)


@quam_dataclass
class SingleChannelQuAM(QuamRoot):
channel: IQChannel


def test_sticky_channel():
channel = IQChannel(
id="channel",
opx_output_I=("con1", 1),
opx_output_Q=("con1", 2),
frequency_converter_up=None,
sticky=StickyChannelAddon(duration=20),
)
machine = SingleChannelQuAM(channel=channel)

cfg = machine.generate_config()

channel_cfg = cfg["elements"]["channel"]
assert "sticky" in channel_cfg
assert channel_cfg["sticky"] == {
"duration": 20,
"analog": True,
"digital": True,
}


def test_sticky_channel_disabled():
channel = IQChannel(
id="channel",
opx_output_I=("con1", 1),
opx_output_Q=("con1", 2),
frequency_converter_up=None,
sticky=StickyChannelAddon(duration=20, enabled=False),
)
machine = SingleChannelQuAM(channel=channel)

cfg = machine.generate_config()

channel_cfg = cfg["elements"]["channel"]
assert "sticky" not in channel_cfg

0 comments on commit 6ac1c33

Please sign in to comment.