def __init__(self, name: str, address: str, **kwargs: Any) -> None: super().__init__(name, address, terminator='\n', **kwargs) self.add_parameter('start_freq', label='Sweep start frequency', unit='Hz', set_cmd=partial(self.invalidate_trace, 'STAR {} HZ'), get_cmd='STAR?', get_parser=float, vals=vals.Numbers(30000, 6000000000)) self.add_parameter('stop_freq', label='Sweep stop frequency', unit='Hz', set_cmd=partial(self.invalidate_trace, 'STOP {} HZ'), get_cmd='STOP?', get_parser=float, vals=vals.Numbers(30000, 6000000000)) self.add_parameter('averaging', label='Averaging state', set_cmd='AVERO{}', get_cmd='AVERO?', val_mapping={ 'ON': 1, 'OFF': 0 }) self.add_parameter('number_of_averages', label='Number of averages', set_cmd='AVERFACT{}', get_cmd='AVERFACT?', get_parser=HPIntParser, vals=vals.Ints(0, 999)) self.add_parameter('trace_points', label='Number of points in trace', set_cmd=partial(self.invalidate_trace, 'POIN{}'), get_cmd='POIN?', get_parser=HPIntParser, vals=vals.Enum(3, 11, 26, 51, 101, 201, 401, 801, 1601)) self.add_parameter( 'sweep_time', label='Sweep time', set_cmd='SWET{}', get_cmd='SWET?', unit='s', get_parser=float, vals=vals.Numbers(0.01, 86400), ) self.add_parameter('output_power', label='Output power', unit='dBm', set_cmd='POWE{}', get_cmd='POWE?', get_parser=float, vals=vals.Numbers(-85, 20)) self.add_parameter('s_parameter', label='S-parameter', set_cmd=self._s_parameter_setter, get_cmd=self._s_parameter_getter) # DISPLAY / Y SCALE PARAMETERS self.add_parameter('display_format', label='Display format', set_cmd=self._display_format_setter, get_cmd=self._display_format_getter) # TODO: update this on startup and via display format self.add_parameter( 'display_reference', label='Display reference level', unit=None, # will be set by display_format get_cmd='REFV?', set_cmd='REFV{}', get_parser=float, vals=vals.Numbers(-500, 500)) self.add_parameter( 'display_scale', label='Display scale', unit=None, # will be set by display_format get_cmd='SCAL?', set_cmd='SCAL{}', get_parser=float, vals=vals.Numbers(-500, 500)) self.add_parameter(name='trace', parameter_class=HP8753DTrace) # Startup self.startup() self.connect_message()
def __init__(self, name, alt_dll_path=None, **kwargs): dll_path = 'C:\\WINDOWS\\System32\\ATSApi.dll' # dll_path = 'C:\\WINDOWS\\system32\\ATS_Average_DLL.dll' #additional dll for specific needs (ie GetAverregedBuffer) if alt_dll_path == None: # check if alt_dll has been chosen alt_dll_path = dll_path super().__init__(name, dll_path=dll_path, alt_dll_path=alt_dll_path, **kwargs) # add parameters # ----- Parameters for the configuration of the board ----- self.add_parameter(name='clock_source', parameter_class=TraceParameter, label='Clock Source', unit=None, initial_value='INTERNAL_CLOCK', val_mapping={ 'INTERNAL_CLOCK': 1, 'SLOW_EXTERNAL_CLOCK': 4, 'EXTERNAL_CLOCK_AC': 5, 'EXTERNAL_CLOCK_10_MHz_REF': 7 }) self.add_parameter(name='external_sample_rate', get_cmd=None, parameter_class=TraceParameter, label='External Sample Rate', unit='S/s', vals=validators.Enum(1_000_000_000), initial_value=None) self.add_parameter(name='sample_rate', parameter_class=TraceParameter, label='Sample Rate', unit='S/s', initial_value=1000000000, val_mapping={ 1000: 0x1, 2000: 0x2, 5000: 0x4, 10000: 0x8, 20000: 0xA, 50000: 0xC, 100000: 0xE, 200000: 0x10, 500000: 0x12, 1000000: 0x14, 2000000: 0x18, 5000000: 0x1A, 10000000: 0x1C, 20000000: 0x1E, 50000000: 0x22, 100000000: 0x24, 250000000: 0x2B, 500000000: 0x30, 1000000000: 0x35, 'EXTERNAL_CLOCK': 0x40, '1GHz_REFERENCE_CLOCK': 1000000000 }) 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 }) self.add_parameter(name='decimation', parameter_class=TraceParameter, label='Decimation', unit=None, initial_value=0, vals=validators.Ints(0, 100000)) for i in ['1', '2']: self.add_parameter(name='coupling' + i, parameter_class=TraceParameter, label='Coupling channel ' + i, unit=None, initial_value='AC', val_mapping={ 'AC': 1, 'DC': 2 }) self.add_parameter(name='channel_range' + i, parameter_class=TraceParameter, label='Range channel ' + i, unit='V', initial_value=4, val_mapping={ 0.04: 2, 0.1: 5, 0.2: 6, 0.4: 7, 1.0: 10, 2.0: 11, 4.0: 12 }) self.add_parameter(name='impedance' + i, parameter_class=TraceParameter, label='Impedance channel ' + i, unit='Ohm', initial_value=50, val_mapping={ 1000000: 1, 50: 2 }) self.add_parameter(name='bwlimit' + i, parameter_class=TraceParameter, label='Bandwidth limit channel ' + i, unit=None, initial_value='DISABLED', val_mapping={ 'DISABLED': 0, 'ENABLED': 1 }) 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 }) for i in ['1', '2']: self.add_parameter(name='trigger_engine' + i, parameter_class=TraceParameter, label='Trigger Engine ' + i, unit=None, initial_value='TRIG_ENGINE_' + ('J' if i == 0 else 'K'), val_mapping={ 'TRIG_ENGINE_J': 0, 'TRIG_ENGINE_K': 1 }) self.add_parameter(name='trigger_source' + i, parameter_class=TraceParameter, label='Trigger Source ' + i, unit=None, initial_value='DISABLE', val_mapping={ 'CHANNEL_A': 0, 'CHANNEL_B': 1, 'EXTERNAL': 2, 'DISABLE': 3 }) self.add_parameter(name='trigger_slope' + i, parameter_class=TraceParameter, label='Trigger Slope ' + i, unit=None, initial_value='TRIG_SLOPE_POSITIVE', val_mapping={ 'TRIG_SLOPE_POSITIVE': 1, 'TRIG_SLOPE_NEGATIVE': 2 }) self.add_parameter(name='trigger_level' + i, parameter_class=TraceParameter, label='Trigger Level ' + i, unit=None, initial_value=128, vals=validators.Ints(0, 255)) self.add_parameter(name='external_trigger_coupling', parameter_class=TraceParameter, label='External Trigger Coupling', unit=None, initial_value='AC', val_mapping={ 'AC': 1, 'DC': 2 }) self.add_parameter(name='external_trigger_range', parameter_class=TraceParameter, label='External Trigger Range', unit=None, initial_value='ETR_5V', val_mapping={ 'ETR_5V': 0, 'ETR_1V': 1 }) self.add_parameter(name='trigger_delay', parameter_class=TraceParameter, label='Trigger Delay', unit='Sample clock cycles', initial_value=0, vals=validators.Ints(min_value=0)) self.add_parameter(name='timeout_ticks', parameter_class=TraceParameter, label='Timeout Ticks', unit='10 us', initial_value=0, vals=validators.Ints(min_value=0)) 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 }) 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 }) # ----- Parameters for the acquire function ----- self.add_parameter(name='mode', label='Acquisition mode', unit=None, initial_value='NPT', get_cmd=None, set_cmd=None, val_mapping={ 'NPT': 0x200, 'TS': 0x400, 'AVG': 0x600 }) # samples_per_record must be a multiple of of some number (64 in the # case of ATS9870) and and has some minimum (256 in the case of ATS9870) # These values can be found in the ATS-SDK programmar's guide self.add_parameter(name='samples_per_record', label='Samples per Record', unit=None, initial_value=96000, get_cmd=None, set_cmd=None, vals=validators.Multiples(divisor=64, min_value=256)) self.add_parameter(name='records_per_buffer', label='Records per Buffer', unit=None, initial_value=1, get_cmd=None, set_cmd=None, vals=validators.Ints(min_value=0)) self.add_parameter(name='buffers_per_acquisition', label='Buffers per Acquisition', unit=None, get_cmd=None, set_cmd=None, initial_value=1, vals=validators.Ints(min_value=0)) self.add_parameter(name='channel_selection', label='Channel Selection', unit=None, get_cmd=None, set_cmd=None, initial_value='AB', val_mapping={ 'A': 1, 'B': 2, 'AB': 3 }) self.add_parameter(name='transfer_offset', label='Transfer Offset', unit='Samples', get_cmd=None, set_cmd=None, initial_value=0, vals=validators.Ints(min_value=0)) self.add_parameter(name='external_startcapture', label='External Startcapture', unit=None, get_cmd=None, set_cmd=None, initial_value='ENABLED', val_mapping={ 'DISABLED': 0X0, 'ENABLED': 0x1 }) self.add_parameter(name='enable_record_headers', label='Enable Record Headers', unit=None, get_cmd=None, set_cmd=None, initial_value='DISABLED', val_mapping={ 'DISABLED': 0x0, 'ENABLED': 0x8 }) self.add_parameter(name='alloc_buffers', label='Alloc Buffers', unit=None, get_cmd=None, set_cmd=None, initial_value='DISABLED', val_mapping={ 'DISABLED': 0x0, 'ENABLED': 0x20 }) self.add_parameter(name='fifo_only_streaming', label='Fifo Only Streaming', unit=None, get_cmd=None, set_cmd=None, initial_value='DISABLED', val_mapping={ 'DISABLED': 0x0, 'ENABLED': 0x800 }) self.add_parameter(name='interleave_samples', label='Interleave Samples', unit=None, get_cmd=None, set_cmd=None, initial_value='DISABLED', val_mapping={ 'DISABLED': 0x0, 'ENABLED': 0x1000 }) self.add_parameter(name='get_processed_data', label='Get Processed Data', unit=None, get_cmd=None, set_cmd=None, initial_value='DISABLED', val_mapping={ 'DISABLED': 0x0, 'ENABLED': 0x2000 }) self.add_parameter(name='allocated_buffers', label='Allocated Buffers', unit=None, get_cmd=None, set_cmd=None, initial_value=1, vals=validators.Ints(min_value=0)) self.add_parameter(name='buffer_timeout', label='Buffer Timeout', unit='ms', get_cmd=None, set_cmd=None, initial_value=1000, vals=validators.Ints(min_value=0)) self.add_parameter(name='dmaBufferCount', label='dma Buffer Count', unit=None, get_cmd=None, set_cmd=None, initial_value=8, vals=validators.Ints(min_value=2)) self.add_parameter(name='number_of_averaging', label='number of averaging', unit=None, get_cmd=None, set_cmd=None, initial_value=1, vals=validators.Ints(min_value=1)) model = self.get_idn()['model'] if model != 'ATS9870': raise Exception("The Alazar board kind is not 'ATS9870'," " found '" + str(model) + "' instead.")
class DacChannel(InstrumentChannel, DacReader): """ A single DAC channel of the DECADAC """ _CHANNEL_VAL = vals.Ints(0, 3) def __init__(self, parent, name, channel, min_val=-5, max_val=5): super().__init__(parent, name) # Validate slot and channel values self._CHANNEL_VAL.validate(channel) self._channel = channel self._slot = self.parent._slot # Calculate base address for querying channel parameters # Note that the following values can be found using these offsets # 0: Interrupt Period # 4: DAC High Limit # 5: DAC Low Limit # 6: Slope (double) # 8: DAC Value (double) self._base_addr = 1536 + (16 * 4) * self._slot + 16 * self._channel # Store min/max voltages assert (min_val < max_val) self.min_val = min_val self.max_val = max_val # Add channel parameters # Note we will use the older addresses to read the value from the dac # rather than the newer 'd' command for backwards compatibility self._volt_val = vals.Numbers(self.min_val, self.max_val) self.add_parameter("volt", get_cmd=partial(self._query_address, self._base_addr + 9, 1), get_parser=self._dac_code_to_v, set_cmd=self._set_dac, set_parser=self._dac_v_to_code, vals=self._volt_val, label="channel {}".format(channel + self._slot * 4), unit="V") # The limit commands are used to sweep dac voltages. They are not # safety features. self.add_parameter("lower_ramp_limit", get_cmd=partial(self._query_address, self._base_addr + 5), get_parser=self._dac_code_to_v, set_cmd="L{};", set_parser=self._dac_v_to_code, vals=self._volt_val, label="Lower_Ramp_Limit", unit="V") self.add_parameter("upper_ramp_limit", get_cmd=partial(self._query_address, self._base_addr + 4), get_parser=self._dac_code_to_v, set_cmd="U{};", set_parser=self._dac_v_to_code, vals=self._volt_val, label="Upper_Ramp_Limit", unit="V") self.add_parameter("update_period", get_cmd=partial(self._query_address, self._base_addr), get_parser=int, set_cmd="T{};", set_parser=int, vals=vals.Ints(50, 65535), label="Update_Period", unit="us") self.add_parameter("slope", get_cmd=partial(self._query_address, self._base_addr + 6, 2), get_parser=int, set_cmd="S{};", set_parser=int, vals=vals.Ints(-(2**32), 2**32), label="Ramp_Slope") # Manual parameters to control whether DAC channels should ramp to # voltages or jump self._ramp_val = vals.Numbers(0, 10) self.add_parameter("enable_ramp", get_cmd=None, set_cmd=None, initial_value=False, vals=vals.Bool()) self.add_parameter("ramp_rate", get_cmd=None, set_cmd=None, initial_value=0.1, vals=self._ramp_val, unit="V/s") # Add ramp function to the list of functions self.add_function("ramp", call_cmd=self._ramp, args=(self._volt_val, self._ramp_val)) # If we have access to the VERSADAC (slot) EEPROM, we can set the # initial value of the channel. # NOTE: these values will be overwritten by a K3 calibration if self.parent._VERSA_EEPROM_available: _INITIAL_ADDR = [6, 8, 32774, 32776] self.add_parameter("initial_value", get_cmd=partial(self._query_address, _INITIAL_ADDR[self._channel], versa_eeprom=True), get_parser=self._dac_code_to_v, set_cmd=partial(self._write_address, _INITIAL_ADDR[self._channel], versa_eeprom=True), set_parser=self._dac_v_to_code, vals=vals.Numbers(self.min_val, self.max_val)) def _ramp(self, val, rate, block=True): """ Ramp the DAC to a given voltage. Params: val (float): The voltage to ramp to in volts rate (float): The ramp rate in units of volts/s block (bool): Should the call block until the ramp is complete? """ # We need to know the current dac value (in raw units), as well as the # update rate c_volt = self.volt.get() # Current Voltage if c_volt == val: # If we are already at the right voltage, we don't need to ramp return c_val = self._dac_v_to_code(c_volt) # Current voltage in DAC units e_val = self._dac_v_to_code(val) # Endpoint in DAC units # Number of refreshes per second t_rate = 1 / (self.update_period.get() * 1e-6) # Number of seconds to ramp secs = abs((c_volt - val) / rate) # The formula to calculate the slope is: Number of DAC steps divided by # the number of time steps in the ramp multiplied by 65536 slope = int(((e_val - c_val) / (t_rate * secs)) * 65536) # Now let's set up our limits and ramo slope if slope > 0: self.upper_ramp_limit.set(val) else: self.lower_ramp_limit.set(val) self.slope.set(slope) # Block until the ramp is complete is block is True if block: while self.slope.get() != 0: pass def _set_dac(self, code): """ Set the voltage on the dac channel, ramping if the enable_rate parameter is set for this channel. Params: code (int): the DAC code to set the voltage to """ if self.enable_ramp.get(): self._ramp(self._dac_code_to_v(code), rate=self.ramp_rate.get()) else: code = int(code) self._set_channel() self.ask_raw("U65535;L0;D{};".format(code)) def write(self, cmd): """ Overload write to set channel prior to any channel operations. Since all commands are echoed back, we must keep track of responses as well, otherwise commands receive the wrong response. """ self._set_channel() return self.ask_raw(cmd) def ask(self, cmd): """ Overload ask to set channel prior to operations """ self._set_channel() return self.ask_raw(cmd)
def __init__(self, parent, name, channum): """ Args: parent (Instrument): The instrument to which the channel is attached. name (str): The name of the channel channum (int): The number of the channel in question (1-48) """ super().__init__(parent, name) # Validate the channel self._CHANNEL_VALIDATION.validate(channum) # Add the parameters self.add_parameter('v', label=f'Channel {channum} voltage', unit='V', set_cmd=partial(self._parent._set_voltage, channum), get_cmd=partial(self._parent._get_voltage, channum), get_parser=float, vals=vals.Numbers(-10, 10) ) self.add_parameter('vrange', label=f'Channel {channum} atten.', set_cmd=partial(self._parent._set_vrange, channum), get_cmd=partial(self._parent._get_vrange, channum), vals=vals.Enum(0, 1) ) self.add_parameter('i', label=f'Channel {channum} current', get_cmd=f'get {channum}', unit='A', get_parser=self._parent._current_parser ) self.add_parameter('irange', label=f'Channel {channum} irange', set_cmd=f'cur {channum} {{}}', get_cmd=f'cur {channum}', get_parser=int ) self.add_parameter('slope', label=f'Channel {channum} slope', unit='V/s', set_cmd=partial(self._parent._setslope, channum), get_cmd=partial(self._parent._getslope, channum), vals=vals.MultiType(vals.Enum('Inf'), vals.Numbers(1e-3, 100)) ) self.add_parameter('sync', label=f'Channel {channum} sync output', set_cmd=partial(self._parent._setsync, channum), get_cmd=partial(self._parent._getsync, channum), vals=vals.Ints(0, 5) ) self.add_parameter(name='sync_delay', label=f'Channel {channum} sync pulse delay', unit='s', get_cmd=None, set_cmd=None, initial_value=0 ) self.add_parameter(name='sync_duration', label=f'Channel {channum} sync pulse duration', unit='s', get_cmd=None, set_cmd=None, initial_value=0.01 )
class DacSlot(InstrumentChannel, DacReader): """ A single DAC Slot of the DECADAC """ _SLOT_VAL = vals.Ints(0, 4) SLOT_MODE_DEFAULT = "Coarse" def __init__(self, parent, name, slot, min_val=-5, max_val=5): super().__init__(parent, name) # Validate slot and channel values self._SLOT_VAL.validate(slot) self._slot = slot # Store whether we have access to the VERSADAC EEPROM self._VERSA_EEPROM_available = self.parent._VERSA_EEPROM_available # Create a list of channels in the slot channels = ChannelList(self, "Slot_Channels", parent.DAC_CHANNEL_CLASS) for i in range(4): channels.append( parent.DAC_CHANNEL_CLASS(self, f"Chan{i}", i, min_val=min_val, max_val=max_val)) self.add_submodule("channels", channels) # Set the slot mode. Valid modes are: # Off: Channel outputs are disconnected from the input, grounded # with 10MOhm. # Fine: 2-channel mode. Channels 0 and 1 are output, use 2 and 3 # for fine adjustment of Channels 0 and 1 respectively # Coarse: All 4 channels are used as output # FineCald: Calibrated 2-channel mode, with 0 and 1 output, 2 and 3 # used automatically for fine adjustment. This mode only works # for calibrated DecaDAC's # # Unfortunately there is no known way of reading the slot mode hence # this will be set in initialization if self.parent._cal_supported: slot_modes = {"Off": 0, "Fine": 1, "Coarse": 2, "FineCald": 3} else: slot_modes = {"Off": 0, "Fine": 1, "Coarse": 2} self.add_parameter('slot_mode', get_cmd="m;", get_parser=self._dac_parse, set_cmd="M{};", val_mapping=slot_modes) # Enable all slots in coarse mode. self.slot_mode.set(self.SLOT_MODE_DEFAULT) def write(self, cmd): """ Overload write to set channel prior to any channel operations. Since all commands are echoed back, we must keep track of responses as well, otherwise commands receive the wrong response. """ self._set_slot() return self.ask_raw(cmd) def ask(self, cmd): """ Overload ask to set channel prior to operations """ self._set_slot() return self.ask_raw(cmd)
def __init__(self, parent: 'B1520A', name: str, **kwargs: Any): super().__init__(parent, name, **kwargs) self.add_parameter(name='sweep_auto_abort', set_cmd=self._set_sweep_auto_abort, get_cmd=self._get_sweep_auto_abort, set_parser=constants.Abort, get_parser=constants.Abort, vals=vals.Enum(*list(constants.Abort)), initial_cache_value=constants.Abort.ENABLED, docstring=textwrap.dedent(""" enables or disables the automatic abort function for the CV (DC bias) sweep measurement (MM18) and the pulsed bias sweep measurement (MM20). The automatic abort function stops the measurement when one of the following conditions occurs: - NULL loop unbalance condition - IV amplifier saturation condition - Overflow on the AD converter """)) self.add_parameter(name='post_sweep_voltage_condition', set_cmd=self._set_post_sweep_voltage_condition, get_cmd=self._get_post_sweep_voltage_condition, set_parser=constants.WMDCV.Post, get_parser=constants.WMDCV.Post, vals=vals.Enum(*list(constants.WMDCV.Post)), initial_cache_value=constants.WMDCV.Post.START, docstring=textwrap.dedent(""" This command also sets the post measurement condition of the MFCMU. After the measurement is normally completed, the DC bias sweep source forces the value specified by the post parameter, and the pulsed bias sweep source forces the pulse base value. If the measurement is stopped by the automatic abort function, the DC bias sweep source forces the start value, and the pulsed bias sweep source forces the pulse base value after sweep. """)) self.add_parameter(name='hold_time', initial_value=0.0, vals=vals.Numbers(0, 655.35), unit='s', parameter_class=GroupParameter, docstring=textwrap.dedent(""" Hold time (in seconds) that is the wait time after starting measurement and before starting delay time for the first step 0 to 655.35, with 10 ms resolution. Numeric expression. """)) self.add_parameter(name='delay', initial_value=0.0, vals=vals.Numbers(0, 65.535), unit='s', parameter_class=GroupParameter, docstring=textwrap.dedent(""" Delay time (in seconds) that is the wait time after starting to force a step output and before starting a step measurement. 0 to 65.535, with 0.1 ms resolution. Numeric expression. """)) self.add_parameter(name='step_delay', initial_value=0.0, vals=vals.Numbers(0, 1), unit='s', parameter_class=GroupParameter, docstring=textwrap.dedent(""" Step delay time (in seconds) that is the wait time after starting a step measurement and before starting to force the next step output. 0 to 1, with 0.1 ms resolution. Numeric expression. If this parameter is not set, step delay will be 0. If step delay is shorter than the measurement time, the B1500 waits until the measurement completes, then forces the next step output. """)) self.add_parameter(name='trigger_delay', initial_value=0.0, unit='s', parameter_class=GroupParameter, docstring=textwrap.dedent(""" Step source trigger delay time (in seconds) that is the wait time after completing a step output setup and before sending a step output setup completion trigger. 0 to the value of ``delay``, with 0.1 ms resolution. Numeric expression. If this parameter is not set, trigger delay will be 0. """)) self.add_parameter(name='measure_delay', initial_value=0.0, unit='s', vals=vals.Numbers(0, 65.535), parameter_class=GroupParameter, docstring=textwrap.dedent(""" Step measurement trigger delay time (in seconds) that is the wait time after receiving a start step measurement trigger and before starting a step measurement. 0 to 65.535, with 0.1 ms resolution. Numeric expression. If this parameter is not set, measure delay will be 0. """)) self._set_sweep_delays_group = Group([self.hold_time, self.delay, self.step_delay, self.trigger_delay, self.measure_delay], set_cmd='WTDCV ' '{hold_time},' '{delay},' '{step_delay},' '{trigger_delay},' '{measure_delay}', get_cmd=self._get_sweep_delays(), get_parser=self._get_sweep_delays_parser) self.add_parameter(name='sweep_mode', initial_value=constants.SweepMode.LINEAR, vals=vals.Enum(*list(constants.SweepMode)), set_parser=constants.SweepMode, parameter_class=GroupParameter, docstring=textwrap.dedent(""" Sweep mode. 1: Linear sweep (single stair, start to stop.) 2: Log sweep (single stair, start to stop.) 3: Linear sweep (double stair, start to stop to start.) 4: Log sweep (double stair, start to stop to start.) """)) self.add_parameter(name='sweep_start', initial_value=0.0, unit='V', vals=vals.Numbers(-25, 25), parameter_class=GroupParameter, docstring=textwrap.dedent(""" Start value of the DC bias sweep (in V). For the log sweep, start and stop must have the same polarity. """)) self.add_parameter(name='sweep_end', initial_value=0.0, unit='V', vals=vals.Numbers(-25, 25), parameter_class=GroupParameter, docstring=textwrap.dedent(""" Stop value of the DC bias sweep (in V). For the log sweep, start and stop must have the same polarity. """)) self.add_parameter(name='sweep_steps', initial_value=1, vals=vals.Ints(1, 1001), parameter_class=GroupParameter, docstring=textwrap.dedent(""" Number of steps for staircase sweep. Possible values from 1 to 1001""")) self.add_parameter(name='_chan', initial_value=self.parent.channels[0], parameter_class=GroupParameter) self._set_sweep_steps_group = Group( [self._chan, self.sweep_mode, self.sweep_start, self.sweep_end, self.sweep_steps], set_cmd='WDCV ' '{_chan},' '{sweep_mode},' '{sweep_start},' '{sweep_end},' '{sweep_steps}', get_cmd=self._get_sweep_steps(), get_parser=self._get_sweep_steps_parser )
def __init__(self, name, address, num_chans=48, update_currents=True): """ Instantiates the instrument. Args: name (str): The instrument name used by qcodes address (str): The VISA name of the resource num_chans (int): Number of channels to assign. Default: 48 update_currents (bool): Whether to query all channels for their current current value on startup. Default: True. Returns: QDac object """ super().__init__(name, address) handle = self.visa_handle # This is the baud rate on power-up. It can be changed later but # you must start out with this value. handle.baud_rate = 460800 handle.parity = visa.constants.Parity(0) handle.data_bits = 8 self.set_terminator('\n') # TODO: do we want a method for write termination too? handle.write_termination = '\n' # TODO: do we need a query delay for robust operation? self._write_response = '' # The following bool is used in self.write self.debugmode = False self.num_chans = num_chans if self._get_firmware_version() < 0.170202: raise RuntimeError(''' Obsolete QDAC Software version detected. QCoDeS only supports version 0.170202 or newer. Contact [email protected] for an update. ''') self._update_currents = update_currents # Assigned slopes. Entries will eventually be [chan, slope] self._slopes = [] # Function generators (used in _set_voltage) self._fgs = set(range(1, 9)) self._assigned_fgs = {} # {chan: fg} # Sync channels self._syncoutputs = [] # Entries: [chan, syncchannel] self.chan_range = range(1, 1 + self.num_chans) self.channel_validator = vals.Ints(1, self.num_chans) self._params_to_skip_update = [] for i in self.chan_range: self._params_to_skip_update.append('ch{:02}_v'.format(i)) self._params_to_skip_update.append('ch{:02}_i'.format(i)) self._params_to_skip_update.append('ch{:02}_vrange'.format(i)) self._params_to_skip_update.append('ch{:02}_irange'.format(i)) stri = str(i) self.add_parameter(name='ch{:02}_v'.format(i), label='Channel ' + stri, unit='V', set_cmd=partial(self._set_voltage, i), vals=vals.Numbers(-10, 10), get_cmd=partial(self.read_state, i, 'v')) self.add_parameter(name='ch{:02}_vrange'.format(i), set_cmd=partial(self._set_vrange, i), get_cmd=partial(self.read_state, i, 'vrange'), vals=vals.Enum(0, 1)) self.add_parameter(name='ch{:02}_irange'.format(i), set_cmd='cur ' + stri + ' {}', get_cmd=partial(self.read_state, i, 'irange')) self.add_parameter(name='ch{:02}_i'.format(i), label='Current ' + stri, unit='A', get_cmd='get ' + stri, get_parser=self._current_parser) self.add_parameter(name='ch{:02}_slope'.format(i), label='Maximum voltage slope', unit='V/s', set_cmd=partial(self._setslope, i), get_cmd=partial(self._getslope, i), vals=vals.MultiType(vals.Enum('Inf'), vals.Numbers(1e-3, 100))) self.add_parameter(name='ch{:02}_sync'.format(i), label='Channel {} sync output', set_cmd=partial(self._setsync, i), get_cmd=partial(self._getsync, i), vals=vals.Ints(0, 5)) self.add_parameter(name='ch{:02}_sync_delay'.format(i), label='Channel {} sync pulse delay'.format(i), unit='s', get_cmd=None, set_cmd=None, initial_value=0) self.add_parameter( name='ch{:02}_sync_duration'.format(i), label='Channel {} sync pulse duration'.format(i), unit='s', get_cmd=None, set_cmd=None, initial_value=0.01) for board in range(6): for sensor in range(3): label = 'Board {}, Temperature {}'.format(board, sensor) self.add_parameter(name='temp{}_{}'.format(board, sensor), label=label, unit='C', get_cmd='tem {} {}'.format(board, sensor), get_parser=self._num_verbose) self.add_parameter(name='cal', set_cmd='cal {}', vals=self.channel_validator) # TO-DO: maybe it's too dangerous to have this settable. # And perhaps ON is a better verbose mode default? self.add_parameter(name='verbose', set_cmd='ver {}', val_mapping={ True: 1, False: 0 }) self.add_parameter( name='fast_voltage_set', label='fast voltage set', get_cmd=None, set_cmd=None, vals=vals.Bool(), initial_value=False, docstring= """"Toggles if DC voltage set should unset any ramp attached to this channel. If you enable this you should ensure thay any function generator is unset from the channel before setting voltage""" ) # Initialise the instrument, all channels DC (unbind func. generators) for chan in self.chan_range: # Note: this call does NOT change the voltage on the channel self.write('wav {} 0 1 0'.format(chan)) self.verbose.set(False) self.connect_message() log.info('[*] Querying all channels for voltages and currents...') self._get_status(readcurrents=update_currents) log.info('[+] Done')
def add_parameters_from_file(self, filename: str): """ Takes in a node_doc JSON file auto generates parameters based on the contents of this file. """ f = open(filename).read() node_pars = json.loads(f) for par in node_pars.values(): node = par['Node'].split('/') # The parfile is valid for all devices of a certain type # so the device name has to be split out. parname = '_'.join(node[2:]).lower() parfunc = "/" + self._devname + "/" + "/".join(node[2:]) # This block provides the mapping between the ZI node and QCoDes # parameter. par_kw = {} par_kw['name'] = parname if par['Unit'] != 'None': par_kw['unit'] = par['Unit'] else: par_kw['unit'] = 'arb. unit' par_kw['docstring'] = par['Description'] if "Options" in par.keys(): # options can be done better, this is not sorted par_kw['docstring'] += '\nOptions:\n' + str(par['Options']) # Creates type dependent get/set methods if par['Type'] == 'Integer (64 bit)': par_kw['set_cmd'] = self._gen_set_func(self._dev.seti, parfunc) par_kw['get_cmd'] = self._gen_get_func(self._dev.geti, parfunc) # min/max not implemented yet for ZI auto docstrings #352 par_kw['vals'] = vals.Ints() elif par['Type'] == 'Double': par_kw['set_cmd'] = self._gen_set_func(self._dev.setd, parfunc) par_kw['get_cmd'] = self._gen_get_func(self._dev.getd, parfunc) # min/max not implemented yet for ZI auto docstrings #352 par_kw['vals'] = vals.Numbers() elif par['Type'] == 'ZIVectorData': par_kw['set_cmd'] = self._gen_set_func(self._dev.setv, parfunc) par_kw['get_cmd'] = self._gen_get_func(self._dev.getv, parfunc) # min/max not implemented yet for ZI auto docstrings #352 par_kw['vals'] = vals.Arrays() elif par['Type'] == 'CoreString': par_kw['get_cmd'] = self._gen_get_func(self._dev.getd, parfunc) par_kw['set_cmd'] = None # Not implemented par_kw['vals'] = vals.Strings() else: raise NotImplementedError # If not readable/writable the methods are removed after the type # dependent loop to keep this more readable. if 'Read' not in par['Properties']: par_kw['get_cmd'] = None if 'Write' not in par['Properties']: par_kw['set_cmd'] = None self.add_parameter(**par_kw)
def __init__(self, name, address, **kwargs): super().__init__(name, address, terminator='\r\n', timeout=10, **kwargs) self.channel_mapping = { 'T0': 0, 'T1': 1, 'A': 2, 'B': 3, 'C': 4, 'D': 5, 'E': 6, 'F': 7, 'G': 8, 'H': 9 } self.output_mapping = {'T0': 0, 'AB': 1, 'CD': 2, 'EF': 3, 'GH': 4} # self.display_mapping = { # 'trig_rate': 0, # 'trig_thresh': 1, # 'trig_single_shot': 2, # 'trig_line': 3, # 'advanced_trig_enable': 4, # 'trig_holdoff': 5, # 'prescale_config': 6, # 'burst_mode': 7, # 'burst_delay': 8, # 'burst_count': 9, # 'burst_period': 10, # 'channel_delay': 11, # 'channel_output_levels': 12, # 'channel_output_polarity': 13, # 'burst_T0_config': 14 # } self.prescale_mapping = {'trig': 0, 'AB': 1, 'CD': 2, 'EF': 3, 'GH': 4} self.trig_mapping = { 'internal': 0, 'ext_rising': 1, 'ext_falling': 2, 'single_ext_rising': 3, 'single_ext_falling': 4, 'single': 5, 'line': 6 } self.polarity_mapping = {'-': 0, '+': 1} self.add_parameter('trig_holdoff', label='Trigger holdoff', unit='s', get_cmd='HOLD?', get_parser=float, set_cmd='HOLD {}') #: Prescale parameters for k, v in self.prescale_mapping.items(): if v > 0: self.add_parameter( 'phase_{}'.format(k), label='Prescale phase factor {}'.format(k), unit='', get_cmd=lambda ch=k: self._get_phase_prescale(ch), get_parser=int, set_cmd=lambda val, ch=k: self._set_phase_prescale( val, channel=ch), vals=vals.Ints(min_value=0)) self.add_parameter( 'prescale_{}'.format(v), label='Prescale factor {}'.format(v), unit='', get_cmd=lambda ch=k: self._get_prescale(ch), get_parser=int, set_cmd=lambda val, ch=k: self._set_prescale(val, channel=ch), vals=vals.Ints(min_value=0)) #: Trigger parameters self.add_parameter('trig_level', label='Trigger level', unit='V', get_cmd='TLVL?', get_parser=float, set_cmd='TLVL {}', vals=vals.Numbers()) self.add_parameter('trig_rate', label='Trigger rate', unit='Hz', get_cmd='TRAT?', get_parser=float, set_cmd='TRAT {}', vals=vals.Numbers(min_value=0)) self.add_parameter('trig_source', label='Trigger source', unit='', get_cmd=self._get_trig_source, get_parser=str, set_cmd=self._set_trig_source, vals=vals.Enum(tuple(self.trig_mapping.keys()))) #: Burst parameters self.add_parameter('burst_count', label='Burst count', unit='', get_cmd='BURC?', get_parser=int, set_cmd='BURC {}', vals=vals.Ints(min_value=0)) self.add_parameter('burst_delay', label='Burst delay', unit='s', get_cmd='BURD?', get_parser=float, set_cmd='BURD {}', vals=vals.Numbers(min_value=0)) self.add_parameter('burst_period', label='Burst period', unit='s', get_cmd='BURP?', get_parser=float, set_cmd='BURC {}', vals=vals.Numbers(min_value=100e-9, max_value=2000 - 10e-9)) self.add_parameter('burst_T0_config', label='Burst T0 configuration', unit='', get_cmd='BURT?', get_parser=int, set_cmd='BURT {}', vals=vals.Enum(0, 1)) #: Channel parameters for ch, idx in self.channel_mapping.items(): if idx > 1: self.add_parameter( 'delay_{}'.format(ch), label='{} delay'.format(ch), unit='s', get_cmd=lambda c=ch: self._get_delay(channel=c), get_parser=str, set_cmd=lambda src_delay, c=ch: self._set_delay(src_delay, target=c), vals=vals.Strings()) self.add_parameter( 'channel_link_{}'.format(ch), label='Channel linked to {}'.format(ch), unit='', get_cmd=lambda c=ch: self._get_link(channel=c), get_parser=int, set_cmd=lambda d, c=ch: self._set_link(d, channel=c), vals=vals.Enum( tuple(k for k in self.channel_mapping if k != 'T1'))) #: Output parameters for out, idx in self.output_mapping.items(): self.add_parameter( 'amp_out_{}'.format(out), label='Output {} amplitude'.format(out), unit='V', get_cmd=lambda o=out: self._get_amp(output=o), get_parser=float, set_cmd=lambda lvl, o=out: self._set_amp(lvl, output=o), vals=vals.Numbers()) self.add_parameter( 'offset_out_{}'.format(out), label='Output {} offset'.format(out), unit='V', get_cmd=lambda o=out: self._get_offset(output=o), get_parser=float, set_cmd=lambda lvl, o=out: self._set_offset(lvl, output=o), vals=vals.Numbers()) self.add_parameter( 'polarity_out_{}'.format(out), label='Output {} polarity'.format(out), unit='', get_cmd=lambda o=out: self._get_polarity(output=o), get_parser=int, set_cmd=lambda lvl, o=out: self._set_offset(lvl, output=o), vals=vals.Enum(0, 1)) self.snapshot(update=True) self.connect_message()
def __init__(self, name, **kwargs): dll_path = 'C:\\WINDOWS\\System32\\ATSApi.dll' super().__init__(name, dll_path=dll_path, **kwargs) self._bwlimit_support = False # add parameters self.channels = ['A', 'B', 'C', 'D'] # ----- Parameters for the configuration of the board ----- self.add_parameter(name='clock_source', parameter_class=AlazarParameter, label='Clock Source', unit=None, value='internal_clock', byte_to_value_dict={ 1: 'internal_clock', 4: 'slow_external_clock', 5: 'external_clock_AC', 7: 'external_clock_10_MHz_ref' }) self.add_parameter(name='sample_rate', parameter_class=AlazarParameter, label='Sample Rate', unit='S/s', value=100000, byte_to_value_dict={ 0x1: 1000, 0x2: 2000, 0x4: 5000, 0x8: 10000, 0xA: 20000, 0xC: 50000, 0xE: 100000, 0x10: 200000, 0x12: 500000, 0x14: 1000000, 0x18: 2000000, 0x1A: 5000000, 0x1C: 10000000, 0x1E: 20000000, 0x22: 50000000, 0x24: 100000000, 0x25: 125000000, 0x40: 'external_clock', 1000000000: '1GHz_reference_clock' }) self.add_parameter(name='clock_edge', parameter_class=AlazarParameter, label='Clock Edge', unit=None, value='rising', byte_to_value_dict={ 0: 'rising', 1: 'falling' }) self.add_parameter(name='decimation', parameter_class=AlazarParameter, label='Decimation', unit=None, value=0, vals=validators.Ints(0, 100000)) # Acquisition channel parameters for ch in self.channels: self.add_parameter(name='coupling' + ch, parameter_class=AlazarParameter, label='Coupling channel ' + ch, unit=None, value='DC', byte_to_value_dict={ 1: 'AC', 2: 'DC' }) self.add_parameter(name='channel_range' + ch, parameter_class=AlazarParameter, label='Range channel ' + ch, unit='V', value=1, byte_to_value_dict={ 5: 0.1, 6: 0.2, 7: 0.4, 10: 1., 11: 2., 12: 4. }) self.add_parameter(name='impedance' + ch, parameter_class=AlazarParameter, label='Impedance channel ' + ch, unit='Ohm', value=50, byte_to_value_dict={2: 50}) # Trigger parameters self.add_parameter(name='trigger_operation', parameter_class=AlazarParameter, label='Trigger Operation', unit=None, value='J', byte_to_value_dict={ 0: 'J', 1: 'K', 2: 'J_or_K', 3: 'J_and_K', 4: 'J_xor_K', 5: 'J_and_not_K', 6: 'not_J_and_K' }) for i in ['1', '2']: self.add_parameter(name='trigger_engine' + i, parameter_class=AlazarParameter, label='Trigger Engine ' + i, unit=None, value=('J' if i == '1' else 'K'), byte_to_value_dict={ 0: 'J', 1: 'K' }) self.add_parameter(name='trigger_source' + i, parameter_class=AlazarParameter, label='Trigger Source ' + i, unit=None, value='disable', byte_to_value_dict={ 0: 'A', 1: 'B', 2: 'trig_in', 3: 'disable', 4: 'C', 5: 'D' }) self.add_parameter(name='trigger_slope' + i, parameter_class=AlazarParameter, label='Trigger Slope ' + i, unit=None, value='positive', byte_to_value_dict={ 1: 'positive', 2: 'negative' }) self.add_parameter(name='trigger_level' + i, parameter_class=AlazarParameter, label='Trigger Level ' + i, unit=None, value=150, vals=validators.Ints(0, 255)) self.add_parameter(name='external_trigger_coupling', parameter_class=AlazarParameter, label='External Trigger Coupling', unit=None, value='AC', byte_to_value_dict={ 1: 'AC', 2: 'DC' }) self.add_parameter(name='external_trigger_range', parameter_class=AlazarParameter, label='External Trigger Range', unit='V', value=5, byte_to_value_dict={ 0: 5, 1: 1 }) self.add_parameter(name='trigger_delay', parameter_class=AlazarParameter, label='Trigger Delay', unit='Sample clock cycles', value=0, vals=validators.Ints(min_value=0)) # 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.add_parameter(name='timeout_ticks', parameter_class=AlazarParameter, label='Timeout Ticks', unit='10 us', value=0, vals=validators.Ints(min_value=0)) # ----- Parameters for the acquire function ----- self.add_parameter(name='mode', parameter_class=AlazarParameter, label='Acquisition mode', unit=None, value='NPT', byte_to_value_dict={ 0x100: 'CS', 0x200: 'NPT', 0x400: 'TS' }) # samples_per_record must be a multiple of 32, and 256 minimum! # TODO check if it is 32 or 16, manual is unclear self.add_parameter(name='samples_per_record', parameter_class=AlazarParameter, label='Samples per Record', unit=None, value=1024, vals=validators.Multiples(divisor=16, min_value=16)) self.add_parameter(name='records_per_buffer', parameter_class=AlazarParameter, label='Records per Buffer', unit=None, value=10, vals=validators.Ints(min_value=0)) self.add_parameter(name='buffers_per_acquisition', parameter_class=AlazarParameter, label='Buffers per Acquisition', unit=None, value=10, vals=validators.Ints(min_value=0)) self.add_parameter(name='channel_selection', parameter_class=AlazarParameter, label='Channel Selection', unit=None, value='AB', byte_to_value_dict={ 1: 'A', 2: 'B', 3: 'AB', 4: 'C', 5: 'AC', 6: 'BC', 8: 'D', 9: 'AD', 10: 'BD', 12: 'CD', 15: 'ABCD' }) self.add_parameter(name='transfer_offset', parameter_class=AlazarParameter, label='Transer Offset', unit='Samples', value=0, vals=validators.Ints(min_value=0)) self.add_parameter(name='external_startcapture', parameter_class=AlazarParameter, label='External Startcapture', unit=None, value='enabled', byte_to_value_dict={ 0x0: 'disabled', 0x1: 'enabled' }) self.add_parameter(name='enable_record_headers', parameter_class=AlazarParameter, label='Enable Record Headers', unit=None, value='disabled', byte_to_value_dict={ 0x0: 'disabled', 0x8: 'enabled' }) self.add_parameter(name='alloc_buffers', parameter_class=AlazarParameter, label='Alloc Buffers', unit=None, value='disabled', byte_to_value_dict={ 0x0: 'disabled', 0x20: 'enabled' }) self.add_parameter(name='fifo_only_streaming', parameter_class=AlazarParameter, label='Fifo Only Streaming', unit=None, value='disabled', byte_to_value_dict={ 0x0: 'disabled', 0x800: 'enabled' }) self.add_parameter(name='interleave_samples', parameter_class=AlazarParameter, label='Interleave Samples', unit=None, value='disabled', byte_to_value_dict={ 0x0: 'disabled', 0x1000: 'enabled' }) self.add_parameter(name='get_processed_data', parameter_class=AlazarParameter, label='Get Processed Data', unit=None, value='disabled', byte_to_value_dict={ 0x0: 'disabled', 0x2000: 'enabled' }) self.add_parameter(name='allocated_buffers', parameter_class=AlazarParameter, label='Allocated Buffers', unit=None, value=2, vals=validators.Ints(min_value=0)) self.add_parameter(name='buffer_timeout', parameter_class=AlazarParameter, label='Buffer Timeout', unit='ms', value=1000, vals=validators.Ints(min_value=0))
def __init__(self, parent: 'B1517A', name: str, **kwargs: Any): super().__init__(parent, name, **kwargs) self._sweep_step_parameters: SweepSteps = \ {"sweep_mode": constants.SweepMode.LINEAR, "sweep_range": constants.VOutputRange.AUTO, "sweep_start": 0.0, "sweep_end": 0.0, "sweep_steps": 1, "current_compliance": None, "power_compliance": None} self.add_parameter(name='sweep_auto_abort', set_cmd=self._set_sweep_auto_abort, get_cmd=self._get_sweep_auto_abort, set_parser=constants.Abort, get_parser=constants.Abort, vals=vals.Enum(*list(constants.Abort)), initial_cache_value=constants.Abort.ENABLED, docstring=textwrap.dedent(""" The WM command enables or disables the automatic abort function for the staircase sweep sources and the pulsed sweep source. The automatic abort function stops the measurement when one of the following conditions occurs: - Compliance on the measurement channel - Compliance on the non-measurement channel - Overflow on the AD converter - Oscillation on any channel This command also sets the post measurement condition for the sweep sources. After the measurement is normally completed, the staircase sweep sources force the value specified by the post parameter, and the pulsed sweep source forces the pulse base value. If the measurement is stopped by the automatic abort function, the staircase sweep sources force the start value, and the pulsed sweep source forces the pulse base value after sweep. """)) self.add_parameter(name='post_sweep_voltage_condition', set_cmd=self._set_post_sweep_voltage_condition, get_cmd=self._get_post_sweep_voltage_condition, set_parser=constants.WM.Post, get_parser=constants.WM.Post, vals=vals.Enum(*list(constants.WM.Post)), initial_cache_value=constants.WM.Post.START, docstring=textwrap.dedent(""" Source output value after the measurement is normally completed. If this parameter is not set, the sweep sources force the start value. """)) self.add_parameter(name='hold_time', initial_value=0.0, vals=vals.Numbers(0, 655.35), unit='s', parameter_class=GroupParameter, docstring=textwrap.dedent(""" Hold time (in seconds) that is the wait time after starting measurement and before starting delay time for the first step 0 to 655.35 s, with 10 ms resolution. Numeric expression. """)) self.add_parameter(name='delay', initial_value=0.0, vals=vals.Numbers(0, 65.535), unit='s', parameter_class=GroupParameter, docstring=textwrap.dedent(""" Delay time (in seconds) that is the wait time after starting to force a step output and before starting a step measurement. 0 to 65.535 s, with 0.1 ms resolution. Numeric expression. """)) self.add_parameter(name='step_delay', initial_value=0.0, vals=vals.Numbers(0, 1), unit='s', parameter_class=GroupParameter, docstring=textwrap.dedent(""" Step delay time (in seconds) that is the wait time after starting a step measurement and before starting to force the next step output. 0 to 1 s, with 0.1 ms resolution. Numeric expression. If this parameter is not set, step delay will be 0. If step delay is shorter than the measurement time, the B1500 waits until the measurement completes, then forces the next step output. """)) self.add_parameter(name='trigger_delay', initial_value=0.0, unit='s', parameter_class=GroupParameter, docstring=textwrap.dedent(""" Step source trigger delay time (in seconds) that is the wait time after completing a step output setup and before sending a step output setup completion trigger. 0 to the value of ``delay`` s, with 0.1 ms resolution. If this parameter is not set, trigger delay will be 0. """)) self.add_parameter(name='measure_delay', initial_value=0.0, unit='s', vals=vals.Numbers(0, 65.535), parameter_class=GroupParameter, docstring=textwrap.dedent(""" Step measurement trigger delay time (in seconds) that is the wait time after receiving a start step measurement trigger and before starting a step measurement. 0 to 65.535 s, with 0.1 ms resolution. Numeric expression. If this parameter is not set, measure delay will be 0. """)) self._set_sweep_delays_group = Group( [ self.hold_time, self.delay, self.step_delay, self.trigger_delay, self.measure_delay ], set_cmd='WT ' '{hold_time},' '{delay},' '{step_delay},' '{trigger_delay},' '{measure_delay}', get_cmd=self._get_sweep_delays(), get_parser=self._get_sweep_delays_parser) self.add_parameter(name='sweep_mode', set_cmd=self._set_sweep_mode, get_cmd=self._get_sweep_mode, vals=vals.Enum(*list(constants.SweepMode)), set_parser=constants.SweepMode, snapshot_get=False, docstring=textwrap.dedent(""" Sweep mode. Note that Only linear sweep (mode=1 or 3) is available for the staircase sweep with pulsed bias. 1: Linear sweep (single stair, start to stop.) 2: Log sweep (single stair, start to stop.) 3: Linear sweep (double stair, start to stop to start.) 4: Log sweep (double stair, start to stop to start.) """)) self.add_parameter(name='sweep_range', set_cmd=self._set_sweep_range, get_cmd=self._get_sweep_range, vals=vals.Enum(*list(constants.VOutputRange)), set_parser=constants.VOutputRange, snapshot_get=False, docstring=textwrap.dedent(""" Ranging type for staircase sweep voltage output. Integer expression. See Table 4-4 on page 20. The B1500 usually uses the minimum range that covers both start and stop values to force the staircase sweep voltage. However, if you set `power_compliance` and if the following formulas are true, the B1500 uses the minimum range that covers the output value, and changes the output range dynamically (20 V range or above). Range changing may cause 0 V output in a moment. For the limited auto ranging, the instrument never uses the range less than the specified range. - Icomp > maximum current for the output range - Pcomp/output voltage > maximum current for the output range """)) self.add_parameter(name='sweep_start', set_cmd=self._set_sweep_start, get_cmd=self._get_sweep_start, unit='V', vals=vals.Numbers(-25, 25), snapshot_get=False, docstring=textwrap.dedent(""" Start value of the stair case sweep (in V). For the log sweep, start and stop must have the same polarity. """)) self.add_parameter(name='sweep_end', set_cmd=self._set_sweep_end, get_cmd=self._get_sweep_end, unit='V', vals=vals.Numbers(-25, 25), snapshot_get=False, docstring=textwrap.dedent(""" Stop value of the DC bias sweep (in V). For the log sweep,start and stop must have the same polarity. """)) self.add_parameter(name='sweep_steps', set_cmd=self._set_sweep_steps, get_cmd=self._get_sweep_steps, vals=vals.Ints(1, 1001), snapshot_get=False, docstring=textwrap.dedent(""" Number of steps for staircase sweep. Possible values from 1 to 1001""")) self.add_parameter(name='current_compliance', set_cmd=self._set_current_compliance, get_cmd=self._get_current_compliance, unit='A', vals=vals.Numbers(-40, 40), snapshot_get=False, docstring=textwrap.dedent(""" Current compliance (in A). Refer to Manual 2016. See Table 4-7 on page 24, Table 4-9 on page 26, Table 4-12 on page 27, or Table 4-15 on page 28 for each measurement resource type. If you do not set current_compliance, the previous value is used. Compliance polarity is automatically set to the same polarity as the output value, regardless of the specified Icomp. If the output value is 0, the compliance polarity is positive. If you set Pcomp, the maximum Icomp value for the measurement resource is allowed, regardless of the output range setting. """)) self.add_parameter(name='power_compliance', set_cmd=self._set_power_compliance, get_cmd=self._get_power_compliance, unit='W', vals=vals.Numbers(0.001, 80), snapshot_get=False, docstring=textwrap.dedent(""" Power compliance (in W). Resolution: 0.001 W. If it is not entered, the power compliance is not set. This parameter is not available for HVSMU. 0.001 to 2 for MPSMU/HRSMU, 0.001 to 20 for HPSMU, 0.001 to 40 for HCSMU, 0.001 to 80 for dual HCSMU, 0.001 to 3 for MCSMU, 0.001 to 100 for UHVU """))
def __init__(self, name, **kwargs): dll_path = 'C:\\WINDOWS\\System32\\ATSApi.dll' super().__init__(name, dll_path=dll_path, **kwargs) # add parameters # ----- Parameters for the configuration of the board ----- self.add_parameter(name='clock_source', parameter_class=AlazarParameter, label='Clock Source', unit=None, value='INTERNAL_CLOCK', byte_to_value_dict={ 1: 'INTERNAL_CLOCK', 4: 'SLOW_EXTERNAL_CLOCK', 5: 'EXTERNAL_CLOCK_AC', 7: 'EXTERNAL_CLOCK_10_MHz_REF' }) self.add_parameter(name='sample_rate', parameter_class=AlazarParameter, label='Sample Rate', unit='S/s', value=1000000000, byte_to_value_dict={ 0x1: 1000, 0x2: 2000, 0x4: 5000, 0x8: 10000, 0xA: 20000, 0xC: 50000, 0xE: 100000, 0x10: 200000, 0x12: 500000, 0x14: 1000000, 0x18: 2000000, 0x1A: 5000000, 0x1C: 10000000, 0x1E: 20000000, 0x22: 50000000, 0x24: 100000000, 0x2B: 250000000, 0x30: 500000000, 0x35: 1000000000, 0x40: 'EXTERNAL_CLOCK', 1000000000: '1GHz_REFERENCE_CLOCK' }) self.add_parameter(name='clock_edge', parameter_class=AlazarParameter, label='Clock Edge', unit=None, value='CLOCK_EDGE_RISING', byte_to_value_dict={ 0: 'CLOCK_EDGE_RISING', 1: 'CLOCK_EDGE_FALLING' }) self.add_parameter(name='decimation', parameter_class=AlazarParameter, label='Decimation', unit=None, value=0, vals=validators.Ints(0, 100000)) for i in ['1', '2']: self.add_parameter(name='coupling' + i, parameter_class=AlazarParameter, label='Coupling channel ' + i, unit=None, value='AC', byte_to_value_dict={ 1: 'AC', 2: 'DC' }) self.add_parameter(name='channel_range' + i, parameter_class=AlazarParameter, label='Range channel ' + i, unit='V', value=4, byte_to_value_dict={ 2: 0.04, 5: 0.1, 6: 0.2, 7: 0.4, 10: 1., 11: 2., 12: 4. }) self.add_parameter(name='impedance' + i, parameter_class=AlazarParameter, label='Impedance channel ' + i, unit='Ohm', value=50, byte_to_value_dict={ 1: 1000000, 2: 50 }) self.add_parameter(name='bwlimit' + i, parameter_class=AlazarParameter, label='Bandwidth limit channel ' + i, unit=None, value='DISABLED', byte_to_value_dict={ 0: 'DISABLED', 1: 'ENABLED' }) self.add_parameter(name='trigger_operation', parameter_class=AlazarParameter, label='Trigger Operation', unit=None, value='TRIG_ENGINE_OP_J', byte_to_value_dict={ 0: 'TRIG_ENGINE_OP_J', 1: 'TRIG_ENGINE_OP_K', 2: 'TRIG_ENGINE_OP_J_OR_K', 3: 'TRIG_ENGINE_OP_J_AND_K', 4: 'TRIG_ENGINE_OP_J_XOR_K', 5: 'TRIG_ENGINE_OP_J_AND_NOT_K', 6: 'TRIG_ENGINE_OP_NOT_J_AND_K' }) for i in ['1', '2']: self.add_parameter(name='trigger_engine' + i, parameter_class=AlazarParameter, label='Trigger Engine ' + i, unit=None, value='TRIG_ENGINE_' + ('J' if i == 0 else 'K'), byte_to_value_dict={ 0: 'TRIG_ENGINE_J', 1: 'TRIG_ENGINE_K' }) self.add_parameter(name='trigger_source' + i, parameter_class=AlazarParameter, label='Trigger Source ' + i, unit=None, value='DISABLE', byte_to_value_dict={ 0: 'CHANNEL_A', 1: 'CHANNEL_B', 2: 'EXTERNAL', 3: 'DISABLE' }) self.add_parameter(name='trigger_slope' + i, parameter_class=AlazarParameter, label='Trigger Slope ' + i, unit=None, value='TRIG_SLOPE_POSITIVE', byte_to_value_dict={ 1: 'TRIG_SLOPE_POSITIVE', 2: 'TRIG_SLOPE_NEGATIVE' }) self.add_parameter(name='trigger_level' + i, parameter_class=AlazarParameter, label='Trigger Level ' + i, unit=None, value=128, vals=validators.Ints(0, 255)) self.add_parameter(name='external_trigger_coupling', parameter_class=AlazarParameter, label='External Trigger Coupling', unit=None, value='AC', byte_to_value_dict={ 1: 'AC', 2: 'DC' }) self.add_parameter(name='external_trigger_range', parameter_class=AlazarParameter, label='External Trigger Range', unit=None, value='ETR_5V', byte_to_value_dict={ 0: 'ETR_5V', 1: 'ETR_1V' }) self.add_parameter(name='trigger_delay', parameter_class=AlazarParameter, label='Trigger Delay', unit='Sample clock cycles', value=0, vals=validators.Ints(min_value=0)) self.add_parameter(name='timeout_ticks', parameter_class=AlazarParameter, label='Timeout Ticks', unit='10 us', value=0, vals=validators.Ints(min_value=0)) # ----- Parameters for the acquire function ----- self.add_parameter(name='mode', parameter_class=AlazarParameter, label='Acquisiton mode', unit=None, value='NPT', byte_to_value_dict={ 0x200: 'NPT', 0x400: 'TS' }) # samples_per_record must be a multiple of of some number (64 in the # case of ATS9870) and and has some minimum (256 in the case of ATS9870) # These values can be found in the ATS-SDK programmar's guide self.add_parameter(name='samples_per_record', parameter_class=AlazarParameter, label='Samples per Record', unit=None, value=96000, vals=validators.Multiples(divisor=64, min_value=256)) # TODO(damazter) (M) figure out if this also has to be a multiple of # something, # I could not find this in the documentation but somehow I have the # feeling it still should be a multiple of something # NOTE by ramiro: At least in previous python implementations # (PycQED delft), this is an artifact for compatibility with # AWG sequencing, not particular to any ATS architecture. # ==> this is a construction imposed by the memory # strategy implemented on the python driver we # are writing, not limited by any actual ATS # feature. self.add_parameter(name='records_per_buffer', parameter_class=AlazarParameter, label='Records per Buffer', unit=None, value=1, vals=validators.Ints(min_value=0)) self.add_parameter(name='buffers_per_acquisition', parameter_class=AlazarParameter, label='Buffers per Acquisition', unit=None, value=1, vals=validators.Ints(min_value=0)) self.add_parameter(name='channel_selection', parameter_class=AlazarParameter, label='Channel Selection', unit=None, value='AB', byte_to_value_dict={ 1: 'A', 2: 'B', 3: 'AB' }) self.add_parameter(name='transfer_offset', parameter_class=AlazarParameter, label='Transer Offset', unit='Samples', value=0, vals=validators.Ints(min_value=0)) self.add_parameter(name='external_startcapture', parameter_class=AlazarParameter, label='External Startcapture', unit=None, value='ENABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x1: 'ENABLED' }) self.add_parameter(name='enable_record_headers', parameter_class=AlazarParameter, label='Enable Record Headers', unit=None, value='DISABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x8: 'ENABLED' }) self.add_parameter(name='alloc_buffers', parameter_class=AlazarParameter, label='Alloc Buffers', unit=None, value='DISABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x20: 'ENABLED' }) self.add_parameter(name='fifo_only_streaming', parameter_class=AlazarParameter, label='Fifo Only Streaming', unit=None, value='DISABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x800: 'ENABLED' }) self.add_parameter(name='interleave_samples', parameter_class=AlazarParameter, label='Interleave Samples', unit=None, value='DISABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x1000: 'ENABLED' }) self.add_parameter(name='get_processed_data', parameter_class=AlazarParameter, label='Get Processed Data', unit=None, value='DISABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x2000: 'ENABLED' }) self.add_parameter(name='allocated_buffers', parameter_class=AlazarParameter, label='Allocated Buffers', unit=None, value=1, vals=validators.Ints(min_value=0)) self.add_parameter(name='buffer_timeout', parameter_class=AlazarParameter, label='Buffer Timeout', unit='ms', value=1000, vals=validators.Ints(min_value=0)) model = self.get_idn()['model'] if model != 'ATS9870': raise Exception("The Alazar board kind is not 'ATS9870'," " found '" + str(model) + "' instead.")
def __init__(self, name: str, address: str, **kwargs): super().__init__(name, address, terminator='\n', **kwargs) self.range_vals = { 2e-3: 0, 20e-3: 1, 200e-3: 2, 2: 3, 20: 4, 200: 5, 2e3: 6, 20e3: 7, 200e3: 8, 2e6: 9, np.nan: np.nan } self.excitation_vals = { 20e-6: 0, 60e-6: 1, 200e-6: 2, 600e-6: 3, 2e-3: 4, 6e-3: 5, 20e-3: 6, np.nan: np.nan } self.dfilter_vals = { 0.2: '00', 0.4: '01', 0.6: '02', 0.8: '03', 1.0: '04', 1.6: '05', 2.0: '06', 3.0: '07', 5.0: '08', 7.0: '09', 10.0: '10', 15.0: '11', 20.0: '12', 30.0: '13', 45.0: '14', 60.0: '15', 90.0: '16', 120.0: '17', 180.0: '18', 300.0: '19', 420.0: '20', 600.0: '21', 900.0: '22', 1200.0: '23', 1800.0: '24', np.nan: np.nan } self.afilter_vals = { 0.01: 0, 0.1: 1, 0.3: 2, 1.0: 3, 3.0: 4, 10.0: 5, 30.0: 6 } self.add_parameter('range', set_cmd='Range {}', val_mapping=self.range_vals, get_cmd=partial(self.get_string_repeat, 'Get 6'), get_parser=partial(self.get6parser, 'range'), unit='Ohms') self.add_parameter('autorange', set_cmd='Autorange {}', vals=vals.Ints(0, 1)) self.add_parameter('excitation', set_cmd='Excitation {}', get_cmd=partial(self.get_string_repeat, 'Get 6'), get_parser=partial(self.get6parser, 'excitation'), val_mapping=self.excitation_vals, unit='V') self.add_parameter('exc_pct', set_cmd='Varexc ={}', set_parser=partial(zfill_parser, 2), get_cmd=partial(self.get_string_repeat, 'Get 6'), get_parser=partial(self.get6parser, 'exc_pct'), vals=vals.Ints(5, 99)) self.add_parameter('exc_pct_on', set_cmd='Varexc {}', vals=vals.Ints(0, 1)) self.add_parameter('R_measure', get_cmd=partial(self.get_string_repeat, 'Get 0'), unit='Ohms', get_parser=R_parser) self.add_parameter('DelR_measure', get_cmd=partial(self.get_string_repeat, 'Get 2'), get_parser=R_parser, unit='Ohms') self.add_parameter('X_measure', get_cmd=partial(self.get_string_repeat, 'Get 1'), get_parser=R_parser) self.add_parameter('DelX_measure', get_cmd=partial(self.get_string_repeat, 'Get 3'), get_parser=R_parser) self.add_parameter('x10mode', set_cmd='Mode {}', get_cmd=partial(self.get_string_repeat, 'Get 6'), get_parser=partial(self.get6parser, 'x10mode'), vals=vals.Ints(0, 1)) self.add_parameter('dfilter', set_cmd=self.dfilter_set, get_cmd=partial(self.get_string_repeat, 'Get 6'), get_parser=partial(self.get6parser, 'dfilter'), val_mapping=self.dfilter_vals, unit='s') self.add_parameter('afilter', set_cmd='Noise F={}', val_mapping=self.afilter_vals, unit='s') self.add_parameter('afilter_input', set_cmd='Noise I={}', val_mapping={ 'delR': 0, 'delX': 1 }) self.add_parameter('R_offset', label='LR Resistance', set_cmd='Offset {}', set_parser=partial(offset_parser, 'R'), get_cmd=partial(self.get_string_repeat, 'Get 4'), get_parser=R_parser, unit='Ohms', vals=vals.MultiType(vals.Numbers(-99.9995, 99.9995), vals.Enum('R', 'X'))) self.add_parameter('X_offset', set_cmd='Offset {}', set_parser=partial(offset_parser, 'X'), get_cmd=partial(self.get_string_repeat, 'Get 5'), get_parser=R_parser, vals=vals.MultiType(vals.Numbers(-99.9995, 99.9995), vals.Enum('R', 'X')))
def __init__(self, instrument_name, **kwargs): super().__init__(instrument_name, **kwargs) self.pulse_sequence.allow_targeted_pulses = True self.pulse_sequence.allow_untargeted_pulses = False self.pulse_sequence.allow_pulse_overlap = False self._clk_freq = int(100e6) self.pulse_implementations = [ TriggerPulseImplementation(pulse_requirements=[]) ] self._data_channels = { f'trace_{k}': Channel(instrument_name=self.instrument_name(), name=f'trace_{k}', id=k, output=False, input=True) for k in range(8) } self._pxi_channels = { 'pxi{}'.format(k): Channel(instrument_name=self.instrument_name(), name='pxi{}'.format(k), id=4000 + k, input_trigger=True, output=True, input=True) for k in range(8) } self._channels = { **self._data_channels, **self._pxi_channels, } self.add_parameter('blip_threshold', parameter_class=ManualParameter, vals=vals.Numbers(-3, 3), unit='V', docstring='The blip threshold in volts.') self.add_parameter( 'full_scale_range', parameter_class=ManualParameter, vals=vals.Numbers(-3, 3), unit='V', docstring='The full scale range of the trace channel in volts.') self.add_parameter( 'update_time', parameter_class=ManualParameter, vals=vals.Numbers(), unit='s', docstring= 'The length of time in seconds after a blip required to perform the ' 'Bayesian update.') self.add_parameter( 'timeout', parameter_class=ManualParameter, vals=vals.Numbers(), unit='s', docstring= 'The duration since the Bayesian update starts from where you cancel the ' 'Bayesian update and continue with the experiment.') self.add_parameter( 'trace_select', parameter_class=ManualParameter, vals=vals.Ints(0, 7), docstring='The channel you want to select from 0 to 7.') self.add_parameter( 'pxi_channel', parameter_class=ManualParameter, vals=vals.Ints(4000, 4007), docstring='The PXI channel the trigger will be output on.')
def __init__(self, parent: Instrument, name: str, channum: int) -> None: """ Args: parent: The instrument to which the channel is attached name: The name of the channel channum: The number of the channel in question. Must match the actual number as used by the instrument (1..4) """ if channum not in [1, 2, 3, 4]: raise ValueError('Invalid channel number! Must be 1, 2, 3, or 4.') self.channum = channum super().__init__(parent, name) self.add_parameter('state', label=f'Channel {channum} state', get_cmd=f'CHANnel{channum}:STATe?', set_cmd=f'CHANnel{channum}:STATE {{}}', vals=vals.Enum('ON', 'OFF'), docstring='Switches the channel on or off') self.add_parameter('coupling', label=f'Channel {channum} coupling', get_cmd=f'CHANnel{channum}:COUPling?', set_cmd=f'CHANnel{channum}:COUPling {{}}', vals=vals.Enum('DC', 'DCLimit', 'AC'), docstring=('Selects the connection of the channel' 'signal. DC: 50 Ohm, DCLimit 1 MOhm, ' 'AC: Con. through DC capacitor')) self.add_parameter('ground', label=f'Channel {channum} ground', get_cmd=f'CHANnel{channum}:GND?', set_cmd=f'CHANnel{channum}:GND {{}}', vals=vals.Enum('ON', 'OFF'), docstring=('Connects/disconnects the signal to/from' 'the ground.')) # NB (WilliamHPNielsen): This parameter depends on other parameters and # should be dynamically updated accordingly. Cf. p 1178 of the manual self.add_parameter( 'scale', label=f'Channel {channum} Y scale', unit='V/div', get_cmd=f'CHANnel{channum}:SCALe?', set_cmd=self._set_scale, get_parser=float, ) self.add_parameter('range', label=f'Channel {channum} Y range', unit='V', get_cmd=f'CHANnel{channum}:RANGe?', set_cmd=self._set_range, get_parser=float) # TODO (WilliamHPNielsen): would it be better to recast this in terms # of Volts? self.add_parameter('position', label=f'Channel {channum} vert. pos.', unit='div', get_cmd=f'CHANnel{channum}:POSition?', set_cmd=f'CHANnel{channum}:POSition {{}}', get_parser=float, vals=vals.Numbers(-5, 5), docstring=('Positive values move the waveform up,' ' negative values move it down.')) self.add_parameter( 'offset', label=f'Channel {channum} offset', unit='V', get_cmd=f'CHANnel{channum}:OFFSet?', set_cmd=f'CHANnel{channum}:OFFSet {{}}', get_parser=float, ) self.add_parameter('invert', label=f'Channel {channum} inverted', get_cmd=f'CHANnel{channum}:INVert?', set_cmd=f'CHANnel{channum}:INVert {{}}', vals=vals.Enum('ON', 'OFF')) # TODO (WilliamHPNielsen): This parameter should be dynamically # validated since 800 MHz BW is only available for 50 Ohm coupling self.add_parameter('bandwidth', label=f'Channel {channum} bandwidth', get_cmd=f'CHANnel{channum}:BANDwidth?', set_cmd=f'CHANnel{channum}:BANDwidth {{}}', vals=vals.Enum('FULL', 'B800', 'B200', 'B20')) self.add_parameter('impedance', label=f'Channel {channum} impedance', unit='Ohm', get_cmd=f'CHANnel{channum}:IMPedance?', set_cmd=f'CHANnel{channum}:IMPedance {{}}', vals=vals.Ints(1, 100000), docstring=('Sets the impedance of the channel ' 'for power calculations and ' 'measurements.')) self.add_parameter('overload', label=f'Channel {channum} overload', get_cmd=f'CHANnel{channum}:OVERload?') self.add_parameter('arithmetics', label=f'Channel {channum} arithmetics', set_cmd=f'CHANnel{channum}:ARIThmetics {{}}', get_cmd=f'CHANnel{channum}:ARIThmetics?', val_mapping={ 'AVERAGE': 'AVER', 'OFF': 'OFF', 'ENVELOPE': 'ENV' }) self.add_parameter('trace', channum=self.channum, parameter_class=ScopeTrace) self._trace_ready = False
def __init__(self, name, **kw): super().__init__(name, **kw) self.add_parameter('channel', initial_value=1, vals=vals.Ints(), parameter_class=ManualParameter) self.add_parameter( 'kernel_list', initial_value=[], vals=vals.Lists(vals.Strings()), parameter_class=ConfigParameter, docstring='List of filenames of external kernels to be loaded') self.add_parameter('kernel_dir', initial_value='kernels/', vals=vals.Strings(), parameter_class=ManualParameter, docstring='Path for loading external kernels,' + 'such as room temperature correction kernels.') self.add_parameter('config_changed', vals=vals.Bool(), get_cmd=self._get_config_changed) self.add_parameter( 'kernel', vals=vals.Arrays(), get_cmd=self._get_kernel, docstring=('Returns the predistortion kernel. \n' + 'Recalculates if the parameters changed,\n' + 'otherwise returns a precalculated kernel.\n' + 'Kernel is based on parameters in kernel object \n' + 'and files specified in the kernel list.')) self.add_parameter('skineffect_alpha', unit='', parameter_class=ConfigParameter, initial_value=0, vals=vals.Numbers()) self.add_parameter('skineffect_length', unit='s', parameter_class=ConfigParameter, initial_value=600e-9, vals=vals.Numbers()) self.add_parameter('decay_amp_1', unit='', initial_value=0, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('decay_tau_1', unit='s', initial_value=1e-9, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('decay_length_1', unit='s', initial_value=100e-9, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('decay_amp_2', unit='', initial_value=0, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('decay_tau_2', unit='s', initial_value=1e-9, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('decay_length_2', unit='s', initial_value=100e-9, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('bounce_amp_1', unit='', initial_value=0, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('bounce_tau_1', unit='s', initial_value=0, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('bounce_length_1', unit='s', initial_value=1e-9, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('bounce_amp_2', unit='', initial_value=0, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('bounce_tau_2', unit='s', initial_value=0, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('bounce_length_2', unit='s', initial_value=1e-9, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('poly_a', unit='', initial_value=0, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('poly_b', unit='', initial_value=0, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('poly_c', unit='', initial_value=1, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('poly_length', unit='s', initial_value=600e-9, parameter_class=ConfigParameter, vals=vals.Numbers()) self.add_parameter('corrections_length', unit='s', parameter_class=ConfigParameter, initial_value=10e-6, vals=vals.Numbers()) self.add_parameter('sampling_rate', parameter_class=ManualParameter, initial_value=1e9, vals=vals.Numbers())
def __init__(self, name: str, address: str, model: Optional[str] = None, timeout: float = 5., HD: bool = True, terminator: str = '\n', **kwargs: Any) -> None: """ Args: name: name of the instrument address: VISA resource address model: The instrument model. For newer firmware versions, this can be auto-detected timeout: The VISA query timeout HD: Does the unit have the High Definition Option (allowing 16 bit vertical resolution) terminator: Command termination character to strip from VISA commands. """ super().__init__(name=name, address=address, timeout=timeout, terminator=terminator, **kwargs) # With firmware versions earlier than 3.65, it seems that the # model number can NOT be queried from the instrument # (at least fails with RTO1024, fw 2.52.1.1), so in that case # the user must provide the model manually. firmware_version = self.get_idn()['firmware'] if LooseVersion(firmware_version) < LooseVersion('3'): log.warning('Old firmware version detected. This driver may ' 'not be compatible. Please upgrade your firmware.') if LooseVersion(firmware_version) >= LooseVersion('3.65'): # strip just in case there is a newline character at the end self.model = self.ask('DIAGnostic:SERVice:WFAModel?').strip() if model is not None and model != self.model: warnings.warn("The model number provided by the user " "does not match the instrument's response." " I am going to assume that this oscilloscope " f"is a model {self.model}") else: if model is None: raise ValueError('No model number provided. Please provide ' 'a model number (eg. "RTO1024").') else: self.model = model self.HD = HD # Now assign model-specific values self.num_chans = int(self.model[-1]) self.num_meas = 8 self._horisontal_divs = int(self.ask('TIMebase:DIVisions?')) self.add_parameter('display', label='Display state', set_cmd='SYSTem:DISPlay:UPDate {}', val_mapping={ 'remote': 0, 'view': 1 }) # Triggering self.add_parameter('trigger_display', label='Trigger display state', set_cmd='DISPlay:TRIGger:LINes {}', get_cmd='DISPlay:TRIGger:LINes?', val_mapping={ 'ON': 1, 'OFF': 0 }) # TODO: (WilliamHPNielsen) There are more available trigger # settings than implemented here. See p. 1261 of the manual # here we just use trigger1, which is the A-trigger self.add_parameter('trigger_source', label='Trigger source', set_cmd='TRIGger1:SOURce {}', get_cmd='TRIGger1:SOURce?', val_mapping={ 'CH1': 'CHAN1', 'CH2': 'CHAN2', 'CH3': 'CHAN3', 'CH4': 'CHAN4', 'EXT': 'EXT' }) self.add_parameter('trigger_mode', label='Trigger mode', set_cmd='TRIGger:MODE {}', get_cmd='TRIGger1:SOURce?', vals=vals.Enum('AUTO', 'NORMAL', 'FREERUN'), docstring='Sets the trigger mode which determines' ' the behaviour of the instrument if no' ' trigger occurs.\n' 'Options: AUTO, NORMAL, FREERUN.', unit='none') self.add_parameter('trigger_type', label='Trigger type', set_cmd='TRIGger1:TYPE {}', get_cmd='TRIGger1:TYPE?', val_mapping={ 'EDGE': 'EDGE', 'GLITCH': 'GLIT', 'WIDTH': 'WIDT', 'RUNT': 'RUNT', 'WINDOW': 'WIND', 'TIMEOUT': 'TIM', 'INTERVAL': 'INT', 'SLEWRATE': 'SLEW', 'DATATOCLOCK': 'DAT', 'STATE': 'STAT', 'PATTERN': 'PATT', 'ANEDGE': 'ANED', 'SERPATTERN': 'SERP', 'NFC': 'NFC', 'TV': 'TV', 'CDR': 'CDR' }) # See manual p. 1262 for an explanation of trigger types self.add_parameter('trigger_level', label='Trigger level', set_cmd=self._set_trigger_level, get_cmd=self._get_trigger_level) self.add_parameter('trigger_edge_slope', label='Edge trigger slope', set_cmd='TRIGger1:EDGE:SLOPe {}', get_cmd='TRIGger1:EDGE:SLOPe?', vals=vals.Enum('POS', 'NEG', 'EITH')) # Horizontal settings self.add_parameter('timebase_scale', label='Timebase scale', set_cmd=self._set_timebase_scale, get_cmd='TIMebase:SCALe?', unit='s/div', get_parser=float, vals=vals.Numbers(25e-12, 10000)) self.add_parameter('timebase_range', label='Timebase range', set_cmd=self._set_timebase_range, get_cmd='TIMebase:RANGe?', unit='s', get_parser=float, vals=vals.Numbers(250e-12, 100e3)) self.add_parameter('timebase_position', label='Horizontal position', set_cmd=self._set_timebase_position, get_cmd='TIMEbase:HORizontal:POSition?', get_parser=float, unit='s', vals=vals.Numbers(-100e24, 100e24)) # Acquisition # I couldn't find a way to query the run mode, so we manually keep # track of it. It is very important when getting the trace to make # sense of completed_acquisitions. self.add_parameter('run_mode', label='Run/acquisition mode of the scope', get_cmd=None, set_cmd=None) self.run_mode('RUN CONT') self.add_parameter('num_acquisitions', label='Number of single acquisitions to perform', get_cmd='ACQuire:COUNt?', set_cmd='ACQuire:COUNt {}', vals=vals.Ints(1, 16777215), get_parser=int) self.add_parameter('completed_acquisitions', label='Number of completed acquisitions', get_cmd='ACQuire:CURRent?', get_parser=int) self.add_parameter('sampling_rate', label='Sample rate', docstring='Number of averages for measuring ' 'trace.', unit='Sa/s', get_cmd='ACQuire:POINts:ARATe' + '?', get_parser=int) self.add_parameter('acquisition_sample_rate', label='Acquisition sample rate', unit='Sa/s', docstring='recorded waveform samples per second', get_cmd='ACQuire:SRATe' + '?', set_cmd='ACQuire:SRATe ' + ' {:.2f}', vals=vals.Numbers(2, 20e12), get_parser=float) # Data self.add_parameter('dataformat', label='Export data format', set_cmd='FORMat:DATA {}', get_cmd='FORMat:DATA?', vals=vals.Enum('ASC,0', 'REAL,32', 'INT,8', 'INT,16')) # High definition mode (might not be available on all instruments) if HD: self.add_parameter('high_definition_state', label='High definition (16 bit) state', set_cmd=self._set_hd_mode, get_cmd='HDEFinition:STAte?', val_mapping=create_on_off_val_mapping( on_val=1, off_val=0), docstring='Sets the filter bandwidth for the' ' high definition mode.\n' 'ON: high definition mode, up to 16' ' bit digital resolution\n' 'Options: ON, OFF\n\n' 'Warning/Bug: By opening the HD ' 'acquisition menu on the scope, ' 'this value will be set to "ON".') self.add_parameter('high_definition_bandwidth', label='High definition mode bandwidth', set_cmd='HDEFinition:BWIDth {}', get_cmd='HDEFinition:BWIDth?', unit='Hz', get_parser=float, vals=vals.Numbers(1e4, 1e9)) self.add_parameter('error_count', label='Number of errors in the error stack', get_cmd='SYSTem:ERRor:COUNt?', unit='#', get_parser=int) self.add_parameter('error_next', label='Next error from the error stack', get_cmd='SYSTem:ERRor:NEXT?', get_parser=str) # Add the channels to the instrument for ch in range(1, self.num_chans + 1): chan = ScopeChannel(self, f'channel{ch}', ch) self.add_submodule(f'ch{ch}', chan) for measId in range(1, self.num_meas + 1): measCh = ScopeMeasurement(self, f'measurement{measId}', measId) self.add_submodule(f'meas{measId}', measCh) self.add_function('stop', call_cmd='STOP') self.add_function('reset', call_cmd='*RST') self.add_parameter('opc', get_cmd='*OPC?') self.add_parameter('stop_opc', get_cmd='STOP;*OPC?') self.add_parameter('status_operation', get_cmd='STATus:OPERation:CONDition?', get_parser=int) self.add_function('run_continues', call_cmd='RUNContinous') # starts the shutdown of the system self.add_function('system_shutdown', call_cmd='SYSTem:EXIT') self.connect_message()
def __init__(self, name: str, address: str, update_currents: bool = False, **kwargs: Any): """ Instantiates the instrument. Args: name: The instrument name used by qcodes address: The VISA name of the resource update_currents: Whether to query all channels for their current sensor value on startup, which takes about 0.5 sec per channel. Default: False. Returns: QDac object """ super().__init__(name, address, **kwargs) handle = self.visa_handle self._get_status_performed = False assert isinstance(handle, SerialInstrument) # Communication setup + firmware check handle.baud_rate = 480600 handle.parity = visa.constants.Parity(0) handle.data_bits = 8 self.set_terminator('\n') handle.write_termination = '\n' self._write_response = '' firmware_version = self._get_firmware_version() if firmware_version < 1.07: LOG.warning(f"Firmware version: {firmware_version}") raise RuntimeError(''' No QDevil QDAC detected or the firmware version is obsolete. This driver only supports version 1.07 or newer. Please contact [email protected] for a firmware update. ''') # Initialse basic information and internal book keeping self.num_chans = self._get_number_of_channels() num_boards = int(self.num_chans/8) self._output_n_lines = self.num_chans + 2 self._chan_range = range(1, 1 + self.num_chans) self.channel_validator = vals.Ints(1, self.num_chans) self._reset_bookkeeping() # Add channels (and channel parameters) channels = ChannelList(self, "Channels", QDacChannel, snapshotable=False, multichan_paramclass=QDacMultiChannelParameter) for i in self._chan_range: channel = QDacChannel(self, f'chan{i:02}', i) channels.append(channel) self.add_submodule(f"ch{i:02}", channel) self.add_submodule("channels", channels.to_channel_tuple()) # Updatechannel sync port validator according to number of boards self._num_syns = max(num_boards-1, 1) for chan in self._chan_range: self.channels[chan-1].sync.vals = vals.Ints(0, self._num_syns) # Add non-channel parameters for board in range(num_boards): for sensor in range(3): label = f'Board {board}, Temperature {sensor}' self.add_parameter(name=f'temp{board}_{sensor}', label=label, unit='C', get_cmd=f'tem {board} {sensor}', get_parser=self._num_verbose) self.add_parameter(name='cal', set_cmd='cal {}', vals=vals.Ints(0, self.num_chans)) self.add_parameter(name='mode_force', label='Mode force', get_cmd=None, set_cmd=None, vals=vals.Bool(), initial_value=False) # Due to a firmware bug in 1.07 voltage ranges are always reported # vebosely. So for future compatibility we set verbose True self.write('ver 1') self._update_voltage_ranges() # The driver require verbose mode off except for the above command self.write('ver 0') self._verbose = False # Just so that the code can check the state self.connect_message() LOG.info('[*] Querying all channels for voltages and currents...') self._update_cache(update_currents=update_currents) self._update_currents = update_currents self._load_state() LOG.info('[+] Done')
def __init__( self, parent: "ZNB", name: str, channel: int, vna_parameter: Optional[str] = None, existing_trace_to_bind_to: Optional[str] = None, ) -> None: """ Args: parent: Instrument that this channel is bound to. name: Name to use for this channel. channel: channel on the VNA to use vna_parameter: Name of parameter on the vna that this should measure such as S12. If left empty this will fall back to `name`. existing_trace_to_bind_to: Name of an existing trace on the VNA. If supplied try to bind to an existing trace with this name rather than creating a new trace. """ n = channel self._instrument_channel = channel # Additional wait when adjusting instrument timeout to sweep time. self._additional_wait = 1 if vna_parameter is None: vna_parameter = name self._vna_parameter = vna_parameter super().__init__(parent, name) if existing_trace_to_bind_to is None: self._tracename = f"Trc{channel}" else: traces = self._parent.ask("CONFigure:TRACe:CATalog?") if existing_trace_to_bind_to not in traces: raise RuntimeError(f"Trying to bind to" f" {existing_trace_to_bind_to} " f"which is not in {traces}") self._tracename = existing_trace_to_bind_to # map hardware channel to measurement # hardware channels are mapped one to one to QCoDeS channels # we are not using sub traces within channels. if existing_trace_to_bind_to is None: self.write(f"CALC{self._instrument_channel}:PAR:SDEF" f" '{self._tracename}', '{self._vna_parameter}'") # Source power is dependent on model, but not well documented. # Here we assume -60 dBm for ZNB20, the others are set, # due to lack of knowledge, to -80 dBm as of before the edit. full_modelname = self._parent.get_idn()["model"] if full_modelname is not None: model = full_modelname.split("-")[0] else: raise RuntimeError("Could not determine ZNB model") self._model_min_source_power = { "ZNB4": -80, "ZNB8": -80, "ZNB20": -60, "ZNB40": -60, } if model not in self._model_min_source_power.keys(): raise RuntimeError(f"Unsupported ZNB model: {model}") self._min_source_power: float self._min_source_power = self._model_min_source_power[model] self.add_parameter( name="vna_parameter", label="VNA parameter", get_cmd=f"CALC{self._instrument_channel}:PAR:MEAS? " f"'{self._tracename}'", get_parser=self._strip, ) self.add_parameter( name="power", label="Power", unit="dBm", get_cmd=f"SOUR{n}:POW?", set_cmd=f"SOUR{n}:POW {{:.4f}}", get_parser=float, vals=vals.Numbers(self._min_source_power, 25), ) self.add_parameter( name="bandwidth", label="Bandwidth", unit="Hz", get_cmd=f"SENS{n}:BAND?", set_cmd=self._set_bandwidth, get_parser=int, vals=vals.Enum(*np.append( 10**6, np.kron([1, 1.5, 2, 3, 5, 7], 10**np.arange(6)))), docstring="Measurement bandwidth of the IF filter. " "The inverse of this sets the integration " "time per point. " "There is an 'increased bandwidth option' " "(p. 4 of manual) that does not get taken " "into account here.", ) self.add_parameter( name="avg", label="Averages", unit="", get_cmd=f"SENS{n}:AVER:COUN?", set_cmd=f"SENS{n}:AVER:COUN {{:.4f}}", get_parser=int, vals=vals.Ints(1, 5000), ) self.add_parameter( name="start", get_cmd=f"SENS{n}:FREQ:START?", set_cmd=self._set_start, get_parser=float, vals=vals.Numbers(self._parent._min_freq, self._parent._max_freq - 10), ) self.add_parameter( name="stop", get_cmd=f"SENS{n}:FREQ:STOP?", set_cmd=self._set_stop, get_parser=float, vals=vals.Numbers(self._parent._min_freq + 1, self._parent._max_freq), ) self.add_parameter( name="center", get_cmd=f"SENS{n}:FREQ:CENT?", set_cmd=self._set_center, get_parser=float, vals=vals.Numbers(self._parent._min_freq + 0.5, self._parent._max_freq - 10), ) self.add_parameter( name="span", get_cmd=f"SENS{n}:FREQ:SPAN?", set_cmd=self._set_span, get_parser=float, vals=vals.Numbers(1, self._parent._max_freq - self._parent._min_freq), ) self.add_parameter( name="npts", get_cmd=f"SENS{n}:SWE:POIN?", set_cmd=self._set_npts, get_parser=int, ) self.add_parameter( name="status", get_cmd=f"CONF:CHAN{n}:MEAS?", set_cmd=f"CONF:CHAN{n}:MEAS {{}}", get_parser=int, ) self.add_parameter( name="format", get_cmd=partial(self._get_format, tracename=self._tracename), set_cmd=self._set_format, val_mapping={ "dB": "MLOG\n", "Linear Magnitude": "MLIN\n", "Phase": "PHAS\n", "Unwr Phase": "UPH\n", "Polar": "POL\n", "Smith": "SMIT\n", "Inverse Smith": "ISM\n", "SWR": "SWR\n", "Real": "REAL\n", "Imaginary": "IMAG\n", "Delay": "GDEL\n", "Complex": "COMP\n", }, ) self.add_parameter( name="trace_mag_phase", start=self.start(), stop=self.stop(), npts=self.npts(), channel=n, parameter_class=FrequencySweepMagPhase, ) self.add_parameter( name="trace", start=self.start(), stop=self.stop(), npts=self.npts(), channel=n, parameter_class=FrequencySweep, ) self.add_parameter( name="electrical_delay", label="Electrical delay", get_cmd=f"SENS{n}:CORR:EDEL2:TIME?", set_cmd=f"SENS{n}:CORR:EDEL2:TIME {{}}", get_parser=float, unit="s", ) self.add_parameter( name="sweep_time", label="Sweep time", get_cmd=f"SENS{n}:SWE:TIME?", get_parser=float, unit="s", ) self.add_parameter( name="sweep_type", get_cmd=f"SENS{n}:SWE:TYPE?", set_cmd=self._set_sweep_type, val_mapping={ "Linear": "LIN\n", "Logarithmic": "LOG\n", "Power": "POW\n", "CW_Time": "CW\n", "CW_Point": "POIN\n", "Segmented": "SEGM\n", }, docstring="The sweep_type parameter is used to set " "the type of measurement sweeps. It " "allows switching the default linear " "VNA sweep type to other types. Note that " "at the moment only the linear and " "CW_Point modes have supporting " "measurement parameters.", ) self.add_parameter( name="cw_frequency", get_cmd=f"SENS{n}:FREQ:CW?", set_cmd=self._set_cw_frequency, get_parser=float, vals=vals.Numbers(self._parent._min_freq + 0.5, self._parent._max_freq - 10), docstring="Parameter for setting frequency and " "querying for it when VNA sweep type is " "set to CW_Point mode.", ) self.add_parameter( "cw_check_sweep_first", parameter_class=ManualParameter, initial_value=True, vals=vals.Bool(), docstring="Parameter that enables a few commands " "which are called before each get in " "continuous wave mode checking whether " "the vna is setup correctly. Is recommended " "to be turned, but can be turned off if " "one wants to minimize overhead in fast " "measurements. ", ) self.add_parameter( name="trace_fixed_frequency", npts=self.npts(), bandwidth=self.bandwidth(), parameter_class=FixedFrequencyTraceIQ, ) self.add_parameter(name="point_fixed_frequency", parameter_class=FixedFrequencyPointIQ) self.add_parameter( name="point_fixed_frequency_mag_phase", parameter_class=FixedFrequencyPointMagPhase, ) self.add_parameter( name="averaging_enabled", initial_value=False, get_cmd=None, set_cmd=self._enable_averaging, vals=vals.Bool(), val_mapping=create_on_off_val_mapping(on_val="ON", off_val="OFF"), ) self.add_parameter( name="auto_sweep_time_enabled", initial_value=False, get_cmd=None, set_cmd=self._enable_auto_sweep_time, vals=vals.Bool(), val_mapping=create_on_off_val_mapping(on_val="ON", off_val="OFF"), docstring="When enabled, the (minimum) sweep time is " "calculated internally using the other channel settings " "and zero delay", ) self.add_function("set_electrical_delay_auto", call_cmd=f"SENS{n}:CORR:EDEL:AUTO ONCE") self.add_function( "autoscale", call_cmd=f"DISPlay:TRACe1:Y:SCALe:AUTO ONCE, {self._tracename}", )
def __init__(self, parent: "QDac", name: str, channum: int): """ Args: parent: The instrument to which the channel belongs. name: The name of the channel channum: The number of the channel (1-24 or 1-48) """ super().__init__(parent, name) # Add the parameters self.add_parameter(name='v', label=f'Channel {channum} voltage', unit='V', set_cmd=partial(self._parent._set_voltage, channum), get_cmd=f'set {channum}', get_parser=float, # Initial range. Updated on init and during # operation: vals=vals.Numbers(-9.99, 9.99) ) self.add_parameter(name='mode', label=f'Channel {channum} mode.', set_cmd=partial(self._parent._set_mode, channum), get_cmd=None, vals=vals.Enum(*list(Mode)) ) self.add_parameter(name='i', label=f'Channel {channum} current', get_cmd=f'get {channum}', unit='A', get_parser=self._parent._current_parser ) self.add_parameter(name='slope', label=f'Channel {channum} slope', unit='V/s', set_cmd=partial(self._parent._setslope, channum), get_cmd=partial(self._parent._getslope, channum), vals=vals.MultiType(vals.Enum('Inf'), vals.Numbers(1e-3, 10000)) ) self.add_parameter(name='sync', label=f'Channel {channum} sync output', set_cmd=partial(self._parent._setsync, channum), get_cmd=partial(self._parent._getsync, channum), vals=vals.Ints(0, 4) # Updated at qdac init ) self.add_parameter(name='sync_delay', label=f'Channel {channum} sync pulse delay', unit='s', get_cmd=None, set_cmd=None, vals=vals.Numbers(0, 10000), initial_value=0 ) self.add_parameter( name='sync_duration', label=f'Channel {channum} sync pulse duration', unit='s', get_cmd=None, set_cmd=None, vals=vals.Numbers(0.001, 10000), initial_value=0.01 )
def __init__(self, name, address, num_chans=48, update_currents=True, **kwargs): """ Instantiates the instrument. Args: name (str): The instrument name used by qcodes address (str): The VISA name of the resource num_chans (int): Number of channels to assign. Default: 48 update_currents (bool): Whether to query all channels for their current current value on startup. Default: True. Returns: QDac object """ super().__init__(name, address, **kwargs) self._output_n_lines = 50 handle = self.visa_handle self._get_status_performed = False # This is the baud rate on power-up. It can be changed later but # you must start out with this value. handle.baud_rate = 480600 handle.parity = visa.constants.Parity(0) handle.data_bits = 8 self.set_terminator('\n') # TODO: do we want a method for write termination too? handle.write_termination = '\n' # TODO: do we need a query delay for robust operation? self._write_response = '' if self._get_firmware_version() < 0.170202: raise RuntimeError(''' Obsolete QDAC Software version detected. QCoDeS only supports version 0.170202 or newer. Contact [email protected] for an update. ''') self.num_chans = num_chans # Assigned slopes. Entries will eventually be [chan, slope] self._slopes = [] # Function generators (used in _set_voltage) self._fgs = set(range(1, 9)) self._assigned_fgs = {} # {chan: fg} # Sync channels self._syncoutputs = [] # Entries: [chan, syncchannel] self.chan_range = range(1, 1 + self.num_chans) self.channel_validator = vals.Ints(1, self.num_chans) channels = ChannelList(self, "Channels", QDacChannel, snapshotable=False, multichan_paramclass=QDacMultiChannelParameter) for i in self.chan_range: channel = QDacChannel(self, f'chan{i:02}', i) channels.append(channel) # Should raise valueerror if name is invalid (silently fails now) self.add_submodule(f'ch{i:02}', channel) channels.lock() self.add_submodule('channels', channels) for board in range(6): for sensor in range(3): label = f'Board {board}, Temperature {sensor}' self.add_parameter(name=f'temp{board}_{sensor}', label=label, unit='C', get_cmd=f'tem {board} {sensor}', get_parser=self._num_verbose) self.add_parameter(name='cal', set_cmd='cal {}', vals=self.channel_validator) # TO-DO: maybe it's too dangerous to have this settable. # And perhaps ON is a better verbose mode default? self.add_parameter(name='verbose', set_cmd='ver {}', val_mapping={True: 1, False: 0}) # Initialise the instrument, all channels DC (unbind func. generators) for chan in self.chan_range: # Note: this call does NOT change the voltage on the channel self.write(f'wav {chan} 0 1 0') self.verbose.set(False) self.connect_message() log.info('[*] Querying all channels for voltages and currents...') self._update_cache(readcurrents=update_currents) self._update_currents = update_currents log.info('[+] Done')
def __init__(self, parent: 'ZNB', name: str, channel: int, vna_parameter: Optional[str] = None, existing_trace_to_bind_to: Optional[str] = None) -> None: """ Args: parent: Instrument that this channel is bound to. name: Name to use for this channel. channel: channel on the VNA to use vna_parameter: Name of parameter on the vna that this should measure such as S12. If left empty this will fall back to `name`. existing_trace_to_bind_to: Name of an existing trace on the VNA. If supplied try to bind to an existing trace with this name rather than creating a new trace. """ n = channel self._instrument_channel = channel # Additional wait when adjusting instrument timeout to sweep time. self._additional_wait = 1 if vna_parameter is None: vna_parameter = name self._vna_parameter = vna_parameter super().__init__(parent, name) if existing_trace_to_bind_to is None: self._tracename = f"Trc{channel}" else: traces = self._parent.ask("CONFigure:TRACe:CATalog?") if existing_trace_to_bind_to not in traces: raise RuntimeError(f"Trying to bind to" f" {existing_trace_to_bind_to} " f"which is not in {traces}") self._tracename = existing_trace_to_bind_to # map hardware channel to measurement # hardware channels are mapped one to one to QCoDeS channels # we are not using sub traces within channels. if existing_trace_to_bind_to is None: self.write(f"CALC{self._instrument_channel}:PAR:SDEF" f" '{self._tracename}', '{self._vna_parameter}'") # Source power is dependent on model, but not well documented. # Here we assume -60 dBm for ZNB20, the others are set, # due to lack of knowledge, to -80 dBm as of before the edit. full_modelname = self._parent.get_idn()['model'] if full_modelname is not None: model = full_modelname.split('-')[0] else: raise RuntimeError("Could not determine ZNB model") mSourcePower = {'ZNB4': -80, 'ZNB8': -80, 'ZNB20': -60, 'ZNB40': -60} if model not in mSourcePower.keys(): raise RuntimeError(f"Unsupported ZNB model: {model}") self._min_source_power: float self._min_source_power = mSourcePower[model] self.add_parameter(name='vna_parameter', label='VNA parameter', get_cmd=f"CALC{self._instrument_channel}:" f"PAR:MEAS? '{self._tracename}'", get_parser=self._strip) self.add_parameter(name='power', label='Power', unit='dBm', get_cmd=f'SOUR{n}:POW?', set_cmd=f'SOUR{n}:POW {{:.4f}}', get_parser=float, vals=vals.Numbers(self._min_source_power, 25)) # there is an 'increased bandwidth option' (p. 4 of manual) that does # not get taken into account here self.add_parameter( name='bandwidth', label='Bandwidth', unit='Hz', get_cmd=f'SENS{n}:BAND?', set_cmd=f'SENS{n}:BAND {{:.4f}}', get_parser=int, vals=vals.Enum(*np.append( 10**6, np.kron([1, 1.5, 2, 3, 5, 7], 10**np.arange(6))))) self.add_parameter(name='avg', label='Averages', unit='', get_cmd=f'SENS{n}:AVER:COUN?', set_cmd=f'SENS{n}:AVER:COUN {{:.4f}}', get_parser=int, vals=vals.Ints(1, 5000)) self.add_parameter(name='start', get_cmd=f'SENS{n}:FREQ:START?', set_cmd=self._set_start, get_parser=float, vals=vals.Numbers(self._parent._min_freq, self._parent._max_freq - 10)) self.add_parameter(name='stop', get_cmd=f'SENS{n}:FREQ:STOP?', set_cmd=self._set_stop, get_parser=float, vals=vals.Numbers(self._parent._min_freq + 1, self._parent._max_freq)) self.add_parameter(name='center', get_cmd=f'SENS{n}:FREQ:CENT?', set_cmd=self._set_center, get_parser=float, vals=vals.Numbers(self._parent._min_freq + 0.5, self._parent._max_freq - 10)) self.add_parameter( name='span', get_cmd=f'SENS{n}:FREQ:SPAN?', set_cmd=self._set_span, get_parser=float, vals=vals.Numbers(1, self._parent._max_freq - self._parent._min_freq)) self.add_parameter(name='npts', get_cmd=f'SENS{n}:SWE:POIN?', set_cmd=self._set_npts, get_parser=int) self.add_parameter(name='status', get_cmd=f'CONF:CHAN{n}:MEAS?', set_cmd=f'CONF:CHAN{n}:MEAS {{}}', get_parser=int) self.add_parameter(name='format', get_cmd=partial(self._get_format, tracename=self._tracename), set_cmd=self._set_format, val_mapping={ 'dB': 'MLOG\n', 'Linear Magnitude': 'MLIN\n', 'Phase': 'PHAS\n', 'Unwr Phase': 'UPH\n', 'Polar': 'POL\n', 'Smith': 'SMIT\n', 'Inverse Smith': 'ISM\n', 'SWR': 'SWR\n', 'Real': 'REAL\n', 'Imaginary': 'IMAG\n', 'Delay': "GDEL\n", 'Complex': "COMP\n" }) self.add_parameter(name='trace_mag_phase', start=self.start(), stop=self.stop(), npts=self.npts(), channel=n, parameter_class=FrequencySweepMagPhase) self.add_parameter(name='trace', start=self.start(), stop=self.stop(), npts=self.npts(), channel=n, parameter_class=FrequencySweep) self.add_parameter(name='electrical_delay', label='Electrical delay', get_cmd=f'SENS{n}:CORR:EDEL2:TIME?', set_cmd=f'SENS{n}:CORR:EDEL2:TIME {{}}', get_parser=float, unit='s') self.add_parameter(name='sweep_time', label='Sweep time', get_cmd=f'SENS{n}:SWE:TIME?', get_parser=float, unit='s') self.add_function('set_electrical_delay_auto', call_cmd=f'SENS{n}:CORR:EDEL:AUTO ONCE') self.add_function('autoscale', call_cmd='DISPlay:TRACe1:Y:SCALe:AUTO ONCE, ' f"{self._tracename}")
def __init__(self, name, FPGA, **kwargs): super().__init__(name, **kwargs) self._clk_freq = int(100e6) self.FPGA = FPGA self.port = 0 self.write_port_signals = { "reset": { "address": 0, 'width': 1, 'type': bool }, "enable": { "address": 1, 'width': 1, 'type': bool }, "blip_threshold": { "address": 2, 'width': 1, 'type': np.int16 }, "blip_t_wait": { "address": 3, 'width': 1, 'type': np.uint32 }, "blip_timeout": { "address": 4, 'width': 1, 'type': np.uint32 }, "trace_sel": { "address": 5, 'width': 1, 'type': np.uint8 }, "pxi_sel": { "address": 6, 'width': 1, 'type': np.uint8 }, "timer_threshold": { "address": 7, 'width': 2, 'type': list }, "trigger_delay": { "address": 9, 'width': 1, 'type': np.uint32 } } self.read_port_signals = { "update_counter": { "address": 0, 'width': 1, 'type': np.uint32 }, "timeout_counter": { "address": 1, 'width': 1, 'type': np.uint32 }, "trigger_counter": { "address": 2, 'width': 1, 'type': np.uint32 }, "timer_counter": { "address": 3, 'width': 2, 'type': np.uint64 }, "trace_out": { "address": 5, 'width': 1, 'type': np.int16 }, "bayesian_state": { "address": 6, 'width': 1, 'type': np.int16 }, } self.add_parameter( 'blip_threshold', set_cmd=self._set_blip_threshold, vals=vals.Ints(-0x8000, 0x7FFF), docstring='The blip threshold in the range of [-0x8000, 0x7FFF].') self.add_parameter('blip_t_wait', set_cmd=self._set_blip_t_wait, vals=vals.Ints(0, 0xFFFFFFFF), docstring='The blip timeout in samples.') self.add_parameter('blip_timeout', set_cmd=self._set_blip_timeout, vals=vals.Ints(0, 0xFFFFFFFF), docstring='The blip timeout in samples.') self.add_parameter( 'trace_select', set_cmd=self._set_trace_select, vals=vals.Ints(0, 7), docstring='The channel you want to select from 0 to 7.') self.add_parameter( 'pxi_select', set_cmd=self._set_pxi_select, vals=vals.Ints(0, 7), docstring= 'The PXI channel the trigger will be output on, from 0 to 7.') self.add_parameter( 'timer_duration', set_cmd=self._set_timer_duration, vals=vals.Ints(0, int(2**48 - 1)), docstring= "The post-update timer duration to match pulse sequence duration.")
def __init__(self, name: str, address: str, reset: bool=False, **kwargs): """ Args: name: Name to use internally in QCoDeS address: VISA ressource address reset: Set Keithley to defaults? True or False """ super().__init__(name, address, terminator='\n', **kwargs) self._ac_init = False self._ac_ampl = False self._ac_freq = False self.add_parameter('current', label='Current', get_cmd='SOUR:CURR?', set_cmd='SOUR:CURR {}', get_parser=float, unit='A', vals=vals.Numbers()) self.add_parameter('output', get_cmd='OUTP:STAT?', set_cmd='OUTP:STAT {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('range', get_cmd='CURR:RANG?', set_cmd='CURR:RANG {}', get_parser=float, unit='A', vals=vals.Numbers(-105e-3, 105e-3)) self.add_parameter('auto_range', get_cmd='CURR:RANG:AUTO?', set_cmd='CURR:RANG:AUTO {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('compliance', get_cmd='CURR:COMP?', set_cmd='CURR:COMP {}', unit='V', get_parser=float, vals=vals.Numbers(-.1, 105)) self.add_parameter('delay', unit='s', get_cmd='SOUR:DEL?', set_cmd='SOUR:DEL {}', get_parser=float, vals=vals.Numbers(0.001, 999999.999)) self.add_parameter('filter', get_cmd='CURR:FILT?', set_cmd='CURR:FILT {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('speed', get_cmd='OUTP:RESP?', set_cmd='OUTP:RESP {}', get_parser=str, vals=vals.Enum('slow', 'fast', 'SLOW', 'FAST')) self.add_parameter('display', snapshot_get=False, get_cmd='DISP:ENAB?', set_cmd='DISP:ENAB {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('beeper', snapshot_get=False, get_cmd='SYST:BEEP?', set_cmd='SYST:BEEP {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('AC_amplitude', get_cmd='SOUR:WAVE:AMPL?', set_cmd=self._setac_amplitude, get_parser=float, unit='A', vals=vals.Numbers(2e-12, 0.105)) self.add_parameter('AC_frequency', get_cmd='SOUR:WAVE:FREQ?', set_cmd=self._setac_frequency, get_parser=float, unit='Hz', vals=vals.Numbers(0, 1e5)) self.add_parameter('AC_offset', get_cmd='SOUR:WAVE:OFFS?', set_cmd='SOUR:WAVE:OFFS {}', get_parser=float, unit='A', vals=vals.Numbers(-0.105, 0.105)) self.add_parameter('AC_duration_time', get_cmd='SOUR:WAVE:DUR:TIME?', set_cmd='SOUR:WAVE:DUR:TIME {}', get_parser=float, unit='s', vals=vals.MultiType(vals.Enum('INF'), vals.Numbers(100e-9, 999999.999))) self.add_parameter('AC_duration_cycles', get_cmd='SOUR:WAVE:DUR:CYCL?', set_cmd='SOUR:WAVE:DUR:CYCL {}', get_parser=float, unit='cycles', vals=vals.MultiType(vals.Enum('INF'), vals.Numbers(0.001, 99999999900))) self.add_parameter('AC_phasemark', get_cmd='SOUR:WAVE:PMAR:STAT?', set_cmd='SOUR:WAVE:PMAR:STAT {}', get_parser=int, set_parser=parse_output_bool, vals=vals.Enum(*boolcheck)) self.add_parameter('AC_phasemark_offset', get_cmd='SOUR:WAVE:PMAR?', set_cmd='SOUR:WAVE:PMAR {}', get_parser=float, unit='degrees', vals=vals.Numbers(0, 360)) self.add_parameter('AC_ranging', get_cmd='SOUR:WAVE:RANG?', set_cmd='SOUR:WAVE:RANG {}', get_parser=str, vals=vals.Enum('BEST', 'best', 'FIX', 'fix', 'FIXED', 'fixed')) # Related to attached 2182(a) nanovoltmeter self.add_parameter('unit', label='diff conductance unit', get_cmd='UNIT?', set_cmd='UNIT {}', initial_value='OHMS', get_parser=str, vals=vals.Enum('V', 'ohms', 'OHMS', 'S', 'SIEM', 'siem', 'siemens', 'SIEMENS')) self.add_parameter('k2182_present', get_cmd='SOUR:DELT:NVPR?', get_parser=int) self.add_parameter('delta_arm', get_cmd='SOUR:DELT:ARM?', get_parser=int) self.add_parameter('diff_arm', get_cmd='SOUR:DCON:ARM?', get_parser=int) self.add_parameter('delta_IV_sweep', # STILL A WORK IN PROGRESS snapshot_get=False, get_cmd=self.delta_IV_sweep_get, set_cmd=self.delta_IV_sweep_set, get_parser=float, set_parser=float) # These are only useable if you have connected to the Keithley 2182 # Through an RS-232 port. Make sure to check the settings on the 2182 # at set to GPIB: off, RS-232 on self.add_parameter('k2_measure', snapshot_get=False, get_cmd=partial(self.k2_read_cmd, 'SENS:DATA:FRES?'), get_parser=float, unit='V') self.add_parameter('k2_range', snapshot_get=False, set_cmd='SYST:COMM:SER:SEND "VOLT:RANG {}"', get_cmd=partial(self.k2_read_cmd, 'VOLT:RANG?'), set_parser=float, get_parser=float, vals=vals.Numbers(0, 120)) self.add_parameter('k2_nplc', snapshot_get=False, set_cmd='SYST:COMM:SER:SEND "VOLT:NPLC {}"', get_cmd=partial(self.k2_read_cmd, 'VOLT:NPLC?'), set_parser=float, get_parser=float, vals=vals.Numbers(0.01, 60)) self.add_parameter('k2_line_sync', snapshot_get=False, set_cmd='SYST:COMM:SER:SEND "SYST:LSYN {}"', get_cmd=partial(self.k2_read_cmd, 'SYST:LSYN?'), set_parser=parse_output_bool, get_parser=int, vals=vals.Enum(*boolcheck)) self.add_parameter('k2_front_autozero', snapshot_get=False, set_cmd='SYST:COMM:SER:SEND "SYST:FAZ {}"', get_cmd=partial(self.k2_read_cmd, 'SYST:FAZ?'), set_parser=parse_output_bool, get_parser=int, vals=vals.Enum(*boolcheck)) self.add_parameter('k2_autozero', snapshot_get=False, set_cmd='SYST:COMM:SER:SEND "SYST:AZER {}"', get_cmd=partial(self.k2_read_cmd, 'SYST:AZER?'), set_parser=parse_output_bool, get_parser=int, vals=vals.Enum(*boolcheck)) self.add_parameter('k2_dfilter_count', snapshot_get=False, get_cmd=partial(self.k2_read_cmd, 'SENS:VOLT:DFIL:COUN?'), set_cmd='SYST:COMM:SER:SEND "SENS:VOLT:DFIL:COUN {}"', get_parser=int, set_parser=int, vals=vals.Ints(1, 100)) self.add_parameter('k2_dfilter_window', snapshot_get=False, get_cmd=partial(self.k2_read_cmd, 'SENS:VOLT:DFIL:WIND?'), set_cmd='SYST:COMM:SER:SEND "SENS:VOLT:DFIL:WIND {}"', get_parser=float, set_parser=float, vals=vals.Numbers(0.01, 10)) self.add_parameter('k2_dfilter_type', snapshot_get=False, get_cmd=partial(self.k2_read_cmd, 'SENS:VOLT:DFIL:TCON?'), set_cmd='SYST:COMM:SER:SEND "SENS:VOLT:DFIL:TCON {}"', vals=vals.Enum('MOV', 'REP')) self.add_function('abort_arm', call_cmd='SOUR:SWE:ABOR') self.add_function('reset', call_cmd='*RST') # TODO: Getting error messages doesn't work self.add_function('get_error', call_cmd='SYST:ERR?') if reset: self.reset() self.connect_message()
def __init__(self, name: str, dll_path: Optional[str] = None, **kwargs: Any): """ Args: name: Name of the instrument. dll_path: Path to ``sa_api.dll`` Defaults to the default dll within Spike installation **kwargs: """ super().__init__(name, **kwargs) self._parameters_synced = False self._trace_updated = False log.info('Initializing instrument SignalHound USB 124B') self.dll = ct.CDLL(dll_path or self.dll_path) self._set_ctypes_argtypes() self.hf = Constants self.add_parameter('frequency', label='Frequency', unit='Hz', initial_value=5e9, vals=vals.Numbers(), parameter_class=SweepTraceParameter, docstring='Center frequency for sweep.' 'This is the set center, the actual ' 'center may be subject to round off ' 'compared to this value') self.add_parameter('span', label='Span', unit='Hz', initial_value=.25e6, vals=vals.Numbers(), parameter_class=SweepTraceParameter, docstring='Width of frequency span' 'This is the set span, the actual ' 'span may be subject to round off ' 'compared to this value') self.add_parameter('npts', label='Number of Points', get_cmd=self._get_npts, set_cmd=False, docstring='Number of points in frequency sweep.') self.add_parameter('avg', label='Averages', initial_value=1, get_cmd=None, set_cmd=None, vals=vals.Ints(), docstring='Number of averages to perform. ' 'Averages are performed in software by ' 'acquiring multiple sweeps') self.add_parameter('ref_lvl', label='Reference power', unit='dBm', initial_value=0, vals=vals.Numbers(max_value=20), parameter_class=TraceParameter, docstring="Setting reference level will " "automatically select gain and attenuation" "optimal for measuring at and below " "this level") self.add_parameter( 'external_reference', initial_value=False, vals=vals.Bool(), parameter_class=ExternalRefParameter, docstring='Use an external 10 MHz reference source. ' 'Note that Signal Hound does not support ' 'disabling external ref. To disable close ' 'the connection and restart.') self.add_parameter('device_type', set_cmd=False, get_cmd=self._get_device_type) self.add_parameter('device_mode', get_cmd=lambda: 'sweeping', set_cmd=False, docstring='The driver currently only ' 'supports sweeping mode. ' 'It is therefor not possible' 'to set this parameter to anything else') self.add_parameter('acquisition_mode', get_cmd=lambda: 'average', set_cmd=False, docstring="The driver only supports averaging " "mode it is therefor not possible to set" "this parameter to anything else") self.add_parameter('rbw', label='Resolution Bandwidth', unit='Hz', initial_value=1e3, vals=vals.Numbers(0.1, 250e3), parameter_class=TraceParameter, docstring='Resolution Bandwidth (RBW) is' 'the bandwidth of ' 'spectral energy represented in each ' 'frequency bin') self.add_parameter('vbw', label='Video Bandwidth', unit='Hz', initial_value=1e3, vals=vals.Numbers(), parameter_class=TraceParameter, docstring='The video bandwidth (VBW) is applied ' 'after the signal has been converted to ' 'frequency domain as power, voltage, ' 'or log units. It is implemented as a ' 'simple rectangular window, averaging the ' 'amplitude readings for each frequency ' 'bin over several overlapping FFTs. ' 'For best performance use RBW as the VBW.') self.add_parameter('reject_image', label='Reject image', unit='', initial_value=True, parameter_class=TraceParameter, get_cmd=None, docstring="Apply software filter to remove " "undersampling mirroring", vals=vals.Bool()) self.add_parameter('sleep_time', label='Sleep time', unit='s', initial_value=0.1, get_cmd=None, set_cmd=None, docstring="Time to sleep before and after " "getting data from the instrument", vals=vals.Numbers(0)) # We don't know the correct values of # the sweep parameters yet so we supply # some defaults. The correct will be set when we call configure below self.add_parameter(name='trace', sweep_len=1, start_freq=1, stepsize=1, parameter_class=FrequencySweep) self.add_parameter('power', label='Power', unit='dBm', get_cmd=self._get_power_at_freq, set_cmd=False, docstring="The maximum power in a window of 250 kHz" "around the specified frequency with " "Resolution bandwidth set to 1 kHz." "The integration window is specified by " "the VideoBandWidth (set by vbw)") # scale is defined after the trace and power parameter so that # it can change the units of those in it's set method when the # scale changes self.add_parameter('scale', initial_value='log-scale', vals=vals.Enum('log-scale', 'lin-scale', 'log-full-scale', 'lin-full-scale'), parameter_class=ScaleParameter) self.add_parameter('frequency_axis', label='Frequency', unit='Hz', get_cmd=self._get_freq_axis, set_cmd=False, vals=vals.Arrays(shape=(self.npts, )), snapshot_value=False) self.add_parameter('freq_sweep', label='Power', unit='depends on mode', get_cmd=self._get_sweep_data, set_cmd=False, parameter_class=ParameterWithSetpoints, vals=vals.Arrays(shape=(self.npts, )), setpoints=(self.frequency_axis, ), snapshot_value=False) self.openDevice() self.configure() self.connect_message()
def __init__(self, name: str, address: str, silent: bool = False, **kwargs): """ Create an instance of the instrument. Args: name: Name used by QCoDeS. Appears in the DataSet address: Visa-resolvable instrument address. silent: If True, the connect_message of the instrument is supressed. Default: False """ super().__init__(name, address, terminator='\n', **kwargs) idn = self.IDN.get() self.model = idn['model'] self.is_34465A_34470A = self.model in ['34465A', '34470A'] #################################### # Instrument specifications options = self._options() self.has_DIG = self.is_34465A_34470A and ( 'DIG' in options or LooseVersion('A.03') <= LooseVersion(idn['firmware'])) # Note that the firmware version check is still needed because # ``_options`` (the ``*OPT?`` command) returns 'DIG' option for # firmware 3.0 only if it has been purchased before self.has_MEM = self.is_34465A_34470A and 'MEM' in options PLCs = { '34410A': [0.006, 0.02, 0.06, 0.2, 1, 2, 10, 100], '34460A': [0.02, 0.2, 1, 10, 100], '34461A': [0.02, 0.2, 1, 10, 100], '34465A': [0.02, 0.06, 0.2, 1, 10, 100], '34470A': [0.02, 0.06, 0.2, 1, 10, 100] } if self.has_DIG: PLCs['34465A'] = [0.001, 0.002, 0.006] + PLCs['34465A'] PLCs['34470A'] = [0.001, 0.002, 0.006] + PLCs['34470A'] ranges = { '34410A': [10**n for n in range(3, 10)], # 100 to 1 G '34460A': [10**n for n in range(-3, 9)], # 1 m to 100 M '34461A': [10**n for n in range(-3, 9)], # 1 m to 100 M '34465A': [10**n for n in range(-3, 10)], # 1 m to 1 G '34470A': [10**n for n in range(-3, 10)], # 1 m to 1 G } # The resolution factor order matches the order of PLCs res_factors = { '34410A': [ 30e-6, 15e-5, 6e-6, 3e-6, 1.5e-6, 0.7e-6, 0.3e-6, 0.2e-6, 0.1e-6, 0.03e-6 ], '34460A': [300e-6, 100e-6, 30e-6, 10e-6, 3e-6], '34461A': [100e-6, 10e-6, 3e-6, 1e-6, 0.3e-6], '34465A': [3e-6, 1.5e-6, 0.7e-6, 0.3e-6, 0.1e-6, 0.03e-6], '34470A': [1e-6, 0.5e-6, 0.3e-6, 0.1e-6, 0.03e-6, 0.01e-6] } if self.has_DIG: res_factors['34465A'] = [30e-6, 15e-6, 6e-6 ] + res_factors['34465A'] res_factors['34470A'] = [30e-6, 10e-6, 3e-6 ] + res_factors['34470A'] self._resolution_factors = res_factors[self.model] self.ranges = ranges[self.model] self.NPLC_list = PLCs[self.model] #################################### # PARAMETERS # this is the "master" parameter that determines whether the DMM is # a voltmeter, an ampmeter, etc. self.add_parameter('sense_function', label="Instrument sense function", get_cmd="SENSe:FUNCtion?", set_cmd="SENSe:FUNCtion {}", val_mapping={ "DC Voltage": '"VOLT"', "AC Voltage": '"VOLT:AC"', "DC Current": '"CURR"', "AC Current": '"CURR:AC"', "2 Wire Resistance": '"RES"', "4 Wire Resistance": '"FRES"' }) self.add_parameter('line_frequency', get_cmd='SYSTem:LFRequency?', get_parser=int, set_cmd=False, label='Line Frequency', unit='Hz', docstring=('The frequency of the power line where ' 'the instrument is plugged')) self.add_parameter('NPLC', get_cmd='SENSe:VOLTage:DC:NPLC?', get_parser=float, set_cmd=self._set_NPLC, vals=vals.Enum(*self.NPLC_list), label='Integration time', unit='NPLC', docstring=textwrap.dedent("""\ Sets the integration time in number of power line cycles (PLC) for DC voltage and ratio measurements. Integration time is the period that the instrument's analog-to-digital (A/D) converter samples the input signal for a measurement. A longer integration time gives better measurement resolution but slower measurement speed. Only integration times of 1, 10, or 100 PLC provide normal mode (line frequency noise) rejection. Setting the integration time also sets the measurement resolution.""")) self.add_parameter('range', get_cmd='SENSe:VOLTage:DC:RANGe?', get_parser=float, set_cmd='SENSe:VOLTage:DC:RANGe {:f}', vals=vals.Enum(*self.ranges)) self.add_parameter('resolution', get_cmd='SENSe:VOLTage:DC:RESolution?', get_parser=float, set_cmd=self._set_resolution, label='Resolution', unit='V', vals=vals.MultiType(vals.Numbers(0), vals.Enum('MIN', 'MAX', 'DEF')), docstring=textwrap.dedent("""\ Selects the measurement resolution for DC voltage and ratio measurements. The resolution is specified in the same units as the selected measurement function, not in number of digits. You can also specify MIN (best resolution) or MAX (worst resolution). To achieve normal mode (line frequency noise) rejection, use a resolution that corresponds to an integration time that is an integral number of power line cycles. Refer to "Resolution Table" or "Range, Resolution and NPLC" sections of the instrument's manual for the available ranges for the resolution values.""")) self.add_parameter('autorange', label='Autorange', set_cmd='SENSe:VOLTage:DC:RANGe:AUTO {}', get_cmd='SENSe:VOLTage:DC:RANGe:AUTO?', val_mapping={ 'ON': 1, 'OFF': 0 }, vals=vals.Enum('ON', 'OFF')) self.add_parameter('autozero', label='Autozero', set_cmd='SENSe:VOLTage:DC:ZERO:AUTO {}', get_cmd='SENSe:VOLTage:DC:ZERO:AUTO?', val_mapping={ 'ON': 1, 'OFF': 0, 'ONCE': 'ONCE' }, vals=vals.Enum('ON', 'OFF', 'ONCE'), docstring=textwrap.dedent("""\ Disables or enables the autozero mode for DC voltage and ratio measurements. ON: the DMM internally measures the offset following each measurement. It then subtracts that measurement from the preceding reading. This prevents offset voltages present on the DMM’s input circuitry from affecting measurement accuracy. OFF: the instrument uses the last measured zero measurement and subtracts it from each measurement. It takes a new zero measurement each time you change the function, range or integration time. ONCE: the instrument takes one zero measurement and sets autozero OFF. The zero measurement taken is used for all subsequent measurements until the next change to the function, range or integration time. If the specified integration time is less than 1 PLC, the zero measurement is taken at 1 PLC to optimize noise rejection. Subsequent measurements are taken at the specified fast (< 1 PLC) integration time.""")) #################################### # Aperture parameters if self.is_34465A_34470A: # Define the extreme aperture time values for the 34465A and 34470A utility_freq = self.line_frequency() if utility_freq == 50: apt_times = {'34465A': [0.3e-3, 2], '34470A': [0.3e-3, 2]} elif utility_freq == 60: apt_times = { '34465A': [0.3e-3, 1.67], '34470A': [0.3e-3, 1.67] } if self.has_DIG: apt_times['34465A'][0] = 20e-6 apt_times['34470A'][0] = 20e-6 self.add_parameter('aperture_mode', label='Aperture mode', set_cmd='SENSe:VOLTage:DC:APERture:ENABled {}', get_cmd='SENSe:VOLTage:DC:APERture:ENABled?', val_mapping={ 'ON': 1, 'OFF': 0 }, vals=vals.Enum('ON', 'OFF'), docstring=textwrap.dedent("""\ Enables the setting of integration time in seconds (called aperture time) for DC voltage measurements. If aperture time mode is disabled (default), the integration time is set in PLC (power-line cycles).""")) self.add_parameter('aperture_time', label='Aperture time', set_cmd=self._set_apt_time, get_cmd='SENSe:VOLTage:DC:APERture?', get_parser=float, vals=vals.Numbers(*apt_times[self.model]), docstring=textwrap.dedent("""\ Specifies the integration time in seconds (called aperture time) with 2 µs resolution for DC voltage measurements. Use this command for precise control of the DMM's integration time. Use `NPLC` for better power-line noise rejection characteristics (NPLC > 1). Setting the aperture time automatically enables the aperture mode.""")) #################################### # Submodules self.add_submodule('display', Display(self, 'display')) self.add_submodule('trigger', Trigger(self, 'trigger')) self.add_submodule('sample', Sample(self, 'sample')) #################################### # Measuring parameter self.add_parameter('volt', get_cmd=partial(self._get_parameter, "DC Voltage"), label='Voltage', unit='V') self.add_parameter('curr', get_cmd=partial(self._get_parameter, "DC Current"), label='Current', unit='A') self.add_parameter('ac_volt', get_cmd=partial(self._get_parameter, "AC Voltage"), label='AC Voltage', unit='V') self.add_parameter('ac_curr', get_cmd=partial(self._get_parameter, "AC Current"), label='AC Current', unit='A') self.add_parameter('res', get_cmd=partial(self._get_parameter, "2 Wire Resistance"), label='Resistance', unit='Ohms') self.add_parameter('four_wire_res', get_cmd=partial(self._get_parameter, "4 Wire Resistance"), label='Resistance', unit='Ohms') ##################################### # Time trace parameters self.add_parameter('timetrace_npts', label='Time trace number of points', initial_value=500, get_cmd=None, set_cmd=None, vals=vals.Ints(1)) self.add_parameter('timetrace_dt', label='Time trace time interval', unit='s', initial_value=1e-1, get_cmd=None, set_cmd=None, vals=vals.Numbers(0)) self.add_parameter('time_axis', label='Time', unit='s', snapshot_value=False, vals=vals.Arrays(shape=(self.timetrace_npts, )), parameter_class=TimeAxis) self.add_parameter('timetrace', vals=vals.Arrays(shape=(self.timetrace_npts, )), setpoints=(self.time_axis, ), parameter_class=TimeTrace) #################################### # Connect message if not silent: self.connect_message()
def __init__(self, parent: 'KeysightB1500', name: Optional[str], slot_nr, **kwargs): super().__init__(parent, name, slot_nr, **kwargs) self.channels = (ChNr(slot_nr),) self.setup_fnc_already_run = False self._ranging_mode: Union[constants.RangingMode, int] = \ constants.RangingMode.AUTO self._measurement_range_for_non_auto: Optional[int] = None self.add_parameter(name="voltage_dc", unit="V", set_cmd=self._set_voltage_dc, get_cmd=self._get_voltage_dc ) self.add_parameter(name="voltage_ac", unit="V", set_cmd=self._set_voltage_ac, get_cmd=self._get_voltage_ac ) self.add_parameter(name="frequency", unit="Hz", set_cmd=self._set_frequency, get_cmd=self._get_frequency ) self.add_parameter(name="capacitance", get_cmd=self._get_capacitance, snapshot_value=False) self.add_submodule('correction', Correction(self, 'correction')) self.add_parameter(name="phase_compensation_mode", set_cmd=self._set_phase_compensation_mode, get_cmd=None, set_parser=constants.ADJ.Mode, docstring=textwrap.dedent(""" This parameter selects the MFCMU phase compensation mode. This command initializes the MFCMU. The available modes are captured in :class:`constants.ADJ.Mode`: - 0: Auto mode. Initial setting. - 1: Manual mode. - 2: Load adaptive mode. For mode=0, the KeysightB1500 sets the compensation data automatically. For mode=1, execute the :meth:`phase_compensation` method ( the ``ADJ?`` command) to perform the phase compensation and set the compensation data. For mode=2, the KeysightB1500 performs the phase compensation before every measurement. It is useful when there are wide load fluctuations by changing the bias and so on.""")) self.add_submodule('cv_sweep', CVSweeper(self, 'cv_sweep')) self.add_parameter(name='sweep_mode', initial_value=constants.SweepMode.LINEAR, vals=vals.Enum(*list(constants.SweepMode)), set_parser=constants.SweepMode, parameter_class=GroupParameter, docstring=textwrap.dedent(""" Sweep mode. 1: Linear sweep (single stair, start to stop.) 2: Log sweep (single stair, start to stop.) 3: Linear sweep (double stair, start to stop to start.) 4: Log sweep (double stair, start to stop to start.) """)) self.add_parameter(name='sweep_start', initial_value=0.0, unit='V', vals=vals.Numbers(-25, 25), parameter_class=GroupParameter, docstring=textwrap.dedent(""" Start value of the DC bias sweep (in V). For the log sweep, start and stop must have the same polarity. """)) self.add_parameter(name='sweep_end', initial_value=0.0, unit='V', vals=vals.Numbers(-25, 25), parameter_class=GroupParameter, docstring=textwrap.dedent(""" Stop value of the DC bias sweep (in V). For the log sweep, start and stop must have the same polarity. """)) self.add_parameter(name='sweep_steps', initial_value=1, vals=vals.Ints(1, 1001), parameter_class=GroupParameter, docstring=textwrap.dedent(""" Number of steps for staircase sweep. Possible values from 1 to 1001""")) self.add_parameter(name='chan', initial_value=self.channels[0], parameter_class=GroupParameter) self._set_sweep_steps_group = Group([self.chan, self.sweep_mode, self.sweep_start, self.sweep_end, self.sweep_steps], set_cmd='WDCV ' '{chan},' '{sweep_mode},' '{sweep_start},' '{sweep_end},' '{sweep_steps}', get_cmd=self._get_sweep_steps(), get_parser=self._get_sweep_steps_parser) self.add_parameter(name='adc_coef', initial_value=1, parameter_class=GroupParameter, vals=vals.Ints(1, 1023), docstring=textwrap.dedent(""" Coefficient used to define the number of averaging samples or the averaging time. Integer expression. - For mode=0: 1 to 1023. Initial setting/default setting is 2. - For mode=2: 1 to 100. Initial setting/default setting is 1. """)) self.add_parameter(name='adc_mode', initial_value=constants.ACT.Mode.PLC, parameter_class=GroupParameter, vals=vals.Enum(*list(constants.ACT.Mode)), set_parser=constants.ACT.Mode, docstring=textwrap.dedent(""" Sets the number of averaging samples or the averaging time set to the A/D converter of the MFCMU ``constants.ACT.Mode.AUTO``: Auto mode. Defines the number of averaging samples given by the following formula. Then initial averaging is the number of averaging samples automatically set by the B1500 and you cannot change. Number of averaging samples = N x initial averaging ``constants.ACT.Mode.PLC``: Power line cycle (PLC) mode. Defines the averaging time given by the following formula. Averaging time = N / power line frequency """)) self._adc_group = Group([self.adc_mode, self.adc_coef], set_cmd='ACT {adc_mode},{adc_coef}', get_cmd=self._get_adc_mode(), get_parser=self._get_adc_mode_parser) self.add_parameter(name='ranging_mode', set_cmd=self._set_ranging_mode, vals=vals.Enum(*list(constants.RangingMode)), set_parser=constants.RangingMode, get_cmd=None, docstring=textwrap.dedent(""" Specifies the measurement range or the measurement ranging type of the MFCMU. In the initial setting, the auto ranging is set. The range changing occurs immediately after the trigger (that is, during the measurements). Possible ranging modes are autorange and fixed range. """)) self.add_parameter(name='measurement_range_for_non_auto', set_cmd=self._set_measurement_range_for_non_auto, get_cmd=None, docstring=textwrap.dedent(""" Measurement range. Needs to set when ``ranging_mode`` is set to PLC. The value shoudl be integer 0 or more. 50 ohm, 100 ohm, 300 ohm, 1 kilo ohm, 3 kilo ohm, 10 kilo ohm, 30 kilo ohm, 100 kilo ohm, and 300 kilo ohm are selectable. Available measurement ranges depend on the output signal frequency set by the FC command. """)) self.add_parameter(name="measurement_mode", get_cmd=None, set_cmd=self._set_measurement_mode, set_parser=MM.Mode, vals=vals.Enum(*list(MM.Mode)), docstring=textwrap.dedent(""" Set measurement mode for this module. It is recommended for this parameter to use values from :class:`.constants.MM.Mode` enumeration. Refer to the documentation of ``MM`` command in the programming guide for more information. """)) self.add_parameter(name='impedance_model', set_cmd=self._set_impedance_model, get_cmd=None, vals=vals.Enum( *list(constants.IMP.MeasurementMode)), set_parser=constants.IMP.MeasurementMode, initial_value=constants.IMP.MeasurementMode.Cp_D, docstring=textwrap.dedent(""" The IMP command specifies the parameter measured by the MFCMU. Look at the ``constants.IMP.MeasurementMode`` for all the modes. """)) self.add_parameter(name='ac_dc_volt_monitor', set_cmd=self._set_ac_dc_volt_monitor, get_cmd=None, vals=vals.Ints(0, 1), initial_value=False, docstring=textwrap.dedent(""" This command enables or disables the data monitor and data output of the MFCMU AC voltage and DC voltage. 0: Disables the data monitor and output. Initial setting. 1: Enables the data monitor and output. """)) self.add_parameter(name='cv_sweep_voltages', get_cmd=self._cv_sweep_voltages, unit='V', label='Voltage', docstring=textwrap.dedent(""" Outputs the tuple of voltages to sweep. sweep_start, sweep_end and sweep_step functions are used to define the values of voltages. There are possible modes; linear sweep, log sweep, linear 2 way sweep and log 2 way sweep. The output of sweep_mode method is used to decide which mode to use. """)) self.add_parameter(name='run_sweep', parameter_class=CVSweepMeasurement, docstring=textwrap.dedent(""" This is MultiParameter. Running the sweep runs the measurement on the list of values of cv_sweep_voltages. The output is a primary parameter (for ex Capacitance) and a secondary parameter (for ex Dissipation) both of whom use the same setpoint cv_sweep_voltages. The impedance_model defines exactly what will be the primary and secondary parameter. The default case is Capacitance and Dissipation. """))
def __init__(self, name, **kw): super().__init__(name, **kw) self.add_parameter('E_c', unit='Hz', parameter_class=ManualParameter, vals=vals.Numbers()) self.add_parameter('E_j', unit='Hz', parameter_class=ManualParameter, vals=vals.Numbers()) self.add_parameter( 'anharmonicity', unit='Hz', label='Anharmonicity', docstring='Anharmonicity, negative by convention', parameter_class=ManualParameter, # typical target value initial_value=-300e6, vals=vals.Numbers()) self.add_parameter('T1', unit='s', parameter_class=ManualParameter, vals=vals.Numbers(0, 200e-6)) self.add_parameter('T2_echo', unit='s', parameter_class=ManualParameter, vals=vals.Numbers()) self.add_parameter('T2_star', unit='s', parameter_class=ManualParameter, vals=vals.Numbers()) self.add_parameter('dac_voltage', unit='mV', parameter_class=ManualParameter) self.add_parameter('dac_sweet_spot', unit='mV', parameter_class=ManualParameter) self.add_parameter('dac_flux_coefficient', unit='', parameter_class=ManualParameter) self.add_parameter('asymmetry', unit='', initial_value=0, parameter_class=ManualParameter) self.add_parameter('dac_channel', vals=vals.Ints(), parameter_class=ManualParameter) self.add_parameter('f_qubit', label='qubit frequency', unit='Hz', parameter_class=ManualParameter) self.add_parameter('f_max', label='qubit frequency', unit='Hz', parameter_class=ManualParameter) self.add_parameter('f_res', label='resonator frequency', unit='Hz', parameter_class=ManualParameter) self.add_parameter('f_RO', label='readout frequency', unit='Hz', parameter_class=ManualParameter) # Sequence/pulse parameters self.add_parameter('RO_pulse_delay', unit='s', parameter_class=ManualParameter) self.add_parameter('RO_pulse_length', unit='s', parameter_class=ManualParameter) self.add_parameter('RO_acq_marker_delay', unit='s', parameter_class=ManualParameter) self.add_parameter('RO_acq_marker_channel', parameter_class=ManualParameter, vals=vals.Strings()) self.add_parameter('RO_amp', unit='V', parameter_class=ManualParameter) # Time between start of pulses self.add_parameter('pulse_delay', unit='s', initial_value=0, vals=vals.Numbers(0, 1e-6), parameter_class=ManualParameter) self.add_parameter( 'f_qubit_calc_method', vals=vals.Enum('latest', 'dac', 'flux'), # in the future add 'tracked_dac', 'tracked_flux', initial_value='latest', parameter_class=ManualParameter) self.add_parameter('F_ssro', initial_value=0, label='RO assignment fidelity', vals=vals.Numbers(0.0, 1.0), parameter_class=ManualParameter) self.add_parameter('F_discr', initial_value=0, label='RO discrimination fidelity', vals=vals.Numbers(0.0, 1.0), parameter_class=ManualParameter) self.add_parameter('F_RB', initial_value=0, label='RB single qubit Clifford fidelity', vals=vals.Numbers(0, 1.0), parameter_class=ManualParameter) self.add_parameter('V_per_phi0', initial_value=1, label='V per phi0', vals=vals.Numbers(), docstring='Conversion between flux and voltage. ' 'How many volts need to be applied to ' 'have a flux of 1 phi0 (pulsed).', parameter_class=ManualParameter) self.add_parameter('V_offset', initial_value=0, label='V offset', vals=vals.Numbers(), docstring='AWG voltage at which the sweet spot is ' 'found (pulsed).', parameter_class=ManualParameter)
def __init__(self, parent, name, channel, min_val=-5, max_val=5): super().__init__(parent, name) # Validate slot and channel values self._CHANNEL_VAL.validate(channel) self._channel = channel self._slot = self.parent._slot # Calculate base address for querying channel parameters # Note that the following values can be found using these offsets # 0: Interrupt Period # 4: DAC High Limit # 5: DAC Low Limit # 6: Slope (double) # 8: DAC Value (double) self._base_addr = 1536 + (16 * 4) * self._slot + 16 * self._channel # Store min/max voltages assert (min_val < max_val) self.min_val = min_val self.max_val = max_val # Add channel parameters # Note we will use the older addresses to read the value from the dac # rather than the newer 'd' command for backwards compatibility self._volt_val = vals.Numbers(self.min_val, self.max_val) self.add_parameter("volt", get_cmd=partial(self._query_address, self._base_addr + 9, 1), get_parser=self._dac_code_to_v, set_cmd=self._set_dac, set_parser=self._dac_v_to_code, vals=self._volt_val, label="channel {}".format(channel + self._slot * 4), unit="V") # The limit commands are used to sweep dac voltages. They are not # safety features. self.add_parameter("lower_ramp_limit", get_cmd=partial(self._query_address, self._base_addr + 5), get_parser=self._dac_code_to_v, set_cmd="L{};", set_parser=self._dac_v_to_code, vals=self._volt_val, label="Lower_Ramp_Limit", unit="V") self.add_parameter("upper_ramp_limit", get_cmd=partial(self._query_address, self._base_addr + 4), get_parser=self._dac_code_to_v, set_cmd="U{};", set_parser=self._dac_v_to_code, vals=self._volt_val, label="Upper_Ramp_Limit", unit="V") self.add_parameter("update_period", get_cmd=partial(self._query_address, self._base_addr), get_parser=int, set_cmd="T{};", set_parser=int, vals=vals.Ints(50, 65535), label="Update_Period", unit="us") self.add_parameter("slope", get_cmd=partial(self._query_address, self._base_addr + 6, 2), get_parser=int, set_cmd="S{};", set_parser=int, vals=vals.Ints(-(2**32), 2**32), label="Ramp_Slope") # Manual parameters to control whether DAC channels should ramp to # voltages or jump self._ramp_val = vals.Numbers(0, 10) self.add_parameter("enable_ramp", get_cmd=None, set_cmd=None, initial_value=False, vals=vals.Bool()) self.add_parameter("ramp_rate", get_cmd=None, set_cmd=None, initial_value=0.1, vals=self._ramp_val, unit="V/s") # Add ramp function to the list of functions self.add_function("ramp", call_cmd=self._ramp, args=(self._volt_val, self._ramp_val)) # If we have access to the VERSADAC (slot) EEPROM, we can set the # initial value of the channel. # NOTE: these values will be overwritten by a K3 calibration if self.parent._VERSA_EEPROM_available: _INITIAL_ADDR = [6, 8, 32774, 32776] self.add_parameter("initial_value", get_cmd=partial(self._query_address, _INITIAL_ADDR[self._channel], versa_eeprom=True), get_parser=self._dac_code_to_v, set_cmd=partial(self._write_address, _INITIAL_ADDR[self._channel], versa_eeprom=True), set_parser=self._dac_v_to_code, vals=vals.Numbers(self.min_val, self.max_val))
def __init__(self, name, **kwargs): dll_path = 'C:\\WINDOWS\\System32\\ATSApi.dll' super().__init__(name, dll_path=dll_path, **kwargs) # add parameters # ----- Parameters for the configuration of the board ----- self.add_parameter(name='clock_source', parameter_class=AlazarParameter, label='Clock Source', unit=None, value='INTERNAL_CLOCK', byte_to_value_dict={ 1: 'INTERNAL_CLOCK', 2: 'FAST_EXTERNAL_CLOCK', 7: 'EXTERNAL_CLOCK_10MHz_REF' }) self.add_parameter(name='external_sample_rate', parameter_class=AlazarParameter, label='External Sample Rate', unit='S/s', vals=validators.Ints(300000000, 1800000000), value=500000000) self.add_parameter(name='sample_rate', parameter_class=AlazarParameter, label='Internal Sample Rate', unit='S/s', value=500000000, byte_to_value_dict={ 0x00000001: 1000, 0x00000002: 2000, 0x00000004: 5000, 0x00000008: 10000, 0x0000000A: 20000, 0x0000000C: 50000, 0x0000000E: 100000, 0x00000010: 200000, 0x00000012: 500000, 0x00000014: 1000000, 0x00000018: 2000000, 0x0000001A: 5000000, 0x0000001C: 10000000, 0x0000001E: 20000000, 0x00000021: 25000000, 0x00000022: 50000000, 0x00000024: 100000000, 0x00000025: 125000000, 0x00000026: 160000000, 0x00000027: 180000000, 0x00000028: 200000000, 0x0000002B: 250000000, 0x00000030: 500000000, 0x00000032: 800000000, 0x00000035: 1000000000, 0x00000037: 1200000000, 0x0000003A: 1500000000, 0x0000003D: 1800000000, 0x0000003F: 2000000000, 0x0000006A: 2400000000, 0x00000075: 3000000000, 0x0000007B: 3600000000, 0x00000080: 4000000000, 0x00000040: 'EXTERNAL_CLOCK', }) self.add_parameter(name='clock_edge', parameter_class=AlazarParameter, label='Clock Edge', unit=None, value='CLOCK_EDGE_RISING', byte_to_value_dict={ 0: 'CLOCK_EDGE_RISING', 1: 'CLOCK_EDGE_FALLING' }) self.add_parameter(name='decimation', parameter_class=AlazarParameter, label='Decimation', unit=None, value=1, vals=validators.Ints(0, 100000)) for i in ['1', '2']: self.add_parameter(name='coupling' + i, parameter_class=AlazarParameter, label='Coupling channel ' + i, unit=None, value='DC', byte_to_value_dict={ 1: 'AC', 2: 'DC' }) self.add_parameter(name='channel_range' + i, parameter_class=AlazarParameter, label='Range channel ' + i, unit='V', value=0.4, byte_to_value_dict={7: 0.4}) self.add_parameter(name='impedance' + i, parameter_class=AlazarParameter, label='Impedance channel ' + i, unit='Ohm', value=50, byte_to_value_dict={2: 50}) self.add_parameter(name='trigger_operation', parameter_class=AlazarParameter, label='Trigger Operation', unit=None, value='TRIG_ENGINE_OP_J', byte_to_value_dict={ 0: 'TRIG_ENGINE_OP_J', 1: 'TRIG_ENGINE_OP_K', 2: 'TRIG_ENGINE_OP_J_OR_K', 3: 'TRIG_ENGINE_OP_J_AND_K', 4: 'TRIG_ENGINE_OP_J_XOR_K', 5: 'TRIG_ENGINE_OP_J_AND_NOT_K', 6: 'TRIG_ENGINE_OP_NOT_J_AND_K' }) for i in ['1', '2']: self.add_parameter(name='trigger_engine' + i, parameter_class=AlazarParameter, label='Trigger Engine ' + i, unit=None, value='TRIG_ENGINE_' + ('J' if i == 0 else 'K'), byte_to_value_dict={ 0: 'TRIG_ENGINE_J', 1: 'TRIG_ENGINE_K' }) self.add_parameter(name='trigger_source' + i, parameter_class=AlazarParameter, label='Trigger Source ' + i, unit=None, value='EXTERNAL', byte_to_value_dict={ 0: 'CHANNEL_A', 1: 'CHANNEL_B', 2: 'EXTERNAL', 3: 'DISABLE' }) self.add_parameter(name='trigger_slope' + i, parameter_class=AlazarParameter, label='Trigger Slope ' + i, unit=None, value='TRIG_SLOPE_POSITIVE', byte_to_value_dict={ 1: 'TRIG_SLOPE_POSITIVE', 2: 'TRIG_SLOPE_NEGATIVE' }) self.add_parameter(name='trigger_level' + i, parameter_class=AlazarParameter, label='Trigger Level ' + i, unit=None, value=140, vals=validators.Ints(0, 255)) self.add_parameter(name='external_trigger_coupling', parameter_class=AlazarParameter, label='External Trigger Coupling', unit=None, value='DC', byte_to_value_dict={ 1: 'AC', 2: 'DC' }) self.add_parameter(name='external_trigger_range', parameter_class=AlazarParameter, label='External Trigger Range', unit=None, value='ETR_2V5', byte_to_value_dict={ 0: 'ETR_5V', 1: 'ETR_1V', 2: 'ETR_TTL', 3: 'ETR_2V5' }) self.add_parameter(name='trigger_delay', parameter_class=AlazarParameter, label='Trigger Delay', unit='Sample clock cycles', value=0, vals=validators.Ints(min_value=0)) # 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.add_parameter(name='timeout_ticks', parameter_class=AlazarParameter, label='Timeout Ticks', unit='10 us', value=0, vals=validators.Ints(min_value=0)) self.add_parameter(name='aux_io_mode', parameter_class=AlazarParameter, label='AUX I/O Mode', unit=None, value='AUX_IN_AUXILIARY', byte_to_value_dict={ 0: 'AUX_OUT_TRIGGER', 1: 'AUX_IN_TRIGGER_ENABLE', 13: 'AUX_IN_AUXILIARY' }) self.add_parameter(name='aux_io_param', parameter_class=AlazarParameter, label='AUX I/O Param', unit=None, value='NONE', byte_to_value_dict={ 0: 'NONE', 1: 'TRIG_SLOPE_POSITIVE', 2: 'TRIG_SLOPE_NEGATIVE' }) # ----- Parameters for the acquire function ----- self.add_parameter(name='mode', parameter_class=AlazarParameter, label='Acquisition mode', unit=None, value='NPT', byte_to_value_dict={ 0x200: 'NPT', 0x400: 'TS' }) self.add_parameter(name='samples_per_record', parameter_class=AlazarParameter, label='Samples per Record', unit=None, value=1024, vals=validators.Multiples( divisor=self.samples_divisor, min_value=256)) self.add_parameter(name='records_per_buffer', parameter_class=AlazarParameter, label='Records per Buffer', unit=None, value=10, vals=validators.Ints(min_value=0)) self.add_parameter(name='buffers_per_acquisition', parameter_class=AlazarParameter, label='Buffers per Acquisition', unit=None, value=10, vals=validators.Ints(min_value=0)) self.add_parameter(name='channel_selection', parameter_class=AlazarParameter, label='Channel Selection', unit=None, value='AB', byte_to_value_dict={ 1: 'A', 2: 'B', 3: 'AB' }) self.add_parameter(name='transfer_offset', parameter_class=AlazarParameter, label='Transfer Offset', unit='Samples', value=0, vals=validators.Ints(min_value=0)) self.add_parameter(name='external_startcapture', parameter_class=AlazarParameter, label='External Startcapture', unit=None, value='ENABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x1: 'ENABLED' }) self.add_parameter(name='enable_record_headers', parameter_class=AlazarParameter, label='Enable Record Headers', unit=None, value='DISABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x8: 'ENABLED' }) self.add_parameter(name='alloc_buffers', parameter_class=AlazarParameter, label='Alloc Buffers', unit=None, value='DISABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x20: 'ENABLED' }) self.add_parameter(name='fifo_only_streaming', parameter_class=AlazarParameter, label='Fifo Only Streaming', unit=None, value='DISABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x800: 'ENABLED' }) self.add_parameter(name='interleave_samples', parameter_class=AlazarParameter, label='Interleave Samples', unit=None, value='DISABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x1000: 'ENABLED' }) self.add_parameter(name='get_processed_data', parameter_class=AlazarParameter, label='Get Processed Data', unit=None, value='DISABLED', byte_to_value_dict={ 0x0: 'DISABLED', 0x2000: 'ENABLED' }) self.add_parameter(name='allocated_buffers', parameter_class=AlazarParameter, label='Allocated Buffers', unit=None, value=4, vals=validators.Ints(min_value=0)) self.add_parameter(name='buffer_timeout', parameter_class=AlazarParameter, label='Buffer Timeout', unit='ms', value=1000, vals=validators.Ints(min_value=0)) model = self.get_idn()['model'] if model != 'ATS9360': raise Exception("The Alazar board kind is not 'ATS9360'," " found '" + str(model) + "' instead.")