Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QDAC2: slow-trigger for 2D sweep #258

Merged
merged 1 commit into from
Oct 5, 2023
Merged
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
116 changes: 97 additions & 19 deletions docs/examples/QDevil/QDAC2/Scan.ipynb

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/examples/QDevil/QDAC2/Sine.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "qcodespip311",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
Expand All @@ -333,7 +333,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.0 | packaged by conda-forge | (main, Jan 16 2023, 14:12:30) [MSC v.1916 64 bit (AMD64)]"
"version": "3.10.12"
},
"nbsphinx": {
"execute": "never"
Expand Down
47 changes: 41 additions & 6 deletions qcodes_contrib_drivers/drivers/QDevil/QDAC2.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from packaging.version import Version, parse
import abc

# Version 1.6.0
# Version 1.8.0
#
# Guiding principles for this driver for QDevil QDAC-II
# -----------------------------------------------------
Expand Down Expand Up @@ -45,6 +45,10 @@
# - Detect and handle mixing of internal and external triggers (_trigger).
#


pseudo_trigger_voltage = 5


error_ambiguous_wave = 'Only one of frequency_Hz or period_s can be ' \
'specified for a wave form'

Expand Down Expand Up @@ -1871,10 +1875,12 @@ def _make_ready_to_start(self): # Bug circumvention
class Arrangement_Context:
def __init__(self, qdac: 'QDac2', contacts: Dict[str, int],
output_triggers: Optional[Dict[str, int]],
internal_triggers: Optional[Sequence[str]]):
internal_triggers: Optional[Sequence[str]],
outer_trigger_channel: Optional[int]):
self._qdac = qdac
self._fix_contact_order(contacts)
self._allocate_triggers(internal_triggers, output_triggers)
self._outer_trigger_channel = outer_trigger_channel
self._correction = np.identity(self.shape)

def __enter__(self):
Expand Down Expand Up @@ -2099,6 +2105,7 @@ def virtual_sweep2d(self, inner_contact: str, inner_voltages: Sequence[float],
start_sweep_trigger: Optional[str] = None,
inner_step_time_s: float = 1e-5,
inner_step_trigger: Optional[str] = None,
outer_step_trigger: Optional[str] = None,
repetitions: int = 1) -> Virtual_Sweep_Context:
"""Sweep two contacts to create a 2D sweep

Expand All @@ -2110,15 +2117,41 @@ def virtual_sweep2d(self, inner_contact: str, inner_voltages: Sequence[float],
start_sweep_trigger (None, optional): Trigger that starts sweep
inner_step_time_s (float, optional): Delay between voltage changes
inner_step_trigger (None, optional): Trigger that marks each step
outer_step_trigger (None, optional): Name of trigger that marks outer step
repetitions (int, Optional): Number of back-and-forth sweeps, or -1 for infinite

Returns:
Virtual_Sweep_Context: context manager
"""
if not start_sweep_trigger:
# Use a random, unique name
start_sweep_trigger = uuid.uuid4().hex
sweep = self._calculate_2d_values(inner_contact, inner_voltages,
outer_contact, outer_voltages)
return Virtual_Sweep_Context(self, sweep, start_sweep_trigger,
inner_step_time_s, inner_step_trigger, repetitions)
ctx = Virtual_Sweep_Context(self, sweep, start_sweep_trigger,
inner_step_time_s, inner_step_trigger,
repetitions)
if outer_step_trigger:
self._setup_outer_trigger(outer_step_trigger, start_sweep_trigger,
len(inner_voltages)*inner_step_time_s,
len(outer_voltages))
return ctx

def _setup_outer_trigger(self, outer_step_trigger: str,
start_sweep_trigger: str,
period_s: float, outer_cycles: int) -> None:
if not self._outer_trigger_channel:
raise ValueError("Arrangement needs an outer_trigger_channel when"
" using outer_step_trigger")
return
helper_ch = self._qdac.channel(self._outer_trigger_channel)
helper_ctx = helper_ch.sine_wave(
period_s=period_s, repetitions=outer_cycles, span_V=0)
helper_ctx.start_on(self.get_trigger_by_name(start_sweep_trigger))
trigger = self.get_trigger_by_name(outer_step_trigger)
helper_ctx._marker_period_start = trigger
helper_ctx.period_start_marker()
self._outer_trigger_context = helper_ctx

def _calculate_2d_values(self, inner_contact: str,
inner_voltages: Sequence[float],
Expand Down Expand Up @@ -2434,7 +2467,8 @@ def mac(self) -> str:

def arrange(self, contacts: Dict[str, int],
output_triggers: Optional[Dict[str, int]] = None,
internal_triggers: Optional[Sequence[str]] = None
internal_triggers: Optional[Sequence[str]] = None,
outer_trigger_channel: Optional[int] = None
) -> Arrangement_Context:
"""An arrangement of contacts and triggers for virtual gates

Expand All @@ -2455,12 +2489,13 @@ def arrange(self, contacts: Dict[str, int],
contacts (Dict[str, int]): Name/channel pairs
output_triggers (Sequence[Tuple[str,int]], optional): Name/number pairs of output triggers
internal_triggers (Sequence[str], optional): List of names of internal triggers to allocate
outer_trigger_channel (int, optional): Additional channel if outer trigger is needed

Returns:
Arrangement_Context: context manager
"""
return Arrangement_Context(self, contacts, output_triggers,
internal_triggers)
internal_triggers, outer_trigger_channel)

# -----------------------------------------------------------------------
# Instrument-wide functions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,39 @@ def test_arrangement_detune(qdac): # noqa
# Start sweep
'tint 1'
]


@pytest.mark.wip
def test_arrangement_sweep_outer_trigger(qdac): # noqa
qdac.free_all_triggers()
arrangement = qdac.arrange(
contacts={'plunger1': 1, 'plunger2': 2},
output_triggers={'slow': 1},
outer_trigger_channel=1)
qdac.start_recording_scpi()
# -----------------------------------------------------------------------
sweep = arrangement.virtual_sweep2d(
inner_contact='plunger1',
inner_voltages=np.linspace(-1, 1, 5),
outer_contact='plunger2',
outer_voltages=np.linspace(-1, 1, 3),
outer_step_trigger='slow')
# -----------------------------------------------------------------------
commands = qdac.get_recorded_scpi_commands()
assert commands == [
# Outer trigger generator
'sour1:sine:trig:sour hold',
'sour1:sine:per 5e-05',
'sour1:sine:pol norm',
'sour1:sine:span 0',
'sour1:sine:offs 0.0',
'sour1:sine:slew inf',
'sour1:sine:del 0',
'sour1:sine:coun 3',
'sour1:sine:trig:sour bus',
'sour1:sine:init:cont on',
'sour1:sine:trig:sour int2',
'sour1:sine:init:cont on',
# Internal to external
'sour1:sine:mark:pstart 1',
]