09-02-2020 05:07 AM - edited 09-02-2020 05:24 AM
Hello, I have a program that should send a waveform (a sine wave for example) to several channels of an NI multifunction board. This board has multiple AO channels and I want to use all of them. The user should send waveforms (can all be different) at any time and the resulting voltage and current should be displayed live.
Normally you would simply send the entire waveform array to the DAQmx write function and read it back every 100ms or so. But I want that while one waveform is being read (can lasts several seconds) the user should be able to send another waveform on another channel. With the DAQmx write function you have to send the entire waveform for all channels at the same time, which is not good when one waveform has already been written.
My strategy for this problem is to divide the waveform into pieces of 100ms worth of points. Then send those pieces every 100ms while the input is read continously. I've attached a test VI that I quickly made (sorry for the messiness). You can send a waveform to either channel 0 or 1 and any time and also while there is already a waveform being send. It works, but at high sample rate, the signal jitters at regular intervals. Like this:
I've been trying to use the buffer as follows: Add 200ms of data and then every 100ms after that add another 100ms of data. In this way there should always be between 100 and 200ms worth of data in the buffer, but jitter still remains. In fact there is no jitter the first 200ms and then it it appears. So it seems to me that the buffer is not properly used. I'm not sure how to properly use it. Can anybody help with this problem?
Solved! Go to Solution.
09-02-2020 07:37 AM
You've done substantial work, but I think you may not be aware of a few subtleties with DAQmx.
1. You should write to the AO buffer once *before* you start the task.
1a. When you do this, the # samples (per channel) you write will set the buffer size
for the AO task.
1b. This buffer and the device's own onboard FIFO will combine to create *latency*
between writing data to the task buffer and having the new signal show up in
the real world.
2. You have the AO task set for "Do Not Allow Regeneration" and you also have your AO write loop wait for a queued message telling it when to write data. The first might not be necessary (or even helpful) and the second definitely isn't.
The best reason to set "Do Not Allow Regeneration" is to make sure the task throws errors like the ones you see when you don't feed it data fast enough to keep up with the hardware generation. That's a legit use case, wanting to be informed, but it isn't *everybody's* use case.
If you don't set that property, DAQmx will just keep circling over the old data in the buffer until you do give it new data. Again, this fits some use cases but not all. I simply don't know what yours really is.
Similarly, if your AO loop were structured more like your AI loop, DAQmx would manage your iteration timing because it wouldn't let the new data being written into the buffer "catch up and pass" the point where data is being delivered down to the hardware device. So the call to DAQmx Write would block and wait until all the data can be delivered safely, thus handling your loop timing auto-magically.
The essential point is that the AO loop doesn't need to be structured to be "commanded" periodically to write more data. If you made a tight writing loop that attempted to write too often, DAQmx would throttle you down to the point where (loop rate) * (samples written per loop) matches up with the task sample rate.
3. Surprise! The 'samples per channel' value from the AI task isn't particularly meaningful. I wouldn't query it and use it for things that matter. Not very intuitive, right? If you agree, consider lending support to my related suggestion here.
4. You could probably stand to sync your AO and AI tasks. Because you're using the same sample rate for AO & AI and are sequenced to start the AO task last, I'd configure AI to use the AO task's sample clock. Search the forums for "shared sample clock" and you'll probably find dozens of threads with more info.
-Kevin P
09-02-2020 09:09 AM
Thank you so much for you reply. It helped a lot. Indeed I was not familiar with some of the details of the DAQmx library.
Especially the DAQmx write function waiting for all previous data to be finished before writing new data is very useful!
I tried to use the buffer node before but always got an error. I was not aware that you had to write data to intialize the buffer. Great advise!
I have implemented your suggestions and it is working great now!
09-02-2020 09:48 AM
What's left to consider is syncing the AO and AI sampling. Right now you start AI first so at least you aren't missing any of the response to the AO stimulus you generate. But you also don't have precise correlation to know which AI sample corresponds to the first AO sample.
It's possible this doesn't matter for your purposes, but if it does, look into the "shared sample clock". (Triggering schemes can also work, but I tend to advocate for shared clocks when possible as clocks provide sync across multiple devices in a way that triggers alone can't.)
-Kevin P