Skip to content

Commit 9fca33b

Browse files
authored
Merge pull request #102 from dihm/NIDAQ_AI_ext_timebase
Externally clocked analog inputs on NI-DAQmx
2 parents 337f010 + a3e52b8 commit 9fca33b

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

docs/source/devices/ni_daqs.rst

+20
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ Exact numbers of channels, performance, and configuration depend on the model of
7979
AnalogOut('daq_ao0',daq,'ao0')
8080
AnalogIn('daq_ai1',daq,'ai1')
8181
82+
WaitMonitors
83+
------------
84+
8285
NI DAQs are also used within labscript to provide a :class:`WaitMonitor <labscript:labscript.labscript.waitmonitor>`.
8386
When configured, the `WaitMonitor` allows for arbitrary-length pauses in experiment execution, waiting for some trigger to restart.
8487
The monitor provides a measurement of the duration of the wait for use in interpreting the resulting data from the experiment.
@@ -154,6 +157,23 @@ For example, to share the clock in the previous with an additional PXIe-6535 dig
154157
155158
In addition to clocking, the `connected_terminals` argument can be used to link output terminals on an NI DAQ module to shared triggers, then link those shared triggers to input terminals of another NI DAQ module in the same chassis.
156159

160+
AI timing skew
161+
--------------
162+
163+
Given how the NI-DAQmx driver currently works,
164+
all of the outputs (and generally other hardware) are hardware-timed via direct outputs from the parent pseudoclocks.
165+
Under default usage, this is not true for the analog inputs of the DAQs,
166+
which are timed via the internal reference oscillator of the DAQ.
167+
Synchronization between the two is handled at the end by correlating start times and slicing the AI traces at the appropriate times.
168+
This works fine if the reference clocks for the pseudoclock and the DAQ don't drift relative to each other,
169+
but that is generally not the case for a longer shot (on the order of 1 second) since the standard clocks for a pulseblaster and a DAQ both have accuracy on the order of 50 ppm.
170+
171+
With version 1.2.0 of the NI-DAQmx driver, this issue can be mitigated by suppling an external sample timebase that is phase synchronous with the DAQ's pseudoclock device.
172+
This is done using the DAQmx `SampleClkTimebase` synchronization method.
173+
Simply provide an external clocking signal that is faster than the analog input sampling rate,
174+
and the DAQ will use an internall PLL to derive the AI sample clock from the provided timebase.
175+
Specifying an externally provided sample timebase is done using the `AI_timebase_terminal` and `AI_timebase_rate` arguments,
176+
which specify the input terminal (generally a PFI line) and the clock frequency.
157177

158178
Detailed Documentation
159179
~~~~~~~~~~~~~~~~~~~~~~

labscript_devices/NI_DAQmx/blacs_tabs.py

+2
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ def initialise_GUI(self):
206206
'AI_range': properties['AI_range'],
207207
'AI_start_delay': properties['AI_start_delay'],
208208
'AI_start_delay_ticks': properties['AI_start_delay_ticks'],
209+
'AI_timebase_terminal': properties.get('AI_timebase_terminal',None),
210+
'AI_timebase_rate': properties.get('AI_timebase_rate',None),
209211
'clock_terminal': clock_terminal,
210212
},
211213
)

labscript_devices/NI_DAQmx/blacs_workers.py

+7
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,13 @@ def start_task(self, chans, rate):
514514
None,
515515
)
516516

517+
if self.AI_timebase_terminal is None:
518+
# use internal default
519+
pass
520+
else:
521+
self.task.SetSampClkTimebaseSrc(self.AI_timebase_terminal)
522+
self.task.SetSampClkTimebaseRate(self.AI_timebase_rate)
523+
517524
self.task.CfgSampClkTiming(
518525
"", rate, DAQmx_Val_Rising, DAQmx_Val_ContSamps, num_samples
519526
)

labscript_devices/NI_DAQmx/labscript_devices.py

+18-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# #
1212
#####################################################################
1313

14-
__version__ = '1.1.0'
14+
__version__ = '1.2.0'
1515

1616

1717
from labscript import (
@@ -64,6 +64,8 @@ class NI_DAQmx(IntermediateDevice):
6464
"AI_start_delay_ticks",
6565
"AI_term",
6666
"AI_chans",
67+
"AI_timebase_terminal",
68+
"AI_timebase_rate",
6769
"AO_range",
6870
"max_AI_multi_chan_rate",
6971
"max_AI_single_chan_rate",
@@ -102,6 +104,8 @@ def __init__(
102104
AI_start_delay_ticks=None,
103105
AI_term='RSE',
104106
AI_term_cfg=None,
107+
AI_timebase_terminal=None,
108+
AI_timebase_rate=None,
105109
AO_range=None,
106110
max_AI_multi_chan_rate=None,
107111
max_AI_single_chan_rate=None,
@@ -154,6 +158,12 @@ def __init__(
154158
AI_term_cfg (dict, optional): Dictionary of analog input channels and their
155159
supported terminations. Best to use `get_capabilities.py` to introspect
156160
these.
161+
AI_timebase_terminal (str, optional): Channel string that specifies what
162+
channel to use for the Sample Clock Timebase signal.
163+
If None, use default internal clocks.
164+
Must also specify the rate when not using the internal sources.
165+
AI_timebase_rate (float, optional): Supplied clock frequency for the AI timebase.
166+
Only specify if using an external clock source.
157167
AO_range (iterable, optional): A `[Vmin, Vmax]` pair that sets the analog
158168
output voltage range for all analog outputs.
159169
max_AI_multi_chan_rate (float, optional): Max supported analog input
@@ -250,6 +260,13 @@ def __init__(
250260
# no analog inputs
251261
self.AI_chans = []
252262
self.start_delay_ticks = None
263+
# special AI timebase handling
264+
if num_AI > 0:
265+
if (AI_timebase_rate is None) ^ (AI_timebase_terminal is None):
266+
raise LabscriptError("You must specify terminal and rate when using an external AI timebase")
267+
self.AI_timebase_terminal = AI_timebase_terminal
268+
self.AI_timebease_rate = AI_timebase_rate
269+
253270
self.num_AO = num_AO
254271
self.num_CI = num_CI
255272
self.ports = ports if ports is not None else {}

0 commit comments

Comments
 (0)