CORDIC(Coordinate Rotation Digital Computer)是坐标旋转数字计算机算法的简称。主要用于解决三角函数、反三角函数和开方等运算。该算法最终可以分解为一系列的加减和移位操作。
可分为三个系统,每个系统又含有两个模式:
具体的原理细节,就不在这里一一讲述了,具体代码如下:
由于前一个模块算出的结果是无符号数的角度,所以要做象限处理,以及符号化
//不清楚角度是在第几象限,所以要先对角度进行象限处理,
//CORDIC算法求三角函数,只能是求第一象限和第四象限,所以要把角度换算到这两个象限
module cordic(
input clk,
input rst_n,
input [12:0] phi_pre,
// input start,
output reg flag_done,
output signed [16:0] sin_phi,
output signed [16:0] cos_phi
);
//--------对角度进行预处理------------
//输入角度值是(0~2π)
parameter ANGLE_90 = 13'd90;
parameter ANGLE_180 = 13'd180;
parameter ANGLE_270 = 13'd270;
parameter ANGLE_0 = 13'd0;
reg [12:0]phi; //处理后的角度
reg [2:0] quadrant; //判断象限
/* always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
phi <= 13'd0;
quadrant <= 3'b0;
end
else if(start) begin
if(phi_pre >= ANGLE_0 && phi_pre <= ANGLE_90) begin
phi <= phi_pre;
quadrant <= 3'b1;
end
else if(phi_pre >= ANGLE_90 && phi_pre <= ANGLE_180) begin
phi <= phi_pre - ANGLE_90;
quadrant <= 3'd2;
end
else if(phi_pre >= ANGLE_180 && phi_pre <= ANGLE_270) begin
phi <= phi_pre - ANGLE_180;
quadrant <= 3'd3;
end
else begin
phi <= phi_pre - ANGLE_270;
quadrant <= 3'd4;
end
end
else begin
phi <= 13'd0;
quadrant <= 3'b0;
end
end */
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
phi <= 13'd0;
quadrant <= 3'b0;
end
else if(phi_pre >= ANGLE_0 && phi_pre <= ANGLE_90) begin
phi <= phi_pre;
quadrant <= 3'b1;
end
else if(phi_pre >= ANGLE_90 && phi_pre <= ANGLE_180) begin
phi <= phi_pre - ANGLE_90;
quadrant <= 3'd2;
end
else if(phi_pre >= ANGLE_180 && phi_pre <= ANGLE_270) begin
phi <= phi_pre - ANGLE_180;
quadrant <= 3'd3;
end
else begin
phi <= phi_pre - ANGLE_270;
quadrant <= 3'd4;
end
end
reg [2:0] quadrant_rr;
reg signed [31:0] phi_w;
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
phi_w <= 'd0;
quadrant_rr <= 'd0;
end
else begin
phi_w <= {19'b0,phi};
quadrant_rr <= quadrant;
end
end
parameter ANGLE_1 = 32'd2949120; //45度*2^16
parameter ANGLE_2 = 32'd1740992; //26.5651度*2^16
parameter ANGLE_3 = 32'd919872 ; //14.0362度*2^16
parameter ANGLE_4 = 32'd466944 ; //7.1250度*2^16
parameter ANGLE_5 = 32'd234368 ; //3.5763度*2^16
parameter ANGLE_6 = 32'd117312 ; //1.7899度*2^16
parameter ANGLE_7 = 32'd58688 ; //0.8952度*2^16
parameter ANGLE_8 = 32'd29312 ; //0.4476度*2^16
parameter ANGLE_9 = 32'd14656 ; //0.2238度*2^16
parameter ANGLE_10 = 32'd7360 ; //0.1119度*2^16
parameter K = 17'h0_9b74; //K=0.607253*2^16,16'h9b74,
reg signed [16:0] x_r [10:0];
reg signed [16:0] y_r [10:0];
reg signed [31:0] angle_remain [10:0];
reg [3:0] quadrant_r [11:0];
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
x_r[0] <= 17'sd0;
y_r[0] <= 17'sd0;
angle_remain[0] <= 32'sd0;
end
else begin
x_r[0] <= K;
y_r[0] <= 17'sd0;
angle_remain[0] <= phi_w<<<16;
end
end
//第一次旋转
always @ (posedge clk or negedge rst_n) begin
/* if(!rst_n) begin
x_r[1] <= 16'sd0;
y_r[1] <= 16'sd0;
angle_remain[1] <= 32'sd0;
end
else */if(angle_remain[0] > 32'sd0) begin
x_r[1] <= x_r[0] - y_r[0];
y_r[1] <= y_r[0] + x_r[0];
angle_remain[1] <= angle_remain[0] - ANGLE_1;
end
else begin
x_r[1] <= x_r[0] + y_r[0];
y_r[1] <= y_r[0] - x_r[0];
angle_remain[1] <= angle_remain[0] + ANGLE_1;
end
end
//第二次旋转
always @(posedge clk or negedge rst_n) begin
/* if(!rst_n) begin
x_r[2] <= 16'sd0;
y_r[2] <= 16'sd0;
angle_remain[2] <= 32'sd0;
end
else */if(angle_remain[1] > 32'sd0) begin
x_r[2] <= x_r[1] - (y_r[1]>>>1);
y_r[2] <= y_r[1] + (x_r[1]>>>1);
angle_remain[2] <= angle_remain[1] - ANGLE_2;
end
else begin
x_r[2] <= x_r[1] + (y_r[1]>>>1);
y_r[2] <= y_r[1] - (x_r[1]>>>1);
angle_remain[2] <= angle_remain[1] + ANGLE_2;
end
end
//第三次旋转
always @(posedge clk or negedge rst_n) begin
/* if(!rst_n) begin
x_r[3] <= 16'sd0;
y_r[3] <= 16'sd0;
angle_remain[3] <= 32'sd0;
end
else */if(angle_remain[2] > 32'sd0) begin
x_r[3] <= x_r[2] - (y_r[2]>>>2);
y_r[3] <= y_r[2] + (x_r[2]>>>2);
angle_remain[3] <= angle_remain[2] - ANGLE_3;
end
else begin
x_r[3] <= x_r[2] + (y_r[2]>>>2);
y_r[3] <= y_r[2] - (x_r[2]>>>2);
angle_remain[3] <= angle_remain[2] + ANGLE_3;
end
end
//第四次旋转
always @(posedge clk or negedge rst_n) begin
/* if(!rst_n) begin
x_r[4] <= 16'sd0;
y_r[4] <= 16'sd0;
angle_remain[4] <= 32'sd0;
end
else */ if(angle_remain[3] > 32'sd0) begin
x_r[4] <= x_r[3] - (y_r[3]>>>3);
y_r[4] <= y_r[3] + (x_r[3]>>>3);
angle_remain[4] <= angle_remain[3] - ANGLE_4;
end
else begin
x_r[4] <= x_r[3] + (y_r[3]>>>3);
y_r[4] <= y_r[3] - (x_r[3]>>>3);
angle_remain[4] <= angle_remain[3] + ANGLE_4;
end
end
//第五次旋转
always @(posedge clk or negedge rst_n) begin
/* if(!rst_n) begin
x_r[5] <= 16'sd0;
y_r[5] <= 16'sd0;
angle_remain[5] <= 32'sd0;
end
else */if(angle_remain[4] > 32'sd0) begin
x_r[5] <= x_r[4] - (y_r[4]>>>4);
y_r[5] <= y_r[4] + (x_r[4]>>>4);
angle_remain[5] <= angle_remain[4] - ANGLE_5;
end
else begin
x_r[5] <= x_r[4] + (y_r[4]>>>4);
y_r[5] <= y_r[4] - (x_r[4]>>>4);
angle_remain[5] <= angle_remain[4] + ANGLE_5;
end
end
//第6次旋转
always @(posedge clk or negedge rst_n) begin
/* if(!rst_n) begin
x_r[6] <= 16'sd0;
y_r[6] <= 16'sd0;
angle_remain[6] <= 32'sd0;
end
else */if(angle_remain[5] > 32'sd0) begin
x_r[6] <= x_r[5] - (y_r[5]>>>5);
y_r[6] <= y_r[5] + (x_r[5]>>>5);
angle_remain[6] <= angle_remain[5] - ANGLE_6;
end
else begin
x_r[6] <= x_r[5] + (y_r[5]>>>5);
y_r[6] <= y_r[5] - (x_r[5]>>>5);
angle_remain[6] <= angle_remain[5] + ANGLE_6;
end
end
//第7次旋转
always @(posedge clk or negedge rst_n) begin
/* if(!rst_n) begin
x_r[7] <= 16'sd0;
y_r[7] <= 16'sd0;
angle_remain[7] <= 32'sd0;
end
else */if(angle_remain[6] > 32'sd0) begin
x_r[7] <= x_r[6] - (y_r[6]>>>6);
y_r[7] <= y_r[6] + (x_r[6]>>>6);
angle_remain[7] <= angle_remain[6] - ANGLE_7;
end
else begin
x_r[7] <= x_r[6] + (y_r[6]>>>6);
y_r[7] <= y_r[6] - (x_r[6]>>>6);
angle_remain[7] <= angle_remain[6] + ANGLE_7;
end
end
//第8次旋转
always @(posedge clk or negedge rst_n) begin
/* if(!rst_n) begin
x_r[8] <= 16'sd0;
y_r[8] <= 16'sd0;
angle_remain[8] <= 32'sd0;
end
else */if(angle_remain[7] > 32'sd0) begin
x_r[8] <= x_r[7] - (y_r[7]>>>7);
y_r[8] <= y_r[7] + (x_r[7]>>>7);
angle_remain[8] <= angle_remain[7] - ANGLE_8;
end
else begin
x_r[8] <= x_r[7] + (y_r[7]>>>7);
y_r[8] <= y_r[7] - (x_r[7]>>>7);
angle_remain[8] <= angle_remain[7] + ANGLE_8;
end
end
//第9次旋转
always @(posedge clk or negedge rst_n) begin
/* if(!rst_n) begin
x_r[9] <= 16'sd0;
y_r[9] <= 16'sd0;
angle_remain[9] <= 32'sd0;
end
else */if(angle_remain[8] > 32'sd0) begin
x_r[9] <= x_r[8] - (y_r[8]>>>8);
y_r[9] <= y_r[8] + (x_r[8]>>>8);
angle_remain[9] <= angle_remain[8] - ANGLE_9;
end
else begin
x_r[9] <= x_r[8] + (y_r[8]>>>8);
y_r[9] <= y_r[8] - (x_r[8]>>>8);
angle_remain[9] <= angle_remain[8] + ANGLE_9;
end
end
//第10次旋转
always @(posedge clk or negedge rst_n) begin
/* if(!rst_n) begin
x_r[10] <= 16'sd0;
y_r[10] <= 16'sd0;
angle_remain[10] <= 32'sd0;
end
else */ if(angle_remain[9] > 32'sd0) begin
x_r[10] <= x_r[9] - (y_r[9]>>>9);
y_r[10] <= y_r[9] + (x_r[9]>>>9);
angle_remain[10] <= angle_remain[9] - ANGLE_10;
end
else begin
x_r[10] <= x_r[9] + (y_r[9]>>>9);
y_r[10] <= y_r[9] - (x_r[9]>>>9);
angle_remain[10] <= angle_remain[9] + ANGLE_9;
end
end
//每个phi值的所在现象的流水线延迟
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
quadrant_r[0] <= 3'b0; //不能合并着写
quadrant_r[1] <= 3'b0;
quadrant_r[2] <= 3'b0;
quadrant_r[3] <= 3'b0;
quadrant_r[4] <= 3'b0;
quadrant_r[5] <= 3'b0;
quadrant_r[6] <= 3'b0;
quadrant_r[7] <= 3'b0;
quadrant_r[8] <= 3'b0;
quadrant_r[9] <= 3'b0;
quadrant_r[10] <=3'b0;
end
else
begin
quadrant_r[0]<= quadrant_rr;
quadrant_r[1]<= quadrant_r[0];
quadrant_r[2]<= quadrant_r[1];
quadrant_r[3]<= quadrant_r[2];
quadrant_r[4]<= quadrant_r[3];
quadrant_r[5]<= quadrant_r[4];
quadrant_r[6]<= quadrant_r[5];
quadrant_r[7]<= quadrant_r[6];
quadrant_r[8]<= quadrant_r[7];
quadrant_r[9]<= quadrant_r[8];
quadrant_r[10]<= quadrant_r[9];
// quadrant_r[11]<= quadrant_r[10];
end
end
wire signed [16:0] ret_x;
wire signed [16:0] ret_y;
wire [2:0] quadrant_flag;
assign ret_x = x_r[10];
assign ret_y = y_r[10];
assign quadrant_flag = quadrant_r[10];
//坐标系转换回去
reg signed [16:0] sin_phi_r;
reg signed [16:0] cos_phi_r;
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
sin_phi_r <= 17'sd0;
cos_phi_r <= 17'sd0;
end
else
case(quadrant_flag) //根据原始角度所在象限,还原其三角函数值sin_phi和cos_phi
3'd1:
begin
cos_phi_r <= ret_x;
sin_phi_r <= ret_y;
flag_done <= 1'b1;
end
3'd2: //若再乘上极径和模长补偿因子,则实现直角坐标系变换
begin
cos_phi_r <= ~(ret_y) + 1'b1; //-sin
sin_phi_r <= ret_x;
flag_done <= 1'b1;
end
3'd3:
begin
cos_phi_r <= ~ret_x + 1'b1;
sin_phi_r <= ~ret_y + 1'b1;
flag_done <= 1'b1;
end
3'd4:
begin
cos_phi_r <= ret_y;
sin_phi_r <= ~ret_x + 1'b1;
flag_done <= 1'b1;
end
default:
begin
sin_phi_r <= 17'sd0;
cos_phi_r <= 17'sd0;
flag_done <= 1'b0;
end
endcase
end
assign sin_phi = sin_phi_r;
assign cos_phi = cos_phi_r;
endmodule
/*这个模块的代码由于自己在开始处理象限的时候全部设计成第一象限的结果,导致sin和cos的结果全部是正值,
那么变成负数的时候只需要取反加1,(以补码的的形式表示)*/
测试模块:
/* `timescale 1ns/1ps
module cordic_tb();
reg rst_n;
reg clk;
reg [12:0] phi_pre;
wire flag_done;
wire [15:0] sin_phi;
wire [15:0] cos_phi;
reg [12:0] cnt;
reg [12:0] cnt_n;
initial begin
rst_n = 1'b0;
clk = 1'b0;
#15;
rst_n = 1'b1;
end
always #10 clk = ~clk;
always @ (*) begin
if(cnt==13'd359) begin
cnt_n = 'b0;
end
else begin
cnt_n = cnt_n + 1'b1;
end
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt <= 'd0;
end
else begin
cnt <= cnt_n;
end
end
always @ (posedge clk or negedge rst_n) begin
if(!rst_n) begin
phi_pre <= 'd0;
end
else begin
phi_pre <= cnt;
end
end
cordic cord9c_inst(
.clk(clk),
.rst_n(rst_n),
.phi_pre(phi_pre),
// .,
.flag_done(flag_done),
.sin_phi(sin_phi),
.cos_phi(cos_phi)
);
endmodule
*/
`timescale 1 ps/ 1 ps
module cordic_tb;
// Inputs
reg clk;
reg rst_n;
reg [12:0] cnt;
reg [12:0] cnt_n;
reg [12:0] Phase_n;
reg [12:0] phi_pre;
wire [16:0] sin_phi;
wire [16:0] cos_phi;
// Instantiate the Unit Under Test (UUT)
cordic uut
(
.clk (clk ),
.rst_n (rst_n ),
.phi_pre (phi_pre ),
.sin_phi (sin_phi ),
.cos_phi (cos_phi )
);
initial
begin
#0 clk = 1'b0;
#10000 rst_n = 1'b0;
#10000 rst_n = 1'b1;
#10000000 $stop;
end
always #10000
begin
clk = ~clk;
end
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
cnt <= 1'b0;
else
cnt <= cnt_n;
end
always @ (*)
begin
if(cnt == 13'd359)
cnt_n = 1'b0;
else
cnt_n = cnt + 1'b1;
end
//生成相位0-359度,Phase[17:16]为相位的象限,Phase[15:10]为相位的值
always @ (posedge clk or negedge rst_n)
begin
if(!rst_n)
phi_pre <= 1'b0;
else
phi_pre <= Phase_n;
end
always @ (*)
begin
Phase_n = cnt;
end
endmodule
出现下面这个原因,是对象限标志在进行周期延时的时候,多延时了一个周期。
最初浪费很多时间在仿真时因为,在查看波形的时候,没有先将信号设置为有符号数,再设置为模拟