Announcement

Collapse
No announcement yet.

Arc tangent function

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    Very cool.
    In addition, I turn off T0 (millis and delay) for the time counting, nothing interferes with the measurement.
    Once I came across an Arduino board with 328BP from Pololu called 'A Star' has 2 additional 16b timers - T3 and T4, in the size of 1/2 Nano.

    Comment


    • #17
      A few thoughts from someone with modest maths skills:

      Calculating arctan(x) usually seems to be really difficult, taking loads of CPU time. Splitting it into several 'zones', dependant on x, and treating each differently is the smartest way. I recall Fishers F75 splits it into 3 sections.

      For small values of x , the simplest approximation is based on the well-known sin(x) = tan(x) = x.
      So arctan(x) = x , a pretty easy one, OK up to 0.25 radians, and if you add a fiddle-factor:
      arctan (x) = 0.95 x ; is OK to 0.4 radians
      Beyond simple linear straight-line functions, the next step is Pade approximations, these are based on polynomials ( Pade has an acute e, I can't get it to work on here ).
      A simple one is:
      arctan (x) = 3x / (x2 +3)
      or with tweaking:
      arctan = 3.06x / ( x2 +3) , good from 0 to 0.7 radians ( about 40 degrees )

      A more exotic Pade approximation is:
      arctan(x) = ( 55x3 + 105x ) / ( 9x4 + 90x2 + 105 )

      Looks ugly, but it's simple multiplication etc, and good from 0 to 1.05 radians ( 60 degrees )

      The problem with the Pade approximations is they fail really badly for larger x values, kinda disappointing.

      However, there is one family of approximations ( by Shafer ) that are really good for the entire 0 to pi/2 ( 90 degrees ):

      BUT ... they use a square-root, which also sucks CPU power, it just depends on the algorithm used, I guess.

      The 'Shafer' approximation is:

      arctan (x) = 8x / ( 3 + sqrt ( 25 + 25.94 x2 ))

      ( the 25.94 is actually (16/pi)2 )

      It works for large x values, and converges at the correct pi/2 ( 90 degrees ), it's just slightly out in the 70 - 80 degrees area, but otherwise its a great approximation.

      I guess you would need to try these out to evaluate them properly.

      Maths References:

      Pade approximations:
      https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5285437/
      https://www.ncbi.nlm.nih.gov/pmc/art...ort=objectonly

      and Shafer approximations:
      https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6010512/

      Comment


      • #18
        The old time coders here might remember the CORDIC algorithm for doing trig including arc tan on limited microprocessors and early computers. Iteratively it has precision to any required number of decimal places and uses minimal memory resources.
        you can google the solution :-)

        eg

        https://github.com/MartinStokroos/fastCORDIC
        moodz.

        Comment


        • #19
          There's another decent approximation that uses fractional powers. Again, it may be a bad choice for a micro.
          I've seen it used in analogue math circuits, based around multiplier/divider IC's that use log cells. Fractional powers are not complex to do with those devices.

          The formula is:

          arctan (x) = pi/2 * x1.2125 / ( 1 + x1.2125 )

          As x gets progressively larger, the function moves towards the correct pi/2 ( 90 degrees )

          A really simple formula that works at 90 degrees, and at zero degrees, and is acceptable inbetween, is:

          arctan (x) = 1.59 * x / (x+1)

          It has to be the easiest approximation, even if it's 3 or 4 degrees out in the 60 to 80 degrees range.

          Comment


          • #20
            ...
            Last edited by ivconic; 01-12-2023, 07:00 PM.

            Comment


            • #21
              ...
              Last edited by ivconic; 01-12-2023, 07:00 PM.

              Comment


              • #22
                Originally posted by Skippy View Post
                A really simple formula that works at 90 degrees, and at zero degrees, and is acceptable inbetween, is:

                arctan (x) = 1.59 * x / (x+1)

                It has to be the easiest approximation, even if it's 3 or 4 degrees out in the 60 to 80 degrees range.
                I think this is how a lot of detectors do it. You can imagine a straight line from 0° to 90° with a unity slope and that passes through an x-y value. The phase is then y/(x+y)*90°.



                The approximation is perfect at 0, 45, & 90° and has a max error of about 4° otherwise. In the plot above the vector is actually 30° but calculates to 33°. You could then use a lookup table to further correct if that's important. The error plot looks like this:



                You can also create another line for negative values of x. In a real detector I like to place 0° on the left axis and 180° on the right, and label the signals X & R instead of x & y so the diagram and equations look like this:



                In code you simply do this:

                Code:
                if(X<0)
                  phase = 90*R/(R-X);
                else
                  phase = 90*(R+X<<1)/(R+X);
                This requires a division so you still need to watch processor overhead.

                Some TR and analog VLF designs did effectively the same thing using a potentiometer connected between the X & R demods to select a discrimination threshold point. It was a linearized selection and the disc knob was labeled as needed to make the selection match reality.
                Attached Files
                Last edited by Carl-NC; 01-29-2023, 05:47 PM.

                Comment


                • #23
                  My earlier post dealt with some arctan approximations that were good for smaller angles, 0 up to near 60 degrees. As part of a scheme to split the atn function approximation into 2 (or 3) sections, what's needed is good approximations for large x values. These have to be correct at x = infinity, where atn (x) = pi/2 ( 90 degrees ). Functions of the form arctan(x) = pi/2 + a correction term are what's needed.
                  Based on a simple polynomial expansion, one very easy approximation is:

                  arctan(x) = pi/2 - 1/x

                  this is OK from 65 to 90 degrees, and tweaking it to:

                  arctan(x) = pi/2 - 0.95/x

                  can make it fit down to 60 degrees pretty well.

                  A better approximation (derived from a fast-converging expansion for the arccot(x) function) is:

                  arctan(x) = pi/2 - 4x /(4x2 + 1)

                  This is pretty decent, accurate down to about 50 degrees. With a few tweaks, it can be made good to below 45 degrees:

                  arctan(x) = pi/2 - 4x /(4.07x2 + 1)

                  This then allows the full 0 to 90 degrees range to be approximated accurately in just 2 sections.

                  Taking the small-value formula: arctan(x) = 3x / (x2 + 3) ( see previous post ) and fiddling with the coefficients, it can be made to match up extremely well to the above large-value expression:

                  arctan(x) = 3.016x /(0.87x2 +3)

                  They match up at x = 0.9 , where both have zero error.

                  Summary:

                  If x < 0.9 use:

                  arctan(x) = 3.016x /(0.87x2 +3)

                  and if x > 0.9 use:

                  arctan(x) = pi/2 - 4x /(4.07x2 + 1)

                  The maximum error for this combination is about 0.3 degrees ( when x = 0.6 and 1.2 roughly ) which is very good.

                  I plotted the two functions on DESMOS, see attached image. Atn(x) is not shown as it just sits perfectly on top of the other two lines.



                  Attached Files

                  Comment


                  • #24
                    After a bit more playing around with the 'Desmos' program, I've come up with some more accurate approximations to arctan(x).
                    Choosing the transition point between the 'low value' approximation and the 'high value' one is tricky, but most other methods seem to choose x=1 ( ie. 45 degrees ) as the transition.
                    I readjusted the formulae in the previous post to an x=1 transition, and came up with:

                    For x < 1 use:

                    arctan(x) = 3.8877x / ( x2 + 3.78 )

                    and for x above 1, use:

                    arctan(x) = pi/2 - 0.9841x / ( x2 + 0.253 )

                    Both of these have matching errors, of < 0.16 degrees. This is half the error of the previous post. Neat.
                    An error plot for the two approximations is attached.

                    I had another rummage around the Web and found an approximation for the x < 1 case that doesn't use a division, only multiplication. It's a cubic equation:

                    arctan(x) = (pi/4)x - x( x-1 )( 0.0663x + 0.2447 )

                    which can be rearranged to:

                    arctan(x) = 0.0663x (11.846 - ( x-1 )( x + 3.691 ))

                    The maximum error is just 0.09 degrees, error plot is attached below.​
                    Attached Files

                    Comment

                    Working...
                    X