Well I'm trying to implement the function Sin and Cos in VHDL but I have a problem because my FPGA's doesn't works with float numbers and I can't use any kind of math libraries. I did a program in C language to calculate Sin() with the Taylor series aproximation but the question is...how can I translate this program to VHDL? I don't need to calculate exactly the Sin() value...only a relative good value of it. For example: Sin(30º)=0.45 or something like that
Thanks guys for your help! (and sorry for my english...)
#include <iostream>
using namespace std;
int main()
{
int c,square,d, fat, expden;
float x, seno, y;
seno=0;
expden=1; //Value of the exponent
cout <<"Insert value of the angle"<<endl;
cin >>x;
x=x*3.1415/180; //Degree to Rad
for(c=1;c<=5;c++) //Number of iterations
{
fat=1;
for(d=1;d<=expden;d++)
{fat=fat*d;}
y=1;
for(square=1;square<=expden;square++){ //Loop to elevate to square
y=x*y;
}
if(c%2==0)
{seno=seno-(y/fat);
}
else
{seno=seno+(y/fat);
}
expden=expden+2;
}
cout <<"Sinus = ";
cout <<seno<<endl;
system("pause");
return 0;
}
have you thought about using fixed point rather than floating? FPGAs can do floating point, but you have to use IP cores to do it, and they have longer latencies compared to fixed point.
If you only need an appriximate value, I suggest you look into generating a lookup table for the sin and cos values. This is the simplest way of implementing sign and cos. Your address is the X value, and the output of the table is sin(x).
Well, more or less I can understand what you mean...do you have an example? no all the code but something to start...or some link to learn it how can I start? because I'm a little bit lost...sorry and thanks again!
A look-up-table would be the most easy solution. It's usually stored in internal ROM that's available with most FPGA families.
Cordic is another common method, also taylor series can work. You have to translate the C code to a sequential VHDL process, performing one iteration step per clock cycle. This is not achievable with a VHDL for loop.
a quick example - I hope it makes sense. It should generate a rom.
Code:
type sin_table_t is array(-1024 to 1023) of sfixed(0 downto -15);
constant SIN_TABLE : sin_table_t := ( a load of values );
process(clk)
begin
if rising_edge(clk) then
sin_output <= sin_table_t(input_angle)
end if;
end process;
Input angle is an integer that may have to be scaled by 2^n appropriatly. But the output of the table are values in the range -1 to +1
I would also consider a lookup table.
But if you want to use taylor series (and the sine doesn't need to be exact), with a bunch of multipliers, a couple of adders and some dividers, you can do the trick...
sin(x) = x + x^3/6 could give a result close enough (if you known beforehand what angles you're dealing with).
The second formula I wanted to use is cos A = sin(90 - A) for degrees or the equivalent for radians.
A is the coarse angle 0-90 degrees. B is the fraction part of the angle.
For the fraction angle B we don't save any memory with this formula,
so I also use a cosinus table.
This gives the final result for degrees: sin(A + B) = sin A * cos B + sin(90 - A) * sin B
Replace 90 with pi/2 for radians.
Using one table for sin A, one for sin B and one for cos(B) can save a lot of memory. For example, A could be 0.0-89.9 degrees and B could be 0.0000-0.0999 degrees. The total no of memory entries is 2900 and you can have arbitrary precision for sin(X) where X is 0.0000-89.9999
With only 1 table, 900 000 values must be stored.
I wanted to show the basic principle. There are probably smart tricks to reduce the memory usage even more.