FM的正交解调法

1.FM的模拟调制过程

​ FM信号是一种频率调制信号,其携带的信息保存在其信号的频率中,通过改变载波的频率来实现基带数据的传输。

其函数表达式如下:

\[s(t) = A*cos(w_c*t + K_f*\int m(\tau) d\tau) \]

其中:
A:表示载波幅度。
\(m(\tau)\):表示基带信号。
\(w_c\):表示载波信号角度增量。
\(K_f\):是调频灵敏度。

正交调制法公式如下:

\[\begin{array}{3} I(t) = cos(K_f*\int m(\tau) d\tau) \\Q(t) = sin(K_f*\int m(\tau) d\tau) \\s(t) = A*(I(t)*cos(w_c*t) - Q(t)*sin(w_c*t)) \end{array} \]

2.FM的数字正交解调

原理:

对于I路:

\[I(n) = cos(K_f*\int m(\tau) d\tau) = cos(K_f*\sum m(n)) \]

对于Q路:

\[Q(n) = sin(K_f*\int m(\tau) d\tau) = sin(K_f*\sum m(n)) \]

同时:

\[\begin{array}{c} \frac{Q(n)}{I(n)} = \frac{sin(K_f*\sum m(n))}{cos(K_f*\sum m(n))} = tan(K_f*\sum m(n)) \space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space\space (K_f*\sum m(n)) \in [-\pi/2\space\space\space\space\pi/2] \\ SUM(n) = arctan(\frac{Q(n)}{I(n)}) = K_f*\sum m(n) \\ M(n) = SUM(n) - SUM(n-1) = K_f* m(n) \end{array}\]

注:上式推算中使用了tan函数,其中tan的输入范围\([-\pi/2\space\space\space\space\pi/2]\)。当范围超过将计算错误。所以将使用MATLAB的atan2函数进行计算。

\[\begin{array}{c} SUM(n) = atan2(Q(n),I(n)) = K_f*\sum m(n) \\ M(n) = SUM(n) - SUM(n-1) = K_f* m(n) \end{array} \]

3.MATLAB仿真

仿真代码:

fs = 20000;%采样率
l = 1E3;%基带信号点数
f = 100;%基带信号
f_c = 2000;%载波信号
t = 0:1/fs:(l-1)/fs;
mt = cos(2*pi*f*t);
kf = fs * 0.4;
%% IQ信号
I = cos(kf*cumtrapz(t,mt));
Q = sin(kf*cumtrapz(t,mt));
%% 调制数据
mod_data = I.*cos(2*pi*f_c*t) - Q.*sin(2*pi*f_c*t);
%% 解调
mmm = atan2(Q,I);
demod = zeros(1,length(mmm));
for i = 2:1:length(demod)demod(i) = mmm(i) - mmm(i-1);if(demod(i) >= pi)demod(i) = demod(i) - pi*2; elseif(demod(i) <= -pi)demod(i) = demod(i) + pi*2;  else demod(i) =  demod(i); end
end%% 保存IQ数据FPGA使用仿真
fid = fopen('FM.txt','w');
for i = 1:lfprintf(fid,'%d %d\n',floor(I(i)* (2^13)),floor(Q(i)* (2^13)));
end
fclose(fid);%% 绘制
figure
time = 3;
subplot(time,1,1);
plot(mt);
title('基带数据');subplot(time,1,2);
plot(mod_data);
title('调制数据');subplot(time,1,3);
plot(demod);
title('解调数据');

结果:

image-20241004235833600

4.FPGA解调

逻辑代码:

module fm_demod(input           clk             ,input           rst             ,//解调参数input           i_valid         ,input [15:0]    i_data_i        ,input [15:0]    i_data_q        ,output reg          o_rdy       ,output reg [15:0]   o_data    );wire            fm_valid          ;wire [23:0]     fm_i              ;wire [23:0]     fm_q              ;wire            fm_rdy            ;wire [47 : 0]   m_axis_dout_tdata ;wire [15:0]     fm_phase          ;  //AM 解调assign fm_valid     = i_valid                        ;assign fm_i         = {{8{i_data_i[15]}},i_data_i}   ;assign fm_q         = {{8{i_data_q[15]}},i_data_q}   ;           cordic_translate cordic_translate (.aclk                     (clk                      ),                                        // input wire aclk.s_axis_cartesian_tvalid  (fm_valid                 ),  // input wire s_axis_cartesian_tvalid.s_axis_cartesian_tdata   ({fm_i,fm_q}              ),    // input wire [47 : 0] s_axis_cartesian_tdata.m_axis_dout_tvalid       (fm_rdy                   ),            // output wire m_axis_dout_tvalid.m_axis_dout_tdata        (m_axis_dout_tdata        )              // output wire [47 : 0] m_axis_dout_tdata);reg [15:0] fm_phase_d;assign fm_phase = m_axis_dout_tdata[24 +:16];always @(posedge clk)beginif(rst)begino_rdy       <= 0;o_data      <= 0;o_data      <= 0;endelse begino_rdy       <= fm_rdy;fm_phase_d  <= fm_phase[15:0];o_data      <= fm_phase[15:0] - fm_phase_d;endendendmodule

仿真代码:


module tb_fm_demod();reg     clk;reg     rst;initial beginclk <= 0;rst <=   1;#300rst <= 0;endalways #(100/2) clk  <=~clk;reg     valid;reg     [15:0]  din_i;reg     [15:0]  din_q;wire          o_rdy     ;wire  [15:0]  o_data  ;fm_demod   fm_demod(.clk         (clk),.rst         (rst),.i_valid     (valid),.i_data_i    (din_i),.i_data_q    (din_q),.o_rdy           (o_rdy     ),.o_data          (o_data    ));integer file_rd;                //定义数据读指针integer flag;initial begin                        //打开读取和写入的文件,这里的路径要对    file_rd = $fopen("FM.txt","r");end  reg     [15:0]  cnt;always @(posedge clk)beginif(rst)begindin_i   <= 0;din_q   <= 0;cnt     <= 0;valid   <= 0;endelse if(cnt <= 1000)beginvalid   <= 1;flag = $fscanf(file_rd,"%d %d",din_i,din_q);cnt <= cnt + 1;endelse begin$fclose(file_rd);$stop();endend
endmodule

仿真结果:

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

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

相关文章

工具推荐:支持工作流的高颜值 Windows 搜索启动器:Fluent Search

Fluent Search是一款专为Windows 10和Windows 11设计的高效搜索工具,它能够快速查找运行中的应用程序、浏览器标签、书签、文件等,帮助用户无缝切换工作流程。该软件采用了微软提倡的Fluent Design,具有半透明磨砂质感、圆角图形设计、简洁明快的图标和配色,提供了类似于Wi…

工具推荐:免费好用的WebP格式转换工具:AnyWebP

AnyWebP是一个多功能的WebP格式转换工具,它既提供在线服务也有适用于Windows和macOS的离线客户端。该工具能够将WebP图片转换为JPEG、PNG、ICO等常见格式,同时也支持将这些格式的图片转换为WebP格式。AnyWebP特别适合需要在不同平台和设备之间传输图片的用户,尤其是那些需要…

WPS股票价格查询EXCEL表格

第一步在表格内使用公式=GetStockSource(Stock_code)查询股票的即时交易信息,Stock_code表示股票代码;第二步通过公式从Source中提取所需要的数据,可以提取股票名称、价格、涨跌幅、收盘价格、成交额、成交量、换手率等。 公式如下: GetStockSource(Stock_code),查询股票即…

【2024.10.4 闲话】0/99+

当符卡收取100次后,收率显示会从xx/99+变为master,收率master是成为神触第一步呢(笑)。今日推歌:没有。明天可能有。 今日 set:也没有。话说应该没人知道 set 是什么吧,总之不是 std::set。[ARC176E] Max Vector 给你两个长度为 \(N\) 的正整数序列: \(X=(X_1,X_2,\dot…

2024 ciscn WP

一、MISC1.火锅链观光打卡打开后连接自己的钱包,然后点击开始游戏,答题八次后点击获取NFT,得到有flag的图片没什么多说的,知识问答题兑换 NFTFlag{y0u_ar3_hotpot_K1ng}2.Power Trajectory Diagram方法1:使用py中的numpy和pandas库读取npz文件并保存为csv文件,代码如下:…

30. 协程

1.协程的概念 1.1 定义 进程是操作系统内部运行的程序 线程是进程内部运行的程序 协程是线程内部运行的程序 协程是单线程下的并发,又成微线程,英文名coroutine 1.2 协程的优点协程切换的开销更小 GIL锁导致同一时刻只能运行一个线程,一个线程内不会限制协程数,单线程就可以…

.net core 安装服务

https://www.jianshu.com/p/e1b3b61f876a使用NSSM 后面的代码演示以Asp.net Core 2.1作为演示,其他.Net Core方式一致。 1、确保.Net Core程序可以正常运行 先把Asp.net Core发布,然后直接运行dotnet命令,确保程序可以运行并访问 2、使用NSSM安装dotnet 下载NSSM,使用命…

vs2015安装包丢失或损坏解决工具 或者不能启动

打开“本地组策略编辑器”(gpedit.msc)。展开“计算机配置”>“管理模板”>“系统”>“Internet 通信管理”,然后选择“Internet 通信设置”。选择“关闭自动根证书更新”>,“禁用”,然后选择“确定”或“应用”。  下载最新的组件版本(备份的) https://lea…

uboot 启动自编写程序的方式

uboot 启动自编写程序的方式 uboot 存在 boot 命令。 自己最初在尝试撰写串口程序时,选择了使用汇编来完成。 在这段时间,自己使用 go 命令来尝试载入程序 先是在 Ubuntu 上搭建 tftp 目录 # /etc/default/tftpd-hpaTFTP_USERNAME="tftp" TFTP_DIRECTORY="/ho…

10.Java集合框架_List接口

集合与数组的区别数组:长度开始时必须指定,而且一旦指定,不能修改。 保存的必须为同一类型的元素。 使用数组进行增加/删除元素比较麻烦。集合:可以动态保存任意多个对象,使用比较方便。 提供了一系列方便操作对象的方法: add、remove、set、get。 使用集合添加,删除新元…