Jump to content

mje

Members
  • Posts

    1,068
  • Joined

  • Last visited

  • Days Won

    48

Posts posted by mje

  1. The basic timing primitives and VIs that have timeouts function off a resolution set by the system timer which is controlled by the host operating system. Even on modern PCs, you'll at best get a system timer resolution between 10-20 ms. This is something LabVIEW inherits from the OS, I believe all non-deterministic operating systems have similar resolutions. I've done very little deterministic programming, and none of it in LabVIEW, but even then I was dealing with tick resolutions on a similar timescale.

    The reason the system timer is so coarse is largely beyond my comprehension, but as I've been told it more or less boils down to scheduling. Having the scheduler decide what to run is overhead, and chopping the timer resolution up into finer increments means your scheduling overhead runs more often, chewing up a larger fraction of your processing time that is best spent executing other things.

    All of that though has nothing to do with how fast a VI can run. You can get VIs to run in well under a millisecond. You probably won't get down to a microsecond though, there is some amount of overhead involved in a VI call (as is the case with function calls in any language). That doesn't mean you can't execute a chunk of code more often than a microsecond, careful placement of loops, use of inline VIs, and subroutines can make for some pretty impressive speeds.

    However to get meaningful metrics off pieces of code like that you need to loop such that you execute however many times to get an appreciable amount of time passing, then divide the elapsed time by the number of iterations.

  2. Thanks Phillip! That quadtree is pretty much what I imagined in a 2D space. New words are fun!

    What I'm really after I imagine is simply extending a binary search into N-dimensions, but the fact that's I'm dealing with areas, volumes, or N-dimensional volumes does add a slight kink. That seems like a good start.

  3. Hi Gang,

    I need some help with some computer science grammar.

    Say I have a 2D surface and an array of rectangles in that geometry. For an arbitrary coordinate I need to determine which rectangle, if any, contains the coordinate.

    I have a simple solution that just tackles it via brute force, and it works just fine because I typically don't have to track more than a thousand features.

    However I think this is a good learning experience. I imagine how one can do much better than iterating over each element by building a branching data structure and stepping through the hierarchy. I know this is a common problem in math and CS but I have no idea what this is called, so I'm not having much luck with blind searching. Does anyone at least know the name of what it is I'm trying to do?

  4. That's interesting. Though both my xcontrol and native ui tests now render reasonably quickly now, the xcontrol is considerably laggier. I wonder if it's the two UI queues competing for processing.

    Might be best if I stick with the devil I know...

  5. Ah, found a flaw in both my test and the xcontrol.

    Basically, the xcontrol was hanging onto the raw picture data, which is a bunch of non-rendered opcodes. The test was using a pre-rendered bitmap. It seems moving an image around is far more efficient if it's a "flat" bitmap. Add in this little ditty before dumping the image into the picture control and things work quite well.

    post-11742-0-15370600-1332429068.png

    Ok, I'm back on the XControl bandwagon.

  6. I took my first plunge into XControls a while ago with a proof of principle of some functionality I'd like to implement in one of my applications, and I'm curious to hear from those of you who have more experience with them than I.

    My XControl is basically a single 2D Picture, with a some rendering logic attached to it. In the end, it generates a decent size image (usually in the neighborhood of 5-10 MP), and has tracking logic to translate location to rendered features.

    Obviously I'm only showing a subset of the image at any one time. I found the easiest way to do so is just to play with the Picture.Origin properties of the control, or alternatively just show the picture's scrollbars. The problem is both of these are hideously slow in the XControl, when operating on the picture I'm lucky to get more than 2 or 3 frames per second.

    In another test, I borrowed the rendering logic of my XControl, and used it to render into a picture control in a normal VI, then tried handling the same mouse tracking algorithms in the VI's own loop+event structure and it works pretty slick, moving the picture around is very smooth.

    So the question is, is there something about an XControl implementation that is fundamentally slower than just kludging together all the pieces in a "normal" VI? I really like the XControl encapsulation, but if it comes at the expense of performance, I'll take kludgy over encapsulated any day. I keep looking at the XControl trying to find something that will slow things down, but I admittedly still don't really understand what's going on under the hood of XControls, so I think I'm fighting a loosing battle on that front.

    Sorry, I can't post the XControl logic. I'm just curious what others experiences are.

  7. I think it's quite well documented.

    Although you can specify the shared library to call by name or by path, these techniques use different search algorithms for locating the shared library and have different ramifications on distributing the shared libraries with stand-alone applications. Ensure that you choose the proper technique for your use case. For example, always specify system shared libraries, such as kernel32.dll, by name.

    Note the referenced link in the quote.

    Also relevant is the KB article Configuring the CLFN, which describes using wildcards, and a few other nuggets.

  8. This one caused me a day of grief.

    Turns out an error in the start up logic of one of my applications would request a duty cycle of NaN to a counter output I'm using for pulse width modulation. The problem is the NaN request goes through without returning an error. But the next request to update the duty cycle hangs the DAQmx write VI. After hanging, there's no way out, aborting the calling VI leaves LabVIEW in a sorry state.

    Example:

    post-11742-0-66818400-1332266046_thumb.p

    WARNING: Running the snippet above can leave LabVIEW in an undefined state. Save your work before you do so!

    Now obviously a NaN duty cycle makes no sense, but I'd expect DAQmx to be able to handle such requests gracefully, either by ignoring them, or preferably issuing an error.

    I've observed this behavior on the USB-6343 device.

  9. Gotcha, that makes sense.

    I actually see an error in my post, I was trying to say I expect the alternatives to be containment. All these silly semantics. Aggregation and containment are different forms of composition. I trip over these words all the time.

    Anyways, to me what you describe is containment, because the Engine becomes attached to a Car, and once attached is only accessible through the Car. I completely agree though that the line gets blurry, because you definitely can have an Engine before you have the Car, and it could also be removed, or returned when you're done with the car...

  10. Also somehow missed this discussion the first time around.

    I've noticed a budding trend in my LV development that I want to stop and consider. When I have a class that aggregates other classes -- meaning that the owning object has a different lifetime than the owned object(s) -- I've started putting the owned object into a DVR and holding the DVR in the owning object.

    I don't understand how an aggregation model can ever be implemented purely by value. The very fact that you're aggregating something with a lifetime independent of the aggregator means the items being aggregated are exposed and potentially likely used outside of the scope of the aggregator. If these objects are operated on in an external scope and you're aggregating by-value, how would the aggregated values ever possibly contain accurate state information?

    The aggregator model to me requires some level of referencing mechanism, be it DVRs or otherwise. If anyone can generate an example illustrating otherwise I'd love to see it, but I suspect such examples would actually be composition (where the lifetime of the contained objects is tied to the container).

  11. The closest I think you can come is using nested subpanels. Top level VI is simply one with two subpanels. It hosts one of your dynamic UIs in one and a clone of itself in the other, which in turn hosts another UI and another clone. Keep going until done. You then would need to manage the scrollbar on the top level VI, along with the size of all the nested panels.

    In theory doable, but very messy. I have an app I'd like to do this in, bit the kludginess of it all has turned me off even trying. The good news is that this should be doable in a fairly extensible way, but I agree dynamic control creation would be way better.

    • Like 1
  12. So I am strongly contemplating just having one function "Register XYZ.vi", and if the user passes zero for the value to register, that just removes the item from the table (registering zero and not having an entry in the table are functionally equivalent).

    Other than the obvious changes in interface, I really don't see the difference because in the end they are functionally equivalent: there exists some means of unregistering. Between these two options, I prefer an separate unregister method because it's more explicit. I know you said you're working entirely by value, but the unregister method is also somewhat consistent with the acquire/use/release paradigm that is all over the place in LabVIEW, even if that is usually for reference objects.

    Now of course I can't really say if an unregister method is required. That's something that's on you. I imagine you're entertaining the idea though because you can imagine at least one use case where it would be useful...

  13. Can't say I know the hardware, but I just finished an application that had to do much the same, only I was doing an SPI read rather than an counter read after a digital edge is received.

    All I can say is I had zero luck with any form of digital edge detection in DAQmx (the mode where you set up an event structure to get signaled upon a digital edge transition). Everything seemed to work as no errors would ever be generated, but nothing would ever cause my blocked code to wake up. The example VI didn't work either. I'd watch the pulses go by on my scope, meanwhile the DAQmx driver was on a coffee break or something. I know the mode works though, as I have used them in the past, all I can say is there seems to be something going on where some hardware just silently refuses to work in this mode. This was on an X-series USB device for what it's worth.

    I could poll the line and things would work...

    Ultimately I ended up configuring the digital line as a clock source for a timed event structure and I do the read when the loop wakes up. No idea why the digital edge can be detected as a clock source but not a digital edge. Maybe it's just not...edgy enough? One of those mysteries of the NI universe I guess.

    /shrug

  14. It is very important to realize the cast or flatten primitives do not provide you with the binary form of the data as represented in memory. They do provide you with a serial form of the data which can be used to rebuild the data. It's an important distinction.

    When passing variable length data into DLLs, break them out of any struct/clusters. Fixed length clusters are fine, so long as you're mindful of byte boundaries/padding (#pragma pack(), etc). For arrays and such, pass in two items, an integer specifying the length, then the actual array as an array data pointer.

    For example:

    post-11742-0-35007700-1331140130.png

    This code calls a DLL to generate 3 arrays of data all of equal size. It first initializes three dummy arrays at a known maximum size, then passes the arrays, along with their size to the DLL, which populates the arrays with data. The DLL knows not to exceed the given size, and returns the actual number of elements used, so LabVIEW then trims the arrays if needed after the DLL call.

    The other way of doing it is to make two serial calls to a DLL, one to determine the size of the arrays you'll need, LabVIEW then initializes the arrays, then call the DLL again by supplying the appropriate sized array. Which to use really depends on where your bottleneck is.

    • Like 1
  15. Yeah I totally agree that this should be a native LabVIEW function in the event structure.

    Indeed. The good news though is in normal UI situations (read: not an XControl) you can come pretty darned close. Make a user event, then pass it onto a DLL which registers the hook, meanwhile the LabVIEW side registers for the event dynamically with an event structure. When the DLL's hook callback gets called*, it forwards the signal into waiting LabVIEW event structures via a call to PostLVUserEvent.

    Of course XControls don't play nice with dynamic events, so in that case you need the intermediate LabVIEW worker task. Seems the simplest option is to have a hidden control in the XControl, which you can then invoke a Val (Sgl) property change to affect statically linked code within the event structure (yes, that's creating a dynamic event and a worker task whose sole job is to ultimately trigger statically linked code). This is my first foray into XControls, and I'm still not convinced they are a good thing. Might be my last...

    *There's of course a little more book keeping, such as comparing window handles and making sure the mouse coordinates are over the correct controls.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.