基于FPGA的CORDIC算法

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


出现下面这个原因,是对象限标志在进行周期延时的时候,多延时了一个周期。
在这里插入图片描述
在这里插入图片描述
最初浪费很多时间在仿真时因为,在查看波形的时候,没有先将信号设置为有符号数,再设置为模拟
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43727437/article/details/104182097