Source code for dwfpy.analog_input

"""
Analog Input module for Digilent WaveForms devices.
"""

#
# This file is part of dwfpy: https://github.com/mariusgreuel/dwfpy
# Copyright (C) 2019 Marius Greuel
#
# SPDX-License-Identifier: MIT
#

import ctypes
import time
from typing import Callable, Optional, Tuple, Union
import numpy as np
from . import bindings as api
from . import device as fwd  # pylint: disable=unused-import
from .constants import (
    AnalogInputCoupling,
    AcquisitionMode,
    FilterMode,
    Status,
    TriggerLengthCondition,
    TriggerSlope,
    TriggerSource,
    TriggerType,
)
from .exceptions import WaveformsError
from .helpers import Helpers
from .analog_recorder import AnalogRecorder


[docs]class AnalogInputTrigger: """Represents the trigger unit of an Analog Input module.""" def __init__(self, module): self._device = module.device @property def source(self) -> TriggerSource: """Gets or sets the current trigger source setting for the instrument.""" return TriggerSource(api.dwf_analog_in_trigger_source_get(self._device.handle)) @source.setter def source(self, value: TriggerSource) -> None: api.dwf_analog_in_trigger_source_set(self._device.handle, value) @property def position_min(self) -> float: """Gets the minimum supported trigger position in seconds.""" return api.dwf_analog_in_trigger_position_info(self._device.handle)[0] @property def position_max(self) -> float: """Gets the maximum supported trigger position in seconds.""" return api.dwf_analog_in_trigger_position_info(self._device.handle)[1] @property def position_steps(self) -> int: """Gets the number of trigger position steps.""" return int(api.dwf_analog_in_trigger_position_info(self._device.handle)[2]) @property def position(self) -> float: """Gets or sets the horizontal trigger position in seconds.""" return api.dwf_analog_in_trigger_position_get(self._device.handle) @position.setter def position(self, value: float) -> None: api.dwf_analog_in_trigger_position_set(self._device.handle, value) @property def actual_position(self) -> float: """Gets the actual trigger position in seconds.""" return api.dwf_analog_in_trigger_position_status(self._device.handle) @property def auto_timeout_min(self) -> float: """Gets the minimum auto trigger timeout in seconds.""" return api.dwf_analog_in_trigger_auto_timeout_info(self._device.handle)[0] @property def auto_timeout_max(self) -> float: """Gets the maximum auto trigger timeout in seconds.""" return api.dwf_analog_in_trigger_auto_timeout_info(self._device.handle)[1] @property def auto_timeout_steps(self) -> int: """Gets the number of adjustable steps for the auto trigger timeout.""" return int(api.dwf_analog_in_trigger_auto_timeout_info(self._device.handle)[2]) @property def auto_timeout(self) -> float: """Gets or sets the auto trigger timeout in seconds.""" return api.dwf_analog_in_trigger_auto_timeout_get(self._device.handle) @auto_timeout.setter def auto_timeout(self, value: float) -> None: api.dwf_analog_in_trigger_auto_timeout_set(self._device.handle, value) @property def hold_off_min(self) -> float: """Gets the minimum trigger hold-off time in seconds.""" return api.dwf_analog_in_trigger_hold_off_info(self._device.handle)[0] @property def hold_off_max(self) -> float: """Gets the maximum trigger hold-off time in seconds.""" return api.dwf_analog_in_trigger_hold_off_info(self._device.handle)[1] @property def hold_off_steps(self) -> int: """Gets the number of adjustable steps for the trigger hold-off time.""" return int(api.dwf_analog_in_trigger_hold_off_info(self._device.handle)[2]) @property def hold_off(self) -> float: """Gets or sets the trigger hold-off time in seconds.""" return api.dwf_analog_in_trigger_hold_off_get(self._device.handle) @hold_off.setter def hold_off(self, value: float) -> None: api.dwf_analog_in_trigger_hold_off_set(self._device.handle, value) @property def type_info(self) -> Tuple[TriggerType, ...]: """Gets the supported output types.""" return Helpers.map_enum_values( TriggerType, api.dwf_analog_in_trigger_type_info(self._device.handle) ) @property def type(self) -> TriggerType: """Gets or sets the output type.""" return TriggerType(api.dwf_analog_in_trigger_type_get(self._device.handle)) @type.setter def type(self, value: TriggerType) -> None: api.dwf_analog_in_trigger_type_set(self._device.handle, value) @property def channel_min(self) -> int: """Gets the minimum channel index that can be triggered on.""" return api.dwf_analog_in_trigger_channel_info(self._device.handle)[0] @property def channel_max(self) -> int: """Gets the maximum channel index that can be triggered on.""" return api.dwf_analog_in_trigger_channel_info(self._device.handle)[1] @property def channel(self) -> int: """Gets or sets the trigger channel.""" return api.dwf_analog_in_trigger_channel_get(self._device.handle) @channel.setter def channel(self, value: int) -> None: api.dwf_analog_in_trigger_channel_set(self._device.handle, value) @property def filter_info(self) -> Tuple[FilterMode, ...]: """Gets the supported trigger filters.""" return Helpers.map_enum_values( FilterMode, api.dwf_analog_in_trigger_filter_info(self._device.handle) ) @property def filter(self) -> FilterMode: """Gets or sets the trigger filter.""" return FilterMode(api.dwf_analog_in_trigger_filter_get(self._device.handle)) @filter.setter def filter(self, value: FilterMode) -> None: api.dwf_analog_in_trigger_filter_set(self._device.handle, value) @property def level_min(self) -> float: """Gets the minimum trigger voltage level.""" return api.dwf_analog_in_trigger_level_info(self._device.handle)[0] @property def level_max(self) -> float: """Gets the maximum trigger voltage level.""" return api.dwf_analog_in_trigger_level_info(self._device.handle)[1] @property def level_steps(self) -> int: """Gets the number of trigger voltage level steps.""" return int(api.dwf_analog_in_trigger_level_info(self._device.handle)[2]) @property def level(self) -> float: """Gets or sets the trigger voltage level in volts.""" return api.dwf_analog_in_trigger_level_get(self._device.handle) @level.setter def level(self, value: float) -> None: api.dwf_analog_in_trigger_level_set(self._device.handle, value) @property def hysteresis_min(self) -> float: """Gets the minimum trigger hysteresis level.""" return api.dwf_analog_in_trigger_hysteresis_info(self._device.handle)[0] @property def hysteresis_max(self) -> float: """Gets the maximum trigger hysteresis level.""" return api.dwf_analog_in_trigger_hysteresis_info(self._device.handle)[1] @property def hysteresis_steps(self) -> int: """Gets the number of trigger hysteresis level steps.""" return int(api.dwf_analog_in_trigger_hysteresis_info(self._device.handle)[2]) @property def hysteresis(self) -> float: """Gets or sets the trigger hysteresis level in volts.""" return api.dwf_analog_in_trigger_hysteresis_get(self._device.handle) @hysteresis.setter def hysteresis(self, value: float) -> None: api.dwf_analog_in_trigger_hysteresis_set(self._device.handle, value) @property def condition_info(self) -> Tuple[TriggerSlope, ...]: """Gets the supported trigger conditions.""" return Helpers.map_enum_values( TriggerSlope, api.dwf_analog_in_trigger_condition_info(self._device.handle) ) @property def condition(self) -> TriggerSlope: """Gets or sets the trigger condition.""" return TriggerSlope(api.dwf_analog_in_trigger_condition_get(self._device.handle)) @condition.setter def condition(self, value: TriggerSlope) -> None: api.dwf_analog_in_trigger_condition_set(self._device.handle, value) @property def length_min(self) -> float: """Gets the minimum trigger length in seconds.""" return api.dwf_analog_in_trigger_length_info(self._device.handle)[0] @property def length_max(self) -> float: """Gets the maximum trigger length in seconds.""" return api.dwf_analog_in_trigger_length_info(self._device.handle)[1] @property def length_steps(self) -> int: """Gets the number of trigger length steps.""" return int(api.dwf_analog_in_trigger_length_info(self._device.handle)[2]) @property def length(self) -> float: """Gets or sets the trigger length in seconds.""" return api.dwf_analog_in_trigger_length_get(self._device.handle) @length.setter def length(self, value: float) -> None: api.dwf_analog_in_trigger_length_set(self._device.handle, value) @property def length_condition_info(self) -> Tuple[TriggerLengthCondition, ...]: """Gets the supported trigger length conditions.""" return Helpers.map_enum_values( TriggerLengthCondition, api.dwf_analog_in_trigger_length_condition_info(self._device.handle), ) @property def length_condition(self) -> TriggerLengthCondition: """Gets or sets the trigger length condition.""" return TriggerLengthCondition( api.dwf_analog_in_trigger_length_condition_get(self._device.handle) ) @length_condition.setter def length_condition(self, value: TriggerLengthCondition) -> None: api.dwf_analog_in_trigger_length_condition_set(self._device.handle, value) @property def sampling_source(self) -> TriggerSource: """Gets or sets the acquisition data sampling source.""" return TriggerSource(api.dwf_analog_in_sampling_source_get(self._device.handle)) @sampling_source.setter def sampling_source(self, value: TriggerSource) -> None: api.dwf_analog_in_sampling_source_set(self._device.handle, value) @property def sampling_slope(self) -> TriggerSlope: """Gets or sets the sampling slope.""" return TriggerSlope(api.dwf_analog_in_sampling_slope_get(self._device.handle)) @sampling_slope.setter def sampling_slope(self, value: TriggerSlope) -> None: api.dwf_analog_in_sampling_slope_set(self._device.handle, value) @property def sampling_delay(self) -> float: """Gets or sets the sampling delay.""" return api.dwf_analog_in_sampling_delay_get(self._device.handle) @sampling_delay.setter def sampling_delay(self, value: float) -> None: api.dwf_analog_in_sampling_delay_set(self._device.handle, value)
[docs]class AnalogInputChannel: """Represents an Analog Input channel.""" def __init__(self, module, channel): self._device = module.device self._module = module self._channel = channel self._label = 'ch' + str(channel + 1) @property def device(self) -> 'fwd.Device': """Gets the device.""" return self._device @property def module(self) -> 'AnalogInput': """Gets the Analog Input module.""" return self._module @property def index(self) -> int: """Gets the channel index.""" return self._channel @property def label(self) -> str: """Gets or sets the channel label.""" return self._label @label.setter def label(self, value: str) -> None: self._label = value @property def enabled(self) -> bool: """Enables or disables the channel.""" return bool(api.dwf_analog_in_channel_enable_get(self._device.handle, self._channel)) @enabled.setter def enabled(self, value: bool) -> None: api.dwf_analog_in_channel_enable_set(self._device.handle, self._channel, value) @property def adc_bits(self) -> int: """Gets the number bits used by the ADC.""" return api.dwf_analog_in_bits_info(self._device.handle) @property def filter_info(self) -> Tuple[FilterMode, ...]: """Gets the supported acquisition filters.""" return Helpers.map_enum_values( FilterMode, api.dwf_analog_in_channel_filter_info(self._device.handle) ) @property def filter(self) -> FilterMode: """Gets or sets the acquisition filter.""" return FilterMode(api.dwf_analog_in_channel_filter_get(self._device.handle, self._channel)) @filter.setter def filter(self, value: FilterMode) -> None: api.dwf_analog_in_channel_filter_set(self._device.handle, self._channel, value) @property def range_info(self) -> Tuple[float, ...]: """Gets the supported channel ranges.""" volt_steps = (ctypes.c_double * 32)() steps = api.dwf_analog_in_channel_range_steps(self._device.handle, volt_steps) return tuple(volt_steps)[:steps] @property def range_min(self) -> float: """Gets the minimum channel range.""" return api.dwf_analog_in_channel_range_info(self._device.handle)[0] @property def range_max(self) -> float: """Gets the maximum channel range.""" return api.dwf_analog_in_channel_range_info(self._device.handle)[1] @property def range_steps(self) -> int: """Gets the number of channel range steps.""" return int(api.dwf_analog_in_channel_range_info(self._device.handle)[2]) @property def range(self) -> float: """Gets or sets the channel range.""" return api.dwf_analog_in_channel_range_get(self._device.handle, self._channel) @range.setter def range(self, value: float) -> None: api.dwf_analog_in_channel_range_set(self._device.handle, self._channel, value) @property def offset_min(self) -> float: """Gets the minimum supported offset voltage.""" return api.dwf_analog_in_channel_offset_info(self._device.handle)[0] @property def offset_max(self) -> float: """Gets the maximum supported offset voltage.""" return api.dwf_analog_in_channel_offset_info(self._device.handle)[1] @property def offset_steps(self) -> int: """Gets the number of adjustable steps.""" return int(api.dwf_analog_in_channel_offset_info(self._device.handle)[2]) @property def offset(self) -> float: """Gets or sets the channel offset in volts.""" return api.dwf_analog_in_channel_offset_get(self._device.handle, self._channel) @offset.setter def offset(self, value: float) -> None: api.dwf_analog_in_channel_offset_set(self._device.handle, self._channel, value) @property def attenuation(self) -> float: """Gets or sets the channel attenuation.""" return api.dwf_analog_in_channel_attenuation_get(self._device.handle, self._channel) @attenuation.setter def attenuation(self, value: float) -> None: api.dwf_analog_in_channel_attenuation_set(self._device.handle, self._channel, value) @property def bandwidth(self) -> float: """Gets or sets the channel bandwidth in Hz.""" return api.dwf_analog_in_channel_bandwidth_get(self._device.handle, self._channel) @bandwidth.setter def bandwidth(self, value: float) -> None: api.dwf_analog_in_channel_bandwidth_set(self._device.handle, self._channel, value) @property def impedance(self) -> float: """Gets or sets the channel impedance in Ohms.""" return api.dwf_analog_in_channel_impedance_get(self._device.handle, self._channel) @impedance.setter def impedance(self, value: float) -> None: api.dwf_analog_in_channel_impedance_set(self._device.handle, self._channel, value) @property def coupling_info(self) -> Tuple[AnalogInputCoupling, ...]: """Gets the supported channel coupling modes.""" return Helpers.map_enum_values( AnalogInputCoupling, api.dwf_analog_in_channel_coupling_info(self._device.handle) ) @property def coupling(self) -> AnalogInputCoupling: """Gets or sets the channel coupling.""" return AnalogInputCoupling( api.dwf_analog_in_channel_coupling_get(self._device.handle, self._channel) ) @coupling.setter def coupling(self, value: AnalogInputCoupling) -> None: api.dwf_analog_in_channel_coupling_set(self._device.handle, self._channel, value)
[docs] def get_sample(self) -> float: """Gets the last ADC conversion sample. Notes ----- Before calling this function, call the 'read_status()' function to read the data from the device. """ return api.dwf_analog_in_status_sample(self._device.handle, self._channel)
[docs] def get_data(self, first_sample: int = 0, sample_count: int = -1, raw: bool = False): """Gets the acquired data samples. Notes ----- Before calling this function, call the 'read_status()' function to read the data from the device. """ if sample_count < 0: sample_count = self._device.analog_input.valid_samples if raw: samples16 = np.empty(sample_count, dtype=np.short) api.dwf_analog_in_status_data16( self._device.handle, self._channel, samples16.ctypes.data_as(ctypes.POINTER(ctypes.c_short)), first_sample, sample_count, ) return samples16 else: samples = np.empty(sample_count, dtype=np.double) api.dwf_analog_in_status_data2( self._device.handle, self._channel, samples.ctypes.data_as(ctypes.POINTER(ctypes.c_double)), first_sample, sample_count, ) return samples
[docs] def get_noise(self, first_sample: int = 0, sample_count: int = -1): """Gets the acquired noise samples. Notes ----- Before calling this function, call the 'read_status()' function to read the data from the device. """ if sample_count < 0: sample_count = self._device.analog_input.valid_samples min_samples = (ctypes.c_double * sample_count)() max_samples = (ctypes.c_double * sample_count)() api.dwf_analog_in_status_noise( self._device.handle, self._channel, min_samples, max_samples, first_sample, sample_count ) return np.array((min_samples, max_samples)).T
# pylint: disable-next=redefined-builtin
[docs] def setup( self, range: Optional[float] = None, offset: Optional[float] = None, coupling: Optional[Union[str, AnalogInputCoupling]] = None, bandwidth: Optional[float] = None, attenuation: Optional[float] = None, impedance: Optional[float] = None, filter: Optional[Union[str, FilterMode]] = None, enabled: bool = True, ) -> None: """Sets up the channel for data acquisition. Parameters ---------- range : float, optional The channel range in Volts. offset : float, optional The channel offset in Volts. coupling : str or AnalogInputCoupling, optional The channel coupling. Can be 'dc' or 'ac'. bandwidth : float, optional The channel bandwidth in Hz. attenuation : float, optional The channel attenuation. impedance : float, optional The channel impedance in Ohms. filter : str or FilterMode, optional The channel acquisition filter. Can be 'decimate', 'average', or 'min-max'. enabled : bool, optional If True, then the channel is enabled (default True). """ if range is not None: self.range = range if offset is not None: self.offset = offset if coupling is not None: self.coupling = Helpers.map_coupling(coupling) if bandwidth is not None: self.bandwidth = bandwidth if attenuation is not None: self.attenuation = attenuation if impedance is not None: self.impedance = impedance if filter is not None: self.filter = Helpers.map_filter(filter) if enabled is not None: self.enabled = enabled
[docs]class AnalogInput: """Analog Input module (Oscilloscope).""" def __init__(self, device): self._device = device self._trigger = AnalogInputTrigger(self) self._channels = tuple( AnalogInputChannel(self, i) for i in range(api.dwf_analog_in_channel_count(self._device.handle)) ) def __enter__(self): return self def __exit__(self, exception_type, exception_value, traceback) -> None: del exception_type, exception_value, traceback self.reset() @property def device(self) -> 'fwd.Device': """Gets the device.""" return self._device @property def trigger(self) -> AnalogInputTrigger: """Gets the trigger unit.""" return self._trigger @property def channels(self) -> Tuple[AnalogInputChannel, ...]: """Gets a collection of Analog Input channels.""" return self._channels def __getitem__(self, key) -> AnalogInputChannel: if isinstance(key, int): return self._channels[key] if isinstance(key, str): for channel in self._channels: if channel.label == key: return channel raise IndexError(key) @property def remaining_samples(self) -> int: """Gets the number of samples left in the acquisition. Notes ----- Before calling this function, call the 'read_status()' function to read the data from the device. """ return api.dwf_analog_in_status_samples_left(self._device.handle) @property def valid_samples(self) -> int: """Gets the number of valid/acquired data samples. Notes ----- Before calling this function, call the 'read_status()' function to read the data from the device. """ return api.dwf_analog_in_status_samples_valid(self._device.handle) @property def write_index(self) -> int: """Gets the buffer write pointer, which is needed in scan_screen acquisition mode to display the scan bar. Notes ----- Before calling this function, call the 'read_status()' function to read the data from the device. """ return api.dwf_analog_in_status_index_write(self._device.handle) @property def auto_triggered(self) -> bool: """Returns True if the acquisition is auto triggered. Notes ----- Before calling this function, call the 'read_status()' function to read the data from the device. """ return bool(api.dwf_analog_in_status_auto_triggered(self._device.handle)) @property def time(self) -> Tuple[int, int, int]: """Gets instrument trigger time information. Notes ----- Before calling this function, call the 'read_status()' function to read the data from the device. """ return api.dwf_analog_in_status_time(self._device.handle) @property def record_status(self) -> Tuple[int, int, int]: """Gets information about the recording process: Returns (available_samples, lost_samples, corrupted_samples) Notes ----- Before calling this function, call the 'read_status()' function to read the data from the device. """ return api.dwf_analog_in_status_record(self._device.handle) @property def record_length(self) -> float: """Gets or sets the record length in seconds.""" return api.dwf_analog_in_record_length_get(self._device.handle) @record_length.setter def record_length(self, value: float) -> None: api.dwf_analog_in_record_length_set(self._device.handle, value) @property def counter_max(self) -> float: """Gets the maximum count value.""" return api.dwf_analog_in_counter_info(self._device.handle)[0] @property def timeout_max(self) -> float: """Gets the maximum timeout value.""" return api.dwf_analog_in_counter_info(self._device.handle)[1] @property def counter(self) -> float: """Gets or sets the current timeout in seconds.""" return api.dwf_analog_in_counter_get(self._device.handle) @counter.setter def counter(self, value: float) -> None: api.dwf_analog_in_counter_set(self._device.handle, value) @property def counter_status(self) -> Tuple[float, float, int]: """Gets the count, frequency and tick values.""" return api.dwf_analog_in_counter_status(self._device.handle) @property def frequency_min(self) -> float: """Gets the minimum supported sample frequency.""" return api.dwf_analog_in_frequency_info(self._device.handle)[0] @property def frequency_max(self) -> float: """Gets the maximum supported sample frequency.""" return api.dwf_analog_in_frequency_info(self._device.handle)[1] @property def frequency(self) -> float: """Gets or sets the configured sample frequency in Hz.""" return api.dwf_analog_in_frequency_get(self._device.handle) @frequency.setter def frequency(self, value: float) -> None: api.dwf_analog_in_frequency_set(self._device.handle, value) @property def buffer_size_min(self) -> int: """Gets the minimum supported buffer size.""" return api.dwf_analog_in_buffer_size_info(self._device.handle)[0] @property def buffer_size_max(self) -> int: """Gets the maximum supported buffer size.""" return api.dwf_analog_in_buffer_size_info(self._device.handle)[1] @property def buffer_size(self) -> int: """Gets or sets the buffer size.""" return api.dwf_analog_in_buffer_size_get(self._device.handle) @buffer_size.setter def buffer_size(self, value: int) -> None: api.dwf_analog_in_buffer_size_set(self._device.handle, value) @property def noise_buffer_size_max(self) -> int: """Gets the maximum supported noise buffer size.""" return api.dwf_analog_in_noise_size_info(self._device.handle) @property def noise_buffer_size(self) -> int: """Gets or sets the noise buffer size.""" return api.dwf_analog_in_noise_size_get(self._device.handle) @noise_buffer_size.setter def noise_buffer_size(self, value: int) -> None: api.dwf_analog_in_noise_size_set(self._device.handle, value) @property def acquisition_mode_info(self) -> Tuple[AcquisitionMode, ...]: """Gets the supported acquisition modes.""" return Helpers.map_enum_values( AcquisitionMode, api.dwf_analog_in_acquisition_mode_info(self._device.handle) ) @property def acquisition_mode(self) -> AcquisitionMode: """Gets or sets the acquisition mode.""" return AcquisitionMode(api.dwf_analog_in_acquisition_mode_get(self._device.handle)) @acquisition_mode.setter def acquisition_mode(self, value: AcquisitionMode) -> None: api.dwf_analog_in_acquisition_mode_set(self._device.handle, value)
[docs] def reset(self) -> None: """Resets and configures all instrument parameters to default values.""" api.dwf_analog_in_reset(self._device.handle)
[docs] def configure(self, reconfigure: bool = False, start: bool = False) -> None: """Configures the instrument and optionally starts the acquisition.""" api.dwf_analog_in_configure(self._device.handle, reconfigure, start)
[docs] def force_trigger(self) -> None: """Force trigger of instrument.""" api.dwf_analog_in_trigger_force(self._device.handle)
[docs] def read_status(self, read_data: bool = False) -> Status: """Gets the acquisition state and optionally reads the data.""" return Status(api.dwf_analog_in_status(self._device.handle, read_data))
[docs] def wait_for_status(self, status, read_data: bool = False) -> None: """Waits for the specified acquisition state.""" while self.read_status(read_data=read_data) != status: time.sleep(0.001)
# pylint: disable-next=redefined-builtin
[docs] def setup_channel( self, channel: int, range: Optional[float] = None, offset: Optional[float] = None, coupling: Optional[Union[str, AnalogInputCoupling]] = None, bandwidth: Optional[float] = None, attenuation: Optional[float] = None, impedance: Optional[float] = None, filter: Optional[Union[str, FilterMode]] = None, enabled: bool = True, ) -> None: """Sets up a channel for data acquisition. Parameters ---------- channel : int The channel to setup. range : float, optional The channel range in Volts. offset : float, optional The channel offset in Volts. coupling : str or AnalogInputCoupling, optional The channel coupling. Can be 'dc' or 'ac'. bandwidth : float, optional The channel bandwidth in Hz. attenuation : float, optional The channel attenuation. impedance : float, optional The channel impedance in Ohms. filter : str or FilterMode, optional The channel acquisition filter. Can be 'decimate', 'average', or 'min-max'. enabled : bool, optional If True, then the channel is enabled (default True). """ self.channels[channel].setup( range=range, offset=offset, coupling=coupling, bandwidth=bandwidth, attenuation=attenuation, impedance=impedance, filter=filter, enabled=enabled, )
[docs] def setup_edge_trigger( self, channel: int, slope: Optional[Union[str, TriggerSlope]] = None, level: Optional[float] = None, hysteresis: Optional[float] = None, position: Optional[float] = None, hold_off: Optional[float] = None, mode: Optional[str] = None, ) -> None: """Trigger upon a certain voltage level in the positive or negative slope of the waveform. Parameters ---------- channel : int The source channel used for triggering. slope : str or TriggerSlope, optional The trigger slope. Can be 'rising', 'falling', or 'either'. level : float, optional The trigger level in Volts. hysteresis : float, optional The trigger hysteresis in Volts. position : float, optional The horizontal trigger position in seconds. hold_off : float, optional The trigger hold-off time in seconds. mode : str, optional The trigger mode. Can be 'normal' or 'auto'. """ self.trigger.source = TriggerSource.DETECTOR_ANALOG_IN self.trigger.type = TriggerType.EDGE self._set_trigger_parameter( channel=channel, condition=slope, level=level, hysteresis=hysteresis, position=position, hold_off=hold_off, mode=mode, )
[docs] def setup_pulse_trigger( self, channel: int, condition: Optional[Union[str, TriggerSlope]] = None, length_condition: Optional[Union[str, TriggerLengthCondition]] = None, length: Optional[float] = None, level: Optional[float] = None, hysteresis: Optional[float] = None, position: Optional[float] = None, hold_off: Optional[float] = None, mode: Optional[str] = None, ) -> None: """Trigger upon a positive or negative pulse width when measured at a certain voltage level. Parameters ---------- channel : int The source channel used for triggering. condition : str, optional The trigger condition. Can be 'positive' or 'negative'. length_condition : str, optional The trigger length condition. Can be 'less', 'timeout', or 'more'. length : float, optional The pulse length in seconds. level : float, optional The trigger level in Volts. hysteresis : float, optional The trigger hysteresis in Volts. position : float, optional The horizontal trigger position in seconds. hold_off : float, optional The trigger hold-off time in seconds. mode : str, optional The trigger mode. Can be 'normal' or 'auto'. """ self.trigger.source = TriggerSource.DETECTOR_ANALOG_IN self.trigger.type = TriggerType.PULSE self._set_trigger_parameter( channel=channel, condition=condition, length_condition=length_condition, length=length, level=level, hysteresis=hysteresis, position=position, hold_off=hold_off, mode=mode, )
[docs] def setup_transition_trigger( self, channel: int, condition: Optional[Union[str, TriggerSlope]] = None, length_condition: Optional[Union[str, TriggerLengthCondition]] = None, length: Optional[float] = None, level: Optional[float] = None, hysteresis: Optional[float] = None, position: Optional[float] = None, hold_off: Optional[float] = None, mode: Optional[str] = None, ) -> None: """Sets up a transition trigger. Parameters ---------- channel : int The source channel used for triggering. condition : str, optional The trigger condition. Can be 'rising', 'falling', or 'either'. length_condition : str, optional The trigger length condition. Can be 'less', 'timeout', or 'more'. length : float, optional The transition length in seconds. level : float, optional The trigger level in Volts. hysteresis : float, optional The trigger hysteresis in Volts. position : float, optional The horizontal trigger position in seconds. hold_off : float, optional The trigger hold-off time in seconds. mode : str, optional The trigger mode. Can be 'normal' or 'auto'. """ self.trigger.source = TriggerSource.DETECTOR_ANALOG_IN self.trigger.type = TriggerType.TRANSITION self._set_trigger_parameter( channel=channel, condition=condition, length_condition=length_condition, length=length, level=level, hysteresis=hysteresis, position=position, hold_off=hold_off, mode=mode, )
[docs] def setup_window_trigger( self, channel: int, condition: Optional[Union[str, TriggerSlope]] = None, length: Optional[float] = None, level: Optional[float] = None, hysteresis: Optional[float] = None, position: Optional[float] = None, hold_off: Optional[float] = None, mode: Optional[str] = None, ) -> None: """Trigger upon a signal entering or exiting a window at certain voltage thresholds. Parameters ---------- channel : int The source channel used for triggering. condition : str, optional The trigger condition. Can be 'entering' or 'exiting'. length : float, optional The window length in seconds. level : float, optional The trigger level in Volts. hysteresis : float, optional The trigger hysteresis in Volts. position : float, optional The horizontal trigger position in seconds. hold_off : float, optional The trigger hold-off time in seconds. mode : str, optional The trigger mode. Can be 'normal' or 'auto'. """ self.trigger.source = TriggerSource.DETECTOR_ANALOG_IN self.trigger.type = TriggerType.WINDOW self._set_trigger_parameter( channel=channel, condition=condition, length=length, level=level, hysteresis=hysteresis, position=position, hold_off=hold_off, mode=mode, )
def _set_trigger_parameter( self, channel: Optional[int] = None, condition: Optional[Union[str, TriggerSlope]] = None, length_condition: Optional[Union[str, TriggerLengthCondition]] = None, length: Optional[float] = None, level: Optional[float] = None, hysteresis: Optional[float] = None, position: Optional[float] = None, hold_off: Optional[float] = None, mode: Optional[str] = None, ) -> None: if channel is not None: self.trigger.channel = self[channel].index if condition is not None: self.trigger.condition = Helpers.map_trigger_slope(condition) if length_condition is not None: self.trigger.length_condition = Helpers.map_trigger_length_condition(length_condition) if length is not None: self.trigger.length = length if level is not None: self.trigger.level = level if hysteresis is not None: self.trigger.hysteresis = hysteresis if position is not None: self.trigger.position = position if hold_off is not None: self.trigger.hold_off = hold_off if mode is not None: if mode == 'normal': self.trigger.auto_timeout = 0 elif mode == 'auto': self.trigger.auto_timeout = 1 else: raise WaveformsError('Invalid mode.')
[docs] def setup_acquisition( self, mode: Optional[Union[str, AcquisitionMode]] = None, sample_rate: Optional[float] = None, buffer_size: Optional[Union[int, float]] = None, record_length: Optional[float] = None, configure: bool = False, start: bool = False, ) -> None: """Sets up a new data acquisition. Parameters ---------- mode : str or AcquisitionMode, optional The sampling mode. Can be 'single', 'scan-shift', 'scan-screen', or 'record'. sample_rate : float, optional The sampling rate in Hz. buffer_size : int or float, optional The buffer size. record_length : float, optional The record length in seconds. configure : bool, optional If True, then the instrument is configured (default False). start : bool, optional If True, then the acquisition is started (default False). """ if mode is not None: self.acquisition_mode = Helpers.map_acquisition_mode(mode) if sample_rate is not None: self.frequency = sample_rate if buffer_size is not None: self.buffer_size = int(buffer_size) if record_length is not None: self.record_length = record_length if configure or start: self.configure(reconfigure=configure, start=start)
[docs] def single( self, sample_rate: Optional[float] = None, buffer_size: Optional[Union[int, float]] = None, continuous: bool = True, configure: bool = False, start: bool = False, ) -> None: """Starts a single data acquisition. Parameters ---------- sample_rate : float, optional The sampling rate in Hz. buffer_size : int or float, optional The buffer size. continuous : bool, optional If True, then the instrument is rearmed after the data is retrieved. (default True). configure : bool, optional If True, then the instrument is configured (default False). start : bool, optional If True, then the acquisition is started (default False). """ self.setup_acquisition( AcquisitionMode.SINGLE if continuous else AcquisitionMode.SINGLE1, sample_rate=sample_rate, buffer_size=buffer_size, configure=configure, start=start, ) if start: self.wait_for_status(Status.DONE, read_data=True)
[docs] def scan_shift( self, sample_rate: Optional[float] = None, buffer_size: Optional[Union[int, float]] = None, configure: bool = False, start: bool = False, ) -> None: """Starts a scan-shift data acquisition. Parameters ---------- sample_rate : float, optional The sampling rate in Hz. buffer_size : int or float, optional The buffer size. configure : bool, optional If True, then the instrument is configured (default False). start : bool, optional If True, then the acquisition is started (default False). """ self.setup_acquisition( AcquisitionMode.SCAN_SHIFT, sample_rate=sample_rate, buffer_size=buffer_size, configure=configure, start=start, )
[docs] def scan_screen( self, sample_rate: Optional[float] = None, buffer_size: Optional[Union[int, float]] = None, configure: bool = False, start: bool = False, ) -> None: """Starts a scan-screen data acquisition. Parameters ---------- sample_rate : float, optional The sampling rate in Hz. buffer_size : int or float, optional The buffer size. configure : bool, optional If True, then the instrument is configured (default False). start : bool, optional If True, then the acquisition is started (default False). """ self.setup_acquisition( AcquisitionMode.SCAN_SCREEN, sample_rate=sample_rate, buffer_size=buffer_size, configure=configure, start=start, )
[docs] def record( self, sample_rate: Optional[float] = None, length: Optional[float] = None, buffer_size: Optional[Union[int, float]] = None, callback: Optional[Callable[['AnalogRecorder'], bool]] = None, configure: bool = False, start: bool = False, ) -> AnalogRecorder: """Starts a data recording. Parameters ---------- sample_rate : float, optional The sampling rate in Hz. length : float, optional The recording length in seconds. buffer_size : int or float, optional The buffer size. configure : bool, optional If True, then the instrument is configured (default False). start : bool, optional If True, then the recording is started (default False). Returns ------- AnalogRecorder The recorder instance. """ self.setup_acquisition( AcquisitionMode.RECORD, sample_rate=sample_rate, record_length=length, buffer_size=buffer_size, configure=configure, ) recorder = AnalogRecorder(self) if start: recorder.record(callback) return recorder