Skip to content

Commit

Permalink
Merge ea1af99 into 11e2434
Browse files Browse the repository at this point in the history
  • Loading branch information
terrorfisch committed Jun 7, 2021
2 parents 11e2434 + ea1af99 commit 9f1ea61
Show file tree
Hide file tree
Showing 16 changed files with 338 additions and 1,333 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Expand Up @@ -4,8 +4,8 @@ python:
- 3.7
- 3.8
env:
- INSTALL_EXTRAS=[plotting,zurich-instruments,tektronix]
- INSTALL_EXTRAS=[plotting,zurich-instruments,tektronix,Faster-fractions]
- INSTALL_EXTRAS=[plotting,zurich-instruments,tektronix,tabor-instruments]
- INSTALL_EXTRAS=[plotting,zurich-instruments,tektronix,tabor-instruments,Faster-fractions]

#use container based infrastructure
sudo: false
Expand Down
1 change: 1 addition & 0 deletions changes.d/599.bugfix
@@ -0,0 +1 @@
Replace pytabor and teawg with tabor_control to support newer(>=1.11) pyvisa versions
2 changes: 1 addition & 1 deletion qupulse/hardware/awgs/__init__.py
Expand Up @@ -19,7 +19,7 @@
def install_requirements(vendor: str):
package_repos = {
'tektronix': 'tek_awg',
'tabor': 'https://git.rwth-aachen.de/qutech/python-TaborDriver/-/archive/python3/python-TaborDriver-python3.zip'
'tabor': 'tabor_control'
}

if vendor not in package_repos:
Expand Down
70 changes: 41 additions & 29 deletions qupulse/hardware/awgs/tabor.py
@@ -1,15 +1,13 @@
import fractions
import functools
import warnings
import weakref
import logging
import numbers
from typing import List, Tuple, Set, Callable, Optional, Any, Sequence, cast, Union, Dict, Mapping, NamedTuple
from collections import OrderedDict

# Provided by Tabor electronics for python 2.7
# a python 3 version is in a private repository on https://git.rwth-aachen.de/qutech
# Beware of the string encoding change!
import teawg
import tabor_control.device
import numpy as np

from qupulse.utils.types import ChannelID
Expand All @@ -26,14 +24,18 @@
class TaborAWGRepresentation:
def __init__(self, instr_addr=None, paranoia_level=1, external_trigger=False, reset=False, mirror_addresses=()):
"""
:param instr_addr: Instrument address that is forwarded to teawg
:param paranoia_level: Paranoia level that is forwarded to teawg
:param instr_addr: Instrument address that is forwarded to tabor_control
:param paranoia_level: Paranoia level that is forwarded to tabor_control
:param external_trigger: Not supported yet
:param reset:
:param mirror_addresses:
"""
self._instr = teawg.TEWXAwg(instr_addr, paranoia_level)
self._mirrors = tuple(teawg.TEWXAwg(address, paranoia_level) for address in mirror_addresses)
visa_instr = tabor_control.open_session(instr_addr)
paranoia_level = tabor_control.ParanoiaLevel(paranoia_level)

self._instr = tabor_control.device.TEWXAwg(visa_instr, paranoia_level)
self._mirrors = tuple(tabor_control.device.TEWXAwg(tabor_control.open_session(address), paranoia_level)
for address in mirror_addresses)
self._coupled = None

self._clock_marker = [0, 0, 0, 0]
Expand Down Expand Up @@ -64,28 +66,30 @@ def channel_pair_CD(self) -> 'TaborChannelPair':
return self._channel_pair_CD

@property
def main_instrument(self) -> teawg.TEWXAwg:
def main_instrument(self) -> tabor_control.device.TEWXAwg:
return self._instr

@property
def mirrored_instruments(self) -> Sequence[teawg.TEWXAwg]:
def mirrored_instruments(self) -> Sequence[tabor_control.device.TEWXAwg]:
return self._mirrors

@property
def paranoia_level(self) -> int:
return self._instr.paranoia_level
return self._instr.paranoia_level.value

@paranoia_level.setter
def paranoia_level(self, val):
if isinstance(val, int):
val = min(max(val, 0), 2)
for instr in self.all_devices:
instr.paranoia_level = val

@property
def dev_properties(self) -> dict:
return self._instr.dev_properties
return self._instr.dev_properties.as_dict()

@property
def all_devices(self) -> Sequence[teawg.TEWXAwg]:
def all_devices(self) -> Sequence[tabor_control.device.TEWXAwg]:
return (self._instr, ) + self._mirrors

def send_cmd(self, cmd_str, paranoia_level=None):
Expand All @@ -99,20 +103,24 @@ def send_query(self, query_str, query_mirrors=False) -> Any:
return self._instr.send_query(query_str)

def send_binary_data(self, pref, bin_dat, paranoia_level=None):
assert pref == ':TRAC:DATA'
for instr in self.all_devices:
instr.send_binary_data(pref, bin_dat=bin_dat, paranoia_level=paranoia_level)
instr.write_segment_data(bin_dat, paranoia_level=paranoia_level)

def download_segment_lengths(self, seg_len_list, pref=':SEGM:DATA', paranoia_level=None):
assert pref == ':SEGM:DATA'
for instr in self.all_devices:
instr.download_segment_lengths(seg_len_list, pref=pref, paranoia_level=paranoia_level)
instr.write_segment_lengths(seg_len_list, paranoia_level=paranoia_level)

def download_sequencer_table(self, seq_table, pref=':SEQ:DATA', paranoia_level=None):
assert pref == ':SEQ:DATA'
for instr in self.all_devices:
instr.download_sequencer_table(seq_table, pref=pref, paranoia_level=paranoia_level)
instr.write_sequencer_table(seq_table, paranoia_level=paranoia_level)

def download_adv_seq_table(self, seq_table, pref=':ASEQ:DATA', paranoia_level=None):
assert pref == ':ASEQ:DATA'
for instr in self.all_devices:
instr.download_adv_seq_table(seq_table, pref=pref, paranoia_level=paranoia_level)
instr.write_advanced_sequencer_table(seq_table, paranoia_level=paranoia_level)

def _send_cmd(self, cmd_str, paranoia_level=None) -> Any:
"""Overwrite send_cmd for paranoia_level > 3"""
Expand Down Expand Up @@ -254,9 +262,9 @@ def reset(self) -> None:
def trigger(self) -> None:
self.send_cmd(':TRIG')

def get_readable_device(self, simulator=True) -> teawg.TEWXAwg:
def get_readable_device(self, simulator=True) -> tabor_control.device.TEWXAwg:
for device in self.all_devices:
if device.fw_ver >= 3.0:
if device.supports_basic_reading():
if simulator:
if device.is_simulator:
return device
Expand Down Expand Up @@ -396,14 +404,16 @@ def _free_points_at_end(self) -> int:
@with_select
def read_waveforms(self) -> List[np.ndarray]:
device = self.device.get_readable_device(simulator=True)

old_segment = device.send_query(':TRAC:SEL?')
waveforms = []
uploaded_waveform_indices = np.flatnonzero(self._segment_references) + 1
for segment in uploaded_waveform_indices:
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), paranoia_level=self.internal_paranoia_level)

try:
waveforms = []
uploaded_waveform_indices = np.flatnonzero(self._segment_references) + 1
for segment in uploaded_waveform_indices:
device.send_cmd(':TRAC:SEL {}'.format(segment), paranoia_level=self.internal_paranoia_level)
waveforms.append(device.read_segment_data())
finally:
device.send_cmd(':TRAC:SEL {}'.format(old_segment), paranoia_level=self.internal_paranoia_level)
return waveforms

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

@with_select
def read_advanced_sequencer_table(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
return self.device.get_readable_device(simulator=True).read_adv_seq_table()
adv_seq_table = self.device.get_readable_device(simulator=True).read_advanced_sequencer_table()
return adv_seq_table['repeats'], adv_seq_table['segment_no'], adv_seq_table['jump_flag']

def read_complete_program(self) -> PlottableProgram:
return PlottableProgram.from_read_data(self.read_waveforms(),
Expand Down Expand Up @@ -765,7 +777,7 @@ def set_volatile_parameters(self, program_name: str, parameters: Mapping[str, nu
self._execute_multiple_commands_with_config_guard(commands)

# Wait until AWG is finished
_ = self.device.main_instrument._visa_inst.query('*OPC?')
_ = self.device.main_instrument.send_query('*OPC?')

def set_marker_state(self, marker: int, active: bool) -> None:
"""Sets the marker state of this channel pair.
Expand Down
8 changes: 6 additions & 2 deletions qupulse/hardware/feature_awg/features.py
Expand Up @@ -8,7 +8,11 @@
AWGChannelTuple
from qupulse.utils.types import ChannelID

import pyvisa
try:
# only required for type annotations
import pyvisa
except ImportError:
pyvisa = None


########################################################################################################################
Expand All @@ -20,7 +24,7 @@ class SCPI(AWGDeviceFeature, ABC):
https://en.wikipedia.org/wiki/Standard_Commands_for_Programmable_Instruments
"""

def __init__(self, visa: pyvisa.resources.MessageBasedResource):
def __init__(self, visa: 'pyvisa.resources.MessageBasedResource'):
super().__init__()
self._socket = visa

Expand Down
68 changes: 34 additions & 34 deletions qupulse/hardware/feature_awg/tabor.py
Expand Up @@ -3,10 +3,13 @@
import numbers
import sys
import weakref
import warnings
from typing import List, Tuple, Set, Callable, Optional, Any, cast, Union, Dict, Mapping, NamedTuple, Iterable,\
Collection
Collection, Sequence
from collections import OrderedDict

import numpy as np

from qupulse import ChannelID
from qupulse._program._loop import Loop, make_compatible

Expand All @@ -18,16 +21,12 @@

from qupulse.utils.types import TimeType
from qupulse.hardware.feature_awg.base import AWGChannelTuple, AWGChannel, AWGDevice, AWGMarkerChannel
from typing import Sequence
from qupulse._program.tabor import TaborSegment, TaborException, TaborProgram, PlottableProgram, TaborSequencing, \
make_combined_wave

import tabor_control.device
import pyvisa
import warnings

# Provided by Tabor electronics for python 2.7
# a python 3 version is in a private repository on https://git.rwth-aachen.de/qutech
# Beware of the string encoding change!
import teawg

assert (sys.byteorder == "little")

Expand Down Expand Up @@ -237,16 +236,17 @@ def __init__(self, device_name: str, instr_addr=None, paranoia_level=1, external
Args:
device_name (str): Name of the device
instr_addr: Instrument address that is forwarded to teawag
paranoia_level (int): Paranoia level that is forwarded to teawg
instr_addr: Instrument address that is forwarded to tabor_control
paranoia_level (int): Paranoia level that is forwarded to tabor_control
external_trigger (bool): Not supported yet
reset (bool):
mirror_addresses: list of devices on which the same things as on the main device are done.
For example you can a simulator and a real Device at once
"""
super().__init__(device_name)
self._instr = teawg.TEWXAwg(instr_addr, paranoia_level)
self._mirrors = tuple(teawg.TEWXAwg(address, paranoia_level) for address in mirror_addresses)
self._instr = tabor_control.device.TEWXAwg(tabor_control.open_session(instr_addr), paranoia_level)
self._mirrors = tuple(tabor_control.device.TEWXAwg(tabor_control.open_session(address), paranoia_level)
for address in mirror_addresses)
self._coupled = None
self._clock_marker = [0, 0, 0, 0]

Expand Down Expand Up @@ -326,19 +326,19 @@ def channel_tuples(self) -> Collection["TaborChannelTuple"]:
return self._channel_tuples

@property
def main_instrument(self) -> teawg.TEWXAwg:
def main_instrument(self) -> tabor_control.device.TEWXAwg:
return self._instr

@property
def mirrored_instruments(self) -> Sequence[teawg.TEWXAwg]:
def mirrored_instruments(self) -> Sequence[tabor_control.device.TEWXAwg]:
return self._mirrors

@property
def all_devices(self) -> Sequence[teawg.TEWXAwg]:
def all_devices(self) -> Sequence[tabor_control.device.TEWXAwg]:
return (self._instr,) + self._mirrors

@property
def _paranoia_level(self) -> int:
def _paranoia_level(self) -> tabor_control.ParanoiaLevel:
return self._instr.paranoia_level

@_paranoia_level.setter
Expand All @@ -348,25 +348,23 @@ def _paranoia_level(self, val):

@property
def dev_properties(self) -> dict:
return self._instr.dev_properties
return self._instr.dev_properties.as_dict()

def _send_binary_data(self, pref, bin_dat, paranoia_level=None):
def _send_binary_data(self, bin_dat, paranoia_level=None):
for instr in self.all_devices:
instr.send_binary_data(pref, bin_dat=bin_dat, paranoia_level=paranoia_level)
instr.write_segment_data(bin_dat, paranoia_level=paranoia_level)

def _download_segment_lengths(self, seg_len_list, pref=":SEGM:DATA", paranoia_level=None):
def _download_segment_lengths(self, seg_len_list, paranoia_level=None):
for instr in self.all_devices:
instr.download_segment_lengths(seg_len_list, pref=pref, paranoia_level=paranoia_level)
instr.write_segment_lengths(seg_len_list, paranoia_level=paranoia_level)

def _download_sequencer_table(self, seq_table, pref=":SEQ:DATA", paranoia_level=None):
def _download_sequencer_table(self, seq_table, paranoia_level=None):
for instr in self.all_devices:
instr.download_sequencer_table(seq_table, pref=pref, paranoia_level=paranoia_level)
instr.write_sequencer_table(seq_table, paranoia_level=paranoia_level)

def _download_adv_seq_table(self, seq_table, pref=":ASEQ:DATA", paranoia_level=None):
def _download_adv_seq_table(self, seq_table, paranoia_level=None):
for instr in self.all_devices:
instr.download_adv_seq_table(seq_table, pref=pref, paranoia_level=paranoia_level)

make_combined_wave = staticmethod(teawg.TEWXAwg.make_combined_wave)
instr.write_advanced_sequencer_table(seq_table, paranoia_level=paranoia_level)

def _initialize(self) -> None:
# 1. Select channel
Expand All @@ -386,7 +384,7 @@ def _initialize(self) -> None:
self[SCPI].send_cmd(":INST:SEL 3")
self[SCPI].send_cmd(setup_command)

def _get_readable_device(self, simulator=True) -> teawg.TEWXAwg:
def _get_readable_device(self, simulator=True) -> tabor_control.device.TEWXAwg:
"""
A method to get the first readable device out of all devices.
A readable device is a device which you can read data from like a simulator.
Expand All @@ -398,7 +396,7 @@ def _get_readable_device(self, simulator=True) -> teawg.TEWXAwg:
TaborException: this exception is thrown if there is no readable device in the list of all devices
"""
for device in self.all_devices:
if device.fw_ver >= 3.0:
if device.supports_basic_reading():
if simulator:
if device.is_simulator:
return device
Expand Down Expand Up @@ -676,7 +674,7 @@ def clear(self) -> None:
self._channel_tuple.device[SCPI].send_cmd(":TRAC:DEF 1, 192")
self._channel_tuple.device[SCPI].send_cmd(":TRAC:SEL 1")
self._channel_tuple.device[SCPI].send_cmd(":TRAC:MODE COMB")
self._channel_tuple.device._send_binary_data(pref=":TRAC:DATA", bin_dat=self._channel_tuple._idle_segment.get_as_binary())
self._channel_tuple.device._send_binary_data(bin_dat=self._channel_tuple._idle_segment.get_as_binary())

self._channel_tuple._segment_lengths = 192 * np.ones(1, dtype=np.uint32)
self._channel_tuple._segment_capacity = 192 * np.ones(1, dtype=np.uint32)
Expand Down Expand Up @@ -1015,7 +1013,7 @@ def read_waveforms(self) -> List[np.ndarray]:

for segment in uploaded_waveform_indices:
device.send_cmd(":TRAC:SEL {}".format(segment), paranoia_level=self.internal_paranoia_level)
waveforms.append(device.read_act_seg_dat())
waveforms.append(device.read_segment_data())
device.send_cmd(":TRAC:SEL {}".format(old_segment), paranoia_level=self.internal_paranoia_level)
return waveforms

Expand All @@ -1028,13 +1026,15 @@ def read_sequence_tables(self) -> List[Tuple[np.ndarray, np.ndarray, np.ndarray]
uploaded_sequence_indices = np.arange(len(self._sequencer_tables)) + 1
for sequence in uploaded_sequence_indices:
device.send_cmd(":SEQ:SEL {}".format(sequence), paranoia_level=self.internal_paranoia_level)
sequences.append(device.read_sequencer_table())
table = device.read_sequencer_table()
sequences.append((table['repeats'], table['segment_no'], table['jump_flag']))
device.send_cmd(":SEQ:SEL {}".format(old_sequence), paranoia_level=self.internal_paranoia_level)
return sequences

@with_select
def read_advanced_sequencer_table(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
return self.device._get_readable_device(simulator=True).read_adv_seq_table()
table = self.device._get_readable_device(simulator=True).read_advanced_sequencer_table()
return table['repeats'], table['segment_no'], table['jump_flag']

def read_complete_program(self) -> PlottableProgram:
return PlottableProgram.from_read_data(self.read_waveforms(),
Expand Down Expand Up @@ -1153,7 +1153,7 @@ def _upload_segment(self, segment_index: int, segment: TaborSegment) -> None:
paranoia_level=self.internal_paranoia_level)
wf_data = segment.get_as_binary()

self.device._send_binary_data(pref=":TRAC:DATA", bin_dat=wf_data)
self.device._send_binary_data(bin_dat=wf_data)
self._segment_references[segment_index] = 1
self._segment_hashes[segment_index] = hash(segment)

Expand All @@ -1174,7 +1174,7 @@ def _amend_segments(self, segments: List[TaborSegment]) -> np.ndarray:
paranoia_level=self.internal_paranoia_level)
self.device[TaborSCPI].send_cmd(":TRAC:MODE COMB",
paranoia_level=self.internal_paranoia_level)
self.device._send_binary_data(pref=":TRAC:DATA", bin_dat=wf_data)
self.device._send_binary_data(bin_dat=wf_data)

old_to_update = np.count_nonzero(self._segment_capacity != self._segment_lengths)
segment_capacity = np.concatenate((self._segment_capacity, new_lengths))
Expand Down

0 comments on commit 9f1ea61

Please sign in to comment.