Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / fp_math / fp_math.c @ 1602

History | View | Annotate | Download (4.29 KB)

1 1579 justin
#include "fp_math.h"
2
3
#include <avr/pgmspace.h>
4
#include <math.h>
5
#include <serial.h>
6
7
#define ABS(x) (x > 0 ? x : -x)
8 1585 justin
#define FP_PI_OVER_TWO 102944
9
#define FP_TWO_PI 411775
10 1579 justin
11 1585 justin
#define TABLE_LENGTH 64
12 1602 justin
#define TABLE_STEP 1635//.160757
13
#define EXP_MAGICONSTANT 726817 //ln(2^16) * 2^16
14 1579 justin
15 1602 justin
//#define DEBUG
16
17
//TODO This can probably be removed at some point.
18 1579 justin
static int32_t linspace[TABLE_LENGTH] PROGMEM = {
19 1602 justin
        0, 1634, 3268, 4902, 6536, 8170, 9804, 11438,
20
        13072, 14706, 16340, 17974, 19608, 21242, 22876, 24510,
21
        26144, 27778, 29412, 31047, 32681, 34315, 35949, 37583,
22
        39217, 40851, 42485, 44119, 45753, 47387, 49021, 50655,
23
        52289, 53923, 55557, 57191, 58825, 60459, 62093, 63727,
24
        65361, 66995, 68629, 70263, 71897, 73531, 75165, 76799,
25
        78433, 80067, 81701, 83335, 84969, 86603, 88237, 89871,
26
        91506, 93140, 94774, 96408, 98042, 99676, 101310, 102944,
27 1579 justin
};
28
29 1585 justin
static int32_t fp_cos_table[TABLE_LENGTH] PROGMEM = {
30 1602 justin
        65536, 65516, 65455, 65353, 65210, 65027, 64804, 64540,
31
        64237, 63893, 63509, 63087, 62624, 62123, 61584, 61006,
32
        60390, 59736, 59046, 58319, 57555, 56756, 55921, 55052,
33
        54148, 53211, 52241, 51238, 50203, 49138, 48041, 46915,
34
        45760, 44576, 43364, 42126, 40861, 39571, 38256, 36918,
35
        35556, 34173, 32768, 31343, 29898, 28435, 26954, 25456,
36
        23943, 22415, 20872, 19317, 17750, 16171, 14583, 12986,
37
        11380, 9768, 8149, 6525, 4898, 3267, 1634, 0,
38 1579 justin
};
39
40 1585 justin
//FIXME Lazy implementations of tangent and sine.
41
int32_t fp_tan(int32_t theta) {
42
        return fp_div(fp_sin(theta), fp_cos(theta));
43
}
44 1579 justin
45 1585 justin
int32_t fp_sin(int32_t theta) {
46
        return fp_cos(theta + FP_PI_OVER_TWO);
47
}
48
49 1586 justin
int32_t fp_exp(int32_t x) {
50
        //Try with partial fractions for now.
51
        int32_t xsquare = fp_mult(x,x);
52
        int32_t result, i;
53
54 1602 justin
        if(x > EXP_MAGICONSTANT) {
55 1586 justin
                usb_puts("Output value is out of range.\n\r");
56
                return -1;
57
        }
58
59
        //This is again, massive amounts of lazyness.
60
        //The approximation fails outside this range (approximately).
61 1602 justin
        if(x < (-17l << 16))
62 1586 justin
                return 0;
63
64
        result = xsquare;
65 1602 justin
        for(i= (22l << 16); i > (2l << 16); i-= (4l << 16)) {
66 1586 justin
                result += i;
67
                result = fp_div(xsquare, result);
68
        }
69
70 1602 justin
        result += (2l << 16) - x;
71
        return (1l << 16) + fp_div(fp_mult((2l << 16), x), result);
72 1586 justin
73
}
74
75 1579 justin
//Quadratic interpolation.
76
int32_t fp_cos(int32_t theta) {
77
        uint8_t n;
78 1585 justin
        int8_t negative;
79 1579 justin
        int32_t x_n, x_np1, x_np2;
80
        int32_t y_n, y_np1, y_np2;
81 1585 justin
        int32_t dd_n, dd_np1, second_dd, result;
82 1602 justin
83
#ifdef DEBUG
84
        char buf[128];
85
#endif
86
87 1585 justin
        //Move theta into [0, pi/2] w/ appropriate sign.
88
        theta = ABS(theta) % FP_TWO_PI;
89
90 1579 justin
        if(theta > FP_PI)
91
                theta = FP_TWO_PI - theta;
92 1585 justin
93
        if(theta > FP_PI_OVER_TWO) {
94
                theta = FP_PI - theta;
95
                negative = 1;
96
        }
97 1579 justin
98
        //Find the nearest table values. FIXME
99
        n = theta / TABLE_STEP;
100 1602 justin
        while( n < TABLE_LENGTH - 1
101
                && (x_np1 = pgm_read_dword(&linspace[n+1]) < theta))
102 1585 justin
                n++;
103 1579 justin
104
        //theta is between x_{n} and x_{n+1}
105 1602 justin
106 1579 justin
        if(n == TABLE_LENGTH - 1) {
107 1585 justin
                //Perform linear interpolation, since we're close to zero anyway.
108
                x_n = pgm_read_dword(&linspace[TABLE_LENGTH - 1]);
109
                y_n = pgm_read_dword(&fp_cos_table[TABLE_LENGTH - 1]);
110
111 1602 justin
                result = fp_mult(
112
                        fp_div(FP_PI_OVER_TWO - x_n, 0 - y_n), theta - x_n) + y_n;
113
114 1585 justin
                return negative ? -result : result;
115 1579 justin
        }
116 1585 justin
117
        if(n == TABLE_LENGTH) {
118
                //We didn't find a value! Oh no!
119 1602 justin
                usb_puts("fp_math: Fatal! We couldn't find surrounding table values! \n\r");
120
121 1585 justin
                return 0;
122
        }
123 1602 justin
124 1579 justin
        //Address the general case. Quadratic interpolation.
125
        //Load in the necessary values.
126
        x_n = pgm_read_dword(&linspace[n]);
127 1602 justin
        x_np1 = pgm_read_dword(&linspace[n + 1]);
128 1579 justin
        x_np2  = pgm_read_dword(&linspace[n + 2]);
129
130 1585 justin
        y_n = pgm_read_dword(&fp_cos_table[n]);
131
        y_np1 = pgm_read_dword(&fp_cos_table[n + 1]);
132
        y_np2 = pgm_read_dword(&fp_cos_table[n + 2]);
133 1579 justin
134 1602 justin
#ifdef DEBUG
135
        sprintf(buf, "x_n = %ld, theta = %ld, x_{n+1} = %ld", x_n, theta, x_np1);
136
        usb_puts(buf);
137
#endif
138
139 1579 justin
        //Calculate first divided differences.
140
        dd_n = fp_div(y_np1 - y_n, x_np1 - x_n);
141
        dd_np1 = fp_div(y_np2 - y_np1, x_np2 - x_np1);
142
143
        //Calculate the second divided difference.
144
        second_dd = fp_div(dd_np1 - dd_n, x_np2 - x_n);
145
146 1585 justin
        result = fp_mult(fp_mult(second_dd, theta - x_n), theta - x_np1)
147
                           + fp_mult(dd_n, theta - x_n) + y_n;
148
149
        return negative ? -result : result;
150 1579 justin
}
151
152
//FIXME I didn't write these functions very carefully...
153
int32_t fp_mult(int32_t a, int32_t b) {
154
        return (int32_t) (((int64_t)a) * ((int64_t)b)) >>  16;
155
}
156
157
int32_t fp_div(int32_t a, int32_t b) {
158
        return (int32_t) ((int64_t)a << 16) / (int64_t)b;
159
}
160
161