Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
4d38383
Modifications to `get_capabilities.py` to handle DAQs to include details
dihm May 5, 2021
5193aa9
Modified NI_DAQmx to handle differentially terminated analog inputs.
dihm May 5, 2021
aeaf81b
Add support of AI pseudoDiff termination.
dihm May 24, 2021
0a5f1d6
Configure get_capabilities to recognize PseudoDiff as a default AI_term.
dihm May 24, 2021
d4eaf67
Add ability for DAQmx device to specify analog input delay in terms of
dihm May 24, 2021
539f328
Fix AI_start_delay_ticks logic so it actually works.
dihm May 26, 2021
3116af4
Update docstring to include new DAQmx features.
dihm Oct 21, 2021
5be6992
Add more robust backwards compatibility checks for installations
dihm Oct 21, 2021
05146dd
Update capabilities to include PXIe-4499 and USB-6363
dihm Nov 8, 2021
f138144
Add nominal support for analog inputs with the NRSE termination.
dihm Nov 8, 2021
0767130
Adding explanatory warnings to the backwards compatibility code instr…
dihm Nov 8, 2021
be71723
Fix extremely bad merge conflict resolution from #70.
dihm Nov 8, 2021
2f5393c
Update existing capabilities.json and pre-generated models with new
dihm Nov 8, 2021
7123c4c
Update version tag of NI_DAQmx to 1.1.0 to denote semi-significant ch…
dihm Nov 8, 2021
81b411d
Updating to be more clear about how AI_start_delay is calculated,
dihm Nov 8, 2021
052a0f0
Fix bad logic in determining where things occur.
dihm Nov 8, 2021
9a4d0a1
Fix muffed indentation error.
dihm Nov 8, 2021
7be7413
Updating docstrings.
dihm Nov 29, 2021
4ea4dc2
Fixing docstring formatting.
dihm Nov 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions labscript_devices/NI_DAQmx/blacs_tabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from blacs.device_base_class import DeviceTab
from .utils import split_conn_AO, split_conn_DO
from . import models
import warnings


class NI_DAQmxTab(DeviceTab):
Expand All @@ -41,6 +42,17 @@ def initialise_GUI(self):

num_AO = properties['num_AO']
num_AI = properties['num_AI']
try:
AI_chans = properties['AI_chans']
except KeyError:
# new code being run on older model specification file
# assume legacy behavior, warn user to update
AI_chans = [f'ai{i:d}' for i in range(num_AI)]
msg = """Connection table was compiled with old model specifications for {0}.
Please recompile the connection table.
"""
warnings.warn(dedent(msg.format(properties['MAX_name'])), FutureWarning)

ports = properties['ports']
num_CI = properties['num_CI']

Expand Down Expand Up @@ -187,8 +199,11 @@ def initialise_GUI(self):
{
'MAX_name': self.MAX_name,
'num_AI': num_AI,
'AI_chans': AI_chans,
'AI_term': properties['AI_term'],
'AI_range': properties['AI_range'],
'AI_start_delay': properties['AI_start_delay'],
'AI_start_delay_ticks': properties['AI_start_delay_ticks'],
'clock_terminal': clock_terminal,
},
)
Expand Down
16 changes: 14 additions & 2 deletions labscript_devices/NI_DAQmx/blacs_workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ def init(self):

# Hard coded for now. Perhaps we will add functionality to enable
# and disable inputs in manual mode, and adjust the rate:
self.manual_mode_chans = ['ai%d' % i for i in range(self.num_AI)]
self.manual_mode_chans = self.AI_chans
self.manual_mode_rate = 1000

# An event for knowing when the wait durations are known, so that we may use
Expand Down Expand Up @@ -471,11 +471,20 @@ def start_task(self, chans, rate):
self.read_array = np.zeros((num_samples, len(chans)), dtype=np.float64)
self.task = Task()

if self.AI_term == 'RSE':
term = DAQmx_Val_RSE
elif self.AI_term == 'NRSE':
term = DAQmx_Val_NRSE
elif self.AI_term == 'Diff':
term = DAQmx_Val_Diff
elif self.AI_term == 'PseudoDiff':
term = DAQmx_Val_PseudoDiff

for chan in chans:
self.task.CreateAIVoltageChan(
self.MAX_name + '/' + chan,
"",
DAQmx_Val_RSE,
term,
self.AI_range[0],
self.AI_range[1],
DAQmx_Val_Volts,
Expand Down Expand Up @@ -527,6 +536,9 @@ def transition_to_buffered(self, device_name, h5file, initial_values, fresh):
self.buffered_chans = sorted(set(chans), key=split_conn_AI)
self.h5_file = h5file
self.buffered_rate = device_properties['acquisition_rate']
if device_properties['start_delay_ticks']:
# delay is defined in sample clock ticks, calculate in sec and save for later
self.AI_start_delay = self.AI_start_delay_ticks*self.buffered_rate
self.acquired_data = []
# Stop the manual mode task and start the buffered mode task:
self.stop_task()
Expand Down
62 changes: 56 additions & 6 deletions labscript_devices/NI_DAQmx/labscript_devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# #
#####################################################################

__version__ = '1.0.0'
__version__ = '1.1.0'


from labscript import (
Expand All @@ -30,6 +30,7 @@
from labscript_utils import dedent
from .utils import split_conn_DO, split_conn_AO, split_conn_AI
import numpy as np
import warnings

_ints = {8: np.uint8, 16: np.uint16, 32: np.uint32, 64: np.uint64}

Expand Down Expand Up @@ -59,6 +60,9 @@ class NI_DAQmx(IntermediateDevice):
"clock_mirror_terminal",
"AI_range",
"AI_start_delay",
"AI_start_delay_ticks",
"AI_term",
"AI_chans",
"AO_range",
"max_AI_multi_chan_rate",
"max_AI_single_chan_rate",
Expand All @@ -72,11 +76,12 @@ class NI_DAQmx(IntermediateDevice):
"supports_buffered_AO",
"supports_buffered_DO",
"supports_semiperiod_measurement",
"supports_simultaneous_AI_sampling",
"clock_limit",
"wait_monitor_minimum_pulse_width",
"wait_monitor_supports_wait_completed_events",
],
"device_properties": ["acquisition_rate"],
"device_properties": ["acquisition_rate","start_delay_ticks"],
}
)
def __init__(
Expand All @@ -90,7 +95,11 @@ def __init__(
clock_mirror_terminal=None,
acquisition_rate=None,
AI_range=None,
AI_range_Diff=None,
AI_start_delay=0,
AI_start_delay_ticks=None,
AI_term='RSE',
AI_term_cfg=None,
AO_range=None,
max_AI_multi_chan_rate=None,
max_AI_single_chan_rate=None,
Expand All @@ -104,6 +113,7 @@ def __init__(
supports_buffered_AO=False,
supports_buffered_DO=False,
supports_semiperiod_measurement=False,
supports_simultaneous_AI_sampling=False,
**kwargs
):
"""Generic class for NI_DAQmx devices.
Expand All @@ -125,8 +135,20 @@ def __init__(
acquisiton_rate (float, optional): Default sample rate of inputs.
AI_range (iterable, optional): A `[Vmin, Vmax]` pair that sets the analog
input voltage range for all analog inputs.
AI_range_Diff (iterable, optional): A `[Vmin, Vmax]` pair that sets the analog
input voltage range for all analog inputs when using Differential termination.
AI_start_delay (float, optional): Time in seconds between start of an
analog input task starting and the first sample.
AI_start_delay_ticks (int, optional): Time in sample clock periods between
start of an analog input task starting and the first sample. To use
this method, `AI_start_delay` must be set to `None`. This is necessary
for DAQs that employ delta ADCs.
AI_term (str, optional): Configures the analog input termination for all
analog inputs. Must be supported by the device. Supported options are
`'RSE'`, `'NRSE'` `'Diff'`, and '`PseudoDiff'`.
AI_term_cfg (dict, optional): Dictionary of analog input channels and their
supported terminations. Best to use `get_capabilities.py` to introspect
these.
AO_range (iterable, optional): A `[Vmin, Vmax]` pair that sets the analog
output voltage range for all analog outputs.
max_AI_multi_chan_rate (float, optional): Max supported analog input
Expand All @@ -148,7 +170,7 @@ def __init__(
buffered output
supports_buffered_DO (bool, optional): True if digital outputs support
buffered output
supports_semiperiod_measurement (bool, optional): True if deviec supports
supports_semiperiod_measurement (bool, optional): True if device supports
semi-period measurements

"""
Expand Down Expand Up @@ -192,12 +214,39 @@ def __init__(
self.max_DO_sample_rate = max_DO_sample_rate
self.min_semiperiod_measurement = min_semiperiod_measurement
self.num_AI = num_AI
# special handling for AI termination configurations
self.AI_term = AI_term
if AI_term_cfg == None:
# assume legacy configuration if none provided
AI_term_cfg = {f'ai{i:d}': ['RSE'] for i in range(num_AI)}
# warn user to update their local model specs
msg = """Model specifications for {} needs to be updated.
Please run the `get_capabilites.py` and `generate_subclasses.py`
scripts or define the `AI_Term_Cfg` kwarg for your device.
"""
warnings.warn(dedent(msg.format(self.description)), FutureWarning)
self.AI_chans = [key for key,val in AI_term_cfg.items() if self.AI_term in val]
if not len(self.AI_chans):
msg = """AI termination {0} not supported by this device."""
raise LabscriptError(dedent(msg.format(AI_term)))
if AI_term == 'Diff':
self.AI_range = AI_range_Diff
if AI_start_delay is None:
if AI_start_delay_ticks is not None:
# Tell blacs_worker to use AI_start_delay_ticks to define delay
self.start_delay_ticks = True
else:
raise LabscriptError("You have specified `AI_start_delay = None` but have not provided `AI_start_delay_ticks`.")
else:
# Tells blacs_worker to use AI_start_delay to define delay
self.start_delay_ticks = False
self.num_AO = num_AO
self.num_CI = num_CI
self.ports = ports if ports is not None else {}
self.supports_buffered_AO = supports_buffered_AO
self.supports_buffered_DO = supports_buffered_DO
self.supports_semiperiod_measurement = supports_semiperiod_measurement
self.supports_simultaneous_AI_sampling = supports_simultaneous_AI_sampling

if self.supports_buffered_DO and self.supports_buffered_AO:
self.clock_limit = min(self.max_DO_sample_rate, self.max_AO_sample_rate)
Expand Down Expand Up @@ -291,8 +340,7 @@ def add_device(self, device):
buffered output"""
raise ValueError(dedent(msg) % port_str)
elif isinstance(device, AnalogIn):
ai_num = split_conn_AI(device.connection)
if ai_num >= self.num_AI:
if device.connection not in self.AI_chans:
msg = """Cannot add analog input with connection string '%s' to device
with num_AI=%d"""
raise ValueError(dedent(msg) % (device.connection, self.num_AI))
Expand Down Expand Up @@ -352,7 +400,9 @@ def _check_AI_not_too_fast(self, AI_table):
# Either no AI in use, or already checked against single channel rate in
# __init__.
return
if self.acquisition_rate <= self.max_AI_multi_chan_rate / n:
if self.supports_simultaneous_AI_sampling and self.acquisition_rate <= self.max_AI_multi_chan_rate:
return
elif self.acquisition_rate <= self.max_AI_multi_chan_rate / n:
return
msg = """Requested acqusition_rate %f for device %s with %d analog input
channels in use is too fast. Device supports a rate of %f per channel when
Expand Down
21 changes: 21 additions & 0 deletions labscript_devices/NI_DAQmx/models/NI_PCI_6251.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,27 @@
#:
CAPABILITIES = {
'AI_range': [-10.0, 10.0],
'AI_range_Diff': [-10.0, 10.0],
'AI_start_delay': 2.5e-07,
'AI_term': 'RSE',
'AI_term_cfg': {
'ai0': ['RSE', 'NRSE', 'Diff'],
'ai1': ['RSE', 'NRSE', 'Diff'],
'ai10': ['RSE', 'NRSE'],
'ai11': ['RSE', 'NRSE'],
'ai12': ['RSE', 'NRSE'],
'ai13': ['RSE', 'NRSE'],
'ai14': ['RSE', 'NRSE'],
'ai15': ['RSE', 'NRSE'],
'ai2': ['RSE', 'NRSE', 'Diff'],
'ai3': ['RSE', 'NRSE', 'Diff'],
'ai4': ['RSE', 'NRSE', 'Diff'],
'ai5': ['RSE', 'NRSE', 'Diff'],
'ai6': ['RSE', 'NRSE', 'Diff'],
'ai7': ['RSE', 'NRSE', 'Diff'],
'ai8': ['RSE', 'NRSE'],
'ai9': ['RSE', 'NRSE'],
},
'AO_range': [-10.0, 10.0],
'max_AI_multi_chan_rate': 1000000.0,
'max_AI_single_chan_rate': 1250000.0,
Expand All @@ -43,6 +63,7 @@
'supports_buffered_AO': True,
'supports_buffered_DO': True,
'supports_semiperiod_measurement': True,
'supports_simultaneous_AI_sampling': False,
}


Expand Down
1 change: 1 addition & 0 deletions labscript_devices/NI_DAQmx/models/NI_PCI_6534.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#:
CAPABILITIES = {
'AI_range': None,
'AI_range_Diff': None,
'AI_start_delay': None,
'AO_range': None,
'max_AI_multi_chan_rate': None,
Expand Down
1 change: 1 addition & 0 deletions labscript_devices/NI_DAQmx/models/NI_PCI_6713.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#:
CAPABILITIES = {
'AI_range': None,
'AI_range_Diff': None,
'AI_start_delay': None,
'AO_range': [-10.0, 10.0],
'max_AI_multi_chan_rate': None,
Expand Down
1 change: 1 addition & 0 deletions labscript_devices/NI_DAQmx/models/NI_PCI_6733.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#:
CAPABILITIES = {
'AI_range': None,
'AI_range_Diff': None,
'AI_start_delay': None,
'AO_range': [-10.0, 10.0],
'max_AI_multi_chan_rate': None,
Expand Down
1 change: 1 addition & 0 deletions labscript_devices/NI_DAQmx/models/NI_PCI_DIO_32HS.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#:
CAPABILITIES = {
'AI_range': None,
'AI_range_Diff': None,
'AI_start_delay': None,
'AO_range': None,
'max_AI_multi_chan_rate': None,
Expand Down
94 changes: 94 additions & 0 deletions labscript_devices/NI_DAQmx/models/NI_PCIe_6343.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#####################################################################
# #
# /NI_DAQmx/models/_subclass_template.py #
# #
# Copyright 2018, Christopher Billington #
# #
# This file is part of the module labscript_devices, in the #
# labscript suite (see http://labscriptsuite.org), and is #
# licensed under the Simplified BSD License. See the license.txt #
# file in the root of the project for the full license. #
# #
#####################################################################

#####################################################################
# WARNING #
# #
# This file is auto-generated, any modifications may be #
# overwritten. See README.txt in this folder for details #
# #
#####################################################################


from labscript_devices.NI_DAQmx.labscript_devices import NI_DAQmx

#:
CAPABILITIES = {
'AI_range': [-10.0, 10.0],
'AI_range_Diff': [-10.0, 10.0],
'AI_start_delay': 7e-08,
'AI_term': 'RSE',
'AI_term_cfg': {
'ai0': ['RSE', 'NRSE', 'Diff'],
'ai1': ['RSE', 'NRSE', 'Diff'],
'ai10': ['RSE', 'NRSE'],
'ai11': ['RSE', 'NRSE'],
'ai12': ['RSE', 'NRSE'],
'ai13': ['RSE', 'NRSE'],
'ai14': ['RSE', 'NRSE'],
'ai15': ['RSE', 'NRSE'],
'ai16': ['RSE', 'NRSE', 'Diff'],
'ai17': ['RSE', 'NRSE', 'Diff'],
'ai18': ['RSE', 'NRSE', 'Diff'],
'ai19': ['RSE', 'NRSE', 'Diff'],
'ai2': ['RSE', 'NRSE', 'Diff'],
'ai20': ['RSE', 'NRSE', 'Diff'],
'ai21': ['RSE', 'NRSE', 'Diff'],
'ai22': ['RSE', 'NRSE', 'Diff'],
'ai23': ['RSE', 'NRSE', 'Diff'],
'ai24': ['RSE', 'NRSE'],
'ai25': ['RSE', 'NRSE'],
'ai26': ['RSE', 'NRSE'],
'ai27': ['RSE', 'NRSE'],
'ai28': ['RSE', 'NRSE'],
'ai29': ['RSE', 'NRSE'],
'ai3': ['RSE', 'NRSE', 'Diff'],
'ai30': ['RSE', 'NRSE'],
'ai31': ['RSE', 'NRSE'],
'ai4': ['RSE', 'NRSE', 'Diff'],
'ai5': ['RSE', 'NRSE', 'Diff'],
'ai6': ['RSE', 'NRSE', 'Diff'],
'ai7': ['RSE', 'NRSE', 'Diff'],
'ai8': ['RSE', 'NRSE'],
'ai9': ['RSE', 'NRSE'],
},
'AO_range': [-10.0, 10.0],
'max_AI_multi_chan_rate': 500000.0,
'max_AI_single_chan_rate': 500000.0,
'max_AO_sample_rate': 917431.1926605505,
'max_DO_sample_rate': 1000000.0,
'min_semiperiod_measurement': 1e-07,
'num_AI': 32,
'num_AO': 4,
'num_CI': 4,
'ports': {
'port0': {'num_lines': 32, 'supports_buffered': True},
'port1': {'num_lines': 8, 'supports_buffered': False},
'port2': {'num_lines': 8, 'supports_buffered': False},
},
'supports_buffered_AO': True,
'supports_buffered_DO': True,
'supports_semiperiod_measurement': True,
'supports_simultaneous_AI_sampling': False,
}


class NI_PCIe_6343(NI_DAQmx):
description = 'NI-PCIe-6343'

def __init__(self, *args, **kwargs):
"""Class for NI-PCIe-6343"""
# Any provided kwargs take precedent over capabilities
combined_kwargs = CAPABILITIES.copy()
combined_kwargs.update(kwargs)
NI_DAQmx.__init__(self, *args, **combined_kwargs)
Loading