LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Create a Save Data Button, General VI Improvement help.

Hello, My name is James and I research high-temperature superconductivity as a hobby. 

 

I created a VI to control a Stanford Research Systems SR-530 dual-phase lock-in amplifier, and an HP34401A digital multimeter remotely and then live-plots the two phases with respect to temperature. Everything works fine regarding graphing and plotting and saving data to a file.

 

My big issue is that it always creates a file every time I run the program, and would like to program a button to choose whether or not to create the file and save it because sometimes the experiment run is bad and not worth saving. It's creating a big mess in my data folder. 

 

Besides the save button to create and save the data, are there any other improvements you would suggest to improve speed and performance? It works great, but can it be improved?

 

Thanks in advance! 

0 Kudos
Message 1 of 11
(2,424 Views)

@User002 wrote:

 

My big issue is that it always creates a file every time I run the program, and would like to program a button to choose whether or not to create the file and save it because sometimes the experiment run is bad and not worth saving. It's creating a big mess in my data folder.?

 

Thanks in advance! 


 

Well, if you wrote the VI, you know which primitive does the file saving. To conditionally execute code parts we have the case structure. Have you tried?

 


@User002 wrote:

Besides the save button to create and save the data, are there any other improvements you would suggest to improve speed and performance? It works great, but can it be improved?

 


Hard to tell, because we are missing all subVIs. Maybe you want to use one of the more advanced architectures such as a state machine. You can create the file name with a single "format into string". No need to concatenate and covert to a path. etc.

 

 

0 Kudos
Message 2 of 11
(2,381 Views)

Hi, Knight of NI

 

Thanks for your reply. I wrote the VI and most Sub VIs. The only ones I didn't are the bottom ones used for the SR-530 Lock in amp. Those are from a pre-existing driver created for LabVIEW which I took full advantage of. 

 

I am aware of the case structure and I could perhaps better utilize the state machine format. The thing I'm having trouble with is the data logging/writing to file is in my while loop, and the creation, file path, closing, etc are outside of the while loop. I'm not sure how to implement the case structure when half is in a while loop and the other half is not. 

 

0 Kudos
Message 3 of 11
(2,374 Views)

Is there a way to write all the data to a file after the while loop closes?

 

If I can do that, then I can create a user prompt to save the data or not. This would be ideal since I can choose whether to save it or not after the sample run is completed. 

 

0 Kudos
Message 4 of 11
(2,362 Views)

These are miscellaneous comments.

  1. Do you know before you start the Run that the "experiment run will be bad" so that you can avoid writing the file as the data are being collected?  If so, use Case statements to (a) not open the file before the While loop, (b) not do the TDMS Write inside the loop, and (c) not close the file after the loop.
  2. On the other hand, if you discover during the Run that the experiment is bad, when the loop exits, you could alternatively close the TDMS file, delete it, and skip viewing it.
  3. The third option, of course, is to leave the file alone, look at it, decide if it is worth keeping, and use File Manager to delete it (or write a little LabVIEW routine that runs after the Viewing and has a big Red Delete button to delete the file.
  4. When I see a VI with a lot of parallel tracks (congratulations, by the way, for using the Error Line to serialize your code), I wonder whether you intend to run all of the "tracks" inside the While loop at the same speed (which, of course, will be the speed of whatever takes the longest time!).  Do you know about the Producer/Consumer Design Pattern?
    1. Here's the idea:  You have some Data Acquisition that has the important "Time" element, one that you'd ideally like to run in a loop by itself so nothing else "slows it down" and it can run "as fast as it can" (which, since it is taking data, means "as fast as I'm supposed to be taking data").
    2. An important thing about "Data Acquisition Time" is that your DAQ Hardware generally has a very accurate clock that runs very fast, and usually takes very little PC CPU time to "do its thing".  For example, if you asked an A/D converter to convert 1000 samples on 16 channels at 1 kHz, you expect the hardware to deliver you 16,000 points every second.  Well, once a second, the device will spit out an array of 16 x 1000 points, and it might take 100 µs to do this, which means that the PC's CPU is idle for 999.9 ms, and can be doing useful things like making plots, writing files to disk, etc.
    3. So when the DAQ device delivers you the data, instead of immediately processing it in the same loop where you acquired it, you "package" the data and send it to another loop.  The DAQ Loop where the data are acquired is called the "Producer Loop" (because it "produces" data), and the other loop that Consumes it has a name I'll let you guess.
    4. So how do you get data from the Producer to the Consumer?  You want something that waits patiently for input, and when it arrives, "instanteously" (well, almost) delivers it to the intended recipient.  In LabVIEW, there are two structures that do this.  The "traditional" one is called a Queue -- when you Enqueue something, it will "magically" appear on the input of a connected Dequeue function.  Since LabVIEW is a Data Flow language, the (Consumer) Loop holding the Dequeue does not run until the data appear on its input.
    5. Imagine starting the Producer and Consumer at the same time, with the Producer collecting 16,000 data points and putting them on a Queue.  Remember that the DAQ device in the Producer is a "clock" -- it doesn't put anything on the Queue until the second it took the data to be acquired has passed.  This means that the Consumer loop, which needs data on its Dequeue function to proceed, has to wait one second before it can Consume (i.e. "process") the data.  It has a whole second to do this and be ready for the next data point!
    6. It's even better than that!  Sometimes the Consumer needs a little more time.  Well, like any good Queue (think a Queue at a bus stop), it is "elastic" and can hold more than one element.  As long as, on average, the Consumer can "consume" faster than the Producer can "produce", you'll be fine.
    7. But I've saved the best for last.  In LabVIEW 2016, NI introduced the Asynchronous Channel Wire, which is a more intuitive way of asychronously (meaning "almost instantaneously") sending data from a Writer to a Reader.  Look up "asynchronous wires" in the LabVIEW Help for a nice introduction.
  5. I notice that you have two DAQ tasks, both driven by VISA, one for temperature and one for "something else".  It looks like the two might be "slaved" together and forced to run at the same rate (I see a "wait 30 msec" timer in your loop, so that will determine the fastest you loop can run (though it certainly can run slower...).  So maybe you have a slightly different design than the simple Producer/Consumer -- hard to tell without knowing more about the boxes with grey question marks, as well as a "What is this code supposed to do" (we can see how it does it, but it's not clear what it is doing).

I have a friend/colleague (who introduced me to LabVIEW Vision) who has a pair of large monitors and uses every square inch for his VIs.  They are messier than yours, and when we discuss his code (we do a fair amount of helping find bugs in each other's code), my first question is always "What (in a few words) are you trying to do?".  I've finally got him to write sub-VIs to "hide the messy details" and let the flow of data shine forth ...

 

Bob Schor

0 Kudos
Message 5 of 11
(2,349 Views)

Hi Bob,

 

Thanks for the great reply. I have added some pictures of my lab (American Levitation Company) to help you understand what my ultimate goals are and hopefully you'll know what the best possible architecture could be (at the bottom I describe them). I taught myself everything I know about LabVIEW from the provided examples which I built off of, so I am not familiar with the queue and consumer-producer formatting. I will absolutely research it. 

 

As for your questions:

 

1.) No. I only find out if it's bad after it starts. Generally the issues are thermal contraction (using liquid nitrogen here) causes false positives in my signals, or the thermometer isn't accurate to the true sample temperature. I have found out that pausing before the while loop starts, I can transfer my chilled sample in without having to cool the coils, eliminating the thermal distortion issues. Now the issue is simply thermal contact of my thermometer to sample.

 

2.) How do I delete a file using labview programming? I couldn't find anything like that. 

 

3.) I am also not familiar with File Manager. I will have to look into this. I can tell based on the graph plot whether it is worth saving or not. It's pretty apparent when things aren't right. 

 

4.) What is my code suppose to do? I will try to explain everything in detail. Hopefully the pictures will help. In short, I use two devices to plot two Y-plots to one X-plot. (Y1,Y2,X) or (Real, Imaginary, Temp).

I also log the data to a pre-destined folder, for organization. 

 

I have two DAQ devices, IMG_4262, the top one is my HP34401A 6.5 Digit Digital Multimeter. It is connected to a T-Type thermocouple and is remote controlled via an RS-232 serial cable to USB. The first subVI measures the voltage, and the next converts it to the temperature based on a 6th order polynomial. This is my X-axis data. The bottom device is my "rolls royce", a Stanford Research System SR-530 Dual Phase Lock-In Amplifier controlled by a high-speed GPIB-to-USB cable. It measures the difference in phase between a reference signal and measured signal and produces a phase-dependent DC voltage output based on the change in phase. This device provides the two Y signals, a "Real" component of the signal and a "Imaginary" component. My (Y1,Y2). The first subVI measures the Y1,Y2, but also the noise for each signal. The second subVI, tells me the phase and reference frequency. (I can't cry wolf here, so I measure absolutely everything I can.)

 

A typical run looks like IMG_4401. The REAL signal drops to a negative value showing a transition of my sample to its superconducting state. The IMAGINARY signal spikes through the transition, which describes the conduction of induced currents across the grains. The temperature of this run is wayyy off. It should be around 90 Kelvin, not 150K. So this run wouldn't be saved, although it is pretty. 

 

The sample looks like a minitature hockey puck (IMG 4213), and the sample holder/fancy transformer is (IMG 4244).  The sample sits in the middle of the bottom half of the secondary coil (two coils opposing each other) and this whole thing sits inside the primary (the larger outer coil). 

 

The beauty of it all is, it tells me the volume fraction which is superconducting, the critical temperature at which superconductivity begins, and the IMAGINERY signal is related to how well it can conduct supercurrents across its grain boundaries, i.e. how well I could make a wire out of it. All of this without touching the sample, so no thermal EMF, faulty contacts, and maintain the ability to further process it, as well as high throughput testing. MIND BLOWN. 

 

I have no idea if consumer producer is right for me or not, I taught myself everything based on examples. In general, I have to extract two Y-data points simultanesouly from the lock-in amp, and plot it against the temperture data, X-data points, obtained from my multimeter, while also logging the data. 

 

Warm ups work best. I cool the sample or sample + entire coils down to 77K with liquid nitrogen, hit run, and then let it warm up while plotting. Typically, 2 measurements/second. More could be better as long as I don't run into timing issues. I'm happy to provide any subVIs if you think it will help. 

 

Looking forward to your reply. 

 

Regards,

James. 

 

 

 

 

0 Kudos
Message 6 of 11
(2,327 Views)

@User002 wrote:

Hi Bob,

As for your questions:

 

2.) How do I delete a file using labview programming? I couldn't find anything like that. 

File I/O Palette, Adv File Functions sub-Palette, Delete.  Wire the path to the input, run it, and the file will be deleted.  Read the Help for the function.

 

3.) I am also not familiar with File Manager. I will have to look into this. I can tell based on the graph plot whether it is worth saving or not. It's pretty apparent when things aren't right.

Windows File Manager is what you use to examine all of the Files on your Windows system.  It's what runs when you type <Windows Key>+E, and what you use (probably every day) to copy, move, and delete files by seeing the whole file system and finding the file(s) you want to use. 

 

4.) What is my code suppose to do? I will try to explain everything in detail. Hopefully the pictures will help. In short, I use two devices to plot two Y-plots to one X-plot. (Y1,Y2,X) or (Real, Imaginary, Temp).

I also log the data to a pre-destined folder, for organization. 

Thanks for the description.  Let me see if I can condense it a bit and rephrase it as my understanding of "What" you want to do:

  • You have two devices connected to different DAQ hardware.  One uses straight VISA commands, the other uses GPIB, or something similar.
  • The two devices work independently, that is, there is nothing intrisically synchronizing the rate at which they acquire samples.
  • Your sampling rate is fairly low (2 Hz, but you wouldn't mind going at 20 Hz).

So here is a question -- I've worked with VISA devices (and once did something with GPIB), and think of them as "Call and Response" things -- you send an Instruction ("Take a Reading") and wait for a Response ("Here's the data you wanted"), with the data often returning in String format.  Sometimes the device can be set up to provide data at a specified rate, but if you have two separate devices, you might get into a situation where the rates aren't exactly equal, in which case you can ask (repeatedly) for single samples from both.  Oops, where's the Question?  It is "Which situation fits your code?".  I suspect you are doing two Call and Responses, in which case the Solution Writes Itself.


Here's an interesting Self-Study Exercise for you.  Open LabVIEW.  Click on "File", then "New ..." (the second entry, with three dots), expand "VI", "From Template", "Frameworks", and click on "Producer/Consumer Design Pattern (Data)".  This shows you a Queue-based Producer/Consumer Design Pattern.  You would put your code that reads from VISA and gets a data point in the top (Producer) Loop, which you see does nothing except "produce data", and all of the processing (making Charts, saving to disk, etc.) in the bottom "Consumer" loop.

 

Which brings up another question -- are you getting samples at a fixed (and known) rate, and is the rate the same for both?  I recall that you are using a Graph, instead of a Chart.  Do you understand the difference between the two?  Charts are for displaying data "as it comes in", and is good for visualizing data that are changing in time (think of a Strip Chart recorder, or an oscilloscope where "the moving finger writes"), whereas Graphs are designed to be static (what you see doesn't change unless you overwrite everything again).  When acquiring data, Charts are more commonly used, with Graphs used after the data are all collected and you want to "look at it (all)".  I don't have your code in front of me right now, but I have a vague recollection that you used Graphs instead of Charts.  [Of course, another reason for a Graph, particularly an XY Graph, is when X is not "equally-spaced time intervals" ...]

 

Bob Schor  

0 Kudos
Message 7 of 11
(2,246 Views)

Hi Bob,

 

Thanks for all the great advice. I think the File Delete is the easiest solution. However, I'm not one to shy away from great advice and went ahead and made a new VI as a consumer-producer architect based on the example you suggested. 

 

You are right about my DAQs. I have two completely independent DAQs that I collect data from using a call and response methodology. I write command and it sends me the results. The way I "synchronized" them was by adding a wait-time between the Write and Read Functions. It's controlled in the multimeter subVI because of timing issues without it. 

 

Without that wait time, I got a bunch of timing issues and errors. It works as it should, but I will attach the subVI so you can see. Everything else should be okay. 

 

I am using graphs as my data is temperature-dependent and not time-dependent at all. 

 

How is my new Consumer-Producer design? I have not tested it yet, but I am about to in a few minutes.

 

Looking forward to your reply. 

 

Thanks again, Bob! 

 

James

Download All
0 Kudos
Message 8 of 11
(2,234 Views)

Hi Bob,

 

I tried out my new Consumer Producer VI, and it works as it should. I found out that I am limited by the speed of my multimeter so I can't read data faster than ~2.4 samples/second. Perhaps there is a way but I will leave that for another day. 

 

I made some small adjustments to get it working as I wanted it to. I added a false constant on the TDMS file creation so it stopped making TDMS_index_files as the File Delete only deleted the TDMS file and not the index file too. The second adjustment was I added a flat sequence around the File Delete prompt after the producer loop closes. I was getting asked to save the data way too early and this fixed it. 

 

My last and only thing that could be better is how can I reinitialize the arrays in the producer while loop? I would like to be able to graph data to see it cool down, but then refresh the graph when I actually want to start collecting true data on the warm-up. It would be nice to do this without having to restart the program. 

 

Any advice? This has been a great learning experience. 

 

Thank you so much. 

 

James

 

0 Kudos
Message 9 of 11
(2,219 Views)

Hi Again!

 

I added a case structure inside the consumer while loop that reinitializes the arrays by way of a boolean control button. I changed its mechanical action to "latch when released". When it's true, it reinitializes the arrays and then changes to false, and when it is false, all data is passed through unharmed. 

 

This should be my final VI form until I read your future feedback. 

 

Thanks for everything, Bob.  Wish I could buy you a beer/beverage.

James

0 Kudos
Message 10 of 11
(2,213 Views)