Sign in to follow this  
Followers 0
Lenfras

Scientific Notation

15 posts in this topic

Hi to everyone, I hope you can help me with this situation, I want to eliminate the exponent in a float number, I don't want the "e" as the result in a label, example: 0.0000002004145 instead 2.004145e-07, I don't know it is possible, thanks for your help

Share this post


Link to post
Share on other sites
You are going to have to give us more information. Label where? On What? Give us a detailed explanation of the problem.

Share this post


Link to post
Share on other sites
Ok, I send the value of F8:118 to a printer, this value is a leak rate of a test, every thing works good but production people don't want the "e-07", they want the complete number, I don't know how to do that. thanks for reply

Share this post


Link to post
Share on other sites
so from the 2.004145e-07 in F8:118 you would like the 2004145 in N7:118 and 000000 in N7:117 or so ahead of it.

Share this post


Link to post
Share on other sites
yes ahead of it, so the complete number in F8:118 instead scientific notation. Edited by Lenfras

Share this post


Link to post
Share on other sites
Sorry one last question. You mention F8 so I assume your PLC is a PLC 5 or SLC 500 series. Could you specify? What you'll most likely need to do is take the following: {note most likely means untested concept} 1. take the exponent from F8:118 A masked move of the exponent bits into an N7 register should give you this. 2. take the mantissa bits into an N7 register with a masked move and bit shift combination. 3. For Negative Exponents Send the ascii character for zero the number of times indicated by the exponent then the mantissa, 4. For positive exponents send the digits of the mantissa subtracting one from the exponent for each digit. If you reach zero send the decimal point. If not at zero at end mantissa then send zeros to reach zero. You'll be doing more string parsing and math. Others with a better understanding of PLC math may have a cleaner and clearer solution.

Share this post


Link to post
Share on other sites
This may not be quite as straightforward as you had hoped. How much do you know about the floating point format? I've never worked with PLC5 or ControlLogix, only MicroLogix and SLC among Allen Bradley hardware. They use the IEEE 754 single-precision floating point format. The conversion between floating point and decimal formats is not trivial, and is summarized here: 1) Convert the number, including the fractional portion, to binary. In the example given here (0.0000002004145), we get: 0.0000000000000000000000110101110011000110000101 2) "Normalize" this result by shifting the "decimal" point so that it is to the right of the most significant "1": 1.1010 1110 0110 0011 0000 101x2^-23 The red digits become the mantissa portion of the floating point number while the blue number is the exponent. Note that there is an odd number of bits for the mantissa and that the exponent is negative. The most significant "1" is understood to be present, and is therefore not included in the mantissa that is stored. 3) Add 127 to the exponent and convert it to binary. Adding 127 (called "excess 127") saves us from having to designate a sign for the power, allowing all 8 bits to be significant. exponent becomes -23 + 127 = 104 = 0110 1000 4) If the original number is negative, the first bit of the floating point number will be a 1, otherwise it's a 0. The final layout is: S EEEE EEEE MMMM MMMM MMMM MMMM MMMM MMM So, for your number, decimal 0.0000002004145, we get this bit pattern: 0 0110 1000 1010 1110 0110 0011 0000 101 Now, in a SLC, it is possible to work with this, but, as mentioned before, it won't be trivial. I just did a little testing in a SLC 5/04 on the bench. A COP instruction will get the 32 bits into 2 integer elements: COP #F8:0 #N7:1 2 In this example, the most significant 16 bits will be in the first element (N7:1) while the least significant bits will be in N7:2. If you know you will always have positive numbers, you can ignore the most significant bit (N7:1/15). The next 8 bits are the exponent portion while the remaining bits form the normalized mantissa. I found a pretty good converter app here: http://www.h-schmidt.net/FloatApplet/IEEE754.html It is not difficult to extract the exponent portion, using a MVM instruction on the most significant integer element: MVM N7:1 7F80h N7:10 The address N7:10 now contains the exponent, but it needs to be shifted to the right 7 places. This can be done using BSR instructions, or, more simply, using a DIV instruction: DIV N7:10 128 N7:11 To get the actual exponent, we need to subtract 127: SUB N7:11 127 N7:12 At this point, these are the values in memory: F8:0 = 2.004145E-007 N7:1 = 0011 0100 0101 0111b = 13399d (most significant 16 bits) N7:2 = 0011 0001 1000 0101b = 12677d (least significant 16 bits) N7:10 = 0011 0100 0000 0000b = 13312d (result of MVM, the exponent portion) N7:11 = 0000 0000 0110 1000b = 104d (actual binary exponent in excess-127 format) N7:12 = -23d (actual binary exponent after normalizing the original decimal number) We now have the binary exponent. Unfortunately, the mantissa uses 23 bits, which is too much information for a single 16-bit integer element. Depending on how we handled the data, we could use AT MOST only the most significant 16 bits of the mantissa, but we would lose precision without it necessarily being apparent. If we change the least significant 7 bits of the mantissa to 0, the original number becomes 2.0041443E-7. If this is accurate enough, we can proceed, using only one integer element for the mantissa: We need bits 6 thru 0 of N7:1 and bits 15 thru 7 of N7:2 combined into a single element. Here goes: MVM N7:1 007Fh N7:13 We'll want to shift this to the left 9 places so they are the most significant bits of our final element. If we just multiply by 2^9, we will cause overflow, so multiply by 2^8 and use a BSL: MUL N7:13 256 N7:14 OTU R6:0/EN BSL #N7:14 R6:0 B3:0/0 1 Now, we need to extract the next 9 bits of the original mantissa, which are bits 15 thru 7 of N7:2: MVM N7:2 FE80h N7:15 This needs to be shifted to the right 7 places, so divide by 2^7: DIV N7:15 128 N7:16 Gather the appropriate portions of N7;14 and N7:16 into our final mantissa: MVM N7:14 FF80h N7:17 MVM N7:16 007Fh N7:17 N7:17 now contains the most significant 16 bits from the mantissa of the original floating point number. Keep in mind, that this integer CANNOT be used "raw!" It must be interpreted using the IEEE standard and the exponent above. Remember that there is another "1" in front of these 16 bits AND that, if the first bit is a 1, the integer file will show a negative number that is NOT the same magnitude as its positive counterpart. SLCs store integers in 2's complement format, which uses the most significant bit as a sign bit. 2's complement is a bit involved to discuss here, but it's explained in Appendix F of Publication 1747-RM001E-EN-P. As a quick experiment, store "400" in an integer element using the datafile or a CDM. Change the radix to binary and set the sign bit. Change back to decimal, and it is -32368. To make the final data simpler to handle, we can drop 2 bits, using only the 14 most significant bits of the mantissa. We will lose more precision, with our original number now 2.0040898E-7 If this is OK, modify the above code thus: MVM N7:1 007Fh N7:13 MUL N7:13 128 N7:14 MVM N7:2 FE00h N7:15 DIV N7:15 512 N7:16 MVM N7:14 FF80h N7:17 MVM N7:16 007Fh N7:17 OTE N7:17/14 The last line of code sets bit 14. Recall that there is a one preceeding the "decimal" point that's implied in the IEEE format. The bit pattern in N7:17 is now the most significant 14 bits of the mantissa with the bit before the "decimal" point set. The sign bit is still not evaluated here. I'm not sure how useful all of this is, though (not at all, yet). Now, we have a 15-bit mantissa that we may or may not be able to do anything with. Because of the complexity of the IEEE conversion, going back and forth between binary and decimal, I don't know that we can accomplish what you're asking easily. The exponent portion of the floating point number is the binary exponent, not the "-007" in our example, and there doesn't seem to be a simple way to extract it. If you know where the decimal point will always be, in other words, if the number will always be x.xxE-7, you can simply: MUL F8:0 10000000 F8:2 ...and then do the string parsing from there. BTW, the code here is a bit longer and uses more memory locations than really necessary, but I think it's clearer. Bottom line: it may be "easier" to display the information on an HMI, maybe have the HMI do the printing. Is that an option? Sorry for the disjointed post. I've run out of time for now, so I'll have to revisit this later. Or, someone else with better ideas may post. I've never really tried this, so it's been a learning experience for me, too!

Share this post


Link to post
Share on other sites
I thought of something on the way home. We have the 16 most significant bits of the mantissa stored in N7:17. We can convert that to a decimal value like this: MOV 1 F8:5 XIC N7:17/15 ADD F8:5 0.5 F8:5 XIC N7:17/14 ADD F8:5 0.25 F8:5 XIC N7:17/13 ADD F8:5 0.125 F8:5 XIC N7:17/12 ADD F8:5 0.0625 F8:5 XIC N7:17/11 ADD F8:5 0.03125 F8:5 . . and so on until XIC N7:17/0 ADD F8:5 1.5259E-5 F8:5 Each bit in N7:17 represents a decreasing power of 2: /15 = 2^-1 /14 = 2^-2 /13 = 2^-3 . . . /0 = 2^-16 I'll test this tonight, but we should now have the mantissa in decimal format stored in F8:5=2.004145. We still have to deal with the exponent, however. I didn't think of it before, even though it's what Bob probably meant, but can we convert the floating point number directly to a string? I see, but have never used, the AIC instruction, but it appears only to apply to integers. If there's a way to do that, this exercise just got easier. *******EDITED TO ADD******* OK, I finally got to test this and it does NOT give the correct number. I've managed to extract the floating point to a string, but it's pretty cumbersome. I'll post a new reply with what I came up with. Edited by Joe E.

Share this post


Link to post
Share on other sites
Hi Lenfras, you should tell first what plc you have there since they have different instruction sets for example. also it is not clear what is the range this value will ever have. this may have dramatic impact on complexity of solution. it is much simpler to come up with something that has fixed range, for example 0.00000001...0.00001000. then we can fake the first few digits ("0.0000") since they never change and only focus on what is left. Next question is what format you can use. Did you try to print ascii or integers etc (just a dummy)? Regards, Panic

Share this post


Link to post
Share on other sites
We are using a SLC 5/04, an the "0.0000" is not the same each cycle, it moves contastly, I'm not a pro working with AB so it looks dificult for me but I will tray your advices. Thanks for your sopport

Share this post


Link to post
Share on other sites
How are you getting this value in an SLC-5/04 ? There is no "Floating Point to String" function in the SLC, is there ?

Share this post


Link to post
Share on other sites
I have run into similar problems with historians, the problem was not what the SLC was sending, it was how the historian was handling the information. I would guess you need to change the formatting in the printer. I would guess the printer program is set up to display 7 significant digits. If you change that to 11 or 12 or 13, the problem will go away.

Share this post


Link to post
Share on other sites
We haven't heard back from Lenfras yet, so we don't know if he still needs help. Ken Moore's solution is probably the neatest, if it's possible in this case, but this kept nagging at me. I wrote a program (attached) for the SLC 5/04 that converts the floating point value to a string, since there doesn't appear to be an instruction that does it directly. It's actually pretty simple and doesn't involve decoding the floating point format (which is a good thing ). There are some calculations which introduce a slight rounding error, and it sometimes chokes when the input value is near the fringes of valid values for a floating point. It seems to work OK, but, as always, YMMV, test thoroughly before relying on the results, etc. FLOATING_POINT_to_STRING.RSS

Share this post


Link to post
Share on other sites
Hey guys! thanks to everyone for your time and help, the solution for this application was very easy but clever for me, Ken Moore was right, I only gave more characters(spaces) to the printer lay out and it works good, I'll keep the attachment that Joe E posted to review later, and again. thank you for your time.

Share this post


Link to post
Share on other sites
Thanks for following up with the solution, maybe useful to someone else in the future. Glad it worked, glad to help, anytime.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0