使用verilog 实现 cordic 算法 ----- 旋转模式

news/2025/2/21 14:49:28/

1-设计流程

● 了解cordic 算法原理,公式,模式,伸缩因子,旋转方向等,推荐以下链接视频了解 cordic 算法。哔哩哔哩-cordic算法原理讲解
● 用matlab 或者 c 实现一遍算法
● 在FPGA中用 verilog 实现,注意使用有符号变量以及小数点定点化处理

备注:
在verilog 需要用 ram 存储的值:列举了13次迭代的tan值和对应角度;
在这里插入图片描述

2-RTL

分享自己写的一个cordic rtl :

2-1 测试代码 ,测试 一二三四象限内角度的sin cos 值。

module test_my_cordic(input i_clk,input i_rst);reg signed	[31:0]	r_angle;
reg					r_valid ;wire				w_ready;
wire signed	[31:0]	r_x = 39796;
wire signed	[31:0]	r_y = 0;(*dont_touch = "true"*)
my_cordic inst_my_cordic
(.i_clk             (i_clk),.i_rst             (i_rst),.i_iteration_count (16), //设置迭代次数 ,最大16次.i_setx            (r_x),.i_sety            (r_y),.i_set_angle       (r_angle),.i_valid           (r_valid),.o_sin             (),.o_cos             (),.o_valid           (),.o_ready           (w_ready)
);/*  测试 第四象限  0 ~ -90°
always @ (posedge i_clk or posedge i_rst) 
beginif (i_rst) beginr_angle <= 0;end else if (r_angle == -5898240 && w_ready) beginr_angle <= 0;	end else if (w_ready && r_valid) beginr_angle <= r_angle - 655360;	end else beginr_angle <= r_angle;			end
end
*/// 测试 第一象限 0 ~ 90°
always @ (posedge i_clk or posedge i_rst) 
beginif (i_rst) beginr_angle <= 0;end else if (r_angle == 5898240 && w_ready) beginr_angle <= 0;	end else if (w_ready && r_valid) beginr_angle <= r_angle + 655360;	end else beginr_angle <= r_angle;			end
end/* //测试 第三象限 -180 ~ -90°
always @ (posedge i_clk or posedge i_rst) 
beginif (i_rst) beginr_angle <= -11796480;end else if (r_angle == -5898240 && w_ready) beginr_angle <= -11796480;	end else if (w_ready && r_valid) beginr_angle <= r_angle + 655360;	end else beginr_angle <= r_angle;			end
end
*//*// 测试 第二象限 90° ~ 180 °
always @ (posedge i_clk or posedge i_rst) 
beginif (i_rst) beginr_angle <= 5898240;end else if (r_angle == 11796480 && w_ready) beginr_angle <= 0;	end else if (w_ready && r_valid) beginr_angle <= r_angle + 655360;	end else beginr_angle <= r_angle;			end
end
*/always @ (posedge i_clk or posedge i_rst) 
beginif (i_rst) r_valid <= 0;else if (w_ready && r_valid)r_valid <= 0;else if  (w_ready)r_valid <= 1;			else r_valid <= 0;	
endendmodule

2-2 核心代码:

//运算公式:
//x(i+1) = x(i) - y(i) * di * 2^(-i)
//y(i+1) = y(i) + x(i) * di * 2^(-i)
//z(i+1) = z(i) - arctan(di * 2^(-i))
//author : 技术小白爱FPGA
//备注:cordic 算法,旋转模式,迭代次数固定 16次,可以自己任意设置,最大16次module my_cordic (input                    i_clk                   ,input                    i_rst                   ,input [4:0]              i_iteration_count       ,input  signed [31:0]     i_setx                  ,input  signed [31:0]     i_sety                  ,input  signed [31:0]     i_set_angle             ,input                    i_valid                 ,output   signed [31:0]   o_sin                   ,output   signed [31:0]   o_cos                   ,output                   o_valid                 ,output                   o_ready    );wire signed	[31:0]	r_arctan [0:15];
wire				r_di ;reg signed	[31:0]	r_sin;
reg signed	[31:0]	r_cos;
reg signed	[31:0]	r_setx ;
reg signed	[31:0]	r_sety ;
reg signed	[31:0]	r_angle ;
reg	[4:0]			r_count;
reg					r_run_cal;
reg					ro_valid ;
reg					ro_ready ;
reg	[1:0]			r_site;assign o_sin   = r_sin;
assign o_cos   = r_cos;
assign o_ready = ro_ready;
assign o_valid = ro_valid;//存储 arctan 值,整体表示-----扩大2^16倍数,相当于将小数点定在16bit位置上
assign	r_arctan[0] = 2949120;
assign	r_arctan[1] = 1740967;
assign	r_arctan[2] = 919879;
assign	r_arctan[3] = 466945;
assign	r_arctan[4] = 234378;
assign	r_arctan[5] = 117303;
assign	r_arctan[6] = 58666;
assign	r_arctan[7] = 29334;
assign	r_arctan[8] = 14667;
assign	r_arctan[9] = 7333;
assign	r_arctan[10]= 3666;
assign	r_arctan[11]= 1833;
assign	r_arctan[12]= 916;
assign	r_arctan[13]= 458;
assign	r_arctan[14]= 229;
assign	r_arctan[15]= 114;//判断旋转的方向
assign r_di = (r_angle > 0 && r_run_cal)?1:0;//运算迭代  >>>  --- > 算数右移,不改变符号位; 如果使用 >> ,移位,高位补0;
always @ (posedge i_clk) 
beginif (i_valid) beginr_setx <= i_setx;r_sety <= i_sety;endelse if (r_run_cal && r_di ) beginr_setx <= r_setx - (r_sety >>> r_count);r_sety <= r_sety + (r_setx >>> r_count);		end else if (r_run_cal && !r_di) beginr_setx <= r_setx + (r_sety >>> r_count);r_sety <= r_sety - (r_setx >>> r_count);	end
end//旋转角度的迭代,输入角度的象限处理
always @ (posedge i_clk ) 
begin// 处理 一四象限 -90° ~ 90°if (i_valid && (i_set_angle >= -5898240 && i_set_angle <= 5898240 ) ) beginr_angle <= i_set_angle;r_site  <= 2'b00;// 处理 二象限 90° ~ 180°end else if (i_valid && (i_set_angle > 5898240 && i_set_angle <= 11796480 )) beginr_angle <= 11796480 - i_set_angle;r_site  <= 2'b10;// 处理 三象限 -180° ~ -90°end else if (i_valid && (i_set_angle >= -11796480 && i_set_angle < -5898240 )) beginr_angle <= -11796480 - i_set_angle ;r_site  <= 2'b11;end else if (r_di && r_run_cal) beginr_angle <= r_angle - r_arctan[r_count];		endelse if (!r_di && r_run_cal) beginr_angle <= r_angle + r_arctan[r_count];		end else beginr_angle <= r_angle;r_site  <= r_site ;end
end//迭代运算次数
always @ (posedge i_clk or posedge i_rst) 
beginif (i_rst) beginr_count <= 0;end else if (r_count == i_iteration_count -1) beginr_count <= 0;endelse if (r_run_cal) beginr_count <= r_count + 1;end
end//迭代运算标志
always @ (posedge i_clk or posedge i_rst) 
beginif (i_rst) beginr_run_cal <= 0;endelse if (r_count == i_iteration_count -1) beginr_run_cal <= 0;	endelse if(i_valid) beginr_run_cal <= 1;		endelse beginr_run_cal <= r_run_cal;	end
end//最终输出的 sin cos 值
always @ (posedge i_clk or posedge i_rst) 
beginif (i_rst) beginr_sin <= 0;r_cos <= 0;endelse if (r_site == 2'b00 && r_count == i_iteration_count -1) beginr_sin <= r_sety;r_cos <= r_setx;		end else if (r_site == 2'b10 && r_count == i_iteration_count -1) beginr_sin <= r_sety;r_cos <= -r_setx;	end else if (r_site == 2'b11 && r_count == i_iteration_count -1) beginr_sin <= r_sety;r_cos <= -r_setx;	end
endalways @ (posedge i_clk or posedge i_rst) 
beginif (i_rst) beginro_ready <= 1;endelse if (i_valid || r_run_cal) beginro_ready <= 0;		end else beginro_ready <= 1;end
end//最终输出的 sin cos valid 信号
always @ (posedge i_clk or posedge i_rst) 
beginif (i_rst) ro_valid <= 0;else if (r_count == i_iteration_count -1)ro_valid <= 1;		else ro_valid <= 0;	
endendmodule

2-3 tb仿真代码

module tb_cordic();reg i_clk;
reg i_rst;initial begin i_clk = 0;i_rst = 1;#100@(posedge i_clk)i_rst =0;
endalways #10 i_clk = ~i_clk;test_my_cordic inst_test_my_cordic (.i_clk(i_clk), .i_rst(i_rst));endmodule

3-仿真

a. 首先 有符号的信号需要设置 小数点位数,如下图所示:
在这里插入图片描述
b. 以第一象限为例子:0 ~ 90°
在这里插入图片描述
c. 运算处理 持续周期 就是 迭代次数:
在这里插入图片描述

d. 可借助 计算机科学模式验证结果:
在这里插入图片描述

4-可优化空间

● r_ange逻辑级数;
● 360°以内,高于180°和小于-180°处理
● 迭代运算拆成流水线形式;
● 加上向量模式
● 整体其它逻辑的优化

http://www.ppmy.cn/news/1573541.html

相关文章

调用deepseek接口

首次调用 http请求 curl https://api.deepseek.com/chat/completions \-H "Content-Type: application/json" \-H "Authorization: Bearer <DeepSeek API Key>" \-d {"model": "deepseek-chat","messages": [{"…

day53 第十一章:图论part04

110.字符串接龙 bfs: 求最短路径长度 # bfs from collections import deque from collections import defaultdict def bfs(beginStr, endStr, strDict):que deque()que.append(beginStr)strDict[beginStr] 1while que:curStr que.popleft()curList list(curStr)for i in …

@Autowired注解(springboot)

Autowired 注解的说明 Autowired 是 Spring 框架中的一个重要注解&#xff0c;用于实现依赖注入&#xff08;Dependency Injection, DI&#xff09;。它可以让 Spring 容器自动将所需的依赖项注入到类中&#xff0c;而无需手动创建或查找这些依赖项。这有助于减少代码耦合&…

【Docker】容器被停止/删除的方式及命令:全面解析与实践指南

文章目录 引言一、容器的生命周期二、停止容器的命令及方式1. docker stop 命令2. docker kill 命令3. docker pause 和 docker unpause 命令4. docker restart 命令 三、删除容器的命令及方式1. docker rm 命令2. docker container prune 命令3. docker rm 与 docker rmi 的区…

NetCDF数据处理

NetCDF 文件格式在气象数据工程领域占据着举足轻重的地位&#xff0c;其结构灵活、强兼容性等优势使其成为该领域的一个标准。无论是从事学术研究还是工程实践&#xff0c;掌握这种数据格式变得越发重要。其次&#xff0c;我注意到气象编程大多数课程都聚焦于某个特定库的使用方…

基于SpringBoot+vue+uniapp的投票小程序+LW示例参考

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…

单片机原理与运用

个人主页&#xff1a;java之路-CSDN博客(期待您的关注) 目录 一、走进单片机的世界 二、单片机是什么 &#xff08;一&#xff09;定义与本质 &#xff08;二&#xff09;与普通计算机的区别 三、单片机的工作原理深度剖析 &#xff08;一&#xff09;硬件组成及功能 &am…

filebeat抓取nginx日志

目录 一、抓取普通的应用输出日志到elasticsearch 二、抓取nginx日志输出到ElasticSearch 2.1、nginx.conf设定日志输出为JSON格式 2.2、nginx.conf设定日志按天输出文件 2.3、抓取Nginx JSON到ElasticSearch配置 一、抓取普通的应用输出日志到elasticsearch - type: log…