CORDIC Algorithm : Here sine and cos wave generation circuit has been designed and implemented using Verilog HDL using the CORDIC Algorithm
CORDIC Algorithm
The working principle for generation trigonometric signal using cordic algorithm is to decompose required rotation angle (θ) into weighted sum of set of pre-defined elementary rotation angles such that rotation through each of them can be attained by simple shift and add operation instead of complex multiplications.
Here in this post the major objective is to :-
- Generate trigonometric signals like sine and cosine digitally as they come to use in many applications.
- Implement it with a hardware-friendly algorithm that is less complex and carries less number of multiplication, which can be done through the CORDIC algorithm.
Cartesian Coordinate Plane Rotations :The standard method of rotating a point (x1, y1) by θ degrees in the xy plane to a point is given by the well known equations:
x2 = x1cosθ − y1sinθ
y2 = x1sinθ + y1cosθ
Let the angle the point rotated or a phase shift to be 90 degrees. That implies the values of sinθ = 1 and cosθ = 0
The CORDIC Method
To pseudo rotate vector according to the above equations multipliers are needed and that makes the calculations and circuit quite complex.
So here is where the CORDIC comes into picture, where one only needs to select angles at those tan function becomes exponents of 2 so that instead of multiplication simple shift and add would be sufficient.
x2 = x1 − y12−i
y2 = y1 + x12−i
At this stage we alter the transform to become an iterative algorithm. We restrict the angles that we are able to rotate by, such that to rotate by an arbitrary requires a series of successively smaller rotations at each iteration i.
The rotation angles obey the law : tanθi = 2−i.
Obeying this law causes the multiplication by the tangent term to become a shift.
Angle accumulator
Now the angle required would be achieved in an iterative manner by adding and subtracting the predefined angles that obey above mentioned law.
The equations can be rewritten for each iteration as follows:
xˆi+1 = xi − di
(y12−i)
yˆi+1 = yi − di
(x12−i)
At this stage a new equation is introduced called the Angle Accumulator which is used to keep track of the accumulative angle rotated at each iteration
zi+1 = zi − di(θi) ,
Here di = +/-1. The symbol di is a decision operator and is used to decide which direction to rotate.
Signal Flow
Angle Values
A look up table has to be developed with the predefined set of angles that obeys the rule of tangent function in exponents of 2.
The table below shows the rotation angles that can be used for each iteration (i) of the CORDIC algorithm:
i | θi (in degrees ) | tan θi = 2-i | cos θi |
---|---|---|---|
0 | 45.0 | 1 | 0.707106781 |
1 | 26.555051177 | 0.5 | 0.894427191 |
2 | 14.036243467 | 0.25 | 0.9701425 |
3 | 7.125016348 | 0.125 | 0.992277877 |
4 | 3.576334374 | 0.0625 | 0.998052578 |
5 | 1.789906082 | 0.03125 | 0.999512076 |
6 | 0.8951797102 | 0.015625 | 0.999877952 |
7 | 0.4476141709 | 0.0078125 | 0.999969484 |
8 | 0.2238105004 | 0.00390625 | 0.9999992371 |
9 | 0.1119056771 | 0.001953125 | 0.999998093 |
10 | 0.0559528919 | 0.000976563 | 0.999999523 |
11 | 0.0279764526 | 0.00048821 | 0.999999881 |
12 | 0.0139882271 | 0.000244141 | 0.999999997 |
. | . | . | . |
. | . | . | . |
. | . | . | . |
. | . | . | . |
Verilog Code
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: alljobs.co.in
// Engineer: Team ( alljobs.co.in )
// Design Name: CORDIC algorithm in Verilog for sine & cos wave generation
// Module Name: CORDIC
// Project Name: CORDIC algorithm in Verilog for sine & cos wave generation
// Language Used : Verilog HDL.
// Description: Here Cordic algorithm have been used to design and simulate the sine and cos wave generation circuit.
//////////////////////////////////////////////////////////////////////////////////
module CORDIC(clock,angle,Xin,Yin,Xout,Yout);
parameter XY_SZ = 16;
localparam STG = XY_SZ;
input clock;
input signed [31:0] angle;
input signed [XY_SZ-1:0] Xin;
input signed [XY_SZ-1:0] Yin;
output signed [XY_SZ:0] Xout;
output signed [XY_SZ:0] Yout;
wire signed [31:0] atan_table [0:30];
assign atan_table[00] = 32'b00100000000000000000000000000000;
assign atan_table[01] = 32'b00010010111001000000010100011101;
assign atan_table[02] = 32'b00001001111110110011100001011011;
assign atan_table[03] = 32'b00000101000100010001000111010100;
assign atan_table[04] = 32'b00000010100010110000110101000011;
assign atan_table[05] = 32'b00000001010001011101011111100001;
assign atan_table[06] = 32'b00000000101000101111011000011110;
assign atan_table[07] = 32'b00000000010100010111110001010101;
assign atan_table[08] = 32'b00000000001010001011111001010011;
assign atan_table[09] = 32'b00000000000101000101111100101110;
assign atan_table[10] = 32'b00000000000010100010111110011000;
assign atan_table[11] = 32'b00000000000001010001011111001100;
assign atan_table[12] = 32'b00000000000000101000101111100110;
assign atan_table[13] = 32'b00000000000000010100010111110011;
assign atan_table[14] = 32'b00000000000000001010001011111001;
assign atan_table[15] = 32'b00000000000000000101000101111101;
assign atan_table[16] = 32'b00000000000000000010100010111110;
assign atan_table[17] = 32'b00000000000000000001010001011111;
assign atan_table[18] = 32'b00000000000000000000101000101111;
assign atan_table[19] = 32'b00000000000000000000010100011000;
assign atan_table[20] = 32'b00000000000000000000001010001100;
assign atan_table[21] = 32'b00000000000000000000000101000110;
assign atan_table[22] = 32'b00000000000000000000000010100011;
assign atan_table[23] = 32'b00000000000000000000000001010001;
assign atan_table[24] = 32'b00000000000000000000000000101000;
assign atan_table[25] = 32'b00000000000000000000000000010100;
assign atan_table[26] = 32'b00000000000000000000000000001010;
assign atan_table[27] = 32'b00000000000000000000000000000101;
assign atan_table[28] = 32'b00000000000000000000000000000010;
assign atan_table[29] = 32'b00000000000000000000000000000001;
assign atan_table[30] = 32'b00000000000000000000000000000000;
reg signed [XY_SZ:0] X [0:STG-1];
reg signed [XY_SZ:0] Y [0:STG-1];
reg signed [31:0] Z [0:STG-1];
wire [1:0] quadrant;
assign quadrant = angle[31:30];
always @(posedge clock)
begin
case (quadrant)
2'b00,
2'b11:
begin
X[0] <= Xin;
Y[0] <= Yin;
Z[0] <= angle;
end
2'b01:
begin
X[0] <= -Yin;
Y[0] <= Xin;
Z[0] <= {2'b00,angle[29:0]};
end
2'b10:
begin
X[0] <= Yin;
Y[0] <= -Xin;
Z[0] <= {2'b11,angle[29:0]};
end
endcase
end
genvar i;
generate
for (i=0;i<(STG-1);i=i+1)
begin: XYZ
wire Z_sign;
wire signed [XY_SZ:0] X_shr,Y_shr;
assign X_shr = X[i] >>> i;
assign Y_shr = Y[i] >>> i;
assign Z_sign = Z[i][31];
always @(posedge clock)
begin
X[i+1] <= Z_sign ? X[i] + Y_shr : X[i] - Y_shr;
Y[i+1] <= Z_sign ? Y[i] - X_shr : Y[i] + X_shr;
Z[i+1] <= Z_sign ? Z[i] + atan_table[i] : Z[i] - atan_table[i];
end
end
endgenerate
assign Xout = X[STG-1];
assign Yout = Y[STG-1];
endmodule
//Testbecnch for CORDIC algorithm
module tb;
reg clock;
reg signed [31:0] angle;
reg signed [31:0] Xin;
reg signed [15:0] Yin;
wire signed [16:0] Xout;
wire signed [16:0] Yout;
CORDIC c1(clock,angle,Xin,Yin,Xout,Yout);
initial
begin
clock =1'b0;
forever #10 clock = ~clock;
end
initial
begin
angle = 32'd35;
Xin = 16'd32;
Yin = 16'd36;
end
endmodule