03-30-2009 07:48 PM
Hello all,
I am trying to solve a problem that seems superficially quite easy, but I haven't been able to figure out a way to implement it.
I am describing here the behavior of a temperature control program. There are three inputs: a list of temperatures, a corresponding list of wait times, and a specifications for an experiment to run at each temperature.
Here is what I'd like the temperature control program to do:
1) Send a setpoint to controller. The controller automatically heats/cools to adjust temperature. (already solved how to do this)
2) Wait until temperature is within a threshold value of setpoint.
3) Wait until the end of the wait time proscribed in the list. During this phase, it should reset the counter if the temperature drifts outside of the setpoint +/- the threshold value (though this is less important at the moment).
4) Take sample measurements using the specified inputs (also a problem I believe I've solved for this case).
I have attached the first file I got to work. In this case, it takes the iteration from the loop to determine which index to read out the setpoint/wait periods from the table. The problem with it is that it uses a time delay, so the program becomes nonresponsive during the wait period. I would like to use modules included in the base package if possible to avoid additional expense when it comes time to purchase (I'm using the evaluation version now).
I would like to use the elapsed time vi for the waiting periods, and after the wait period has ended it would increment the index. I was working on a way to increment the loop index using the elapsed time vi, but I was trying to use boolean operators to add/multiply 0/1 and found this functionality didn't work. I've also spent a fair amount of time looking at different structures (again, trying to avoid the event structure because it isn't in the base package) but I am not sure what type of structure would be best for this.
If the "elapsed time" approach works, the only problem with it is that the loop will run continuously, but I am not overly worried about that at this point because the driver for the temperature controller has a small wait time in it so the temperature only reads out 3 times/second, thereby limiting the rate of execution on the loop.
Any advice would be much appreciated, and I am actively working on this problem.
Thank you, and regards,
Scott
03-30-2009 08:59 PM
Using the elapsed time VI would be the better way to go. Why didn't that work for you? It would be better to post that VI and try to solve the problems on that one. You will probably need just 2 shift registers, one to hold the index value you are currently working with, and another to hold the start time of your wait cycle.
Why do you convert the string value to an integer, then to a complex double (very odd because what do temperatures have to do with complex numbers?), then basically to a double? Why not just use the string to fractional number VI in one shot?
03-30-2009 09:04 PM
Hi Scott,
See attached VI.
I think you want two nested loops -- one for each condition, one to keep track of the elapsed time. I think this will work (but can't tell for certain without the rest of your code.) BTW, if you use auto-indexing, you don't need to specify the number of iterations for the outer loop.
03-31-2009 12:38 AM
Thanks for the help guys. I'm totally new here, so even the minor hints you gave were useful, and I think I implemented all of them. I have some comments on each of the things I've tried, and I put some additional questions at the end.
@Ravens Fan
I made a vi with the elapsed time approach and it seems to be working okay. I ended up implementing it with shift registers and a case structure - those were the elements I was missing to get it to work properly (previously I couldn't figure out a good way to increment the index manually). However, the remaining problem is that the number of rows in the table is input manually as "number of temperatures" in the file "SetTemp Elapsed Time vs 1.vi"
This approach has also allowed the stop button to work fairly well (though not as fast as if I use an event structure, sadly).
@MattBradley
Thanks for the posting. I slightly edited the version you posted and got it to reproduce the original behavior. I could not figure out how to get it to stop, however, and it qualitatively behaves the same as the original file I posted (ie: you can't do anything until the inner loop finishes). Is there a convenient way to put a stop button inside of the inner loop? I couldn't get it to work for some reason. By the way, the auto-indexing feature was good to know (I didn't understand what it meant before). In this case I need to control when the index incements, so I'm not sure how I can use it. I do need to know the number of rows in the table, though. Any ideas?
Also, for any newbs like me who stumble upon this, the necessary edit to this file was that the "Index Array" modules weren't wired correctly. That is because with the table coming in from the outside (and thus auto-indexing), the "row" index was implicitly specified, and the constants had to be re-wired to the other input, at which point the 2nd (and unnecessary) index automatically removed itself.
Remaining questions
1) How do I tell automatically how many rows are in the table? If Auto-indexing can do it, there must be a function. I see that "number of rows" is an array property, but how do you call that function?
2) With respect to my original post, I now have the 2nd wait time working correctly. The implementation now needs a primary wait time to make sure the temperature is at the setpoint. Would it be better to implement another loop, another elapsed time block, some sort of conditional or sequence structure, or something else entirely? I am inclined to use the elapsed time block again.
03-31-2009 08:52 AM
The wire coming out of your table is just a 2-D array of strings. You can use the Array Size function on the array palette to get the size of the array. It will give you a 1-D array of 2 elements, 1 element for # of rows and 1 element for # of columns. You would just use index array to get whichever value you are interested in.
For that preliminary wait time, I would probably just use another case that handles elapsed time. Once that case has sucessfully completed (and you could keep track of that from one iteration to the next using a boolean shift register), you would go through your normal incrementing of the index that is part of your profile table.
03-31-2009 08:25 PM
Thanks for the advice. I implemented the array size function to determine the size of the input block. It has the curious problem that if I enter, for example, 5 entries in the table it will read the array size as 5, but when I delete 1 or more entries, it still reads 5. I got around this by making the program skip the final entries (their "wait times" are 0, so I set it to increment the loop if the wait time was 0.)
The conditional statement I added turned out to work really well. If the temperature is within the threshold value, the loop condition is true and the timer starts counting down - eventually incrementing once the system has waited the proscribed period. If at any point during the wait the temperature drifts out of the threshold range, the condition turns false and the elapsed time block is reset and waits the full period once the temperature returns to within the threshold. I also added that it will display infinite wait time if the temperature is out of range.
At this point the only thing I'd really like to change is that inputting values to the table is a little awkward, since the slide bar at the bottom tends to slide over when I'm entering values in the 2nd column. I can probably resize it or make some other adjustment, but it's aesthetically unpleasant.
Thanks again for the help. For one final question, would it make sense for me to mark my own post as a "solution"? The posted file is definitely what I was looking for, and I got there with help of the forum, but it's my own post. What is the prevailing etiquette?
Thank you.
Regards,
Scott
03-31-2009 08:52 PM
I'm glad to hear it is working more the way you want it go now.
It has the curious problem that if I enter, for example, 5 entries in the table it will read the array size as 5, but when I delete 1 or more entries, it still reads 5. I got around this by making the program skip the final entries (their "wait times" are 0, so I set it to increment the loop if the wait time was 0.)
How do you delete entries from the table? If you just delete whatever values are entered into a cell, it just basically creates an empty string cell. If you right click on a cell and select delete row, then the string array should shrink with it. The easiest way to see what is happening would be to put an array container on the front panel and drop in a string indicator, then add a dimension to make it a 2-D array of strings. Then enlarge the array so you see more rows and the 2 columns. Wire your table to that. Now you'll be able to see in the string array indicator whether a row exists and is just empty strings, or whether a row doesn't exist at all. That should help yo debug what is going on.
SAMullin wrote:
At this point the only thing I'd really like to change is that inputting values to the table is a little awkward, since the slide bar at the bottom tends to slide over when I'm entering values in the 2nd column. I can probably resize it or make some other adjustment, but it's aesthetically unpleasant.
I would adjust the sizing of the table a bit if necessary. But another option is to turn off the horizontal scrollbar in the properties of the table.
SAMullin wrote:
Thanks again for the help. For one final question, would it make sense for me to mark my own post as a "solution"? The posted file is definitely what I was looking for, and I got there with help of the forum, but it's my own post. What is the prevailing etiquette?
The solution marking is a relatively new feature to the forums and the etiquette on it is still evolving. Marking a reply as a solution could serve 1 of 3 purposes that I can think of.
1. Identify threads in the master list as to which questions have been solved and which still need more help.
2. Identify the reply in a thread as to which reply was the actual solution. That way for threads that have dozens of messages over numerous pages, it is easy to jump to the reply that really solved the problem.
3. Identify the reply that was most helpful in solving the problem. This can help in the event there are any ratings or contests based on which users have helped solved the most questions. Right now this doesn't seem to be tracked and only Kudos are being tallied. Marking a reply with a Kudo is always appreciated as a Thank you as well.
As a simplification in coding with your new lower shift register, rather than carrying a 0 or 1 and comparing that to a 1 to determine whether to reset the clock. You could just use a boolean True and False constants and turn that shift register into a green wire. I would also recommend initializing that shift register with a True or a 1 so that you guarantee the elapsed time is always reset on the first iteration of that loop even if the temperature is already in range.