用FPGA CORDIC IP核实现信号的相位检测,计算相位角

用FPGA CORDIC IP核实现信号的相位检测

1.matlab仿真

波形仿真代码:

代码功能:生成一个点频信号s,求出s的实部和虚部;并且结算相位角atan2。画出图形,并且将Q和I数据写入文件中。

%代码功能:生成一个点频信号s,求出s的实部和虚部;并且结算相位角atan2。画出图形,并且将Q和I数据写入
clc; clear;close all;F1=1; %信号频率
Fs=65536; %采样频率					Fs=N,能采一个周期
P1=45; %信号初始相位(单位:°),90-cos函数
N=65536; %采样点数
t=[0:1/Fs:(N-1)/Fs]; %采样时刻
A=2^15-1; %信号幅度%生成点频信号
s=A*exp(1i *(2*pi*F1*t + pi*P1/180));% IQ分解,分别提取实部和虚部
I = real(s);
Q = imag(s);% 计算相位角
phase = atan2(Q, I);% 提取初始相位(t=0处的相位值)
initial_phase = phase(1);
%显示初始相位值,将其转换为π的倍数进行显示 
disp(['初始相位值:', num2str(initial_phase/pi),'pi']);% 绘制结果图,画出signal信号的实部和虚部
figure;
subplot(3,1,1);
plot(t, real(s), 'b');
title('In-phase Component (I)');subplot(3,1,2);
plot(t, imag(s), 'r');
title('Quadrature Component (Q)');
xlabel('Time (s)');% 计算相位角
subplot(3,1,3);
plot(t, phase);
xlabel('时间');
ylabel('相位');
title('相位随时间变化');
%将纵坐标转化为Π的倍数
yticks([-1*pi, -0.5*pi, 0, 0.5*pi, pi]);
yticklabels({'-π', '-0.5π', '0', '0.5π', 'π'});%创建 coe 文件  Idatafild = fopen('Idata_65536x15bit.coe','wt');%写入 coe 文件头%固定写法,表示写入的数据是 10 进制表示fprintf(fild, '%s\n','memory_initialization_radix=10;');%固定写法,下面开始写入数据fprintf(fild, '%s\n\n','memory_initialization_vector ='); for i = 1:Ns2(i) = round(I(i)); %对小数四舍五入以取整fprintf(fild, '%d',s2(i)); %数据写入if i==Nfprintf(fild, '%s\n',';'); %最后一个数据用;elsefprintf(fild,',\n'); % 其他数据用,endendfclose(fild); % 写完了,关闭文件%创建 coe 文件  Qdatafild = fopen('Qdata_65536x15bit.coe','wt');%写入 coe 文件头%固定写法,表示写入的数据是 10 进制表示fprintf(fild, '%s\n','memory_initialization_radix=10;');%固定写法,下面开始写入数据fprintf(fild, '%s\n\n','memory_initialization_vector ='); for i = 1:Ns3(i) = round(Q(i)); %对小数四舍五入以取整fprintf(fild, '%d',s3(i)); %数据写入if i==Nfprintf(fild, '%s\n',';'); %最后一个数据用;elsefprintf(fild,',\n'); % 其他数据用,endendfclose(fild); % 写完了,关闭文件

​ 上面的代码除了生成下面的波形结果外,还将数据写入文件“Idata_65536x15bit.coe” 和 “Qdata_65536x15bit.coe”

可以在电脑win图标旁边直接搜索这两个文件,默认是在MATLAB文件中的一个文件夹中。

波形结果

在这里插入图片描述

2.FPGA实现

生成的点频信号signal 以及I,Q的分解,可以用ROM来输入。

用FPGA实现的关键以及难点是计算相位角phase = atan2(Q, I);

ROM

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

创建两个ROM,分别将Idata_65536x15bit 和 Qdata_65536x15bit 写入。

数学知识补充:atan和atan2

参考文章:atan2函数和atan函数 - 知乎 (zhihu.com)

在MATLAB中,atan和atan2函数都用于计算角度,但它们之间有一些重要的区别。

  1. atan函数:
  • atan函数是计算反正切值的标准函数,其语法为y = atan(x)。
  • atan函数返回的角度范围是[-π/2, π/2],即从-90度到90度之间。
  • atan函数只能接受一个参数,即y = atan(x),其中x是输入的实数值。
  1. atan2函数:
  • atan2函数是计算反正切值的扩展函数,其语法为y = atan2(y, x)。
  • atan2函数返回的角度范围是[-π, π],即从-180度到180度之间。
  • atan2函数可以处理所有四个象限的情况,避免了由于分母为零而导致的错误。
  • atan2函数接受两个参数,即y = atan2(y, x),其中y是输入的虚部,x是输入的实部。

​ 主要区别在于atan函数只能处理一个参数且返回值范围是[-π/2, π/2],而atan2函数可以处理两个参数且返回值范围是[-π, π],并且能够处理所有四个象限的情况。在处理复数的相位角度时,通常会使用atan2函数来确保得到正确的结果

这两个函数的转换关系

atan函数转换为atan2函数:(图片来自知乎)

在这里插入图片描述

  • x > 0, 是一、四象限的点,等价atan;
  • x < 0,是二、三象限的点,根据y的范围来确定:
    • y > 0,是第二象限的点,先用atan得到第四象限的弧度制,再加上Π就转换到了第二象限;
    • y < 0.是第三象限的点,先用atan得到第一象限的弧度制,再减去Π就转换到了第二象限;
  • x = 0,根据y的正负来确定
    • y > 0, 值为Π/2
    • y < 0,值为-Π/2
  • 注意,当x=0,y=0时,atan2(0,0)=0 (matlab中这样规定)

FPGA代码思路

VIVADO的CORDIC IP核中的Arc Tan ,可以直接计算atan2(自动将atan转换为atan2)。

CORDIC IP核使用

参考视频:FPGA IP之CORDIC使用与仿真_哔哩哔哩_bilibili

参考文章:FPGA数字信号处理(十四)Vivado Cordic IP核计算arctan_fpga arctan-CSDN博客

FPGA 代码

DDS_IQ模块,是DDS波形产生模块,读取ROM中存入的数据,生成两个波形 I_data 和 Q_data

module DDS_IQ
(input 				clk,    	//系统时钟input 				rst_n,output signed [15:0] I_data,output signed [15:0] Q_data);reg [15:0]r_Fword;		//频率控制字寄存器
reg [1:0]r_Pword;		//相位控制字寄存器
reg [31:0] Fcnt;		//累加寄存器
wire [15:0] I_rom_addr; 	//ROM地址,宽度:16位
wire [15:0] Q_rom_addr; 	//ROM地址,宽度:16位//将值存入寄存器
always@(posedge clk or negedge rst_n)beginif(!rst_n)beginr_Fword <= 16'd0;r_Pword <= 2'd0;endelse beginr_Fword <= 16'd1000;	r_Pword <= 2'd0;	end
end//累加
always@(posedge clk or negedge rst_n)beginif(!rst_n)Fcnt <= 32'd0;elseFcnt <= Fcnt + r_Fword;
end//相位调制器
assign I_rom_addr = Fcnt[31:15] + r_Pword;	//截取高位,并加上相位累加器的值
assign Q_rom_addr = Fcnt[31:15] + r_Pword;blk_mem_gen_I I_value(.clka(clk),    // input wire clka.ena(1'b1),      // input wire ena.addra(I_rom_addr),  // input wire [15 : 0] addra.douta(I_data)  // output wire [15 : 0] douta
);
blk_mem_gen_Q Q_value (.clka(clk),    // input wire clka.ena(1'b1),      // input wire ena.addra(Q_rom_addr),  // input wire [15 : 0] addra.douta(Q_data)  // output wire [15 : 0] douta
);endmodule

顶层 atan_top 模块,计算atan(Q/I)

module atan_top(input 				clk,    	//系统时钟input 				rst_n,input 				[15:0] I_data,input 				[15:0] Q_data,output signed 		out_valid,   //输出有效信号output signed [15:0]theta 		//arctan计算结果);//例化DDS_IQ模块,将两个信号引入	
DDS_IQ u_DDS_IQ(.clk		(clk),    	.rst_n		(rst_n),.I_data		(I_data),.Q_data		(Q_data)
);//输入I和Q,out=arctan(Q/I);
//tdata端口,虚部Q在前,实部I在后
cordic_1 u_cordic_1 (.aclk(clk),                                        // input wire aclk.aresetn(rst_n),                                  // input wire aresetn.s_axis_cartesian_tvalid(1'b1),  // input wire s_axis_cartesian_tvalid.s_axis_cartesian_tdata({Q_data[15],Q_data[15:1],I_data[15],I_data[15:1]}),    // input wire [31 : 0] s_axis_cartesian_tdata.m_axis_dout_tvalid(out_valid),            // output wire m_axis_dout_tvalid.m_axis_dout_tdata(theta)              // output wire [15 : 0] m_axis_dout_tdata
);
//输入的32位中,[15:0]为实部I,[16:31]为虚部Qendmodule
TB文件
module cordic_tb_top();//接口声明reg clk;reg rst_n;wire signed out_valid;wire signed [15:0]theta;wire signed[15:0]I_data;wire signed[15:0]Q_data;//initial handle = $fopen("F:/MY_WORK/3U_phase_discrimination/cordic.txt");//打开文件/*
//对被测的设计进行例化
DDS_IQ u_DDS_IQ(.clk		(clk),    	.rst_n		(rst_n),.I_data		(I_data),.Q_data		(Q_data)
);
*/
DDS_IQ u_DDS_IQ(.clk		(clk),    	.rst_n		(rst_n),.I_data		(I_data),.Q_data		(Q_data)
);atan_top u_atan_top(.clk		(clk),    	.rst_n		(rst_n),.I_data		(I_data),.Q_data		(Q_data),.out_valid	(out_valid),  .theta 		(theta)
);//产生时钟 50MHZ
initial clk = 1;
always #10 clk = ~clk;//测试激励产生
initial beginrst_n = 0;#200;rst_n = 1;end/*
always@(posedge clk) beginif(out_valid)$fdisplay(handle,"%b",theta);//写数据
end
*/endmodule
仿真结果

注意这三个波形为模拟波形,有符号数

在这里插入图片描述

结果分析

如何判断自己的仿真结果是正确的?

就以上面的仿真图片和下面的结果来验证一下

在这里插入图片描述

数据1:Q = 0 ; I = -32767 ; atan2 = 25736

数据2:Q = -25279; I = -20848; atan2 = -18517

这些数据如何转化为二进制,可以查看CORDIC IP核中的这个界面:

在这里插入图片描述

Q格式数据可以用Fix格式数据表示。

对于有符号数,表示为Fix(1+X+N)_N,X表示整数位数,N表示小数位数。

但是在这里的结果验证中,不需要转换数据格式就可以


  • 数据1:属于《数学知识补充:atan和atan2》 的第二种情况,x<0, y>=0

​ atan2(Q,I) = atan(Q/I) + Π = 0 + Π = Π

​ 而根据输出波形,atan2 = 25736,将它转换:25736/(2^13) = 3.1416

  • 数据2:属于《数学知识补充:atan和atan2》 的第三种情况,x<0, y<0

​ atan2(Q,I) = atan(Q/I) - Π

​ 其中,atan(Q/I) = atan(-25279/-20848) = atan(1.2125) = 0.88115 Radians

​ ∴ atan2(Q,I) = 0.88115 - Π = -2.26

而根据输出波形,atan2 = -18517,将它转换:-18517/(2^13) = -2.26


仿真结果符合事实

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/730677.shtml

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

相关文章

20.网络游戏逆向分析与漏洞攻防-网络通信数据包分析工具-数据分析工具数据类型编辑功能的实现

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易道云信息技术研究院VIP课 上一个内容&#xff1a;19.数据分析工具数据类型配置功能的实现 码云地址&#xff08;master 分支&#…

unity学习(49)——服务器三次注册限制以及数据库化角色信息4--角色信息数据库化

1.此处下断开始调试,list函数内就有问题&#xff1a; 2. 现在的问题是只读不写&#xff01;32行就是写入部分的代码&#xff1a; 3. 很奇怪&#xff0c;调试的时候确实是写进来了 程序正常执行后&#xff0c;文件中数据也没有消失 关闭服务器文件内容依旧正常。 players包含所…

MySQL篇—执行计划之覆盖索引Using index和条件过滤Using where介绍(第三篇,总共三篇)

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux&#xff0c;也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&#xff0c;并且也会默默的点赞收藏加关注❣…

提醒一下!今年考研的人不要太老实了!!

今年准备计算机考研的同学&#xff0c;别太老实了&#xff01;别人说什么你就信什么 如果你的工作能力不足以支撑找到一个满意的工作&#xff0c;那我建议再沉淀两年&#xff01; 很多同学其实有点眼高手低&#xff0c;在计算机专业&#xff0c;低于1w的工作看不上&#xff0…

操作系统引导

目录 一. 什么是操作系统引导 \quad 一. 什么是操作系统引导 \quad 什么是操作系统引导: 就是在开机的时候, 怎么让操作系统运行起来 操作系统是安装在C盘的 分区表用来说明C,D,E,F盘的存储空间 RAM一关机, 里面的数据就会被清空, ROM则不会 MBR里面的程序被读到RAM里面, 那…

qt自定义时间选择控件窗口

效果如图&#xff1a; 布局如图&#xff1a; 参考代码&#xff1a; //DateTimeSelectWidget #ifndef DATETIMESELECTWIDGET_H #define DATETIMESELECTWIDGET_H#include <QWidget> #include <QDateTime>namespace Ui { class DateTimeSelectWidget; }class DateTim…

单链表OJ题:LeetCode--141.环形链表

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下LeetCode中的第141道单链表OJ题&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; 数据结构与算法专栏&#xff1a;数据结构与算法 个 …

O2O:Sample Efficient Offline-to-Online Reinforcement Learning

IEEE TKDE 2024 paper Introduction O2O存在策略探索受限以及分布偏移问题&#xff0c;进而导致在线微调阶段样本效率低。文章提出OEMA算法首先使用离线数据训练乐观的探索策略&#xff0c;然后提出基于元学习的优化方法&#xff0c;减少分布偏移并提高O2O的适应过程。 Meth…

OpenHarmony教程指南-自定义通知推送

介绍 本示例主要展示了通知过滤回调管理的功能&#xff0c;使用ohos.notificationManager 接口&#xff0c;进行通知监听回调&#xff0c;决定应用通知是否发送。 效果预览 使用说明 1.在使用本应用时&#xff0c;需安装自定义通知角标应用&#xff1b; 2.在主界面&#xff…

重学SpringBoot3-WebMvcAutoConfiguration类

重学SpringBoot3-WebMvcAutoConfiguration类 是什么什么用生效条件作用 自定义配置的三种方式自定义配置举例1. 自定义 DispatcherServlet 配置2. 静态资源配置3. 自定义MVC配置4. 消息转换器5. 异常处理 是什么 org.springframework.boot.autoconfigure.web.servlet.WebMvcAut…

FPGA IBUFG

IBUFG和IBUFGDS的输入端仅仅与芯片的专用全局时钟输入管脚有物理连接&#xff0c;与普通IO和其它内部CLB等没有物理连接。 所以&#xff0c;IBUFG输入的不能直接接另外信号。 GTH transceiver primitives are called GTHE3_COMMON and GTHE3_CHANNEL in UltraScale FPGAs, an…

@RequestMapping与@GetMapping和@PostMapping等注解的区别

目录 前置知识 大致区别 使用场景上的注意事项 如何工作 使用案例 写法对比 前置知识 HTTP请求方法一共有9种&#xff0c;为&#xff1a;GET、POST、HEAD、OPTIONS、PUT、PATCH、DELETE、TRACE、CONNECTGET(获取资源) 本质就是发送一个请求来取得服务器上的某一资源&…

【Java代码审计】JNDI+RMI绕过高版本JDK的限制

【Java代码审计】JNDIRMI绕过高版本JDK的限制 1.高版本JDK利用注入导致的问题2.绕过分析3.Tomcat8绕过4.工具绕过 1.高版本JDK利用注入导致的问题 JDK 6u132、7u122、8u113 开始 com.sun.jndi.rmi.object.trustURLCodebase 默认值为false&#xff0c;运行时需加入参数 -Dcom.s…

Go语言物联网开发安科瑞ADW300/4G电能表数据上传mqtt平台-电表接线到传输数据完整流程

电能表功能说明 ADW300是方便用户进行用电监测、集抄和管理&#xff0c;可灵活安装在配电箱中&#xff0c;可用于电力运维、环保监管等在线监测类平台中。我们本案例是用于工业售电公司对出售电的管理&#xff0c;设备可以监控用电情况、故障监控及警报&#xff0c;售电公司可…

(完美方案)解决mfc140u.dll文件丢失问题,快速且有效的修复

唉&#xff0c;又是丢失了mfc140u.dll&#xff0c;这该怎么办呢&#xff1f;如果你的电脑突然找不到或丢失mfc140u.dll文件&#xff0c;那就真是太糟糕了。别担心&#xff0c;我分享给你一些干货&#xff0c;告诉你如何快速解决mfc140u.dll丢失的问题。 一.mfc140u.dll属性功能…

百度地图城市点位数据下载并转换

概述 在浏览百度地图开放平台的时候&#xff0c;发现有个资源下载页面&#xff0c;里面有个城市中心点位和百度地图行政区划adcode映射表数据&#xff0c;这是一个经常使用到的数据&#xff0c;本文实现将这个数据转换为geojson&#xff0c;并借助QGIS转换为经纬度坐标或火星坐…

LCR 175. 计算二叉树的深度

一、题目描述 LCR 175. 计算二叉树的深度 二、思路 递归求左右子树的高度 三、解题思路 把大规模的问题拆分成小规模的问题1、要求根节点的二叉树深度 2、转换子问题&#xff1a;求左子树为根节点的二叉树深度 3、转换子问题&#xff1a;成求右子树为根节点的二叉树深度 4、最…

宏auto关键字(C++基础)

宏 宏可以实现对语句的同义替换&#xff0c;简单来说就是预处理阶段、编译前的替换&#xff08;包括符号&#xff0c;变量等&#xff09;。 #define LOG(x) std::cout << x << std::endl; LOG("hello") 可以正常使用。 下面通过上图中借用不同开发模…

Threejs着色器(GPU)编程——感温管网

管网,作为支撑现代城市运转的重要基础设施,是隐藏在地面之下的庞大工程网络。这些管网如同城市的血脉,负责输送各种必要的资源,如水源、热力、燃气等,同时排除废水和其他废弃物。然而,由于其位于地下,人们往往难以直接感知其存在和运行状态。为了保障这些地下管网的安全…

Leetcode - 周赛387

目录 一&#xff0c;3069. 将元素分配到两个数组中 I 二&#xff0c;3070. 元素和小于等于 k 的子矩阵的数目 三&#xff0c;3071. 在矩阵上写出字母 Y 所需的最少操作次数 四&#xff0c;3072. 将元素分配到两个数组中 II 一&#xff0c;3069. 将元素分配到两个数组中 I 本…