调频信号FM的原理与matlab与FPGA实现

平台:matlab r2021b,vivado2023.1

本文知识内容摘自《软件无线电原理和应用》

调频(FM)是载波的瞬时频率随调制信号成线性变化的一种调制方式,音频调频信号的数学表达式可以写为:

s(t)=A[cos(\omega _{c}t+k_{\Omega }\int_{0}^{t}v_{\Omega (t)dt})]

Fm频率调制,载波的幅度随着调制波形的幅度变化而变化。

其中\omega _{c}为载波频率,v_{\Omega }t为调制信号,k_{\Omega }为调制角频率。

下面是FM调制的matlab实现

clc;
clear;
% 设置参数
fs = 312.5e6;       % 采样率
fc = 20e6;          % 载波频率
fm = 1e6;           % 调制信号频率,内调制最大3mhz
t1 = 0:1/fs:2;      % 时间序列,1微秒
t = t1(1:5000);     %RW需要取整数计算出的频率是真实
% 生成调制信号
m = cos(2*pi*fm*t);%正弦波
% m = square(2*pi*fm*t);%方波
% m = sawtooth(2*pi*fm*t, 0.5);%三角波
% m = sawtooth(2*pi*fm*t);% 锯齿波
% 例如,y=x^2;t=1-5;
% Q=cumtrapa(t,y);
% q0=0;
% q1=0.5*(4+1)+0=2.5;
% q2=0.5*(9+3)+2.5=9;
% q3=0.5*(16+9)+9=21.5;
% q4=0.5*(25+16)+21.5=42;
% 计算积分累计积分结果,返回一个向量
integral_term = cumtrapz(t, m);% 生成载波信号
c = cos(2*pi*fc*t);
% FM调制,
kf = 100e6; % 调频系数
k = 2*pi*fc*t;
k1= kf*integral_term;
s = cos(2*pi*fc*t + kf*integral_term);
% 绘制时域波形
figure(1);
subplot(3,1,1);
plot(t*1e6, m);
title('调制信号');
xlabel('时间 (μs)');
ylabel('幅度');subplot(3,1,2);
plot(t*1e6, c);
title('载波信号');
xlabel('时间 (μs)');
ylabel('幅度');subplot(3,1,3);
plot(t*1e6, s);
title('调制后信号');
xlabel('时间 (μs)');
ylabel('幅度');figure(2);
subplot(1,1,1);
plot(t*1e6, c, 'r', 'LineWidth', 2); % 使用红色绘制载波信号,线条宽度为2
title('载波信号');
xlabel('时间 (μs)');
ylabel('幅度');
hold on;plot(t*1e6, s, 'k', 'LineWidth', 2); % 使用黑色绘制调制后信号,线条宽度为2
title('调制后信号');
xlabel('时间 (μs)');
ylabel('幅度');% 绘制频域波形
figure(3);
% 计算频谱
N = length(t);
f = (-fs/2:fs/N:fs/2-fs/N); % 频率向量
M = fftshift(fft(m));
C = fftshift(fft(c));
S = fftshift(fft(s));subplot(3,1,1);
plot(f, abs(M)/N,'b');
title('调制信号频谱');
xlabel('频率 (GHz)');
ylabel('幅度');subplot(3,1,2);
plot(f, abs(C)/N,'g');
title('载波信号频谱');
xlabel('频率 (GHz)');
ylabel('幅度');subplot(3,1,3);
plot(f, abs(S)/N,'r');
title('调制后信号频谱');
xlabel('频率 (GHz)');
ylabel('幅度');

调制波为余弦波时时域和频域图像

当调制信号为方波时。

为锯齿波时

FPGA的实现

当我们的调制波是一个余弦波时。

可以看到我们的调制波形是一个余弦波。载波也是一个余弦波,调制波的频率随着调制波形的积

分变化而变化。其变化规律如下。

余弦波时,积分量在0,pi和2pi时最小,对应着在0时频偏最小,在pi/2时频率与载波相同,在pi时

频偏正向最大。在3*pi/2时又与载波频率相同。在2pi时达到了最小频偏。

在逻辑中有几种产生正余弦波形的方式,基于DDS的波形发生器,基于cordic的波形发生器。这里我们使用cordic来产生我们的载波和调制波。

关于cordic的频率控制字这里说明一下。Cordic是你对其输入一个角度,他给你计算出y(cos,sin)的一个结果。所以我们需要对频率控制字执行一个累加的过程。其中cordic的角度范围表示为(-pi,pi)。

关于输出的频率计算公式为

f_{o}=\tfrac{phase*fs}{2^{N-2}}

其中f_{o}为输出频率,phase为相位控制字,f_{s}为采样率。2^{N-2}是因为cordic将数据的范围量化到(-pi,pi)。

所以我们需要控制cordic的累加量

p=p+pi+po

其中p为频率控制字,pi为载波的频率控制字,po为频偏控制字。

例如我们要载波为fi,最大频偏为fo。假定现在的采样率时钟为fs。根据公式

可以算出载波的频率控制字为

pi=\frac{​{​{}2^{14}}*fi}{fs}

可以算出最大频偏控制字为

po=\frac{​{​{}2^{14}}*fo}{fs}

所以又调制波的幅度最大为16’h4000=16’d16384表示最大为正1v。
所以po与幅度的对应关系为

k=\frac{​{​{}2^{14}}*fo}{fs*2^{14}}=\tfrac{fo}{fs}

所以最大频偏和调制波幅度的关系为

po=\frac{fo}{fs}*x

其中x为调制波幅度

逻辑实现现在假定调制波为1mhz,载波为8mhz,最大频偏为2mhz,采样率为512mhz。

插入FPGA代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2024/06/06 21:09:44
// Design Name: 
// Module Name: vtf_cordic
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module vtf_cordic;reg             aclk;
reg             rst_n;
reg             s_axis_phase_tvalid;
reg  [15 : 0]   s_axis_phase_tdata;
reg  [15 : 0]   s_axis_phase_tdata_0;wire            m_axis_dout_tvalid;
wire [31 : 0]   m_axis_dout_tdata;wire [15:0]     sin ;
wire [15:0]     cos ;
wire [15:0]     sin0 ;
wire [15:0]     cos0 ;cordic_0 u_cordic_0 (.aclk                         (aclk                         ),// input wire aclk.s_axis_phase_tvalid          (s_axis_phase_tvalid          ),// input wire s_axis_phase_tvalid.s_axis_phase_tdata           (s_axis_phase_tdata           ),// input wire [15 : 0] s_axis_phase_tdata.m_axis_dout_tvalid           (m_axis_dout_tvalid           ),// output wire m_axis_dout_tvalid.m_axis_dout_tdata            ({sin,cos}                    )// output wire [31 : 0] m_axis_dout_tdata
);cordic_0 u_cordic_1 (.aclk                         (aclk                         ),// input wire aclk.s_axis_phase_tvalid          (s_axis_phase_tvalid          ),// input wire s_axis_phase_tvalid.s_axis_phase_tdata           (s_axis_phase_tdata_0           ),// input wire [15 : 0] s_axis_phase_tdata.m_axis_dout_tvalid           (                             ),// output wire m_axis_dout_tvalid.m_axis_dout_tdata            ({sin0,cos0}                  )// output wire [31 : 0] m_axis_dout_tdata
);initial
beginaclk    =0;rst_n   =0;#100;rst_n   =1;#100;s_axis_phase_tvalid =1;endreg     [15:0]      wave_add;
reg     [15:0]      phase_tdata;
reg     [15:0]      phase_tdata_0;
//产生一个载波
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginwave_add  <= 16'b0;endelse beginwave_add  <= 16'd32;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginphase_tdata  <= 16'b0;endelse beginphase_tdata  <= phase_tdata + wave_add;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginphase_tdata_0  <= 16'b0;endelse if(phase_tdata >= 16'h0 && phase_tdata <= 16'h4000 )beginphase_tdata_0  <= phase_tdata;endelse if(phase_tdata > 16'h4000 && phase_tdata <= 16'h8000 )beginphase_tdata_0  <= phase_tdata - 16'h4000;endelse if(phase_tdata > 16'h8000 && phase_tdata <= 16'hc000 )beginphase_tdata_0  <= phase_tdata - 16'h8000;endelse if(phase_tdata > 16'hc000 && phase_tdata <= 16'hffff )beginphase_tdata_0  <= phase_tdata - 16'hc000;endelse beginphase_tdata_0  <= phase_tdata;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)begins_axis_phase_tdata  <= 16'b0;endelse begins_axis_phase_tdata  <= 16'he000 + phase_tdata_0;end
end//-------------------------------------------------------------------
reg     [15:0]      wave_add_m;
reg     [15:0]      phase_tdat_m;
reg     [15:0]      phase_tdata_0_m;wire    [15:0]      sinsin={sin[15],sin[15],sin[15],sin[15],sin[15],sin[15],sin[15],sin[15],sin[15:8]};
//产生一个方波
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginwave_add_m  <= 16'b0;endelse beginwave_add_m  <= sinsin + 16'd262;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginphase_tdat_m  <= 16'b0;endelse beginphase_tdat_m  <= phase_tdat_m + wave_add_m;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)beginphase_tdata_0_m  <= 16'b0;endelse if(phase_tdat_m >= 16'h0 && phase_tdat_m <= 16'h4000 )beginphase_tdata_0_m  <= phase_tdat_m;endelse if(phase_tdat_m > 16'h4000 && phase_tdat_m <= 16'h8000 )beginphase_tdata_0_m  <= phase_tdat_m - 16'h4000;endelse if(phase_tdat_m > 16'h8000 && phase_tdat_m <= 16'hc000 )beginphase_tdata_0_m  <= phase_tdat_m - 16'h8000;endelse if(phase_tdat_m > 16'hc000 && phase_tdat_m <= 16'hffff )beginphase_tdata_0_m  <= phase_tdat_m - 16'hc000;endelse beginphase_tdata_0_m  <= phase_tdat_m;end
end
always@(posedge aclk or negedge rst_n)
beginif(rst_n == 1'b0)begins_axis_phase_tdata_0  <= 16'b0;endelse begins_axis_phase_tdata_0  <= 16'he000 + phase_tdata_0_m;end
endalways#0.977 aclk = ~aclk;endmodule

仿真为

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

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

相关文章

open()函数——打开文件并返回文件对象

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 open()函数用于打开文件&#xff0c;返回一个文件读写对象&#xff0c;然后可以对文件进行相应读写操作。 语法参考 open()函数的语法格式如下&…

【K8s】专题六(2):Kubernetes 稳定性之健康检查

以下内容均来自个人笔记并重新梳理&#xff0c;如有错误欢迎指正&#xff01;如果对您有帮助&#xff0c;烦请点赞、关注、转发&#xff01;欢迎扫码关注个人公众号&#xff01; 目录 一、基本介绍 二、工作原理 三、探针类型 1、存活探针&#xff08;LivenessProbe&#x…

docker入门配置

1、创建配置镜像 由于国内docker连接外网速度慢&#xff0c;采用代理 vi /etc/docker/daemon.json添加以下内容 {"registry-mirrors": ["https://9cpn8tt6.mirror.aliyuncs.com","https://dockerproxy.com","https://hub-mirror.c.163.co…

SOA和ESB介绍

SOA&#xff08;面向服务的架构&#xff09; 面向服务的架构&#xff08;Service-Oriented Architecture&#xff0c;SOA&#xff09;是一种设计理念&#xff0c;用于构建松耦合的、可互操作的、模块化的服务。在SOA架构中&#xff0c;应用程序被划分为一系列的服务&#xff0c…

电脑屏幕花屏怎么办?5个方法解决问题!

“我刚刚打开电脑就发现我的电脑屏幕出现了花屏的情况。这让我很困惑&#xff0c;我应该怎么解决这个问题呢&#xff1f;求帮助。” 在这个数字时代的浪潮中&#xff0c;电脑早已成为我们生活中不可或缺的一部分。然而&#xff0c;当你正沉浸在紧张的游戏对战中&#xff0c;或是…

谷歌上搞下来的,无需付费,可以收藏!

在数字化时代&#xff0c;我们越来越依赖于智能设备来获取信息和知识。中国智谋App正是这样一款应用&#xff0c;它将中国古代的智慧与谋略书籍带入了我们的移动设备&#xff0c;让我们能够随时随地学习和领悟。而且提供文言文的原文和译文。 软件下载方式&#xff1a;谷歌上搞…

39.右键弹出菜单管理游戏列表

上一个内容&#xff1a;38.控制功能实现 以 ​​​​​​​ 38.控制功能实现 它的代码为基础进行修改 效果图&#xff1a; 点击设置之后的样子 点击删除 点击删除之后的样子 实现步骤&#xff1a; 首先添加一个菜单资源&#xff0c;右击项目资源选择下图红框 然后选择Menu 然…

【C语言】字符/字符串+内存函数

目录 Ⅰ、字符函数和字符串函数 1 .strlen 2.strcpy 3.strcat 4.strcmp 5.strncpy 6.strncat 7.strncmp 8.strstr 9.strtok 10.strerror 11.字符函数 12. 字符转换函数 Ⅱ、内存函数 1 .memcpy 2.memmove 3.memcmp Ⅰ、字符函数和字符串函数 1 .strlen 函数原型&#xff1a;…

《计算机英语》 Unit 6 Internet 互联网

Section A Internet 互联网 The Internet is a global system of interconnected computer networks that use the standard Internet protocol suite (TCP/IP) to link several billion devices worldwide. 互联网是一个全球性的互连计算机网络系统&#xff0c;使用标准的互联…

苹果CMS-V10 搭建教程踩坑,跳过部分验证

我突发奇想,想要安装一个CMS 苹果CMS搭建教程-CSDN博客 然后就有了下面的问题 结论是zip相关依赖未安装, 通过 apt install php-zip, 重新打开安装页面,同样如此 最后依据某个网站提示,修改 "\\192.168.1.200\root\var\www\html\maccms\application\install\control…

多家国产大模型提供OpenAI API服务替代方案,谷歌将推出明星网红AI聊天机器人

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 更多资源欢迎关注 1、OpenAI终止对中国提供服务 6月25日凌晨&#xff0c;多个用户收到OpenAI的推送邮件&#xff0c;信中称&#xff0c;自今年7月9日起&#xff0c;将开始阻止来自非支持国家和地区的API&#xff08;应…

3.任务的创建与删除

1.什么是任务&#xff1f; 任务可以理解为进程/线程&#xff0c;创建一个任务&#xff0c;就会在内存开辟一个空间。 任务通常都含有while(1)死循环 2.任务创建与删除相关的函数 3.CUBEMAX相关配置 编辑一个led1闪烁的任务

小程序使用echarts和echarts配置项总结(全网最简单详细)

文章目录 概要小程序中使用echarts1. ec-canvas2. 下载项目3. 去echarts官网定制&#xff1a;4.点击下载5.引入使用 echarts的option配置知识点归纳整理&#xff08;还在更新&#xff09;&#xff1a;小结 概要 小程序中使用echarts&#xff08;简单详细&#xff09; 小程序中…

解密城市酷选为何异军突起!打造消费新潮流的排队免单模式

一、城市酷选平台简介 在数字化浪潮席卷全球的今天&#xff0c;城市酷选作为一个前沿的消费平台&#xff0c;凭借其独特的排队免单模式&#xff0c;成功吸引了众多消费者和商家的目光。该平台不仅整合了线上线下的资源&#xff0c;更通过数字化手段&#xff0c;为消费者提供了…

C3P0数据库连接池

目录 一&#xff1a;连接池介绍 1.1连接池解决的问题 2.常用的数据库连接池 二&#xff1a;c3p0介绍 2.1C3P0介绍&#xff1a; 2.2C3P0快速入门 1.常用参数说明 2.API介绍 3.使用步骤 1.导入jar包c3p0-0.9.1.2.jar 2.编写c3p0-config.xml配置文件&#xff0c;配置对…

node 实现导出, 在导出excel中包含图片(附件)

如果想查看 node mySql 实现数据的导入导出&#xff0c;以及导入批量插入的sql语句&#xff0c;连接如下 node mySql 实现数据的导入导出&#xff0c;以及导入批量插入的sql语句-CSDN博客https://blog.csdn.net/snows_l/article/details/139998373 一、效果如图&#xff1a; 二…

【Linux详解】进程的状态 | 运行 阻塞 挂起 | 僵尸和孤儿状态

目录 操作系统中 运行状态 阻塞状态 进程状态转换 Linux系统中 查看进程状态 深度睡眠状态 T 暂停状态 Z 僵尸状态 孤儿状态 文章手稿 xmind: 引言 介绍系统中的进程状态及其管理方式。将通过结合操作系统原理和实际代码示例&#xff0c;详细说明进程的各种状态、转换…

鸿蒙开发Ability Kit(程序框架服务):【FA模型切换Stage模型指导】 app和deviceConfig的切换

app和deviceConfig的切换 为了便于开发者维护应用级别的属性配置&#xff0c;Stage模型将config.json中的app和deviceConfig标签提取到了app.json5中进行配置&#xff0c;并对部分标签名称进行了修改&#xff0c;具体差异见下表。 表1 配置文件app标签差异对比 配置项FA模型…

Excel中的“点选输入”——次级下拉列表创建

在Excel中&#xff0c;用“数据验证”功能可以设置下拉列表&#xff0c;二级下拉列表需要设置公式。 (笔记模板由python脚本于2024年06月16日 18:36:37创建&#xff0c;本篇笔记适合经常使用Excel处理数据的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;http…

后端之路第三站(Mybatis)——入门配置

一、Mybatis是啥&#xff1f; 就是一个用java来操控数据库的框架语言 之前学的datagrip或者navicat这些软件里我们操作数据库&#xff0c;原理是我们编写完的操作语句发送到服务器传送到数据库系统&#xff0c;然后数据库执行完之后再发送给服务器返回给datagrip或者navicat显…