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\n",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\n", 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標准)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM