调频信号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
begin
        aclk    =0;

        rst_n   =0;

        #100;
        rst_n   =1;

        #100;
        s_axis_phase_tvalid =1;

end

reg     [15:0]      wave_add;
reg     [15:0]      phase_tdata;
reg     [15:0]      phase_tdata_0;
//产生一个载波
always@(posedge aclk or negedge rst_n)
begin
        if(rst_n == 1'b0)begin
                wave_add  <= 16'b0;
        end
        else begin
                wave_add  <= 16'd32;
        end
end
always@(posedge aclk or negedge rst_n)
begin
        if(rst_n == 1'b0)begin
                phase_tdata  <= 16'b0;
        end
        else begin
                phase_tdata  <= phase_tdata + wave_add;
        end
end
always@(posedge aclk or negedge rst_n)
begin
        if(rst_n == 1'b0)begin
                phase_tdata_0  <= 16'b0;
        end
        else if(phase_tdata >= 16'h0 && phase_tdata <= 16'h4000 )begin
                phase_tdata_0  <= phase_tdata;
        end
        else if(phase_tdata > 16'h4000 && phase_tdata <= 16'h8000 )begin
                phase_tdata_0  <= phase_tdata - 16'h4000;
        end
        else if(phase_tdata > 16'h8000 && phase_tdata <= 16'hc000 )begin
                phase_tdata_0  <= phase_tdata - 16'h8000;
        end
        else if(phase_tdata > 16'hc000 && phase_tdata <= 16'hffff )begin
                phase_tdata_0  <= phase_tdata - 16'hc000;
        end
        else begin
                phase_tdata_0  <= phase_tdata;
        end
end
always@(posedge aclk or negedge rst_n)
begin
        if(rst_n == 1'b0)begin
                s_axis_phase_tdata  <= 16'b0;
        end
        else begin
                s_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)
begin
        if(rst_n == 1'b0)begin
                wave_add_m  <= 16'b0;
        end
        else begin
                wave_add_m  <= sinsin + 16'd262;
        end
end
always@(posedge aclk or negedge rst_n)
begin
        if(rst_n == 1'b0)begin
                phase_tdat_m  <= 16'b0;
        end
        else begin
                phase_tdat_m  <= phase_tdat_m + wave_add_m;
        end
end
always@(posedge aclk or negedge rst_n)
begin
        if(rst_n == 1'b0)begin
                phase_tdata_0_m  <= 16'b0;
        end
        else if(phase_tdat_m >= 16'h0 && phase_tdat_m <= 16'h4000 )begin
                phase_tdata_0_m  <= phase_tdat_m;
        end
        else if(phase_tdat_m > 16'h4000 && phase_tdat_m <= 16'h8000 )begin
                phase_tdata_0_m  <= phase_tdat_m - 16'h4000;
        end
        else if(phase_tdat_m > 16'h8000 && phase_tdat_m <= 16'hc000 )begin
                phase_tdata_0_m  <= phase_tdat_m - 16'h8000;
        end
        else if(phase_tdat_m > 16'hc000 && phase_tdat_m <= 16'hffff )begin
                phase_tdata_0_m  <= phase_tdat_m - 16'hc000;
        end
        else begin
                phase_tdata_0_m  <= phase_tdat_m;
        end
end
always@(posedge aclk or negedge rst_n)
begin
        if(rst_n == 1'b0)begin
                s_axis_phase_tdata_0  <= 16'b0;
        end
        else begin
                s_axis_phase_tdata_0  <= 16'he000 + phase_tdata_0_m;
        end
end


always#0.977 aclk = ~aclk;


    
endmodule


仿真为

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LLM文本数据集775TB:覆盖32个领域,444个数据集

大语言模型在各领域展现出巨大潜力&#xff0c;其性能在很大程度上依赖于训练和测试所用的数据集。然而&#xff0c;目前在如何构建和优化这些数据集方面&#xff0c;尚缺乏统一的认识和方法论。下面从五个方面整合和分类了LLM数据集的基本内容&#xff1a;预训练语料库、指令微…

【第14章】探索新技术:如何自学SD3模型(找官方资料/精读/下载/安装/3款工作流/效果测试)ComfyUI基础入门教程

近期,也就是2024年6月12日,StabilityAI开源了最新的SD3模型的2B版本,而神奇的是,ComfyUI早在6月11号就已经适配了SD3!相比之下,SD WebUI 的更新速度却远远落后... 所以,如果想要尝试一些AI绘画领域的新技术,ComfyUI是一个非常值得投入时间学习的工具。 这节课,我们就…

什么是API?如何进行API对接?

目录 一、API和API对接的定义 二、API接口的应用场景 三、为什么需要API对接 四、如何进行API对接 GET请求 POST请求 五、API对接的注意事项 在这个数字化时代&#xff0c;API像一把万能钥匙&#xff0c;让数据流动起来&#xff0c;创造出无限可能。本文旨在介绍API及其…

分享一个 MySQL 简单快速进行自动备份和还原的脚本和方法

前言 数据备份和还原在信息技术领域中具有非常重要的作用&#xff0c;不论是人为误操作、硬件故障、病毒感染、自然灾害还是其他原因&#xff0c;数据丢失的风险都是存在的。如果没有备份&#xff0c;一旦数据丢失&#xff0c;可能对个人、企业甚至整个组织造成巨大的损失。 …

6毛钱SOT-23封装28V、400mA 开关升压转换器,LCD偏置电源和白光LED应用芯片TPS61040

SOT-23-5 封装 TPS61040 丝印PHOI 1 特性 • 1.8V 至 6V 输入电压范围 • 可调节输出电压范围高达 28V • 400mA (TPS61040) 和 250mA (TPS61041) 内部开关电流 • 高达 1MHz 的开关频率 • 28μA 典型空载静态电流 • 1A 典型关断电流 • 内部软启动 • 采用 SOT23-5、TSOT23…

【会议征稿,IEEE出版】第三届机器人、人工智能与智能控制国际会议(RAIIC 2024,7月5-7)

第三届机器人、人工智能与智能控制国际会议&#xff08;RAIIC 2024&#xff09;将于2024年7月5-7日中国绵阳举行。 RAIIC 2024是汇聚业界和学术界的顶级论坛&#xff0c;会议将邀请国内外著名专家就以传播机器人、人工智能与智能控制领域的技术进步、研究成果和应用做专题报告…

呼叫中心项目需要关注什么?

呼叫中心系统项目合作的关键要素可以归纳如下&#xff1a; 1、明确合作目标和需求&#xff1a; 首先&#xff0c;需要明确呼叫中心系统项目的合作目标&#xff0c;例如提高客户满意度、降低成本、提升服务效率等。 同时&#xff0c;需要详细分析项目的具体需求&#xff0c;包括…

【Linux】线程Thread

&#x1f525;博客主页&#xff1a; 我要成为C领域大神&#x1f3a5;系列专栏&#xff1a;【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 ​ ​ 线程概述 …

期货交易记录20240626

文章目录 期货交易系统构建第一步、选品第二步、心态历练第三步、开仓纪律第四步、持仓纪律第五步、接下来的计划 2024年6月26号&#xff0c;开始写期货交易的第四篇日记。 交易记录&#xff1a;做了一笔纯碱的多单&#xff0c;在回撤了400个点左右后&#xff0c;看到企稳信号后…

标签接口开发(富含完整CRUD开发流程)

文章目录 1.easyCode生成CRUD1.生成代码2.查看代码3.调整代码1.SubjectLabelDao.xml发现生成的select语句不带逗号&#xff01;&#xff01;&#xff01;1.解决方法&#xff1a;2.entity.java.vm3.dao.java.vm4.Mapper.xml.vm 2.重新生成代码3.SubjectLabelDao.java 删除Pageab…

ArkTS开发系列之Web组件的学习(2.9)

上篇回顾&#xff1a;ArkTS开发系列之事件&#xff08;2.8.2手势事件&#xff09; 本篇内容&#xff1a; ArkTS开发系列之Web组件的学习&#xff08;2.9&#xff09; 一、知识储备 Web组件就是用来展示网页的一个组件。具有页面加载、页面交互以及页面调试功能 1. 加载网络…

【Java】Java序列化和反序列化

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 # Java中的序列化和反序列化 在Java中&#xff0c;序列化是将对象的状态写入字节流的机制。它主要用于Hibernate…

国家自然科学基金标书大全(2002-2024)

数据来源&#xff1a;在20世纪80年代初&#xff0c;为了促进中国的科技体制革新并改革科研资金分配机制&#xff0c;中国科学院的89位院士联名向党和国家领导人提出建议&#xff0c;设立了国家自然科学基金的设立。国自然基金自创立以来&#xff0c;根据国家发展科学技术方针、…

可以一键生成热点营销视频的工具,建议收藏

在当今的商业环境中&#xff0c;热点营销已经成为了一种非常重要的营销策略。那么&#xff0c;什么是热点营销呢&#xff1f;又怎么做热点营销视频呢&#xff1f; 最近高考成绩慢慢公布了&#xff0c;领导让结合“高考成绩公布”这个热点&#xff0c;做一个关于企业或产品的营销…

力扣:59. 螺旋矩阵 II(Java,模拟)

目录 题目描述示例 1&#xff1a;代码实现 题目描述 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5…

想布局短视频赛道,云微客AI矩阵系统告诉你诀窍

随着人工智能技术的不断发展&#xff0c;越来越多的企业和个人创作者开始意识到智能化的重要性。而现阶段&#xff0c;随着短视频市场的膨胀扩大&#xff0c;批量成片、智能创作、定时发布是当下重要的趋势&#xff0c;企业如果想在短视频赛道分一杯羹&#xff0c;智能化的平台…

七天速通javaSE:第二天 基础:标识符与数据类型

文章目录 前言一、注释与标识符1. 注释2. 标识符2.1 标识符2.2 关键字 二、数据类型1. 语言类型2. 数据类型2.1 基本数据类型2.2引用数据类型 三、类型转换1. 自动转换2. 强制转换&#xff08;不建议&#xff09; 四、代码规范 前言 今天将学习Java语法的基础&#xff0c;认识…

自然语言处理——英文文本预处理

高质量数据的重要性 数据的质量直接影响模型的性能和准确性。高质量的数据可以显著提升模型的学习效果&#xff0c;帮助模型更准确地识别模式、进行预测和决策。具体原因包括以下几点&#xff1a; 噪音减少&#xff1a;高质量的数据经过清理&#xff0c;减少了无关或错误信息…

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

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

Vite响应Ajax请求

Vite响应Ajax请求 陈拓 2024/06/20-2024/06/24 1. 概述 http-server、live-server 等常用于本地测试和开发的http服务器不能很好的支持 ES 模块&#xff0c;在测试ES 模块时浏览器控制台经常显示错误&#xff1a; Failed to load module script: Expected a JavaScript modu…