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

news2025/7/11 14:37:39

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) 
begin
	if (i_rst) begin
		r_angle <= 0;
	end else if (r_angle == -5898240 && w_ready) begin
		r_angle <= 0;	
	end else if (w_ready && r_valid) begin
		r_angle <= r_angle - 655360;	
	end else begin
		r_angle <= r_angle;			
	end
end
*/

// 测试 第一象限 0 ~ 90°
always @ (posedge i_clk or posedge i_rst) 
begin
	if (i_rst) begin
		r_angle <= 0;
	end else if (r_angle == 5898240 && w_ready) begin
		r_angle <= 0;	
	end else if (w_ready && r_valid) begin
		r_angle <= r_angle + 655360;	
	end else begin
		r_angle <= r_angle;			
	end
end

/* //测试 第三象限 -180 ~ -90°
always @ (posedge i_clk or posedge i_rst) 
begin
	if (i_rst) begin
		r_angle <= -11796480;
	end else if (r_angle == -5898240 && w_ready) begin
		r_angle <= -11796480;	
	end else if (w_ready && r_valid) begin
		r_angle <= r_angle + 655360;	
	end else begin
		r_angle <= r_angle;			
	end
end
*/

/*// 测试 第二象限 90° ~ 180 °
always @ (posedge i_clk or posedge i_rst) 
begin
	if (i_rst) begin
		r_angle <= 5898240;
	end else if (r_angle == 11796480 && w_ready) begin
		r_angle <= 0;	
	end else if (w_ready && r_valid) begin
		r_angle <= r_angle + 655360;	
	end else begin
		r_angle <= r_angle;			
	end
end
*/

always @ (posedge i_clk or posedge i_rst) 
begin
	if (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;	
end

endmodule

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) 
begin
	if (i_valid) begin
		r_setx <= i_setx;
		r_sety <= i_sety;
	end
	else if (r_run_cal && r_di ) begin
		r_setx <= r_setx - (r_sety >>> r_count);
		r_sety <= r_sety + (r_setx >>> r_count);		
	end else if (r_run_cal && !r_di) begin
		r_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 ) ) begin
		r_angle <= i_set_angle;
		r_site  <= 2'b00;
	// 处理 二象限 90° ~ 180°
	end else if (i_valid && (i_set_angle > 5898240 && i_set_angle <= 11796480 )) begin
		r_angle <= 11796480 - i_set_angle;
		r_site  <= 2'b10;
	// 处理 三象限 -180° ~ -90°
	end else if (i_valid && (i_set_angle >= -11796480 && i_set_angle < -5898240 )) begin
		r_angle <= -11796480 - i_set_angle ;
		r_site  <= 2'b11;
	end else if (r_di && r_run_cal) begin
		r_angle <= r_angle - r_arctan[r_count];		
	end
	else if (!r_di && r_run_cal) begin
		r_angle <= r_angle + r_arctan[r_count];		
	end else begin
		r_angle <= r_angle;
		r_site  <= r_site ;
	end
end

//迭代运算次数
always @ (posedge i_clk or posedge i_rst) 
begin
	if (i_rst) begin
		r_count <= 0;
	end else if (r_count == i_iteration_count -1) begin
		r_count <= 0;
	end
	else if (r_run_cal) begin
		r_count <= r_count + 1;
	end
end

//迭代运算标志
always @ (posedge i_clk or posedge i_rst) 
begin
	if (i_rst) begin
		r_run_cal <= 0;
	end
	else if (r_count == i_iteration_count -1) begin
		r_run_cal <= 0;	
	end
	else if(i_valid) begin
		r_run_cal <= 1;		
	end
	else begin
		r_run_cal <= r_run_cal;	
	end
end

//最终输出的 sin cos 值
always @ (posedge i_clk or posedge i_rst) 
begin
	if (i_rst) begin
		r_sin <= 0;
		r_cos <= 0;
	end
	else if (r_site == 2'b00 && r_count == i_iteration_count -1) begin
		r_sin <= r_sety;
		r_cos <= r_setx;		
	end else if (r_site == 2'b10 && r_count == i_iteration_count -1) begin
		r_sin <= r_sety;
		r_cos <= -r_setx;	
	end else if (r_site == 2'b11 && r_count == i_iteration_count -1) begin
		r_sin <= r_sety;
		r_cos <= -r_setx;	
	end
end

always @ (posedge i_clk or posedge i_rst) 
begin
	if (i_rst) begin
		ro_ready <= 1;
	end
	else if (i_valid || r_run_cal) begin
		ro_ready <= 0;		
	end else begin
		ro_ready <= 1;
	end
end

//最终输出的 sin cos valid 信号
always @ (posedge i_clk or posedge i_rst) 
begin
	if (i_rst) 
		ro_valid <= 0;
	else if (r_count == i_iteration_count -1)
		ro_valid <= 1;		
	else 
		ro_valid <= 0;	
end

endmodule

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;
end

always #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.coloradmin.cn/o/2298785.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【css】width:100%;padding:20px;造成超出100%宽度的解决办法 - box-sizing的使用方法 - CSS布局

问题 修改效果 解决方法 .xx {width: 100%;padding: 0 20px;box-sizing: border-box; } 默认box-sizing: content-box下&#xff0c; width 内容的宽度 height 内容的高度 宽度和高度的计算值都不包含内容的边框&#xff08;border&#xff09;和内边距&#xff08;padding&…

贪心算法_翻硬币

蓝桥账户中心 依次遍历 不符合条件就反转 题目要干嘛 你就干嘛 #include <bits/stdc.h>#define endl \n using namespace std;int main() {ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); string s; cin >> s;string t; cin >> t;int ret 0;for ( i…

深入HBase——引入

引入 前面我们通过深入HDFS到深入MapReduce &#xff0c;从设计和落地&#xff0c;去深入了解了大数据最底层的基石——存储与计算是如何实现的。 这个专栏则开始来看大数据的三驾马车中最后一个。 通过前面我们对于GFS和MapReduce论文实现的了解&#xff0c;我们知道GFS在数…

2025年02月12日Github流行趋势

项目名称&#xff1a;data-formulator 项目地址url&#xff1a;https://github.com/microsoft/data-formulator 项目语言&#xff1a;TypeScript 历史star数&#xff1a;4427 今日star数&#xff1a;729 项目维护者&#xff1a;danmarshall, Chenglong-MS, apps/dependabot, mi…

【落羽的落羽 数据结构篇】双向链表

文章目录 一、链表的分类二、双向链表1. 结构2. 申请一个新节点3. 尾部插入数据4. 头部插入数据5. 尾部删除数据6. 头部删除数据7. 在指定位置之后插入数据8. 删除指定位置节点9. 销毁链表 一、链表的分类 链表的分类实际上要从这三个方向分析&#xff1a;是否带头、单向还是双…

Golang的并发编程问题解决思路

Golang的并发编程问题解决思路 一、并发编程基础 并发与并行 在计算机领域&#xff0c;“并发”和“并行”经常被混为一谈&#xff0c;但它们有着不同的含义。并发是指一段时间内执行多个任务&#xff0c;而并行是指同时执行多个任务。在 Golang 中&#xff0c;通过 goroutines…

剑指offer第2版:搜索算法(二分/DFS/BFS)

查找本质就是排除的过程&#xff0c;不外乎顺序查找、二分查找、哈希查找、二叉排序树查找、DFS/BFS查找 一、p39-JZ3 找出数组中重复的数字&#xff08;利用特性&#xff09; 数组中重复的数字_牛客题霸_牛客网 方法1&#xff1a;全部排序再进行逐个扫描找重复。 时间复杂…

在 CentOS 上更改 SSH 默认端口以提升服务器安全性

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode︱ Gitee ︱ Github &#x1f496; 欢迎点赞 &#x1f44d; 收藏 ⭐评论 …

2025年:边缘计算崛起下运维应对新架构挑战

一、引言 随着科技的飞速发展&#xff0c;2025年边缘计算正以前所未有的速度崛起&#xff0c;给运维行业带来了全新的架构挑战。在这个充满机遇与挑战的时代&#xff0c;美信时代公司的美信监控易运维管理软件成为运维领域应对这些挑战的有力武器。 二、边缘计算崛起带来的运维…

怎么理解 Spring Boot 的约定优于配置 ?

在传统的 Spring 开发中&#xff0c;大家可能都有过这样的经历&#xff1a;项目还没开始写几行核心业务代码&#xff0c;就已经在各种配置文件中耗费了大量时间。比如&#xff0c;要配置数据库连接&#xff0c;不仅要在 XML 文件里编写冗长的数据源配置&#xff0c;还要处理事务…

学习总结2.14

深搜将题目分配&#xff0c;如果是两个题目&#xff0c;就可以出现左左&#xff0c;左右&#xff0c;右左&#xff0c;右右四种时间分配&#xff0c;再在其中找最小值&#xff0c;即是两脑共同处理的最小值 #include <stdio.h> int s[4]; int sum0; int brain[25][25]; …

Electron 客户端心跳定时任务调度库调研文档 - Node.js 任务调度库技术调研文档

Electron 客户端心跳定时任务调度库调研文档 - Node.js 任务调度库技术调研文档 本文将对七个流行的定时任务调度库&#xff1a;node-cron、rxjs、bull、node-schedule、agenda、bree、cron。这些库都可以用来处理定时任务&#xff0c;但它们的特点和适用场景有所不同。我们将从…

【学术投稿-第四届智能电网和绿色能源国际学术会议(ICSGGE 2025)】CSS基本选择器详解:掌握基础,轻松布局网页

可线上 官网&#xff1a;www.icsgge.org 时间&#xff1a;2025年2月28-3月2日 目录 前言 一、基本选择器简介 1. 元素选择器&#xff08;Type Selector&#xff09; 基本语法 示例 注意事项 2. 类选择器&#xff08;Class Selector&#xff09; 基本语法 示例 注意…

singleTaskAndroid的Activity启动模式知识点总结

一. 前提知识 1.1. 任务栈知识 二. Activity启动模式的学习 2.1 standard 2.2 singleTop 2.3.singleTask 2.4.singleInstance 引言&#xff1a; Activity作为四大组件之一&#xff0c;也可以说Activity是其中最重要的一个组件&#xff0c;其负责调节APP的视图&#xff…

Vue 入门到实战 十

第10章 Vue Router​​​​​​​ 目录 10.1 什么是路由 10.2 Vue Router的安装 10.2.1 本地独立版本方法 10.2.2 CDN方法 10.2.3 NPM方法 10.2.4 命令行工具&#xff08;Vue CLI&#xff09;方法 10.3 Vue Router的基本用法 10.3.1 跳转与传参 10.3.2 配置路由 10.…

jenkins-获取当前时间戳

一. 简述&#xff1a; 很多场景下&#xff0c;需要获取当前时间戳。 二. 使用方法&#xff1a; 1. 安装&#xff1a; 最简单的&#xff0c; 莫过于直接部署相关插件&#xff1a; Build Timestamp Plugin 2. 配置&#xff1a; 3. 使用&#xff1a; post {success {script…

【Jenkins流水线搭建】

Jenkins流水线搭建 01、SpringBoot项目 - Jenkins基于Jar持续集成搭建文档基于手动方式发布项目基于dockerfile基于jenkins + dockerfile + jenkinsfile +pieline基于jenkins + jar方式的发布01、环境说明01、准备项目02、准备服务器03、安装git04、安装jdk1.805、安装maven依赖…

【Java】规则引擎 Drools

https://www.bilibili.com/video/BV1nW421R7qJ 来自尚硅谷 背景 /*** 设置订单积分*/ public void setOrderPoint(Order order){if (order.getAmout() < 100){order.setScore(0);}else if(order.getAmout() > 100 && order.getAmout() < 500){order.setScore(…

深入浅出Java反射:掌握动态编程的艺术

小程一言反射何为反射反射核心类反射的基本使用获取Class对象创建对象调用方法访问字段 示例程序应用场景优缺点分析优点缺点 注意 再深入一些反射与泛型反射与注解反射与动态代理反射与类加载器 结语 小程一言 本专栏是对Java知识点的总结。在学习Java的过程中&#xff0c;学习…

数据挖掘智能Agent

&#x1f917; CodeGenie - 智能编程助手 数据处理和分析对于数据分析工作人员来说&#xff0c;往往既复杂又令人头疼&#xff0c;需要耗费大量精力进行重复性工作。为了解决这一问题&#xff0c;我们开发了一款集成了自然语言处理和代码生成功能的智能编程助手——CodeGenie。…