分享

FPGA算法学习(1)

 xiehj4606 2023-02-12 发布于四川

上两篇博文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标准)

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约