> 技术文档 > FSK非相干解调的FPGA实现(附代码)

FSK非相干解调的FPGA实现(附代码)


文章目录

  • FSK解调的几种方法
  • 包络检波解调法的原理
  • 包络检波解调法的FPGA实现
    • 1.顶层模块的实现
    • 2.滤波器模块的实现
    • 3.位同步模块的实现
    • 3.测试模块的实现
  • 资源链接

阅读本文章之前,需要注意的是,本文章与之前发的文章是一个系列,如果有部分内容不明白的话可以阅读先前的文章,也可以联系博主进行询问。

FSK解调的几种方法

根据网上链接可以得知:
FSK解调大致有四种方法(也许还有其他方法,这里只阐述这四种方法),这四种方法分别是

  1. 相乘微分型AFC环解调法(属于非相干解调)
  2. 包络检波解调法(属于非相干解调)
  3. 最佳FSK相干解调器(属于相干解调)
  4. 易于实现的FSK相干解调器(属于相干解调)

其中相干解调比非相干解调的性能要好一些,但是相干解调的实现过程更复杂一些,因此本文主要使用“包络检波解调法”对FSK信号进行解调,并使用Verilog代码实现该功能。


包络检波解调法的原理

包络检波解调法的原理可以使用以下图片来表示,该图片是使用visio软件绘制的,文末将给出visio文件的链接。
在这张图片中,包含以下过程:

  1. 首先将FSK信号通过两个带通滤波器,而两个带通滤波器的中心频率分别是f1和f2,这一步所得到的两个结果实质上是两个ASK信号。在本文中,两个频率分别是2.5MHz和5MHz。
  2. 然后再将两个信号分别进行“全波整流”的操作,也就是信号取绝对值。
  3. 然后再将信号通过低通滤波器,这一步的实质是获取信号的包络,这也正好对应解调方法的名字。
  4. 然后再将两个信号相减,并根据相减的结果进行判决输出,也就是输出二进制比特流。
    FSK非相干解调的FPGA实现(附代码)

包络检波解调法的FPGA实现

1.顶层模块的实现

首先给出顶层模块的实现,如下所示。其中需要注意的是,全波整流的实现主要是通过负数取补码的形式来得到的,而正数的补码就是正数本身。

module demodulation_top( input clk, input rst_n, input [15:0] FSK_signal, input FSK_signal_valid, output bit_out);wire signed [34:0] filter_out_1;wire filter_out_1_valid;wire signed [34:0] filter_out_2;wire filter_out_2_valid;//带通滤波器,中心频率是2.5MHzfilter_25 filter_25_inst( .clk (clk ), .clk_enable (1\'b1), .reset (~rst_n ), .filter_in (FSK_signal ), .filter_out (filter_out_1));//带通滤波器,中心频率是5MHzfilter_5 filter_5_inst( .clk (clk ), .clk_enable (1\'b1), .reset (~rst_n ), .filter_in (FSK_signal ), .filter_out (filter_out_2));//全波整流,也就是取绝对值reg [34:0] rectified_1_t;reg [34:0] rectified_2_t;wire [15:0] rectified_1;wire [15:0] rectified_2;always @(posedge clk or negedge rst_n)begin if(!rst_n)begin rectified_1_t <= 0; rectified_2_t <= 0; end else begin rectified_1_t <= filter_out_1[34] ? $signed({1\'b0, ~filter_out_1[33:0]}) + 1 : filter_out_1; rectified_2_t <= filter_out_2[34] ? $signed({1\'b0, ~filter_out_2[33:0]}) + 1 : filter_out_2; endendassign rectified_1 = rectified_1_t[34:34-15];assign rectified_2 = rectified_2_t[34:34-15];wire signed [34:0] filtered_1;wire signed [34:0] filtered_2;filter_lowpass_5 filter_lowpass_5_inst_1( .clk (clk ), .clk_enable (1\'b1), .reset (~rst_n ), .filter_in (rectified_1 ), .filter_out (filtered_1));filter_lowpass_5 filter_lowpass_5_inst_2( .clk (clk ), .clk_enable (1\'b1), .reset (~rst_n ), .filter_in (rectified_2 ), .filter_out (filtered_2));//判决输出reg bit_temp;always @(posedge clk or negedge rst_n)begin if(!rst_n)begin bit_temp <= 0; end else begin bit_temp <= filtered_1 < filtered_2 ? 1\'b0 : 1\'b1; endendBit_Synchronization Bit_Synchronization_inst( .clk (clk ), .rst_n (rst_n ), .bit (bit_temp ), .bit_syn(bit_out));endmodule

2.滤波器模块的实现

由于滤波器模块的代码较长,就一起放在文末的链接中了。

3.位同步模块的实现

module Bit_Synchronization( input clk, input rst_n, input bit, output reg bit_syn);reg bit_r;always @(posedge clk or negedge rst_n)begin if(!rst_n)begin bit_r <= 0; end else begin bit_r <= bit; endendreg [9:0] count;always @(posedge clk or negedge rst_n)begin if(!rst_n)begin count <= 0; end else if(bit_r == bit) begin count <= count + 1; end else count <= 0;endreg syn_pulse;always @(posedge clk or negedge rst_n)begin if(!rst_n)begin syn_pulse <= 0; end else if(count == 49) begin syn_pulse <= 1; end else syn_pulse <= 0;endalways @(posedge clk or negedge rst_n)begin if(!rst_n)begin bit_syn <= 0; end else if(syn_pulse) begin bit_syn <= bit; end else bit_syn <= bit_syn;endendmodule

3.测试模块的实现

module demodulation_top_tb(); // 参数定义 parameter DATA_WIDTH = 16; parameter CLK_PERIOD = 20; // 50MHz时钟周期(20ns) parameter FILE_PATH = \"noisy_FSK_output.txt\"; parameter SAMPLES = 2000; // 要读取的样本数 // 信号声明 reg clk; reg reset_n; reg signed [DATA_WIDTH-1:0] FSK_signal; reg FSK_signal_valid; wire bit_out; integer file, i; integer data_count = 0; // 时钟生成 initial begin clk = 0; forever #(CLK_PERIOD/2) clk = ~clk; end // 复位生成 initial begin reset_n = 0; #100 reset_n = 1; end // 读取文件并输入数据 initial begin // 初始化 FSK_signal = 0; FSK_signal_valid = 0; // 等待复位完成 wait(reset_n == 1); #100; // 打开数据文件 file = $fopen(FILE_PATH, \"r\"); if (!file) begin $display(\"Error: Could not open file %s\", FILE_PATH); $finish; end @(posedge clk); begin : read_loop // 读取并发送数据 for (i = 0; i < SAMPLES; i = i + 1) begin // 从文件读取一行数据 if ($fscanf(file, \"%d\", FSK_signal) != 1) begin  $display(\"End of file reached at sample %d\", i);  disable read_loop; // 跳出循环read_loop end // 将无符号数转换为有符号数 if (FSK_signal > 32767)  FSK_signal = FSK_signal - 65536; FSK_signal_valid = 1; data_count = data_count + 1; @(posedge clk); FSK_signal_valid = 0; end end // read_loop块结束 // 关闭文件 $fclose(file); // 等待解调完成 #2000; $display(\"Simulation completed. Processed %0d samples.\", data_count); $finish; end // 实例化FSK解调模块 demodulation_top demodulation_top_inst( .clk(clk), .rst_n(reset_n), .FSK_signal(FSK_signal), .FSK_signal_valid(FSK_signal_valid), .bit_out(bit_out) ); // 记录解调输出 // initial begin // integer out_file; // out_file = $fopen(\"demod_output.txt\", \"w\"); // forever begin // @(posedge clk); // if (bit_out_valid) begin // $fwrite(out_file, \"%d\\n\", demod_out); // $display(\"Demodulated output: %d\", demod_out); // end // end // end // 仿真控制 initial begin #100000; // 最大仿真时间 $display(\"Simulation timeout\"); $finish; end initial begin  $dumpfile(\"wave.vcd\"); //生成的vcd文件名称 $dumpvars(0, demodulation_top_tb); endendmodule

资源链接

本文章的资源链接是FSK非相干解调的FPGA实现,该资源的下载是免费的,可以直接下载,如果下载时显示需要下载码,可以根据CSDN官方的提示获取下载码,当然,也可以联系博主直接获取。

如果大家喜欢我的文章,可以点击收藏和关注,后续将分享更多有关FPGA实现的文章和代码。