LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

DAQmx: Numerical indicators go blank intermittently using DAQmx Read

Hello everyone,
 
I was wondering if anyone else has ever fought this issue and won.  I have a loop (I will attempt to attach an image of the block diagram) which performs a DAQmx Read operation.  The loop employs a 200 millisecond wait.  The loop scales the data, sends all of the values to little indicators in an array, picks out a few critical values to display on duplicate large indicators, and optionally logs the data by streaming it to disk.  The task will usually (99.9% of the time) be run at 100Hz.  So, I was figuring I could do a "Read All", since at 200 ms of wait time due to the millisecond multiple wait function, I should always have around 20 points to read in the buffer the next time around.  This would allow me to have very current readings in my displays.  I could do a partial read, but then I figure I would have a lag between the displayed values and the reality of what's going on in the test.  Having current readings, as current as can be, is highly desirable for this application.
 
I figured everything was good with what I was doing, especially when I tested it with a simulated device (I know a simulated device behaves much differently than a real device, especially at start up).  Everything seemed to work well.  When I go to the real hardware, though, I intermittently get blank indicators.  Actually, it is more like intermittent numbers in my indicators.  Most of the time, the DAQmx Read operation returns a null, empty array (no data available in the buffer).  I must be missing something, because I figured that a 200 ms wait would allow another 20 samples to be collected.
 
If someone could please just ease my conscience and let me know that I haven't done something very fundamentally wrong in this code, even if you couldn't help me with a solution, I would very much appreciate it.  I feel that this code should work, keeping data in the indicators at all times, and don't know why it doesn't work.  If you could offer me the solution, even if it is to point out that I did something very wrong, I would much appreciate it.
 
I am just writing this code, and still have some icons to make, so the sub VI's still have the default icons.  Sorry about that.  Basically all those do is get array subsets, or scale data, or write data to the data files.  If you need to ask questions about the code, I can understand.  I am not the greatest yet at writing self documenting code yet.  And if you need to know what that event structure does, it watches the two boolean button controls to determine what state in the state machine to go to next, and the time out case of the event structure highlights a data value if it goes out of bounds.
 
Sorry if I am too wordy.  I have been accused of that before.  I just notice a lot of "Help!  DAQ doesn't work.  How do I fix?" posts, and I don't see how I or anyone else could help that person at all.
 
I am using LV8.2, with DAQmx 8.3.1, on Windows XP, 1GB of RAM, and a fairly healthy Duo core processor.  I have a workaround where I throttle back the read operation, only reading 55% of the available samples, as reported by a DAQmx Read property node (the highest percentage I found that prevents the indicators from going blank).  This introduces a small lag between the real world and the data on display, however.  Also, it seems like a processor dependent solution.  I would have to tweak this percentage for every machine I run this on.
 
If I have left anything important out, please let me know, and I will do my best to clarify, and thank to anyone who reads this, and a big thank you to anyone who takes the time to reply.  Again, I would be real happy with a "That code looks good to me, and your thinking is correct", if that indeed is the case.
 
Thanks.
0 Kudos
Message 1 of 9
(3,804 Views)

Does anyone know if the block diagram I posted has decent code in it (see previous post)?  I am wondering if I am doing something wrong, since I only get intermittent displays of data.

Thanks for any help you can provide.

0 Kudos
Message 2 of 9
(3,784 Views)

Briefly: the code could be improved.  Key points of concern:

  • you're using the "200 msec multiple" version of wait and it is free to operate in parallel with all the other code in the loop.  Use dataflow to enforce the sequencing of when you do the wait vs. when you read & process samples.
  • I would highly recommend taking back control over the DAQmx Read call.  By not wiring an explicit value to '# to read', you're saying, "give me whatever samples you've got, I don't care how many."  However, later processing of those samples assumes and depends on certain minimal # of samples.  Suggestion: query for '# available samples' then read the MAX of (# available, # required).

I half suspect that those 2 things alone might fix your problem, but I can't honestly say I tried to follow all the code details.  A little wire neatening would help readability for mods and debugging purposes... Smiley Wink

-Kevin P.

ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 3 of 9
(3,779 Views)
Hi InternationAL,

Thank you for your descriptive post!  The main thing that I see missing in your code is a DAQmx Timing VI.  I am assuming that your Analog Input Task is set up in MAX with the acquisition mode set to Continuous, a rate of 100 Hz, and number of samples set to 20.  Please note that in a continuous acquisition, the number of samples input is really the buffer size used in the acquisition.

Here are my suggestions:
  • Even if your timing is set up in MAX, I would still suggest using a DAQmx Timing VI in your code before the DAQmx Start Task VI.
  • If you have a DAQmx Read inside a loop and the task is hardware timed in the way you describe, there isn't a need for a Wait Until Next ms Multiple function because in your case, the DAQmx Read will block other processes until it has its 20 samples, which will take 1/5 of a second.  So essentially, the DAQmx Read will control the timing.  You want to make sure to wire an explicit value (e.g., 20) to the number of samples to read input (like Kevin says above), this way the DAQmx Read will wait for exactly 20 samples before returning.
  • Finally, I would suggest monitoring the status of your Error Cluster (using an Unbundle by Name function) and if an error occurs, stop your while loop (see attached picture). This is good programming practice and saves you from getting the same error over and over again because it is in a loop.
I hope this helps!

Regards,
Erik J.

Message Edited by Erik J on 03-14-2007 12:10 PM

0 Kudos
Message 4 of 9
(3,779 Views)

Thanks for the great advice everyone!  I knew I would forget something.  I have attached an image of the DAQmx task builder subVI I am using to create my task.  This is sort of a datalogger application, and a fixed task in MAX would not be feasible.  A setup VI allows the user to select channels for logging, and the sampling rate, and then fires off the attached code to build the DAQmx task.

I believe the fix being recommended is to wire in a "-1" to the timeout terminal of the DAQmx Read function, and to specify "Sample Rate/5" as the number of samples to read (I want to have display updates around 5 times a second).  Then, I should ditch the millisecond wait function, correct?

I guess I am still puzzled by the fact that the millisecond wait function did not allow 20 or so samples (100Hz * 200 ms) to accumulate into the buffer on every loop iteration, so that I would always have data to read as I came around for the next loop iteration.  I wish someone could explain to me why the "software" method of timing the loop didn't work, because it sure seemed like it should work to me.  If the hardware method is the recommended way to go, though, I will do that from now on.  I really like sticking to best practices, and other who stick to best practices, because it makes it easier to share and debug code with each other.  But the fact that the "software" method didn't work...what is it that I don't understand about the millisecond multiple wait function?

Thanks again to everyone who is helping me upgrade my programming skills.  I am definitely famous around work for having the most beautiful wiring diagrams.  I will definitely work on this and I will add a stop on error to my loops.  The attached block diagram is a little prettier to look at.

0 Kudos
Message 5 of 9
(3,762 Views)

Yeah, as you and Erik said, just specifying (Sample Rate / 5) as the '# to read' could do the trick.  Then you can ditch the 'Wait (msec multiple)' function.  I don't think I'd recommend the -1 = infinite timeout though.  I'm pretty leery of stuff that can lead to an infinite wait or an infinite loop.  Even a 1 sec timeout should easily be way more than enough.  Note however that this method depends on all your processing code executing in under 200 msec on average.  Otherwise, your reads will fall behind and you'll eventually get a DAQ buffer overflow error.  My earlier suggestion to first query for # available samples and then read the MAX of (# available, SampleRate/5) will prevent cumulative fall-behind effects.

There's too many unknowns to speculate with any confidence on exactly why the software timing method didn't work.   I can point out some additional things that bear greater scrutiny though.

1. You've got some sort of function dealing with file streaming that takes a path input and produces a path output.  This probably means that every loop iteration you're using the path to open a file, write data, and close the file again.  This actually may consume more than 200 msec, at least some of the time.  Because this runs in parallel with the msec wait function, something like the following could be happening:

A. Iteration 1 proceeds as expected.  The DAQ read collects 20 samples, the file write consumes only 100 msec, and the wait msec function ends after 160 msec in order to end on a 200 msec multiple.  The wait function took longest, so your whole loop ends on a 200 msec multiple.

B. On iteration 2, the wait msec function ends after 200 msec on the next 200 msec multiple.  The DAQ read collects another 20 samples (because it's been pretty much exactly 200 msec since the previous loop iteration started) right away.  However, Windows was busy messing with the file cache so this time your file write consumes 375 msec.  The file function took longest so your whole loop ends 175 msec into the next 200 msec multiple.

C. On iteration 3, the wait msec function ends after 25 msec on the next 200 msec multiple.  The DAQ read collects 37 samples that have come in since the prior call 375 msec ago.  The file function consumes only 50 msec this time, ending the loop 25 msec into the next 200 msec multiple.

D. On iteration 4, the wait msec function ends after 175 msec at the next 200 msec multiple.  The DAQ read collects the 5 samples that have come in since the prior call 50 msec ago.  Uh oh, not enough samples...

One possible fix is to open the file outside the loop and leave it open until after the loop is done.  Opening and closing files has quite a lot of overhead.  Inside the loop, you'd be passing around the file refnum.  Doing this one thing alone might also be a way to fix your timing problem.  Along similar lines, you could write the data to a queue and then do your file writes in an independent loop that reads the data out of the queue.  You can search here for "producer consumer" for more info.

-Kevin P.

 

ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 6 of 9
(3,750 Views)

D'oh!

You guessed it right on the button about the file open/close.  Nice one.

I can't believe I forgot this.  It makes sense now.  I thought closing the file reference would free up resources, but now I remember learning something like this, even back in BASIC and PASCAL in high school.  Open the file, but don't close it until you are absolutely finished with it.  I also recall encountering this recently with Excel VBA.  The recommendation is that if you will be accessing the VBA object model frequently at some point, or some points near each other, to set an object variable to point to that particular point in the object model, or use the With...End With structure.  I will try to implement the file open and close outside the loop.

Also, my thinking was clouded a little bit by assuming the loop would always take about the same amount of time on each iteration.  I've timed loops before, and thought that that was true.  But I forgot about Windows every now and again coming in to mess things up, and other random, unpredictable overhead.  If the loop ends near a millisecond multiple, it could take very little time to loop over again, and after having "read all", the buffer could be empty (less than 10 ms since last read).  I must have been alternating between no data and having some.

If using "MAX(Samples Available, Sample Rate/5)" alleviates this problem, I will be glad to forget all about the attempt to software time this.  What I won't forget is how helpful you guys have been.  Thank you very much.  I will also remember to wire better, use stop on error for loops, and use hardware timing whenever possible.  Maybe I should stop letting LabVIEW decide where to plop the wires and take more control!  I also need to take that course on LabVIEW design patterns (producer/consumer).

0 Kudos
Message 7 of 9
(3,745 Views)
One quick tidbit: if you get rid of the software timing and use that idea of MAX(# available, SampleRate/5), you may see your Windows Task Manager report 100% CPU usage while the DAQmx Read is waiting for its chunk of data.  Don't be overly concerned.  The DAQmx driver is setup to use whatever CPU power is readily available.  However, it will easily yield and give it up to other apps or other parts of your LV code.  You'll see this if you mess around with some other app while your data acq program runs -- it'll be plenty responsive.  The older driver was not nearly so friendly and drove me to the habit of querying first and then reading only what was already available. 

Query first, read second can still be useful sometimes but thankfully it's not always necessary.

Sounds to me like you're off to a great start.  Good luck with your future wiring adventures.  I still find that I'm trying out one or two new (to me) techniques on just about every good-sized project.  That seems to work out well.  The times I've tried too many new things all at once didn't tend to go so well.  Your first usage of a technique isn't likely gonna be your best... Smiley Wink

-Kevin P.

ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 8 of 9
(3,737 Views)

I just wanted to report back that I tried the advice offered here, and it works beautifully!  I couldn't be more delighted.  Using the DAQmx Read function to time the loop is indeed the way the application should be programmed.  I am indebted to the fine programmers who offered their help here.  I want to sincerely thank both of you.  Hopefully, someone else will find this thread when needed and save themselves a lot of trial and error.

Thanks again, and best wishes!

0 Kudos
Message 9 of 9
(3,733 Views)