当前位置:   article > 正文

基于FPGA实现经过Matalb验证的CORDIC算法并Modelsim波形仿真——旋转模式和向量模式

cordic


前言

FPGA能容易地实现加减运算,但是计算三角函数或者指数、对数、平方根等很复杂。一般这些复杂函数的计算,会通过查找表或者近似计算(泰勒展开)等技术在FPGA上实现。【查找表方法:比如说要计算三角函数,就可以先采用三角函数基本公式以及和差化积等公式将函数值求出,建立查找表,将求出后的数值存在内存中,需要该数值时进行寻址;泰勒级数展开:会涉及到很多乘除法以及浮点数问题,运算复杂且影响精度】

CORDIC(坐标旋转数字计算方法)算法由J.D.Volder提出,相当于是一个“移位相加“算法,该算法用基本的加减或者移位运算来代替乘法运算,逐渐与目标值逼近,从而最终得到函数的解。另外该算法分别可以在圆坐标系、线性坐标系和双曲线坐标系使用。

CORDIC算法有两种工作模式:旋转模式和向量模式,旋转模式是给定旋转角,计算旋转后的坐标,而向量模式相当于旋转模式的变体(倒推得到),根据旋转后的坐标,得到向量的角度和模值。

因此采用CORDIC算法后,函数就能采用FPGA进行简易地处理,下面主要讲解旋转模式。

旋转模式

首先根据旋转模式下的圆坐标系进行分析学习
根据下图我们可以进行旋转公式推导
在这里插入图片描述

该图展示的是从红色旋转到蓝色,因此根据三角关系即可得到如下旋转数学仿真:
在这里插入图片描述
写成旋转矩阵形式:
在这里插入图片描述
还可以提取cosθ,便于写成tanθ的形式,写成tanθ后就可以转换成2的次幂形式。
在这里插入图片描述
cosθ可以作为伸缩因子,将其去掉,我们就能得到CORDIC的伪旋转,对于伪旋转来说,旋转的角度不变,但是由于除去了cosθ,相当于xy的值乘以了cosθ的倒数,cosθ的倒数 > 1 ,因此向量的模值在旋转的过程中会变大,后续我们会引入参数进行补偿(K)。
在这里插入图片描述
2的次幂形式转换:
在这里插入图片描述
在这里插入图片描述
举例:当逆时针旋转90度的时候在这里插入图片描述
可得到如下的矩阵变换:
在这里插入图片描述
至此,我们就介绍完了旋转的几何原理,该算法就是已知一点坐标以及旋转角度,我们即可求出旋转后点的坐标。此时就涉及到了求取三角函数值的问题,并不适用于FPGA实现,于是采用CORDIC算法进行简化,将三角函数运算转换成移位加法运算。

CORDIC算法原理

该算法主要包括以下几点:
1、将旋转角度θ分成若干个固定大小的角度θi(θ0-θi),同时θi满足如下的公式,可看出已经将正切函数部分转换成了移位操作。(除以i个2,相当于右移i位)。
在这里插入图片描述

2、同时θ 的范围是【-π/2,π/2】,其余超出的角度我们给与一个方向值d来判断角度,也称为符号判决因子,如果旋转角已经大于θ,则di = -1,表示顺时针旋转;如果旋转角已经小于θ,则di = 1,表示旋转为逆时针。因此其每次旋转的角度值为 di*θi,最终得到每次迭代的旋转表达式:
在这里插入图片描述
如下为角度累加器的公式,z为角度叠加值,d为旋转方向
在这里插入图片描述
3、迭代操作得到增益K值

因此当我们进行第一次旋转的时候:(θ0角的旋转方向为d0)

x1 = cosθ0(x0 – d0y0tanθ0)
y1 = cosθ0(y0 + d0x0tanθ0)

第二次旋转的时候:(将上面的x1 和 y1 代入并提取cosθ)

x2 = cosθ1(x1 – d1y1tanθ1) = cosθ1cosθ0(x0 – d0y0tanθ0 – d1y0tanθ1 –d1d0 x0tanθ1 tanθ0)
y2 = cosθ1(y1 + d1x1tanθ1) = cosθ1cosθ0(y0 +d0x0tanθ0 + d1x0tanθ1 – d1d0y0tanθ1 tanθ0)

当进行到第n次旋转,即可得到n个cos相乘,我们将其规定为K(增益),当i的次数很大时,K的值趋于一个常数。K的数值需要根据迭代次数来确定,同时迭代次数确定后,k的值也能确定出来,我们就可以将这个误差值K预先存储下来,迭代结束后就可以对旋转后的xy进行补偿校正。
由于如下公式以及tanθi = 2^(-i)
在这里插入图片描述

在这里插入图片描述
4、把所有tanθi = 2^(-i)对应的旋转角度和正切值制成一张表如下,便于存储为查找表。
于是任意的旋转角θ,都能由下表的不同θi进行多次累加旋转得到。
在这里插入图片描述

CORDIC算法最终公式

经过CORDIC算法原理分析以及推导,我们可以得到最终的公式:
通过下面公式可看出,对应三角函数运算转化为了基本的加减和移位运算。
补充:当计算向量模值的时候,角度累加器Z 可忽略,只用前两个公式即可。
在这里插入图片描述

当FPGA进行计算的时候,每次迭代运算需要需要步骤:

1次查表【每次迭代都会有一个相对固定角度的累加,这个角度就是公式中2^(-i)对应的角度值,一个i对应一个角度值,用查找表实现】
三次加法【xyz的累加】
2次移位(每迭代一次,xy要分别进行一次移位)


最终公式的数学矩阵形式:
在这里插入图片描述
通常简化操作如下:
在这里插入图片描述

Matlab实现CORDIC算法(旋转模式)

close all;
clear;
clc;
% 初始化
die = 16;     %迭代次数
x = zeros(die+1,1);
y = zeros(die+1,1);
z = zeros(die+1,1);
x(1) = 0.607253;   %初始设置
z(1) = pi/6;    %待求角度θ
%迭代操作
for i = 1:die
    if z(i) >= 0% 判断旋转角度是逆时针还是顺时钟
        d = 1;  % 逆时针
    else
        d = -1; %顺时针旋转
    end
    % CORDIC算法是三个公式
    x(i+1) = x(i) - d*y(i)*(2^(-(i-1)));
    y(i+1) = y(i) + d*x(i)*(2^(-(i-1)));
    z(i+1) = z(i) - d*atan(2^(-(i-1)));
end
cosa = vpa(x(17),10)
sina = vpa(y(17),10)
c = vpa(z(17),10)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

FPGA实现

旋转角度需要提前存在ROM中,另外还需要用到加法器和移位操作。根据输入: X Y Z 得到 输出:旋转后的 X’ 和 Y‘
在这里插入图片描述
单次迭代的框图:

**旋转角度:**通过xy的最高有效位进行XOR异或操作,我们即可判断xy最高有效位的同号还是异号,从而判断出旋转角度 d 是 -1 还是 1 。
**选择信号:**根据公式,当X进行加法运算的时候,Y进行减法运算,或者X减法Y加法,因此二者的选择是互为相反,而选择信号均来自XOR结果,因此在Y的选择器处进行了取反操作,为保证与X互为相反的加减运算。(起到控制加减法的作用)
二选一多路器:根据选择信号来判断是进行加法还是减法操作。

在这里插入图片描述
两次迭代框图:
两次迭代就是逻辑的复制。
在这里插入图片描述本文的学习资料参考包含verilog代码及测试文件。该代码采用如下的数学矩阵来计算。
首先确定迭代次数以及增益K的数值,然后根据查找表的角度值即可实现。

在这里插入图片描述

CORDIC旋转模式的verilog代码

该代码中将迭代次数设置为16,以下是代码的学习理解:

//*********************************************************
//用该模块的时候需要给予一个角度theta
//已知角thea,求正弦sinθ(sin_theta)和余弦cosθ(cos_theta)

//思想:若向量模值为1,则其x坐标就是余弦值,y坐标就是正弦值。
//利用这一点,从(K,0)处迭代旋转至θ处的单位矢量即可。

//*********************************************************

module cordic_A(
	input clk,
	input rst_n,
	input  [15:0]theta, /给予角度
	output reg [15:0]sin_theta, // 正弦值 y
	output reg [15:0]cos_theta  //余弦值 x
);
//给定增益k
parameter Kn  = 'd19898;    // 0.607253*2^15
parameter iKn = 'd53961;    // 1.64676*2^15 

parameter arctan_0 = 8192    ;  // arctan(1/2)
parameter arctan_1 = 4836    ;  // arctan(1/2^1)
parameter arctan_2 = 2555    ;  // arctan(1/2^2)
parameter arctan_3 = 1297    ;  // arctan(1/2^3)
parameter arctan_4 = 651     ;  // arctan(1/2^4)
parameter arctan_5 = 326     ;  // arctan(1/2^5)
parameter arctan_6 = 163     ;  // arctan(1/2^6)
parameter arctan_7 = 81      ;  // arctan(1/2^7)
parameter arctan_8 = 41      ;  // arctan(1/2^8)
parameter arctan_9 = 20      ;  // arctan(1/2^9)
parameter arctan_10 = 10     ;  // arctan(1/2^10)
parameter arctan_11 = 5      ;  // arctan(1/2^11)

reg signed [15:0] x [11:0];
reg signed [15:0] y [11:0];
reg signed [15:0] z [11:0];

wire [15:0]x_tmp;
wire [15:0]y_tmp;

reg signed [15:0]theta_1;
wire [2:0] Quadrant;//theta角所在的象限

// 象限判断
assign Quadrant = theta[15:14] + 1;

always@(*)
begin
	begin
		theta_1 <= {2'b00,theta[13:0]};
		if(Quadrant==1)
		begin
			theta_1 <= theta;
		end
		else if(Quadrant==2)
		begin
			theta_1 <= 32768 - theta;
		end
		else if(Quadrant==3)
		begin
			theta_1 <= theta - 32768;
		end
		else if(Quadrant==4)
		begin
			theta_1 <= 65536 - theta;
		end
	end
end
//指定迭代次数为16次。
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
	begin
		x[0] <= 16'd0;
		y[0] <= 16'd0;
		z[0] <= 16'd0;
	end
	else
	begin
		x[0] <= Kn;
		y[0] <= 16'd0;
		z[0] <= theta_1;
	end
end

always@(posedge clk or negedge rst_n) // i=0
begin
	if(!rst_n)
	begin
		x[1] <= 16'd0;
		y[1] <= 16'd0;
		z[1] <= 16'd0;
	end
	else
	begin
		if(z[0][15]) // 剩余角度为负数,顺时针旋转,d=-1
		begin
			x[1] <= x[0] + y[0];
			y[1] <= y[0] - x[0];
			z[1] <= z[0] + arctan_0;
		end          // 剩余角度为正数,顺时针旋转,d=+1
		else
		begin
			x[1] <= x[0] - y[0];
			y[1] <= y[0] + x[0];
			z[1] <= z[0] - arctan_0;
		end
	end
end

// >>>符号表示算术右移,不改变符号位
always@(posedge clk or negedge rst_n) // i=1
begin
	if(!rst_n)
	begin
		x[2] <= 16'd0;
		y[2] <= 16'd0;
		z[2] <= 16'd0;
	end
	else
	begin
		if(z[1][15]) // 剩余角度为负数,顺时针旋转,d=-1
		begin
			x[2] <= x[1] + (y[1] >>> 1);
			y[2] <= y[1] - (x[1] >>> 1);
			z[2] <= z[1] + arctan_1;
		end          // 剩余角度为正数,逆时针旋转,d=+1
		else
		begin
			x[2] <= x[1] - (y[1] >>> 1);
			y[2] <= y[1] + (x[1] >>> 1);
			z[2] <= z[1] - arctan_1;
		end
	end
end

always@(posedge clk or negedge rst_n) // i=2
begin
	if(!rst_n)
	begin
		x[3] <= 16'd0;
		y[3] <= 16'd0;
		z[3] <= 16'd0;
	end
	else
	begin
		if(z[2][15]) // 剩余角度为负数,顺时针旋转,d=-1
		begin
			x[3] <= x[2] + (y[2] >>> 2);
			y[3] <= y[2] - (x[2] >>> 2);
			z[3] <= z[2] + arctan_2;
		end          // 剩余角度为正数,逆时针旋转,d=+1
		else
		begin
			x[3] <= x[2] - (y[2] >>> 2);
			y[3] <= y[2] + (x[2] >>> 2);
			z[3] <= z[2] - arctan_2;
		end
	end
end

always@(posedge clk or negedge rst_n) // i=3
begin
	if(!rst_n)
	begin
		x[4] <= 16'd0;
		y[4] <= 16'd0;
		z[4] <= 16'd0;
	end
	else
	begin
		if(z[3][15]) // 剩余角度为负数,顺时针旋转,d=-1
		begin
			x[4] <= x[3] + (y[3] >>> 3);
			y[4] <= y[3] - (x[3] >>> 3);
			z[4] <= z[3] + arctan_3;
		end          // 剩余角度为正数,逆时针旋转,d=+1
		else
		begin
			x[4] <= x[3] - (y[3] >>> 3);
			y[4] <= y[3] + (x[3] >>> 3);
			z[4] <= z[3] - arctan_3;
		end
	end
end


always@(posedge clk or negedge rst_n) // i=4
begin
	if(!rst_n)
	begin
		x[5] <= 16'd0;
		y[5] <= 16'd0;
		z[5] <= 16'd0;
	end
	else
	begin
		if(z[4][15]) // 剩余角度为负数,顺时针旋转,d=-1
		begin
			x[5] <= x[4] + (y[4] >>> 4);
			y[5] <= y[4] - (x[4] >>> 4);
			z[5] <= z[4] + arctan_4;
		end          // 剩余角度为正数,逆时针旋转,d=+1
		else
		begin
			x[5] <= x[4] - (y[4] >>> 4);
			y[5] <= y[4] + (x[4] >>> 4);
			z[5] <= z[4] - arctan_4;
		end
	end
end

always@(posedge clk or negedge rst_n) // i=5
begin
	if(!rst_n)
	begin
		x[6] <= 16'd0;
		y[6] <= 16'd0;
		z[6] <= 16'd0;
	end
	else
	begin
		if(z[5][15]) // 剩余角度为负数,顺时针旋转,d=-1
		begin
			x[6] <= x[5] + (y[5] >>> 5);
			y[6] <= y[5] - (x[5] >>> 5);
			z[6] <= z[5] + arctan_5;
		end          // 剩余角度为正数,逆时针旋转,d=+1
		else
		begin
			x[6] <= x[5] - (y[5] >>> 5);
			y[6] <= y[5] + (x[5] >>> 5);
			z[6] <= z[5] - arctan_5;
		end
	end
end

always@(posedge clk or negedge rst_n) // i=6
begin
	if(!rst_n)
	begin
		x[7] <= 16'd0;
		y[7] <= 16'd0;
		z[7] <= 16'd0;
	end
	else
	begin
		if(z[6][15]) // 剩余角度为负数,顺时针旋转,d=-1
		begin
			x[7] <= x[6] + (y[6] >>> 6);
			y[7] <= y[6] - (x[6] >>> 6);
			z[7] <= z[6] + arctan_6;
		end          // 剩余角度为正数,逆时针旋转,d=+1
		else
		begin
			x[7] <= x[6] - (y[6] >>> 6);
			y[7] <= y[6] + (x[6] >>> 6);
			z[7] <= z[6] - arctan_6;
		end
	end
end


always@(posedge clk or negedge rst_n) // i=7
begin
	if(!rst_n)
	begin
		x[8] <= 16'd0;
		y[8] <= 16'd0;
		z[8] <= 16'd0;
	end
	else
	begin
		if(z[7][15]) // 剩余角度为负数,顺时针旋转,d=-1
		begin
			x[8] <= x[7] + (y[7] >>> 7);
			y[8] <= y[7] - (x[7] >>> 7);
			z[8] <= z[7] + arctan_7;
		end          // 剩余角度为正数,逆时针旋转,d=+1
		else
		begin
			x[8] <= x[7] - (y[7] >>> 7);
			y[8] <= y[7] + (x[7] >>> 7);
			z[8] <= z[7] - arctan_7;
		end
	end
end

always@(posedge clk or negedge rst_n) // i=8
begin
	if(!rst_n)
	begin
		x[9] <= 16'd0;
		y[9] <= 16'd0;
		z[9] <= 16'd0;
	end
	else
	begin
		if(z[8][15]) // 剩余角度为负数,顺时针旋转,d=-1
		begin
			x[9] <= x[8] + (y[8] >>> 8);
			y[9] <= y[8] - (x[8] >>> 8);
			z[9] <= z[8] + arctan_8;
		end          // 剩余角度为正数,逆时针旋转,d=+1
		else
		begin
			x[9] <= x[8] - (y[8] >>> 8);
			y[9] <= y[8] + (x[8] >>> 8);
			z[9] <= z[8] - arctan_8;
		end
	end
end

always@(posedge clk or negedge rst_n) // i=9
begin
	if(!rst_n)
	begin
		x[10] <= 16'd0;
		y[10] <= 16'd0;
		z[10] <= 16'd0;
	end
	else
	begin
		if(z[9][15]) // 剩余角度为负数,顺时针旋转,d=-1
		begin
			x[10] <= x[9] + (y[9] >>> 9);
			y[10] <= y[9] - (x[9] >>> 9);
			z[10] <= z[9] + arctan_9;
		end          // 剩余角度为正数,逆时针旋转,d=+1
		else
		begin
			x[10] <= x[9] - (y[9] >>> 9);
			y[10] <= y[9] + (x[9] >>> 9);
			z[10] <= z[9] - arctan_9;
		end
	end
end

always@(posedge clk or negedge rst_n) // i=10
begin
	if(!rst_n)
	begin
		x[11] <= 16'd0;
		y[11] <= 16'd0;
		z[11] <= 16'd0;
	end
	else
	begin
		if(z[10][15]) // 剩余角度为负数,顺时针旋转,d=-1
		begin
			x[11] <= x[10] + (y[10] >>> 10);
			y[11] <= y[10] - (x[10] >>> 10);
			z[11] <= z[10] + arctan_10;
		end          // 剩余角度为正数,逆时针旋转,d=+1
		else
		begin
			x[11] <= x[10] - (y[10] >>> 10);
			y[11] <= y[10] + (x[10] >>> 10);
			z[11] <= z[10] - arctan_10;
		end
	end
end

// 溢出判断
assign x_tmp = x[11][15]==1 ? 16'h7FFF : x[11];
assign y_tmp = y[11][15]==1 ? 16'h7FFF : y[11];
//assign x_tmp = x[11];
//assign y_tmp = y[11];

always@(posedge clk or negedge rst_n) // i=11
begin
	if(!rst_n)
	begin
		sin_theta <= 16'd0;
		cos_theta <= 16'd0;
	end
	else
	begin
		if(Quadrant == 3'd1)
		begin
			sin_theta <= y_tmp;
			cos_theta <= x_tmp;
		end
		else if(Quadrant == 3'd2)
		begin
			sin_theta <= y_tmp;
			cos_theta <= -x_tmp;
		end
		else if(Quadrant == 3'd3)
		begin
			sin_theta <= -y_tmp;
			cos_theta <= -x_tmp;
		end
		else if(Quadrant == 3'd4)
		begin
			sin_theta <= -y_tmp;
			cos_theta <= x_tmp;
		end
		else
		begin
			sin_theta <= sin_theta;
			cos_theta <= cos_theta;
		end
	end
end
endmodule


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408

对CORDIC算法进行封装,同时给与一个旋转角度60度。

module top(

				input clk,
				input rst_n,

				output 	 signed [31:0]	Sin,
				output 	 signed [31:0]	Cos

);

cordic_A inst1(
		.clk(clk),
		.rst_n(rst_n),
		.angle(60),
		.start(start),
		
		.Sin(Sin),
		.Cos(Cos),
		.finished(finished)
		
);
endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

RTL图

得到如下的RTL图:
在这里插入图片描述

可以看到给与60度旋转角,根据旋转角,采用CORDIC算法即可得到最终的正余弦值。

对CORDIC算法tb仿真

`timescale 1ns/1ns

module cordic_Atb();


integer i;

reg clk,rst_n;
reg [15:0] theta;
wire [15:0]sin_theta,cos_theta;


cordic_A u0(
	.clk       (clk      ),
	.rst_n     (rst_n    ),
	.theta     (theta    ),
	.sin_theta (sin_theta),
	.cos_theta (cos_theta)
);

initial
begin
    #0 clk = 1'b0;
    #10 rst_n = 1'b0;
    #10 rst_n = 1'b1;
    #10000000 $stop;
end 
always #10
begin
    clk = ~clk;
end


initial
begin
    #0 theta = 16'd20;  //初始化角度为20
   for(i=0;i<10000;i=i+1)
	begin
		#400;
		theta <= theta + 16'd20; //每延迟400ns,角度加20
	end
end 


endmodule
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

仿真波形如下:
可看到我们得到了正余弦值。
在这里插入图片描述显示正余弦波的方式:在这里插入图片描述
在这里插入图片描述

向量模式

向量模式相当于旋转模式的倒推,是将给定的向量旋转到X轴上,因此我们就有了旋转后的坐标,根据旋转后的坐标(梯度模值),可确定处旋转的角度(梯度方向)。
在这里插入图片描述
寄存器X值为梯度模值,符号判决因子d与寄存器y的值相反,得到d后,仍然使用旋转模式中推到的角度累加器Z来计算梯度方向。
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/625470
推荐阅读
相关标签
  

闽ICP备14008679号