LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

What is the best way to store data in an array from within a time critical loop?

I have a real time system application (running on an 8146RT) that reads data from two analog input channels (using the AI single scan VI) and processes it from within a time critical loop (a continuously running WHILE loop). Every now and then, following a Save Data command from the host PC, I need to save each data point read into an array before reading the next sample. After a certain number (which could be anywhere between 3000 and 20000) of successive data points has been stored, the array has to be transferred back to the host PC. What is the best way to do this? I am using the RT communication wizard to generate the Time Critical Loop and Normal Priority Loop, and more importantly,
the various RT FIFOs that I need. I have tried several methods of initializing and then inserting into the array, but every method seems to result in the NPL losing communication with the host PC
0 Kudos
Message 1 of 3
(3,375 Views)
Arun,

Thanks for the great description of your issue.

The Comm Wizard provides a generic architecture that suits most monitoring and simple control applications. There are optimizations that can be done that reduce the overhead that the product of the Communication Wizard can incur in, but it probably requires good understanding of how the RT FIFOs work. My recommendation would be to use the product of the Communication Wizard as a reference while you take your original application and implement the FIFO functionality from scratch.

As far as I can tell, there are two possible ways of making this application more efficient:

1) Array FIFOS

� Pre-allocate an array, of up to the maximum required size, before entering the Time-Critical Loop. If using several channels then pre-allocate a similar array for each one.
� Use the Replace Array Subset primitive to replace the contents of the array with the recently acquired data, one point at a time. You could choose between always doing this or only doing it when a certain message is receive from the host (and it is passed to the Time-Critical loop using FIFOs), or you could always store the data into the array, regardless of whether you want to save it or not, which has the �advantage� of always showing you what your worst-case scenario is in terms of timing in the Time-Critical loop.
� Use an Array FIFO to pass the whole array back to the communication loop (Normal-Priority loop). Use one FIFO per channel
� Every time the Communication Loop runs, it should read all FIFO elements (each one being an array of points), this means invoking the FIFO Read function until it returns empty (then discarding the last array).
� The Communication Loop can then assemble, resize or reshape one or many of these arrays and send the data back to the host (or log it to disk)
� Play with the FIFO and Array (FIFO element) sizes until you get a compromise between responsiveness, efficiency and memory usage. Larger FIFOs will help you buffer more data and allow the communication loop to run less often, but will also require more memory. Running the communication loop less often will make the application more efficient but a bit less responsive (you can only transfer data when the communication loop runs). Larger arrays will make things more efficient in terms of time but will consume more memory and might make the application less responsive (you have to wait for more samples before you can extract an array of data).
� This scheme is useful if you are using a few channels. For multiple channels the amount of FIFOs complicates the implementation.

2) Single Element FIFOs

� This is similar to what the Communication Wizard does, but we can optimize it by having the communication loop run less often and then read single samples from the FIFO until its empty.
� Use large single-element FIFOs (scalar data-type FIFOs if reading one channel, or Array FIFOs to store one sample from all similar channels) for samples obtained within the Time Critical Loop. Write every point you read from a channel (or set of channels) into the corresponding FIFO.
� Have the Communication Loop run less often but make sure that it reads all FIFOs in a loop until they are empty.
� Buffer the samples read from each FIFO in separate arrays until they reach the desired number of elements and then transmit them back to the host (or log them to disk)
� Depending on the application requirements, there are several optimizations that can be done:
- Note how many samples your Communication Loop has to read from the FIFOs until they are empty. This will give you an idea of whether they are the right size or not. You probably want to make them 3 to 5 times the theoretically expected size so that you can account for worst case scenarios.
- Always read data from the FIFOs or only read data when you need it. This won�t �make or break� the application, but only reading the FIFOs when needed will allow you to run with lower CPU usage. Always reading from the FIFOs allows you to easily determine what your worst case CPU usage is.
- A larger FIFO size will allow your communication loop to run less often, but you will use more memory and might loose some responsiveness (you have to wait longer before you can interact with the target).
To increase transfer (or logging) efficiency, you might want to buffer the incoming samples into an even larger circular buffer (use an array and keep track of your Read and Write offsets), inside the Communication Loop. Sending data back to the host (or writing to file) in chunks with sizes which are multiples of 1KB (1024 bytes) is much more efficient than using some common numbers like 200, 500 or 1000 elements. Take into account the size of your data type, in bytes, try to buffer the data until you get a multiple of 1024 bytes, and then send it back to the host (or log it to disk). By using this technique, you can obtain a compromise between running your communication loop often enough to make it responsive (minimize delays in the execution of commands sent to the communication loop, update indicators, etc) and making your data transfer (or logging) operations more efficient than before by buffering data to specified sizes.

� This approach is useful when reading multiple channels of the same type, since only one FIFO is needed to transfer many channels of the same type.



Other notes:

- 814X targets usually don�t have as much memory as other more powerful PXI targets, so try to make sure you are not running out of memory with the large arrays and FIFOS.
- There is always the possibility that you might be requiring too much of your current target, making the Time-Critical loop consume all available time, therefore starving other processes as the communication threads which cause you to loose connection to the target. The suggestions above might help, but start to build your application with as few channels as possible and then increase the number of channels while monitoring the effect on CPU usage. There will always be a point where you will need a faster processor before adding more channels to the application.
- There are tools built into LabVIEW Real-Time 7.1 that allow you to monitor CPU and Memory usage on the target. For earlier versions of Real-Time you can download individual utilities from our Developer Zone that perform similar tasks.


I hope this helps,

Alejandro
0 Kudos
Message 2 of 3
(3,375 Views)
Thank you Alejandro for that excellent, comprehensive answer; it addressed almost all of my doubts / concerns!

I found it conveninet to use single element FIFOs in my application. The time critical loop and the normal priority loop (communication loop) were created using the RT communication wizard, and then were customized to suit my needs. I need to log the sampled data from only one of the analog channels, when I give a Save Data command. After the required number of samples (about 20,000) has been moved into the sampled data FIFO, the time critical loop sets a 'data saved' flag (another FIFO). The normal priority loop runs at it usual pace and reads / writes into every FIFO except the sampled data FIFO, until it sees the 'data saved' flag
. At this point it reads the sampled data FIFO until it is empty, resets the 'data saved' flag and proceeds as usual. I have found that this 'event-driven' communication has very little impact on the responsiveness; there is a slight hiatus in communication only when the normal priority loop is reading from the sampled data FIFO.

Thank you very much..

Arun
0 Kudos
Message 3 of 3
(3,375 Views)