I've been learning how CORDIC algorithms work to calculate SIN() and COS(), once you have the precomputed table it just uses bitshifts, additions and subtractions.
It's so I can make a 24-bit DDS for experimenting with my CS4434 I2S DAC board with an FPGA. Yes, I know I can do it easier, but it is a hobby learning project...
I must say, it is pretty nifty! What I really like is that you don't have to have the input angle in radians or degrees, you can have it in anything you like. It will tie up really nice with a binary phase accumulator.
Code is for calculating a sin() or cos() for the first quadrant (0 -> PI/2), just to make sure I understand the algorithm and checking the number of repetitions and bits required:
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#define PI (3.14159265358979323846)
#define FULL_CIRCLE (2.0*PI)
#define EIGHTH_CIRCLE (FULL_CIRCLE/8)
#define CORDIC_REPS (27)
#define BITS (30)
int64_t initial;
double angles[CORDIC_REPS];
/****************************************************************
* Calculate the values required for CORDIC sin()/cos() function
***************************************************************/
void setup(void) {
int i;
double scale = 1.0;
for(i = 0; i < CORDIC_REPS; i++ ) {
angles[i] = atan(1.0/pow(2,i+1));
scale *= cos(angles[i]);
}
initial = (int64_t)(pow(0.5,0.5)*scale*pow(2.0,BITS)+0.5);
}
/***************************************************************
* Cordic routine to calculate Sine and Cosine for angles
* from 0.0 to a little over PI/2
**************************************************************/
void cordic_sine_cosine(double z, int64_t *s, int64_t *c) {
int i;
int64_t x = initial,y = initial;
z -= EIGHTH_CIRCLE;
for(i = 0; i < CORDIC_REPS; i++ ) {
int64_t tx = (x + (1<<i)) >> (i+1);
int64_t ty = (y + (1<<i)) >> (i+1);
x -= (z > 0 ? ty : -ty);
y += (z > 0 ? tx : -tx);
z -= (z > 0 ? angles[i] : -angles[i]);
}
*c = x;
*s = y;
}
/**************************************************************/
int main(int argc, char *argv[]) {
double a = 0.8;
int64_t sll, cll;
setup();
for(a = 0; a <= PI/2; a += PI/40) {
double s,c;
cordic_sine_cosine(a, &sll, &cll);
s = sll / pow(2,BITS);
c = cll / pow(2,BITS);
printf("Computed sin(%11.8f), cos(%11.8f), ", s, c);
printf("error %11.8f & %11.8f\n",s-sin(a), c-cos(a));
}
return 0;
}
/**************************************************************/