LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

EMG data acquisition program missing data points

Hello,

 

I previously posted here about an EMG data acquisition program I am trying to write with LabVIEW that takes in data from 2 Measurement Computing 1208fs AD converters. The answers I received helped with the lag I was seeing in the waveforms of my data.

 

I have now completed the program, but I am finding that when the waveform data is written out, there are data points missing every few seconds (see attached text file for what I am referring to). I am new to writing data acquisition programs so I am not sure exactly why this is happening. I have tried re-writing the VI so that it all occurs on one frame (no local variables), but this doesn't seem to fix the issue. It is because LabVIEW cannot handle a 2000 Hz sampling rate? I am wondering if anyone knows a good solution to this problem- I would appreciate any insight someone might have!

 

Thanks,

Ben

Download All
0 Kudos
Message 1 of 6
(3,063 Views)

Do you know that Index Array is resizable?  You don't need to copy it a dozen times and wire up all those constants.

 

Where are you writing the data out?  I see a single Write TDMS, but it is in an orphan case structure with broken wires.  What concerns me is your use of the sequence structure and local variables is a sign of race conditions.  If that oprhan case structure was actually connected, it would get its data from the local variable called AllSignals.  There isno control over when the data is written to the indicator in the one loop versus when the data is read (in a missing loop?)  You could be getting stale data, you could be missing data.

 

I don't have the ULX library to read its help.  Those subVI's are missing fro me.  But you are using N chan N samples.  I don't see how many samples you are trying to read with each one.  My guess is it defaults to -1 which would be all available samples.  If your two reads weren't grabbing the same amount of data each iteration of the loop, then I believe you would something like you have where one batch of channels is longer and the other batch is blank from the missing samples.  Only the next time around, those "missing" samples are there and it gives you a longer run of data in that batch and is now "missing" samples from the other read.  I bet you actually have more rows total in that table then you actually should.  I wouldn't trust that any of that data is aligned or timestamped properly.

 

Try wiring a const for how many samples to read to both of those ULx reads.  Perhas 1/2 second or 1 second worth of data.  Also, I would add a queue and use a producer/consumer architecture to pass the data capture off to the consumer loop that is responsible for writing it to the TDMS file.

 

 

Message 2 of 6
(3,048 Views)

RavensFan,

 

Thank you for the reply- I really appreciate your expertise.

 

I realized from your reply that in my haste to post this to the forum, I attached the incorrect program. The case structure with the Write TDMS function was supposed to be in the frame 2 of the sequence structure. I've attached the correct version to this reply.

 

I did not know the Index Array is resizable- I will modify that in a newer version.

 

I thought that by using a sequence structure, I was avoiding race conditions because data would be passed in the order of the sequence structure. In other words, frame 0 would operate first, and then pass that info to frame 1, and so on. Is this not correct? Your comment may have been referring to the first version of the program I attached where the case structure was outside of the while loop (I apologize once again for that).

 

When you say to specify how many samples I am trying to read with the ULx Read function, do you mean to wire the input "number of samples per channel"? Because that is the only other input for this function that I don't have wired besides "timeout". If so, would that be a fraction of my sampling rate? For example, you said to use 1/2 to 1 second. Since I am sampling at 2000 Hz, would I wire 1000 or 2000?

 

This is my first experience writing a DAQ program, so I am not too familiar with the producer/consumer architecture. I have found several articles on NI's website however, so I plan to try and learn from those samples and apply it to this program. Once I do so, I plan to repost the next version and am hopeful for your feedback.

 

Thanks again for the help!

Ben

0 Kudos
Message 3 of 6
(2,994 Views)

I cleaned up your code and was able to eliminate the stacked sequence structure.

 


@bcconner wrote:

RavensFan,

 

I thought that by using a sequence structure, I was avoiding race conditions because data would be passed in the order of the sequence structure. In other words, frame 0 would operate first, and then pass that info to frame 1, and so on. Is this not correct? Your comment may have been referring to the first version of the program I attached where the case structure was outside of the while loop (I apologize once again for that).
Yes.  A sequence structure can be used to avoid race conditions.  But often you don't need that.  I cleaned up your code and was able to eliminate the stacked sequence structure.  If you ever do need a sequence structure, a flat structure is preferable to stacked because the stacked structure hides code.  The race condition I was talking about was the one in your original code where there was a read of the local variable outside of the loop and was thus happening in parallel to whatever happened inside the loop.  But you can see with the attached code, many local variables were eliminated, as was the sequence structure, and you shouldn't have any race condition now.

When you say to specify how many samples I am trying to read with the ULx Read function, do you mean to wire the input "number of samples per channel"? Because that is the only other input for this function that I don't have wired besides "timeout". If so, would that be a fraction of my sampling rate? For example, you said to use 1/2 to 1 second. Since I am sampling at 2000 Hz, would I wire 1000 or 2000?

 

Yes.  Wire a constant into those inputs.  Put in a fraction of your sampling rate, your sample rate, or a number larger than your sampling rate.  The number you put in will determine how quickly your display refreshes.  A large number will be slower updates, but will allow the Write to File to execute larger chunks.  A small number would be fast updates, but the constant opening and closing of the file may slow down your code.  I would pick 1000 to start and see how it goes from there.

 

 

 

 


 

Message 4 of 6
(2,985 Views)

Hi RavensFan,

 

Wow- thank you for cleaning up the code! Truly impressed by your expertise.

 

I have some follow up questions- hope that's alright.

 

By inputing 1000 for the number of samples, I understand that this will be better for the Write Out function, but it causes the waveform chart to lag considerably. I assume this is because it only updates every 1/2 second now, but even with inputting something as small as "1", the waveform chart still appears substantially slower. Is there a way to prevent this from happening while still easing up the load on the Write Out function?

 

Also, I was able to research some producer - consumer architecture. Are you implying that I should create 2 while loops: one with the Read function and the second with the Write Out function? And then implement a queue in between?

 

Really appreciate all of the help!

 

Best,

Ben

0 Kudos
Message 5 of 6
(2,978 Views)

I feel like 1 sample would be way too small.  If 1/2 second seems too laggy, try makikng it 200.  That would update every 10th of a second.  But would be much larger chunks of data being written out.

 

Yes, the producer/consumer means two loops, one for reading, and the other doing the writing.  A queue is the mechanism that transfers the data

0 Kudos
Message 6 of 6
(2,976 Views)