LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Programmatically create array from common cluster items inside array of clusters

Solved!
Go to solution

I have seen many questions and responses on dealing with arrays of clusters, but none that discuss quite what I am looking for. I am trying to programmatically create an array from common cluster items inside array of clusters. I have a working solution but looking for a cleaner approach.  I have an array of clusters representing channels of data.  Each cluster contains a mixture of control data types, i.e.. names, types, range, values, units, etc. The entire cluster is a typedef made up of other typedefs such as the type, range and units and native controls like numeric and boolean. One array is a “block” or module. One cluster is a channel of data. I wrote a small vi to extract all the data with the same units and “pipe” them into another array so that I can process all the data from all the channels of the same units together.  It consists of a loop to iterate through the array, in which there is an unbundle by name and a case structure with a case for each unit.  Within a specific case, there is a build array for that unit and all the other non-relevant shift registers pass through.  As you can see from the attached snapshots, the effort to add an additional unit grows as each non-relevant case must be wired through.  It is important to note that there is no default case.  My question:  Is there a cleaner, more efficient and elegant way to do this?

 

Thanks in advance!

 

Download All
0 Kudos
Message 1 of 10
(5,889 Views)

Sure, you can do this easily. Start by creating an array of clusters (similar to your final output), one element per unit. You can get the number of items in the units enumeration by using GetNumericInfo from vi.lib\utility\VariantDataType. Then, in the for loop, use the enumeration as an index into that array, and update that array element. The in-place element structure makes it easy to modify an individual array element.

 

If that's not enough of an explanation, post your code and I'll demonstrate.

0 Kudos
Message 2 of 10
(5,876 Views)

Thanks for the reply and the offer to further demonstrate.  I took a quick look at GetNumericInfo. Just for clarification, I am not using the units "native" to LabVIEW.  In my case Units is typedef with an enumeration of the units.  I don't think that is what you were implying but just wanted to clarify.

0 Kudos
Message 3 of 10
(5,850 Views)

Yes, that's correct, I wasn't referring to LabVIEW's built-in units. I should have been more clear that I meant that you could use GetNumericInfo as a way to get the number of elements in the enumeration from the size of the corresponding array of strings. Here's your VI, modified but untested. Also I disconnected all the type definitions since you didn't provide them, so you should not use this VI as is, although you can copy most of it unchanged into your existing VI. I hope it's clear what it's doing, I don't have time to write a longer explanation right now, but post again if you have questions.

ChanToGraphsSnippet.png

Message 4 of 10
(5,840 Views)

Nice example Nathand!  One minor point.  With 2011 and later those IPE's actually SLOW DOWN the code since modern compiler optomizations recognize those code constructs as safe to operate on "in place." That DOES assume that the overall code complexity is low enough to pass the "Go Ahead and apply this optomization" test (and any ini settings you might have tweaked in 2012 or later):smileywink:


"Should be" isn't "Is" -Jay
0 Kudos
Message 5 of 10
(5,837 Views)

Jeff - can you provide a reference for the claim that the IPE will be slower? It may not provide any optimization but I doubt it's going to be slower; in any case I used it here because it's fewer wires than index array/replace array subset and unbundle/bundle by name. I realize that the compiler may be able to identify the pattern as eligible for optimization, but my understanding is that the result of that optimization is the same as what you get by using the IPE. Of course, this is a trivial detail unless the VI is being run in a very tight loop - any speed difference is likely to be minimal.

0 Kudos
Message 6 of 10
(5,828 Views)

Reference unavailable.  I did some benchmarking in 2011f2 a little over a year ago and wrote an internal memo after some back'n'forth with NI.  Unfortunately that internal memo stayed internal to the group I was working with (Ironically, the same group I'm back at right now but, the memo is vapor)

 

The slow-down is due to the additional synchronization boundary the IPE forces on dataflow.  The overhead is very slight but, exists.


"Should be" isn't "Is" -Jay
0 Kudos
Message 7 of 10
(5,820 Views)

Your comments made me curious, so I put together a quick test. Maybe there's an error in the code (below as a snippet, and attached as a VI) or maybe it's been fixed in LabVIEW 2013, but I'm consistently getting faster times from the IPE (2-3 ms versus 5-6ms for unbundle/index). See if you get the same results. For fun I flipped the order of the test and got the same results (this is why the snippet and the VI execute the tests in opposite order).

benchmark IPE vs Unbundle Index.png

Message 8 of 10
(5,811 Views)
Solution
Accepted by topic author NI-hilator

Nathand & Jeff: Thanks for the info on the efficiency of various methods. Timing is not critical in my case.  Just wanted something more elegant and less code maintenance.

Nathand: Thanks for the code. It doesn't quite do what it should though. The output array should only have one cluster for each unit type.  Since the initial array is initialized with the cluster constant and the Units constant has CCM for the default, any of the units that don't appear in any of the channel clusters get a CCM units by default.  So, I added a loop after the initialize array to set the units enum to a unique value for each cluster.  See attached.

 

Thanks again!

 

ChanToGraphs.png

0 Kudos
Message 9 of 10
(5,785 Views)

@nathand wrote:

Your comments made me curious, so I put together a quick test. Maybe there's an error in the code (below as a snippet, and attached as a VI) or maybe it's been fixed in LabVIEW 2013, but I'm consistently getting faster times from the IPE (2-3 ms versus 5-6ms for unbundle/index). See if you get the same results. For fun I flipped the order of the test and got the same results (this is why the snippet and the VI execute the tests in opposite order).

 


This seems like a poster child for using the IPES!  We can look at the index array + replace subset and recognize that it is in place, but the compiler is not so clever (yet!).  The bundle/unbundle is a well-known "magic pattern" so it should be roughly equivalent to the IPES, with a tiny penalty due to overhead.

 

Replace only the array operation with an IPES and leave the bundle/unbundle alone and I wager the times will be roughly the same as using the nested IPES.  Maybe even a slight lean toward the magic pattern now if I recall correctly.

 

If you instantly recognize all combinations which the compiler will optimize and not optimize, or you want to exhaustively benchmark all of your code then pick and choose between the two to avoid the slight overhead.  Otherwise I think the IPES looks better, at best works MUCH better, and at worst works ever-so-slightly worse.  And as a not-so-gentle reminder to all:  if you really care about performance at this level of detail: TURN OFF DEBUGGING!

0 Kudos
Message 10 of 10
(5,769 Views)