floating point math on integer math PLC

snaggletto

Member
Join Date
Jul 2004
Posts
61
Hello,
I'm working with an AD DL05, integer math only. I've got a C-more micro for an HMI.

I need to input inch dimensions for a cut to length machine, IE. 14.5, 22.3 etc... and multiply by a constant, 11942, for encoder counts per inch, to calculate the number of encoder counts for a given dimension.

I understand that I can fake it in the PLC by multiplying by 145 (rather than 14.5) and then dividing by 10 to shift the 'understood' decimal point. However, decimals that aren't an even divisor of 10 end up with a decimal point after the multiplication. I'm not sure how to truncate this calculated decimal point in the PLC.

Or, maybe I can create two cells on the HMI, two different V-memory locations. I could draw a decimal point between them on the screen. Then do two different multiplications and combine the results after...?

I'm sure this is a common problem as not all PLC's have real or floating point math. There must be some more elegant work arounds out there.

Any ideas/techniques would be greatly appreciated. Thanks.
 
I understand that I can fake it in the PLC by multiplying by 145 (rather than 14.5) and then dividing by 10 to shift the 'understood' decimal point. However, decimals that aren't an even divisor of 10 end up with a decimal point after the multiplication. I'm not sure how to truncate this calculated decimal point in the PLC.
You are on the right track. I haven't worked with the DL05 PLC, but I know that on Allen-Bradley units, if you do an integer division that produces a fractional result, it is rounded. So, 146 * 11942 / 10 = 174353, not 174353.2.
 
There is no need to "Truncate" the decimal point. It's impossible to have a decimal point in integer math. Everything gets rounded.
 
1. On the C-More Micro in the Numeric Entry setup under 'Display Format' there is a 'Number of Digits' entry. Set the 'fractional' to '1'. The operator then can enter a fractional number (eg 14.5) and the full number (145) will be sent to the PLC.

2. The AD DIV operator truncates. it doesn't round. If needed, the remainder is on the stack and can be retrieved with a POP command.

3. Make sure to use the 'binary' data type in the AD. For your target. Make sure the C-More Micro's tag is set up the same. Then, once the operator enters a value, you can multiply (MULB) by a 11942 as constant (which has to be entered in its hex form - 2EA6). You will want to send the result via an OUTD to a pair of locations as it will probably overflow 16 bits.
 
3. Make sure to use the 'binary' data type in the AD. For your target. Make sure the C-More Micro's tag is set up the same. Then, once the operator enters a value, you can multiply (MULB) by a 11942 as constant (which has to be entered in its hex form - 2EA6). You will want to send the result via an OUTD to a pair of locations as it will probably overflow 16 bits.


Sounds easy enough. However, in my ignorance and inexperience with PLC's and computer numbering systems, I don't really understand why to use binary. I would like to understand, so can somebody elaborate on this and enlighten me? Thanks for the help everyone...
 
I should elaborate further on the results of my calculations. I'm driving an AD Sureservo servo amp in position mode via modbus, or I will be when I figure out all the programming.

I will be writing 3 parameters to the servo amp,

1. RPM
2. # of revolutions (IE. 10,000 encoder counts per rev)
3. # of pulses (IE. # of encoder counts less than 10,000)

For example, on a 26" part, and 11,942 encoder counts per inch (determined from gear reduction and feed wheel diameter) I get;
26 * 11942 = 310,492 Or 31 revs (10,000 count revs) and 0492 pulses (partial revolution). So, 31 goes to one v-memory location, and 0492 goes to another v-mem location. Both values are loaded to the respective parameter in the servo amp, telling the servo motor where to move to.

I just need a way to calculate values like 14.25 and 16.75 etc... Thanks again.
 
Sounds easy enough. However, in my ignorance and inexperience with PLC's and computer numbering systems, I don't really understand why to use binary. I would like to understand, so can somebody elaborate on this and enlighten me? Thanks for the help everyone...

Binary has the advantage of a larger number range. BCD intentionally throws away certain combonations as they are difficult for humans to easily interpret.

Single word (one Vmem) BCD range = 0-9,999
Double word (two Vmems) BCD range = 0-99,999,999
Single word (one Vmem) Binary = 0-65,535
Double word (two Vmems) Binary = 0-4,294,967,295

In addition, math operations with binary numbers are faster than BCD operations.

I should elaborate further on the results of my calculations. I'm driving an AD Sureservo servo amp in position mode via modbus, or I will be when I figure out all the programming.

I will be writing 3 parameters to the servo amp,

1. RPM
2. # of revolutions (IE. 10,000 encoder counts per rev)
3. # of pulses (IE. # of encoder counts less than 10,000)

For example, on a 26" part, and 11,942 encoder counts per inch (determined from gear reduction and feed wheel diameter) I get;
26 * 11942 = 310,492 Or 31 revs (10,000 count revs) and 0492 pulses (partial revolution). So, 31 goes to one v-memory location, and 0492 goes to another v-mem location. Both values are loaded to the respective parameter in the servo amp, telling the servo motor where to move to.

I just need a way to calculate values like 14.25 and 16.75 etc... Thanks again.

If you need two decimal places, just set up your math and HMI to use 2 (or 3) implied decimal places. Your math formula would look like this: 1675 * 11942 = 20002850 ... 20002850 / 100 (to move the decimal place) = 200028 ... The PLC will truncate the remainder and place it in the accumulator stack. We don't care about this remainder, but we will on the next operation. 200028 / 11942 = 16 You would OUT this to a Vmem as the number of complete revolutions. Remember that I said that the remainder is placed in the accumulator stack? The next instruction that we need (as bcarlton pointed out earlier) is a POP. This moves the remainder from the accumulator stack to the accumulator. We can then OUT this number into a Vmem that will represent how many pulses to move.

Note that (depending on your max diameter) the numbers are staying below the limits for a double BCD number. If you wanted 3 implied decimal places, you would have to move to binary to hold the intermediate results.

Brian
 
Last edited:
Ok,I ignored the binary format for the moment and focused on the calculations using MULD and DIVD for double BCD
numbers. What I have works, though I'm sure it isn't foolproof, and definitely not elegant or efficient. However,
it does put the correct numbers in V2001 and V2002, so far so good.


|c0|------LDD V1203 (11942 encoder counts/inch)
MULD V1201 (length as entered on HMI, IE. 26.25)
OUTD V1205 (temp storage of calculated value)
LD K100 (Constant 100 used as divisor to shift decimal)
OUT V1207 (DIVD doesn't appear to be able to use a constant?)
LDD V1205 (calculated value IE. 11942 * 2625 = 31347750)
DIVD V1207 (divide by constant 100 yields 313477)
OUTD V2001 (outputs 3447 in V2001, and 31 in V2002)

The '31' in V2002 is the # of complete revs (10,000 encoder counts per rev) of the servo motor, the '3447' in V2001 is the # of pulses for the partial revolution. Both values will be converted to binary and loaded into respective parameters in the Sureservo drive.

I'm not exactly clear on how to deal with binary numbers when inputing data from the HMI, and how to carry out the same calculations with binary rather than BCD...? Thanks for any input.
 
Last edited:
Ok,I ignored the binary format for the moment and focused on the calculations using MULD and DIVD for double BCD
numbers. What I have works, though I'm sure it isn't foolproof, and definitely not elegant or efficient. However,
it does put the correct numbers in V2001 and V2002, so far so good.


|c0|------LDD V1203 (11942 encoder counts/inch)
MULD V1201 (length as entered on HMI, IE. 26.25)
OUTD V1205 (temp storage of calculated value)
LD K100 (Constant 100 used as divisor to shift decimal)
OUT V1207 (DIVD doesn't appear to be able to use a constant?)
LDD V1205 (calculated value IE. 11942 * 2625 = 31347750)
DIVD V1207 (divide by constant 100 yields 313477)
OUTD V2001 (outputs 3447 in V2001, and 31 in V2002)

The '31' in V2002 is the # of complete revs (10,000 encoder counts per rev) of the servo motor, the '3447' in V2001 is the # of pulses for the partial revolution. Both values will be converted to binary and loaded into respective parameters in the Sureservo drive.

I'm not exactly clear on how to deal with binary numbers when inputing data from the HMI, and how to carry out the same calculations with binary rather than BCD...? Thanks for any input.

A few thoughts...

First, there is nothing _wrong_ with using BCD math. You just have to observe the limitations of the numbering format.

Second, the code you have works for your current situation. Hopefully you realize that your getting the correct numbers in V2001 and V2002 is a fluke that depends on you having a 10,000 count per rev encoder. Your math is incomlete if you change to a different encoder. As I said, your code works for your current situation, and is even elegant in this regard (avoids another divide.)

Third, dealing with binary is not that all that different than what you are doing now.
You have two options for dealing with data that was input from the HMI. First, you can leave the HMI data type set to BCD, convert the BCD info for use in the calculations; or second, (route I would take) set the HMI data type to binary (2 decimal places). This way, the HMI will put data into a Vmem that is already properly formatted for binary calculations.

Next, keep in mind the larger size limits of a binary Vmem. What used to be a LDD to get the number 11942 into the accumulator can now be a LD (LDD will still work, but then you can't use the next Vmem for anything and it will always be 0 if your constant doesn't exceed 65535.) Next would be a MULB (B is for Binary). Note that this too is now a single word instruction instead of a MULDB (or MULBD, I can't remember the correct spelling.)

Now, the result of this calculation _will_ be larger than 65535 from the numbers you have mentioned; so we still need the OUTD to put the result in storage (more on improving elegance here later).
Next, you would load your constant to remove the implied decimal places. In BCD math, this number is 100 (this is that whole human-readable thing here); in binary (hex actually) that number is 64. Fire up windows calculator in scientific mode for a handy converter. Enter a number in Dec mode and then change the mode to Hex to see the equivalent value. So, a LD K64 and an OUT to a Vmem to hold the constant (next Vmem will have to be empty as the instruction this constant is being used with will look at it as a double word.)

Next will be the DIVBD. Now, here is a difference with binary math vs. BCD. In BCD, all you had to do was OUTD and you had your two values. Just like magic. This won't be the case with binary (unless you changed encoders to a 65536 pulse per rev model.) To separate the revs from the pulses you will need to do another divide. Another LD K2710 (10000 in hex) and OUT to a Vmem and then another DIVBD is needed.

Now you have the number of revs in the accumulator and the number of additional pulses in the accumulator stack. An OUT will put the number of revs into a Vmem. You then need a POP to move the number of additional pulses from the stack to the accumulator where another OUT can place them in another Vmem.

Whew...

On improving elegance...
I would LD and OUT your constants at the beginning of the program. First, they will only be setup once instead of every time you calculate a move (this will improve scan time.) Second, you will be able to move from one instruction to the next without temporarily storing a calculated value just to setup a constant. Your MUL would be followed immediatly with a DIVBD. This will improve readability.

On a separate note on elegance...
If you stay with BCD, you can eliminate your divide to get rid of the implied decimal places. You can do a SHFR K8. This would be a cleaner way to handle the math, it would cut down on scan time; plus, it makes you look like a programming wiz :) If you do this, PLEASE document your code for the guy after you. Also, it wouldn't hurt for you to look up the instruction and figure out exactly how and why that works (and why the same trick won't work with binary data.)

Brian
 
Last edited:
An excellent analysis Brian - thank you. I'm a big fan of binary because of the lessened execution time of the math commands compared to BCD and of course the larger storage. If they didn't have timers and counters requiring BCD I wouldn't have them anywhere.
 
An excellent analysis Brian - thank you. I'm a big fan of binary because of the lessened execution time of the math commands compared to BCD and of course the larger storage. If they didn't have timers and counters requiring BCD I wouldn't have them anywhere.

Thanks Bernie, always nice to know I'm not in left field.

I had to chuckle at the increased execution speed comment, though. This is one case where he is avoiding using any DIVs at all, where the binary math would have to use two. He would have to have two BCD to BIN instruction later to be able to actually use the numbers. I haven't looked up the execution times for both methods; I wonder which would be faster in this case.

Brian
 
Ok, thanks for the info, I'm going to have to let that soak in a bit. I can really appreciate the added elgance and improved scan time. However, I'm also using the 100 word DirectSoft 5 demo, and I'm currently at 98 words with the whole program including my BCD math as shown above. It sounds like maybe I would save some by getting rid of the double word instructions, but then gain more back with extra conversions and math instructions??
 
If you want, you could post what you have now. Let us know what works and what doesn't. I know I wouldn't mind taking a look at your code and try to help optimize or fix it for you; I suspect that Bernie would give it a go as well.

Brian
 
hi Snaggletto,

having done aloooot of cut to length by using Sureservo systems (I have used 1Kw low, and medium inertia, 2 Kw medium inertia etc) one thing you might need to think of, usually in cut to length applications you have a roller shaft feeding the sheet under a shear and when the length is reahced you triger a cut bit. However, what happens if the operator press the stop button ? are you using incremental positioning or absolute ? after the operator presses stop will the length be lost and machine need to CUT (reset) before it feeds a new length?

I usually do cut to length systems by using a PC and communicate with Servo over Modbus to write to the registers...I do my calculation as follows:

(shaft Diameter x Pi) / 10000 = mm/pulse

also

1 / mm/pulse = pulses / mm

example:

if shaft diameter = 50 mm

mm/pulse = (50 x 3.1415) / 10000 = 0.0157075

above is the linear feed(length in mm) you for every pulse from your plc to servo drive.

pulses/mm = 1 / 0.0157075 = 63.67

now what you can do is just multiply the required length by pulses/mm (63.67) round the number and send to servo driver...

depending on the accuracy you want to achieve this tolerance of 0.016 mm / pulses shouldnt matter to most cut to length system (espoecially if they are not CNC (controlled by a Scada interface of a PC)

let me know if you need more help mate, I hope above informations will give you some ideas.

I almost forgot, keep in mind that you can easily do positioning by sending a pulse train to the drive from your DL05 (I think DL05 can output 5 Khz which is so slow to me :D ) if the speed doesnt matter then alright..however you can then use electronic gear to increase the speed... this will increase speed on the cost of accuracy...
 
Last edited:

Similar Topics

I'm working on a math-heavy project on CompactLogix L45 (Rev. 20) and am running into some issues with a calculation to determine the angle...
Replies
8
Views
3,924
Processor: Micrologix 1400 When doing subtraction using floating points (SUB F34:0 F94:10 F94:15 ) I am subtracting two values which have a...
Replies
10
Views
2,537
am using s7200 cpu222 my cpu support cosine,sin,tan function....but i neeed arcsin(sin-1) function how can i obtain it?????
Replies
4
Views
2,257
Hello everybody I'm new to plc programming and i'm trying to program some simple math operations to convert some measurments for a project. The...
Replies
8
Views
5,597
Does anybody know how the floating point math works in the ML 1200? I'm trying to divide 2 numbers, can i get a result accurate to 1 decimal...
Replies
3
Views
3,173
Back
Top Bottom