I'm trying to start two tasks simultaneously using software trigger (one for analog output, one for digital output).
I have something that looks like this:
with nidaqmx.Task() as a_task, nidaqmx.Task() as d_task: # Set analog output. for a_ch in ni_config['analog']: a_task.ao_channels.add_ao_voltage_chan(a_ch) d_task.do_channels.add_do_chan(ni_config["digital"], line_grouping=LineGrouping.CHAN_PER_LINE) a_task.timing.cfg_samp_clk_timing(rate=ni_config["sample_rate_hz"], sample_mode=ni.constants.AcquisitionType.FINITE,samps_per_chan=a_data.shape) a_writer = AnalogMultiChannelWriter(a_task.out_stream, auto_start=False) a_writer.write_many_sample(a_data) # Set digital output. d_task.timing.cfg_samp_clk_timing(rate=ni_config["sample_rate_hz"], sample_mode=ni.constants.AcquisitionType.FINITE,samps_per_chan=len(d_data)) d_task.triggers.start_trigger.cfg_dig_edge_start_trig(a_task.triggers.start_trigger.term) d_writer = DigitalSingleChannelWriter(d_task.out_stream, auto_start=False) d_writer.write_many_sample_port_byte(d_data) a_task.start()
However, the digital task doesn't start.
When I try to add explicitly
I get consistent delay between the analog and digital (probably the time it takes for NI to actually start the task)>
How can I have a single software trigger such that both start at the same time?
[Side note: The analog outputs use (multiple) PXIe-4468, and the digital output use PXIe-6535]
Solved! Go to Solution.
A software trigger will always have an unknown delay. If you want to synchronize multiple devices, you should use a hardware trigger.
I'm getting multiple errors:
DaqError: Specified property is not supported by the device or is not applicable to the task. Property: DAQmx_RefClk_Src
Specified property is not supported by the device or is not applicable to the task. Property: DAQmx_Trigger_SyncType
I've got a lot of general DAQmx knowledge, but don't know your devices specifically and also don't know Python syntax.
Here's some thoughts to try to give you a little boost, not likely to solve everything.
1. Maybe your 4468's for AO don't support multi-device tasks? (See also "channel expansion" when searching)
2. When possible, I like to advocate sync via shared sample clock alone. No dealing with triggers, sync pulses, reference clock config, etc. Sample clock sharing is typically better for syncing tasks across devices than triggers alone.
3. I don't see where you set a sample rate for acquisition, unless the construct ni_config["sample_rate_hz"] resolves to a numeric value that's been set up elsewhere.
4. However, PXI can be an exception. Most devices sync up their internal timebases to the PXI chassis clock. So in the specific case of PXI, sync via trigger alone often *can* be sufficient. This appears to be what you're trying to do.
5. However, with the DI task wanting to trigger off the AO task's (internal) start trigger, you should be starting DI *before* you start AO.
6. This may not be the *only* way to make things work, but if your AO device doesn't support "channel expansion" I would consider the following:
In general, you could make any one of the tasks be the "master", but it seems sensible to me to have the one and only DI task play a special role while all the AO tasks are the same as one another.
Alternatively, if a software solution to trigger both at the same time is not possible, is there a way to trigger both tasks using an external hardware trigger? How do I set this up?
The below works on simulated devices. You can complete the multi writer/reader on your own.
"""Example of AI multitask operation.""" import pprint import nidaqmx from nidaqmx.constants import AcquisitionType, TaskMode, LineGrouping, Signal pp = pprint.PrettyPrinter(indent=4) with nidaqmx.Task() as master_task, nidaqmx.Task() as slave_task: master_task.do_channels.add_do_chan("/6535/port0/line0:3", line_grouping=LineGrouping.CHAN_FOR_ALL_LINES) slave_task.ao_channels.add_ao_voltage_chan("/4468_1/ao0:1") slave_task.ao_channels.add_ao_voltage_chan("/4468_2/ao0:1") master_task.timing.cfg_samp_clk_timing(1000, sample_mode=AcquisitionType.FINITE, samps_per_chan=4) master_task.export_signals.export_signal(signal_id=Signal.SAMPLE_CLOCK, output_terminal="/6535/PXI_Trig7") slave_task.timing.cfg_samp_clk_timing(1000, source="/4468_1/PXI_Trig7", sample_mode=AcquisitionType.FINITE, samps_per_chan=4) master_task.control(TaskMode.TASK_COMMIT) slave_task.triggers.start_trigger.cfg_dig_edge_start_trig("/6535/do/StartTrigger") print("1 Channel N Lines N Samples Unsigned Integer Write: ") print(master_task.write([1, 2, 4, 8])) print("N Channel N Samples Write: ") print( slave_task.write( [[1.0, 2.0, 3.0, 4.0], [1.1, 2.1, 3.1, 4.1], [1.2, 2.2, 3.2, 4.2], [1.3, 2.3, 3.3, 4.3]], ) ) slave_task.start() master_task.start() slave_task.wait_until_done() slave_task.stop() master_task.wait_until_done() master_task.stop()
Big kudos to ZYOng for the example!
Brief comment: he gave you a little bonus by showing 2 different ways to share timing signals.
- Explicitly - by exporting the master DO sample clock to a specific PXI trigger line and configuring AO to use it
- Implicitly - by telling the AO task to use a signal from the DO device "/6535/do/StartTrigger". With this method, DAQmx figures out routing automatically.
I see consistent latency between the two signals with both solutions.
The analog lags the digital by ~32.8 ms.
This happens regardless of how I configure things. Even when I set both to trigger to be an external PFI.
Now that I've looked at the spec sheet for the 4468, I can probably explain the timing offset. Do you have a sample rate of ~2kHz?
Your AO devices use a Delta Sigma converter which incorporates a bandwidth-limiting digital filter which brings with it an inherent delay along the signal path. According to the spec sheet, the delay is ~65 samples for sample rates from 100 Hz to 10 kHz. So a 2 kHz sample rate could be expected to have a 32.5 msec delay.
With acquisition signals, such delays can be compensated in post-processing. That's not really an option for *output* signals that need to be synced though. Instead you'd have to pre-compensate.
There may be other methods (possibly a "trigger delay" property in DAQmx?) but here's one that could work. Configure a chassis counter to generate a 32.8 msec pulse. Trigger AO off the leading edge and trigger DO off the falling edge. The 32.8 msec head start you gave to AO will be used up by the filter delay, then the output signals should be in sync.
On a separate note, 'm a bit surprised though if you can use the DO as master and AO as slave for your sample clock config. Delta Sigma devices typically don't allow for an external signal to be used directly as a sample clock. Or did you drop the shared sample clock and try to sync solely via common trigger?