LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 
Reply

Running two tasks simultaneously

Thank you for the suggestions! I tried both Kay and Paul's suggestions on my VI, they don't seem to work. The total run time will still be the sum of run time + loop time. I have attached the VI with Paul's suggestion. Yet, if I use my idea to fix this, the elapsed time count will not be the same as run time value and I found this is a little odd. Is this a good fix for the problem?

I have also another question. It seems like the time elapsed count is a little off, see attached Front Panel picture. Is there a way to improve the count?

 

To answer mcduff's question - the reason I am not using the finite set of data point is because I'd like the user has an option to run the code continuously or to specify a run time.

0 Kudos
Message 21 of 31
(524 Views)
Highlighted
  1. Drake,

     Thanks for giving me "another chance to teach".  Please forgive the somewhat-rambling nature of this Post -- I'm putting in the effort because I sense you are interested in becoming better (and maybe even proficient) in LabVIEW development, but you need some guidance.

     I'm attaching a "partly-cleaned-up" version of your code, with lots of comments, in no particular order.  I also know why your "timing" is off, and (more important) "how to fix it".  That will come later.  First:

  • The name of your file, "...3 input R3 testing R2", suggests this is #3, Revision 3, test Revision 2, and you are (therefore) not using any form of Version Control, like Subversion or Git.  Look into learning about Subversion or Git (I use Subversion, myself).
  • There is no reason to use 8 point labels on Controls and Indicators.  I changed (some of) them to 14 point, so I can see what they are.
  • You almost never need (nor should have) a Frame, much less a Frame Sequence.  I replaced your Sequence with a single Frame around the initial "Get Time" function.
  • Reorganizing your code and keeping wires as straight and left-right as possible can help eliminate White Space and make your Block Diagram smaller and much more readable.  I did the first part, leaving the rest for you.

Now, let's talk about Time, a key concept in LabVIEW (dealing, as it does, with timed events like DAQ, and with Time as a primitive Data Type (Timestamps).  Here is a Principle -- DAQ Hardware Is the Best Clock!  If you really want to time something, and you have DAQ functions, use the DAQ, don't depend on the CPU clock!  You appear to be doing all of your Sampling at once, taking 10,000 samples a second for 10 seconds from 4 channels -- I certainly hope your cDAQ device has a 400,000-sample buffer!  Assuming that it does, the DAQ Read is guaranteed to take 10 seconds, at which point it will transfer all of the data to the Array of Waveforms coming out of the DAQ Read function.  Until this happens, almost nothing else in the Loop can run (as the Principle of Data Flow says it can't run until there is "Data on the Wire").  Now, everything else in the loop needs to run before the loop can finish, which might take a little extra time (and explains why your Elapsed Time is > 10 seconds).

 

How can you fix this?  Simple, don't do all that processing before ending the While Loop!  "But I have to process the data!", you say.  Yes, but not in that loop.  The Principle of Data Flow also means that LabVIEW can run two loops at the same time in something called the Producer-Consumer Design Pattern (there are LabVIEW Examples and Templates illustrating this).  Here's how it works:

  1.  Let's assume your DAQ device has sufficient buffering to allow you to hold all of the Samples you need to acquire (i.e. 10s * 10kHz * 4 channels = 400,000 samples).
  2. Put the DAQms Read function in a small While Loop.  Put nothing else (yet) in the While Loop.  Put in a Stop button to end the While loop.  Try it out, and observe that no matter when you push the Stop button, the loop will run for (almost exactly) a multiple of 10 seconds.  In actuality, when it executes the DAQmx Read, anything that depends on the Read finishing (i.e. anything that uses either the Data Out or Error Out wire from that Function) will wait for the Read to finish (by the Principle of Data Flow).
  3. In particular, anything you do with the data will delay taking any more data.  So you don't want to do anything "time-consuming" inside the loop.
  4. Here's where the Magic Happens.  This While Loop is the "Producer" -- it "produces" data every 10 seconds.  It wants to get rid of the data quickly and send it to another Loop, the Consumer, that can run at the same time that the Producer is doing the next DAQmx Read.
  5. Do you know about Queues?  A Queue is a data structure that says "I'm going to put some data in here, and take it out over there, taking very little time to do this".  The data don't actually move in a Queue, what you are really doing is passing a reference to the data, which takes very little time.  I'm not going to try to tell you all about Queues and how they are used in Producer/Consumer Loops, but if you do a little research, look at the LabVIEW Help, look at the LabVIEW Examples, and look at the Producer/Consumer Design Pattern Template (open LabVIEW, go to File, New ... (the dots are important), From Template, Design Patterns, Producer Consumer Design Pattern (Data), you'll get an Example to study and adapt to your situation.
  6. You put your Data Processing code in the Consumer Loop.  Assuming "Consuming" takes less than the 10 seconds the Producer loop spends "producing" the data that the Consumer is "consuming", the two Loops run "in parallel", with the Producer running at full speed and the Consumer, when it runs, not "blocking" the Producer from running again.
  7. A wonderful side effect of this is that if your DAQ device does not have a big enough buffer, so what?  Instead of generating all 100,000 samples at once, generate them 1000 at a time, sending them to the Consumer, and run the Producer for 100 iterations until all 100,000 samples have been Produced and Consumed.  The Producer will still "produce" the data as fast as before (since nothing it blocking it from running continuously) and the Consumer will follow right along.

I'm attaching my revised version of your code.  When you rewrite your DAQ loop and transform it into a Producer/Consumer design, try to copy the "style" of compactness, less white space, straighter (and shorter) wires, and a level Error Line ("The Error Line Runs Through It").

 

Post your New and Improved Code.  Does it work (much) better?

 

Bob Schor

Message 22 of 31
(530 Views)

Thank you for the thorough elaboration, Bob. I will take some times to study the Producer/Consumer design and post the improved code. 

 

Best,

Drake

 

 

0 Kudos
Message 23 of 31
(479 Views)

Hi Bob,

I have modified my VI using your suggestion. Few questions have came up:

1) When the VI is running, the FFT Graph and the corresponding data value are working fine. Yet, When I pressed the stop button/when the VI stopped, the graph is cleared and the data value is not properly shown, see attached 123 picture.

2) I set the run time to be 10sec, yet the time elapsed indicator only shows 9sec. I believe the loop starts counting with 0, that's why it gives me 9. Is it necessary to have this fixed.

3) I get rid of the Get Time Function because even with the producer/consumer design pattern, the timestamp count will still not be an integer; and replaced with the loop count as the timestamps. Is this what you referred to as "DAQ Hardware clock"?
4) In my previous version, by changing the "timeout" of the DAQmx Read, let say 5sec, the FFT graph will produce a FFT for this 5sec. However, when I used producer/consumer design pattern, I noticed that the 5sec "timeout" of the DAQmx Read will multiply the total run time. For example, "Run Time" is set to 10sec, "timeout" is set to 5sec. the total run time will be 50sec instead of 10sec specified (the time elapsed indicator will still remain 9sec). How can I fixed this issue?

 

Thank you,

Drake

 

0 Kudos
Message 24 of 31
(270 Views)

Hi All,

Does anyone have an suggestion how to proceed to the 4 problems above? I'm still having difficulties to figure it out.

 

Thank you,

Drake

 

 

0 Kudos
Message 25 of 31
(202 Views)

@Drakelau wrote:

Hi Bob,

I have modified my VI using your suggestion. Few questions have came up:

1) When the VI is running, the FFT Graph and the corresponding data value are working fine. Yet, When I pressed the stop button/when the VI stopped, the graph is cleared and the data value is not properly shown, see attached 123 picture.  Remember the Principle of Data Flow.  How do you stop your Consumer?  You kill the Queue, so the Consumer "errors out", delivering an empty Array to the Index Array function and hence an empty chunk of data to the Graph and all that follows in the Consumer.  Stopping a loop by causing a deliberate Error is (in my opinion) clumsy, but effective.  If you are thinking "Data Flow" (the First Principle of LabVIEW, and the Second, and Third, as well), you'll say "... and if there is an error, then I don't want to do any of the subsequent processing as it will overwrite my efforts with zeros or other garbage".  [How do you do "If ... then" in LabVIEW?]

2) I set the run time to be 10sec, yet the time elapsed indicator only shows 9sec. I believe the loop starts counting with 0, that's why it gives me 9. Is it necessary to have this fixed.  Did someone say "Principle of Data Flow"?  Look at the order in which you increment and display the time.

3) I get rid of the Get Time Function because even with the producer/consumer design pattern, the timestamp count will still not be an integer; and replaced with the loop count as the timestamps. Is this what you referred to as "DAQ Hardware clock"?  No.  I haven't looked closely at your DAQ device, but if it is, say, an A/D converter, and you tell it "Take 1000 samples at 1 kHz", then you can figure out the Sample Time and know that if you design your Producer Loop properly, it will repeat exactly at the Sample Time.  "Design your Producer Loop properly" means that you do almost nothing in the Producer except Sample and Export via a Queue (or Channel Wire).
4) In my previous version, by changing the "timeout" of the DAQmx Read, let say 5sec, the FFT graph will produce a FFT for this 5sec. However, when I used producer/consumer design pattern, I noticed that the 5sec "timeout" of the DAQmx Read will multiply the total run time. For example, "Run Time" is set to 10sec, "timeout" is set to 5sec. the total run time will be 50sec instead of 10sec specified (the time elapsed indicator will still remain 9sec). How can I fixed this issue?  Uh, I don't get it!  The TimeOut represents an error, namely you failed to get the Samples in time.  Usually this happens because you failed to start the Acquisition, i.e. your Acquisition has a Trigger and you didn't send the Trigger.  Another way is to start the Acquisition Task, wait a minute, then do the DAQmx Read, too late ...

.

DAQ devices have accurate clocks, and they aren't interrupted by, say, doing a Virus Scan, or a Disk Defragmentation.  Knowing the Sample Rate and Sample Size, you can precisely time the Loop, and if you have a total Sampling Time you want, you can compute how many Loops you need to run (it should be an integer).  Use a Structure that lets you "count" the number of Loops that you "know" you have to do.  K.I.S.S.

 


Bob's Rule #1 (shamelessly "borrowed" from Peter Blume, who taught me LabVIEW Style, sadly overlooked by too many LabVIEW programmers) -- Every Block Diagram must fit on a single Laptop Screen.  If you can't see all of your code and follow all the wires, debugging and refining code will be almost impossible.  Think "Sub-VIs"!

 

0 Kudos
Message 26 of 31
(191 Views)

@Bob_Schor wrote:

@Drakelau wrote:

Hi Bob,

I have modified my VI using your suggestion. Few questions have came up:

1) When the VI is running, the FFT Graph and the corresponding data value are working fine. Yet, When I pressed the stop button/when the VI stopped, the graph is cleared and the data value is not properly shown, see attached 123 picture.  Remember the Principle of Data Flow.  How do you stop your Consumer?  You kill the Queue, so the Consumer "errors out", delivering an empty Array to the Index Array function and hence an empty chunk of data to the Graph and all that follows in the Consumer.  Stopping a loop by causing a deliberate Error is (in my opinion) clumsy, but effective.  If you are thinking "Data Flow" (the First Principle of LabVIEW, and the Second, and Third, as well), you'll say "... and if there is an error, then I don't want to do any of the subsequent processing as it will overwrite my efforts with zeros or other garbage".  [How do you do "If ... then" in LabVIEW?]

2) I set the run time to be 10sec, yet the time elapsed indicator only shows 9sec. I believe the loop starts counting with 0, that's why it gives me 9. Is it necessary to have this fixed.  Did someone say "Principle of Data Flow"?  Look at the order in which you increment and display the time.

3) I get rid of the Get Time Function because even with the producer/consumer design pattern, the timestamp count will still not be an integer; and replaced with the loop count as the timestamps. Is this what you referred to as "DAQ Hardware clock"?  No.  I haven't looked closely at your DAQ device, but if it is, say, an A/D converter, and you tell it "Take 1000 samples at 1 kHz", then you can figure out the Sample Time and know that if you design your Producer Loop properly, it will repeat exactly at the Sample Time.  "Design your Producer Loop properly" means that you do almost nothing in the Producer except Sample and Export via a Queue (or Channel Wire).
4) In my previous version, by changing the "timeout" of the DAQmx Read, let say 5sec, the FFT graph will produce a FFT for this 5sec. However, when I used producer/consumer design pattern, I noticed that the 5sec "timeout" of the DAQmx Read will multiply the total run time. For example, "Run Time" is set to 10sec, "timeout" is set to 5sec. the total run time will be 50sec instead of 10sec specified (the time elapsed indicator will still remain 9sec). How can I fixed this issue?  Uh, I don't get it!  The TimeOut represents an error, namely you failed to get the Samples in time.  Usually this happens because you failed to start the Acquisition, i.e. your Acquisition has a Trigger and you didn't send the Trigger.  Another way is to start the Acquisition Task, wait a minute, then do the DAQmx Read, too late ...

.

DAQ devices have accurate clocks, and they aren't interrupted by, say, doing a Virus Scan, or a Disk Defragmentation.  Knowing the Sample Rate and Sample Size, you can precisely time the Loop, and if you have a total Sampling Time you want, you can compute how many Loops you need to run (it should be an integer).  Use a Structure that lets you "count" the number of Loops that you "know" you have to do.  K.I.S.S.

 


Bob's Rule #1 (shamelessly "borrowed" from Peter Blume, who taught me LabVIEW Style, sadly overlooked by too many LabVIEW programmers) -- Every Block Diagram must fit on a single Laptop Screen.  If you can't see all of your code and follow all the wires, debugging and refining code will be almost impossible.  Think "Sub-VIs"!

 


Believe it or not, I read his book cover-to-cover.

Bill
CLD
(Mid-Level minion.)
My support system ensures that I don't look totally incompetent.
Proud to say that I've progressed beyond knowing just enough to be dangerous. I now know enough to know that I have no clue about anything at all.
Humble author of the CLAD Nugget.
0 Kudos
Message 27 of 31
(184 Views)

@billko wrote:

@Bob_Schor wrote:

Bob's Rule #1 (shamelessly "borrowed" from Peter Blume, who taught me LabVIEW Style, sadly overlooked by too many LabVIEW programmers) -- Every Block Diagram must fit on a single Laptop Screen.  If you can't see all of your code and follow all the wires, debugging and refining code will be almost impossible.  Think "Sub-VIs"! 

Believe it or not, I read his book cover-to-cover.


For those who are curious, "The LabVIEW Style Book", by Peter Blume.  Billko has read it cover-to-cover, and I've done the same three or four times (I'm a "slower learner" than Bill ...).

0 Kudos
Message 28 of 31
(176 Views)

Hi Bob,

Thank you again for your helpful explanation. I am able to solve most of the problems I have asked. Yet, I am still struggling with one problem. For my FFT Power Spectrum and PSD vi, I would like to have an user interface to control the number of samples to be used to perform the power spectrum graph. For example, the sampling rate of the DAQmx vi is 10000S/sec, an user might want to see the power spectrum graph for 5 sec acquisition period, which I will need to have the vi to perform a power spectrum plot of 50000 samples. I have tried different ways, but still couldn't get this to work. (I tried to alter the "number of samples per channel" of the DAQmx Read vi, but this will affect the acceleration graph and create other issues, which I do not prefer) Do you have any suggestion for this problem?

 

Thank you,

Drake

0 Kudos
Message 29 of 31
(160 Views)

@Drakelau wrote:

Hi Bob,

Thank you again for your helpful explanation. I am able to solve most of the problems I have asked. Yet, I am still struggling with one problem. For my FFT Power Spectrum and PSD vi, I would like to have an user interface to control the number of samples to be used to perform the power spectrum graph. For example, the sampling rate of the DAQmx vi is 10000S/sec, an user might want to see the power spectrum graph for 5 sec acquisition period, which I will need to have the vi to perform a power spectrum plot of 50000 samples.


Use a lossy queue to act as a circular buffer for the data samples.  Once you have enough samples, dequeue that data and perform the FFT.  You will want to limit the queue's size, and therefore your FFT size, when you initialize the queue and use the Lossy Enqueue function to add samples to the queue.


There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
0 Kudos
Message 30 of 31
(155 Views)