From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

How to get complete array out of a for loop and plot it after each iteration?

Solved!
Go to solution

Hi all. There are a few topics like this but I haven't found anything just right yet. The attached vi works nicely, it collects data packets of 40 values from a specified bit of hardware, puts it into the first row of a 2D array and then collects another 40 values, puts it into the 2nd row etc. Each time round the loop it plots the average of the columns thus far, i.e. first iteration it plots the first row, 2nd iteration it plots the average of the first & second rows, and so on, until it has done 10 plots, with a steadily improving signal, due to the averaging.

My problem is that the graph functions are inside the loop, but I want this to be a sub vi, with the graphs on the front panel of the main vi, so I need to get the data out each iteration of the for loop.

I get a warning when I try to make a sub vi.

I know I have to be very careful about race conditions but I'm sure there's nothing else that will cause this. I've never used queues yet but I'm guessing that might be the way?

 

Thanks for any help available.

Andrew

 

0 Kudos
Message 1 of 30
(5,999 Views)
Solution
Accepted by topic author ASH2020

That shift register thing seems overcomplicated...sure it could be simplified, but I do not really understand (yet) what you want with your data.

Some hints to improve your code (and i strongly advice you to take some tutorials, like Core 1-2!):

  • You do not have any error handling. I would check for errors even in that FOR loop (if the serial comm fails, you should not continue iterations)
  • Keep in mind, if you change this fixed iteration FOR loop into a While loop, or if you increase the iteration number, then you have an every growing memory leak: the shift register holding the growing array
  • You could use a Queue in your Main VI: Obtain the Queue ref in your main.vi, then send the Queue reference into the subVI. In your subVI, use the Enqueue element, and in your main-vi, use the Dequeue element. Search for the term: "Producer-consumer (Data)", it is also shipped with LabVIEW...
  • Do not do the summation in your subVI (Producer), you can do it in your main.vi (Consumer)
  • Be careful how you design your main.vi! The sub.vi and the consumer part of the main.vi MUST run in parallel! Again, check the design pattern Producer-Consumer...

EDIT:

Some hints, see snippet below. This is just an example, i did not care about error handling, etc. Also, if you use named Queue, you do not need to lead the reference into the subVI:

EDIT 2.:

Of course, the consumer code part will hang after it got all the data, and you will not able to stop it. So you need to program this case around, for example to set some timeout for the "Dequeue element". Or, you can send a "Last data tag?" marker along with the data, so you will know when to stop and quit that top application loop...

All depends on your actual design and requirements! I strongly advice to use a State Machine in some form, if you need to have re-startable DAQ, etc...!

 

Pcap read 10_BD.png

Message 2 of 30
(5,986 Views)
Solution
Accepted by topic author ASH2020

Hi,

 

Looking at your VI, it seems you have a main For loop running 11 times, and you want to make this entire loop a subVI. Did I understand correctly? If so, you'll probably have an easier time making parts of that loop into a subVI.

 

Consider something like the following:

subvis.png

Here I suggested two possible subVIs from your main loop - the first holds code that makes the measurement using the VISA tools. It needs, as an input, the VISA control, an Error In wire, and the PCAP data Main values. My guess is that Header length and Data packet length could be constants, but if they are not, you could also use those as controls to the subVI. It outputs an array of integers, and the VISA and Error wires.

 

The second is just the inner For loop, plus a decrement function (there's a built-in LabVIEW function to subtract 1). You probably don't need (or want) a wait function here. This section has two inputs (the 2D array and the 'i' value) and one output (the average 1D array).

 

Both of these should be possible to create using the 'Create SubVI' tool without them complaining. By creating these two subVIs, your main VI becomes much smaller, and the functionality is split into suitable components doing separate things.


GCentral
Message 3 of 30
(5,984 Views)

@Blokk wrote:

That shift register thing seems overcomplicated...sure it could be simplified, but I do not really understand (yet) what you want with your data.

Some hints to improve your code (and i strongly advice you to take some tutorials, like Core 1-2!):

  • You do not have any error handling. I would check for errors even in that FOR loop (if the serial comm fails, you should not continue iterations)
  • Keep in mind, if you change this fixed iteration FOR loop into a While loop, or if you increase the iteration number, then you have an every growing memory leak: the shift register holding the growing array

As Blokk wrote, the Shift Register is a little odd (actually, he didn't write that, but it is).

One possible alternative would be a Replace Array Subset combined with an Initialize Array outside of the For loop. Currently, the shift registers are uninitialized, so they will hold previous values (perhaps that's intentional).

 

You could do that like this:

Example_VI_BD.png


GCentral
0 Kudos
Message 4 of 30
(5,978 Views)

Thanks for the quick reply. I take the point about error handling, thanks.

The data comes in in packets, always 40 data points, which plot as a curve. The same test is done 10 times (11 because the first is zero). Each loop, the curve is averaged with previous data and plotted, so it is the same curve, but steadily improving in quality as each packet comes in and is averaged.

I guess I could do the averaging in the main vi, although what I had in my mind was to get this working (which it now does) and drop the whole thing into a case structure so it does the 10 tests when a GUI button is pressed. 

I will look at queue examples although its a bit scary at first.

Cheers.Andrew

0 Kudos
Message 5 of 30
(5,971 Views)

Yes, and the main question is the top level code. As I understood, he/she wants to use the DAQ loop inside another VI. Maybe if we get more details, we can propose a better solution? I am pretty sure the whole thing could be just handled by a Producer-consumer pattern with some sort of State Machine, so the DAQ task can be re-initiated at will...

 

Edit: you replied during I was editing my reply 🙂 Can you give some more details? Do you need to repeat this DAQ task in your application? Or is it ok, if you just restart the whole VI from the LabVIEW IDE?

The best would be if you give us a kind of flow-chart type explanation, like detail the steps what you want your code do...

Message 6 of 30
(5,966 Views)

Thanks cbutcher.

I hadn't thought of separating it into smaller sub vis, basically because I've done a bottom up project, to get this little bit working. I've made a skeleton GUI and then was hoping to drop in the individual sub vis once I am happy they work. For instance, there may be a very similar on to this, but doing 4 tests instead of 10. (always 40 data points)

 

I don't understand why the shift register is strange. It has to average whatever is has got, each time round, so it's not a case of doing all 10 tests , then averaging. i.e. each test takes half a second, to get 40 data points. So it is slowly building up an array of 40 columns, first 1 row, then 2 rows, then 3 rows, etc. It averages columns 1& 2, then 1, 2 &3, then 1,2,3 & 4 and so on. Each stage is plotted, not just the final average.

 

I can't see how it would work without a shift register, so I need the main for loop to keep stacking the data into the array the required number of times.

Thanks.

Andrew

0 Kudos
Message 7 of 30
(5,953 Views)

@ASH2020 wrote:

 

I don't understand why the shift register is strange. It has to average whatever is has got, each time round, so it's not a case of doing all 10 tests , then averaging. i.e. each test takes half a second, to get 40 data points. So it is slowly building up an array of 40 columns, first 1 row, then 2 rows, then 3 rows, etc. It averages columns 1& 2, then 1, 2 &3, then 1,2,3 & 4 and so on. Each stage is plotted, not just the final average.

 

I can't see how it would work without a shift register, so I need the main for loop to keep stacking the data into the array the required number of times.

Thanks.

Andrew


I wasn't suggesting that you abandon a shift register - only that you change its datatype. In the code you posted, you have a 1D array, and the previous 10 iterations are available via the LHS of the shift register.

 

In my second reply, I show a way to use a 2D array on the shift register and average the most recent 11 measurements. If you wanted to make the number of iterations variable (say 4) you would wire a control to 'N' in the outer For loop, and pass the same value (either via the inside of the N terminal, or by wiring the same control into the loop) to the lower input to the Quotient and Remainder function, which instructs the Replace Array Subset which row to replace.

 

I used a RAS, because I was responding to Blokk's comments regarding a future possible While loop. If instead you always want a known number of iterations, and you want all of them in the last averaging, you can just have a Build Array node and wire the new data to the second input with the old in the first input (and to both sides of the shift register, like so):

Example_VI_BD.png


GCentral
0 Kudos
Message 8 of 30
(5,942 Views)

Hi Blokk

Sorry, I can't post the GUI, as it has proprietary stuff on it. Basically it is a series of test buttons. For instance when you press Test1 it send a request to a certain piece of the hardware for 10 tests to be done, a 1/2 second intervals. As the test data comes in (40 points at a time) a curve is plotted. As each new test comes in, it is averaged with the last ones and again plotted. 

When you press Test2 button, it would request 4 tests to be done by a different piece of the hardware, again plotting and averaging.

Hope this makes sense. I'm happy with the way the example works, I just really need a way of plotting without waiting for the loop to finish, so passing the data out with each iteration.

Cheers.

0 Kudos
Message 9 of 30
(5,940 Views)

Right now i do not have much time to get closer look. But one thing: are you aware that your code takes 600 msec per iteration? Not half second as you want. For that 500 msec value, use the "Wait until ms multiple" instead...

0 Kudos
Message 10 of 30
(5,933 Views)