06-13-2012 03:56 AM - edited 06-13-2012 04:01 AM
@rickford66 wrote:
Won't that force copies to be made in my sub vi because I'd then have to use an output array?
First of all, LabVIEW is a dataflow language and its data is NOT reference based. If you pass in an array into the subVI and replace an element in it then yes LabVIEW needs to create a copy of it. This is because the caller VI has to retain the original array, to pass it into the subVI again in the next iteration, and the Replace element function is not replacing an element into that array by reference but instead creating a new array to replace that element in. Actually I would guess that LabVIEW is actually creating the new array when passing the array to the subVI rather than inside the subVI since the connector terminal on the subVI gets flagged by the compiler that the subVI is modifying the actual data inside the subVI. However this needs to be taken with caution as this are areas that LabVIEW has changed regualrly in how it optimizes code but it's unimportant for this cause, as the data copy will be done, either when passing the data to the subVI or inside the subVI for the Replace Array Element node. Since you do not pass the modified data out of the VI, this modification is lost and the subVI starts with a new zero array each time.
Now if you use a shift register in the main VI to hold onto that array AND write the subVI such that this array is passed into the subVI on one side and out of it on the other side AND wire the left side of the shift register to the input and the right side to the output AND make sure that the terminals in the subVI are not somehow inside a case structure or another LabVIEW structure, LabVIEW will actually NOT make any array copy at all (and you will get your circular buffer operation that you want). This is the whole purpose of shift registers and the LabVIEW developers spent thousends if not tenthousends of hours to make this shift register optimization not only possible but actually work reliable.
06-13-2012 06:03 AM
Now if you use a shift register in the main VI to hold onto that array AND write the subVI such that this array is passed into the subVI on one side and out of it on the other side AND wire the left side of the shift register to the input and the right side to the output AND make sure that the terminals in the subVI are not somehow inside a case structure or another LabVIEW structure, LabVIEW will actually NOT make any array copy at all (and you will get your circular buffer operation that you want). This is the whole purpose of shift registers and the LabVIEW developers spent thousends if not tenthousends of hours to make this shift register optimization not only possible but actually work reliable.
I'm not trying to be thick headed, I just want to be clear. If my sub vi contains an array input and an array output, and I just have a simple path from input to output that only contains the replace element function, then the output array will be the same array as the input array and not a copy? So then, I can wire them to a shift register in the calling vi and no array copies will be made?
06-13-2012 06:14 AM - edited 06-13-2012 06:16 AM
@rickford66 wrote:
I'm not trying to be thick headed, I just want to be clear. If my sub vi contains an array input and an array output, and I just have a simple path from input to output that only contains the replace element function, then the output array will be the same array as the input array and not a copy? So then, I can wire them to a shift register in the calling vi and no array copies will be made?
That is indeed the idea, and except in a few older, intermediate LabVIEW versions, that had an optimization bug in such things, this is also what will happen. You could in newer versions of LabVIEW make this even more explicit by using the LabVIEW Inplace structure inside the subVI. This will not only hint to LabVIEW that you really intend the operation to be inplace but also show a casual reviewer that this is what you have intended. But in this particular simple case, the Inplace structure is not really needed in order for the operation to be automatically inplaced in LabVIEW. This is one of the really amazing parts of the shift registers, that can analyze such use and optimize it accordingly (and the first few LabVIEW versions that had a Feedback Node did NOT implement in the same way, always causing data copies when the Feedback Node was used, despite the fact that a Feedback Node is mostly a shift register turned inside out).
06-13-2012 06:28 AM
Fabulous. When I get to work, I'll have to rewrite it as such.
Thanks to all who contributed. I think part of what was making this difficult to understand was that I've done it before lots of times and it's worked, and I'm not sure what the difference was. In all those cases, I fed the array to a node that called a driver function... the array was passed by reference so the driver put the data in the same array. Then, the next time around, I used the data from the array in the application, and then performed the same driver call after I used it to get data for the next time around. I may have to start a new thread to find out why that works when what I tried in this thread doesn't... if I can find time. Gotta get this app done. Thanks again everyone.
06-13-2012 06:43 AM - edited 06-13-2012 06:45 AM
@rickford66 wrote:
Fabulous. When I get to work, I'll have to rewrite it as such.
Thanks to all who contributed. I think part of what was making this difficult to understand was that I've done it before lots of times and it's worked, and I'm not sure what the difference was. In all those cases, I fed the array to a node that called a driver function... the array was passed by reference so the driver put the data in the same array. Then, the next time around, I used the data from the array in the application, and then performed the same driver call after I used it to get data for the next time around. I may have to start a new thread to find out why that works when what I tried in this thread doesn't... if I can find time. Gotta get this app done. Thanks again everyone.
I assume that your driver was an external code function called with the Call Library Node. In this case the data is indeed passed as a pointer reference to the extenal code and if that code modifies anything inside that data this will reflect in the LabVIEW data buffer. But it is very unreliable. Unless you use the data array on the right side of the Call Library Node to go further, the change to the data could be in a temporary copy of the array and get lost as soon as the sub VI returns. The reasons for LabVIEW to create a copy of data or not are involved but always logic. A change in this logic can be triggered easily by a seemingly harmless change of the code, such as branching of the wire to do some other operation on it that LabVIEW determines needs to get it's own copy of the data in the wire. Also, improvements in LabVIEW optimization between versions can cause a change in LabVIEW when determining the logic when an array needs to be copied or not. So your use of the hidden modification of LabVIEW data by passing it by reference to external code is likely to cause problems sooner or later that will be hard to debug.
06-13-2012 07:44 AM
@rickford66 wrote:
Fabulous. When I get to work, I'll have to rewrite it as such.
Thanks to all who contributed. I think part of what was making this difficult to understand was that I've done it before lots of times and it's worked, and I'm not sure what the difference was. In all those cases, I fed the array to a node that called a driver function... the array was passed by reference so the driver put the data in the same array. Then, the next time around, I used the data from the array in the application, and then performed the same driver call after I used it to get data for the next time around. I may have to start a new thread to find out why that works when what I tried in this thread doesn't... if I can find time. Gotta get this app done. Thanks again everyone.
I thnk Rolf nailed the confusion factor becuase the call library function is the only *(?) time data data can flow backwards through a wire.
If you are interested in getting abetter understanding I suggest you go back in this thread and review the notes and links I posted. Part of those notes explained how you CAN SEE the data buffers used by LV.
The "Clear as Mud" thread includes posting by one of the senior architects of LV explain how and when LV will pass data to a sub-VI as a pointer vs a new copy.
The other suggestion not mentioned above is to watch your code in executiion highlighting mode (turn on the light bulb). Use some probes to monitor what is in the wires. That exercise alone would have shown you that you were passing the same intitalized array to the sub-VI every time it was called.
Re: Lightbulb mode
I have told my rookies that they should spend some time watching their code in execution highlighting mode and when they get to t the point that they can predict what operation will happen next, they will have good idea about the data flow paradigm.
Ben
* There was a bug in an earlier version of LV but I am not sure which version but due to a bug data could actual flow backwards through a wire becuase the compiler failed to create a copy of a diagram constant. This manifest itself as the constant itself would be changed and when teh VI was saved, the updated cluster value was saved also. This was very "freeky" when viewing in a data flow mind set.
06-13-2012 09:34 AM - edited 06-13-2012 09:40 AM
Ok, I've gotta know why this use of an array works, but the previous use does not. That is, my original post created a new array copy loaded with all 0's for use each time the loop iterated. The vi I have posted here, a stripped down version of my main vi, holds the data across loop iterations. Why?
Note, the FTD2xx is actually FTD2xx.dll. You will need to change the extension.
06-13-2012 09:44 AM - edited 06-13-2012 09:46 AM
You are still doing exactly the same garbage, but spread over two stacked sequence frames. A sequence local is NOT a shift register.
You are also not touching the array this time (no replace array subset), thus it remains static. You are just indexing elements out.
If this is the subVI, can you show us the calling VI?
06-13-2012 09:48 AM - edited 06-13-2012 09:52 AM
...and since there are mods of the array the dll works in that array. Please see Rolf's reply and mine where I commented this is the one situation where data can appear to flow backwards through the wire.
The question you are asking is very complicated and there is no simple answer. If you you really want to understand this situation you really have to read the previous posts by Rolf and others.
Ben
06-13-2012 11:26 AM
This thread has gotten so long that I think it is creating a communications gap...
I have gone back and read the things you have written. I have carefully read the entire thread over and looked up the clear as mud link. I am also aware that making a call to an external dll function in this way passes the array by reference and that when the dll function makes the change, it will occur on the same array that was passed to it and not a copy. I have learned about putting the input and output variables in the root of the sub vi and all that... very informative.
Now...
I am aware that I am "still doing exactly the same garbage" in the most recent vi. Actually, that's not exactly true because my most recent code post was written years ago. I know it's the same, that's why I posted it. The most recent vi post, WhyDoesThisWork.vi, is what I modeled my original code (and original question) on. That is, I wrote code that was supposed to process a buffer, the same buffer, over and over. You all have shown me why it doesn't work, and now, using shift registers, it works fine. My question now is, if my original code on this thread didn't work in its original form, and required a shift register to work, then why in the world does the WhyDoesThisWork.vi work, because to me it looks like the same thing. I'm aware that the dll function call is done by reference and so a copy is not made, but the array is not used immediately. It is used after the loop iterates a couple times... so why is the array, by the time it is processed, not reset back to the original as it was in my first post? Is it simply because I index it instead of replacing the variable? Does LV create a new array everytime the array is modified by Replace Element, even though there are no other branches that modify the array? That's not was I was told by an engineer at NI... he told me LV had to detect a conflict... ie, 2 paths that changed the array. Besides, it seems terribly inefficient if a copy has to be made everytime the Replace Element function is used. BTW, the WhyDoesThisWork.vi is the main vi.
Thanks for the patients everyone.