-1

I have to perform a calculation with 2 floating point numbers using measurements taken from a distance sensor with STM32. Calculation is carried out by following equation;

result = (df-ds)/ds*10000;

where df is first measurement and ds is second measurement.

Sample values for equation;

df = 26.6810; ds = 25.3270;

My problem is, STM32's result for these values is 534.578247, but when i do calculation on Windows' calculator manually i get the result of 534.607336 which is quite different from STM32's calculation. I've also used one hand-calculator and hand-calculator is giving out exactly same result with the computer.

All variables are declared as floats in the program. Why is there so much difference between two calculations? What kind of changes i could make to make STM32 give more precise results?

Thanks in advance for any help.

EDIT : The code i am using as follows;

 float result= 0;
 dmbres = 27.4587;
   int main()
   {
   while(1)
   {
   result= (float)((dmbres- res)/res)*10000;
   dmbres = res;
   sprintf(datapackage, "%d;%.4f;%.6f\r\n", mid, res,result);
   monitor(datapackage);
   }

datapackage consists 2 other information i need from MCU and they are not relevant with the result calculation.

I am using STM32F407 DISC-1 board.

Teo Laferla
  • 41
  • 1
  • 7
  • What's the C code? I think we can't understand the problem without seeing the code that generates your issue. – Sir Jo Black May 03 '19 at 10:57
  • 1
    `26.6810` is not a float, it's a double. Which STM32 is this, does it have a FPU? Overall, there's way too little information to answer the question. Post the actual code. – Lundin May 03 '19 at 11:02
  • `df` and `ds` are too close in magnitude for the subtraction to have an effect on the 4th significant figure. The issue is in code you haven't pasted up. – Bathsheba May 03 '19 at 11:11
  • I added the code. Thank you for your attention – Teo Laferla May 03 '19 at 11:24
  • With the precision of the numbers you have posted, the result could be anywhere between 534.566797 and 534.647875, so your actual result looks fine to me. – Ian Abbott May 03 '19 at 11:39
  • @IanAbbott But how could the computer and hand-calculator gives out exactly same results but not STM32? – Teo Laferla May 03 '19 at 11:43
  • @TeoLaferla I am assuming that `df` could be anywhere in the range (26.68095, 26.68105) and that `ds` could be anywhere in the range (25.32695, 25.32705) since your `sprintf` rounds their displayed value to 4 decimal places. – Ian Abbott May 03 '19 at 11:46
  • I read the FPU manual of your MCU, but I've no time to indagate. Have you enabled "correctly" the FPU? https://www.element14.com/community/servlet/JiveServlet/downloadBody/55689-102-1-276747/STMicroelectronics.User_Manual_2.pdf – Sir Jo Black May 03 '19 at 11:52
  • @SirJoBlack I checked several similar threads on here, they all say FPU is initialized by declaring a variable `float`. So i didn't do anything about that and honestly i don't know how. – Teo Laferla May 03 '19 at 12:12
  • @TeoLaferla, Have you tried with a `double`. However I think the C compiler (or better the MCU libraries) should take in account FPU initializations. – Sir Jo Black May 03 '19 at 12:22
  • I suggest you to take a look at the manual I indicate you above at page 240. There's some interesting C code. – Sir Jo Black May 03 '19 at 12:30
  • @SirJoBlack Yes i did try `double` and can't say results between computer calculation and MCU calculation came closer. – Teo Laferla May 03 '19 at 12:31
  • The FPU is single precision 32 bit, then `float`. – Sir Jo Black May 03 '19 at 12:38
  • How does the 27.4587 in your code sample relate to 26.6810 or 25.3270. – Dipstick May 03 '19 at 13:23

2 Answers2

2

You have the following code:

 float result= 0;
 dmbres = 27.4587;
   int main()
   {
   while(1)
   {
   result= (float)((dmbres- res)/res)*10000;
   dmbres = res;
   sprintf(datapackage, "%d;%.4f;%.6f\r\n", mid, res,result);
   monitor(datapackage);
   }

And you gave the following equation:

result = (df-ds)/ds*10000;

with the values:

df = 26.6810; ds = 25.3270;

And you reported the following result:

result = 534.578247

I assume the following:

  1. The value shown for df (26.6810) came from the conversion of the variable res to a string by:

    sprintf(datapackage, "%d;%.4f;%.6f\r\n", mid, res,result);
    

    Since this output string is being rounded to 4 decimal places, the float res value it came from could have been any value in the range 26.680950164794921875 to 26.6810474395751953125. This forms the dmbres value for the next iteration of the loop.

  2. The value shown for ds (25.3270) came from the conversion of the variable res to a string in the next iteration of the loop. Since this output string is also being rounded to 4 decimal places, the float res value it came from could have been any value in the range 25.3269500732421875 to 25.3270473480224609375).

  3. The value shown for result (534.578247) came from the conversion of the variable result to a string by

    sprintf(datapackage, "%d;%.4f;%.6f\r\n", mid, res,result);
    

    This output string is very precise for a float. The closest stored value is 534.5782470703125.

For the possible values of df and ds, the smallest possible value for result = (df-ds)/ds*10000 is given by (26.680950164794921875 - 25.3270473480224609375) / 25.3270473480224609375 * 10000, and the largest possible value is given by (26.6810474395751953125 - 25.3269500732421875) / 25.3269500732421875 * 10000.

The closest float values resulting from those two expressions are 534.5679931640625 and 534.6468505859375, respectively. Your actual result of 534.5782470703125 falls within this range, so is not unexpected.

Ian Abbott
  • 15,083
  • 19
  • 33
0

As others have mentioned, the numbers are "too close". 32-bit float uses 23 bits for the significant so it is only about 7 significant decimal digits. e.g. 1234567. You can place the decimal point anywhere but any digits beyond the 7 is imprecise, especially once you perform calculations with them. 64-bit double uses 52 bits and holds about 16 decimal digits.

So you can declare the variables as double. That would give you a greater range of precision, at a cost of (much) slower execution.