Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

nidaqmx python Synchronize analog output and input in stream

Hi,

 

I am trying to run the multiple analog outputs and inputs simultaneously using the following python codes. But it looks that the reader is delayed and show error with "nidaqmx.errors.DaqError: Requested value is not a supported value for this property. The property value may be invalid because it conflicts with another property.
Property: DAQmx_StartTrig_Type
Requested Value: DAQmx_Val_AnlgEdge
Possible Values: DAQmx_Val_DigEdge, DAQmx_Val_None
Task Name: _unnamedTask<1>
Status Code: -200077"

I believe there is something wrong with trigger, but haven't found a solution yet.

Help is much appreciated,

 

With kind regards,

 

Ho

 

import nidaqmx
import numpy as np
import matplotlib.pyplot as plt
import time
from nidaqmx import constants
from nidaqmx.constants import Edge, Slope
from nidaqmx.stream_readers import AnalogMultiChannelReader
from nidaqmx.stream_writers import AnalogMultiChannelWriter
from nidaqmx.stream_readers import AnalogSingleChannelReader

outputX=np.linspace(10,-10,25000)
outputY=np.linspace(5,-10,25000)
X=np.zeros(25000)

outputData = np.append(outputX,outputY)
outputData=np.append(outputData,outputY)
outputData = outputData.reshape((3,len(outputX)))


inputData=np.zeros(25000*3)
inputData = inputData.reshape((3,25000))
#outputData = np.transpose(outputData)
print(outputData.shape)
print(inputData.shape)

#ao_chan_x=t1.ao_channels.add_ao_voltage_chan("cDAQ1Mod1/ao0")
#ao_chan_y=t1.ao_channels.add_ao_voltage_chan("cDAQ1Mod1/ao1")
#outputChannels = ao_chan_x + "," + ao_chan_y


writingrate1=25000

#while True:
with nidaqmx.Task() as writeTask, nidaqmx.Task() as readTask:
writeTask.ao_channels.add_ao_voltage_chan('cDAQ1Mod1/ao0:2')
readTask.ai_channels.add_ai_voltage_chan('cDAQ1Mod4/ai0:2')

writeTask.timing.cfg_samp_clk_timing(rate=writingrate1,
#source='/cDAQ1/ai/SampleClock',
sample_mode=nidaqmx.constants.AcquisitionType.FINITE, # dont use continuous
samps_per_chan=X.size)

readTask.timing.cfg_samp_clk_timing(rate=writingrate1,
#source='/cDAQ1/ao/SampleClock',
active_edge=nidaqmx.constants.Edge.RISING,
sample_mode=nidaqmx.constants.AcquisitionType.FINITE,
samps_per_chan=X.size)
writeTask.triggers.start_trigger.cfg_anlg_edge_start_trig( trigger_source='/cDAQ1/ai/StartTrigger', trigger_slope=Slope.RISING) # Setting the trigger on the analog input



reader = AnalogMultiChannelReader(readTask.in_stream)
writer = AnalogMultiChannelWriter(writeTask.out_stream)

print("The channels linked to WriteTask are: ")
for i in writeTask.ao_channels:
print(i)


writer.write_many_sample(outputData)
writeTask.start()
reader.read_many_sample(inputData)





#reader.read_many_sample(inputData)
#readTask.start()

#writeTask.start()

writeTask.wait_until_done()
readTask.wait_until_done()

#readTask.start()

print("Done with data")
#print(inputData)

#x=np.linspace(0,25000,25000)
plt.plot(inputData[0])
plt.show()







0 Kudos
Message 1 of 7
(4,640 Views)

Many devices don't support analog triggering for AI tasks.  I don't know of ANY that support analog triggering for AO tasks, not directly at least.

 

I don't know the Python API into DAQmx, but I can offer up a few ideas.

 

- see this thread where I helped talk through an *indirect* method to provide analog triggering for AO.  All the code parts are LabVIEW though.

 

- if some kind of analog start condition is a key to this app, you need to (try to) configure the AI task for analog triggering

 

- the timing config looks a little confused with the read and write tasks configured to use each other's sample clocks.  This strikes me as a circular definition where both tasks will get stuck waiting for the other to generate its sample clock, but neither one can because they're both stuck waiting for the other task to start.

 

- similarly, the internal signal '/cDAQ1/ai/StartTrigger' is a digital trigger signal *result* that asserts when the ai task's start trigger criteria are satisfied.  It isn't available for analog triggering evaluation.  Plus, the AO task can't (directly) use an analog trigger anyway.

    It *would* be feasible to configure that signal as a *digital* start trigger for the AO task.  But you'll also have to resolve the circularly defined timing config.

 

- finally, since you seem to want AI and AO to sample at the same rate and start at the same time, there's a simpler overall approach.

  • on closer inspection, and I'm not a Python guy, it looks like maybe you commented out the source assignment in the timing config for both tasks.  Good!  I'll assume for now that the syntax works and that DAQmx use its default source (an internal timebase) to derive the sample clocks. 
  • you should set up the AI task for analog triggering not AO, assuming your device supports it.  The trigger source should be one of the analog channels in the task, or, possibly (for some devices) a special analog triggering input.
  • AO could still be configured to be *digitally* triggered by '/cDAQ1/ai/StartTrigger'
  • you should then write data to the AO task and start it
  • after that you should start the AI task before trying to read from it.
  • The order of starts matters!  Because the AO task will be waiting for an internal trigger signal from the AI task, it's important to start the AO task first so it won't *miss* the moment when the AI task's triggering condition is satisfied.

 

-Kevin P

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
0 Kudos
Message 2 of 7
(4,595 Views)
import nidaqmx
import numpy as np
import matplotlib.pyplot as plt
import time
from nidaqmx import constants
from nidaqmx.constants import Edge, Slope
from nidaqmx.stream_readers import AnalogMultiChannelReader
from nidaqmx.stream_writers import AnalogMultiChannelWriter
from nidaqmx.stream_readers import AnalogSingleChannelReader

outputX=np.linspace(10,-10,25000)
outputY=np.linspace(5,-10,25000)
X=np.zeros(25000)

outputData = np.append(outputX,outputY)
outputData=np.append(outputData,outputY)
outputData = outputData.reshape((3,len(outputX)))


inputData=np.zeros(25000*3)
inputData = inputData.reshape((3,25000))
#outputData = np.transpose(outputData)
print(outputData.shape)
print(inputData.shape)

#ao_chan_x=t1.ao_channels.add_ao_voltage_chan("cDAQ1Mod1/ao0")
#ao_chan_y=t1.ao_channels.add_ao_voltage_chan("cDAQ1Mod1/ao1")
#outputChannels = ao_chan_x + "," + ao_chan_y


writingrate1=25000

#while True:
with nidaqmx.Task() as writeTask, nidaqmx.Task() as readTask:
writeTask.ao_channels.add_ao_voltage_chan('cDAQ1Mod1/ao0:2')
readTask.ai_channels.add_ai_voltage_chan('cDAQ1Mod4/ai0:2')

writeTask.timing.cfg_samp_clk_timing(rate=writingrate1,
#source='/cDAQ1/ai/SampleClock',
sample_mode=nidaqmx.constants.AcquisitionType.FINITE, # dont use continuous
samps_per_chan=X.size)

readTask.timing.cfg_samp_clk_timing(rate=writingrate1,
#source='/cDAQ1/ao/SampleClock',
active_edge=nidaqmx.constants.Edge.RISING,
sample_mode=nidaqmx.constants.AcquisitionType.FINITE,
samps_per_chan=X.size)
#readTask.triggers.start_trigger.cfg_anlg_edge_start_trig(trigger_source='Voltage')
writeTask.triggers.start_trigger.cfg_dig_edge_start_trig( trigger_source='/cDAQ1/ai/StartTrigger') # Setting the trigger on the analog input



reader = AnalogMultiChannelReader(readTask.in_stream)
writer = AnalogMultiChannelWriter(writeTask.out_stream)

print("The channels linked to WriteTask are: ")
for i in writeTask.ao_channels:
print(i)


writer.write_many_sample(outputData)
writeTask.start()


readTask.start()
reader.read_many_sample(inputData)





#reader.read_many_sample(inputData)
#readTask.start()

#writeTask.start()

writeTask.wait_until_done()
readTask.wait_until_done()

#readTask.start()

print("Done with data")
#print(inputData)

#x=np.linspace(0,25000,25000)
plt.plot(inputData[0])
plt.show()



Hi Kevin,

 

Thanks a lot for your prompt reply.

I do can run the codes without any error following your valuable suggestions. However, when I directly connected the ai and ao channels, the reading data from ai doesn't match the writing data in ao. With NImx software, I can get the reading and writing simultaneously. I believe there is still some delay between reading and writing. Now I am using NI9264 (ao) and NI9205 (ai) incorporated in NI cDAQ9174. You are right that the ai has analog triggering while ao doesn't. 

for the analog triggering of ai, i use the code: 

readTask.triggers.start_trigger.cfg_anlg_edge_start_trig(trigger_source='Voltage')

 and it gives me an error:nidaqmx.errors.DaqError:

An attempt has been made to use an invalid analog trigger source.
Ensure that the trigger source you specify matches the name of the virtual channel in the task or matches the name of a non-scannable terminal that the device can use as an analog trigger source.
Property: DAQmx_AnlgEdge_StartTrig_Src
Corresponding Value: Voltage
Valid Choices: cDAQ1Mod4/ai0
Device: cDAQ1
Task Name: _unnamedTask<1>
Status Code: -200265

 

 
 

Here is the triggering setting of ai:

Capture1.PNG

 

and  here is the ao 

Capture2.PNG

And I believe ai and ao use the same sample clock which I don't need to set it up manually, isn't it?

 

Thanks!

Ho

0 Kudos
Message 3 of 7
(4,588 Views)

The trigger error message is telling you that you need to identify a physical AI channel on the device as the analog trigger source, namely "cDAQ1Mod4/ai0"

 

AO and AI don't quite exactly use the same sample clock, but they both derive their sample clocks from a common master timebase.  To share the same sample clock you should UN-comment the part of the timing config for the AO task where it used to designate:

source='/cDAQ1/ai/SampleClock'

 

One difference is that the AI task's sample clock signal won't start pulsing until after the AI task has started acquisition.  In this case, that won't be until after the analog triggering conditions have been met.   When you configure this way, you won't need the AO task to be triggered any more.  The shared sample clock alone will accomplish the same thing timing-wise.

 

 

-Kevin P

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
0 Kudos
Message 4 of 7
(4,561 Views)

Kevin:

I am also working on synchronized AO/AI. 

The device I have are USB6001 and USB6003. When I tried to set source = '/Dev1/ai/SampleClock' for the ao_Task, it tells me the requested sample clock source is invalid. However, when I try to set the trigger using trigger_source = '/Dev1/ai/StartTrigger' it works.

Do you know which source shall I use?

Thank you!

0 Kudos
Message 5 of 7
(2,560 Views)

Sorry, I don't have any definite knowledge about those low-cost USB devices.  I tried creating simulated devices in MAX to check out signal routing options, but neither of them presented me with the expected "Device Routes" tab.  I'm not entirely sure how to interpret that, but it *seems* to suggest that little or no routing of timing signals is possible with those devices.

 

Triggering can *start* you in sync, but won't keep sampling in sync over the long haul.  Timebase accuracy specs for low cost devices are typically 100 ppm, which translates to ~6 msec per minute of runtime.  If tasks run for 1 minute at 1000 Hz on two such devices, they can each be skewed by +/- 6 msec from nominal over that time frame, which translates to as much as +/- 12 samples misalignment between the two tasks.

 

It's possible that a common external clock source (such as a function generator) could be used to drive both tasks and keep them in sync, but the lack of a "Device Routes" tab in MAX gives me low confidence.

 

 

-Kevin P

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
0 Kudos
Message 6 of 7
(2,530 Views)

Kevin:

Thank you so much for the answer!

 

0 Kudos
Message 7 of 7
(2,527 Views)