基于FPGA的cordic算法的verilog初步实现
最近在看cordic算法,由于还不会使用matlab,真是痛苦,一系列的笔算才大概明白了这个算法是怎么回事。于是尝试用verilog来实现。用verilog实现之前先参考软件的程序,于是先看了此博文http://blog.csdn.net/liyuanbhu/article/details/8458769也不截图了,因为怕图形被其他博客网站检测到后屏蔽图片,造成此博文无法正常阅读。
阅读此博文,需要先阅读上面这个博文的内容。
这是此博文中的C代码。避免浮点运算,所以angle数组里面的角度值都扩大了256倍。此程序中计算点(10,20)与X轴之间的夹角。最终运行结果是16238。而16238/256=63.43
- #include <stdio.h>
- #include <stdlib.h>
- //double my_atan2(double x, double y);
- double my_atan2 (int x, int y)
- {
- const int angle[] = {, , , , , , , , , , , , , , };
- int i = ;
- int x_new, y_new;
- int angleSum = ;
- x *= ;// ½« X Y ·Å´óһЩ£¬½á¹û»á¸ü׼ȷ
- y *= ;
- printf ("org_x = %d, org_y=%d\n",x,y);
- for(i = ; i < ; i++)
- {
- if(y > )
- {
- x_new = x + (y >> i);
- y_new = y - (x >> i);
- x = x_new;
- y = y_new;
- angleSum += angle[i];
- }
- else
- {
- x_new = x - (y >> i);
- y_new = y + (x >> i);
- x = x_new;
- y = y_new;
- angleSum -= angle[i];
- }
- printf("Debug: i = %d x=%d, y =%d angleSum = %d, angle = %d\n", i,x,y ,angleSum, angle[i]);
- }
- return angleSum;
- }
- void main()
- {
- double z= ;
- z = my_atan2(10.0, 20.0);
- printf("\n z = %lf \n", z);
- }
既然有了C 就很好进行verilog设计。
先谈架构。
1,先将角度数据放到一个rom中进行存储
2,取一个数,运算一个数。直到循环结束。
这也就是所谓的cordic算法的向量模式。用来求角度。先看顶层
- //
- //
- //
- //
- module cordic_rotation_top (
- clock ,
- rst_n ,
- x_crd,
- y_crd,
- ena ,
- deg_sum
- );
- input clock ;
- input rst_n ;
- input [:] x_crd ;
- input [:] y_crd ;
- input ena ;
- output [:] deg_sum ;
- wire [:] deg_addr ;
- wire [:] deg_data ;
- alt_ip_rom_cordic u_rom (
- .address (deg_addr),
- .clock (clock),
- .q (deg_data)
- );
- cordic_rotation u_cord (
- .clk (clock),
- .rst_n (rst_n),
- .ena (ena),
- .x_crd (x_crd),
- .y_crd (y_crd),
- .deg_data (deg_data),
- .deg_addr (deg_addr),
- .deg_sum (deg_sum)
- );
- endmodule
rom的初始化文件为
再看运算单元。
- module cordic_rotation (
- clk ,
- rst_n ,
- ena ,
- x_crd,
- y_crd,
- deg_data,
- deg_addr,
- deg_sum
- );
- input clk ;
- input rst_n ;
- input ena ;
- input [:] x_crd ; //x coordinate
- input [:] y_crd ; //y coordinate
- input [:] deg_data ;
- output [:] deg_addr ;
- output reg[:] deg_sum ;
- // ------ rotation count 0 - 14 -------
- reg [:] rot_cnt ;
- reg [:] rot_cnt_r ;
- wire opr_en ;
- assign opr_en = ((rot_cnt_r<'d15)&(ena)) ;
- always @ (posedge clk or negedge rst_n)
- if (!rst_n) begin
- rot_cnt <= 'd0 ;
- rot_cnt_r<= 'd0;
- end
- else if (opr_en) begin
- rot_cnt <= rot_cnt + 'd1 ;
- rot_cnt_r<= rot_cnt ;
- end
- else if (!ena) begin
- rot_cnt <= 'd0 ;
- rot_cnt_r<= rot_cnt ;
- end
- assign deg_addr = rot_cnt ;
- //---------------------------------------
- reg cal_cnt ;
- reg signed [:] x_d, y_d ;
- always @ (posedge clk or negedge rst_n)
- if (!rst_n) begin
- x_d <= 'd0 ;
- y_d <= 'd0 ;
- deg_sum <= 'd0 ;
- cal_cnt <= 'd0 ;
- end
- else if (opr_en) begin
- case (cal_cnt)
- 'd0 : begin
- x_d <= {'d0,x_crd};
- y_d <= {'d0,y_crd};
- deg_sum <= 'd0 ;
- cal_cnt <= 'd1 ;
- end
- 'd1 : begin
- if ((y_d[])|(y_d=='d0)) begin
- x_d <= x_d - (y_d >>> rot_cnt_r);
- y_d <= y_d + (x_d >>> rot_cnt_r) ;
- deg_sum <= deg_sum - deg_data ;
- end
- else begin
- x_d <= x_d + (y_d >>> rot_cnt_r);
- y_d <= y_d - (x_d >>> rot_cnt_r) ;
- deg_sum <= deg_sum + deg_data ;
- end
- end
- endcase
- end
- else begin
- cal_cnt <= 'd0 ;
- end
- endmodule
rot_cnt作为rom的地址。但是由于rom返回度数值需要一个周期,所以下面的运算单元需要等待一个周期才可以进行运算,于是有了rot_cnt_r这个参数。
于是问题又来了,上面的是向量模式。还有一个旋转模式。于是开始捣鼓。
稍微将上述的C代码进行修改,计算30度的cos30,以及sin30
- #include <stdio.h>
- #include <stdlib.h>
- //double my_atan2(double x, double y);
- double my_atan2 (int x, int y)
- {
- const int angle[] = {, , , , , , , , , , , , , , };
- int i = ;
- int x_new, y_new;
- int angleSum = *;
- x *= ;// ½« X Y ·Å´óһЩ£¬½á¹û»á¸ü׼ȷ
- y *= ;
- printf ("org_x = %d, org_y=%d\n",x,y);
- for(i = ; i < ; i++)
- {
- if(angleSum <= )
- {
- x_new = x + (y >> i);
- y_new = y - (x >> i);
- x = x_new;
- y = y_new;
- angleSum += angle[i];
- }
- else
- {
- x_new = x - (y >> i);
- y_new = y + (x >> i);
- x = x_new;
- y = y_new;
- angleSum -= angle[i];
- }
- printf("Debug: i = %d x=%d, y =%d angleSum = %d, angle = %d\n", i,x,y ,angleSum, angle[i]);
- }
- return angleSum;
- }
- void main()
- {
- double z= ;
- z = my_atan2(1.0, 0.0);
- printf("\n z = %lf \n", z);
- }
结果是这样子的
先看已知条件:
1,cordic算法中的Kn极限值=1.6476 。 1/Kn=0.6073.
2,上述软件设置y=0. x=1.并且坐标值扩大了1024倍。从公式上,cosa= x sina= y 角度a=30度
3,运算结果x=1461. y=844
好,开始运算 cosa=1461/(1024*1.6476)=0.8659。 cos30=0.8660.
sina=844/(1024*1.6476) = 0.500 。 sin30 = 0.5
精度由loop次数相关
好,既然验证了这个软件程序是可以的。那么就将它转换成Verilog的程序
- //cordic 算法的旋转模式
- module cordic_rotation (
- clk ,
- rst_n ,
- ena ,
- x_crd,
- y_crd,
- deg_data,
- deg_addr,
- deg_sum
- );
- input clk ;
- input rst_n ;
- input ena ;
- input [:] x_crd ; //x coordinate
- input [:] y_crd ; //y coordinate
- input [:] deg_data ;
- output [:] deg_addr ;
- output [:] deg_sum ;
- parameter DEGREE = ;
- parameter DEG_PARA = (DEGREE*) ;
- // ------ rotation count 0 - 14 -------
- reg [:] rot_cnt ;
- reg [:] rot_cnt_r ;
- wire opr_en ;
- assign opr_en = ((rot_cnt_r<'d15)&(ena)) ;
- always @ (posedge clk or negedge rst_n)
- if (!rst_n) begin
- rot_cnt <= 'd0 ;
- rot_cnt_r<= 'd0;
- end
- else if (opr_en) begin
- rot_cnt <= rot_cnt + 'd1 ;
- rot_cnt_r<= rot_cnt ;
- end
- else if (!ena) begin
- rot_cnt <= 'd0 ;
- rot_cnt_r<= rot_cnt ;
- end
- assign deg_addr = rot_cnt ;
- //---------------------------------------
- reg cal_cnt ;
- reg signed [:] deg_sum_r ;
- reg signed [:] x_d, y_d ;
- always @ (posedge clk or negedge rst_n)
- if (!rst_n) begin
- x_d <= 'd0 ;
- y_d <= 'd0 ;
- deg_sum_r <= 'd0 ;
- cal_cnt <= 'd0 ;
- end
- else if (opr_en) begin
- case (cal_cnt)
- 'd0 : begin
- x_d <= {'d0,x_crd};
- y_d <= {'d0,y_crd};
- deg_sum_r <= DEG_PARA ;
- cal_cnt <= 'd1 ;
- end
- 'd1 : begin
- if ((deg_sum_r[])|(deg_sum_r=='d0)) begin //<=0
- x_d <= x_d + (y_d >>> rot_cnt_r);
- y_d <= y_d - (x_d >>> rot_cnt_r) ;
- deg_sum_r <= deg_sum_r + deg_data ;
- end
- else begin
- x_d <= x_d - (y_d >>> rot_cnt_r);
- y_d <= y_d + (x_d >>> rot_cnt_r) ;
- deg_sum_r <= deg_sum_r - deg_data ;
- end
- end
- endcase
- end
- else begin
- cal_cnt <= 'd0 ;
- end
- assign deg_sum = deg_sum_r ;
- endmodule
这个程序也是在上一个程序的基础上修改的。所以尽量少改动。而是修改了tb。所以需要看看TB是怎么弄的
- ///
- //
- //
- //
- `timescale 1ns/100ps
- module cordic_rotation_top_tb ;
- reg clock ,rst_n ;
- reg [:] x_crd ,y_crd ;
- reg ena ;
- wire [:] deg_sum ;
- cordic_rotation_top u_top (
- .clock (clock),
- .rst_n (rst_n),
- .x_crd (x_crd),
- .y_crd (y_crd),
- .ena (ena),
- .deg_sum (deg_sum)
- );
- always # clock = ~clock ;
- initial begin
- clock = ; rst_n = ;
- x_crd = * ; y_crd=;
- ena = ;
- # rst_n = ;
- #
- /*
- ena = 0 ;
- #40
- x_crd = 10*1024 ; y_crd=10*1024;
- ena = 1 ;
- #350
- ena = 0 ;
- #40
- x_crd = 20*1024 ; y_crd=10*1024;
- ena = 1 ;
- #350 */
- $stop ;
- end
- endmodule
将第28行替换为 x_crd = 10*1024 ; y_crd=20*1024; 就变成了上一个工程的测试代码。
此程序输出结果为:
和软件程序输出结果相同。
有没有发现问题,在计算这些东西的时候,很多网络博文说精度和loop次数相关。但是这个扩大256倍运算到第11次就已经定住了。后面的输出结果白循环了。
欢迎加入: FPGA广东交流群:162664354
FPGA开发者联盟: 485678884
微信公众号:FPGA攻城狮之家
基于FPGA的cordic算法的verilog初步实现的更多相关文章
- 基于FPGA的Cordic算法实现
CORDIC(Coordinate Rotation Digital Computer)算法即坐标旋转数字计算方法,是J.D.Volder1于1959年首次提出,主要用于三角函数.双曲线.指数.对数的 ...
- FPGA之CORDIC算法实现_代码实现(下)
关于FPGA之CORDIC算法的纯逻辑实现,博主洋葱洋葱“https://www.cnblogs.com/cofin/p/9188629.html”以及善良的一休军“https://blog.csdn ...
- 基于FPGA的RGB565_YCbCr_Gray算法实现
前面我们讲了基于FPGA用VGA显示一副静态图片,那么接下来我们就接着前面的工程来实现我们图像处理的基础算法里最简单的一个那就是彩色图像转灰度的实现. 将彩色图像转化为灰度的方法有两种,一个是令RGB ...
- cordic算法的verilog实现及modelsim仿真
1. 算法介绍 CORDIC(Coordinate Rotation Digital Computer)算法即坐标旋转数字计算方法,是J.D.Volder1于1959年首次提出,主要用于三角函数.双曲 ...
- FPGA之CORDIC算法实现_理论篇(上)
关于cordic的算法原理核心思想就是规定好旋转角度,然后通过不停迭代逐步逼近的思想来实现数学求解,网上关于这部分的资料非常多,主要可以参考: 1)https://blog.csdn.net/qq_3 ...
- 基于FPGA的肤色识别算法实现
大家好,给大家介绍一下,这是基于FPGA的肤色识别算法实现. 我们今天这篇文章有两个内容一是实现基于FPGA的彩色图片转灰度实现,然后在这个基础上实现基于FPGA的肤色检测算法实现. 将彩色图像转化为 ...
- 使用CORDIC算法求解角度正余弦及Verilog实现
本文是用于记录在了解和学习CORDIC算法期间的收获,以供日后自己及他人参考:并且附上了使用Verilog实现CORDIC算法求解角度的正弦和余弦的代码.简单的testbench测试代码.以及在Mod ...
- 基于FPGA的中值滤波算法实现
在这一篇开篇之前,我需要解决一个问题,上一篇我们实现了基于FPGA的均值滤波算法的实现,最后的显示效果图上发现有一些黑白色的斑点,我以为是椒盐噪声,然后在做基于FPGA的中值滤波算法的实验时,我发现黑 ...
- 基于FPGA的腐蚀膨胀算法实现
本篇文章我要写的是基于的腐蚀膨胀算法实现,腐蚀膨胀是形态学图像处理的基础,,腐蚀在二值图像的基础上做"收缩"或"细化"操作,膨胀在二值图像的基础上做" ...
随机推荐
- android 回调
调函数(callback Function),顾名思义,用于回调的函数. 回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数.回调函数是一个工作流的一部分,由工作流来决定函数的调用 ...
- QT 信号与槽 QT简单加法器的实现
信号与槽 背景: 面向过程 模块之间低耦合设计(高内聚). 函数调用: 直接调用 回调调用(低耦合) 面向对象 模块之间低耦合设计(高内聚) 对象调用 直接调用 接口调用 QT: 信号与槽解决问题: ...
- bit-map牛刀小试:数组test[X]的值所有在区间[1, 8000]中, 现要输出test中反复的数。要求:1. 不能改变原数组; 2.时间复杂度为O(X);3.除test外空间不超过1KB
先来看看这个题目:数组test[X]的值所有在区间[1, 8000]中. 现要输出test中反复的数.要求:1. 不能改变原数组; 2.时间复杂度为O(X);3.除test外空间不超过1KB. 好, ...
- li span兼容性问题
li与span的搭配使用所产的浏览器兼容性问题 1.ls两位,设定了width还是没用.2.总结了一下就是,里面的标签漂浮以后,就不能撑起外层的容器了. 3.li要设至少一个宽度或高度,还要加上ove ...
- 从Excel转Access的一个方法说开去(DataRow的state状态)
因为客户对access不太熟悉,更喜欢玩EXCEL.但是系统要求导入ACCESS.所以我们得做个把EXCEL转换成Access的小工具.(别问我为啥不让系统直接导入excel....我不知道!),然后 ...
- 性能优化工具---vmstat
作用: 报告关于内核线程.虚拟内存.磁盘.陷阱和 CPU 活动的统计信息 参数: 通过两个数字参数来完成的,第一个参数是采样的时间间隔数,单位是秒,第二个参数是采样的次数 显示说明: 第一行数据反映开 ...
- VlanTrunk
简单的vlan trunk的配置: 第一步:添加vlan 1 Switch>enable 2 Switch#show vlan VLAN Name Status Ports ---- ----- ...
- WCF---服务发布的步骤
服务发布的步骤: 1.打开你的VS2012网站项目,右键点击项目>菜单中 重新生成一下网站项目:再次点击右键>发布: 2.弹出网站发布设置面板,点击<新建..>,创建新的发布配 ...
- XStream和Json
XStream的作用 XStream可以把JavaBean对象转换成XML! 通常服务器向客户端响应的数据都是来自数据库的一组对象,而我们不能直接把对象响应给响应端,所以我们需要把对象转换成XML再响 ...
- TOJ 1702.A Knight's Journey
2015-06-05 问题简述: 有一个 p*q 的棋盘,一个骑士(就是中国象棋里的马)想要走完所有的格子,棋盘横向是 A...Z(其中A开始 p 个),纵向是 1...q. 原题链接:http:// ...