Recently, at work, we encountered an interesting situation that I wanted to write about here, because the case is quite interesting, although it turned out to be simple. On one of the units controlled by the controller from Allen Bradley Compact Logix L33ER, warnings were constantly pouring in the controller, or rather, even minor errors (Minor Faults) – which do not affect the functionality in any way, but annoy with their presence. Several dozen such errors per second without interruption: Type 04 Program fault (Code 04) Arithmetic overflow. Result of an arithmetic instruction out of range
The problem occurs in one subroutine, in two different places (Rung 0 and 37), where the same block is called, that is, the problem is in this Penetration Control block, because by excluding the block call from the program, the errors stopped completely
Inside this block is the formula:
Bend_Radius := ((2.0*Penetration*Material_Gage)-(Penetration **2.0)-(Material_Gage **2.0)-(Roll_Spacing **2.0/4.0))/(4.0*(Penetration-Material_Gage)); Yield_Percent :=1.0-((Bend_Radius*2.0*Material_Yield)/(Modulus_Of_Elasticity*Material_Gage)); IFBend_Radius > 0.0 THEN Bending_Loss :=(3.0*Material_Width*Material_Yield*Material_Gage**2.0)/(2.0*Bend_Radius)*(1.0+(1.0/(86.3-(88.0*Yield_Percent)))); ELSE Bending_Loss := 0.0; END_IF;
The initial assumption was that there are too many decimal places for all of these Material_Gage or Material_Width, and after squaring and in general the number of decimal places becomes even greater. Of course, the REAL data type allows you to store a lot of characters, and moreover, as I understand it, it doesn’t matter how many of these characters there are, it will store the number, just with a loss of precision, but this should not cause errors. But since this hypothesis is the easiest to test, we tried to slightly reduce the accuracy of the calculations by rounding the numbers to 2-3 decimal places. By the way, such strange numbers that are on the screen are obtained due to the fact that millimeters are converted to inches, and other metric units are converted to non-metric ones. As a result, the trick with a decrease in accuracy did not lead to anything, errors continued to pour in.
It’s just another failed attempt.
We tried to tinker with data types a little. DoubleInt did not fit – maybe the range is larger (8 bytes instead of 4, I guess), but it only stores integers. But on the other hand, we checked that the controller doesn’t care, that they want to save a floating point number into an integer type, it just stupidly rounds it up (apparently it is automatically converted)
But the idea of finding out at what stage of the calculations the overflow occurs, has borne fruit. It turned out that the problem is in the very first formula, where there are just a lot of raising to the second degree. After replacing all X ** 2.0 with X * X, in the first formula, the errors stopped pouring. Further it was already interesting and which parameter gives such a failure. And in the end it turned out that Penetration ** 2.0 causes an overflow, but Penetration * Penetration does not. The difference between Penetration and other variables is that it is a negative number. As soon as we change it to a positive number, there are no errors, a negative number immediately crashes.
Here’s an interesting case. I suspect that this overflow is due to a bug in the controller firmware: perhaps the expression is parsed incorrectly, or something. Can be used different instructions in the processor, for different types of records. That’s why I wrote about it here, maybe someone will tell you what it might be, I’m just curious. Or perhaps someone will come across something similar and find this entry through Google, and will be able to immediately fix such an overflow error in their project without unnecessary gestures.