Skip to content
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
5 changes: 3 additions & 2 deletions qupulse/_program/tabor.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,10 +515,11 @@ def get_sampled_segments(self) -> Tuple[Sequence[TaborSegment], Sequence[int]]:

def update_volatile_parameters(self, parameters: Mapping[str, Parameter]) -> Mapping[Union[int, Tuple[int, int]],
Union[TableEntry, TableDescription]]:
"""
""" Set the values of parameters which were marked as volatile on program creation. Sets volatile parameters
in program memory.

Args:
parameters:
parameters: Name of volatile parameters and respective values to which they should be set.

Returns:
Mapping position of change -> (new repetition value, element_num/id, jump flag)
Expand Down
102 changes: 67 additions & 35 deletions qupulse/hardware/awgs/tabor.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,10 +334,23 @@ def __init__(self, tabor_device: TaborAWGRepresentation, channels: Tuple[int, in
self._sequencer_tables = None
self._advanced_sequence_table = None

self._internal_paranoia_level = 0

self.clear()

@property
def internal_paranoia_level(self) -> Optional[int]:
return self._internal_paranoia_level

@internal_paranoia_level.setter
def internal_paranoia_level(self, paranoia_level: Optional[int]):
""" Sets the paranoia level with which commands from within methods are called """
assert paranoia_level in (None, 0, 1, 2)
self._internal_paranoia_level = paranoia_level

def select(self) -> None:
self.device.send_cmd(':INST:SEL {}'.format(self._channels[0]))
self.device.send_cmd(':INST:SEL {}'.format(self._channels[0]),
paranoia_level=self.internal_paranoia_level)

@property
def total_capacity(self) -> int:
Expand Down Expand Up @@ -390,9 +403,9 @@ def read_waveforms(self) -> List[np.ndarray]:
waveforms = []
uploaded_waveform_indices = np.flatnonzero(self._segment_references) + 1
for segment in uploaded_waveform_indices:
device.send_cmd(':TRAC:SEL {}'.format(segment))
device.send_cmd(':TRAC:SEL {}'.format(segment), paranoia_level=self.internal_paranoia_level)
waveforms.append(device.read_act_seg_dat())
device.send_cmd(':TRAC:SEL {}'.format(old_segment))
device.send_cmd(':TRAC:SEL {}'.format(old_segment), paranoia_level=self.internal_paranoia_level)
return waveforms

@with_select
Expand All @@ -403,9 +416,9 @@ def read_sequence_tables(self) -> List[Tuple[np.ndarray, np.ndarray, np.ndarray]
sequences = []
uploaded_sequence_indices = np.arange(len(self._sequencer_tables)) + 1
for sequence in uploaded_sequence_indices:
device.send_cmd(':SEQ:SEL {}'.format(sequence))
device.send_cmd(':SEQ:SEL {}'.format(sequence), paranoia_level=self.internal_paranoia_level)
sequences.append(device.read_sequencer_table())
device.send_cmd(':SEQ:SEL {}'.format(old_sequence))
device.send_cmd(':SEQ:SEL {}'.format(old_sequence), paranoia_level=self.internal_paranoia_level)
return sequences

@with_select
Expand Down Expand Up @@ -497,13 +510,13 @@ def upload(self, name: str,
def clear(self) -> None:
"""Delete all segments and clear memory"""
self.device.select_channel(self._channels[0])
self.device.send_cmd(':TRAC:DEL:ALL')
self.device.send_cmd(':SOUR:SEQ:DEL:ALL')
self.device.send_cmd(':ASEQ:DEL')
self.device.send_cmd(':TRAC:DEL:ALL', paranoia_level=self.internal_paranoia_level)
self.device.send_cmd(':SOUR:SEQ:DEL:ALL', paranoia_level=self.internal_paranoia_level)
self.device.send_cmd(':ASEQ:DEL', paranoia_level=self.internal_paranoia_level)

self.device.send_cmd(':TRAC:DEF 1, 192')
self.device.send_cmd(':TRAC:SEL 1')
self.device.send_cmd(':TRAC:MODE COMB')
self.device.send_cmd(':TRAC:DEF 1, 192', paranoia_level=self.internal_paranoia_level)
self.device.send_cmd(':TRAC:SEL 1', paranoia_level=self.internal_paranoia_level)
self.device.send_cmd(':TRAC:MODE COMB', paranoia_level=self.internal_paranoia_level)
self.device.send_binary_data(pref=':TRAC:DATA', bin_dat=self._idle_segment.get_as_binary())

self._segment_lengths = 192*np.ones(1, dtype=np.uint32)
Expand Down Expand Up @@ -610,12 +623,13 @@ def _upload_segment(self, segment_index: int, segment: TaborSegment) -> None:

segment_no = segment_index + 1

self.device.send_cmd(':TRAC:DEF {}, {}'.format(segment_no, segment.num_points))
self.device.send_cmd(':TRAC:DEF {}, {}'.format(segment_no, segment.num_points),
paranoia_level=self.internal_paranoia_level)
self._segment_lengths[segment_index] = segment.num_points

self.device.send_cmd(':TRAC:SEL {}'.format(segment_no))
self.device.send_cmd(':TRAC:SEL {}'.format(segment_no), paranoia_level=self.internal_paranoia_level)

self.device.send_cmd(':TRAC:MODE COMB')
self.device.send_cmd(':TRAC:MODE COMB', paranoia_level=self.internal_paranoia_level)
wf_data = segment.get_as_binary()

self.device.send_binary_data(pref=':TRAC:DATA', bin_dat=wf_data)
Expand All @@ -632,9 +646,12 @@ def _amend_segments(self, segments: List[TaborSegment]) -> np.ndarray:

segment_index = len(self._segment_capacity)
first_segment_number = segment_index + 1
self.device.send_cmd(':TRAC:DEF {},{}'.format(first_segment_number, trac_len))
self.device.send_cmd(':TRAC:SEL {}'.format(first_segment_number))
self.device.send_cmd(':TRAC:MODE COMB')
self.device.send_cmd(':TRAC:DEF {},{}'.format(first_segment_number, trac_len),
paranoia_level=self.internal_paranoia_level)
self.device.send_cmd(':TRAC:SEL {}'.format(first_segment_number),
paranoia_level=self.internal_paranoia_level)
self.device.send_cmd(':TRAC:MODE COMB',
paranoia_level=self.internal_paranoia_level)
self.device.send_binary_data(pref=':TRAC:DATA', bin_dat=wf_data)

old_to_update = np.count_nonzero(self._segment_capacity != self._segment_lengths)
Expand All @@ -645,14 +662,16 @@ def _amend_segments(self, segments: List[TaborSegment]) -> np.ndarray:
if len(segments) < old_to_update:
for i, segment in enumerate(segments):
current_segment_number = first_segment_number + i
self.device.send_cmd(':TRAC:DEF {},{}'.format(current_segment_number, segment.num_points))
self.device.send_cmd(':TRAC:DEF {},{}'.format(current_segment_number, segment.num_points),
paranoia_level=self.internal_paranoia_level)
else:
# flush the capacity
self.device.download_segment_lengths(segment_capacity)

# update non fitting lengths
for i in np.flatnonzero(segment_capacity != segment_lengths):
self.device.send_cmd(':TRAC:DEF {},{}'.format(i+1, segment_lengths[i]))
self.device.send_cmd(':TRAC:DEF {},{}'.format(i+1, segment_lengths[i]),
paranoia_level=self.internal_paranoia_level)

self._segment_capacity = segment_capacity
self._segment_lengths = segment_lengths
Expand All @@ -678,7 +697,8 @@ def cleanup(self) -> None:
chunk_size = 10
for chunk_start in range(new_end, old_end, chunk_size):
self.device.send_cmd('; '.join('TRAC:DEL {}'.format(i+1)
for i in range(chunk_start, min(chunk_start+chunk_size, old_end))))
for i in range(chunk_start, min(chunk_start+chunk_size, old_end))),
paranoia_level=self.internal_paranoia_level)
except Exception as e:
raise TaborUndefinedState('Error during cleanup. Device is in undefined state.', device=self) from e

Expand All @@ -695,14 +715,26 @@ def remove(self, name: str) -> None:

@with_configuration_guard
def _execute_multiple_commands_with_config_guard(self, commands: List[str]) -> None:
""" Joins the given commands into one and executes it with configuration guard.

Args:
commands: Commands that should be executed.
"""
cmd_str = ";".join(commands)
self.device.send_cmd(cmd_str)
self.device.send_cmd(cmd_str, paranoia_level=self.internal_paranoia_level)

def set_volatile_parameters(self, program_name: str, parameters: Mapping[str, Parameter]) -> None:
"""Set the values of parameters which were marked as volatile on program creation."""
# TODO: Add documentation, increase readability
# When changing the tables of current program use guarded mode as it gives way smaller blips
# But it is slower however (184 ms vs 47 ms)
""" Set the values of parameters which were marked as volatile on program creation. Sets volatile parameters
in program memory and device's (adv.) sequence tables if program is current program.

If set_volatile_parameters needs to run faster, set CONFIG_MODE_PARANOIA_LEVEL to 0 which causes the device to
enter the configuration mode with paranoia level 0 (Note: paranoia level 0 does not work for the simulator)
and set device._is_coupled.

Args:
program_name: Name of program which should be changed.
parameters: Names of volatile parameters and respective values to which they should be set.
"""

waveform_to_segment_index, program = self._known_programs[program_name]

Expand Down Expand Up @@ -742,16 +774,16 @@ def set_marker_state(self, marker: int, active: bool) -> None:
channel=self._channels[0],
marker=(1, 2)[marker],
active='ON' if active else 'OFF')
self.device.send_cmd(command_string)
self.device.send_cmd(command_string, paranoia_level=self.internal_paranoia_level)

def set_channel_state(self, channel, active) -> None:
command_string = ':INST:SEL {}; :OUTP {}'.format(self._channels[channel], 'ON' if active else 'OFF')
self.device.send_cmd(command_string)
self.device.send_cmd(command_string, paranoia_level=self.internal_paranoia_level)

@with_select
def arm(self, name: str) -> None:
if self._current_program == name:
self.device.send_cmd('SEQ:SEL 1')
self.device.send_cmd('SEQ:SEL 1', paranoia_level=self.internal_paranoia_level)
else:
self.change_armed_program(name)

Expand Down Expand Up @@ -798,17 +830,17 @@ def change_armed_program(self, name: Optional[str]) -> None:
advanced_sequencer_table.append((1, 1, 0))

# reset sequencer and advanced sequencer tables to fix bug which occurs when switching between some programs
self.device.send_cmd('SEQ:DEL:ALL')
self.device.send_cmd('SEQ:DEL:ALL', paranoia_level=self.internal_paranoia_level)
self._sequencer_tables = []
self.device.send_cmd('ASEQ:DEL')
self.device.send_cmd('ASEQ:DEL', paranoia_level=self.internal_paranoia_level)
self._advanced_sequence_table = []

# download all sequence tables
for i, sequencer_table in enumerate(sequencer_tables):
self.device.send_cmd('SEQ:SEL {}'.format(i+1))
self.device.send_cmd('SEQ:SEL {}'.format(i+1), paranoia_level=self.internal_paranoia_level)
self.device.download_sequencer_table(sequencer_table)
self._sequencer_tables = sequencer_tables
self.device.send_cmd('SEQ:SEL 1')
self.device.send_cmd('SEQ:SEL 1', paranoia_level=self.internal_paranoia_level)

self.device.download_adv_seq_table(advanced_sequencer_table)
self._advanced_sequence_table = advanced_sequencer_table
Expand All @@ -818,7 +850,7 @@ def change_armed_program(self, name: Optional[str]) -> None:
@with_select
def run_current_program(self) -> None:
if self._current_program:
self.device.send_cmd(':TRIG')
self.device.send_cmd(':TRIG', paranoia_level=self.internal_paranoia_level)
else:
raise RuntimeError('No program active')

Expand All @@ -841,8 +873,8 @@ def num_markers(self) -> int:

def _enter_config_mode(self) -> None:
"""Enter the configuration mode if not already in. All outputs are set to the DC offset of the device and the
sequencing is disabled. The manual states this speeds up sequence validation when uploading multiple
sequences."""
sequencing is disabled. The manual states this speeds up sequence validation when uploading multiple sequences.
When entering and leaving the configuration mode the AWG outputs a small (~60 mV in 4 V mode) blip."""
if self._is_in_config_mode is False:

# 1. Select channel pair
Expand Down
17 changes: 14 additions & 3 deletions tests/hardware/tabor_dummy_based_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,17 @@ def setUpClass(cls):
def setUp(self):
super().setUp()

def test__execute_multiple_commands_with_config_guard(self):
channel_pair = self.TaborChannelPair(self.instrument, identifier='asd', channels=(1, 2))
# prevent entering and exiting configuration mode
channel_pair._configuration_guard_count = 2

given_commands = [':ASEQ:DEF 2,2,5,0', ':SEQ:SEL 2', ':SEQ:DEF 1,2,10,0']
expected_command = ':ASEQ:DEF 2,2,5,0;:SEQ:SEL 2;:SEQ:DEF 1,2,10,0'
with mock.patch.object(channel_pair.device, 'send_cmd') as send_cmd:
channel_pair._execute_multiple_commands_with_config_guard(given_commands)
send_cmd.assert_called_once_with(expected_command, paranoia_level=channel_pair.internal_paranoia_level)

def test_set_volatile_parameters(self):
channel_pair = self.TaborChannelPair(self.instrument, identifier='asd', channels=(1, 2))

Expand Down Expand Up @@ -526,7 +537,7 @@ def test_upload_segment(self):
':TRAC:DEF 3, 208',
':TRAC:SEL 3',
':TRAC:MODE COMB']
expected_log = [((), dict(cmd_str=cmd, paranoia_level=None))
expected_log = [((), dict(cmd_str=cmd, paranoia_level=channel_pair.internal_paranoia_level))
for cmd in expected_commands]
self.assertAllCommandLogsEqual(expected_log)

Expand Down Expand Up @@ -572,7 +583,7 @@ def test_amend_segments_flush(self):
':TRAC:SEL 5',
':TRAC:MODE COMB',
':TRAC:DEF 3,208']
expected_log = [((), dict(cmd_str=cmd, paranoia_level=None))
expected_log = [((), dict(cmd_str=cmd, paranoia_level=channel_pair.internal_paranoia_level))
for cmd in expected_commands]
self.assertAllCommandLogsEqual(expected_log)
#self.assertEqual(expected_log, instrument.main_instrument.logged_commands)
Expand Down Expand Up @@ -622,7 +633,7 @@ def test_amend_segments_iter(self):
':TRAC:MODE COMB',
':TRAC:DEF 5,192',
':TRAC:DEF 6,192']
expected_log = [((), dict(cmd_str=cmd, paranoia_level=None))
expected_log = [((), dict(cmd_str=cmd, paranoia_level=channel_pair.internal_paranoia_level))
for cmd in expected_commands]
self.assertAllCommandLogsEqual(expected_log)

Expand Down
Loading