Virtual Devices

When you don’t have the DAQ hardware you need…

Any version of NI-DAQ and the Measurement and Automation Explorer (MAX) released recently has provisions for “simulated” devices.  You choose which devices you want, and then NI-DAQ will pretend those devices are actually installed on your system, any calls to DAQ functions concerning that device will succeed (or fail) just as if a real device was installed.

This lets you simulate a client’s setup without having their hardware shipped to you and do most (if not all) of the programming on your own terms without being at their site.  The data produced is, of course, simulated data.  For an analog input channel it’s a sine wave, for a digital port, it’s a counting pattern.  It’s enough for you to tell if your software is working correctly with NI-DAQ.

With their hardware simulated on your machine, you can handle the basic communication part to get data in and out. Then you can install conditional-compilation pieces to substitute data more realistic for your particular situation if you need to.

You can be reasonably confident that the DAQ part of a program you develop this way will work on the real hardware, the same as it did on your simulated hardware.  Of course, for any extreme cases (high sample rate, high channel count), the simulation will be less exact, but it’s a useful feature to develop faster with fewer headaches.

What time is it, again?

The TIMESTAMP indicator is smart enough to get you into trouble.

Just ran into what at first appeared to be a bug, but turned out to be proper, if misunderstood, behavior.

I have a project which records data files. When the actual recording starts, and again when it stops, I remember the time (by using a GET DATE/TIME in SECONDS function) in a TIMESTAMP variable, which is stored in the data file. There might or might not be some calibration activity after the recording has stopped.  When the DONE button is finally clicked, I record the current time using a FORMAT DATE and TIME STRING function, into another string field called “TEST TIME”

I have a viewer which examines the data files and reports various info about them. The indicator that shows the TEST TIME is on a different window from the one that shows the START TIME and END TIME.

If there’s no CAL operations done, then the TEST TIME has always been just a few seconds later than the STOP time (enough time to react to the test being done and click the DONE button), or it could be a few minutes later.

However, I recently noticed that, on a data file sent from my client to me, that the TEST TIME was almost an hour EARLIER than the STOP time.  How could that be?  Further rummaging thru other files that I had from him shows the same thing: the TEST TIME was short of an hour EARLIER than the DONE time.  If there were CAL operations done, this difference was 45-55 minutes; if not, it was a few seconds short of an hour.

I have run thousands of tests on my machine without noticing this; my client has also run nearly a thousand, and has never brought it up.  Whay is that?

Continue reading “What time is it, again?” »

Beating the Jitters

A shortcut to determinism in real-time applications

Determinism in software is the ability to ensure that any and all paths taken through the code take a consistent amount of time to execute.  Most desktop applications have no interest in this consistency because A) it doesn’t affect anything, and B) the existence of interrupts and preemptive multitasking means that you cannot do anything about it anyway.

In an embedded control application, or one running under a real-time OS however, determinism is often important because it is critical that the control outputs be changed at a consistent time with respect to the control input sampling time. On the input side, when a signal is changing at a relatively rapid rate, any error in the TIME of measurement is just as destructive to the measurement accuracy as an error in AMPLITUDE.  For applications such as PID loops, this is even more important, since derivative terms are adversely affected by timing inaccuracies.

Equally important, but not always equally recognized, is the fact that the timing of the output samples has exactly the same effect.  If your control output is not consistently timed, then loop stability is compromised.

Continue reading “Beating the Jitters” »

Writing Non-Fragile Code

Oooops…. who broke it?

“Fragile” code is code that breaks in one place because of changes you make in some other place. It’s most aggravating when you’re due to ship a new version tomorrow and you need to make one last tweak at 11:30 PM, or your client is looking over your shoulder and this little “harmless” change shows up as a smoldering heap during the demo.

In this case, “break” doesn’t ONLY mean “broken arrow” , or uncompilable code (at least you can chase those down easily enough). Here, “break” also means “operates incorrectly” or “completely wrecks itself like it never did before” or somewhere in between.

These sorts of breaks come from unrecognized dependencies, and they’re all too easy to make: the header size has been 3 for months and months now, so when you add a new function that needs it, it’s easy to stick in a constant 3 and be done with it.

DON’T DO IT.

Continue reading “Writing Non-Fragile Code” »

Time Alignment of Signals

A picture is worth 1024 words

I discussed the idea of a time-alignment scheme in the article Delays, Delays, Delays.  The idea is that signals which have a mechanical delay of some kind (gas transport time, for example) can be time-aligned with signals that have a lesser or no such delay by means of a “logical” delay line inserted into all channels.  If the sum of all channel’s physical + logical delays is a constant, then the final output is time-aligned.

Here is a test of that concept, where three signals are generated, with different phases, and then fed thru that process. The outputs, as you can see, have been aligned.

TimeAlignment

You have to know the physical delay time, however; it does not guess.  You also have to account for the fact that some data is lost at the beginning, if that’s of concern, then start your recording early enough to account for that.

Even with those caveats, this scheme allows you to shift signals to account for mechanical delays, EVEN IN REAL TIME, if you need to.

Watch your step

But who’s watching the watchers?

Some development environments have a concept called “watching”, where you choose a variable to watch and you see a continuous display of that variable in some window.  This is very useful during debugging, as you can step through your program and find out where this variable is being changed.

LabVIEW has no such built-in feature, but it doesn’t really need one.  You can construct your own watch windows, have them run independently of your main code and accomplish the same thing.

Simply make a new VI with a WHILE loop and a STOP button.  Add a WAIT for 200 mSec (or something) inside it (so you don’t hog the CPU).  Each time thru the loop, grab your watch variable, process it, and display it.

The “processing” can be unbundling a single item from a complicated cluster, or picking an element out of an array, or anything you need to display the item in question.  Perhaps you need to call a VI to get it. Perhaps you need to query an I/O port, or a TCP instrument. Whatever you need to do to watch your troublesome variable.

SUGGESTION:  When you’re done with it, save it in a folder called “Miscellaneous Stuff” or something, so you can get at it easy next time.  There will be a next time.

The Next Step in TCP-IP

Several conversations at once

A question came up on the LabVIEW forum the other day about multiple connections, and how hard it was to have two connections transmitting at two different rates.  This surprised me a bit, because I have been doing just that for quite a few years.  The allegation was made also that TCP requires a minimum packet size of 32 bytes. That is also a surprise since I have been doing things contrary to that “rule” for quite a few years.

So, in an attempt to clarify things above and beyond the Beginner’s Guide to TCP/IP, I present this example with a CLIENT and a SERVER.

The SERVER should be run first and listens for four connections on four consecutive ports. It has four data generators, running at different rates.  When data is available, it transmits it over the connection  if there is one, or listens for one if there’s not.

The SERVER uses a re-entrant VI so that the same code can be executing in four instances at one time.  The four instances are given four different intervals. The WAITs do not conflict because of this reentrancy.

The CLIENT initiates four connections to these same ports, and waits for data in four loops.  I did not use reentrant VIs here, because of the connection to the charts.  Although you could pass a reference to the chart to four reentrant subVIs, I chose not to, thinking that the speed would be better with the direct approach.

Given that this is based on the mSec Timer in LabVIEW, I wouldn’t vouch for it’s accuracy as you approach 1000 Hz. But the basic techniques are sound and will work beyond that frequency.

Click here for a downloadable example of four-channel client server communications.

Speed of En Masse Operations

Zip-zap-zowee and swoosh!

Just in case you thought I was kidding in the article on en masse operations, I decided to offer some proof of the speed advantages they can give you.

I used the Timing Template vi to measure the time it takes to multiply an array of DBLs by two, both with a loop, and without.  I set up the timing VI to create an array of 1000 random numbers, and then time the multiply operation.

First, the loop method, where you auto-index every value out of the array, multiply it, and auto-index it back in:

viaLoop

As you can see, this took 7.47 uSec per loop.  Not all that shabby.  But just removing the loop lets the en masse operation do it:

EnMasse

Holy Speed Demon, Batman!  That’s 0.77 uSec or about ONE TENTH the time!

Now, I’m not guaranteeing that all such operations will save you that much time, but if you have a chance to use them, then you should!

It’s easier on you and easier on the hardware!

Keeping your charts up to date

Use your chart to indicate time of day.

LabVIEW charts, out of the box, don’t lend themselves to displaying the actual time of day.  By default they give you 1024 history points and a visible scale of 0-100 so what you see is in terms of sample numbers, having no relation to actual time. This is reasonable, given that the scale is adjustable in so many ways; there’s no way to guess what you want, so it’s up to you to tailor it to fit what you want.

Sometimes it’s useful to display the time of day on your charts, and keep that axis correctly updated as data flows in. For example:

ChartClock

As you can see, the leading edge of the plots coincides with the current time on the clock  (see here for how to do the clock indicator).   As data keeps coming in to this chart, the leading edge will reach the right side and the chart (and the X-axis scale) will scroll to the left, thus always matching the time of day.

Out of the box, a LabVIEW chart has a history of 1024 samples, and an X scale of 0-100 samples.  This scale has nothing to do with time, so if you want it to display the time, then you have to do several things to make it work.  If you have a CLEAR CHART function, triggered by a button or something, then attach this code to that action, otherwise just do it once when you start the data flowing  (Ideally, you should do this as you feed the first sample to the chart, but the few mSec difference that makes probably won’t matter).

ChartProperties

First, you clear the history.  That makes sure the OFFSET number is operating from an empty buffer (Time 0).  If the history buffer contains data, then the OFFSET applies to the end of it, and that’s not what you want.  The constant has to be an empty array of the same type of data as you feed to the chart (cluster of two DBLs in this case).

Next you set the XSCALE.OFFSET to set the OFFSET number to the current time.

Next you set the XSCALE.MULTIPLIER to the time (in sec) between samples that you display.

Next you set the XSCALE.MAXIMUM to now + the duration (in seconds) that you want the chart to show.

Do them in that order, or it could get confusing.  You also can set the CHART HISTORY LENGTH to match the duration / the display period.  For one minute at 2 Hz, that would be 120 samples.  You only need to do that step once – it’s a property that is not programmable.

Enjoy.

    Affiliations

    • TI Alliance

    Calendar

    July 2010
    M T W T F S S
    « Mar    
     1234
    567891011
    12131415161718
    19202122232425
    262728293031  

Testimonial  Contact Info

207-790-0949

1-877-676-8175 (toll-free)

Fax: 1-815-572-8269

General questions:

Sales@Culverson.com

Accounts/billing questions:

Accounts@Culverson.com


Logo