Pages: [1] 2   Go Down
Author Topic: Equation giving different results  (Read 424 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi there, I am using an Arduino Uno and a Motor Shield to control a DC motor with an encoder. To calculate the RPM's of the motor I use:

RPM_A = (60*(newpositionA - oldpositionA) * 1000) /((newtimeA-oldtimeA)*16*2);

This equation works perfectly fine when going in the positive direction, once I start going in the negative direction it says its rotating at ridiculously high positive speeds. So I broke the equation into:
part1 = 60*(newpositionA - oldpositionA) * 1000;
part2 = (newtimeA-oldtimeA)*16*2;
part3 = part1/part2;

Where part 3 should equal RPM_A, strangely I receive the proper result, I do not understand what is different between the two approaches, mathematically they are the same but through arduino it is different. newposition and oldposition are variable long, newtimeA & oldtimeA are unsigned long, and RPM_A, part1,part2,part3 are double.
Logged

Cincinnati, OH
Online Online
God Member
*****
Karma: 50
Posts: 919
I'm not bossy...I just know what you should be doing.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

In your equation:

Code:
RPM_A = (60*(newpositionA - oldpositionA) * 1000) /((newtimeA-oldtimeA)*16*2);

how is RMP_A defined? If newpositionA - oldpositionA is as small as 1, the numerator for the expression will overflow an int. I'm pretty sure the variable needs to be a long. I'm only guessing since you didn't post your code.

edit:

I see now that you have it as a long. If RPM_A is a double, which is not supported by the Arduino IDE, change it to a float. Also, by default, the compiler will treat numeric constants as int. Try:

Code:
RPM_A =(float) (60.0 * (newpositionA - oldpositionA) * 1000.0) /((newtimeA-oldtimeA)*32.0);

and see what happens.
« Last Edit: July 15, 2014, 08:28:34 am by econjack » Logged

Offline Offline
Edison Member
*
Karma: 45
Posts: 1611
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You can do all kind of in-between-calculations. The compiler will make the same code.

Code:
// multiply by 60 because ... ?
// multiply by 1000 because ... ?
long t1 = 60L * 1000L *(newpositionA - oldpositionA);
// multiply by 16 because ... ?
// multiply by 2 because ... ?
long t2 =16L * 2L * (newtimeA-oldtimeA);
// Calculate the rpm
RPM_A = (float) t1 / (float) t2;
Logged

Doctor, I see Arduino boards everywhere, what can I do ? - Well, I suggest you connect them with I2C.

Fort Lauderdale, FL
Offline Offline
Faraday Member
**
Karma: 71
Posts: 6144
Baldengineer
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I do not understand what is different between the two approaches, mathematically they are the same but through arduino it is different.
Not different in the Arduino, but different to the compiler.  When different variable types are mixed, the compiler sometimes make a bad guess on how to handle the overall calculation.  Keep in mind that numbers like "60" are constants and usually, the compiler will treat them as an integer (int).  So you're mixing ints, longs, and floats (double doesn't exist in AVR).

As already suggested:
1.  Keep the intermediate steps.  They'll likely get optimized out.  Personally this is my method because it allows me to visually see the variable types and their expected results when I scan through the code.

2.  Convert your integers into floats, so they get treated as floats (or as long).  The simplest way is adding the decimal.
Logged

Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.c

Offline Offline
Edison Member
*
Karma: 50
Posts: 1705
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
the compiler sometimes make a bad guess on how to handle the overall calculation.

The compiler doesn't guess.

Pete
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 15
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the feedback,

I didn't realize double wasn't part of the Arduino IDE, I changed it to float and added decimal places to the numbers and it works.
Logged

Offline Offline
Edison Member
*
Karma: 33
Posts: 1483
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It is not that double is not a part of the IDE, it is just that floats and doubles are the same size.
Logged

Offline Offline
Edison Member
*
Karma: 45
Posts: 1611
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
the compiler sometimes make a bad guess on how to handle the overall calculation.

The compiler doesn't guess.

Pete

Pete, that was the funniest reply I read in a while.
I guess the compiler doesn't have to guess, because it "feels" what to do  smiley-grin
Logged

Doctor, I see Arduino boards everywhere, what can I do ? - Well, I suggest you connect them with I2C.

UK
Offline Offline
Tesla Member
***
Karma: 141
Posts: 8033
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
the compiler sometimes make a bad guess on how to handle the overall calculation.

The compiler doesn't guess.

Pete


Perhaps it was the guys who wrote it that did the guessing.

...R
Logged

Offline Offline
Edison Member
*
Karma: 50
Posts: 1705
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The language specification defines how a compiler must handle things like precedence of operators (e.g. a*b + c) and mixed mode operations (e.g. the result of an int * float) and all the other aspects of the language.
There would hardly be any point trying to write a program if the first time you compiled the statement "a = b/5;" the compiler guessed that the 5 was an integer and the next time it guessed that it was a float.

Pete
Logged

UK
Offline Offline
Tesla Member
***
Karma: 141
Posts: 8033
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

guessed that the 5 was an integer and the next time it guessed that it was a float.

Pete, you are taking us too literally.

Of course the copiler doesn't guess. But if the people writing code (me for example) don't know the precise compiler rules we may "guess" wrong about what the compiler will do. The end result is pretty much the same as if the compiler was doing the guessing because we know what we wanted to happen (we would have got the correct answer with a calculator) - but it doesn't happen.

...R
Logged

Offline Offline
Edison Member
*
Karma: 50
Posts: 1705
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The problem is that a newbie might interpret "the compiler guessed wrong" literally. I would have had no problem if the statement had been "the programmer guessed wrong".

Pete
Logged

Fort Lauderdale, FL
Offline Offline
Faraday Member
**
Karma: 71
Posts: 6144
Baldengineer
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I think we've visited this pedantic rat-hole for long enough.
Logged

Capacitor Expert By Day, Enginerd by night.  ||  Personal Blog: www.baldengineer.com  || Electronics Tutorials for Beginners:  www.addohms.c

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 99
Posts: 4837
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You can use casting to do the integer calculation in 32 bit and safely put the result into 16 bit.
This avoids the occasional .999999 is 1 floating point funnies and run a magnitude or two faster than float on AVR.

Code:
int RPM_A;

..........

RPM_A = (int) ( 60L * ((long) newpositionA - (long ) oldpositionA ) * 1000L ) / (((long) newtimeA - (long) oldtimeA ) * 16L * 2L );
Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Offline Offline
Edison Member
*
Karma: 50
Posts: 1705
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@James C4S: Rather than acknowledge that your statement was wrong and move on, your first response on the issue is an ad hominem attack. Classy.

Pete
Logged

Pages: [1] 2   Go Up
Jump to: