problem with lookup sine table

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Pallav

    #1

    problem with lookup sine table

    i'm trying to build a lookup sine table to run some code in an
    embedded processor without floating point unit. the table is 256
    values for 360 degrees.

    my code is below. the fixed point base is 22.10.

    what i'm seeing is that the code seems to work for small integers say
    (-10 - 10), assuming the value is in radians. however as you go up, to
    large integers there is significant mismatch in the LUT and what the
    sin() function returns.

    i'm not sure what the problem is. i thought it could have been
    overflow or i'm not performing the right conversion during lookup.
    however, i seem to be convinced that i'm not running into either
    problem and i'm somewhat stuck.

    can anyone point out what is going wrong? the full code is below, the
    code to generate the sin table is alwso below. it should compile and
    the test program will exit if the difference is greater than 10%.

    thanks
    pallav

    /* fixed.h*/

    /*
    * Fixed Point Arithmetic for 18.14 format
    */

    #ifndef FIXED_H
    #define FIXED_H

    typedef long fp14;

    #define DEGREES 0xFF
    /* THIS WILL GIVE ABOUT 3 DECIMAL DIGITS OF PRECISION */
    #define FRACTION 10

    #define FP_EXP FLOAT2FP(2.7182 8)
    #define FP_ONE INT2FP(1)
    #define MY_PI 3.141592654
    #define FP_PI FLOAT2FP(MY_PI)
    #define FP_MAGIC FLOAT2FP(40.72) // 256/2*pi


    #define FPMAX(a,b) (((a) > (b)) ? (a) : (b))
    #define FPMIN(a,b) (((a) < (b)) ? (a) : (b))
    #define FPABS(a,b) (((a) < 0) ? -(a) : (a))
    #define FPSIGN(a) (((a) < 0) ? -1 : (a) > 0 ? 1 : 0)


    /* CONVERSTION UTILITIES */
    #define INT2FP(a) ((a) << FRACTION)
    #define FP2INT(a) ((a) >> FRACTION)
    #define FPFRACT(a) ((a) & 0x3FF)
    #define FP2FLOAT(a) (((double) (a)) / (1 << FRACTION))
    #define FLOAT2FP(a) ((fp14) (a * (1 << FRACTION)))


    /* ARITHMETIC FUNCTIONS */
    #define FPADD(a1,a2) ((a1) + (a2))
    #define FPSUB(a1,a2) ((a1) - (a2))
    #define FPMUL(a1,a2) ((fp14) ((((long long int) a1) * ((long long int)
    a2)) >> FRACTION))
    #define FPDIV(a1,a2) (FLOAT2FP(FP2FL OAT(a1)/FP2FLOAT(a2)))

    /* SQUARE ROOT OF X^2 + Y^2 */
    #define FPHYPOT(a1,a2) (FPSQRT(FPADD(F PMUL(a1,a1), FPMUL(a2,a2))))

    /* SQUARE ROOT OF X^2 - Y^2 */
    #define FPHYPOTDIFF(a1, a2) (FPSQRT(FPSUB(F PMUL(a1,a1), FPMUL(a2,a2))))


    /* TRIGNOMETRIC FUNCTIONS */
    #define FPSIN(a) (sine[(a) & DEGREES])
    #define FPCOS(a) (cosine[(a) & DEGREES])
    #define FPATAN(a) (invtan[(a) & DEGREES])

    extern long sine[];
    //extern long cosine[];
    //extern long invtan[];

    extern fp14 FPSQRT(fp14 a1);
    extern fp14 FPEXP(fp14 a1);

    #endif /* FIXED_H */

    ---------------------------------
    /* fixed.c */

    #include "fixed.h"

    long sine[] =
    {
    0, 25, 50, 75, 100, 125, 150, 175,
    200, 225, 249, 274, 298, 322, 346, 369,
    393, 416, 439, 462, 484, 506, 528, 549,
    570, 591, 612, 632, 651, 671, 689, 708,
    726, 743, 760, 777, 793, 809, 824, 839,
    853, 867, 880, 893, 905, 916, 927, 938,
    947, 957, 965, 973, 981, 988, 994, 1000,
    1005, 1009, 1013, 1016, 1019, 1021, 1023, 1023,
    1023, 1023, 1022, 1020, 1018, 1015, 1011, 1007,
    1002, 997, 991, 984, 977, 969, 961, 952,
    943, 932, 922, 910, 899, 886, 873, 860,
    846, 832, 817, 801, 785, 769, 752, 735,
    717, 699, 680, 661, 641, 622, 601, 581,
    560, 539, 517, 495, 473, 450, 427, 404,
    381, 358, 334, 310, 286, 261, 237, 212,
    188, 163, 138, 113, 88, 63, 37, 12,
    -12, -37, -63, -88, -113, -138, -163, -188,
    -212, -237, -261, -286, -310, -334, -358, -381,
    -404, -427, -450, -473, -495, -517, -539, -560,
    -581, -601, -622, -641, -661, -680, -699, -717,
    -735, -752, -769, -785, -801, -817, -832, -846,
    -860, -873, -886, -899, -910, -922, -932, -943,
    -952, -961, -969, -977, -984, -991, -997, -1002,
    -1007, -1011, -1015, -1018, -1020, -1022, -1023, -1023,
    -1023, -1023, -1021, -1019, -1016, -1013, -1009, -1005,
    -1000, -994, -988, -981, -973, -965, -957, -947,
    -938, -927, -916, -905, -893, -880, -867, -853,
    -839, -824, -809, -793, -777, -760, -743, -726,
    -708, -689, -671, -651, -632, -612, -591, -570,
    -549, -528, -506, -484, -462, -439, -416, -393,
    -369, -346, -322, -298, -274, -249, -225, -200,
    -175, -150, -125, -100, -75, -50, -25, };


    /* SQUARE ROOT OPERATION: NOTE: a1 must be <= 0; no checks done */
    fp14 FPSQRT(fp14 a1)
    {
    long root = 0, val1, val2, rem;
    int i;

    rem = a1;
    for (i = 0; i <= 30; i += 2) {
    val1 = (0x40000000L >> i);
    val2 = val1 + root;
    root >>= 1;
    if (val2 <= rem) {
    rem -= val2;
    root |= (val1);
    }
    }

    /* cut the error in half by rounding */
    if (root < rem)
    root++;

    /* need to shift left 5 bits because FRACTION = 10 */
    root <<= 5;

    return ((fp14) root);
    }




    /* E^(x) - GIVES GOOD RESULTS ONLY FOR X in -3 to 3. SHOULD BE GOOD
    ENOUGH
    FOR FINGERPRINT COMPUTATIONS */
    fp14 FPEXP(fp14 a)
    {
    int i;
    fp14 prod, fact, approx, count;

    count = FP_ONE;
    fact = FP_ONE;
    approx = FPADD(a, fact);
    prod = a;

    /* Use Taylor Series. Note only 11 terms are used for the
    approximation
    because 10! exceeds the amount of space we have to store the
    integer */
    for (i = 2; i <= 9; i++) {
    count = FPADD(count, FP_ONE);
    fact = FPMUL(fact, count);
    prod = FPMUL(prod, a);
    approx = FPADD(approx, FPDIV(prod,fact ));
    }

    return approx;
    }
    ---------------------------

    /* test program */
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>

    #include "fixed.h"

    int main(int argc, char **argv)
    {
    int u;
    fp14 fpnx;
    double lut, orig;
    printf("%.6f\n" , FP2FLOAT(FP_MAG IC));
    for (u = 0; ; u += 10) {
    fpnx = INT2FP(u);
    fpnx = FPMUL(fpnx, FP_MAGIC);
    lut = FP2FLOAT(FPSIN( FP2INT(fpnx)));
    orig = sin(u);

    if (fabs(lut - orig) > 0.10) {
    printf("at iteration u= %d values differ more than 10%. not
    good\n", u);
    exit (0);
    }

    printf("%d %f %f %f\n", u, FP2FLOAT(fpnx), lut, orig);
    }

    return 0;
    }
    ----------------
    /* code to generate sin table */
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>

    #include "fixed.h"

    int main(void)
    {
    int i, j;
    double angle;
    double sine;
    long isine;
    double pi = 3.141592654;
    double delta = (double) DEGREES / (2 * pi);

    printf("long sine[] =\n");
    printf("{\n");
    for (i = 0, j = 1; i < DEGREES; i++, j++)
    {
    angle = (double) (i/delta);
    sine = sin(angle);
    printf("%6d, ", FLOAT2FP(sine)) ;
    if (j > 7)
    {
    j = 0;
    printf("\n");
    }
    }
    printf("};\n");

    return 0;
    }
Working...