RSLogix 5000 bug or floating point limitation?

ryangriggs

Lifetime Supporting Member
Join Date
Jun 2016
Location
USA
Posts
198
PLC: 1769-L35E
Firmware: 16.24
RSLogix 5000 Full Edition V16.06.00 (CPR 9)


I'm trying to fix someone else's FBD program that calculates motor runtimes. The program currently stops counting at 4096.0015 hours and won't go any higher. I can manually edit the value to 4097, which then counts up a couple clicks to 4097.0015 and stops again.


I'm sure it's a floating point accuracy limitation, which makes additional 1-second additions result in the same value after dividing by 3600.0. I'm not sure the best way around it while keeping the existing code. Maybe it would be best to rewrite it completely.


The simplest way I can think of would be a simple adder, storing the runtime as "Seconds", then calculating another tag for runtime hours, instead of trying to convert hours to seconds then back to hours each loop.



Here's the FBD, which is called from a scheduled task which copies the motor runtime into 'value', the running status bit into 'running' and the runtime reset bit into 'reset' once per second.



As I understand it, the steps are as follows, repeated every second:


1. Multiply the current runtime hrs by 3600.0 to convert horus to seconds.
2. If the motor is running, add 1 to the value. If not running, add 0.0 to the value.
3. Divide the result by 3600.0 to convert back to hours

4. If Reset is enabled, copy 0.0 to the source tag. If Reset is not enabled, copy the resulting hours value to the source tag.
5. Reset 'reset' tag to 0.



(Frankly, I'm not sure why they chose this convoluted way to do such a simple task, but whatever...)

ykru


Thanks for any input. Suggestions and recommendations welcome.
 
Why do you need to do floating point maths ?.
Why not have 3 Double integer variables one for hours, one for mins & one for secs, every second increment the seconds, when it reaches 60, increment mins, reset seconds, when mins = 60 increment hours, reset minutes.
Note: I suggested double integers just to reduce code converting say integer to double for the total (no idea in CLX if this is required or needed depends on max expected value for runtime).
 
Hi Parky, yes I realize it *could* be done a lot of ways. I was just wondering if the current implementation could be fixed without too many changes, to avoid making a bunch of major changes to a running system. However, I guess there's no way to increase the number of digits in a 'real' as there doesn't seem to be a double-precision float in RSLogix 5000.
 
I had to do something similar for monitoring amp/hours off a electroplating power supply for chemical replenish. It can't add 0.00000001 to a number that can't have that precision and CLX's have 7 point precision for real numbers.

The small value every 2 seconds would add to a point, then not make any value change on the amp/hour total that cycle.

What I did was calculate mA/seconds and when that got to a value of 360,000 I added 1 amp hour and subtracted 360,000 from the mA/seconds value.
 
As you note, this behavior is definitely due to the limitation of 32-bit (4-byte) REALs; see the [TL;DR] and Python/NumPy example below.



It may not be the minimal change, but one approach to changing the existing code is
  • Drop MUL_01
  • Have a new variable, DINT [dintvalue], feed ADD_01.SourceA
  • Swap DIV_01 and SEL_02 i.e.
    • SEL_02 will be before DIV_01
    • ADD_01.Dest (a.k.a. [dintvalue]) feeds SEL_02.In1
    • 0 (integer) feeds SEL_02.In2
    • SEL_02.Out
      • Feeds DIV_01.SourceA
      • Goes to [dintvalue]

      xxx.png
    • DIV_01.Dest goes to [value]
    • No change to the following
      • [reset] feed to SEL_02.SelectorIn
      • [3600.0] feed to DIV_01.SourceB
Using this method

  • arithmetically there is no change,
  • logically it is similar,
  • and practically it is more accurate*.



* The [value] will have better accuracy as the hours accumulate, because in the existing code

  • (1/3600)h cannot be represented exactly in IEEE-754 floating-point so it is rounded, and
  • when combined with the ADD, that rounding effect (error) becomes more severe as [value] increases
  • See the final code examples in the [TL;DR] below; the current method is off
    • by 4% (high) at 42d, and
    • by 9% (low) at 167d.

TL;DR

Using a 32-bit REAL to accumulate 1s increments as (1/3600)h increments means the existing FBD approach is limited to accumulating no more than around 16 million seconds (4096h) which is about half a year (a year is around PIe7s).


Using a DINT (32-bit signed integer) to keep track of accumulating whole seconds will be good for accumulating ~68y of 1s increments).



The format (see here) has 23 real bits plus 1 implied bit of mantissa, so its smallest incremental step is one part in 2**24 = 16,277,216 a.k.a. "16M").



Code:
$ python
Python 3.7.7 (default, Mar 26 2020, 15:48:22) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> import numpy
>>> 
>>> i=numpy.array([1.,14745604.,14745605.,14745606.],dtype=numpy.float32)
>>> 
>>> i
array([1.0000000e+00, 1.4745604e+07, 1.4745605e+07, 1.4745606e+07],
      dtype=float32)
>>> 
>>> xi=i/numpy.float32(3600.)
>>> 
>>> xi
array([2.7777778e-04, 4.0960010e+03, 4.0960015e+03, 4.0960015e+03],
      dtype=float32)
>>>
Examples of 32-bit rounding error for the existing code for the first, thousandth, and four-thousandth hours:


Code:
>>> sum([numpy.float32(1.)/numpy.float32(3600.)] * 3600, numpy.float32(0.))
0.99997044
>>>


Naive:


>>> sum([numpy.float32(1000.)]+[numpy.float32(1.)/numpy.float32(3600.)] * 3600, numpy.float32(0.))
1001.09863
>>> 



Actual:


>>> sum([numpy.float32(1.)/numpy.float32(3600.)] * 3600000, numpy.float32(0.))
1038.9353
>>> 



>>> sum([numpy.float32(1.)/numpy.float32(3600.)] * (3600000*4), numpy.float32(0.))
3675.654
>>>
 
Last edited:
For sure use a DINT instead of a float for accumulators like this. For motor run times, I normally run a 36 second RTO (retentive TON timer) when the motor proof of run is detected and each time the DN bit is set, I add 1 to the DINT and reset the timer. The DINT represents run hours to 2 decimal places (hours * 100) and I normally just scale it in the HMI/SCADA to stick that implied decimal point where it belongs.

If you need run times down to the second, the same logic would apply, but you would run out of precision on the 248th day.. EDIT: Scratch that, I divided one too many times. you have 68 years worth of seconds in a signed DINT...
 
Last edited:
EDIT: Scratch that, I divided one too many times. you have 68 years worth of seconds in a signed DINT...

Bet you get a call in about 69 years because of your program.

EDIT: Add another DINT and you're set for a few billion years, if the plastic holding the circuit boards isn't dissolved.
 
Last edited:
Bet you get a call in about 69 years because of your program.

EDIT: Add another DINT and you're set for a few billion years, if the plastic holding the circuit boards isn't dissolved.

Job security. I need something to keep me active when I am 122 years old. Actually, i am pretty sure I roll it over after 10,000,000.00 hours. Yeah, pretty dumb for me to add that extra branch of logic, but in the year 3161 I don't wanna be blamed for a math overflow.
 
A Y2k programmer was very busy in 1998 and 1999, and made so much money and got so burned out that they chose to deep freeze their body.

So one day they are woken up, and after some initial adjustments, they ask "Why did you wake me up?"


"Well, we saw that you had experience with the Y2k problem, 8000 years ago ..."
 
PLC: 1769-L35E

I'm trying to fix someone else's FBD program that calculates motor runtimes. The program currently stops counting at 4096.0015 hours and won't go any higher. I can manually edit the value to 4097, which then counts up a couple clicks to 4097.0015 and stops again.


I'm sure it's a floating point accuracy limitation, which makes additional 1-second additions result in the same value after dividing by 3600.0. I'm not sure the best way around it while keeping the existing code. Maybe it would be best to rewrite it completely.

Yes, as mentioned ... it is an accuracy issue with float

If you keep the code as is, then add a second value (hours) you are good.

If totalizer > 1 then add 1 to hours, subtract 1 from totalizer.
Output hours + totalizer to the value you display.
You would have to modify your reset logic a bit.

The totalizer for decimal hours is still decently accurate. And it keeps counting up.
 
Do you really need to track running time to an increment size of 1 second?
Instead of calling the routine every second call it every ten seconds. Then you can use a factor of 360 instead of 3600. Better still, call it once a minute and use a factor of 60.
 
A Y2k programmer was very busy in 1998 and 1999, and made so much money and got so burned out that they chose to deep freeze their body.

So one day they are woken up, and after some initial adjustments, they ask "Why did you wake me up?"


"Well, we saw that you had experience with the Y2k problem, 8000 years ago ..."

In my encounters with this joke, it's usually specified that the programmer is fluent in COBOL…
 
But what about the January 2038 bug?


I'll be dead by then, but that's for 32-bit, non- or old-Linux systems.


The Deep Impact spacecraft was lost when it presumably safed and started rebooting endlessly shortly after 2013-AUB-11T12:38:49.600000, for an analogous reason.


The reason can be deduced from https://naif.jpl.nasa.gov/pub/naif/DEEPIMPACT/kernels/sclk/DIF_SCLKSCET.00121.tsc and https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/FORTRAN/req/sclk.html.
 
Last edited:

Similar Topics

hi I am using RsLogix 5000 ver 13.03 and many times when I open the application nothing shows up on the screen. The RsLogix icon is not even on...
Replies
4
Views
4,812
Hello, I have a problem with RSlogix5000 v.15.01.00: When i export tags via the CSV file, the file is full of "?" character in...
Replies
6
Views
17,315
Hello, I am trying to read a barcode scanner input using a cognex dataman 280 barcode reader, store it another string, the compare with another...
Replies
1
Views
93
Hi folks, in the alarm manager of Rslogix 5000, the tag-based alarm has been created. But when I tried to change the condition, it was found the...
Replies
2
Views
196
Back
Top Bottom