[Logix] Getting math errors with ADD instruction

defcon.klaxon

Lifetime Supporting Member
Join Date
Feb 2015
Location
Far NorCal
Posts
616
Hi guys,

I am trying to create a very basic totalizer in Logix; I need to keep track of runtime for pumps, their number of starts too; I need daily totals and lifetime totals as well.

After doing a bunch of experimenting with CTU instructions and trying to extract daily and lifetime values I figured I was getting too complicated, and simply resorted to an ADD instruction; I have an RTO pulse every 6 minutes when the pump is running for decimal hours, and each time the pulse occurs I simply add 0.1 to both my runtime tags. At midnight, I reset the daily tag and just let the lifetime tag keep accumulating value.

0diMPQX.png


It's ridiculously simple but it seems to work great...but there's an odd catch. Every time, like clockwork, when I go from 0.6 to 0.7, an error occurs. Instead of simply being 0.7, it's 0.70000005, then after the next pulse the new value is 0.8000001. Then about every fourth pulse, the error occurs again and that miniscule decimal amount in the ten-millionths place changes.

Now in the big scheme of thing, such a small rounding error is probably not going to affect my counter too much, but nonetheless I certainly don't like it. I tried changing the ADD instruction to 0.10000000000000 just to see if having that many zeros might stop the problem, but no dice.

Is this issue a well known problem? Is my code doing something I'm not realizing? I'd really prefer to get this to work right instead of living with this error.
 
So I've done some searching and reading, and it sounds like what I may be dealing with is the conversion of the decimal via IEEE-754 Floating Point Conversion as evidenced by watching the results from this website that shows the process in binary:

http://babbage.cs.qc.edu/IEEE-754.old/Decimal.html

Strangely though, if I modify my code to use a CTU to count pulses, and then simply divide by ten to get the decimal (each pulse would represent six minutes, or 0.1 hours) it works just fine. So why can I do this via division but the ADD instruction falters?
 
I don’t think this is related but it’s something I’d consider doing anyway.
I always use a one shot when using an add function. If it’s not there you run the risk of the rung being true long enough for the add function block to execute more than once.
So this is a real long shot but maybe the add function block has a resolution higher than “0.1”. The rung is true longer than it takes to add “0.1” and it goes false when the add block is “0.0000005” into the next add process so that gets added to the tag. Like I said very much a long shot but maybe it will inspire others to correct me and look at your issue closer (I.E. finding the problem).
 
I don’t think this is related but it’s something I’d consider doing anyway.
I always use a one shot when using an add function. If it’s not there you run the risk of the rung being true long enough for the add function block to execute more than once.
So this is a real long shot but maybe the add function block has a resolution higher than “0.1”. The rung is true longer than it takes to add “0.1” and it goes false when the add block is “0.0000005” into the next add process so that gets added to the tag. Like I said very much a long shot but maybe it will inspire others to correct me and look at your issue closer (I.E. finding the problem).

I will try a one shot just to see, thanks for the suggestion.

EDIT: Tried a one shot in front of the ADD instruction, didn't change the odd behavior.
 
Last edited:
you are getting caught on the real representation of a number in decimal

the CTU is counting integers then you are dividing by 10 how about you do the same
ie ADD 1 to a DINT to accumulate hours then divide by 10

as a side benefit doing this can actually store a larger number of run hours than a real
 
The only EXACT decimals in floating are sub multiples of 2. E.g. 1/2, 1/4, 1/8, 1/16, 1/32 and additions of these values - e.g. 3/4, 5/16 etc.

Just like 1/3 has no EXACT representation in standard decimal then anything except these types of sub multiples of 2 give eventual difference from what you expect.

If you were to approximate 1/3 as .33333 then after adding 3 of these you have .99999, not 1.

Another example of using the right tool for the job. Using a counter to accumulate in a 32 bit accumulator is a much better plan.
 

Similar Topics

I have Logix v21 running in Emulate. I am getting runtime faults at random times, typically it takes anywhere from 30 seconds to 5 minutes for...
Replies
7
Views
2,132
I am very, very new to PLCs. I only have experience with Picos, but I knew enough to save this from the dumpster. Apparently, everything on it is...
Replies
13
Views
614
All, I have a CompactLogix L33 and would like to get data from a height gauge. The gauge is a Fowler Sylac Mark VI with RS232 output. I can...
Replies
8
Views
2,611
I'm wanting to upload the program from a CompactLogix L31 Controller. I'm using a generic (non Allen Bradley) "C2G brand" usb -->rs232 cable...
Replies
4
Views
2,853
Good Afternoon, I'm trying to do online edits on a SLC 500 5/05 . After I put my instruction in , I keep getting " Test Edits Failed " ...
Replies
6
Views
3,735
Back
Top Bottom