I want to generate a sine signal in C without using the standard function sin() in order to trigger sine shaped changes in the brightness of a LED. My basic idea was to use a lo
...a better idea to implement a sine generator in C?
Edit: Suggest first reading this article to gain an appreciation of what OP is asking.
From the context provided in your question, I am assuming the word better might have to do with size and speed of compiled code, as might be required to run on a small micro-processor.
The CORDIC ( COordinate Rotation DIgital Computer ) algorithm is very suitable for use on smaller uP, and FPGA implementations that have limited mathematical computation capabilities as it computes the sine and cosine of a value using only basic arithmetic (addition, subtraction and shifts). More about CORDIC, and how to use it to produce sine/cosine of an angle are provided here.
There are also several sites that provide algorithm implementation examples. Simple CORDIC is one that includes detailed explanations on how to generate a table that can then be pre-compiled for use on your target device, as well as code to test the output of the following function (which uses fixed point math):
(See documentation of following, and other functions in link)
#define cordic_1K 0x26DD3B6A
#define half_pi 0x6487ED51
#define MUL 1073741824.000000
#define CORDIC_NTAB 32
int cordic_ctab [] = {0x3243F6A8, 0x1DAC6705, 0x0FADBAFC, 0x07F56EA6, 0x03FEAB76, 0x01FFD55B,
0x00FFFAAA, 0x007FFF55, 0x003FFFEA, 0x001FFFFD, 0x000FFFFF, 0x0007FFFF, 0x0003FFFF,
0x0001FFFF, 0x0000FFFF, 0x00007FFF, 0x00003FFF, 0x00001FFF, 0x00000FFF, 0x000007FF,
0x000003FF, 0x000001FF, 0x000000FF, 0x0000007F, 0x0000003F, 0x0000001F, 0x0000000F,
0x00000008, 0x00000004, 0x00000002, 0x00000001, 0x00000000 };
void cordic(int theta, int *s, int *c, int n)
{
int k, d, tx, ty, tz;
int x=cordic_1K,y=0,z=theta;
n = (n>CORDIC_NTAB) ? CORDIC_NTAB : n;
for (k=0; k>31;
//get sign. for other architectures, you might want to use the more portable version
//d = z>=0 ? 0 : -1;
tx = x - (((y>>k) ^ d) - d);
ty = y + (((x>>k) ^ d) - d);
tz = z - ((cordic_ctab[k] ^ d) - d);
x = tx; y = ty; z = tz;
}
*c = x; *s = y;
}
Edit:
I found the documentation for using the examples at the Simple CORDIC site very easy to follow. However, one small thing I ran into was when compiling the file cordic-test.c
the error: use of undeclared identifier 'M_PI' occurred. It appears that when executing the compiled gentable.c
file (which generates the cordic-test.c
file) the line:
#define M_PI 3.1415926535897932384626
although included in its own declarations, was not included in the printf statements used to produce the file cordic-test.c
. Once this was remedied, everything worked as advertised.
As documented, the range of data produced generates 1/4 of a complete sine cycle (-π/2 - π/2 ). The following illustration contains a representation of the actual data produced between the light blue dots. The remainder of the sine signal is fabricated via mirroring and transposing the original data section.