10-26-2007 09:24 AM
10-26-2007 01:35 PM
10-29-2007 12:40 PM
Thanks Jonathan,
To elaborate on the speed issues: My application is taking in 32 channels of analog data at 30 kHz and 32 channels at 2 kHz. It is creating and outputting 2 100 kHz analog signals and 8 digital channels. On top of this, I'm visualizing the analog data (either the 32 30 kHz channels or the 32 2 kHz channels; never both at once), running all the analog data through digital filters (1 filter for each channel), and then running the 32 30 kHz channels through another custom filter for artifact rejection and event detection. In the background, all the data is being written to disk. Each of these things tends to slow it down, in terms of updating the graphs and responding to user input. In some cases, it can get bogged down enough to crash the program with a buffer overrun. For an example of something that speeds it up, I reduce the number of points to plot by downsampling the acquired data, which helps a lot. Or, if I don't write the data to disk, that also helps quite a bit. Not using filters again improves the speed.
I've been considering, like I said, separating the UI thread from the acquisition thread and the file writing thread (they're all in the UI thread right now). But I thought that asychronous IO took care of this (and I'm using asynch IO). However, I've noticed that, at least for analog output executed from the main UI thread, asynchronous IO isn't all that asynchronous. For example, if I try to write a long stretch of data to the AO while acquiring data, the application will crash since I'm not acquiring data fast enough from the cards (something in the call to BeginWrite blocks when it shouldn't). If I separate the Write call into a backgroundWorker thread, the application is totally fine. So that's really confusing to me, and is why I'm thinking that all AO should be in separate threads from the UI.
Thanks for the other plotting recommendations. I hadn't seen these before! I'll definitely start using them!
10-30-2007 01:28 PM
Hi John,
Are you benchmarking the performance
of your application in release or debug configuration? You should always base
your application speed on release configurations and never debug as the
debugger slows things down. Also, make sure that when you do configure
your application to release configuration, you make sure to Ctrl+F5 and not
F5. F5 (or Build >> Start Debugging) will still attach the VS
debugger to the release code and use it to catch exceptions. Ctrl+F5 will not
use the debugger.
Our asynchronous model does use a separate worker thread behind the scenes for
the acquisition. This is all discussed in the Asynchronously Reading and
Writing with the NI-DAQmx .NET Class Library and the Events, Callbacks, and
Thread Safety in Measurement Studio .NET Class Libraries help topics in the NI
Measurement Studio Help.
Now, it appears that you actually explicitly created your own thread ran your data acquisition code in there and you saw better performance than using our async model? Is that a correct assumption? If you use this method of explicit thread-creation, you as the user will need to take care of thread-safety and the marshalling of data back to the UI thread. Our async model handles all that behind the scenes. However, if you see a large hit in performance, perhaps we need to look our own code and maybe do some profiling.
Putting all your analysis in a separate thread should also help speed as well.
Let me know
your thoughts
Best Regards,
10-30-2007 01:46 PM
Thanks again Jonathan,
I'm compiling in Release configuration, but I haven't been using Ctrl+F5--I'll try that and see if it helps out.
I have definitely seen better performance when putting analog output code into my own thread (via the BackgroundWorker class), rather than using the async functions. I haven't tried this for analog input yet. It's very perplexing, so I'd be curious as to whether you or anyone else can reproduce it (I might have done something so bizarre that this is only a problem for my application and no one else's).
11-05-2007 12:39 PM
Hi John,
I'll tell you want I have done, maybe this can help you. I'm using the WaveForm chart, but I assume that this configuration is valid for others types of XY graph.
My system produces on 8 channels 1 float every 1000Hz per channel. I can have fluid display by doing this:
PointHistory can be as much as 100 000 points per channels. (800 000 in total)
I'm stacking in one thread 100 points in one buffer per channel (A jagged array of 8 buffer).
Than I use BeginInvoke to send a copy of the buffer to the WaveForm graph using the function PlotAppendY(double [] y) with the buffer for each plot. Using PlotAppendY(float f) is simply impossible. This includes too many computinjg for a single point. Using BeginInvoke with the copy of the buffer is the best option because this doesn't block the data acquisition thread, and the WaveFormGraph, as stated previously when ImmediateUpdate set to false, seems to optimize its display rate depending on the load of the system.
So at 1000Hz of data coming in for 8 channels, I can have a WaveForm chart, showing all 8 channels data in StripChart mode. A total of 800 000 points are continously refresh using the techniques .
So according to my experiment, my advices are:
- Two separate thread.
- Never use PlotAppendY(double y) but PlotAppendY(doube [] y);
- Use BeginInvoke instead of Invoke so you data gathering thread is lock up by the display. The copy of the buffer is less expensive than to wait for the display to be refreshed.
Hope this helps,
Jean
11-06-2007 10:16 AM