|
|
View previous topic :: View next topic |
Author |
Message |
janet
Joined: 17 Feb 2004 Posts: 23
|
sin() and cos() consume too much of resource |
Posted: Tue Mar 16, 2004 12:45 am |
|
|
sin() and cos() in math.h consume too much of resources.
these function return 32-bit float type. Do we have another alternative to get sin()/cos() value? precision is not of my priority. I am looking for some alternatives which can return 16-bit or 8-bit data-type.
The final result i want to get is an integer by the formula
result = (sin(x) * 40) + 40;
so it will not have negative value and decimal point.
Thanks. |
|
|
vaneenbergen Guest
|
|
Posted: Tue Mar 16, 2004 2:40 am |
|
|
why not use a rom table on desgin time not runtime. also very quick
#rom SINE_WAVE =
{
0x????, 0x???, etc
};
create this file using matlab or a custom VB/VC program. |
|
|
janet
Joined: 17 Feb 2004 Posts: 23
|
|
Posted: Tue Mar 16, 2004 2:56 am |
|
|
Thanks! |
|
|
Ttelmah Guest
|
|
Posted: Tue Mar 16, 2004 3:14 am |
|
|
Worth perhaps adding, that you can also do things like have a fairly 'small' lookup table, and linear interpolate between the values on this. Though it does not give fabulous accuracy, it is good enough for a lot of used. For instance I did a decoder some time ago, for a digital compass. The resulting 'number', was to be an angle (nominally) as an integer in 1/10th degree steps. The real accuracy was significantly worse than this, because of errors in the chip, and measurement, so I did the conversion using a single table in 1 degree steps, covering 90 degrees, then interpolated to get the extra digit.
The total size for table and interpolation, was only a few hundred bytes of code, and it was also fast.
Best Wishes |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Tue Mar 16, 2004 4:32 am |
|
|
Then there is always the cordic....this little algorithm can be extended to any precision and uses nothing more than shift and add instructions.
It gives sine cosine arctan and the sqrt(of x^2 Y^2) just perfect for that space probe or toy robot.
Sine and cosine are derived in separate calls in this example but it is the same routine so they both can be derived in the same call. It is based on on binary angles
with the tan of 45 deg =1 26.56=0.1 binary( 1/2) etc.
Code: |
main()
{
signed int16 result;
result= cos(6000);
printf("cosine of 60 is %ld \n\r",result);
result= sin(6000);
printf("sine of 60 is %ld \n\r",result);
result= arctan(10000,6000);
printf("arctan of 0.60 is %ld \n\r",result);
result=sqrt_x2_y2(10000,6000);
printf("sqrt of (6^2+10^2)/0.6073 is %ld \n\r",result);
while(true);
}
//////////// cordic ///////////////////////////////////
////////////////////////////////////////////////////////////////
/// theory /////
/// /////
/// coords (x,y) are rotated thru angle a to (x',y') /////
/// /////
/// x'=x.cos(a)-y.sin(a) /////
/// y'=y.cos(a)+x.sin(a) /////
/// /////
/// x'/cos(a)=x-y.tan(a) /////
/// y'/cos(a)=y+x.tan(a) /////
/// /////
/// now if we choose tan(a) to be /////
/// 1/2,1/4,1/8......1/2*n /////
/// /////
/// we can rotate thru sucessive values /////
/// ex 30.00 degs = 45-26.57+14.03-7.13+3.58 ////
/// +17.9,.90,.45 ////
/// where a minus angle is a counter rotation ////
/// after a rotation of 30 degs ////
/// x' is x.cos(30) if we start with y=0 ////
/// y' is x.sin(30) ////
/// ////
/// angle is in 1/100th units 4500 is 45 degrees ////
/// lengths are in aggregate constant units ////
/// ////
/// aggregate const cos(atan(1)*cos(atan(1/2)*cos(atan(1/4).....)))))
/// or .607252935 ////
/// so 10000 is 6073
long int const atan[13]={4500,2656,1404,712,358,179,90,45,
22,12,6,3,1};/// atan(1/2n)
////
////
//// to clac sin(A) cos(A) set y=0 a=angle and drive a to zero
//// via iterations
//// x value is the cos(a) providing x=6073
//// y value is the sign(a) providing x=6073
////
//// to calc atan(a) set a=0 and drive y to zero
//// a value is atan(y/x)
//// x value is sqrt(x^2+y^2) providing x=6073
signed long int cos(signed long a)
{
int i;
signed long x,y,dx,dy,da;;
x=6073;
y=0;
for (i=0;i<13;i++)
{
if (X>=0) {dx=X >>i;} else { dx=-X >> i;dx=-dx;}
if (Y>=0) {dy=Y >>i;} else { dy=-Y >> i;dy=-dy;}
da=atan[i];
if (a>=0)
{
a=a-da;
x=x-dy;
y=y+dx;
}
else {
a=a+da;
x=x+dy;
y=y-dx;
}
}
return (x);
}
signed long int sin(signed long a)
{
int i;
signed long x,y,dx,dy,da;;
x=6073;
y=0;
for (i=0;i<13;i++)
{
if (X>=0) {dx=X >>i;} else { dx=-X >> i;dx=-dx;}
if (Y>=0) {dy=Y >>i;} else { dy=-Y >> i;dy=-dy;}
da=atan[i];
if (a>=0)
{
a=a-da;
x=x-dy;
y=y+dx;
}
else {
a=a+da;
x=x+dy;
y=y-dx;
}
}
return (y);
}
signed long int arctan(signed long x,signed long y)
{
int i;
signed long a,dx,dy,da;;
a=0;
for (i=0;i<13;i++)
{
if (X>=0) {dx=X >>i;} else { dx=-X >> i;dx=-dx;}
if (Y>=0) {dy=Y >>i;} else { dy=-Y >> i;dy=-dy;}
da=atan[i];
if (y<0)
{
a=a-da;
x=x-dy;
y=y+dx;
}
else {
a=a+da;
x=x+dy;
y=y-dx;
}
}
return (a);
}
signed long int sqrt_x2_y2(signed long x,signed long y)
{
int i;
signed long a,dx,dy,da;;
a=0;
for (i=0;i<13;i++)
{
if (X>=0) {dx=X >>i;} else { dx=-X >> i;dx=-dx;}
if (Y>=0) {dy=Y >>i;} else { dy=-Y >> i;dy=-dy;}
da=atan[i];
if (y<0)
{
a=a-da;
x=x-dy;
y=y+dx;
}
else {
a=a+da;
x=x+dy;
y=y-dx;
}
}
return (x);
}
|
Last edited by Douglas Kennedy on Wed Aug 10, 2005 5:55 am; edited 1 time in total |
|
|
janet
Joined: 17 Feb 2004 Posts: 23
|
|
Posted: Tue Mar 16, 2004 10:09 am |
|
|
Hi, i have tested the routine u gave me ^_^
Code: | signed int16 result;
signed int16 x = 0;
while(1) {
printf("sine %ld = %ld \r\n", x, sin(x));
x= x +400;
getc();
} |
sine 0 = 2
sine 400 = 698
sine 800 = 1398
sine 1200 = 2086
sine 1600 = 2760
sine 2000 = 3423
sine 2400 = 4062
sine 2800 = 4693
sine 3200 = 5292
sine 3600 = 5872
sine 4000 = 6429
sine 4400 = 6945
sine 4800 = 7434
sine 5200 = 7881
sine 5600 = 8292
sine 6000 = 8663
sine 6400 = 8988
sine 6800 = 9274
sine 7200 = 9514
sine 7600 = 9704
sine 8000 = 9846
sine 8400 = 9945
sine 8800 = 9994
sine 9200 = 9993
sine 9600 = 9947
sine 10000 = 9857
sine 10400 = 9857
sine 10800 = 9857
sine 11200 = 9857
the result shows:
1. the parameter is in 1/100th unit
2. the result is int 1/10000th unit
3. the result become constant 9857 after 10000 (??)
4. how bout the negative result?
How to use this function properly? Thanks. |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Tue Mar 16, 2004 8:42 pm |
|
|
Janet
the routine rotates thru binary angles it is valid in the 0... 90 deg quadrant
so the integer range is 0 to 9000 in 1/100th of a degree increments.
There is always a small precision error so it will not get sin(0) correct
but you all ready know it is zero and sin(90) willl also have a small error.
but you know the result is 1. You'll have to do some adjustments to go to the next quadrant ex sin 100 deg is sin(180-100)
This is 16 bit arithmetic so 4 and a half significant digits is the best possible in decimal
The iteration table is 13 entries 2^13 binary or 3 and a half significant digits. In otherwords this particular example will give the sin cos arctan and sqrt(x^2+y^2) to 3 decimal places( 1 in a 1000 error)
The routine keeps things simple no use of radians ...angles are in int16
0 to 9000 where 9000 is 90.00 degrees no complexity just shifts and adds.
Again this uses binary angles so when we translate back to the decimal system there is a mathematically inherent difference introduced.
This comes up a lot on the forum but 0.1 decimal can't be represented in binary without loss of precision. It's just mathematics not an error.
We have an 8 bit processor so the next precision would be 24 bits
but there is no support in CCS so 32 bit would be next.
At 32 bits 9000000 would be 90 degrees and the decimal to binary angle table would need to be adjusted but the result would be 7 significant digits decimal. |
|
|
RKnapp
Joined: 23 Feb 2004 Posts: 51
|
|
Posted: Sun Mar 21, 2004 4:58 pm |
|
|
Sine / Cosine: How about using a Taylor / Maclaurin (?) series truncated at a few terms? Sorry, I don't have the equations in front of me but Google around a bit and I'm sure you'll find the sequence which you then just chop at the 2nd or 3rd power.
Or, a lookup table on one quadrant with some logic on the argument to sort out which part of the wave you're in -- that's the fastest but does chew up some ROM.
Just a suggestion.
Robert |
|
|
dam
Joined: 10 May 2005 Posts: 4
|
|
Posted: Thu Aug 11, 2005 3:39 am |
|
|
This algorithm is really brilliant Have you found it by yourself ? Or does it have a name ? |
|
|
Douglas Kennedy
Joined: 07 Sep 2003 Posts: 755 Location: Florida
|
|
Posted: Thu Aug 11, 2005 6:55 am |
|
|
No its the known CORDIC algorithm ...without it would not have had a moon landing. At that time the biggest MCU was the intel 8004 or maybe the 8008 ....anyway landing involves rotations and distance calcs based on triangulation sqrt(x^2+y^2) so the CORDIC was essential. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|