FPGA 数字信号处理之 FSK 调制、解调的实现与仿真基于 verilog + ise + modelsim + matlab (保姆级)
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
试验说明
笔者复现FSK调制、解调的过程中在网上查了很多很多相关文章至少在本文之前没发现能在参考一篇博文的情况下能完整复现实验结果的。总之全乎的基本没有。
本笔记文的目标是让入门者或者说小白在参考本文的基础上能一步一步完整复现实验结果少走弯路尽力节省时间因为时间很宝贵。
另本实验只是复现参考博文的结果有关概念、原理相关知识请参考原文。
主要参考博文链接如下
https://bestfpga.blog.csdn.net/article/details/81166187
实验目标
达成和博文中最终仿真结果基本一致先看一下本次实验的最终的仿真结果吧
FSK是利用载波的频率表示基带信息比如在2FSK系统中采用单频信号f1表示信息0、单频信号f2表示信息1。根据码元转换时载波的相位是否连续分为非连续相位FSK和连续相位FSK。–摘自参考博文。
注意
非连续相位调制没试验复现只试验了连续相位调制(CPFSK)。
FSK调制信号生成步骤
简单说明
在ISE14.7的环境下完成2FSK(CPFSK)的调制并进行仿真系统时钟32Mhz码元速率1Mhz载波频率6Mhz频移指数h=3.5f1=4.25MHz、f2=7.75Mhz
连续相位调制时配置1个DDS产生两个代表1和0的单频信号要调制–非连续相位的要产生2个信号即可非连续相位的内容具体参考原文。
将DDS的无杂散动态范围设置为95dB对应的位宽为16bits。
有关概念、原理相关知识请参考原文
下面为本次实验的详细记录
首先
DDS IP核的配置过程
ISE14.7新建工程
注意器件选择高端点的在试验过程中被坑过因为器件选的低。
工程建立后添加DDS IP核
上图中指定IP的名称和存放路径
上图指定了DDS 版本
上图参数简要说明
DDS的频率分辨率设置为976.5625Hz正好对应相位位宽为15Bits
Fs/2^B
=32MHz/2^15=976.5625Hz。
因此
f1=4.25MHz对应的频率控制字为4351f1/976.5625-1=4351
f2=7.75MHz对应的频率控制字为7935f2/976.5625-1=7935
本实验使用连续相位FSKCPFSK只需要使用一个DDS Compiler IP核比FSK要节省不少资源。
故省略了参考博文中的----非连续相位的试验。
因此CPFSK配置如下
注意上图参数
生成后到工程内找到ipcore_dir目录复制文件dds_cpfsk2.v 放入modelsim工程模板的src目录备用。
此时也可单独仿真看一下FSK调制的结果具体仿真步骤可参考后面的说明。
CPFSK 连续相位FSK调制的仿真结果
FSK调制部分也提供了单独的仿真文件也详细见后面的说明。
----------------------------------------------------华丽的分割线---------------------------------------------------------------------------------
FSK解调部分实验
首先
要生成滤波器的coe文件供ISE中配置滤波器时调用。
使用matlab配置、滤波器COE文件步骤如下
打开matlab2018b
在命令行窗口输入fdatool
开始配置带通滤波器演示一个其它的方法和步骤一样
简要说明一下
带通滤波器分别筛选两路ASK信号。
系统时钟32Mhz
码元速率1Mhz
载波频率6Mhz
频移指数h=3.5
f1=4.25Mhz
f2=7.75MHz。
带通滤波器通带可分别选为
A(6Mhz-h×1Mhz)–6Mhz。
B6Mhz–(6MHz+h×1Mhz)。
因此带通滤波器A的配置如上图所示。配置完成后就可以导出coe文件了。
导出coe文件
第一步
第二步见上图先选择左侧第三个图标量化后即可。
再选择上面的菜单栏Targets–>XILINX (.COE) File
保存到指定目录即可。
B的配置、导出COE文件的方法同A----即上图这里省略截图了。
低通滤波器的配置
低通滤波器用于提取出基带信号包络截止频率设置为码元速率即可。COE文件导出方式如前文描述。
注
如果在上一步的导出COE界面点击红色箭头即可返回参数配置界面。
至此所有的滤波器系数经过量化后存储为txt(coe)文件供后面在FPGA设计中调用。
全部完成后生成的COE文件共3个
bpf1_fir.coe、bpf2_fir.coe、lpf_fir.coe
名字随意自己记得清即可。
ISE14.7配置IP核
新建工程关键步骤如下
注意下面的器件选择
添加、配置带通滤波器其中-1个的步骤
选择COE文件matlab中生成
输入采用频率和系统时钟
都是32MHz
输出位数32
同时选择截断模式
如上图之前用的6系列的器件这个红框+红圈的地方提示参数错误。应该是6系器件的DSP资源不足导致无法配置。
因此前面说新建工程时要选择一个高端点的器件。
至此配置就完成了点击“Generate”生成IP核即可。
bpf2_fir配置方法和步骤一样略过
lpf_fir的配置方法和步骤也一样略过
全部生成后到ipcore_dir目录内复制文件
bpf1_fir.mif bpf1_fir.mif lpf_fir.mif 该文件放入modelsim工程模板的sim目录
bpf1_fir.v bpf2_fir.v 、lpf_fir.v 该文件放入modelsim工程模板的src目录
----------------------------------------------------华丽的分割线---------------------------------------------------------------------------------
开始仿真
modelsim工程结构
目录结构说明
首先是
run_simulation.bat 脚本文件启动仿真内容如下
@echo off
@cls
title FPGA Auto Simulation batch script
echo ModelSim simulation
echo.
echo Press '1' to start simulation
echo.
:input
set INPUT=
set /P INPUT=Type test number: %=%
if "%INPUT%"=="1" goto run1
goto end
:run1
@cls
echo Start Simulation;
echo.
echo.
cd sim
vsim -do "do compile.do"
goto clean_workspace
:clean_workspace
rmdir /S /Q work
del vsim.wlf
del transcript.
:end
src目录内---- 存源文件
包括生成的.v文件仿真时少的库文件等。
注意
此目录内除了自己实现的文件及上面配置时生成的文件同时在仿真编译时注意看报错提示若是缺少文件自行搜索复制到该目录内即可。
sim目录内— 存激励文件和2个do文件及1个ini文件
两个do文件其中
wave.do文件内容
add wave -divider {cpfsk_modulate_demodulate_tb}
add wave -position insertpoint sim:/cpfsk_modulate_demodulate_tb/*
compile.do文件内容
vlib work
vmap work work
vlog -work work glbl.v
#library
#vlog -work work ../../library/artix7/*.v
#IP
#vlog -work work ../../../source_code/ROM_IP/rom_controller.v
#SourceCode
vlog -work work ../src/*.v
#Testbench
vlog -work work cpfsk_modulate_demodulate_tb.v
#vsim -voptargs=+acc -L unisims_ver -L unisim -L work -Lf unisims_ver work.glbl work.cpfsk_modulate_demodulate_tb
vsim -voptargs=+acc work.glbl work.cpfsk_modulate_demodulate_tb
#Add signal into wave window
do wave.do
#run -all
run 1ms
Modelsim.ini文件内容
[Library]
others = $MODEL_TECH/../modelsim.ini
work = work
[vcom]
VHDL93 = 2002
Explicit = 1
[vlog]
LibrarySearchPath = mtiAvm mtiOvm mtiUvm mtiUPF
[sccom]
[vopt]
[vsim]
VoptFlow = 1
Resolution = ns
UserTimeUnit = default
RunLength = 100
IterationLimit = 5000
BreakOnAssertion = 3
ShowFunctions = 1
DefaultRadix = symbolic
TranscriptFile = transcript
PathSeparator = /
DatasetSeparator = :
UnbufferedOutput = 0
ConcurrentFileLimit = 40
ScTimeUnit = ns
ScMainStackSize = 10 Mb
ScMainFinishOnQuit = 1
ScvPhaseRelationName = mti_phase
OnFinish = ask
DumpportsCollapse = 1
MvcHome = $MODEL_TECH/..
[lmc]
libsm = $MODEL_TECH/libsm.sl
libhm = $MODEL_TECH/libhm.sl
[msg_system]
suppress = 8780
最后附上调制、解调文件和激励文件如下
cpfsk_modulate_demodulate.v该文件放入src目录内文件内容
`timescale 1ns / 1ps
//--------------------------------------------------------
// 包络检波法非相干解调实现FSK信号解调
//--------------------------------------------------------
module cpfsk_modulate_demodulate
(
input clk , //32MHz系统时钟
input rst_n ,
input din , //基带信号输入码元速率1MHz
output [15:0] dout //FSK解调数据输出
);
//-----------------------------------------------------
// CPFSK调制连续相位h=3.5
//-----------------------------------------------------
wire [15:0] fsk;
digital_adds fskmod
(
.clk (clk ) ,
.rst_n (rst_n ) ,
.din (din ) ,
.dout (fsk )
);
//assign dout = fsk ;
//**加上句是为了单独测试CPFSK的调整信号输出--即下面的代码都未添加时--注释掉到98行。**
//--------------------------------------------------------
// 带通滤波器分为两路ASK信号
//--------------------------------------------------------
wire signed [31:0] data1, data2;
wire signed [15:0] bpf1 = data1[29:14];
wire signed [15:0] bpf2 = data2[29:14];
bpf1_fir fir1 (
.aclk (clk ) ,
.s_axis_data_tvalid (1'b1 ) ,
.s_axis_data_tready ( ) ,
.s_axis_data_tdata (fsk ) ,
.m_axis_data_tvalid ( ) ,
.m_axis_data_tdata (data1 )
);
bpf2_fir fir2 (
.aclk (clk ) ,
.s_axis_data_tvalid (1'b1 ) ,
.s_axis_data_tready ( ) ,
.s_axis_data_tdata (fsk ) ,
.m_axis_data_tvalid ( ) ,
.m_axis_data_tdata (data2 )
);
//--------------------------------------------------------
// 整流即求绝对值
//--------------------------------------------------------
reg signed [15:0] bpf1_abs, bpf2_abs;
always @ (posedge clk or posedge rst_n)
if (rst_n) begin bpf1_abs <= 'd0; bpf2_abs <= 'd0; end
else begin
if (bpf1[15]) bpf1_abs <= -bpf1;
else bpf1_abs <= bpf1;
if (bpf2[15]) bpf2_abs <= -bpf2;
else bpf2_abs <= bpf2;
end
//--------------------------------------------------------
// 低通滤波得到基带信号包络
//--------------------------------------------------------
wire signed [31:0] lpf1, lpf2;
lpf_fir fir3 (
.aclk (clk ) ,
.s_axis_data_tvalid (1'b1 ) ,
.s_axis_data_tready ( ) ,
.s_axis_data_tdata (bpf1_abs ) ,
.m_axis_data_tvalid ( ) ,
.m_axis_data_tdata (lpf1 )
);
lpf_fir fir4 (
.aclk (clk ) ,
.s_axis_data_tvalid (1'b1 ) ,
.s_axis_data_tready ( ) ,
.s_axis_data_tdata (bpf2_abs ) ,
.m_axis_data_tvalid ( ) ,
.m_axis_data_tdata (lpf2 )
);
//--------------------------------------------------------
// 减法得到解调信号
//--------------------------------------------------------
reg signed [15:0] sub;
always @ (posedge clk or posedge rst_n)
if (rst_n) sub <= 'd0;
else sub <= lpf1[29:14] - lpf2[29:14];
assign dout = sub;
endmodule
激励文件
cpfsk_modulate_demodulate_tb.v该文件放sim目录中内容如下
//测试文件
`timescale 1ns/1ps
module cpfsk_modulate_demodulate_tb();
reg clk ;
reg rst_n ;
reg din ;
wire [15:0] dout ;
cpfsk_modulate_demodulate cpfsk_modulate_demodulate_inst(
.clk (clk ) ,
.rst_n (rst_n ) ,
.din (din ) ,
.dout (dout )
);
initial clk = 1 ;
always #16 clk = !clk ;
always #1100 din=!din ;
initial begin
rst_n = 1 ;
#100
rst_n = 0 ;
din =1 ;
#500000
$stop;
end
endmodule
最终仿真结果
----------------------------------------------------华丽的分割线---------------------------------------------------------------------------------
附录
仿真工程里还提供了单独仿真FSK调制的文件和激励文件也可在cpfsk_modulate_demodulate.v中只仿真查看fsk输出这种方式具体见cpfsk_modulate_demodulate.v文件中注释部分描述。
先看单独的实现
FSK调制信号的仿真
digital_adds.v和digital_adds_tb.v文件即可
digital_adds.v文件内容
//顶层
module digital_adds(
input clk ,
input rst_n ,
input din ,
output [15:0] dout
);
//-----------------------------------------------------
// 载波Fc=6MHzh=3.5则f1=4.25MHz、f2=7.75Mhz
//-----------------------------------------------------
wire [14:0] phase;
dds_cpfsk2 dds_cpfsk2_inst(
.aclk (clk ),
.s_axis_phase_tvalid (1'b1 ),
.s_axis_phase_tdata ({1'b0,phase} ),
.m_axis_data_tvalid ( ),
.m_axis_data_tdata (dout )
);
assign phase = din ? 'd4351:'d7935 ;
endmodule
digital_adds_tb.v文件内容
//测试文件
`timescale 1ns/1ps
module digital_adds_tb();
reg clk ;
reg rst_n ;
reg din ;
wire [15:0] dout ;
digital_adds digital_adds_inst(
.clk (clk ) ,
.rst_n (rst_n ) ,
.din (din ) ,
.dout (dout )
);
initial clk = 1;
always #16 clk = !clk;
initial begin //同步复位信号需要时钟上升沿检测
rst_n = 0;
#100
rst_n = 1;
din =1;
#1000
din=0 ;
#1000
din=1 ;
#1000;
din =0;
#1000
din=0 ;
#1000
din=1 ;
#1000;
din =0;
#500000
$stop;
end
endmodule
仿真时注意还要修改2个do文件。
wave.do修改如下
add wave -divider {digital_adds_tb}
add wave -position insertpoint sim:/digital_adds_tb/*
compile.do修改如下
vlib work
vmap work work
vlog -work work glbl.v
#library
#vlog -work work ../../library/artix7/*.v
#IP
#vlog -work work ../../../source_code/ROM_IP/rom_controller.v
#SourceCode
vlog -work work ../src/*.v
#Testbench
vlog -work work digital_adds_tb.v
#vsim -voptargs=+acc -L unisims_ver -L unisim -L work -Lf unisims_ver work.glbl work.digital_adds_tb
vsim -voptargs=+acc work.glbl work.digital_adds_tb
#Add signal into wave window
do wave.do
#run -all
run 1ms
另仿真时可能报类似如下的错误
Module ‘RAMB36E1’ is not defined.
解决办法
搜索ISE安装目录下同名的.v文件到modelsim工程模板的src目录即可。
缺少其他文件之类的注意看编译时的错误提示信息确定是否缺少文件问题也可这么操作。
结束语
不夸张的话这应该是全网最详细的关于FSK调制与解调的笔记了如果看到这里还没复现实验结果只有两种可能
1 没有仔细看笔记
2 工具和环境问题
本次实验环境和工具说明
1 win10 专业版 64bits
2 ISE14.7 或 vivado2018.3
3 Modelsim 2020.4 或10.1a
4 matlab2008b
猜测一下如果复现实验的过程真有坑话也可能是在modelsim编译、仿真这里出问题若一语成谶就不要借鉴文中的方法老老实实的自行打开modelsim一步一步的按常规做法新建项目添加文件…等去完成编译和仿真查看波形具体可自行网络查阅。
能看到末了这的说明我们有缘分啊浪费你一秒的时间给个鼓励点关注下次更新不迷路。
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |