Source code for qcodes.instrument_drivers.AlazarTech.ATS9360

from typing import TYPE_CHECKING, Any

import numpy as np
from packaging import version

from qcodes import validators

from .ATS import AlazarTechATS
from .utils import TraceParameter

if TYPE_CHECKING:
    from qcodes.parameters import Parameter


[docs] class AlazarTechATS9360(AlazarTechATS): """ This class is the driver for the ATS9360 board it inherits from the ATS base class """ samples_divisor = 128 _trigger_holdoff_min_fw_version = '21.07' def __init__(self, name: str, dll_path: str = 'C:\\WINDOWS\\System32\\ATSApi.dll', **kwargs: Any): super().__init__(name, dll_path=dll_path, **kwargs) # add parameters # ----- Parameters for the configuration of the board ----- self.clock_source: TraceParameter = self.add_parameter( name="clock_source", parameter_class=TraceParameter, label="Clock Source", unit=None, initial_value="INTERNAL_CLOCK", val_mapping={ "INTERNAL_CLOCK": 1, "FAST_EXTERNAL_CLOCK": 2, "EXTERNAL_CLOCK_10MHz_REF": 7, }, ) """Parameter clock_source""" self.external_sample_rate: TraceParameter = self.add_parameter( name="external_sample_rate", parameter_class=TraceParameter, label="External Sample Rate", unit="S/s", vals=validators.MultiType( validators.Ints(300000000, 1800000000), validators.Enum("UNDEFINED") ), initial_value="UNDEFINED", ) """Parameter external_sample_rate""" self.sample_rate: TraceParameter = self.add_parameter( name="sample_rate", parameter_class=TraceParameter, label="Internal Sample Rate", unit="S/s", initial_value="UNDEFINED", val_mapping={ 1_000: 1, 2_000: 2, 5_000: 4, 10_000: 8, 20_000: 10, 50_000: 12, 100_000: 14, 200_000: 16, 500_000: 18, 1_000_000: 20, 2_000_000: 24, 5_000_000: 26, 10_000_000: 28, 20_000_000: 30, 50_000_000: 34, 100_000_000: 36, 200_000_000: 40, 500_000_000: 48, 800_000_000: 50, 1_000_000_000: 53, 1_200_000_000: 55, 1_500_000_000: 58, 1_800_000_000: 61, "EXTERNAL_CLOCK": 64, "UNDEFINED": "UNDEFINED", }, ) """Parameter sample_rate""" self.clock_edge: TraceParameter = self.add_parameter( name="clock_edge", parameter_class=TraceParameter, label="Clock Edge", unit=None, initial_value="CLOCK_EDGE_RISING", val_mapping={"CLOCK_EDGE_RISING": 0, "CLOCK_EDGE_FALLING": 1}, ) """Parameter clock_edge""" self.decimation: TraceParameter = self.add_parameter( name="decimation", parameter_class=TraceParameter, label="Decimation", unit=None, initial_value=1, vals=validators.Ints(0, 100000), ) """Parameter decimation""" for i in range(1, self.channels+1): self.add_parameter(name=f'coupling{i}', parameter_class=TraceParameter, label=f'Coupling channel {i}', unit=None, initial_value='DC', val_mapping={'AC': 1, 'DC': 2}) self.add_parameter(name=f'channel_range{i}', parameter_class=TraceParameter, label=f'Range channel {i}', unit='V', initial_value=0.4, val_mapping={0.4: 7}) self.add_parameter(name=f'impedance{i}', parameter_class=TraceParameter, label=f'Impedance channel {i}', unit='Ohm', initial_value=50, val_mapping={50: 2}) self.add_parameter(name=f'bwlimit{i}', parameter_class=TraceParameter, label=f'Bandwidth limit channel {i}', unit=None, initial_value='DISABLED', val_mapping={'DISABLED': 0, 'ENABLED': 1}) self.trigger_operation: TraceParameter = self.add_parameter( name="trigger_operation", parameter_class=TraceParameter, label="Trigger Operation", unit=None, initial_value="TRIG_ENGINE_OP_J", val_mapping={ "TRIG_ENGINE_OP_J": 0, "TRIG_ENGINE_OP_K": 1, "TRIG_ENGINE_OP_J_OR_K": 2, "TRIG_ENGINE_OP_J_AND_K": 3, "TRIG_ENGINE_OP_J_XOR_K": 4, "TRIG_ENGINE_OP_J_AND_NOT_K": 5, "TRIG_ENGINE_OP_NOT_J_AND_K": 6, }, ) """Parameter trigger_operation""" n_trigger_engines = 2 for i in range(1, n_trigger_engines+1): self.add_parameter(name=f'trigger_engine{i}', parameter_class=TraceParameter, label=f'Trigger Engine {i}', unit=None, initial_value='TRIG_ENGINE_' + ('J' if i == 1 else 'K'), val_mapping={'TRIG_ENGINE_J': 0, 'TRIG_ENGINE_K': 1}) self.add_parameter(name=f'trigger_source{i}', parameter_class=TraceParameter, label=f'Trigger Source {i}', unit=None, initial_value='EXTERNAL', val_mapping={'CHANNEL_A': 0, 'CHANNEL_B': 1, 'EXTERNAL': 2, 'DISABLE': 3}) self.add_parameter(name=f'trigger_slope{i}', parameter_class=TraceParameter, label=f'Trigger Slope {i}', unit=None, initial_value='TRIG_SLOPE_POSITIVE', val_mapping={'TRIG_SLOPE_POSITIVE': 1, 'TRIG_SLOPE_NEGATIVE': 2}) self.add_parameter(name=f'trigger_level{i}', parameter_class=TraceParameter, label=f'Trigger Level {i}', unit=None, initial_value=140, vals=validators.Ints(0, 255)) self.external_trigger_coupling: TraceParameter = self.add_parameter( name="external_trigger_coupling", parameter_class=TraceParameter, label="External Trigger Coupling", unit=None, initial_value="DC", val_mapping={"AC": 1, "DC": 2}, ) """Parameter external_trigger_coupling""" self.external_trigger_range: TraceParameter = self.add_parameter( name="external_trigger_range", parameter_class=TraceParameter, label="External Trigger Range", unit=None, initial_value="ETR_2V5", val_mapping={"ETR_TTL": 2, "ETR_2V5": 3}, ) """Parameter external_trigger_range""" self.trigger_delay: TraceParameter = self.add_parameter( name="trigger_delay", parameter_class=TraceParameter, label="Trigger Delay", unit="Sample clock cycles", initial_value=0, vals=validators.Multiples(divisor=8, min_value=0), ) """Parameter trigger_delay""" # See Table 3 - Trigger Delay Alignment # TODO: this is either 8 or 16 dependent on the number of channels in use # NOTE: The board will wait for a for this amount of time for a # trigger event. If a trigger event does not arrive, then the # board will automatically trigger. Set the trigger timeout value # to 0 to force the board to wait forever for a trigger event. # # IMPORTANT: The trigger timeout value should be set to zero after # appropriate trigger parameters have been determined, otherwise # the board may trigger if the timeout interval expires before a # hardware trigger event arrives. self.timeout_ticks: TraceParameter = self.add_parameter( name="timeout_ticks", parameter_class=TraceParameter, label="Timeout Ticks", unit="10 us", initial_value=0, vals=validators.Ints(min_value=0), ) """Parameter timeout_ticks""" self.aux_io_mode: TraceParameter = self.add_parameter( name="aux_io_mode", parameter_class=TraceParameter, label="AUX I/O Mode", unit=None, initial_value="AUX_IN_AUXILIARY", val_mapping={ "AUX_OUT_TRIGGER": 0, "AUX_IN_TRIGGER_ENABLE": 1, "AUX_IN_AUXILIARY": 13, }, ) """Parameter aux_io_mode""" self.aux_io_param: TraceParameter = self.add_parameter( name="aux_io_param", parameter_class=TraceParameter, label="AUX I/O Param", unit=None, initial_value="NONE", val_mapping={"NONE": 0, "TRIG_SLOPE_POSITIVE": 1, "TRIG_SLOPE_NEGATIVE": 2}, ) """Parameter aux_io_param""" # ----- Parameters for the acquire function ----- self.mode: Parameter = self.add_parameter( name="mode", label="Acquisition mode", unit=None, initial_value="NPT", set_cmd=None, val_mapping={"NPT": 0x200, "TS": 0x400}, ) """Parameter mode""" self.samples_per_record: Parameter = self.add_parameter( name="samples_per_record", label="Samples per Record", unit=None, initial_value=1024, set_cmd=None, vals=validators.Multiples(divisor=self.samples_divisor, min_value=256), ) """Parameter samples_per_record""" self.records_per_buffer: Parameter = self.add_parameter( name="records_per_buffer", label="Records per Buffer", unit=None, initial_value=10, set_cmd=None, vals=validators.Ints(min_value=0), ) """Parameter records_per_buffer""" self.buffers_per_acquisition: Parameter = self.add_parameter( name="buffers_per_acquisition", label="Buffers per Acquisition", unit=None, set_cmd=None, initial_value=10, vals=validators.Ints(min_value=0), ) """Parameter buffers_per_acquisition""" self.channel_selection: Parameter = self.add_parameter( name="channel_selection", label="Channel Selection", unit=None, set_cmd=None, initial_value="AB", val_mapping={"A": 1, "B": 2, "AB": 3}, ) """Parameter channel_selection""" self.transfer_offset: Parameter = self.add_parameter( name="transfer_offset", label="Transfer Offset", unit="Samples", set_cmd=None, initial_value=0, vals=validators.Ints(min_value=0), ) """Parameter transfer_offset""" self.external_startcapture: Parameter = self.add_parameter( name="external_startcapture", label="External Startcapture", unit=None, set_cmd=None, initial_value="ENABLED", val_mapping={"DISABLED": 0x0, "ENABLED": 0x1}, ) """Parameter external_startcapture""" self.enable_record_headers: Parameter = self.add_parameter( name="enable_record_headers", label="Enable Record Headers", unit=None, set_cmd=None, initial_value="DISABLED", val_mapping={"DISABLED": 0x0, "ENABLED": 0x8}, ) """Parameter enable_record_headers""" self.alloc_buffers: Parameter = self.add_parameter( name="alloc_buffers", label="Alloc Buffers", unit=None, set_cmd=None, initial_value="DISABLED", val_mapping={"DISABLED": 0x0, "ENABLED": 0x20}, ) """Parameter alloc_buffers""" self.fifo_only_streaming: Parameter = self.add_parameter( name="fifo_only_streaming", label="Fifo Only Streaming", unit=None, set_cmd=None, initial_value="DISABLED", val_mapping={"DISABLED": 0x0, "ENABLED": 0x800}, ) """Parameter fifo_only_streaming""" self.interleave_samples: Parameter = self.add_parameter( name="interleave_samples", label="Interleave Samples", unit=None, set_cmd=None, initial_value="DISABLED", val_mapping={"DISABLED": 0x0, "ENABLED": 0x1000}, ) """Parameter interleave_samples""" self.get_processed_data: Parameter = self.add_parameter( name="get_processed_data", label="Get Processed Data", unit=None, set_cmd=None, initial_value="DISABLED", val_mapping={"DISABLED": 0x0, "ENABLED": 0x2000}, ) """Parameter get_processed_data""" self.allocated_buffers: Parameter = self.add_parameter( name="allocated_buffers", label="Allocated Buffers", unit=None, set_cmd=None, initial_value=4, vals=validators.Ints(min_value=0), ) """Parameter allocated_buffers""" self.buffer_timeout: Parameter = self.add_parameter( name="buffer_timeout", label="Buffer Timeout", unit="ms", set_cmd=None, initial_value=1000, vals=validators.Ints(min_value=0), ) """Parameter buffer_timeout""" self.trigger_holdoff: Parameter = self.add_parameter( name="trigger_holdoff", label="Trigger Holdoff", docstring=f"If enabled Alazar will " f"ignore any additional triggers " f"while capturing a record. If disabled " f"a trigger signal during a capture " f" will result in corrupt data. " f"Support for this requires at least " f"firmware version " f"{self._trigger_holdoff_min_fw_version}", vals=validators.Bool(), get_cmd=self._get_trigger_holdoff, set_cmd=self._set_trigger_holdoff, ) """ If enabled Alazar will ignore any additional triggers while capturing a record. """ model = self.get_idn()["model"] if model != "ATS9360": raise Exception( f"The Alazar board kind is not 'ATS9360'," f" found '{model!s}' instead." ) def _get_trigger_holdoff(self) -> bool: fwversion = self.get_idn()['firmware'] if not isinstance(fwversion, str) or version.parse(fwversion) < version.parse( self._trigger_holdoff_min_fw_version ): return False # we want to check if the 26h bit (zero indexed) is high or not output = np.uint32(self._read_register(58)) # the two first two chars in the bit string is the sign and a 'b' # remove those to only get the bit pattern bitmask = bin(output)[2:] # all prefixed zeros are ignored in the bit conversion so the # bit mask may be shorter than what we expect. in that case # the bit we care about is zero so we return False if len(bitmask) < 27: return False return bool(bin(output)[-27]) def _set_trigger_holdoff(self, value: bool) -> None: fwversion = self.get_idn()["firmware"] if not isinstance(fwversion, str) or version.parse(fwversion) < version.parse( self._trigger_holdoff_min_fw_version ): raise RuntimeError( f"Alazar 9360 requires at least firmware " f"version {self._trigger_holdoff_min_fw_version}" f" for trigger holdoff support. " f"You have version {fwversion}" ) current_value = self._read_register(58) if value is True: # to enable trigger hold off we want to flip the # 26th bit to 1. We do that by making a bitwise or # with a number that has a 1 on the 26th place and zero # otherwise. We use numpy.unit32 instead of python numbers # to have unsigned ints of the right size enable_mask = np.uint32(1 << 26) new_value = current_value | enable_mask else: # to disable trigger hold off we want to flip the # 26th bit to 0. We do that by making a bitwise and # with a number that has a 0 on the 26th place and 1 # otherwise disable_mask = ~np.uint32(1 << 26) new_value = current_value & disable_mask self._write_register(58, int(new_value))
class AlazarTech_ATS9360(AlazarTechATS9360): """ Alias for backwards compatibility. Will eventually be deprecated and removed """ pass