• FPGA算法学习(1) -- Cordic(Verilog实现)


    上两篇博文Cordic算法——圆周系统之旋转模式Cordic算法——圆周系统之向量模式做了理论分析和实现,但是所用到的变量依然是浮点型,而cordic真正的用处是基于FPGA等只能处理定点的平台。只需将满足精度的浮点数,放大2^n倍,取整,再进行处理。

    1. 旋转模式

    假设要通过FPGA计算极坐标(55.6767°,1)的直角坐标。首先,角度值为浮点数,需要进行放大处理,放大10000倍。则预设的旋转角度同样要放大10000倍。

    实现伪旋转(忽略模长补偿因子)的代码如下所示,注意,因为是整型运算,起始旋转时x放大了215,放大倍数决定计算精度,满足需求即可。最后得到的x,y在缩小215,即得到伪旋转后的x,y。最后进行模长波长运算(因为是浮点,同样需要放大)。

    #include <stdio.h>
    #include <stdlib.h>
    
    int cordic_c(int a,int r);	
    int x = 32768, y = 0;		//以X轴为旋转起始点,放大倍数2^15
    
    int main(viod)
    {
    
    	int remain = cordic_c(556767,1);		//极坐标值(极角,极径)
    	printf("旋转角度误差:%d, 直角坐标:x = %d, y = %d
    ",remain,x,y);
    	return 0;
    }
    
    int cordic_c(int a,int r)
    {
    	const int theta[] = {450000,265651,140362,71250,35763,17899,8952,4476,2238,1119,560,280,140,70,35,17,9,4,2,1}; //旋转角度
    
    	int i = 0;
    	int x_temp = 0, y_temp = 0;
    	int angle_new = 0;		//旋转后终止角度
    	int angle_remain = a;	//旋转后,剩余角度
    	char detection;				//旋转方向
    
    	for( i=0; i<20;i++)
    	{
    		if(angle_remain > 0)
    		{
    			angle_new = angle_new + theta[i];
    			angle_remain = a - angle_new;
    			x_temp = (x - (y >>i));
    			y_temp = (y + (x >> i));
    			x = x_temp;
    			y = y_temp;
    			detection = '+';
    		}
    		else
    		{
    			angle_new = angle_new - theta[i];
    			angle_remain = a - angle_new;
    			x_temp = (x + (y>>i));
    			y_temp = (y - (x>>i));
    			x = x_temp;
    			y = y_temp;
    			detection = '-'; 
    		}
    		printf(" x = %-8d, y = %-8d, 旋转次数 = %-8d 旋转角度 = %-12d  旋转方向:%-8c  终点角度 = %-8d
    ", x,y,i+1, theta[i],detection,angle_new);
    	}
    	x = r*x;
    	y = r*y;
    	return angle_remain;
    }
    

    完整的FPGA实现过程,包含预处理和后处理,支持{-π,π}的角度,采用流水线方式实现,Verilog完整代码如下,注意在移位过程中要用算术移位(>>>),才能保证带符号的数正确移位:

    
    /****************************************************/
    //预处理
    module Cordic_Pre(
    				clk,
    				rst_n,
    				phi,	
    				
    				phi_pre,
    				quadrant_flag
    				);
    
    /****************************************************/
    
    	input					clk;
    	input					rst_n;
    	input	signed	[23:0]	phi;	
    	
    	output	signed	[23:0]	phi_pre;						//预处理后的角度值
    	output			[1:0]	quadrant_flag;					//象限标记
    	
    /****************************************************/
    
    	parameter				ANGLE_P90	= 24'sd90_0000,		//输入角度范围{-pi,pi},角度值放大了10000倍
    							ANGLE_N90	= -24'sd90_0000,
    							ANGLE_0		= 24'sd00_0000;
    							 
    /****************************************************/
    
    	reg		signed	[23:0]	phi_pre_r;
     	reg				[1:0]	quadrant_flag_r;	 
    
    /****************************************************/
    
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					phi_pre_r <= 24'sd0;
    					quadrant_flag_r <= 2'b00;
    				end
    			else if(phi >= ANGLE_0 && phi <= ANGLE_P90)		//第一象限
    				begin
    					phi_pre_r <= phi;
    					quadrant_flag_r <= 2'b01;			
    				end
    			else if(phi > ANGLE_P90 )						//第二象限			
    				begin
    					phi_pre_r <= phi - ANGLE_P90;
    					quadrant_flag_r <= 2'b10;
    				end
    			else if(phi < ANGLE_0 && phi >= ANGLE_N90)		//第四象限			
    				begin
    					phi_pre_r <= phi;
    					quadrant_flag_r <= 2'b00;
    				end
    			else
    				begin										//第三象限
    					phi_pre_r <= phi - ANGLE_N90;
    					quadrant_flag_r <= 2'b11;
    				end
    		end
    
    /****************************************************/
    
    	assign	phi_pre			= phi_pre_r;
    	assign	quadrant_flag	= quadrant_flag_r;
    	
    /****************************************************/
    
    endmodule
    
    

    我的设计要求精度较高,所以采用20次旋转,旋转过程的代码如下:

    /****************************************************/
    
    module	Cordic_Rotate(
    					clk,
    					rst_n,
    					phi_pre,
    					quadrant_flag,
    					
    					ret_x,
    					ret_y,
    					quadrant
    					);
    
    /****************************************************/
    
    	input					clk;
    	input					rst_n;
    	input	signed	[23:0]	phi_pre;
    	input			[1:0]	quadrant_flag;
    	
    	output	signed	[16:0]	ret_x;
    	output	signed	[16:0]	ret_y;
    	output			[1:0]	quadrant;
    /****************************************************/
    	
    	parameter				X_ORIGN 	= 17'sd32768;	//旋转时x的起始大小,根据精度要求而定。
    	//每次旋转的固定角度值
    	parameter				ANGLE_1		= 24'sd450000,	ANGLE_2		= 24'sd265651,
    							ANGLE_3		= 24'sd140362,	ANGLE_4		= 24'sd71250,
    							ANGLE_5		= 24'sd35763,	ANGLE_6		= 24'sd17899,
    							ANGLE_7		= 24'sd8952,	ANGLE_8		= 24'sd4476,
    							ANGLE_9		= 24'sd2238,	ANGLE_10	= 24'sd1119,
    							ANGLE_11	= 24'sd560,		ANGLE_12	= 24'sd280,
    							ANGLE_13	= 24'sd140,		ANGLE_14	= 24'sd70,
    							ANGLE_15	= 24'sd35,		ANGLE_16	= 24'sd17,
    							ANGLE_17	= 24'sd9,		ANGLE_18	= 24'sd4,
    							ANGLE_19	= 24'sd2,		ANGLE_20	= 24'sd1;
    												
    /****************************************************/
    
    	reg		signed	[16:0]	x_r				[20:0];
    	reg		signed	[16:0]	y_r				[20:0];
    	reg		signed	[23:0]	angle_remain	[20:0];
    	reg		signed	[1:0]	quadrant_r		[20:0];
    	
    /****************************************************/
    //旋转的流水线过程
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[0] <= 17'sd0;
    					y_r[0] <= 17'sd0;
    					angle_remain[0] <= 24'sd0;
    				end
    			else
    				begin
    					x_r[0] <= X_ORIGN;				 
    					y_r[0] <= 17'sd0;
    					angle_remain[0] <= phi_pre;
    				end
    		end
    	//第1次旋转	
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[1] <= 17'sd0;
    					y_r[1] <= 17'sd0;
    					angle_remain[1] <= 24'sd0;
    				end
    				
    			else if(angle_remain[0] > 24'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
    	//第2次旋转		
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[2] <= 17'sd0;
    					y_r[2] <= 17'sd0;
    					angle_remain[2] <= 24'sd0;
    				end
    			else if(angle_remain[1] > 24'sd0)							//比较时,符号标记s必须带上,对结果有影响
    				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
    	//第3次旋转		
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[3] <= 17'sd0;
    					y_r[3] <= 17'sd0;
    					angle_remain[3] <= 24'sd0;
    				end
    			else if(angle_remain[2] > 24'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
    	//第4次旋转		
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[4] <= 17'sd0;
    					y_r[4] <= 17'sd0;
    					angle_remain[4] <= 24'sd0;
    				end
    			else if(angle_remain[3] > 24'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
    	//第5次旋转		
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[5] <= 17'sd0;
    					y_r[5] <= 17'sd0;
    					angle_remain[5] <= 24'sd0;
    				end
    			else if(angle_remain[4] > 24'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 == 1'b0)
    				begin
    					x_r[6] <= 17'sd0;
    					y_r[6] <= 17'sd0;
    					angle_remain[6] <= 24'sd0;
    				end
    			else if(angle_remain[5] > 24'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 == 1'b0)
    				begin
    					x_r[7] <= 17'sd0;
    					y_r[7] <= 17'sd0;
    					angle_remain[7] <= 24'sd0;
    				end
    			else if(angle_remain[6] > 24'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 == 1'b0)
    				begin
    					x_r[8] <= 17'sd0;
    					y_r[8] <= 17'sd0;
    					angle_remain[8] <= 24'sd0;
    				end
    			else if(angle_remain[7] > 24'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 == 1'b0)
    				begin
    					x_r[9] <= 17'sd0;
    					y_r[9] <= 17'sd0;
    					angle_remain[9] <= 24'sd0;
    				end
    			else if(angle_remain[8] > 24'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 == 1'b0)
    				begin
    					x_r[10] <= 17'sd0;
    					y_r[10] <= 17'sd0;
    					angle_remain[10] <= 24'sd0;
    				end
    			else if(angle_remain[9] > 24'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_10;
    				end
    		end
    	//第11次旋转	
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[11] <= 17'sd0;
    					y_r[11] <= 17'sd0;
    					angle_remain[11] <= 24'sd0;
    				end
    			else if(angle_remain[10] > 24'sd0)
    				begin
    					x_r[11] <= x_r[10] - (y_r[10] >>> 10);
    					y_r[11] <= y_r[10] + (x_r[10] >>> 10);
    					angle_remain[11] <= angle_remain[10] - ANGLE_11;
    				end
    			else
    				begin
    					x_r[11] <= x_r[10] + (y_r[10] >>> 10);
    					y_r[11] <= y_r[10] - (x_r[10] >>> 10);
    					angle_remain[11] <= angle_remain[10] + ANGLE_11;
    				end
    		end
    	//第12次旋转	
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[12] <= 17'sd0;
    					y_r[12] <= 17'sd0;
    					angle_remain[12] <= 24'sd0;
    				end
    			else if(angle_remain[11] > 24'sd0)
    				begin
    					x_r[12] <= x_r[11] - (y_r[11] >>> 11);
    					y_r[12] <= y_r[11] + (x_r[11] >>> 11);
    					angle_remain[12] <= angle_remain[11] - ANGLE_12;
    				end
    			else
    				begin
    					x_r[12] <= x_r[11] + (y_r[11] >>> 11);
    					y_r[12] <= y_r[11] - (x_r[11] >>> 11);
    					angle_remain[12] <= angle_remain[11] + ANGLE_12;
    				end
    		end
    	//第13次旋转
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[13] <= 17'sd0;
    					y_r[13] <= 17'sd0;
    					angle_remain[13] <= 24'sd0;
    				end
    			else if(angle_remain[12] > 24'sd0)
    				begin
    					x_r[13] <= x_r[12] - (y_r[12] >>> 12);
    					y_r[13] <= y_r[12] + (x_r[12] >>> 12);
    					angle_remain[13] <= angle_remain[10] - ANGLE_13;
    				end
    			else
    				begin
    					x_r[13] <= x_r[12] + (y_r[12] >>> 12);
    					y_r[13] <= y_r[12] - (x_r[12] >>> 12);
    					angle_remain[13] <= angle_remain[12] + ANGLE_13;
    				end
    		end
    	//第14次旋转	
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[14] <= 17'sd0;
    					y_r[14] <= 17'sd0;
    					angle_remain[14] <= 24'sd0;
    				end
    			else if(angle_remain[13] > 24'sd0)
    				begin
    					x_r[14] <= x_r[13] - (y_r[13] >>> 13);
    					y_r[14] <= y_r[13] + (x_r[13] >>> 13);
    					angle_remain[14] <= angle_remain[13] - ANGLE_14;
    				end
    			else
    				begin
    					x_r[14] <= x_r[13] + (y_r[13] >>> 13);
    					y_r[14] <= y_r[13] - (x_r[13] >>> 13);
    					angle_remain[14] <= angle_remain[13] + ANGLE_14;
    				end
    		end
    	//第15次旋转	
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[15] <= 17'sd0;
    					y_r[15] <= 17'sd0;
    					angle_remain[15] <= 24'sd0;
    				end
    			else if(angle_remain[14] > 24'sd0)
    				begin
    					x_r[15] <= x_r[14] - (y_r[14] >>> 14);
    					y_r[15] <= y_r[14] + (x_r[14] >>> 14);
    					angle_remain[15] <= angle_remain[14] - ANGLE_15;
    				end
    			else
    				begin
    					x_r[15] <= x_r[14] + (y_r[14] >>> 14);
    					y_r[15] <= y_r[14] - (x_r[14] >>> 14);
    					angle_remain[15] <= angle_remain[14] + ANGLE_15;
    				end
    		end	
    	//第16次旋转	
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[16] <= 17'sd0;
    					y_r[16] <= 17'sd0;
    					angle_remain[16] <= 24'sd0;
    				end
    			else if(angle_remain[15] > 24'sd0)
    				begin
    					x_r[16] <= x_r[15] - (y_r[15] >>> 15);
    					y_r[16] <= y_r[15] + (x_r[15] >>> 15);
    					angle_remain[16] <= angle_remain[15] - ANGLE_16;
    				end
    			else
    				begin
    					x_r[16] <= x_r[15] + (y_r[15] >>> 15);
    					y_r[16] <= y_r[15] - (x_r[15] >>> 15);
    					angle_remain[16] <= angle_remain[15] + ANGLE_16;
    				end
    		end	
    	//第17次旋转	
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[17] <= 17'sd0;
    					y_r[17] <= 17'sd0;
    					angle_remain[17] <= 24'sd0;
    				end
    			else if(angle_remain[16] > 24'sd0)
    				begin
    					x_r[17] <= x_r[16] - (y_r[16] >>> 16);
    					y_r[17] <= y_r[16] + (x_r[16] >>> 16);
    					angle_remain[17] <= angle_remain[16] - ANGLE_17;
    				end
    			else
    				begin
    					x_r[17] <= x_r[16] + (y_r[16] >>> 16);
    					y_r[17] <= y_r[16] - (x_r[16] >>> 16);
    					angle_remain[17] <= angle_remain[16] + ANGLE_17;
    				end
    		end	
    	//第18次旋转
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[18] <= 17'sd0;
    					y_r[18] <= 17'sd0;
    					angle_remain[18] <= 24'sd0;
    				end
    			else if(angle_remain[17] > 24'sd0)
    				begin
    					x_r[18] <= x_r[17] - (y_r[17] >>> 17);
    					y_r[18] <= y_r[17] + (x_r[17] >>> 17);
    					angle_remain[18] <= angle_remain[17] - ANGLE_18;
    				end
    			else
    				begin
    					x_r[18] <= x_r[17] + (y_r[17] >>> 17);
    					y_r[18] <= y_r[17] - (x_r[17] >>> 17);
    					angle_remain[18] <= angle_remain[17] + ANGLE_18;
    				end
    		end	
    	//第19次旋转
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[19] <= 17'sd0;
    					y_r[19] <= 17'sd0;
    					angle_remain[19] <= 24'sd0;
    				end
    			else if(angle_remain[18] > 24'sd0)
    				begin
    					x_r[19] <= x_r[18] - (y_r[15] >>> 18);
    					y_r[19] <= y_r[18] + (x_r[15] >>> 18);
    					angle_remain[19] <= angle_remain[18] - ANGLE_19;
    				end
    			else
    				begin
    					x_r[19] <= x_r[18] + (y_r[18] >>> 18);
    					y_r[19] <= y_r[18] - (x_r[18] >>> 18);
    					angle_remain[19] <= angle_remain[18] + ANGLE_19;
    				end
    		end	
    	//第20次旋转	
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					x_r[20] <= 17'sd0;
    					y_r[20] <= 17'sd0;
    					angle_remain[20] <= 24'sd0;
    				end
    			else if(angle_remain[19] > 24'sd0)
    				begin
    					x_r[20] <= x_r[19] - (y_r[19] >>> 19);
    					y_r[20] <= y_r[19] + (x_r[19] >>> 19);
    					angle_remain[20] <= angle_remain[19] - ANGLE_20;
    				end
    			else
    				begin
    					x_r[20] <= x_r[19] + (y_r[19] >>> 19);
    					y_r[20] <= y_r[19] - (x_r[19] >>> 19);
    					angle_remain[20] <= angle_remain[19] + ANGLE_20;
    				end
    		end	
    /****************************************************/
    //每个phi值的所在现象的流水线延迟
    	always @(posedge clk or negedge rst_n)
    		begin
    			if(rst_n == 1'b0)
    				begin
    					quadrant_r[0] <= 2'b00;			//不能合并着写
    					quadrant_r[1] <= 2'b00;
    					quadrant_r[2] <= 2'b00;
    					quadrant_r[3] <= 2'b00;
    					quadrant_r[4] <= 2'b00;
    					quadrant_r[5] <= 2'b00;
    					quadrant_r[6] <= 2'b00;
    					quadrant_r[7] <= 2'b00;
    					quadrant_r[8] <= 2'b00;
    					quadrant_r[9] <= 2'b00;
    					quadrant_r[10] <= 2'b00;
    					quadrant_r[11] <= 2'b00;
    					quadrant_r[12] <= 2'b00;
    					quadrant_r[13] <= 2'b00;
    					quadrant_r[14] <= 2'b00;
    					quadrant_r[15] <= 2'b00;
    					quadrant_r[16] <= 2'b00;
    					quadrant_r[17] <= 2'b00;
    					quadrant_r[18] <= 2'b00;
    					quadrant_r[19] <= 2'b00;
    					quadrant_r[20] <= 2'b00;
    				end
    			else
    				begin
    					quadrant_r[0]	<= quadrant_flag;
    					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];
    					quadrant_r[12]	<= quadrant_r[11];
    					quadrant_r[13]	<= quadrant_r[12];
    					quadrant_r[14]	<= quadrant_r[13];
    					quadrant_r[15]	<= quadrant_r[14];
    					quadrant_r[16]	<= quadrant_r[15];
    					quadrant_r[17]	<= quadrant_r[16];
    					quadrant_r[18]	<= quadrant_r[17];
    					quadrant_r[19]	<= quadrant_r[18];
    					quadrant_r[20]	<= quadrant_r[19];
    				end
    				
    		end
    	
    /****************************************************/	
    	assign ret_x	= x_r[20];
    	assign ret_y	= y_r[20];
    	assign quadrant	= quadrant_r[20];
    /****************************************************/
    endmodule
    

    后处理将象限变换过的坐标还原:

    /****************************************************/
    
    module	Cordic_Post(
    					clk,
    					rst_n,
    					ret_x,
    					ret_y,
    					quadrant,
    					
    					sin_phi,
    					cos_phi
    					);
    
    /****************************************************/
    	input					clk;
    	input					rst_n;
    	input	signed	[16:0]	ret_x;
    	input	signed	[16:0]	ret_y;
    	input			[1:0]	quadrant;
    	
    	output	signed	[16:0]	sin_phi;
    	output	signed	[16:0]	cos_phi;
    	
    /****************************************************/	
    
    	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)					//根据原始角度所在象限,还原其三角函数值sin_phi和cos_phi
    					2'd01:						//若再乘上极径和模长补偿因子,则实现直角坐标系变换
    						begin
    							cos_phi_r <= ret_x;
    							sin_phi_r <= ret_y;							
    						end
    					2'd10:
    						begin
    							cos_phi_r <= ~ret_y + 1'b1;
    							sin_phi_r <= ret_x;
    						end
    					2'd11:
    						begin
    							cos_phi_r <= ret_y;
    							sin_phi_r <= ~ret_x + 1'b1;
    						end	
    					2'd00:
    						begin
    							cos_phi_r <= ret_x;
    							sin_phi_r <= ret_y;
    						end
    					default:
    						begin
    							sin_phi_r <= 17'sd0;
    							cos_phi_r <= 17'sd0;
    						end
    				endcase
    		
    		end
    
    /****************************************************/
    	assign	sin_phi	= sin_phi_r;
    	assign	cos_phi	= cos_phi_r;
    /****************************************************/
    endmodule
    

    在四个象限分别选取一个角度进行仿真,仿真结果如下图所示:

    角度从输入到转换完毕,一共延时21个时钟周期。正好是预处理(1个周期)+旋转(20个周期)的结果。

    2. 向量模式

    至于向量模式,只要理解的算法思想,在编程上大同小异,如果要处理的坐标比较少,可以不采用流水线的方式。FPGA上用非流水线方式实现,Verilog主要代码片段如下,这次是用ROM存着旋转的固定角度值,利用addr地址线来读取相应的旋转角度:

    3'd2:
    						if(times < 5'd16)
    							begin
    								if( yn_r !==22'd0)							//当旋转到y=0时,提前结束,否则继续旋转反而影响精度
    									begin
    										if((yn_r[21]))						//yn最高位为1时,即坐标在第四象限,则逆时针旋转
    											begin
    												xn_r <= xn_r - (yn_r >>> times);
    												yn_r <= yn_r + (xn_r >>> times);
    												addr_r <= addr_r + 1'd1;
    												times <= addr_r;
    												zn_r <= zn_r-angle;
    												i <= 3'd2;
    											end
    										else
    											begin									//反之,坐标在第一象限,则顺时针旋转
    												xn_r <= xn_r + (yn_r >>> times);
    												yn_r <= yn_r - (xn_r >>> times);
    												addr_r <= addr_r + 1'd1;
    												times <= addr_r;
    												zn_r <= zn_r+angle;
    												i <= 3'd2;
    											end
    									end
    								else
    									begin
    										i <= i +1'b1;	
    									end
    							end
    						else
    							begin
    								i <= i +1'b1;
    							end
    

    至此,cordic基于圆周系统的算法总结完毕,至于还有基于线性系统、双曲系统来实现其它运算,等有机会了再学习。

    参考

    学习cordic算法所得(流水线结构、Verilog标准)

  • 相关阅读:
    补:冲刺Day1
    需求规格说明书2.0
    补:冲刺Day2
    冲刺Day3
    Base64上传图片
    C#怎样通过url调用接口
    js键盘控制DIV移动
    利用MVC的过滤器实现url的参数加密和解密
    在.net MVC中异步上传图片或者文件
    mvc url路由参数的加密和解密
  • 原文地址:https://www.cnblogs.com/rouwawa/p/7102173.html
Copyright © 2020-2023  润新知