LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Log Alarm Only Once

Solved!
Go to solution

Hi everyone,

 

I have an interesting issue with logging a 'thermocouple disconnected' alarm as part of a condition monitoring application.

 

I am logging thermocouple readings at 5 Hz  when a thermocouple becomes disconnected the reading rises to 1372, which is detected and should sound an alarm.  The application builds a string at this time (and publishes to a table) telling the user which thermocouple has disconnected, and any action undertaken (for example, turning the heater off).

 

I would usually include a snippet, although the code uses property nodes (as the error log code is in another loop) making it pretty much unreadable.

 

My issue is that the alarm is published on every iteration.  I need to keep checking for other thermocouple failures but disable one which has already occured.  I thought about setting a 'already written' variable in a shift register for each error case but this was getting messy quickly.

 

Any help (or ideas of a better way to do this!) are appreciated,

 

Pete

 

 


Regards,

Peter D

0 Kudos
Message 1 of 14
(4,842 Views)

I generally take care of issues like this using a boolean array.

Each bit represents some alarm, for example

001001

would mean that alarm 2 and alarm 5 were tripped.


This way, you can pass a single array into a shift register.

If an alarm is tripped, check if that bit is 0 or 1.

If it is 0, log that alarm, then switch that bit to 1.

If it is 1, then do nothing.

Cory K
Message 2 of 14
(4,835 Views)

Hi Cory,

 

Thanks for the reply!

 

I have done some work with your advice, with the following result;

 

 Error Logging.png

 

Notes;

 

  • Symbollic Temperatures is an array of 'Low', 'Med'.. 'Thermocouple Disconnected' - this is the only error I want to log at the moment.
  • Data logging to file is occuring in another loop, the local variable 'Log Data' is true if the data (temp, pressure, etc) is being logged and 'Current File' shows the path where that data is logged.

The above code will log the error once while the temp remains over the threshold (say error array 0000000001).  If the temp drops back below the threshold, it alarm reverts to 0000000000.  Then I would expect the program to write another line to the table when the temperature goes back above the threshold, which is desirable.  Although I only seem to be logging the occasional fault.

 

Any ideas why I could be missing them?

 

For a bit of context:- I am logging temperatures, pressures, particle contents (and more) to file continuously (a new file generated every 5 minutes) and ideally I would generate an additional file with a list of faults that have occured and the corresponding log which relates to them.  I'll also display the last few faults on-screen as follows;

 

 Fault Table.PNG

 

Thanks again,

 

Pete


Regards,

Peter D

0 Kudos
Message 3 of 14
(4,815 Views)

Please attach your actual VI, we cannot debug LabVIEW code from a picture, especially if most of the code is hidden in other cases.

 

Judging from what I can see, your code is about 70% too complicated and has many questionable constructs. For example the "equal FALSE" Is typical Rube Goldberg code. It is nothing more than an "invert". More reasonable would be to wire the boolean directly to the case selector and make the currently visible case FALSE. Right? ALso, that constant growing and shrinking of the array is very inefficient.

0 Kudos
Message 4 of 14
(4,806 Views)

I didn't include it initially as it is a small part of a larger project; I have attached a VI which performs the same function.  All the other cases just pass the fault string through.

 

I agree this is not my finest work Smiley Very Happy  There is some issues with the table not populating everytime and as you pointed out, this seems much more complicated than it should be.

 

The problem I have is that I need to cycle through each 'symbollic temp', then check if it is 'thermo disconnected' and following that generate the appropriate error.  I would like this to have something similar which cycles through 'symbollic pressures' and publishes to the same table.. although this method wouldn't scale at all well..

 

Are there any suggestions for a more efficient architecture to have the same result?

 

Thanks again,

 

Pete

 


Regards,

Peter D

0 Kudos
Message 5 of 14
(4,799 Views)
Solution
Accepted by Pete.Dunc

 


@Pete.Dunc wrote:

Are there any suggestions for a more efficient architecture to have the same result?


 

Well, some of your code is not necessary. For example you don't need to select between file name and "-" in the lower loop, because that's already done in the upper loop.

 

 

  • It seems better to keep the table at a fixed size and rotate the rows if needed.
  • I would recommend 10 table entries, else you'll miss some if all are disconnected at program start.
  • I would delete all the "false" diagram constants inside the inner cases and make the output tunnel to "use default if unwired".
  • I think you don't always get a log because you accidentally have a TRUE inside the "High" case. Double-check this!
I attach two versions, one just cleaned up for your architecture and a simpler version that eliminates some structures.
You did not include the subVI, so I made a dummy for it.
See if you get some ideas. 😄
(there are probably bugs...)

 

0 Kudos
Message 6 of 14
(4,787 Views)

Altenbach,

I'm looking at your coding technique to hopefully learn a few things. I was looking at your method to maintain the last 10 temperature alarms in the table. So the array isn't resized, you use a For loop with shift registers to reposition the elements in the array after a new entry is inserted.

 

I wanted to compare the performance of this method against another method where the last element is deleted, then the new element replaces index 0. I created an array of DBLs with 1x10^7 elements and tried to time each method.

 

Where is the flaw in my comparison? These are doing essentially the same thing, correct? Why is one so much faster than the other?

 

Eric

 

shift array elements_BD.png

0 Kudos
Message 7 of 14
(4,782 Views)

Correction on that code...

I had replace array subset where there should have been insert into array.

One method still appears faster and I wonder why this faster method isn't the one we should be using???

 

 

shift array elements_BD.png

0 Kudos
Message 8 of 14
(4,778 Views)

 


@egraham wrote:

One method still appears faster and I wonder why this faster method isn't the one we should be using???


 

Because your method is not the fastest. 😄

 

Yes, I was sloppy in my code and there was an additional buffer allocation due to the autoindexing branch of the array. If we index inside the inner for loop, we eliminate that extra buffer allocation and speed it up by more than a factor of two. (I did the autoindex for quicker coding and cleaner diagram, because it does not really matter in your application).

 

Also, don't underestimate the new compiler. For some reason your "delete..insert" does not cause a buffer allocation, something that might not be guaranteed in all cases. (tools...profile...show buffer allocations). It might also well be different on older LabVIEW versions. (I have not tried). It might also be different on different CPUs (My times are quite slow because they were done on a very old Athlon XP).

 

First, let's make sure we benchmark the right code. We don't do a single replacement as in your benchmark, but there is also an outer shift register where we keep the rotated array. You should also disable debugging, because loops have more debugging overhead, skewing the results.

 

Attached is a simple draft with 5 code alternatives. Just run and select one algorithm at a time via the enum selector. The time in ms will be graphed. (There are probably some bugs, please verify correct operation).

 

  1. Loop In Place: Using a loop and the "in place element" structure to rotate rows down.
  2. Loop Original: Using a loop and the proper inner indexing.
  3. Loop_autoindex: Same as (2) but with autoidenxing, causing a second buffer allocation.
  4. Delete_Insert: Your code (delete last, insert new element at the beginning).
  5. Insert_Delete: Basically same as (4) but with operations reversed.
Here are my results: algorithm incremeneted every 40 iterations)

 

 (1) and (2) are fastest, (3) is slowest, and (4)&(5) are somewhere in the middle, or about half he speed of the first two.

 

Feel free to find a fster method for the same task. There problaby is...... 😉

 

Also note that the real case has a 2D array of strings, so things might again be slighly different (not tested).

 

Just some food for thought.... 😄

Message 9 of 14
(4,744 Views)

Thanks! That's a great comparison study. You're helping all of us learn. Smiley Happy

 

The performance gains seem less significant between the fastest and middle method on the Intel Core 2 I'm using, but it's still noticeable.

 

As for quicker coding and cleaner diagram, that might be a matter of personal opinion which method to use. I'll try to get into the habit of using the more efficient method so if I'm ever working on an application where it really matters, I'm already doing it the right way.

 

Eric

 

shift array elements_compare5Algorithm_FP.png

0 Kudos
Message 10 of 14
(4,728 Views)