07-10-2018 10:06 AM
Hello NI-ites,
I am doing some Data Acquisition in LabVIEW and I'm using a Queue of Dynamic Data to store incoming signals on four channels. I use the Producer/Consumer model to keep parallelism and accurate timing.
I have one loop for DAQ Assistant (N Sample Mode, 25k @ 25k) that runs every second and adds each second-long chunk to the queue. The larger loop runs once every 60 seconds to process that data. On each call of the consumer loop, the entire queue is flushed and I use Append Signals to turn the chain of second-long signals into a single 60 second long signal. (Well, 4 60 second long signals, since I have four channels)
The problem is, I think I lose some important information when I use Append Signals like this. In particular, when I run third octave analysis on the 60-second long signals, I am getting negative dB results for SPL measurements which doesn't make sense. I suspect that when the dynamic data is chopped up and put back together I lose the reference dB because the data looks good, but the dB is in reference to the wrong level. When I run the same Octave analysis on data coming right out of DAQ assistant, I get the proper results.
PS, there is some jankiness going on with the Flat Sequence Structure in the consumer loop, but I do that to ensure that I flush the queue on the same second every minute. I needed to make sure that Wait for next ms multiple, get timestamp, and Flush queue were called in that order every time, and two of those don't have Error Outs that I can use for timing.
Solved! Go to Solution.
07-10-2018 10:39 AM
My first recommendation is to get rid of the Dynamic Data Type. Convert it to an array of waveforms as soon as it comes out of the DAQ Assistant and use that in your queue. My second recommendation is to not use the Flush Queue. Instead, use a FOR loop to Dequeue Element 60 times. This will result in a 2D Array of Waveforms. Do a Transpose 2D Array and then autoindex into another FOR loop to combine your waveforms by channel. You can use Index Array to get the channel you want in order to do the Octave analysis.
07-10-2018 12:13 PM - edited 07-10-2018 12:14 PM
Wow, that seems to work! I checked the status of the queue and got the 60 from there because I want to have the option of using other measurement intervals. Two follow up questions:
What is the purpose of the empty auto indexed for loop? Did I take what you said too literally?
Finally, what do you think about the way I handle timing? If I were logging the results of Octave Analysis, would this give me exactly 60 seconds of data every time? I have been having an issue where the timestamp on the logs are drifting away from marking at the same second on each minute.
07-10-2018 12:28 PM
Thank you, That seems to work. Two follow ups: what is the purpose of the auto-indexing for loop? Am I supposed to be doing something inside of that? And how do you think this method works on timing? I'd like to record this data once per minute at the exact same time every minute, without any drift over time.
07-10-2018 12:28 PM
Thank you, That seems to work. Two follow ups: what is the purpose of the auto-indexing for loop? Am I supposed to be doing something inside of that? And how do you think this method works on timing? I'd like to record this data once per minute at the exact same time every minute, without any drift over time.
07-10-2018 12:33 PM
That FOR loop is where you are supposed to be doing the combining of your 60 waveforms. Right now, you are just keeping the last second.
Note that you do not need any wait in your consumer loop. If you loop 60 times, you will have the last minute of data coming from the DAQ. The Dequeue will sleep while it waits for the data to come in.
07-10-2018 01:24 PM
I see! That makes a lot of sense. Cool how that resolves the timing issue. What do you think of this? I use a nested for loop to make sure that for each channel (one 'for') I build up each of the 1-second signals to those beside it (the other 'for').
Inside the innermost loop, I wasn't sure how to initialize a signal to feed into the input Shift Register so I just went with using the first 1-second signal in line as my initial Signal A, which necessitated the conditional to avoid double counting that chunk.
07-10-2018 01:45 PM
@nds2123 wrote:
Inside the innermost loop, I wasn't sure how to initialize a signal to feed into the input Shift Register so I just went with using the first 1-second signal in line as my initial Signal A, which necessitated the conditional to avoid double counting that chunk.
I would use Delete From Array to delete the first element (0 to the index, leave the length unwired). The "array with subset deleted" then gets autoindexed while the "deleted portion" initializes the shift register. Then you no longer need that case structure or the Index Array.
07-10-2018 02:22 PM
That's pretty sly. Love it.
I've cleaned things up and added in the Sub-VIs within which I record the data to a text file ("Broadband" and "Third Octave", in yellow). Something I am surprised by is that the time stamps I'm recording are not all separated by X seconds, where X is the input to the Dequeue for loop. Even with the Producer/Consumer model, is it still impossible to expect the program to execute at fixed intervals? This problem is why I initially used the "wait until next ms multiple" VI.
07-11-2018 07:00 AM
@nds2123 wrote:
Something I am surprised by is that the time stamps I'm recording are not all separated by X seconds, where X is the input to the Dequeue for loop. Even with the Producer/Consumer model, is it still impossible to expect the program to execute at fixed intervals?
I general, you cannot trust software timing. Even in a RealTime (RT) OS, software timing is not exact. What you really should be doing is getting the T0 from your waveforms and use that timestamp since it is based on the hardware timing of the DAQ, which has A LOT less jitter. HINT: Use the Get Waveform Components on your waveform you already have going into the Linear Octive function and format the T0 into your Date/Time strings.