Help - Search - Members - Calendar
Full Version: ControlLogix 1sec,1 min, and 15min average calcs
Forums.MrPLC.com > PLCs and Supporting Devices > Allen Bradley
servant
Is there a simple way to perform ControlLogix 1second, 1 minute, and 15minute average calcs, and then reset the average to prepare for the next time period averages?
I am reading some analog inputs and a modbus input, and need them to be averaged at the aforementioned intervals, so that drift calculations can be performed.
Please assist.
Ken Moore
Store your analog values in an array, then use the FAL instruction to calculate the average for 1 second.
Store the results in a second array, average those values every 1 minute, store the results in an additional array, average those every 15 minutes.
servant
QUOTE(Ken Moore @ Oct 22 2007, 04:27 PM) [snapback]60751[/snapback]

Store your analog values in an array, then use the FAL instruction to calculate the averages.

Can you offer any examples?
I'm guessing to have a 60 point array being filled every second and dividing the sum of all 60 values by 60 for the one minute array. Then I suppose to take the one minute calculated averages into a 15 point array and dividing the sum of all 15 values by 15.
Example code or picture would be very helpful, as I have never used the arrays.
paulengr
QUOTE(servant @ Oct 22 2007, 05:07 PM) [snapback]60750[/snapback]
Is there a simple way to perform ControlLogix 1second, 1 minute, and 15minute average calcs, and then reset the average to prepare for the next time period averages?
I am reading some analog inputs and a modbus input, and need them to be averaged at the aforementioned intervals, so that drift calculations can be performed.
Please assist.


1. Run the task periodically so that you can control the timing rate at which it takes samples. So for instance if the task runs every 25 ms, then you will have 1000/25 = 40 samples.
1a. Alternatively, set up say a millisecond timer with a preset of 1 second. The timer preset can be anything as long as it is significantly larger than the sampling interval. On each program scan, check if the timer accumulator exceeds your resolution (25 ms in this example). If so, then SUBTRACT 25 ms out of the accumulator and trigger the totalizer code. This will introduce some timing jitter to your sampling but it has the advantage that you don't have to have a specialized task for the timing issue.
2. Clear 2 registers. One will be a sample count. The other will be a totalizer. The sample count can be implemented as a counter which is handy because some of the logic is built-in.
3. At each time interval, add 1 to the sample count. Take a sample and add it into the totalizer (a running total).
4. At the end of your time period, divide the totalizer by the sample count. This is your average. Then go back to step 2.
5. Since your time intervals are exact multiples of each other, you can either repeat this block of code 2 more times (with different sample counts and time intervals) or simply add the 1 second total to a second sample count/totalizer for 1 minute (for 60 samples), and then add THAT one to a totalizer for 15 minutes (15 samples). The results are the same but this version can be more efficient since 2/3rds of your code runs very infrequently (once per second, once per minute). A second issue is that for the 15 minute interval at 25 ms intervals, you will have to use something other than an integer (40 samples per second * 60 secs/min * 15 minutes = 36000 samples, which is larger than 32767).

This version is a running totalizer. Alternatives (which are slower since division is slow on virtually all CPU's) is to do the division operation on every sampling interval. You could do the division every time following the same math as above or calculate ((old average * sample count-1) + new sample) / sample count). The downside of this calculation is that it will have precision issues (division is almost always approximate) so it is best to avoid it.

Finally, you can trigger this sort of code just as easily off the real time clock instead of a sample counter. In this case, most of the time I use a trigger that looks something like the following (in pseudo-code):
If LastReading <> ClockSeconds then
LastReading=ClockSeconds
Set "trigger" to run the code that should run once per second
end if

The primary advantage of triggering off the real time clock is that frequently when doing running totals or averages, managers get hung up with the physical clock on the screen/wall and expect 15 minutes to be synchronized with "real time".

There are also issues with this. If someone is screwing with your clock (since PLC clocks are notoriously inaccurate and can gain/lose a few seconds per day, and also to implement daylight savings time sanely), it will screw up your code if you don't account for it. For the same reasons, if you run a sample count, you may find some jitter in that say on 25 ms intervals, you will sometimes have 40 samples, sometimes 39 samples, or sometimes 41 samples. So the safest bet of course is to implement both (keep a sample count but use the real time clock in the PLC) if you find yourself in a situation of running block averages tied to the wall clock.

All previous versions are a running totalizer system. The previously mentioned FAL or AVERAGE instructions also work. They take more memory and have more processor timing jitter since the processor does the addition step all at once at the end of the interval. Plus, the 15 minute average with 25 ms sampling rates amounts to 36,000 samples. Even on Contrologix, that is going to be one heck of a delay every time it executes an FAL for that many samples.

servant
QUOTE(paulengr @ Oct 24 2007, 05:10 AM) [snapback]60842[/snapback]

QUOTE(servant @ Oct 22 2007, 05:07 PM) [snapback]60750[/snapback]
Is there a simple way to perform ControlLogix 1second, 1 minute, and 15minute average calcs, and then reset the average to prepare for the next time period averages?
I am reading some analog inputs and a modbus input, and need them to be averaged at the aforementioned intervals, so that drift calculations can be performed.
Please assist.


1. Run the task periodically so that you can control the timing rate at which it takes samples. So for instance if the task runs every 25 ms, then you will have 1000/25 = 40 samples.
1a. Alternatively, set up say a millisecond timer with a preset of 1 second. The timer preset can be anything as long as it is significantly larger than the sampling interval. On each program scan, check if the timer accumulator exceeds your resolution (25 ms in this example). If so, then SUBTRACT 25 ms out of the accumulator and trigger the totalizer code. This will introduce some timing jitter to your sampling but it has the advantage that you don't have to have a specialized task for the timing issue.
2. Clear 2 registers. One will be a sample count. The other will be a totalizer. The sample count can be implemented as a counter which is handy because some of the logic is built-in.
3. At each time interval, add 1 to the sample count. Take a sample and add it into the totalizer (a running total).
4. At the end of your time period, divide the totalizer by the sample count. This is your average. Then go back to step 2.
5. Since your time intervals are exact multiples of each other, you can either repeat this block of code 2 more times (with different sample counts and time intervals) or simply add the 1 second total to a second sample count/totalizer for 1 minute (for 60 samples), and then add THAT one to a totalizer for 15 minutes (15 samples). The results are the same but this version can be more efficient since 2/3rds of your code runs very infrequently (once per second, once per minute). A second issue is that for the 15 minute interval at 25 ms intervals, you will have to use something other than an integer (40 samples per second * 60 secs/min * 15 minutes = 36000 samples, which is larger than 32767).

This version is a running totalizer. Alternatives (which are slower since division is slow on virtually all CPU's) is to do the division operation on every sampling interval. You could do the division every time following the same math as above or calculate ((old average * sample count-1) + new sample) / sample count). The downside of this calculation is that it will have precision issues (division is almost always approximate) so it is best to avoid it.

Finally, you can trigger this sort of code just as easily off the real time clock instead of a sample counter. In this case, most of the time I use a trigger that looks something like the following (in pseudo-code):
If LastReading <> ClockSeconds then
LastReading=ClockSeconds
Set "trigger" to run the code that should run once per second
end if

The primary advantage of triggering off the real time clock is that frequently when doing running totals or averages, managers get hung up with the physical clock on the screen/wall and expect 15 minutes to be synchronized with "real time".

There are also issues with this. If someone is screwing with your clock (since PLC clocks are notoriously inaccurate and can gain/lose a few seconds per day, and also to implement daylight savings time sanely), it will screw up your code if you don't account for it. For the same reasons, if you run a sample count, you may find some jitter in that say on 25 ms intervals, you will sometimes have 40 samples, sometimes 39 samples, or sometimes 41 samples. So the safest bet of course is to implement both (keep a sample count but use the real time clock in the PLC) if you find yourself in a situation of running block averages tied to the wall clock.

All previous versions are a running totalizer system. The previously mentioned FAL or AVERAGE instructions also work. They take more memory and have more processor timing jitter since the processor does the addition step all at once at the end of the interval. Plus, the 15 minute average with 25 ms sampling rates amounts to 36,000 samples. Even on Contrologix, that is going to be one heck of a delay every time it executes an FAL for that many samples.

Wow,
Thanks paul!
You said a mouthful.
My first, or current attempt follows closely with your original proposal, except I used an "ADD + 1" instruction instead of a counter. I'm, also using a 100ms timer to trigger my counts, or summations. My biggest setback, or concern, is when to clear the register to get ready for the subsequent averages on the 1sec, 1min, and 15min totals for which to derive my averages. I will not be able to test the logic until one or two days before the scheduled FAT test; therefore, I was hoping to be certain as to the logic results.

Alaric
If you keep a running total and a circular FIFO it is not necessary to perform the summing of all 60 samples every time you recalculate the average.

Here is a sample of the method I set up for another poster who was using an ML1100 to average 200 samples. This would be even simpler in the CLX, especially in ST.. It implements a circular FIFO using an array and a pointer instead of fifo instructions. Its fast because it doesn't shift any large chunks of data around in memory and each new sample requires only one subtracion, one addition, and a single divison to recalculate the new average. On the CLX use the CPT instruction to avoid the intermediate result storage.

http://forums.mrplc.com/index.php?act=Atta...ost&id=5403

(original thread with the solution above http://forums.mrplc.com/index.php?showtopic=12206)

servant
QUOTE(Alaric @ Oct 24 2007, 06:14 PM) [snapback]60875[/snapback]

If you keep a running total and a circular FIFO it is not necessary to perform the summing of all 60 samples every time you recalculate the average.

Here is a sample of the method I set up for another poster who was using an ML1100 to average 200 samples. This would be even simpler in the CLX, especially in ST.. It implements a circular FIFO using an array and a pointer instead of fifo instructions. Its fast because it doesn't shift any large chunks of data around in memory and each new sample requires only one subtracion, one addition, and a single divison to recalculate the new average. On the CLX use the CPT instruction to avoid the intermediate result storage.

http://forums.mrplc.com/index.php?act=Atta...ost&id=5403

(original thread with the solution above http://forums.mrplc.com/index.php?showtopic=12206)

Thanks guys,
I have downloaded the file and see if I can replicate it and get it to work.
This looks super!!!!!!!!!!!!
Leadcommander
Function Block has an Averaging Instruction
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2010 Invision Power Services, Inc.