PaulL Posted September 22, 2009 Report Share Posted September 22, 2009 I have a support case open with NI on this issue (OK, it's been open a while) but I thought it deserved its own topic. Suppose I have a control (named "angle") that is a type DBL and has an associated unit (deg). Suppose the value is 10 deg. Now suppose we want to write this to an XML string. We might want something like: <angle>10</angle>. OK, ideally we want to write the unit as an attribute but I'll settle for getting the correct value and the correct name. Note that the format of the XML string follows the schema used in SimpleXML in Java or in JKI's EasyXML Toolkit (which we like). LabVIEW's internal Write To XML method has a different (uncommon!) format but the issues we describe here apply equally with that method. Well, if we just wire the control to, for example, JKI's EasyGenerate XML VI, the output actually is: <angle>0.174533</angle> Yes, the value is the radian equivalent, simply because the value on the wire in LabVIEW is always in the SI unit. Now, say we really actually want to represent the value in the XML output in the original units. (There a couple reasons why this is desirable: first, we might be using XML as a message passing tool so that converting on one end and reconverting on the other is quite silly extra work, and second--and more importantly, writing values as finite ASCII strings and doing the conversions will result in round-off errors--of course!) Well, then, it seems we need to strip the unit--but retain the value--before writing to XML. Accordingly, we might use LabVIEW's Convert Unit function, which will, if the convert unit matches the source unit, produce a pure number. This sounds logical, but we have a problem. Since the Convert Unit function is really just a subVI, the output value doesn't retain the original name, so when we wire it to JKI's EasyGenerate XML VI the output is: <unnamed_numeric>10</unnamed_numeric> This is not exactly what we wanted, either! Does anybody have a way to write a value with units (any valid unit!) to XML 1) with the value corresponding to the desired unit 2) with the correct name that also must a) work as a subVI? ____ OK, I do have a workaround to do this using variants (which helps with the subVI constraint) to read the name before the Convert Unit and then write the name to the Convert Unit output. This works but 1) a LabVIEW bug necessitates putting To Variants outside the subVI, making this a little messier than I'd like in order to work with arrays as well as single values 2) it's a pretty inelegant solution (the subVI requires two inputs, actually!) that requires the use of some fairly complex OpenG VIs that seem like overkill (and an extra maintenance challenge) for the purpose. Hence I'm hoping one of the LAVA folks has a better solution! Thanks! Paul Quote Link to comment
smenjoulet Posted September 23, 2009 Report Share Posted September 23, 2009 Paul, Don't know if this will fit your requirements, but I worked this up. It does use some OpenG VI's, but I don't think you're getting around that. Sorry if it's a little sloppy. There are a couple different methods contained within this one VI, and both outputs work well with the JKI EasyXML toolkit. Just wire up a Number with Units wire the outpust to your EasyXML VI's. I'll try and post some additional comments later. {additional comments below} A few caveats: - You'll need the OpenG LabVIEW Data VIs, which I assume you already have. I didn't include them. - As I said, it's a little sloppy, especially with two solutions in one VI The top solution (variant in/variant out) will give you results in SI base units. You can see that there are two unit attributes: one with the unit names, and one with the symbols. You could use whichever suits you best. Also, I used [ ] as delimiters for each base unit. The bottom solution (refnum in/variant out) will keep your original units, but you have to use a reference to a control that contains the data. That is so you can get the units. You'll also need to provide a conversion from the base units back to your desired unit. Not ideal, but right now I can't think of another way to do it. I included your example of degrees/radians. If the variety of units you use are limited, it should be manageable. Why don't you post your workaround and see if we can collaborate. Scott physical number to variant with units attribute.vi Quote Link to comment
PaulL Posted September 24, 2009 Author Report Share Posted September 24, 2009 Scott, The first method (with variants) in your VI bears some similarities to the method on which I have been working. When I wire up a control ('angle', with a value of 10 deg) we get the Base Units (rad) in your VI. We want the value in deg. Nonetheless, a version of the this approach really does work (although a LabVIEW bug requires a To Variant outside the subVI to make it work all the time.) The second method (with Refnums) is actually more desirable in some respects, especially since it is a reference to a control and therefore can obtain the original unit (which is one of my requirements). Unfortunately we don't have a reference to the control in our case since we are extracting the values as data members from LabVIEW objects. Paul Quote Link to comment
smenjoulet Posted September 25, 2009 Report Share Posted September 25, 2009 I don't think you're going to be able to get anything other than the base SI Units using variants. The original units information seems only to be tagged with the control. That makes sense as it is only needed to convert from the SI unit that is on the wire for display purposes. Doesn't make it any easier on you when you actually want the original unit and value for some other purpose. The only additional thing I can think of that may help (and you may have thought of this already) is doing the conversion to original when using the variant method. Basically, you'd have to map the base SI units on the wire to your desired unit and do the conversion. This would only be a 1 to 1 relationship. Therefore you couldn't have temperature units being converted from K to both degC and degF. So it limits what end units could go into your XML. Maybe it's an option to help you get closer to your desired goal. Out of curiosity, what is the bug that requires the use of "To Variant" in some situations? I didn't run across that scenario. If I think of anything else, I'll send you a PM Scott Quote Link to comment
PaulL Posted September 25, 2009 Author Report Share Posted September 25, 2009 Scott, Yes, to get the original units we have to know something about the control, not the wire. This is what the Convert Unit function does. What I was trying to do was use the Convert Unit function to get a pure number in the desired units. The Convert Unit output doesn't retain the name, however, so I need that from the variant. I'm not exactly sure what all the constraints are on the bug, but basically what I did was the following: Create a numeric (DBL) control with units in deg on the front panel of VI A. Wire it up to a Convert Unit function with units deg to get a pure number. Wire the output of the Convert Unit function to a subVI (create VI B for this purpose) that has a variant input. (A coercion dot will appear, of course.) Run VI A. The variant control in the subVI (VI B) correctly shows the value with no units. So far so good. Now replace the numeric control (VI A) with an array of these numerics with units. Run VI A. The variant control in the subVI (VI B) correctly shows an array of values with no units. Still good. Now make a copy of VI B (make this VI C--it needs to be a separate VI) and wire the numeric array in VI A directly to the variant input of VI C. (Note that this is before stripping the Convert Unit function.) Run VI A. The VI C control has an array with units (the base units, as expected). The VI B control has an array with units, instead of a pure number. This is unexpected! A workaround is to use To Var functions outside the subVIs instead of having the coercion dots. (This is not ideal, of course, since it means we can't just do a search and replace on a subVI when we find a better method.) A huge deal? Maybe not. It does make me wonder just what exactly the rules are. For the record, the CAR # is 186761. Paul Quote Link to comment
PaulL Posted September 25, 2009 Author Report Share Posted September 25, 2009 Just to add some detail to my previous statement: What I was trying to do was use the Convert Unit function to get a pure number in the desired units. The Convert Unit output doesn't retain the name, however, so I need that from the variant. So my workaround is currently to wire the control to the Convert Unit function, then wire the control and the output of the Convert Unit function to a subVI with variant inputs. From one input (wired from the Convert Unit output) the subVI gets the pure number and from the other input the subVI (wired from the control itself) it gets the name. It then sets the name of the variant with the pure number based on the name from the control. (I'm using OpenG VIs for all this.) Then it writes the result to XML using an Easy XML VI. (Whew!) This process essentially works but now I need a Convert Unit function, two To Var functions (because of the bug) and a subVI to do this. I can't put the Convert Unit functions or the To Var functions inside the subVI. It's not the end of the world, but I think there should be a much better way! That's an awful lot of complexity I need to repeat in a lot of VIs I have to do a fairly simply thing. (I don't know if there is a better way in the current version of LabVIEW, actually, but I'd like to see this change. OK, there are a lot of design issues involved here: units handling most of all, XML secondly, but also LabVIEW object design. I was hoping I was wrong and somebody had a clever way to do this without too much trouble!) Paul Quote Link to comment
PaulL Posted October 23, 2009 Author Report Share Posted October 23, 2009 OK, I have now implemented a workaround (that takes off from an idea offered by NI support) that I think is at least fairly robust. The essentials are: 1) When flattening data with units to XML, wire the data twice to the workaround subVIs we create. The first input is really for the data and allows us to create polymorphic VIs so that we can only wire, say, a Double array with a compatible unit to the workaround subVI. The second input is a variant. We use the VIs in the VariantDataType Utilities library to verify the type is correct and, more importantly, to extract the name of the data. A third input is a typedef of the units for the particular type of unit to specify which unit we want in the XML representation. 2) Unflattening data works the same way except that the first data input is solely for type information. I created polymorphic VIs for Double scalars and arrays for a subset of units (currently planeAngle, Time, Pressure, Force, TemperatureAbs, Length, Velocity, Acceleration, Frequency, and Mass). Adding to this is straightforward but beyond our current scope. I can make the code available if anyone is interested. Some further thoughts: 1) While I consider this to be a reasonably robust workaround, I don't consider this to be a final solution. In particular: a) Having to wire up a node to two inputs on a subVI, while relatively robust in this instance, is quite inelegant. It always begs the question. b) Creating instances to handle new variations (different data types or different units), while straightforward, is time-consuming and should not be necessary at the developer level. 2) I would encourage NI to consider the following: a) Why can't the developer get name and type information from a data item from a LabVIEW object reference in the same way they can get this information from a reference for any other type of LabVIEW data? There may be an issue with security here, but this is quite an important issue that keeps recurring, I find. NI should really figure out a way to allow this if it is in any way possible. b) NI should modify the Convert Unit function so that the data name out (at the various levels) is the same as the data name in. In fact, that is by far the simplest resolution to the current issue. c) Again, NI should make an implementation of XML that conforms to some common schema (a standard, if possible). The XML schema LabVIEW currently implements is useful within the LabVIEW environment, but useless in communicating with an external development environment (e.g., Java). There are immensely powerful possibilities that open up when we use a truly interchangeable schema. Paul Quote Link to comment
PaulL Posted October 23, 2009 Author Report Share Posted October 23, 2009 Two more notes: 1) We use the name to do a search and replace on the XML output. 2) The code I wrote works with JKI's EasyXML VIs, but one could easily change the search and replace to work with LabVIEW's native XML VIs. Paul Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.