View Full Version : Basic Math Help
CoasterFuelPhil
14-02-2007, 10:20
Hi, this is my first post on Chief Delphi. my name is Phil Nguyen and I am on the team 1930, Delta Force.
I am having trouble with multiplying numbers and stuff. the numbers cannot be an int because we need it very precise.
current_height=29.401*(pow((0.0049*((double)Get_An alog_Value(rc_ana_in01)) - 0.0044),-1.0895));
It doesn't work, not even somthing like:
current_height = ((30)*Get_Analog_Value(rc_ana_in01));
I am getting a number like 18 thousand when the analog info is something like 200
We've tried using current height as a double and a float, same thing.
Tom Bottiglieri
14-02-2007, 10:27
I am having trouble with multiplying numbers and stuff. the numbers cannot be an int because we need it very precise.
How precise do you need this number?
If you need it in thousandths, just multiply everything by 1000 first, then deal with the decimal shift later. That way you can use only integer math and keep your precision. Remember, you only get a byte of resolution to drive your motors..
My first thought would be to try something like this.
current_height = Get_Analog_Value(rc_ana_in01);
current_height *= .0049;
current_height -= .0044;
current_height = pow(current_height, -1.0895);
current_height *= 29.401;
Working with floats can be very confusing, since the default casting is (int). I always like to try it like this, until I'm sure my logic is correct. In fact, this may even result in less assembly instructions, although I'm not sure at all.
what type is current_height?
18 thousand could be correct, maybe the analog input value is higher than what you think it is.
Try printing the analog value and the value*30, and compare them.
Also, I strongly recommend not using floats, they are very slow and memory intensive.
CoasterFuelPhil
14-02-2007, 11:06
we're using an infared sensor to detect height, I'd like the height to be close to thousanths. yeah, I did do a printf and thats where I got the number 200 from.
Mark McLeod
14-02-2007, 11:22
Assuming current_height is defined as a float, how are you printing the value?
This printf does not support printing of floats, so are you converting it back to an (int) to print?
By the way, floats, including doubles, on this PIC actually have less accuracy than a long.
CoasterFuelPhil
14-02-2007, 12:18
printf("current_height: %u\r", current_height );
thats probably the problem
Yes, printf does not support floats
Try this: printf("current_height: %u\r", (unsigned int) current_height );
I would strongly suggest not using floats, though.
buddy.smith
14-02-2007, 13:39
Okay, let's look at this another way.
Your analog sensor gives you a value of 0-255
Your motor takes a value of 0-255
So, why are you using a float?
At the worst case, you could use a look up table.
You have your complicated formula you want to use. Use your formula to make an array. Then, you just need:
myvalue = LookUpTable[GetAnalogValue(....)];
Make sense?
Or, you can forget about inches, and deal with everything in the domain of 0-255, whatever units they happen to be :)
Actually, analog inputs on the RC are 0-1023 (OI is 0-255) unless you use a different ADC. Also, they are not trying to controll a motor, they want to calculate the height of something (arm?)
buddy.smith
15-02-2007, 11:05
Actually, analog inputs on the RC are 0-1023 (OI is 0-255) unless you use a different ADC. Also, they are not trying to controll a motor, they want to calculate the height of something (arm?)
I stand corrected.
Still, he does not need floating point for this.
(to the OP): Have you ever heard of "fixed point" math? Someone touched on it earlier - if you need .001 precision, then multiply everything by 1000. Keep in mind that at .001 precision, you can measure just one inch with your A/D....
ttyl,
--buddy
Cheezmeister
15-02-2007, 15:18
I stand corrected.
Still, he does not need floating point for this.
(to the OP): Have you ever heard of "fixed point" math? Someone touched on it earlier - if you need .001 precision, then multiply everything by 1000. Keep in mind that at .001 precision, you can measure just one inch with your A/D....
ttyl,
--buddy
Well, floating point is the most direct solution to the precision needed for complex formula. The values he starts with and the values he'll wind up with ought to be ints, but that doesn't mean that everything in the formula can necessarily be rounded.
I mean,
current_height=29.401*(pow((0.0049*((double)Get_An alog_Value(rc_ana_in01)) - 0.0044),-1.0895));
Shouldn't be turned into
current_height=30*(pow((0*((double)Get_Analog_Valu e(rc_ana_in01)) - 0),-1));
You'd always get a divide by zero =P!
However you might be right in that floats/doubles aren't the tools for the job...I can't say; I'm not up on PIC architecture:D
paulcd2000
15-02-2007, 17:41
I would strongly suggest not using floats, though.
I've never used floats, we always use doubles. They get printed with %dl, and they operate very similarly to floats
Shinigami2057
16-02-2007, 00:31
Doubles are even more memory-intensive than floats on the PIC18F (well, on any architecture, but especially so on the PIC). Using them probably is a bad idea, I doubt you'd ever need that precision for FIRST. Also, double use the %lf token, for "long float." I don't think %dl has the meaning you think it does.
Salik Syed
16-02-2007, 02:57
There is no reason to use floating point numbers,
Why not do this:
current_height=
(294010* pow( (49*(Get_Analog_Value(rc_ana_in01)) - 44),-10895) ) ) / 10000 );
You will need to use a unsigned int for the first param of the pow function
to keep it from overflowing
jdejoannis
16-02-2007, 14:33
There is no reason to use floating point numbers,
Why not do this:
current_height=
(294010* pow( (49*(Get_Analog_Value(rc_ana_in01)) - 44),-10895) ) ) / 10000 );
You will need to use a unsigned int for the first param of the pow function
to keep it from overflowing
No, that only works for linear functions. For example:
y = 1.5x = (15x)/10
but not
y = x^2 != x^(20)/10
Hmm, one way around this is to take the log of both sides:
log y = 2 log x = (20 log x) / 10
or y = 10^((20 log x) / 10)
Be nice to your CPU and give it lookup table and don't be a precision junkie ;)
Jason
Salik Syed
17-02-2007, 17:56
Oh yeah... wow. haha ... i totally didn't take into account that POW might be non-linear. That was dumb.
Shinigami2057
17-02-2007, 18:54
Oh yeah... wow. haha ... i totally didn't take into account that POW might be non-linear. That was dumb.
Also, for future reference, the pow function takes a double, it does not avoid floating-point arithmetic.
From the pow(3) man page:
double pow(double x, double y);
float powf(float x, float y);
long double powl(long double x, long double y);
Salik Syed
17-02-2007, 21:51
Oh okay.... I thought POW was just some function they made up
jdejoannis
19-02-2007, 13:46
Also, for future reference, the pow function takes a double, it does not avoid floating-point arithmetic.
From the pow(3) man page:
double pow(double x, double y);
float powf(float x, float y);
long double powl(long double x, long double y);
Actually the MPLAB C18 Libraries Documentation (http://www.microchip.com/Microchip.WWW.SecureSoftwareList/secsoftwaredownload.aspx?device=en010014&lang=en&ReturnURL=http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en010014&redirects=c18#) defines the standard math functions, eg. sin,tan,pow in single precision.
psquared89
21-02-2007, 14:24
I'd suggest avoiding floats like the plague on these controllers; the floating point precision just is NOT there.
JimGRobot
23-02-2007, 21:30
Your question has prompted a number of different replies, and touches a wide range of topics... Of couse, I will toss in my 2 cents.
The floating point math should be working, so my first question is, "How do you know what the resulting value really is?" I ask this because the [C18] printf function is very lame about displaying floating numbers. I usually scale the number I am interested in, and cast it to an "int" in the printf function call.
In C18 a float and double are both implemented using IEEE-754 floating point standard; they are the same.
One thing to remember about floating point isn't its accuracy, but its wide dynamic range that make it handy...
The chip used in the RC has a built-in 8x8 multiply unit, which makes all math operations faster. It turns out that scaling to long data types, and multiplying and dividing with integers can actually take longer to execute than a simple, single floating point calculation.
I urge everyone to do a little test. At the start of your main code set an RC digital output high, then after it is finished clear the bit. Put an oscillscope on the output pin and see how long your code is really taking to execute. We have some fairly heavy-weight objects in our code, and it takes about one millisecond to execute. I don't think that anyone will run out of computing power for the FIRST application.
Regarding your specific problem, I would recommend unbundling the one huge equation into several smaller ones using intermediate variables along the way. This way you can use [scaled int] printf's on the values to see how the calculation progresses.
I hope this helps,
Jim
vBulletin® v3.6.4, Copyright ©2000-2017, Jelsoft Enterprises Ltd.