用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.rhkb.cn/news/269350.html

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

相关文章

双链表——“数据结构与算法”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰又回来了&#xff0c;到了好久没有更新的数据结构与算法专栏&#xff0c;最近确实发现自己有很多不足&#xff0c;需要学习的内容也有很多&#xff0c;所以之后更新文章可能不会像之前那种一天一篇或者一天两篇啦&…

红帆OA 多处 SQL注入漏洞复现

0x01 产品简介 红帆iOffice.net从最早满足医院行政办公需求(传统OA),到目前融合了卫生主管部门的管理规范和众多行业特色应用,是目前唯一定位于解决医院综合业务管理的软件,是最符合医院行业特点的医院综合业务管理平台,是成功案例最多的医院综合业务管理软件。 0x02 漏…

网络安全: Kali Linux 使用 docker-compose 部署 openvas

目录 一、实验 1.环境 2.Kali Linux 安装docker与docker-compose 3.Kali Linux 使用docker-compose方式部署 openvas 4. KaliLinux 使用openvas 二、问题 1. 信息安全漏洞库 2.信息安全漏洞共享平台 3.Windows 更新指南与查询 4.CVE 查询 5.docker-compose 如何修改o…

哪些型号的高速主轴适合PCB分板机

在选择适合PCB分板机的高速主轴时&#xff0c;SycoTec品牌提供了丰富的型号选择&#xff0c;主要型号包括4025 HY、4033 AC&#xff08;电动换刀&#xff09;、4033 AC-ESD、4033 DC-T和4041 HY-ESD等。 那么如何选择合适的PCB分板机高速主轴型号呢&#xff1f;在选择适合PCB分…

LZO索引文件失效说明

在hive中创建lzo文件和索引时&#xff0c;进行查询时会出现问题.hive的默认输入格式是开启小文件合并的&#xff0c;会把索引也合并进来。所以要关闭hive小文件合并功能&#xff01;

day03_Vue_Element

文章目录 01.Ajax1.1 Ajax 概述1.2 同步异步1.3 原生Ajax 2. Axios2.1 Axios的基本使用2.2 Axios快速入门2.3请求方法的别名2.4 案例 3 前后台分离开发3.1 前后台分离开发介绍 04 YAPI4.1 YAPI介绍4.2 接口文档管理 05 前端工程化5.1 前端工程化介绍5.2 前端工程化入门5.2.1 环…

小程序学习

1、小程序体验 2、注册账号 小程序 (qq.com) 3、开发工具下载 下载 / 稳定版更新日志 (qq.com) 4、目录结构 "navigationBarBackgroundColor": "#00b26a" 配置头部背景色 4、wxml模板介绍 5、wxss 6、js文件 7、宿主环境 1、通信主体 2、运行机制 3、…

网工学习 DHCP配置-接口模式

网工学习 DHCP配置-接口模式 学习DHCP总是看到&#xff0c;接口模式、全局模式、中继模式。理解起来也不困难&#xff0c;但是自己动手操作起来全是问号。跟着老师视频配置啥问题没有&#xff0c;自己组建网络环境配置就是不通&#xff0c;悲催。今天总结一下我学习接口模式的…

动手学深度学习—循环神经网络RNN详解

循环神经网络 循环神经网络的步骤&#xff1a; 处理数据 将数据按照批量大小和时间步数进行处理&#xff0c;最后得到迭代器&#xff0c;即每一个迭代的大小是批量大小时间步数&#xff0c;迭代次数根据整个数据的大小决定&#xff0c;最后得出处理的数据&#xff08;参照第三…

基于SpringBoot的物业管理系统

** &#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;** 一 、设计说明 1.1 研究…

Elasticsearch:使用 Streamlit、语义搜索和命名实体提取开发 Elastic Search 应用程序

作者&#xff1a;Camille Corti-Georgiou 介绍 一切都是一个搜索问题。 我在 Elastic 工作的第一周就听到有人说过这句话&#xff0c;从那时起&#xff0c;这句话就永久地印在了我的脑海中。 这篇博客的目的并不是我出色的同事对我所做的相关陈述进行分析&#xff0c;但我首先…

Python的PrettyTable模块

Python的PrettyTable模块 1.PrettyTable介绍与基本使用 ​ 在使用Python查询表格数据的时候&#xff0c;直接print出来的话。数据杂乱无章&#xff0c;这个使用就可以使用PrettyTable模块来解决这个问题。如下图: 这样在输出的窗口可以很清晰看到所需要的信息。那么类似这种表…

更换个人开发环境后,pycharm连接服务器报错Authentication failed

原因&#xff1a;服务器中更换个人开发环境后&#xff0c;密码变了。 解决&#xff1a;在pycharm中修改服务器开发环境密码即可。 1 找到Tools-Depolyment-Configuration 2 点击SSH Configuration后的省略号 3 修改这里面的Password即可

autodock分子对接操作步骤完整版

对接完整步骤具体操作 设置工作目录 保证工作目录下必须要有这五个文件&#xff1a; 对蛋白质的操作 打开蛋白质 去水&#xff0c;结构周围的小红点。 加氢 将蛋白质设为受体 点击确定进行保存 进行下一步小分子 小分子具体操作 打开小分子 对小分子进行加氢 将小分子设定为配…

第三篇【传奇开心果系列】Python的自动化办公库技术点案例示例:深度解读Pandas股票市场数据分析

传奇开心果博文系列 系列博文目录Python的自动化办公库技术点案例示例系列 博文目录前言一、Pandas进行股票市场数据分析常见步骤和示例代码1. 加载数据2. 数据清洗和准备3. 分析股票价格和交易量4. 财务数据分析 二、扩展思路介绍1. 技术指标分析2. 波动性分析3. 相关性分析4.…

HTML5:七天学会基础动画网页7

CSS3高级特效 2D转换方法 移动:translate() 旋转:rotate() 缩放:scale() 倾斜:skew() 属性:transform 作用:对元素进行移动,旋转,缩放,倾斜。 2D移动 设定元素从当前位置移动到给定位置(x,y) 方法 说明 translate(x,y) 2D转换 沿X轴和Y轴移…

【李沐论文精读】Transformer精读

论文&#xff1a;Attention is All You Need 参考&#xff1a;李沐视频【Transformer论文逐段精读】、Transformer论文逐段精读【论文精读】、李沐视频精读系列 一、摘要 主流的序列转换(sequence transduction)模型都是基于复杂的循环或卷积神经网络&#xff0c;这个模型包含一…

云计算,用价格让利换创新空间?

文 | 智能相对论 作者 | 李源 ECS&#xff08;云服务器&#xff09;最高降36%、OSS&#xff08;对象存储&#xff09;最高降55%、RDS&#xff08;云数据库&#xff09;最高降40%…… 阿里云惊人的降幅&#xff0c;一次性把国内云计算厂商的价格战推到了白热化阶段。 这次能…

LVS负载均衡集群的基本介绍

目录 一、LVS集群基本介绍 1、什么是集群 2、集群的类型 2.1 负载均衡群集&#xff08;Load Balance Cluster) 2.2 高可用群集(High Availiablity Cluster) 2.3 高性能运算群集(High Performance Computing Cluster) 3、负载均衡集群的结构 4、LVS集群类型中的术语 5、…

【javaEE-唠嗑局】如何用jconsole观察进程里的多线程情况

&#x1f4e2;编程环境&#xff1a;idea 如何用jconsole观察进程里的多线程情况 1. 打开jdk2. 打开jconsole3. 查看每个线程的情况 以下面这段代码为例&#xff1a;代码运行时&#xff0c;包括一个进程&#xff0c;该进程中有两个线程。 package thread; public class Demo1 …