​ ​ ​ ​ Better atan approximations
Results 1 to 4 of 4

Thread: Better atan approximations

  1. #1
    Senior Member
    Join Date
    Jun 2010
    Location
    Australia
    Posts
    121

    Default Better atan approximations

    I was looking for a better atan approximation and I have come up with the following three.

    They all work in exactly the same way as the X2 builtin atan function:
    • They provide an arctan function for angles between 0 and 45 degrees.
    • The same coding system is used for the input value. The value is 100 x the real atan value (e.g. 0.39 = 39)
    • e.g let b1 = atan 100 (answer b1 = 45)

    To judge the accuracy of the approximations I'm comparing them with the spreadsheet funciton =round(atan(A/100)*180/pi()). The best approximation is one that gives the same result as this spreadsheet function for all 101 values of A from 0 to 100.

    For measuring the error I'm comparing them with the spreadsheet funciton =atan(A/100)*180/pi(). Because we are rounding or truncating the result to an integer value the best possible absolute error is 0.5 degree and this is the maximum aboslute error for the spreadsheet funciton =round(atan(A/100)*180/pi()).

    I used a 20X2 chip for all my tests.


    Atan approximation #1
    b0=input value
    output value=364-b0*b0/580
    • 7.25% faster than the builtin atan function
    • Gives the same result as the spreadsheet function for 97 out of the 101 input values. The builtin atan function gives the same result for 74 out of 101 input values.
    • Maximum abolute error is 0.72 degrees compared to 0.95 degrees for the builtin atan funciton.
    • Only 12 bytes of code.
    • Does not require any variables for intermediate results. If you don' t need to save the input value you can code the function as b0=364-b0*b0/580
    • You can also define this approximation as a macro "#DEFINE atan(reg) 364-reg*reg/580" and then call it in your code in a similar fashion to the builtin function: b1=atan(b0)

    Atan approximation #2
    This one line implementation of the code is courtesy of Hippy in post #2 and replaces my original two lines of code.
    b0=input value
    output value=b0+250*b0/251^$FFFF+581*b0+400/979
    • Half as fast as the builtin atan function.
    • Gives the same result as the spreadsheet function for all 101 input values.
    • Maximum absolute error is 0.5 degrees.
    • 25 bytes of code.
    • Does not require any variables for intermediate results. If you don' t need to save the input value you can code the fuction as b0=b0+250*b0/251^$FFFF+581*b0+400/979
    • You can also define this approximation as a macro "#DEFINE atan(reg) reg+250*reg/251^$FFFF+581*reg+400/979" and then call it in your code in a similar fashion to the builtin function: b1=atan(b0)

    If you #DEFINE the atan approximation as a macro then the rules for using that macro are the same as for using the builtin atan unary command:
    • It must be the first command on a program line.
    • It may be followed by additional mathematical commands.
    let b1 = atan(30) + 5 ' Is valid
    let b1 = 5 + atan(30) ' Is not valid. It won't generate a syntax error but it will return the wrong result.

    Atan approximation #3
    eeprom (0,1,1,2,2,3,3,4,5,5,6,6,7,7,8,9,9,10,10,11,11,12, 12,13,13,14,15,15,16,16,17,17,18,18,19,19,20,20,21 ,21,22,22,23,23,24,24,25,25,26,26,27,27,27,28,28,2 9,29,30,30,31,31,31,32,32,33,33,33,34,34,35,35,35, 36,36,37,37,37,38,38,38,39,39,39,40,40,40,41,41,41 ,42,42,42,43,43,43,44,44,44,44,45,45)
    read b0, b1
    • Four times as fast as the builtin atan function.
    • Gives the same result as the spreadsheet function for all 101 input values.
    • Maximum absolute error is 0.5 degrees.
    • 3 bytes of code and 101 bytes of data.


    The code to test the speed toggles a pin on a 20X2 that is running at 4MHz and the pulse width was measured using PULSEIN on an 08M2 that is running at 4MHz. The values for 100 pulses were averaged to get the final result for each test.

    atan speed tests.jpg

    Post updated 11/04/2015 - Added approximation #3
    Post updated 06/04/2015 - Replaced these original two lines of code for approximation #2 with the one line of code provided by Hippy
    b3=b0+250*b0/251
    output value=580-b3*b0+400/979
    Last edited by Flenser; 11-04-2015 at 12:24.

  2. #2
    Technical Support
    Join Date
    Jan 1970
    Location
    UK
    Posts
    24,346

    Default

    Interesting work and quite impressive. Your approximation #2 can be refactored to not require an additional temporary variable as follows -

    b4 = b0+250*b0/251^$FFFF+581*b0+400/979

    That rearranges "a-b" to become "-b+a" and uses an 'invert and add one' to do the two's complement negation of b; "b^$FFFF+1+a". There might even be some scope for further optimisation.

  3. #3
    Senior Member
    Join Date
    Jun 2010
    Location
    Australia
    Posts
    121

    Default

    Your approximation #2 can be refactored to not require an additional temporary variable
    Hippy,

    Your one line implementation of the code is 1 byte shorter and 6% faster than my original two lines of code, plus it allows for the elegance of #DEFINEing the second approximation as a macro. Sensational!

    I've updated my original post to show your version. Thanks for the tip about how to do the two's complement negation.

    Flenser

  4. #4
    Senior Member
    Join Date
    Sep 2011
    Location
    Montpellier (FRANCE)
    Posts
    2,794

    Default ATAN approximation #4

    Slow, but accuracy better than 0,001░ :
    Code:
    #simspeed 10
    
    symbol X=w9
    symbol Y=w10
    symbol T1=w11
    symbol T2=w12
    
    symbol I=b2
    
    eeprom(0,0,60,2,121,4,182,6,242,8,46,11,105,13,164,15,221,17,22,20,78,22,133,24,186,26,238,28,33,31,82,33,130,35,176,37,219,39,5,42,45,44,83,46,119,48,152,50,183,52,212,54,238,56,5,59,26,61,44,63,59,65,71,67,80,69,86,71,90,73,90,75,86,77,80,79,70,81,57,83,41,85,21,87,254,88,227,90,197,92,163,94,126,96,85,98,41,100,248,101,197,103,141,105,82,107,19,109,209,110,138,112,64,114,243,115,161,117,76,119,243,120,151,122,54,124,210,125,107,127,255,128,144,130,30,132,167,133,45,135,176,136,46,138,169,139,33,141,149,142,5,144,114,145,220,146,66,148,164,149,3,151,95,152,183,153,12,155,94,156,172,157,247,158,63,160,131,161,197,162,3,164,62,165,118,166,170,167,220,168,11,170,54,171,95,172,133,173,168,174,200,175,229,176)
    
    
    sertxd("----",13,10)
    for x=0 to 100 step 10   ' ATAN from 0.0000 to 0.0100
    	gosub ATAN1
    	sertxd ("ATAN(",#X,")=",#Y,13,10)
    next X
    
    sertxd(".....",13,10)
    for x=4060 to 4070   ' ATAN from 0.4060 to 0.4070
    	gosub ATAN1
    	sertxd ("ATAN(",#X,")=",#Y,13,10)
    next X
    sertxd(".....",13,10)
    for x=9980 to 10005   ' ATAN from 0.9980 to 1.0000
    	gosub ATAN1
    	sertxd ("ATAN(",#X,")=",#Y,13,10)
    next X
    end
    
    ' Y=ATAN(X)   45░=45000  ATN(45░)=10000
    ATAN1:
          I=X/100*2
          read I,WORD T1
          i=i+2
          read I,WORD T2
          T2=T2-T1
          Y=X//100*T2/100+T1+1
    RETURN
    Accuracy curve :
    Tan_Err.jpg
    There are 10 types of people in the world: those who understand binary, and those who don't.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •