VI High 66 - How to Use XY Graphs with Inconsistent Timing

Much like the frequency we post VI High episodes, the timing of your data can be inconsistent. This episode, we explore the basics of XY Graphs, and then see how they can be used to display data taken at inconsistent timing intervals in a state machine. This completes our 4 episode series on charts and graphs in LabVIEW.

Come visit us at sixclear.com/labview-training

And keep up with us here:
http://facebook.com/sixclear
http://twitter.com/sixclear
http://gplus.to/Sixclear

(start transcription)

Thanks again for coming to visit us at VI High. We have been talking about waveform charts and graphs, we discussed their main differences, we looked at adding multiple plots to each, we changed their timing around, and I have been shamelessly encouraging binge watching by alluding to an XY graph discussion, which has finally arrived, after which you can go to bed, get up for work in an hour, spend the first hour tweeting to your friends about the amazing finale, hashtag us, but please no spoilers.

XY graphs are different than waveform charts and graphs, because we are plotting two arrays against each other. For instance, let’s have an array of pressure readings and a corresponding array of temperature readings. I want to plot them against each other, and an XY graph is perfect for this. As always, bring up our Context Help, and it tells us we need a bundle function. I run it now which one is which? The Context Help tells us X array and Y array. So, generally we would have the temperature on the X array so I will switch these. There we go, and I want to relabel these. Now, that is all pretty simple, but the last episode I talked about using an XY graph for inconsistent timing. Let’s see how to do that. I will open up a new VI, put down a random number function, which I will let go a hundred times, ten milliseconds per time, and at first I will start out pretty simple. I will use for my timing palette to get date time in seconds, and as before I will make arrays of these by wiring them to the border. Bring up my XY graph, and use the bundle function. Run it, and it looks like we made the same mistake as last time, and as before I will make arrays of both of these. As we learned, whatever is the top input to the bundle function will be the X axis, so I want this to be the X axis, this the Y axis. Wire them both to the border, put a bundle function down and wire them both to the bundle function and then to an XY graph. Run it. Now, my values across the bottom, what are those? 3.5 billion? Well those are the number of the seconds that are elapsed, since January 1st1904. As our Context Help tells us regarding to get date time in seconds. Now that is not too helpful for the display though, so I can right click, properties, go to my display format, for my time X axis, and then I will change it to absolute time, and I will get rid of the date. So, I just show the time. Actually I will get seconds, okay. Let’s run this again, now this is shifting around a little bit, because the time at which I start the VI, and thus the first time stamp won’t always be exactly on a second, so we see it moving around a little bit, but the common way this would be used, would not be in the method that I have shown here, but rather we would typically have one or more data points being acquired at a single time, and then have time stamp affixed to that, and the next time we get another piece of data we will put another time stamp on it, so that the end result is that we will have an array of values, and then an array of time stamps, corresponding to when those values are taken. For instance, maybe I have a state machine and I cycle through my states and then one of my states is take temperature, whenever I arrive at this stage I will take the temperature, and then get a time stamp from when that temperature is taken, and then I put that on a graph. This XY graph, because the time at which I come to that state in the state machine varies, it is not consistent.

Note that in many cases you often see these time stamp values be changed to double precision. Right click, insert from the numeric palette, from the conversion palette to double precision flow. The reason being, is that this double value ends up being easier to work with, easier to manipulate, to compare between different states, to subtract and get differences in time, etc.

Now if you take our Lucid LabVIEW Fundamentals Training, there will be an exercise called the LabVIEW toaster where you use a state machine to control the states of a toaster, timing how long would it take to toast, to cool down, checking for temperature, and so on. There are various states in the state machine and in the couple of the states we check the temperature, so here would be a use case for the XY graph application we just discussed. On my front panel is my temperature versus time with my time already set on the X axis. Looking at the block diagram I see that I have a cluster with two arrays in it, now this cluster with two arrays in it is the format that the XY graph expects. I put that in a shift register so that it is accessible to all the states in a state machine. If you are unfamiliar with state machines, go check out VI high 49 and keep watching for a few episodes. We talk all about state machines, error handling, passing data between states, and so on. As we see there are many states, and the state where we are polling the temperature is here in the toasting state. Do not worry all about this code down here. In fact, I’ll move it down. This is the part we’re concerned about. In this toasting state we access our way of time stamp and temperature, we get the new value of the time stamp, whenever this is taken, and we concatenate it on to the array. We do the same thing with the temperature array, and then we bundle both of those back into the cluster, and each loop iteration, we pass it to the XY graph. Now granted there are a bunch of things happening in this loop and we have not really dictated our execution order to ensure that these happen at about the same time. However, the resolution I am more concerned with is around the seconds range and not the milliseconds range so, this is okay with me. Then we can watch this in action if we like, we run it, hit the toast button, and see that we record temperature and time together.

Well all this toasting is making me hungry, I think I am going to toast up a salad. I’m cutting carbs. Thanks so much for joining us in this series exploring waveform charts, waveform graphs, and XY graphs. Do you like this stuff? Check out our course, at sixclear.com/labview-training, either online, regional, or we will come to your company, we would like to meet you. Now I have a salad to toast.

(end transcription)

VI High 65 - How to Change Timing on a LabVIEW Waveform Graph

What do good jokes and Waveform Graphs have in common?

Timing.

We’re in episode 3 of a 4-part series on Waveform Charts, Waveform Graphs, and XY Graphs in LabVIEW. Today it’s time to explore the timing in a Waveform Graph, changing the T0, delta T, and Y array.

Want more? Meet us at a regional course! https://sixclear.com/regionals

And keep up with us here:
http://facebook.com/sixclear
http://twitter.com/#!/sixclear
http://gplus.to/Sixclear

(start transcription)

It’s a beautiful sunny May day here in Austin. It’s about time for me to go take a run around Town Lake. Before that time, let’s talk about the time on our Waveform Charts and Graphs because so far in both of them we have time across the bottom, 0 to 99, or 0 to 100 as the default shows. But is it really time, and what are the units of this time?

Really, it’s not time, these are samples. Each sample we get shows up as a point on the X-axis, and the delta between each point is one. Of course our Y-axis is the actual value of the data we’re receiving, whether from the random number function or the sign data. It’s called time by default because our Waveform Charts and our Waveform Graphs always receive time at a consistent interval. So it’s correlated to time, but the time may not be an exact delta of one, and it may not even start at zero.

Now it’s harder to manipulate those values with the Waveform Chart, but the Waveform Graph makes it really easy for us. I’ll bring in my context help over, and we see down here, combine timing information using a bundle node. So, here’s a bundle function, and we have three inputs coming in: X0, delta X and Y array. Since those are on the X-axis, we can also think of those as T for time but in other words, this is the initial X or time. This is our delta T or our delta X, and then the actual array of data.

So let’s do that. First, I’ll just do it on a single plot, get rid of this too, and then Quick Drop’s helpful again here, select that build array function, Control-spacebar, Control-R and it gets removed and wired in its place. Thank you again Darren Nattinger, creator of Quick Drop. So let’s put some timing in here, give me a little more space, and we’ll Quick Drop in a bundle function, Control-I again.

As we saw in the context help, three inputs where the bottom one is the Y-array and then two scalars or doubles. I’ll head to my numeric palette, double numeric. This one will be my T0. Let’s say that my application actually starts recording data 10 seconds in. And then I get new data every half second. I’ll run it again. Now we can ignore the Waveform Chart for now. I ran it again so you see different values here. I’ll make this bigger and as we look at the display, we’ll decrease the number of data points and make it even more obvious.

We see that we start at 10 and each new data point is separated by 0.5. We can go a step further if we like, and make a multi-plot display as we did before. I’ll just copy this, and maybe the timing is different here. Maybe on this sensor, I start at 5 and I’m back to 1. As before, we’ll need a Build Array, run it. Now, admittedly that’s kind of a weird display because essentially we’ve locked ourselves into using the same number of data points, but with a different frequency and starting at different times which is probably not common.

What may be more common is that we have one sensor coming in at a different frequency, which over the same period of time, would probably need more points.

So let’s mock up something like that. We’ll come over here to our code. Incidentally, I’ve left this here for a while. It wasn’t necessary for all the Waveform Graph and Chart manipulation we were doing out here.

Now to create another array with a different number of points, I could just create another loop, get rid of all this down here, and let’s say this loop runs a hundred, this loop runs 150, not the cleanest code right now, but let’s take a look at it. So we see that we can have different sensors with different numbers of points, frequency and starting times on the same graph. The trick to remember here is that the data coming in will always be displayed in equal increments across the X-axis.

But what if I have data coming in that’s not equal increments? Or to broaden the question, what if I wanted to display two arrays against each other instead of having always one array of data displayed against time which are samples. Well, that’s where the XY graph comes in, and we’ll take a look at that next time, because like I said, it’s time for me to run.

It’s a beautiful day and we do courses here in Austin. You should come and visit and spend five days learning LabVIEW with one of us. Check out the next course on the schedule at sixclear.com/regionals.

(end transcription)

VI High 64 - Multiplot Displays on LabVIEW Waveform Charts and Waveform Graphs

We’re in episode 2 of a 4-part series on Waveform Charts, Waveform Graphs, and XY Graphs in LabVIEW. Today we look at making multiplot displays with Waveform Charts and Graphs.

And keep up with us here:
http://facebook.com/sixclear
http://twitter.com/#!/sixclear
http://gplus.to/Sixclear

(start transcription)

Hey! I am glad that you came back. Last episode, we saw that waveform charts accumulate data points and waveform graphs do not. Now, let’s focus on some permutations on using waveform charts and graphs, like displaying multiple plots and changing our timing.

A common thing we’ll be able to do is to display multiple plots. Maybe they are coming from different sensors, maybe a temperature and a pressure sensor, so how do I get both of those on the same chart? Well our context help is valuable in this case. I will hit control H, hover over my waveform chart and I have a little table here telling me what data to wire in, and then what the result is on the chart. As we have already seen, if I wire a scalar in I get a single plot, if I wire in a 1D array as we have done here then I also get a single plot. A WDT, or Waveform Data Type, would give me a single plot, and if I wire in a 2D array I will also get a multiplot display, or combine points with a bundle node. Let’s try that.

I will bring this waveform chart back inside the loop. Control B, wire this in here and I am going to change the timing. Make the time per iteration faster and the number of samples ten times greater. Let’s put another plot on the chart. I’ll move this out of the way for now, and to mock up some meaningful data I will grab a sine function. Using quick drop, control space bar, type in sine and then I will go grab from my numeric palette>>math constants: 2 pi. Multilpy 2 pi by the iteration number, divide it by the number of samples. To get this onto this chart we saw that we can put a bundle function right here. So I will use quick drop again, click and select the wire, control spacebar, bundle, control I, and we insert it right there. Drag this down to get multiple inputs to the bundle function. Wire this in and let’s run it. Now we’re only displaying ten points but I will come back here, back to zero, and there we go, we get a full hundred cycles of our sine wave, and on the same display we have that random number function, remembering that the random number function outputs between zero and one, whereas the sine obviously is one to negative one.

Now how do we do this to the waveform graph? Same as before, pop up our context help, hover over the waveform graph, and we get a corresponding table. If we wire in a 1D array, we get a single plot as we have already seen, a waveform data type another single plot, a 2D array gives us a multiplot. So let’s try that 2D array. Now how will I get a 2D array on both of these pieces of data? Well I already have one array and same method to go wire this to the border, get another array and to make a 2D array now out of these two 1D arrays, we use a build array. Build array function, put it down, make two inputs, delete this wire and combine these. Run it again, there we go, exactly the same display. Incidentally, you probably noticed on the waveform chart (because I read it out loud) that a 2D array would also create a multiplot for the waveform chart. Can we just use the same 2D array coming out of here? Well yes and no, because if I take it, grab it, and wire this 2D array in the waveform chart, run it again then I get a weird display. I put this at one, I can see that, well it is just really weird. What do you think has happened there? Really it is just swapping columns for rows. So I can fix this by transposing the 2D array going to the waveform chart. Quick drop again is my friend, click on the wire, control space bar, transpose 2D array, control I. There is my transpose function. Put this back to 99, run it, there we go. Actually, let’s make that one hundred because we have a hundred points.

One little last step here, now that we have two different plots let’s name them. I will come over here, drag my plot display here. I have different colors, I can change them of course if I like, including the style, the width, etc. I will keep plot zero the default except I will name it ‘Random Signal’, make plot one ‘Sine Wave’ and I can change this line width, something like that. A bunch of other options here for me as well.

So far, we have been essentially doing the same thing to waveform charts and graphs and explained how they are different, but have not really discussed when one is better to use than the other, and really that just comes down to the amount of data that you are receiving. If you are receiving a bunch of single scalar points, for instance: I have a software-timed loop reading two thermocouples and a pressure transducer, and each time I poll that loop I get a single value for each, well I would use a waveform chart, that’s easy. But if I am reading from an oscilloscope and each time I pull that oscilloscope I get a thousand points of data back, I probably want to use a waveform graph because I probably would not care to see the history of those thousand data points. I just want to see the current thousand pieces of data coming from that oscilloscope, especially if I am not using the graph to do any type of analysis, and it is just a qualitative display.

Well that finishes us up this time around. We still have more to talk about, like timing with waveform charts and graphs, and we’ll get to those XY graphs. Don’t worry!

(end transcription)

VI High 63 - What’s the Difference Between LabVIEW Waveform Charts and Waveform Graphs?

We’re starting a new 4 episode series on Waveform Charts, Waveform Graphs, and XY Graphs in LabVIEW. Today we look at the fundamental difference between the two.

And keep up with us here:
http://facebook.com/sixclear
http://twitter.com/#!/sixclear
http://gplus.to/Sixclear

(start transcription)

Charting and graphing data in LabVIEW. How do we do it? There are many options, but the foundational displays in LabVIEW would be the Waveform Chart and the Waveform Graph. How do they differ? It’s pretty simple. The Waveform Charts accumulate data points and the Waveform Graphs refresh their display when they receive new data. Well what does that look like? Let’s go into LabVIEW and find out.

Here’s my front panel. I‘ll go to my graph palette, tack it down, and choose a Waveform Chart and a Waveform Graph. Now they look a little different. The Waveform Graph has grid lines, the Waveform Chart doesn’t, but that’s changeable: I can remove the grid lines from here and put them there, I can make them look exactly the same. So let’s see how they differ in code.

First I’ll take my Waveform Chart indicator and I am going to pass some data to it. Let’s just choose the random number function and a While Loop and I’ll put some timing in here. We‘ll have this run ten times a second. As we run it we see that, ten times a second, we get data appearing on our chart. Let’s put this in highlight execution and watch what happens. Over and over we see that we are reading one piece of data, it goes to the Waveform Chart indicator and then shows up here. Now we say that the Waveform Chart accumulates data points because all of the rest of the data is left up there. In fact, if I take off highlight execution and let it run for a second, and then go back and stop it, put this at zero, then we see that we actually have a history of all that data. I can keep running this for a while and put all the data that I have on this chart. By default there is a chart history length. If I right click, chart history length, I see it’s 1024. Of course I can make that as big as I want, obviously keeping in mind the bigger I make that the more memory I am using. So make it too big and it could slow down my program.

Let’s run this again, and I can right click on this and I can go to update mode and I can see that there are strip, scope, and sweep charts. Those used to be part of the CLAD exam though it looks like, thankfully they have been eliminated as they had absolutely no bearing in one’s ability to program well in LabVIEW.

It was pretty easy to wire up this Waveform Chart, can I do the same with the Waveform Graph? Can I just take this wire coming from the random number function and wire it into here? Well we see that doesn’t work. Why doesn’t it work? Our tip strip, if we hover over tells us, “you have connected two terminals of different types. The type of the source is double, the type of the sink is a 1D array of doubles.” In other words, this random number function outputs a single scalar value, whereas this Waveform Graph expects an array, and the reason that it expects an array, stems from the fact that it refreshes its data each time it receives it, meaning it throws out all the old data and puts up all the new data whenever it receives data. Which means if it could accept a scalar, it would be a pretty bad display because it would just be a single lonely data point sitting there by itself. And so we can see that the Waveform Graph at least needs an array. So what’s an easy way to get that? Well, with our loop we know we can use auto indexing. I can do auto indexing with the While Loop but it’s smarter to do it with a For Loop because it creates an array of a known size. So right click on the While Loop, replace with the For Loop, and I’ll have that run ten times. I’ll take this out here, wire this through the border to the Waveform Graph indicator, and as we can see it auto indexes the output. I can get rid of this stop button. Here’s my scalar wire. Here’s my array of values, so run that again, there we go. Now they don’t exactly seem to match because the Waveform Chart still kept all this previous data. I’ll right click on it, Data Operations, Clear Chart. Run it again, and we see that we actually have the same data. If I put this at nine, they look exactly the same. Of course, if I run this again, I get ten new data points and they match up.

Now obviously I see the data arrived point by point on the Waveform Chart, but then on the Waveform Graph I see they arrive all at once, and that’s because of the dataflow occurring here. This is getting data each loop iteration, whereas this receives data all at the end after the loop finishes. Remember that the loop is a node and a node does not output its data until it finishes execution.

One last point, can I also go take the Waveform Chart and have it accept an array as well? Sure I can. I can pull this out here, control B to clean up that broken wire, and wire the array directly into the Waveform Chart. Run it again, and now both of these receive data at the same time. Though of course, as I keep running this we see that my Waveform Chart is still accumulating data points, whereas my Waveform Graph does not: always zero to nine, the Waveform Chart still accumulating. At any time, I can go back to zero and see it all.

So that’s the fundamental difference between the two, and in our next episode we’ll see how to manipulate the time, create multiple plots, and eventually we’ll compare these with XY Graphs. Hopefully, you have accumulated some knowledge in this episode. See you next time.

(end transcription)

VI High 62 - Numeric Conversion, Coercion, and Memory Usage in LabVIEW

Last episode, we started a discussion on coercion and conversion. We continue that discussion by profiling memory usage of a VI using coercion versus one that doesn’t. We also look at other coercion errors. Then we show a picture of Sixclear co-founder Jassem Shahrani.

And keep up with us here:
http://facebook.com/sixclear
http://twitter.com/#!/sixclear
http://gplus.to/Sixclear

(start transcription)

Welcome back. In our last episode, we watched a little YouTube and we discussed numerical representation and choosing the correct numerical representation for applications we’re designing.

Now that we’re deep into the numbers, let’s discuss coercion and conversion. For instance, I’ll take a double and an I32 and add them together. Now, what’s that little red dot there? Coercion is occurring there. It doesn’t occur due to the order that I’m wiring these up into the function. In fact if I wire the I32 first, then the double, the I32 is still coerced. But what does it mean? LabVIEW is changing the data representation in order to support the operation. That change requires a little extra memory. For instance, let’s count up the memory this little VI is taking. Eight bytes here, four bytes here, another eight bytes here and another eight bytes right there for the coercion itself. In other words, LabVIEW takes the value that’s in this I32 and changes the data representation without changing the value if it can. In this case, no problem. We can make the data width wider, without changing the data value. So if I had 112 here, added to another 100, and run it, no problem, we get the right answer out.

So what, is coercion bad? Well, as we said, it uses a little extra memory. So if we can reduce that, that’s a good thing. In many cases, we can’t avoid using the extra memory because this may be coming from some other place. Maybe I’m reading a value from a database or from a DLL and what comes out is always going to be an I32. So I have to change it at some point. So should I always just let LabVIEW change it? Can I change it myself? I sure can. I can right click on that wire and insert from my numeric conversion palette, right here. To Double Precision float. An I32 goes in, a double comes out. No coercion dot anymore. Am I using more memory? Well I’m actually using the same amount of memory as before. Four bytes here, another eight bytes for the reallocation. So what’s the advantage to converting it versus letting LabVIEW coerce it? The big reason is we choose where the conversion occurs. Because if LabVIEW chooses, it may choose to do it in a place that’s not as efficient. Let’s look at an example of that.

Let’s say I make an array, a big array. One megabyte. So we’re adding a array of one million elements to a scalar and getting a resulting array. The scalar is being added to every element. To help us understand what LabVIEW is doing here, we’re going to go to our Tools and go to our Profile Performance and Memory tool. And I’ll click on profile memory usage and memory usage. And then I start it, I run the VI, and stop it and I’ll change my size units to megabytes, because we see there’s a little bit of noise here at the lower level but we really care about the big chunks. Sixteen megabytes in this case are being used. That makes sense. Eight megabytes for the original array then another eight megabytes for the edited array. Let’s see some coercion occur now. I’m going to come over here to the element input. Right now I’m making an array of doubles but I’m going to make an array of singles. As we see immediately, I get the red coercion dot here which means I’m going to be taking an array of one million singles and changing it to an array of one million doubles in order to add it to the double. Let’s profile this memory usage. Take a look at that. Much higher. So when LabVIEW decides where to coerce, we can use a lot more memory. But this is an easy fix. I’ll use quick drop this time. Control space bar and control I to insert it. Very nice. And run it again. So we’ve definitely reduced our memory usage, but not down to the original 16 megabytes we saw previously. In fact if I take this out, quick drop again, control space bar, control R, and then change this back to a double, and reprofile this, we’ll see that we’re still at 24. Now don’t lose confidence in the profile performance and memory. It may not be exactly consistent for the same VIs, depending on what else is happening in our LabVIEW environment, but it will consistently show that coercing large arrays like we saw uses more memory than converting data types in appropriate places.

So if I’m not dealing with large data arrays, might coercion be safe just for scalars? Well, sometimes we can still get bad results. Let’s make a simple example. We’ll change this to a U8, and this numeric to an I8. I’m going to add them together. Before I add, which will be coerced into the other? Think about it, think about it, and now you know. The signed integer is coerced into the unsigned integer. Just remember that’s a rule LabVIEW follows. We always coerce signed integers to unsigned integers if they’re the same data width. Now if this happens, we can imagine, something could go wrong. I’ll create an indicator. If a signed integer is being coerced to an unsigned integer then obviously if we have a negative number in here, something could go wrong. Let’s make it go wrong. I’ll make this negative two, and this ten. Run it, what do I get, eight. Now that’s not so weird, because ten plus negative two is eight. But if the answer should be negative, we get a problem. So let’s flip these to a negative ten. Run it, 248. That’s not right. But by now, we know what’s going on. The values are rolling over to the max size of the data type and we get a data value with don’t necessarily expect, if we haven’t accounted for the coercion that’s taking place.

If you’d like to know more, there’s a helpful document in your LabVIEW help called coercion dots. It’s also online, as you can see here. It goes over many of the topics we’ve just discussed. Like programming in LabVIEW, we want to avoid coercion, but we’d really like it if you came and visited us at sixclear.com/labview-training. We have a whole course full of this good stuff. We also do live training. Maybe you’ll meet me, or another of our fantastic SIxclear instructors. Maybe Jassem. Look, he’s smiling. See you soon.

(end transcription)

VI High 61 - Understanding Numeric Representation, Integer Overflow, and Fractional Values

How big of a number can we put in an I32? A double? What happens when we try to cram a bigger number into a data space that can’t hold it? We explore these questions today, as well as look as designing applications with these concepts in mind. Next time we’ll talk about numeric coercion and conversion.

Want to meet us? Come to a regional course! sixclear.com/regionals

And keep up with us here:
http://facebook.com/sixclear
http://twitter.com/#!/sixclear
http://gplus.to/Sixclear

(start transcription)

Here at VI High, Sixclear’s LabVIEW training video blog, we believe in the power of YouTube to enact meaningful social change as well as teach technology. Now, on our videos we have almost as many views as PSY, but he did beat us to the punch in breaking YouTube by reaching 2,147,483,647 views, and as we can see, he surpassed that. There was a kerfuffle lately about reaching that number. So, why is it significant?

Let’s pop into LabVIEW and put down a numeric, and I’m going to change this representation to I32. When I hover over it, the Context Help tells me its range. This number looks a little familiar. That was the limit to the maximum number of views a YouTube video could receive because the data type holding it couldn’t hold anymore. Let’s expand this and we’ll put in a big number, like 5G for billion, and as we can see, it doesn’t allow me to go any higher than this number. If I increment, no luck. I can go down but not beyond that number. For instructive purposes, I’ll make a copy of this, and change its representation to an I8. My Context Help tells me that I can now take -128 to 127. So, I’ll put 125 in here and I’ll increase this, but of course we can’t go beyond that because LabVIEW is preventing us from putting a greater value into the numeric than it can hold. But what if I go and programmatically add a value to it? Say I take 127 and add 5 to it. Run it, I get -124. Now, that’s some fuzzy math. What’s happening here? The value is actually rolling over kind of like the digits in a gas gauge when your gas prices aren’t at historic lows. Since we added 5 to this, the next digit would’ve been -128, then -127, -126, -125, and then, finally, -124. So, clearly this could be dangerous if we start adding, subtracting or multiplying numbers beyond the range that they can contain.

So, let’s learn about data types in general. As we saw, if I go and put down a new numeric control, LabVIEW makes it a double, DBL. What does that mean? Our Context Help tells us that we have around 15 digits of precision. It doesn’t give us that exact range that it gave us with integers because this is a floating point value. So, I could have 134265 or 1.34265. So, really it’s the number of digits that’s more important, and with doubles we get about 15. As we also see, that’s 64 bits or 8 bytes of memory, and if we’re in the LabVIEW environment, then that will take 8 bytes of virtual or volatile memory. If I store it to disk, it takes 8 bytes of storage. If I go and grab an integer constant from the block diagram, LabVIEW makes it an I32, possibly inspired by PSY, and that’s fairly typical for most integers, and these two numeric representations are fairly typical. In most cases in LabVIEW, if we have a fractional value, it’s a double. If we have an integer, it’s an I32, though some functions and VIs in LabVIEW may take different data types, like a U32. For instance, our last episodes on timing showed the Wait function and the milliseconds to wait is a U32. So, obviously, with any of these numerics we created, we just right-click, go to Representation, and choose the numeric representation, which dictates how much memory is used and the format: U32s always being positive; I32s being positive and negative; these across the top being fractional values, in other words not whole numbers; across the bottom, complex values, a real value and its imaginary counterpart, in other words, complex conjugates.

Now, why is this information valuable? Well, let’s say I’m in the design phase of a new application, one that tests air quality, and I’m prototyping my front panel because that’s a good idea to do, and here is my very simple user interface. I’ll have the number of test runs, the pressure at which I’m collecting data, and then the value of CO2 in parts per million with an array holding those data values and a display holding the same. Now, in this design phase, I could go through each individual control on my front panel and consider what could go in there. For instance, I know the number of runs will always be between maybe 0 and 10. So, therefore, I could say: well, I should just choose that to be a U8 because that’s the smallest data type that can hold that value, and I also think it’ll always be positive so no need making it an I8. I look at my pressure, and I know I don’t need any great precision to hold my pressure so I make it a single. Now, the CO2 value itself is the thing I’m most interested in so I keep that as a double in order to keep greater precision. Now, that was simple enough for this very simple application. It took a little bit of time for me to think about these things, record them, and then design my application moving forward based on those data representations. But what about the future?

What if I want to scale this up, if I want to replicate it on another test stand? What happens? Let’s say this code is working well for six months, and a coworker says, “Hey, that’s a great code. Can I go and take it on this new test bench we’re building where I’m measuring NOx instead of CO2, and I want to change pressure to temperature, and I’ll do a different number of runs?” Well, I need to go through this same analysis on that new test stand. The question is: what do I really gain from that? In this case, these are a couple of scalars, so I’ve gained at most a few bytes while this code is running. So, I gain a few bytes but I’ve lost some time in my re-evaluation, and there’s some danger. What if I’m changing pressure to temperature and I want it to be much more precise? We’ve seen what happens if you try to cram values into memory space that’s not big enough to hold it. In an unrelated example, my girlfriend used to ask me about the future a lot, especially when I moved to downtown Austin to a smaller condo that wouldn’t accommodate any extra data, and now she’s just a memory. You see how everything comes back to LabVIEW?

So, plan for the future. What do I mean? If you’re on a modern computer, that is, with enough memory and processor juice to handle your applications, then you can just default to LabVIEW’s defaults for numeric representation: that is, doubles for fractional values and I32s for integers. That’s kind of a no-brainer for scalars, in other words, single data values, not arrays. However, with an array, that’s a bit trickier. How big is this array going to get. Is this a huge data set? Maybe in the millions? In that case, the size of the data representation definitely makes a difference, and that could spin up to MBs or even GBs of extra memory which would cause your code to lag or even crash. Now, note that this discussion applies to coding on a Windows machine or a Mac or Linux if you’re using that, but not on something like an embedded device or a microcontroller, where memory considerations are far different because you’re working with much less available memory.

Good chat. In the next episode, we’re going to discuss what happens when we want to change data values. When LabVIEW changes it, which is coercion or when we change it, which is conversion. If you like this stuff, check out our full course at sixclear.com/labview-training. We also deliver it in person. You can meet me. I’m really not that bad. We have regional courses all over the place. For instance, I’ll be in Minneapolis in April 2015. I’m excited to go to Minneapolis. Maybe I’ll see you there.

(end transcription)

VI High 60 - Comparing the Wait and the Wait Until Next Ms Multiple

Last episode we talked about the differences between these 2 functions. This time, we’ll run some timing VIs that show exactly how they differ. This and the last episode are direct excerpts from our Lucid LabVIEW Fundamentals Course.

And keep up with us here:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

(start transcription) 

To get a better feel of how this works, let’s take a look at this VI, Wait until next millisecond Multiple. I shortened it. And this VI, which is called, creatively enough, Wait. The only difference between these two VIs is the function we’re curious about. The Wait function, in the Wait VI, and the Wait until next Millisecond Multiple function in the Wait until Next VI. So here’s what’s going to happen. In both cases, we’re executing a For Loop 20 times, and telling it to wait first 100 milliseconds per iteration. Inside this loop, we’re calling the tick count. The tick count returns exactly what this returns out the other side, the millisecond timer value, which we already looked at. You can see some previous values of that, that I ran earlier, when you weren’t looking. This is in a sequence frame so that this runs first. And we get the millisecond timer and then we run your code.

Let’s take a look at your code. It’s pretty simple. We’re just performing a divide function 500,000 times. We timed how long that takes by calling tick count first, performing the operation, calling tick count again, and seeing how long the process took. And then we output that from the VI. So from here, we’ll get an array of 20 values of how long the process took. And so what we also want to do is take a look at how long each loop iteration took. Is it exactly equal to the process time or is it more? To get that, we take this millisecond timer value. We get the size of the array, subtract one from it, bring the whole array in and we’re going to just take the difference between each value. Indexing out the zeroth iteration, the zeroth value and also the first value, the next iteration will be one and two. And so we’re getting the difference between each of these values.

Let’s move this over a bit so we can see where the differences are. If we flip over into the Wait function, we’ll see it behaves exactly the same way. Except…that’ s better. Now first with the wait function, I’m going to put a wait time of 100. And I’ll run it. It will run for a few seconds here as we can see. The process time which is the time it takes to divide a number by itself half a million times looks to be somewhere between 30 and 60 milliseconds each iteration. Now looking at our millisecond timer value, we can see that they’re pretty much off by 100. And in fact that’s what the differences tell us. Very rarely we will get a one in there. Let’s run it again. This is just based on the inconsistencies of a non-deterministic or non-real time system. LabVIEW is getting these resources like access to the CPU from Windows and Windows is scheduling a bunch of other tasks as well. So sometimes the availability of resources from Windows varies and so our process times vary.

Now let’s flip over to the Wait until next Millisecond Multiple and see how that works. I’ll run it. And notice, that after a couple iterations we get to around 100 milliseconds per iteration, which is what we want. Our process time is always much lower than that, from 30 to 60 like we saw before, closer to 30 in general. But the Wait until next Millisecond Multiple is different from the Wait function in the first iteration. Like we saw in our Context Help, it told us: “however, it is possible that the first loop period might be short”. Indeed it is. In this case, it’s even shorter than the process time which is why it affects the next loop iteration too.

Here’s a good example. The millisecond timer value initially was 625. So the Wait until next Millisecond Multiple function wants to go again at 700. So it waits 75 milliseconds in order to get on that 700 the next time. And from then on, it tries to maintain this 100 millisecond difference per iterations. Again, as long as the time the code takes is less than the time we wait, we’re going to see these relatively consistent loop times. Now, let’s change our wait time to less than the process time. The process time as we see, hovering in between 30 and 60 milliseconds. Let’s take our wait time down to ten. Run it. And now we see the differences between iterations is equal to the process times. Since the time the code takes is longer than what we’ve specified, the code itself is what’s timing the loop. Not this. This is the same for the Wait until next Millisecond Multiple and the Wait function. Here’s the wait. Run it. Same thing.

So, what’s the benefit of using one over another? Again, our Context Help is very valuable because it tells us: “use this function”, the Wait until next Millisecond Multiple, “to synchronize activities”. So, if we have multiple loops running and we want them all to sync up and start together, this is the one we want. If I have multiple loops and I just use the Wait function, it’s possible that they could get off on different times. It may happen on the first iteration or on subsequent iterations. The choice of which to use is up to you, depending on your application.

(end transcription)

VI High 59 - Difference between the Wait and the Wait Until Next Ms Multiple

It’s a common question that we cover in our Lucid LabVIEW Fundamentals Training, and we thought the rest of the world would enjoy. The first episode goes over the differences between the functions. The next episode will do some benchmarking on some code to show exactly how the functions differ.

And keep up with us here:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

(start transcription)

We get asked often. What’s the difference between the Wait and the Wait Until Next ms Multiple function? Let’s take a look at this code. We have a couple of things happening in this loop. We have the code that we’re actually interested in executing, and then, an iteration time, which slows down the loop. We first might ask, are these executed serially? As in, this goes first, then this goes? And, the answer is no. For instance, if I have 10 ms in the loop iteration time, let’s say that the code inside takes 2 ms. Then, do we wait an additional 10 ms for a 12 ms overall iteration? The answer is no. To understand this better, we can think of these happening in parallel, such that the time that the iteration loop takes should be 10 ms in total, as long as the code takes less than that.


To understand what we mean, let’s take a closer look at the millisecond timer, which this Wait function is based off of. If we look at our Context Help, we see that coming out of both the Wait function and the Wait Until Next ms Multiple function is the millisecond Timer Value. What’s that? Well, I’ll right-click and create an indicator off of it, and give this some value as well. 10. We’ll wire it in here, as well. This and this will be equal, so we’ll just look at this one. We’ll run this a few times, seeing that the number just keeps going up. So, underneath the hood, in my operating system–in my case, Windows–there is a clock that is running continuously. And, every time I run this, I return the value of that clock. This is the time by which Windows schedules all of its operations, and LabVIEW accesses that timer. So, when we say wait 10 ms, we’re looking at the Windows system clock. We read whatever the value is, and then hopefully, iterate the loop 10 ms later. So, that’s what’s happening here. We read the value of the clock, execute the code, and then, wait the remainder of 10 ms in order to iterate again. For instance, if the code takes 2 ms to run all of this here, then we wait an additional 8 ms. If the code takes 6 ms, we wait an additional 4 ms. In that respect, both the Wait and the Wait Until Next ms Multiple function are the same. So, I could just go and replace this, if I like. This will execute the same.

Now, we obviously haven’t gotten to the difference yet, so let’s stay on the same pattern of showing you how they’re the same. Because, what happens now if the code, here, takes longer than what you specify? As we can see, I’ve specified this to take 10 ms, but what if the code inside takes 15 ms? What will happen? These timers will never truncate the code. They’ll never stop the code from executing if they’ve run over the time we’ve allotted. All that will happen is that, when the code finishes, there will be no extra wait before the loop iterates again. We’ll see that we’ve taken 15 ms to run this. We were programmed to wait for 10 ms. We’ll just iterate again. No wait. So, the Wait Until Next ms Multiple and the Wait function behave the same way in that regard.

Okay, so what’s the difference? The Context Help is always helpful, in context. I’ll take the Context Help and read it: “Waits until the value of the millisecond timer becomes a multiple of the specified millisecond multiple. Use this function to synchronize activities. You can call this function in a loop to control the loop execution rate, however, it is possible that the first loop period might be short.” In other words, the Wait Until Next ms Multiple function wants to be on the millisecond multiple of whatever you wire in. In our case, 10. So it wants the value of that Windows system clock to end in 10. In other words, this clock. So, what it does is, the first time you run it, it tries to sync up with that clock. For instance, let’s say that, when you run this code, when the loop begins, the Windows system clock is something like 15576812. So, it will wait 8 ms so that the next loop iteration will be 20, and then 30, and 40 and so on, as long as the code underneath takes less than that time. Of course, as we learned, if the code takes longer than the 10 ms, then we’re no longer even using this to time the loop. The code itself times the loop. If, on the other hand, we’re using the Wait function, it will just immediately start its 10 ms wait so that the next iteration, it should be at 22 ms at the end.

(end transcription)

VI High 58 - How to Make Your State Machine Event-Based

We’ve been focusing a lot on state machines over the last few episodes, but we followed a polling scheme. This episode, learn how to make the state machine event-driven.

Need some LabVIEW training? Swing by http://sixclear.com/labviewtraining and check out Sixclear Lucid LabVIEW Fundamentals Training.

And keep up with us here:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

(start transcription)

Now, some of you may have already asked, “Brian, what are you doing using a polling structure when you should be using an event-driven structure?” I know. I get it. Don’t worry. Don’t worry. We’re discussing it now.

This application is very simple. Really, we have two buttons. Basic Test and Stop. And when the state machine goes to the state, that’s where it takes the data and only there. So this application will be better served with an event structure in the idle case rather than this polling scheme. And we’ll implement that event structure in a second, but first we should ask, “Is it always wrong? Should we never use a polling scheme like this?” And the answer is there are definite cases where the polling scheme does work. The classic reason is that you have data coming in at a constant stream, so you need to poll data. So, perhaps you’re connected to an instrument, like an oscilloscope or some network that’s constantly giving you data. And you need to go at a certain pace in order to get data from that. So, maybe I’m going 100 times a second and pulling data off of an oscilloscope. And then I pipe that into the data pipeline and take care of it in other cases. In that case, since I’m already polling over and over again in a loop, it would make sense to go ahead and poll these simple buttons as well. However, in this case, I don’t. All the data is actually being taken in the cases here and here. So, let’s fix it and improve it as well.

Right now, we only go to basic test and stop. But let’s say that I also want the option of going to advance test. Pretty simple. I’ll make a copy of this, and I’ll call it “Advanced Test.” Of course, that’s just the Boolean text, I need to go to the label, too. Ok. We’ll align these to the left and smash them together. Very pleasing. So now, I’ll get rid of this case structure. Don’t need it. And instead, I’ll put down an event structure. And configure the first event, which will be the basic test. A value change is good. Ok. Put the basic test terminal in here since it’s a latch action Boolean. We always want to have those in the event structure. And, of course, we’ll go to the basic test.

Now, we can take advantage of what we just did and right-click and duplicate this event case. In so doing, it creates an extra basic test, but we’ll delete that. And instead, I’ll choose advanced test. Get rid of this. Choose advanced test and bring this terminal in here. And the last, which we won’t duplicate, will be stop. Because remember, our user can stop it from right here. In which case, we won’t actually go to the next state, so I don’t have to put anything here. Now, do we need this? Well, that depends. Do I need that for the other cases? In other words, do I need to wait for 10 milliseconds between these cases? Typically no, so I’ll get rid of it.

Now there’s one other thing we need to take care of. It’s a little tricky, and we haven’t had to deal with it before because all of our cases executed so quickly. The initialize in both the tests happen very quickly. But the problem stems from the fact that the status is being updated at the end of this case. So, when we initialize, for instance, we say initialize and tell the users that status really after we’ve initialized. But because it happened so quickly, we get away with it. However, once we move to an event-driven scheme, we’re going to see in our idle case that we’ll move to the idle case, but we won’t execute it. We’ll just wait here. So, the status will be whatever the last case executed. And really that’s the case with all of them. Status doesn’t say basic test until basic test is actually finished. Now, we’ve kept it quick and simple so far, so we haven’t really had to deal with it. But we should take a look now at a few ways of doing that. A clean and professional way would be to have multiple loops. So, one loop would handle our tests. Another loop would handle our user interface. Once we go down that road, we should ask ourselves how many other loops we should have. And that would lead us to a producer-consumer or queued-message handler type of architecture. So, we may not want to do that. Not that they’re very difficult, but they are the next step up in complexity. What we really want is to have this status be updated at the beginning of the case for all cases. The quick and simple way of doing it is just to make a local variable of it. A property node would also work if we’re going to be editing some other properties. But if we’re just editing the value, it’s not recommended because it requires a thread swap.

Let’s fix it. In my idle case, I’ll right-click and create a local variable of that status. And to ensure that it runs before this does, I’ll need to create some space first. And then move this here. Now floating this over here to the left of this does not ensure that it will go first. So, we’ll need some dataflow to make sure that this definitely goes first. A sequence frame will work. There we go. Now, that fixes that case. We’d have to do that for every other case as well: copy and paste that over. So, of course, ears pricking up, we should use a SubVI. But what am I making a SubVI of? Well, it should just be this really. And if I make a SubVI, I wouldn’t have to use this janky flat sequence structure. I could instead, put error clusters and pop it right on this error wire. So, let’s do that instead.

Right-click. Remove that sequence and just click once on the border. Edit. Create SubVI. And there we go. Go into the SubVI, we see that under the hood, we are using a property node. So what I said earlier about the thread swap still does apply. So, it’s up to you. In most cases if we’re not calling these property nodes a lot, this is ok. In other words, not calling them repeatedly in the loop over and over, so that we generate a lot of thread swaps. This, however, totally permissible. We said that we wanted those error clusters, so let’s put those in. Assign those and change our icon. You’re getting pretty good at this by now. And what we’re really doing is handling the UI, the user interface. So we’ll just say “UI,” and we’ll jump over to glyphs. An image of the front panel is actually pretty useful. So, I’ll just grab that. Ok. And save it as UI Handler. And put it on the error wire. Oops. It looks like I actually have an error in instead of an error out. Easily changed. We just right-click and change to an indicator. Now the complexity could grow because we’re using the user interface in each case. And we could also stand to use it at the beginning and in other places as well, but you get the idea. This is a valid use case of it. A very simple one, but this could also address a lot of other things on our user interface. For now, we’ll keep it simple. And to go put this somewhere else, I’ll just do one of the other cases, maybe the initialize. And we’ll go pull it out of here. And we’ll want that same reference that we had last time, so let’s just go grab it. We’ll leave a copy out there because we’ll use it again. Eventually we’ll go and change that in all cases and I can just pull the status really anywhere because it doesn’t need to be here anymore. So, I’ll just get rid of this, and I’ll go fix any other cases like I did here. You don’t have to watch.

All right. All fixed up. We can see that in every case, we’re updating the status. So, let’s go ahead and run it. Back to the front panel, hit the basic test, and remember the last episode we had programmed the basic test to fail with the voltage of 2.6. That sounds good, and we’ll jump back to the idle state. What about advanced? Well, look at this. The basic test failed with a voltage of 2.6. That clearly can’t be right. What went wrong? Well, going back to our idle state, this is the place where we go after all of our tests are done. Basic test, advanced test, notify, back to idle. Here we should be clearing out any past data. So, let’s do that. Clear out past data which is carried right here. So, let’s just delete that and make a fresh copy of it over here. Create a constant. We’ll make it a little smaller. View it as an icon. Let’s check that again. Ok. Advanced test. It says failed with a voltage of 0. Now, that’s right because we haven’t actually put anything into the data in our advanced test. So with the default being a false, the test failed.

Stopping it goes back. Just double check and put in a value for the advanced test. We’ll say it passed with a value of 10.1 and wire this out. Save and close it. Now remember that we need to go back to our notify SubVI, and I haven’t handled any reporting here for the advanced, but it’s a bit complicated because the advanced test is conditional. It only executes if the basic test passes and then now in our event structure implementation, it can execute without the basic test, so all that logic would have to be programmed in here, which we won’t do right now. Instead, we’ll just go ahead and test this. The advanced test will just say that it fails with a 0 since there’s no real reporting. So basic test, we get the notification. Advanced test, we get the notification as well. Again, it says basic test because we haven’t programmed the notify VI. And stop works. Ok. That does it for state machines. You can probably imagine me making some shameless plug for our online and in person training. So, if you’re thinking of that, we’ve done our job.

(end transcription)

VI High 57 - How to Pass Data Between States in a LabVIEW State Machine - pt 2 

Last time we passed data between states with our data cluster. Now it’s time to report the data using some simple string manipulation and dialog boxes. Next time we incorporate events!

Want to learn LabVIEW? We can help with Sixclear Lucid LabVIEW Fundamentals Training at http://sixclear.com/labviewtraining.

Follow us at all these fine destinations:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

(start transcription)

Ok we’re sharing the data between all states, so what, how do we use it? Well the first task we want to do is go to our notify section and notify the user of exactly what passed. So, in here, we have the data coming in, which of course is an instance of the type def, look at that glyph, so in the no error case we want to go do something, maybe just pop up a dialog box for the user telling them if something passed or failed. So let’s go ahead and unbundle this and I’ll pull out the “basic passed” and the “basic voltage.” Let’s keep it really easy and just send a message to the user. I’ll hold down ctrl, click and drag to create some space here because I’ll send a message to the user with my one-button dialog and we’ll make a message, a string message, create a constant off of this, detach it for now, “the basic test” and then we’ll concatenate on what happened with the select function, if it passed, we’ll make a copy of this click and drag with control, it it’s true, “passed,” we’ll want a space in there too, or “failed.” We’ll use our concatenate strings, another string “with a voltage of,” put some spaces in here so it renders correctly. Now of course the voltage coming out of here is a numeric but we’re reporting it as a string so we need to change that. There we go, number to fractional string, voltage comes in and out comes the value. Let’s test this little block of code. Look how easy LabVIEW will be to prototype and test, copy, ctrl-n for new VI, ctrl v, head to this and let’s say we have a voltage of 5.5, it passed, run it, the basic test passed with a voltage of 5.5, great! This may seem like a little too much data for us, so with our context help we can take a look at this and say that we probably just want a precision of 2, that’s better. Check the prototype, passes, that looks good we don’t need it anymore, we fixed it here and we wire that concatenate string into here just to notify the user. We could obviously go and do the same thing for the advanced test and clearly we can do far more than just send a dialog box. We can write to a file, a database, whatever, we’re just keeping it simple. 

So now the whole point is in another place, like the basic, test we actually go and fill that value. So in basic test “basic passed” will be false and “basic voltage” will be 2.6. So let’s go ahead and run it. Run it, basic test and we get “basic test failed with a voltage of 2.60,” great and back to idle. Now where else can we use this? Well clearly the advanced test we can fill in the same thing also in the error reporting. When it comes time to do the error it’s a good idea to maybe, in the error report, say what’s passed and failed and what the voltage values are to be able to do some troubleshooting after the system has shut down. 

Anything else we should know here? Well keep in mind that we made a type def of our states and of our data because now, if I ever go back and need to add more data that I need to pass between states I just put it in here. I don’t even have to change, in most cases, the coding because this pipeline now grows or shrinks with whatever I put in here and using the unbundle by name I can just take out the new items by name. So essential to use that type def in that data cluster. That’s all on state machines for now, remember this was one of your suggestions, we like those so keep them coming and keep coming back to sixclear.com/labview-training. Take our course online or come visit us at regional course or have us on site.

(end transcription)

VI High 56 - How to Pass Data Between States in a LabVIEW State Machine - pt 1 

We’re almost finished with state machines, and this time we discuss how to pass data between states by making a type defined data cluster and using a shift register. We’ll show how to notify the user of the test results as well.

Want to learn LabVIEW? We can help with Sixclear Lucid LabVIEW Fundamentals Training at http://sixclear.com/labviewtraining.

Follow us at all these fine destinations:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

(start transcription)

In our last episode we took a look at implementing error handling in our state machine and we asked a question at the end: if, for instance, I’m going to notify the user of whether a test passed, how does the notify VI know which test passed? It may be values for the test if the tests occur in other states. In other words, how do we get data between states? Within a state it’s pretty easy, we just pass the data to whatever handles it, but getting it from this state over to this state will require passing that data between loop iterations. Are your ears perking up? Because that’s what a shift register is for and that’s what we’re going to use. In this case let’s say I want to pass the data regarding the basic test from this state to the notify state. Well I’ll right click and create a shift register. Now what should I put in here? Well this “passed” is a boolean, so I could go and wire this boolean into here, but then what about the data for the advanced test? I can’t use the same shift register because that’ll be a different value so I’d have to create another one and then what if I also wanted the actual values for the test? Maybe some voltage values, maybe for both tests. Well now then I have four different shift registers sitting here and pulling them off, and as you can imagine as my application scales I’d have a bunch of these, that’s inconvenient. So what I really want is one shift register that holds all of those and so we’ll keep them in a cluster. We’ll go back here, get rid of this and instead the data is going to more closely reflect what’s in here. 

Now right here we’ve kept the data pretty simple: numeric and boolean and we haven’t even been terribly consistent about the labels, so let’s change that. What we really want is an instance of a type definition in all cases, so I’ll right click on the border and make this a type def, and open up the type def, save it, keep the same prefix and choose “data.” Let’s make this a little prettier, expand this a bit. Let’s say the pieces of data we want are this: four simple pieces, this voltage for each test and then whether that test passed or failed. So we’ll call this “basic voltage” and this “basic passed.” A line across the top and make a copy. Ctrl and shift, keeps them on the same axis and we say “advanced voltage” and “advanced passed,” save that and we’ll look at the order of the controls 0, 1, 2, 3, that looks good to me. So now this is an instance of the type def and it got a little bigger so we’ll move it over a bit here, rearrange some things. This also should be an instance of the type def. We don’t want to make a new one of course we’re just going to right click on it and replace it with the one we just made that way it’s still connected up, it’s still in the block diagram, much easier. Pull this over here, line these up quickly, same here, gorgeous. Wait, not yet gorgeous, now, okay. So I’ll close that out, this now is an instance of that type def and of course we want it going into here, there we go, and now this will be an instance of the type def too. So I can create a constant at the beginning of runtime in order to re-initialize the values in that cluster, very nice. I can even put a label here, it’s good programming practice, we’ll just change it to “data” and make it a little smaller, we don’t need to see all of it and now any other cases that need to access that, we’ll just pull it from there. 

Now I’ll obviously need to go to the “advanced” and do the same thing as I did before. I’d pretty it up but in the light of time, that’s good enough. In we go, and out and finally the notify state, same thing. Obviously we still have this hollow tunnel so we’ll have to decide what to do in the other cases like “initialize” and “idle.” Well in “idle” we won’t have to worry because we’re not changing that data or even hauling it anywhere so I’ll just pass it directly through. So it’s in “initialize” or “error shutdown.” Both of these use the un-type def data so I won’t make you sit through that, I’ll go ahead and change that right now. Okay all done, all of these now have the updated type defs. So I’ll wire them in and out in all cases. Solid tunnel here means we have all cases taken care of. 

(end transcription)

VI High 55 - How to Implement an Error Handling Strategy in a State Machine - pt 2

As promised, we continue programming our state machine by adding error handling into each state and then testing the completed code.

Want to learn LabVIEW? We can help with Sixclear Lucid LabVIEW Fundamentals Training at http://sixclear.com/labviewtraining.

Follow us at all these fine destinations:
http://facebook.com/sixclear
http://twitter.com/#!/sixclear
http://gplus.to/Sixclear

(start transcription)

Welcome back to implementing error handling with our state machine. In our last episode we did these first three, now we’ll do the last. We’ll flip open our application and the first thing we need to do is actually use the error cluster between these VIs, because as we flip through and see these VIs they’re just kind of sitting by themselves out there but using the error cluster would be a smart thing to do. So let’s do that.

So what we can imagine are some error cluster rails kind of going right along here throughout the entire application, and it’s a good idea to have them use shift registers on either side since there are some states that handle errors and some that don’t, and it’s just good programming practice. So I’ll add a shift register here, obviously the shift register is black because it’s unassigned, it doesn’t yet know what it’s a shift register of. So I’ll wire the error cluster into the right side and it becomes the color of the error cluster. So I’ll initialize the error cluster by right clicking and creating a constant. Notice I can’t create that constant until the shift register knows that it contains error clusters. I can leave it like this or I can make it a little bit smaller by “view cluster as icon,” however you like, and then wire this into here. We know that we’ll be checking for errors in every state. 

So how do we check for errors? Well we’ll want to look at the error cluster and then change the transition from where we normally go to the error shutdown case. There are a couple ways of doing this, let’s move this out and use a select function. It’s polymorphic so it can accept this error cluster coming in so if there is an error that has occurred here then there will be a true boolean in here which means whatever is in here will pass out. So first off the select function is still defaulting to doubles, so we’ll change that. Now I wired the idle value into the false input because that will be what we transition to if there’s no error. In other words: false for no error, in the case of an error: error shutdown. Whatever you want to do to make it pretty that’s ok with me. In summary if no error occurs a false will come in here and we do what we normally do. If an error has occured we go to the error shutdown case. 

Now we’re going to be doing this for every state so I could go and copy and paste this little chunk of code over there but we’re better LabVIEW programmers than that. We know this is an excellent use case for a subVI and the thing that will change in every state is what comes in. So I’ll move this outside, highlight the rest of this and go to Edit>>Create SubVI. Now this is definitely an error handler. We’ll clean up this block of code and we’ll save it as “Error Handler.” Now the convention for most error handlers is to actually have the error cluster in and out of both sides, so let’s do that. We can of course change the SubVI we just made with an error out, align these across the top, always like to make it look good, and we haven’t changed what’s in the error cluster so I can just do that and clean it up again. Well that’s a little better. Assign that error out and down here, just like that, move this down so it’s in line, that’s pretty, and of course change the icon, double click, select the old, delete it, make a border, error, in this case, just error. This will be different than the other one we made, the error shutdown, and close it. Now we would normally go and document all these inputs and outputs on the VI, but for time’s sake, we’ll skip it, which we’re all used to because that’s what we do when we run out of time on our projects, sigh. Let’s make this presentable now and head to the next VI. 

Now in the idle state we’re not looking at errors or generating any new ones so I can just pass this right through here and move on to the basic test. In basic test we’ll pull this over here and pull out from our project the error handler and it’s pretty easy now, just wire up that error cluster and the states go in, and the states go out, reminding ourselves we’ll transition to the error shutdown if an error occurs. Move onto advanced test and we’ll do exactly the same thing, straight wires. Now we won’t need to put that error handler in here since this is our error shutdown case and we’re done. Let’s save it, ctrl-s, and let’s run and test it. 

So as before we can run it, click on basic test, we do our basic test, on to advanced test, on to notify, back to idle. That’s very good no error there. We know that it passed the basic test because it’s passing a true out here. If we stop our VI, go to false, run it again and do basic test, then we go basic test to notify because we failed the test, ok that’s correct too. Now how do we test the error handling portion? Well, we need to inject an error. So let’s pretend that an error occurred in the basic test VI. So what should happen is we never go onto advanced test but rather right onto error shutdown. How do we inject an error here? Pretty easy, we’ll just put it in here. We’ll do something similar to what we did here. Let’s give it some space to work with, move this up, bundle by name and the status, which is what we’re looking at, will be true. Ok so now what should happen is we’ll go idle, basic test, and then onto error shutdown and the VI stops just as we designed it. 

Well we’re finished for this episode but there’s still more we can talk about. In fact next time we’re going to look at creating a data pipeline between different states so that common data can be pulled out of there so that, for instance, the notify section can know what it’s notifying the user of, that’s helpful. By the way we do these courses live you know, we can come to your company or you can join us at a regional course. Just go to sixclear.com/regionals that’s just a location that we pick out and you show up and we talk LabVIEW for a week. Maybe I’ll be there, I’m much more palatable in person. See you soon, hopefully.

(end transcription)

VI High 54 - How to Implement an Error Handling Strategy in a State Machine 

We left off our discussion of state machines with VI High 50. We pick it up with this episode when we discuss potential ways to implement an error handling strategy with our state machine. We’ll continue this topic in VI High 55.

Want to learn LabVIEW? We can help with Sixclear Lucid LabVIEW Fundamentals Training at http://sixclear.com/labviewtraining.

Follow us at all these fine destinations:
http://facebook.com/sixclear
http://twitter.com/#!/sixclear
http://gplus.to/Sixclear

(start transcription)

In VI High 49 and 50 we talked about state machines. In 49 we planned it out with the state transition diagram and then in 50 we implemented it. At the end we said we would discuss error handling. The question is: what happens if any of these states has an error. Well, in the previous implementation there was no error handling, that’s bad. In this situation though, we’re going to have every state transition to this error shutdown state. The error shutdown case will handle the error, whatever it is, and then shutdown the application. 

Now, this is one possible implementation, however in many cases, we already have a shutdown case, in which case it may look something like this, where, in the case of an error we move to the error handling state and then to the shutdown case, but if we don’t have an error we just move to the shutdown case and then end. Now we have a lot of red arrows going all over the place, so for simplicity we oftentimes just do this and anything here with the red background automatically forwards to the error handler in the case that they have an error. However, we don’t have a separate shutdown case. It’s a pretty simple application and so we’ll just stick with this one. 

So what’s our path forward? Well, we’ll first ensure that all VIs in the application handle errors then we’ll add the error shutdown case to the Enum then make the error shutdown case in the state machine and then fix the other cases to transition to it with an error handler. So let’s do that. 

We’ll open up again our LabVIEW project containing the state machine and I got rid of that main that we created in VI High 50, don’t need it right now because this is the same. We stopped here so the first thing we’ll do is ensure all VIs handle errors. Well, we’ll go under the hood to the VIs and this is where we left it last time but appropriate error handling strategy, that we learned about in VI High 48, is to wrap any code in a case structure with the error cluster going to the case selector terminal. So we’ll do that, pull down a case selector terminal and wire the error cluster into it and through to the other side, flip over to the error case and just complete wiring the tunnels. Now in the no-error case we perform the test. In the error case we don’t and the state machine will go and decide what to do. 

Now, it’s important to note that failing a test is not an error because the application is designed to determine whether a device under test passes or fails. So it’s doing what it should do. An error would be if the application itself fails, maybe communication with the instrumentation fails or the user requests the application to do something that it can’t do. So those are errors, and we’ll jump out of here and see the other cases with the other VIs already have that implemented. 

So we’ve ensured our VIs handle the errors, now we’ll add to the Enum. That’s done simply enough by going to any instance of the type def, right clicking and opening it up, and we want to add an error shutdown case, and I’ll just add it here at the bottom. I’ll expand this a bit so I can see it, right click and add an item after: “error shutdown.” Save and close it and now all instances of the type def will have that error shutdown as well. Huge help using that type def. We always want to make sure that the Enum, going to our state machine, creates a type def or else we’d have to go and add that item to every instance of the type def, what a pain! 

So now we’ll make our error shutdown case, and we’ll just put it here after notify. I’ll right click, add case after, and the case structure will automatically assign the next case to the unassigned item in the type def enum. What’s going in this case? In keeping with the pattern I’ve already started, I’ll just have a VI that does the error shutdown. It will look a lot like some of the other VIs in here, probably a lot like advanced test notify. So I’ll pull that open, take advanced test, and make a copy of it, and change it to error shutdown, open it up, and we’ll want to make sure that this is in the project, so I’ll just pull it over here and we’ll definitely want to change the icon as well, so I’ll just open up the icon editor, and this is our error shutdown. We’ll actually have another VI later that does the error handling between cases. So we’ll just look for a glyph that’s “shutdown,” ok these are good, we’ll get rid of the old one, select it, delete key, and click and drag this on there. Ok, save that and close it and put this in here. We will fill in the blanks here – or the hollow tunnels – and we’ll end on this case since that’s what our state transition diagram tells us to do right here. So we’ll make this true and here it doesn’t really matter what we do here because we are going to end our application so we’ll just leave it at error shutdown. Of course, we need to supply an input to the tunnel so the VI can run and looking at the guts here of our error shutdown VI we’ll have some stuff in here that does that but it probably won’t reside in the no error case but in the error case or since it’s supposed to execute in an error and only in an error we can even get rid of this if we want, it’s up to us. For now, we’ll leave it as it is and then finally fix the other cases to transition with an error handler and this is a big part so we’ll do this next episode. In the meantime remember to checkout Sixclear.com for all your LabVIEW training needs.

(end transcription) 

VI High turned 3 today! Thanks to everyone for 3 years of LabVIEW lovin’!

VI High turned 3 today! Thanks to everyone for 3 years of LabVIEW lovin’!

VI High 53 - Automatically Selecting NI Software for Installers in LabVIEW 2013 

We do LabVIEW training. When going over installers, we’re always asked “why doesn’t LabVIEW just automatically add the necessary drivers for whatever the code does?” Get ready to smile, now it does.

Want to learn LabVIEW? We can help with Sixclear Lucid LabVIEW Fundamentals Training at http://sixclear.com/labviewtraining.

Follow us at all these fine destinations:

http://facebook.com/sixclear

http://twitter.com/#!/sixclear

http://gplus.to/Sixclear

(start transcription)

In LabVIEW 2013 installers have changed for the better. Let’s take a look at this very simple Acquire and Analyze vi. We’re doing a simple hardware timed DAQ operation and doing some analysis on it, obviously the DAQmx driver is being used. Now I built this into a project and already created an executable from it. Now when it’s time for me to build the installer, previously I would walk through my categories over here on the left, put the executable in the folder I want and then proceeding down the categories I may choose a few other things and I come to the Additional Installers tab. Now previously, before LabVIEW 2013, I’d need to look at all the potential drivers and runtime engines that could be included in my installer and I’d have to know under the hood what my application is relying on, so that when it gets on this target computer it doesn’t break. 

Now we teach LabVIEW and people always ask “well why doesn’t the LabVIEW just know that?” Well, now it does. As you can see there’s a checkbox Automatically Select Recommended Installers and we see what’s been selected is the NI LabVIEW runtime engine 2013 and NI DAQmx Core Runtime 9.8. Now since my application is using DAQmx that totally makes sense. If I were using some other type of driver maybe NI-VISA it would be automatically included here as well. Now if I’d like I can uncheck that and go as before and choose what I’d like to include but this, far easier. 

Now you could justifiably ask, should I always just keep Automatically Select Recommended Installers checked? And the answer is, possibly, but remember that if you do bundle in together these runtime engines and drivers that your installer gets bigger. So if you know that your target computer – where the executable will be running – already has these runtime engines or drivers on it, then you wouldn’t need to go and put them together in the installer, but if you don’t know that, be safe and put them in there.

(end transcription)