Welcome
Username or Email:

Password:


Missing Code




[ ]
[ ]
Online
  • Guests: 18
  • Members: 0
  • Newest Member: omjtest
  • Most ever online: 396
    Guests: 396, Members: 0 on 12 Jan : 12:51
Members Birthdays:
One birthday today, congrats!
Vaxian (17)


Next birthdays
05/21 Dalus (34)
05/21 Kizmo (37)
05/22 Skynet (32)
Contact
If you need assistance, please send an email to forum at 4hv dot org. To ensure your email is not marked as spam, please include the phrase "4hv help" in the subject line. You can also find assistance via IRC, at irc.shadowworld.net, room #hvcomm.
Support 4hv.org!
Donate:
4hv.org is hosted on a dedicated server. Unfortunately, this server costs and we rely on the help of site members to keep 4hv.org running. Please consider donating. We will place your name on the thanks list and you'll be helping to keep 4hv.org alive and free for everyone. Members whose names appear in red bold have donated recently. Green bold denotes those who have recently donated to keep the server carbon neutral.


Special Thanks To:
  • Aaron Holmes
  • Aaron Wheeler
  • Adam Horden
  • Alan Scrimgeour
  • Andre
  • Andrew Haynes
  • Anonymous000
  • asabase
  • Austin Weil
  • barney
  • Barry
  • Bert Hickman
  • Bill Kukowski
  • Blitzorn
  • Brandon Paradelas
  • Bruce Bowling
  • BubeeMike
  • Byong Park
  • Cesiumsponge
  • Chris F.
  • Chris Hooper
  • Corey Worthington
  • Derek Woodroffe
  • Dalus
  • Dan Strother
  • Daniel Davis
  • Daniel Uhrenholt
  • datasheetarchive
  • Dave Billington
  • Dave Marshall
  • David F.
  • Dennis Rogers
  • drelectrix
  • Dr. John Gudenas
  • Dr. Spark
  • E.TexasTesla
  • eastvoltresearch
  • Eirik Taylor
  • Erik Dyakov
  • Erlend^SE
  • Finn Hammer
  • Firebug24k
  • GalliumMan
  • Gary Peterson
  • George Slade
  • GhostNull
  • Gordon Mcknight
  • Graham Armitage
  • Grant
  • GreySoul
  • Henry H
  • IamSmooth
  • In memory of Leo Powning
  • Jacob Cash
  • James Howells
  • James Pawson
  • Jeff Greenfield
  • Jeff Thomas
  • Jesse Frost
  • Jim Mitchell
  • jlr134
  • Joe Mastroianni
  • John Forcina
  • John Oberg
  • John Willcutt
  • Jon Newcomb
  • klugesmith
  • Leslie Wright
  • Lutz Hoffman
  • Mads Barnkob
  • Martin King
  • Mats Karlsson
  • Matt Gibson
  • Matthew Guidry
  • mbd
  • Michael D'Angelo
  • Mikkel
  • mileswaldron
  • mister_rf
  • Neil Foster
  • Nick de Smith
  • Nick Soroka
  • nicklenorp
  • Nik
  • Norman Stanley
  • Patrick Coleman
  • Paul Brodie
  • Paul Jordan
  • Paul Montgomery
  • Ped
  • Peter Krogen
  • Peter Terren
  • PhilGood
  • Richard Feldman
  • Robert Bush
  • Royce Bailey
  • Scott Fusare
  • Scott Newman
  • smiffy
  • Stella
  • Steven Busic
  • Steve Conner
  • Steve Jones
  • Steve Ward
  • Sulaiman
  • Thomas Coyle
  • Thomas A. Wallace
  • Thomas W
  • Timo
  • Torch
  • Ulf Jonsson
  • vasil
  • Vaxian
  • vladi mazzilli
  • wastehl
  • Weston
  • William Kim
  • William N.
  • William Stehl
  • Wesley Venis
The aforementioned have contributed financially to the continuing triumph of 4hv.org. They are deserving of my most heartfelt thanks.
Forums
4hv.org :: Forums :: Computer Science
« Previous topic | Next topic »   

Free trigonometry for PIC18**** devices

Move Thread LAN_403
TheMerovingian
Fri Mar 26 2010, 11:13PM Print
TheMerovingian Registered Member #14 Joined: Thu Feb 02 2006, 01:04PM
Location: Prato/italy
Posts: 383
For a windvane averaging system i had to design my own trig functions (the in-built pic basic ones suck)

It uses a quarter wave 16Bit lookup table to calculate sin
cos is sin(x+90)
tan is sin/cos
Atan2 is useful to calculate angles from the components.
Full singolarity handling and 0,1° angular resolution.

It uses about 4000 words and 130 bytes of ram

You must use:
Include "TRIG-16B.BAS"
in your picbasic

---- SIN -----
IN:
T_Angle = your angle in 0...65535 format, corresponding to 0...6553.5 degrees [WORD]
OUT:
T_RES = your SIN, in 0...65535 format (the T_RES_SIGN takes care of sign) [WORD]
T_RES_SIGN = sign of the above, 0 = POSITIVE, 1 = NEGATIVE [BIT]

---- COS -----
IN:
T_Angle = your angle in 0...65535 format, corresponding to 0...6553.5 degrees [WORD]
OUT:
T_RES = your COS, in 0...65535 format (the T_RES_SIGN takes care of sign) [WORD]
T_RES_SIGN = sign of the above, 0 = POSITIVE, 1 = NEGATIVE [BIT]

---- TAN -----
IN:
T_Angle = your angle in 0...65535 format, corresponding to 0...6553.5 degrees [WORD]
OUT:
T_RESL = your TAN, in 0...2147483647 format (2147483647 is threated as infinity) [LONG]
T_RESL_SIGN = sign of the above, 0 = POSITIVE, 1 = NEGATIVE [BIT]
T_RES_ERR = overflow bit [BIT]

---- ATAN2 -----
IN:
T_x, T_y = Vector components in 0...2147483647 format [LONG], the function takes care of scaling, singularities and so on
OUT:
T_Angle = your angle in 0...3599 format, corresponding to 0...355.9 degrees [WORD] with correct calculation of angles such 90° and 270°


Hope it will be useful






'****************************************************************
'*  Name    : TRIG-16B.BAS                                      *
'*  Author  : Jonathan Filippi                                  *
'*  Notice  : Copyright (cc) 2010 Jonathan Filippi              *
'*          : All Rights Reserved                               *
'*  Date    : 25/03/2010                                        *
'*  Version : 1.0                                               *
'*  Notes   : SIN, COS and TAN and ATAN2 in 16-bit precision    *
'*          :                                                   *
'****************************************************************

 HRSIN       var      word[91]
 T_Angle     var      WORD  
 T_Angle2    var      WORD
 T_Angle3    var      WORD
 T_Angle4    var      WORD
 T_RES       var      WORD 
 T_RES_SIGN  vaR      BIT
 T_w0        var      WORD
 T_w1        var      word
 T_w2        var      word
 T_w3        var      word 
 T_s0        var      byte
 T_s1        var      byte
 T_s2        var      byte
 T_b0        var      bit
 T_b1        var      bit 
 T_RESL      VAR      LONG
 T_x         VAR      LONG
 T_y         VAR      LONG
 T_x_SIGN    VAR      BIT
 T_y_SIGN    VAR      BIT
 T_l0        VAR      LONG
 T_l1        VAR      LONG
 T_l2        VAR      LONG
 T_l0_SIGN   VAR      BIT
 T_l1_SIGN   VAR      BIT
 T_l2_SIGN   VAR      BIT
 T_RES_ERR   var      byte
 T_i         var      byte

  
 SYMBOL SIGN_POSITIVE = 0
 SYMBOL SIGN_NEGATIVE = 1 
 SYMBOL ERR_NONE      = 0
 SYMBOL ERR_OVERFLOW  = 1
 SYMBOL INFINITY = 2147483647
 SYMBOL T_SCALE = 10000
 
 
'quarter wave 16 bit lookup table for SIN function, the rest is derived from this!
HRSIN[0]=0
HRSIN[1]=1144
HRSIN[2]=2287
HRSIN[3]=3430
HRSIN[4]=4571
HRSIN[5]=5712
HRSIN[6]=6850
HRSIN[7]=7987
HRSIN[8]=9121
HRSIN[9]=10252
HRSIN[10]=11380
HRSIN[11]=12505
HRSIN[12]=13625
HRSIN[13]=14742
HRSIN[14]=15854
HRSIN[15]=16962
HRSIN[16]=18064
HRSIN[17]=19161
HRSIN[18]=20251
HRSIN[19]=21336
HRSIN[20]=22414
HRSIN[21]=23486
HRSIN[22]=24550
HRSIN[23]=25607
HRSIN[24]=26655
HRSIN[25]=27696
HRSIN[26]=28729
HRSIN[27]=29752
HRSIN[28]=30767
HRSIN[29]=31771
HRSIN[30]=32768
HRSIN[31]=33753
HRSIN[32]=34728
HRSIN[33]=35693
HRSIN[34]=36647
HRSIN[35]=37589
HRSIN[36]=38521
HRSIN[37]=39440
HRSIN[38]=40347
HRSIN[39]=41243
HRSIN[40]=42125
HRSIN[41]=42995
HRSIN[42]=43851
HRSIN[43]=44695
HRSIN[44]=45524
HRSIN[45]=46340
HRSIN[46]=47142
HRSIN[47]=47929
HRSIN[48]=48701
HRSIN[49]=49460
HRSIN[50]=50203
HRSIN[51]=50930
HRSIN[52]=51642
HRSIN[53]=52339
HRSIN[54]=53019
HRSIN[55]=53683
HRSIN[56]=54331
HRSIN[57]=54962
HRSIN[58]=55577
HRSIN[59]=56174
HRSIN[60]=56755
HRSIN[61]=57318
HRSIN[62]=57864
HRSIN[63]=58392
HRSIN[64]=58902
HRSIN[65]=59395
HRSIN[66]=59869
HRSIN[67]=60325
HRSIN[68]=60763
HRSIN[69]=61182
HRSIN[70]=61583
HRSIN[71]=61965
HRSIN[72]=62327
HRSIN[73]=62671
HRSIN[74]=62996
HRSIN[75]=63302
HRSIN[76]=63588
HRSIN[77]=63855
HRSIN[78]=64103
HRSIN[79]=64331
HRSIN[80]=64539
HRSIN[81]=64728
HRSIN[82]=64897
HRSIN[83]=65047
HRSIN[84]=65176
HRSIN[85]=65286
HRSIN[86]=65375
HRSIN[87]=65445
HRSIN[88]=65495
HRSIN[89]=65525
HRSIN[90]=65535

goto skiptrig:

'******************************************************************************
'********** T_SIN, format  T_Angle [WORD] -> T_RES[WORD];T_RES_SIGN [BIT]
'********** This function calculates the sin of the angle.
'********** Format of the angle: 0..3600 , corresponding to 0...360° with resolution
'********** in complementary form , for eg.  -45° = 3150( 315,0°)
'********** of 0.1°, calculated by linear interpolation of points
'********** the value is in -65535...+65535 format
'******************************************************************************
T_SIN:
   T_Res_ERR = ERR_NONE
   T_Angle = T_Angle // 3600 'if the angle is exceeded
  ' determining the quadrant, appling the correct phase and then calling T_SIN_INTERP
   T_s0 = T_angle / 900    ' shared variables
   T_w1 = T_Angle // 900   ' shared variables
   if (T_s0 = 0) then
    ' First quadrant, applying the function as is
    T_w0 = T_w1
    gosub T_SIN_INTERP:
    T_RES = T_w0
    T_RES_SIGN = SIGN_POSITIVE 'positive
    return
   endif
   
   if (T_s0 = 1) then
    ' second quadrant, applying the function reversed
    T_w0 = 900 - T_w1
    gosub T_SIN_INTERP:
    T_RES = T_w0
    T_RES_SIGN = SIGN_POSITIVE 'positive
    return
   endif
   
   if (T_s0 = 2) then
    ' third quadrant, applying the function as is but the sign is negative
    T_w0 = T_w1
    gosub T_SIN_INTERP:
    T_RES = T_w0
    T_RES_SIGN = SIGN_NEGATIVE 'negative
    return
   endif
   
   if (T_s0 = 3) then
    ' forth quadrant, applying the function reversed and its sign is negative
    T_w0 = 900 - T_w1
    gosub T_SIN_INTERP:
    T_RES = T_w0
    T_RES_SIGN = SIGN_NEGATIVE 'negative
    return
   endif
   
return

'******************************************************************************
'********** T_COS, format  T_Angle [WORD] -> T_RES[WORD];T_RES_SIGN [BIT]
'********** This function calculates the cos of the angle.
'********** Format of the angle: 0..3600 , corresponding to 0...360° with resolution
'********** in complementary form , for eg.  -45° = 3150( 315,0°)
'********** of 0.1°, calculated by linear interpolation of points
'********** the value is in -65535...+65535 format
'******************************************************************************
T_COS:
      'simply shift the phase of 90° and calculate the sin
   T_Angle2 = T_angle
   T_Angle = T_Angle + 900
   Gosub T_Sin:
   T_angle = T_angle2
return


'******************************************************************************
'********** T_TAN, format  T_Angle [WORD] -> T_RESL[LONG];T_RES_SIGN [BIT]
'********** This function calculates the tangent of the angle.
'********** Format of the angle: 0..3600 , corresponding to 0...360° with resolution
'********** in complementary form , for eg.  -45° = 3150( 315,0°)
'********** of 0.1°, calculated by linear interpolation of points
'******************************************************************************
T_TAN:
      'use the functions above
   T_Res_ERR = ERR_NONE
   T_Angle2 = T_angle
   T_Angle = T_Angle // 3600
    
   if (T_Angle = 900) OR (T_Angle = 2700) then
    T_resL = 2147483647  'Infinity
    T_Res_ERR = ERR_OVERFLOW
    T_s0 = T_angle / 900    
    T_RES_SIGN = SIGN_POSITIVE    
    if T_s0 = 1 then 
     T_RES_SIGN = SIGN_NEGATIVE
    endif
    if T_s0 = 3 then 
     T_RES_SIGN = SIGN_NEGATIVE
    endif
    
    return
   endif

   gosub T_Sin:
   T_w2 = T_Res
   T_b0 = T_RES_SIGN
   GOSUB T_COS:
   T_w3 = T_Res
   T_b1 = T_RES_SIGN
   T_RESL = T_w2*10000/T_W3   
   T_RES_SIGN = T_b1*T_b1
   T_angle = T_angle2
return

'******************************************************************************
'********** ATAN function for quarter wave, don't use it, used internally
'**********  T_l0 input variable    0..+INF
'********** In this range the function is monotone so it is easy to interpolate
'******************************************************************************
T_ATAN_QUARTER:      ' iterative method for monotone functions

 T_Angle4 = 4500    ' starting from 45°
 T_Angle3 = 4500
 T_RESL = 0


 While T_Angle3 > 0 
   T_Angle = T_angle4 / 10
   if (T_Angle4 dig 0) >=5 then
   T_Angle = T_Angle + 1
   endif 
   Gosub T_TAN:
   T_Angle3 = T_Angle3  / 2 
   if T_l0 < T_RESL then
    T_Angle4 = T_Angle4 - T_angle3 
   else
    T_Angle4 = T_Angle4 + T_angle3 
   endif 
 WEND
  
 
return


'******************************************************************************
'********** T_ATAN2, T_x;T_y[LONG];T_x_SIGN;T_y_SIGN[BIT] -> T_Angle[WORD]
'********** This function calculates the angle corresponding for a 2D vector
'********** Format of the angle: 0..3600 , corresponding to 0...360° with resolution
'********** of 0.1°
'********** 
'******************************************************************************
T_ATAN2: 

 ' first checking for singularities   
 if T_y = 0 then  ' Y singularity 
  If T_x_SIGN = SIGN_POSITIVE then
   T_Angle = 0       ' if the y is zero the angle is 0° if x is positive
  else
   T_Angle = 1800    ' if the y is zero the angle is 180° if x is negative
  endif  
  return
 endif
 
 
 
 if T_x = 0 then
  T_l0 = INFINITY ' "infinity"
 else
  ' scaling for best resolution    
  if T_y > Infinity / T_SCALE then  ' T_Y is too large to scale up, scaling down the other
   T_l0 = T_y  / (T_x / 10000)
  else
   T_l0 = T_y*T_SCALE  / T_x    ' scaling up T_Y
  endif
  
 endif  
               
 if T_l0 > 10000000 then   ' X singularity
  If T_y_SIGN = SIGN_POSITIVE then
   T_Angle = 900       ' if the x is zero the angle is 90° if y is positive
  else
   T_Angle = 2700    ' if the y is zero the angle is 270° if x is negative
  endif  
  return
 endif
 
  Gosub T_ATAN_QUARTER: 'determining the arctangent regardless of the quadrant
 
 if T_x_sign = SIGN_POSITIVE then  
  if T_y_sign = SIGN_POSITIVE then  
    ' quadrant 1, the angle is correct as is
    return
  else
    T_Angle = 3600 - T_Angle  ' quadrant 4 the angle is negative
    return
  endif
 else
  if T_y_sign = SIGN_POSITIVE then  
    T_Angle = 1800 - T_Angle ' quadrant 2, the angle is complementary 
    return
   else
    T_Angle = 1800 + T_Angle  ' quadrant 3, the angle is supplementary 
   return
  endif
 endif
 
return
           
 

'******************************************************************************
'********** Interpolation function for SIN, don't use it, used internally
'**********  T_w0 input/output variable    0..900  ->  0..90°
'********** In this range the function is monotone so it is easy to interpolate
'******************************************************************************
T_SIN_INTERP:
 
 'checking if the ancle is "round"
 t_s0 = T_w0 DIG 0
 T_s1 = T_w0 / 10
 if (T_s0) = 0 then 'angle is round 
  
  T_w0 = HRSIN[T_s1] ' return the value
  return
 else     'angle is not round, interpolating                    
  T_s2 = T_s1 + 1  ' picking the two closest points
  T_w1 = (HRSIN[T_s2]-HRSIN[T_s1])*T_s0 'calculating their difference
  T_w0 = T_w1 / 10 + HRSIN[T_s1]  ' scaling and summing                    
  return
 endif
 
return



skiptrig: ' label at the end of the soubroutines

Back to top
klugesmith
Sat Mar 27 2010, 08:23AM
klugesmith Registered Member #2099 Joined: Wed Apr 29 2009, 12:22AM
Location: Los Altos, California
Posts: 1714
Nice work, Jonathan.
Here's a friendly review.

1. Well organized and well commented (better than the work of some professionals I know).

2. Based on sin and cos ranges of +-65535, I think there are a couple of errors in your sin(x) table. For 29 degrees you have 31771, should be 31772. For 48 degrees you have 48701; should be 48702.

3. You didn't specify the accuracy, but linear interpolation between points 1.0 degree apart gives sin(x) errors as large as -3 LSB's (about -45 ppm) for angles near 90 degrees, where the sin function is most strongly curved.
This error is proportional to the square of the interval between points in the table, So you can improve it by a factor of four (to less than one LSB) by having lookup-table entries for every half-degree.

4. Without iterative algorithms or linear interpolation, you can get fast high-resolution sin values using the trig. identity sin(a+b) = sin a cos b + cos a sin b.
e.g. for your 0.1 degree resolution, instead of a 900 point table you could have
a 30 point coarse sin table (0 to 87 in steps of 3 degrees) and a 30 point fine sin and cos table (0 to 2.9 in steps of 0.1 degree).
Angular resolution could increase to 0.001 degree (comparable to your sin output resolution) with tables only 10x deeper.
The method can be handy in fast hardware computation, for example DDS in an FPGA.

5. The reduction of arbitrary angles to quadrant values (and fine/coarse components if desired) is more efficient if your angles are represented as binary fractions of a circle. For example, 1/4096 which is about 0.09 degrees. Many shaft angle encoders use these "natural" units of angular measurement.
Back to top
TheMerovingian
Sat Mar 27 2010, 11:04PM
TheMerovingian Registered Member #14 Joined: Thu Feb 02 2006, 01:04PM
Location: Prato/italy
Posts: 383
Klugesmith wrote ...

Nice work, Jonathan.
Here's a friendly review.

Thank you for interest :D

Klugesmith wrote ...

1. Well organized and well commented (better than the work of some professionals I know).

Wow, thank you! It is always fine to receive positive comments about my work.

Klugesmith wrote ...

2. Based on sin and cos ranges of +-65535, I think there are a couple of errors in your sin(x) table. For 29 degrees you have 31771, should be 31772. For 48 degrees you have 48701; should be 48702.

Probably rounding errors, I have corrected the table according to your values


Klugesmith wrote ...

3. You didn't specify the accuracy, but linear interpolation between points 1.0 degree apart gives sin(x) errors as large as -3 LSB's (about -45 ppm) for angles near 90 degrees, where the sin function is most strongly curved.
This error is proportional to the square of the interval between points in the table, So you can improve it by a factor of four (to less than one LSB) by having lookup-table entries for every half-degree.

The reason i choose to limit to 90 elements is to make the software affordable for most PICS, even those with 16K words of program memory and 1K of ram. Also this accuracy is waay too much for the wind vane since i have angles in 10 bit resolution (using PWM output of AS5040), so i have to scale (1/64) it after multiplying the unity vector by the wind speed modulus. In fact I save the average wind angle in 0,1° resolution. In future probably i will try to extend it to make it useful for other purposes.

Klugesmith wrote ...

4. Without iterative algorithms or linear interpolation, you can get fast high-resolution sin values using the trig. identity sin(a+b) = sin a cos b + cos a sin b.
e.g. for your 0.1 degree resolution, instead of a 900 point table you could have
a 30 point coarse sin table (0 to 87 in steps of 3 degrees) and a 30 point fine sin and cos table (0 to 2.9 in steps of 0.1 degree).
Angular resolution could increase to 0.001 degree (comparable to your sin output resolution) with tables only 10x deeper.
The method can be handy in fast hardware computation, for example DDS in an FPGA.

did you mean 0.01 ° resolution?

Interesting, I didn't thought about this method it would give very high resolution trigonometry. Thank you for the input. To arrive to a similar angular resolution for ATAN2, 17 iterations are necessary, not very much more compared to the actual 13.

30 coarse and 30 sin and 30 cos fine table is 90 elements, the same of mine but with less error probably. (180Bytes ram)

to increase to 0.01° :

90 coarse and 100 sin and 100 cos , 290 not very much (580bytes ram)

0.001° is unaffordable for PICS, it would cost too much in terms of program memory and ram and interpolation would not work with 16 bit variables
maybe a third table would work but we are close to the 16bit resolution

30 coarse + 30 sin and 30 cos fine table , plus 100 sin and 100 cos (repeating the identity) total , 290 (580 bytes ram) as you have stated before :D

Klugesmith wrote ...

5. The reduction of arbitrary angles to quadrant values (and fine/coarse components if desired) is more efficient if your angles are represented as binary fractions of a circle. For example, 1/4096 which is about 0.09 degrees. Many shaft angle encoders use these "natural" units of angular measurement.


You are right, the micro would be happy with his natural ability to work with numbers of this type. Humans think in decimals, electronics in binary :D

Thank you for the inputs, I will work at a second version of the library with more general use using 0....65535 angular resolution (0.005° resolution)



Back to top
klugesmith
Sun Mar 28 2010, 05:27AM
klugesmith Registered Member #2099 Joined: Wed Apr 29 2009, 12:22AM
Location: Los Altos, California
Posts: 1714
TheMerovingian wrote ...

Klugesmith wrote ...
...Angular resolution could increase to 0.001 degree (comparable to your sin output resolution) with tables only 10x deeper
did you mean 0.01 ° resolution?
No ... with the sin(a+b) formula, table size goes up as the square root of angular resolution.
For 0.001 ° resolution, instead of 90000 point table you have a 300 point coarse angle table (sin/cos for a quadrant, in steps of 0.3 degrees)
and two 300 point fine angle tables (sin and cos for 0, 0.001, ..., 0.299 degrees).

Hmm - Note that we need separate fine angle tables for sin and cos, while the coarse angle table (covering a full quadrant) covers both sin AND cos.
So if lookup-table ROM space is the critical cost, the 0.001 degree version is more efficiently served with a 450 point coarse table (0.2 degree intervals) and 200 point fine tables (0.199 degree range).

Checking your original 1-degree table was a trivial exercise after cutting and pasting it into a popular spreadsheet calculator program.. Can be used the other way to create source code with algorithmically generated constant data.
Back to top
TheMerovingian
Sun Mar 28 2010, 11:13PM
TheMerovingian Registered Member #14 Joined: Thu Feb 02 2006, 01:04PM
Location: Prato/italy
Posts: 383
Another method, more intensive in terms of calculation power but less in terms of tables would be to use the taylor series for interpolation:

Sin(A+x) = SIN(A) + COS(A)*X - SIN(A) * X^2 / 2

A is the value from the table (the coarse one) and x the increment. SIN(A) is the value obtained from lookup table and COS(A) is the value of SEN(90-A) (can be obtained from the same table), also adding more polynomials would increase the precision (of course never beyond the precision of the table, whithout increasing bits of the lookup table)

The taylor series works for radians so X (in 1/10 of deg) must be converted accordingly using scaling x * 1000 / 572957

Algorithm using two long variables l0, l1,l2

L0 = SIN[A]

L1 = SIN[90-A] * X

L2 = SIN[A] * X * X * 500 / 572057

L1 = (L1 + L2) * 1000 / 572057

L0 = L0 + L1



Example:

linear interpolation for angle=89.5 gives:

65530 (the real value is 65532,504628010465407402570726936, that can be rounded to 65532 or 65533)

Second order taylor gives:

L0 = SIN[A] = SIN[89] = 65525

L1 = SIN[90-A] * X = SIN[1] * 5 = 1144 * 5 = 5720

L2 = SIN[A] * X * X * 500 / 572057 = 65525 * 5 * 5 * 500 / 572057 = 1431

L1 = (L1 - L2) * 1000 / 572057 = (5720 - 1431) * 1000 / 572057 = 7,49 (7)

L0 = L0 + L1 = 65525 + 7 (7,49) = 65532 (really it should be 65532,49)

the error is -1/2LSB maximum, due to the rounding.

Using third order taylor is useless for 16-Bit table and a 32bit table makes the calculations a bit mor complicated (must take care of roll-overs for values higher than (4294967296 unsigned or 2147483648 signed).

Resolution can be increased increasing taylor polynomial but precision not, if the table is 16-Bit based, using finer angle table will not increase it very much even using identity (sin(a+b)) because the precision of the starting values of the identity is quantized at 16 bit.

Maybe adding 8 bits to the table for each element would help

eg:

HRSINH[0]=0 HRSINL[0]=0
HRSIN[1]=1144 HRSINH[1]=190

but the calculation will be more complex and system intensive.

I will modify the algorithm to use the second order taylor polynomial to get rid of the -3LSB error.

Thank you


EDIT: Taylor is too much calculation intensive. I will use the sin(a+b) identity

EDIT2: THis is the last version, usin SIN(A+B) identity and some rounding bugs and minor errors.

' ************************************************** **************
'* Name : TRIG-16B.BAS *
'* Author : Jonathan Filippi *
'* Notice : Copyright (c) 2010 Jonathan Filippi *
'* : All Rights Reserved *
'* Date : 25/03/2010 *
'* Version : 1.2 *
'* Notes : SIN, COS and TAN and ATAN2 in 16-bit precision *
'* : SUM, DIFF , signed 32bit *
'* : Changes: using SIN(A+B)=SIN(A)COS(B)+COS(A)SIN(B) *
'* : identity and some minor bugfixes and rounding *
'* : problems, this version uses a bit less memory but *
'* : is a bit slower due to the replacement of *
'* : linear interpolation with true trig identity but *
'* : higher precision is assured though *
'* : (max error +-1/2LSB @ 16Bit due to rounding *
' ************************************************** **************

HRSINC var word[46]
HRSINF var word[20]
HRCOSF var word[20]
T_Angle var WORD
T_Angle2 var WORD
T_Angle3 var WORD
T_Angle4 var WORD
T_RES var WORD
T_RES_SIGN vaR BIT
T_w0 var WORD
T_w1 var word
T_w2 var word
T_w3 var word
T_s0 var byte
T_s1 var byte
T_s2 var byte
T_b0 var bit
T_b1 var bit
T_RESL VAR LONG
T_x VAR LONG
T_y VAR LONG
T_x_SIGN VAR BIT
T_y_SIGN VAR BIT
T_l0 VAR LONG
T_l1 VAR LONG
T_l2 VAR LONG
T_l0_SIGN VAR BIT
T_l1_SIGN VAR BIT
T_l2_SIGN VAR BIT
T_RES_ERR var byte
T_i var byte


SYMBOL SIGN_POSITIVE = 0
SYMBOL SIGN_NEGATIVE = 1
SYMBOL ERR_NONE = 0
SYMBOL ERR_OVERFLOW = 1
SYMBOL INFINITY = 2147483647
SYMBOL T_SCALE = 10000


'quarter wave coarse 16 bit lookup table for SIN function
'Resolution 2 degrees, from 0 to 88 (46 values)
HRSINC[0]=0 ' 0°
HRSINC[1]=2287
HRSINC[2]=4571
HRSINC[3] =6850
HRSINC[4]=9121
HRSINC[5]=11380 ' 10°
HRSINC[6]=13625
HRSINC[7]=15854
HRSINC[8] =18064
HRSINC[9]=20251
HRSINC[10]=22414 ' 20°
HRSINC[11]=24550
HRSINC[12]=26655
HRSINC[13] =28729
HRSINC[14]=30767
HRSINC[15]=32768 ' 30°
HRSINC[16]=34728
HRSINC[17]=36647
HRSINC[18] =38521
HRSINC[19]=40347
HRSINC[20]=42125 ' 40°
HRSINC[21]=43851
HRSINC[22]=45524
HRSINC[23]=47142
HRSINC[24]=48702
HRSINC[25] =50203 ' 50°
HRSINC[26]=51642
HRSINC[27]=53019
HRSINC[28] =54331
HRSINC[29]=55577
HRSINC[30]=56755 ' 60°
HRSINC[31]=57864
HRSINC[32]=58902
HRSINC[33] =59869
HRSINC[34]=60763
HRSINC[35]=61583 ' 70°
HRSINC[36]=62327
HRSINC[37]=62996
HRSINC[38] =63588
HRSINC[39]=64103
HRSINC[40]=64539 ' 80°
HRSINC[41]=64897
HRSINC[42]=65176
HRSINC[43] =65375
HRSINC[44]=65495
HRSINC[45]=65535 ' 90°

'Fine 16 bit lookup table for SIN function
'Resolution 0.1 degrees, from 0.1° to 1.9° (19 values)
HRSINF[0]=0
HRSINF[1]=114
HRSINF[2] =229
HRSINF[3]=343
HRSINF[4]=458
HRSINF[5] =572
HRSINF[6]=686
HRSINF[7]=801
HRSINF[8] =915
HRSINF[9]=1029
HRSINF[10]=1144
HRSINF[11] =1258
HRSINF[12]=1372
HRSINF[13]=1487
HRSINF[14] =1601
HRSINF[15]=1716
HRSINF[16]=1830
HRSINF[17] =1944
HRSINF[18]=2059
HRSINF[19]=2173


'Fine 16 bit lookup table for COS function
'Resolution 0.1 degrees, from 0.1° to 1.9° (19 values)
HRCOSF[0]=65535
HRCOSF[1]=65535
HRCOSF[2] =65535
HRCOSF[3]=65534
HRCOSF[4]=65533
HRCOSF[5] =65533
HRCOSF[6]=65531
HRCOSF[7]=65530
HRCOSF[8] =65529
HRCOSF[9]=65527
HRCOSF[10]=65525
HRCOSF[11] =65523
HRCOSF[12]=65521
HRCOSF[13] =65518
HRCOSF[14]=65515
HRCOSF[15] =65513
HRCOSF[16]=65509
HRCOSF[17] =65506
HRCOSF[18]=65503
HRCOSF[19]=65499


goto skiptrig:

' ************************************************** ****************************
'********** T_SIN, format T_Angle [WORD] -> T_RES[WORD];T_RES_SIGN [BIT]
'********** This function calculates the sin of the angle.
'********** Format of the angle: 0..3600 , corresponding to 0...360° with resolution
'********** in complementary form , for eg. -45° = 3150( 315,0°)
'********** of 0.1°, calculated by linear interpolation of points
'********** the value is in -65535...+65535 format
' ************************************************** ****************************
T_SIN:
T_Res_ERR = ERR_NONE
T_Angle = T_Angle // 3600 'if the angle is exceeded
' determining the quadrant, appling the correct phase and then calling T_SIN_INTERP
T_s0 = T_angle / 900 ' shared variables
T_w1 = T_Angle // 900 ' shared variables
if (T_s0 = 0) then
' First quadrant, applying the function as is
T_w0 = T_w1
gosub T_SIN_INTERP:
T_RES = T_w0
T_RES_SIGN = SIGN_POSITIVE 'positive
return
endif

if (T_s0 = 1) then
' second quadrant, applying the function reversed
T_w0 = 900 - T_w1
gosub T_SIN_INTERP:
T_RES = T_w0
T_RES_SIGN = SIGN_POSITIVE 'positive
return
endif

if (T_s0 = 2) then
' third quadrant, applying the function as is but the sign is negative
T_w0 = T_w1
gosub T_SIN_INTERP:
T_RES = T_w0
T_RES_SIGN = SIGN_NEGATIVE 'negative
return
endif

if (T_s0 = 3) then
' forth quadrant, applying the function reversed and its sign is negative
T_w0 = 900 - T_w1
gosub T_SIN_INTERP:
T_RES = T_w0
T_RES_SIGN = SIGN_NEGATIVE 'negative
return
endif

return

' ************************************************** ****************************
'********** T_COS, format T_Angle [WORD] -> T_RES[WORD];T_RES_SIGN [BIT]
'********** This function calculates the cos of the angle.
'********** Format of the angle: 0..3600 , corresponding to 0...360° with resolution
'********** in complementary form , for eg. -45° = 3150( 315,0°)
'********** of 0.1°, calculated by linear interpolation of points
'********** the value is in -65535...+65535 format
' ************************************************** ****************************
T_COS:
'simply shift the phase of 90° and calculate the sin
T_Angle2 = T_angle
T_Angle = T_Angle + 900
Gosub T_Sin:
T_angle = T_angle2
return


' ************************************************** ****************************
'********** T_TAN, format T_Angle [WORD] -> T_RESL[LONG];T_RES_SIGN [BIT]
'********** This function calculates the tangent of the angle.
'********** Format of the angle: 0..3600 , corresponding to 0...360° with resolution
'********** in complementary form , for eg. -45° = 3150( 315,0°)
'********** of 0.1°, calculated by linear interpolation of points
' ************************************************** ****************************
T_TAN:
'use the functions above
T_Res_ERR = ERR_NONE
T_Angle2 = T_angle
T_Angle = T_Angle // 3600

if (T_Angle = 900) OR (T_Angle = 2700) then
T_resL = 2147483648 'Infinity
T_Res_ERR = ERR_OVERFLOW
T_s0 = T_angle / 900
T_RES_SIGN = SIGN_POSITIVE
if T_s0 = 1 then
T_RES_SIGN = SIGN_NEGATIVE
endif
if T_s0 = 3 then
T_RES_SIGN = SIGN_NEGATIVE
endif

return
endif

gosub T_Sin:
T_w2 = T_Res
T_b0 = T_RES_SIGN
GOSUB T_COS:
T_w3 = T_Res
T_b1 = T_RES_SIGN
T_RESL = T_w2*T_SCALE/T_W3
T_RES_SIGN = T_b0+T_b1
T_angle = T_angle2
return

' ************************************************** ****************************
'********** ATAN function for quarter wave, don't use it, used internally
'********** T_l0 input variable 0..+INF
'********** In this range the function is monotone so it is easy to interpolate
' ************************************************** ****************************
T_ATAN_QUARTER: ' iterative method for monotone functions

T_Angle4 = 4500 ' starting from arbitrary value
T_Angle3 = 4500
T_RESL = 0


While T_Angle3 > 0 ' if the increment falls to zero exit (end of iterations)
T_Angle = T_angle4 / 10
if (T_Angle4 dig 0) > 5 then
T_Angle = T_Angle + 1
endif
Gosub T_TAN: ' calculating tangent
T_RESL = T_RESL
T_Angle3 = T_Angle3 / 2
if T_l0 = T_RESL then ' i don't want the algorithm to bounce uselessy
' around the solution in case of an accidental equivalence
' (it is not so rare when working with fixed point math)
' Bouncing can lead to an additional error of -+0.1°

' the tangent of the angle is the same of the searched value so found the angle
' return and save some machine computing time
return
else
if T_l0 < T_RESL then ' the value is different, checking in which half and
' adjusting accordingly
T_Angle4 = T_Angle4 - T_angle3
else
T_Angle4 = T_Angle4 + T_angle3
endif
endif
WEND

return


' ************************************************** ****************************
'********** T_ATAN2, T_x;T_y[LONG];T_x_SIGN;T_y_SIGN[BIT] -> T_Angle[WORD]
'********** This function calculates the angle corresponding for a 2D vector
'********** Format of the angle: 0..3600 , corresponding to 0...360° with resolution
'********** of 0.1°
'**********
' ************************************************** ****************************
T_ATAN2:

' first checking for singularities
if T_y = 0 then ' Y singularity
If T_x_SIGN = SIGN_POSITIVE then
T_Angle = 0 ' if the y is zero the angle is 0° if x is positive
else
T_Angle = 1800 ' if the y is zero the angle is 180° if x is negative
endif
return
endif



if T_x = 0 then
T_l0 = INFINITY ' "infinity"
else
' scaling for best resolution
if T_y > Infinity / T_SCALE then ' T_Y is too large to scale up, scaling down the other
T_l0 = T_y / (T_x / 10000)
else
T_l0 = T_y*T_SCALE / T_x ' scaling up T_Y
endif

endif

if T_l0 > 10000000 then ' X singularity
If T_y_SIGN = SIGN_POSITIVE then
T_Angle = 900 ' if the x is zero the angle is 90° if y is positive
else
T_Angle = 2700 ' if the y is zero the angle is 270° if x is negative
endif
return
endif

Gosub T_ATAN_QUARTER: 'determining the arctangent regardless of the quadrant

if T_x_sign = SIGN_POSITIVE then
if T_y_sign = SIGN_POSITIVE then
' quadrant 1, the angle is correct as is
return
else
T_Angle = 3600 - T_Angle ' quadrant 4 the angle is negative
return
endif
else
if T_y_sign = SIGN_POSITIVE then
T_Angle = 1800 - T_Angle ' quadrant 2, the angle is complementary
return
else
T_Angle = 1800 + T_Angle ' quadrant 3, the angle is supplementary
return
endif
endif

return



' ************************************************** ****************************
'********** Interpolation function for SIN, don't use it, used internally
'********** It uses the trigonometry identity SIN(A+B)=SIN(A)COS(B)+SIN(B)COS(A)
'********** T_w0 input/output variable 0..900 -> 0..90.0°
' ************************************************** ****************************
T_SIN_INTERP:

'checking if the ancle is one of the table, this speeds up the things a bit
t_s0 = T_w0 // 20
T_s1 = T_w0 / 20
if (T_s0) = 0 then 'angle is one of the HRSINC table
T_w0 = HRSINC[T_s1] ' return the value
return
endif
if (T_w0) < 20 then 'angle is one of the HRSINF table
T_w0 = HRSINF[T_w0] ' return the value
return
endif
if (T_w0) > 880 then 'angle is one of the HRCOSF table (quarter complementary angle)
T_w0 = HRCOSF[20-T_s0] ' return the value
return
endif

'angle is not in table, using identity
T_l1 = HRSINC[T_s1]*HRCOSF[T_s0] + 32768 'first term of the sum plus rounding correction
T_w0 = T_l1 / 65535 'scaling down to comply with the values used

T_l1 = HRSINC[45-T_s1]*HRSINF[T_s0] + 32768 'second term of the sum plus rounding correction
T_w3 = T_l1 / 65535 'scaling down to comply with the values used

T_w0 = T_w0 + T_w3 ' final sum

return


' ************************************************** ****************************
'********** Sums two numbers T_l0,T_l1 [LONG] T_l0_SIGN,T_l1_SIGN [BIT]
'********** --> T_l2 [LONG] T_l2_SIGN [BIT]
'********** I ignored the Signed LONG to ensure compatibility with the trig functions
' ************************************************** ****************************
T_SUM:

If T_l0_SIGN = T_l1_Sign then
'same sign
T_l2 = T_l0 + T_l1
T_l2_SIGN = T_l0_SIGN
else
'different sign
If T_l0 >= T_l1 then
T_l2 = T_l0 - T_l1
T_l2_SIGN = T_l0_SIGN
else
T_l2 = T_l1 - T_l0
T_l2_SIGN = T_l1_SIGN
endif
endif
if T_l2 = 0 then
T_l2_SIGN = SIGN_POSITIVE ' if zero the sign is positive by definition
endif
return


' ************************************************** ****************************
'********** SUbtracts T_l0 from T_l1 - T_l0,T_l1 [LONG] T_l0_SIGN,T_l1_SIGN [BIT]
'********** --> T_l2 [LONG] T_l2_SIGN [BIT]
'********** I ignored the Signed LONG to ensure compatibility with the trig functions
' ************************************************** ****************************
T_DIFF:
T_l1_SIGN = NOT T_l1_SIGN ' invert the sign
gosub T_SUM ' and sum
return


skiptrig: ' label at the end of the soubroutines

Back to top

Moderator(s): Chris Russell, Noelle, Alex, Tesladownunder, Dave Marshall, Dave Billington, Bjørn, Steve Conner, Wolfram, Kizmo, Mads Barnkob

Go to:

Powered by e107 Forum System
 
Legal Information
This site is powered by e107, which is released under the GNU GPL License. All work on this site, except where otherwise noted, is licensed under a Creative Commons Attribution-ShareAlike 2.5 License. By submitting any information to this site, you agree that anything submitted will be so licensed. Please read our Disclaimer and Policies page for information on your rights and responsibilities regarding this site.