Verilog正交调制解调

本文详细介绍了使用FPGA实现正交调制解调系统的过程,包括实验目的、原理、设计和仿真。实验中,通过Verilog逻辑代码实现了混频和解调模块,并利用IP核完成了滤波器设计。同时,文章还提供了MATLAB生成原始信号数据和滤波器参数的方法,以及通过Modelsim进行仿真验证的步骤。在实验结果分析中,对比了Verilog仿真数据与MATLAB仿真数据的差异,最终得出误差约为万分之七的结论。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FPGA实现信号的正交调制与解调

有具体实验需求可私聊定制

实验目的

  • 了解正交调制解调的原理和实现方法
  • 学会 I P IP IP核的使用
  • 学会利用 m o d e s i m modesim modesim进行仿真

实验要求

  1. 相关参数:
    (1)直线阵通道数: 96 96 96
    (2)信号频率: 10 k H z 10kHz 10kHz
    (3)采样率: 400 k H z 400kHz 400kHz
    (4)低通滤波器阶数: 64 64 64
    (5)低通滤波器截止频率: 20 k H z 20kHz 20kHz
  2. 技术要求:
    (1)结合上述参数完成正交变换(混频+低通滤波),其中混频通过 V e r i l o g Verilog Verilog逻辑代码实现,低通滤波通过 I P IP IP核实现
    (2)低通滤波器参数结合上述参数采用 M a t l a b Matlab Matlab计算
    (3)通道信号可以采用正弦波,结合上述参数及参考 M a t l a b Matlab Matlab程序仿真生成
    (4)仿真生成的通道数据使用方式参考测试平台参考程序
  3. 提交成果:
    (1) M o d e l s i m Modelsim Modelsim仿真结果
    (2) M a t l a b Matlab Matlab计算结果与 M o d e l s i m Modelsim Modelsim仿真结果的对比结果

实验环境

  • Q u a r t u s 18.0 Quartus18.0 Quartus18.0
  • M o d e l S i m − I n t e l F P G A S t a r t e r E d i t i o n 10.5 b ( Q u a r t u s P r i m e 18.0 ) ModelSim - Intel FPGA Starter Edition 10.5b (Quartus Prime 18.0) ModelSimIntelFPGAStarterEdition10.5b(QuartusPrime18.0)

实验原理

为了提高频谱利用率,通信系统通常采用正交调制解调,如下图所示分别为正交调制解调的原理的实现方法:
在这里插入图片描述

在调制端,分别输入信号的实部和虚部,实部和虚部信号分别与 c o s ω 0 t cos\omega_{0}t cosω0t − s i n ω 0 t -sin\omega_{0}t sinω0t相乘,再将两路信号相加后可以得到调制信号。

在解调端,将经过信号的调制信号分为两路,在分别与两路互相正交的信号 c o s ω 0 t cos\omega_{0}t cosω0t − s i n ω 0 t -sin\omega_{0}t sinω0t相乘,再分别经过低通滤波器,可以得出解调信号。

实验结果与分析

本次试验中并非严格按照正交调制解调的的原理进行实验,试验中的两路基带信号为 96 96 96 C W CW CW信号,而非信号实部和虚部,载波频率为 400 k H z 400kHz 400kHz C W CW CW信号频率为 10 k H z 10kHz 10kHz,系统时钟频率为 100 M H z 100MHz 100MHz

整个工程主要分为四个部分:顶层模块,混频模块, F I R FIR FIR滤波器模块,锁相环模块

顶层模块

对各模块进行例化
在这里插入图片描述

混频模块

输入信号处理
assign signal = data-14'd8192;

在实际情况中,处理数据应为 A D AD AD模块量化后的读取信号,所得到的数据为整数,因此需要先对输入数据进行第一步处理,根据 A D AD AD量化精度将信号恢复为有符号数值,本次实验输入数据幅值为 1 − 16384 1-16384 116384,即 14 b i t 14bit 14bit数据,因此需对原始数据减去 8192 8192 8192

调制

两路信号分别与正弦和余弦载波相乘,然后相加得到调制信号

signal_1 		<= signal*carrier_cos;		//	中间变量,用来debug和调整时序
signal_2 		<= signal*carrier_sin;
signal_output 	<= signal*carrier_cos+signal*carrier_sin;

在这里插入图片描述

载波控制模块

载波幅值

载波频率为 100 k H z 100kHz 100kHz,采样频率为 400 k H z 400kHz 400kHz,因此可认为在载波的一个周期内,只采集到四个数据,可以将四个数据特殊化为 1 , 0 , − 1 , 0 1, 0, -1, 0 1,0,1,0,并采用一个 400 k H z 400kHz 400kHz时钟作为触发时钟,每到时钟上升沿触发,载波数据改变到下一个点,调制解调时需要同步载波,因此将载波生成放入另一模块中

always @(posedge clk_400K)	begin
    if (!rst_n) begin
        cnt_4_sin 		<=	3'd0;
        cnt_4_cos		<=	3'd0;
    end
    else begin
        cnt_4_cos 		<=	cnt_4_cos+1'b1;
        cnt_4_sin 		<=	cnt_4_sin+1'b1;
        if(cnt_4_cos==3)begin
            cnt_4_cos	<=	3'd0;
        end
        if(cnt_4_sin==3)begin
            cnt_4_sin	<=	3'd0;
        end
    end
end
状态机

根据计数器数值确定载波下一个的状态

always @(posedge clk) begin
    if(!rst_n)begin
        carrier_cos	<=	2'd0;
        carrier_sin	<=	2'd0;
    end
    else begin
        case(cnt_4_cos)
            3'd0:	carrier_cos	<=	2'b1;
            3'd1:	carrier_cos	<=	2'b0;
            3'd2:	carrier_cos <=	-2'b1;
            3'd3:	carrier_cos	<=	2'b0;
        endcase

        case(cnt_4_sin)
            3'd0:	carrier_sin	<=	2'b0;
            3'd1:	carrier_sin	<=	2'b1;
            3'd2:	carrier_sin <=	2'b0;
            3'd3:	carrier_sin <=	-2'b1;
        endcase
    end	
end

下图所示三个信号分别为读入信号和分别与两路正交信号相乘得出的信号

在这里插入图片描述

解调模块

解调应分为两部分:与同相载波相乘;过低通滤波器

解调模块中只负责将调制信号分别与两路同相正交载波相乘,本次实验在同一工程下实现调制解调,不需要考虑载波相位问题,实际工程中需要加入valid信号控制保证载波同相问题

signal_r <= signal_input*carrier_cos;
signal_i <= signal_input*carrier_sin;

在这里插入图片描述

滤波器模块

实验采用 96 96 96路滤波器,读入的前 96 96 96个数据分别划为 96 96 96个滤波器的第一个数据,读入的下一组 96 96 96个数据分别划为 96 96 96个滤波器的第二个数据,每个滤波器共需读入 400 400 400个数据

滤波器参数通过 M A T L A B MATLAB MATLAB的滤波器设计工具生成

滤波器

在这里插入图片描述

例化信号

fir fir_1(
	.clk                (sys_clk				), 
	.reset_n            (sys_rst_n				),  
	.ast_sink_data      (signal1				), 
	.ast_sink_valid     (data_valid				),  
	.ast_sink_error     (2'b00					),  
	.ast_sink_sop       (ast_sink_sop			),  
	.ast_sink_eop       (ast_sink_eop			),  
	.ast_source_data    (ast_source_data_1		),   
	.ast_source_valid   (ast_source_valid_1		),  
	.ast_source_error   (ast_source_error_1		),   
	.ast_source_sop     (						),
	.ast_source_eop     (						),
	.ast_source_channel (						)  

F I R FIR FIR I P IP IP核需要输入和输出信号线如上

ast_sink_valid为输入数据有效信号,滤波器采样频率为 400 k H z 400kHz 400kHz,因此每 250 250 250个时钟周期进行一次采样,因此在这 250 250 250个时钟周期中,前 96 96 96个时钟周期为多通道滤波器的连续采样时刻,此时valid信号拉高,当一组数据采集完成后,信号拉低,工程中用到两个valid信号,fir_valid落后于data_valid一个时钟周期,因此fir_valid信号在仿真文件中定义如下:

// wire fir_valid;
assign fir_valid 	= (((cnt_valid >= 2)&&(cnt_valid <= 97)) ?1 : 0);

ast_sink_sopast_sink_eop分别为输入数据起始和结束标记脉冲,通过对valid信号上升沿和下降沿的捕获实现 ,基本思路为对valid信号延时并取反相与实现,具体实现方法如下:

// 捕获valid信号上升沿和下降沿
reg        en_d0, en_d1; 
//捕获valid上升沿,得到一个时钟周期的脉冲信号
assign sink_sop = (~en_d1) & en_d0;
//捕获valid下降沿,得到一个时钟周期的脉冲信号
assign sink_eop = (~en_d0) & en_d1;

//对valid信号延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin         
    if (!sys_rst_n) begin
        en_d0 <= 1'b0;                                  
        en_d1 <= 1'b0;
    end                                                      
    else begin                                               
        en_d0 <= fir_valid;                               
        en_d1 <= en_d0;                           
    end
end

在这里插入图片描述

锁相环模块

试验中需要一个 400 k H z 400kHz 400kHz的时钟控制载波信号取值,因此用到了锁相环
在这里插入图片描述

锁相环的使用是存在延时的,而非reset信号拉高后就会输出 400 k H z 400kHz 400kHz时钟,如图所示:
在这里插入图片描述

因此在定义data_valid信号时,需要延时一定时间至度过锁相环延时周期,才能保证正常运行

initial begin
		# 60000; // 锁相环有延时
		forever begin
			@(posedge sys_clk);
			begin
				if(cnt_valid == 250)

仿真文件

系统时钟

每隔 5000 p s 5000ps 5000ps翻转一次

// 100MHz sys_clk generating
localparam   TCLK_HALF     = 5_000;
initial begin
    sys_clk = 1'b0 ;
    forever begin
        # TCLK_HALF sys_clk = ~sys_clk ;
    end
end
定义复位和停止时刻

总时间尺度约为 2500000 ∗ 400 + 60000 2500000*400+60000 2500000400+60000

initial begin
    sys_rst_n = 1'b0 ;
    # 30 ;
    sys_rst_n = 1'b1 ;
    # 1_000_060_000
    $finish ;
end
读取数据

readmemh可读取十六进制数,将读取数据存放到 16 ∗ 38400 16*38400 1638400为寄存器中共后续使用

reg          [15:0] stimulus [0:38399] ;
integer      i ;
initial begin
    $readmemh("data_cw_38400.txt", stimulus) ;
    i = 1 ;
    data = stimulus[0] ;
    forever begin  
        @(negedge sys_clk) ;
        if(data_valid && i<38400)begin
            data	= stimulus[i] ;
            i=i+1;
        end
    end
end

设定读取使能信号,确定何时读取何时停止

// wire data_valid;
assign data_valid = (((cnt_valid >= 1)&&(cnt_valid <= 96)) ?1 : 0);
存放数据

保存数据供后续比对

integer fir1_file, fir2_file;
initial fir1_file = $fopen("data_out_1.txt");
initial fir2_file = $fopen("data_out_2.txt");
always @(posedge sys_clk) begin
    if (!sys_rst_n) begin
        // reset
    end
    else if (ast_source_valid_1) begin
        $fwrite(fir1_file,"%f\n",$signed(ast_source_data_1));// %f 有符号数保存,\n:换行符
        $fwrite(fir2_file,"%f\n",$signed(ast_source_data_2));// %f 有符号数保存,\n:换行符
    end
end

数据对比

为验证 V e r i l o g Verilog Verilog程序是否正确,将通过 M o d e l s i m Modelsim Modelsim仿真得出数据与通过 M a t l a b Matlab Matlab仿真得出数据进行对比

原始数据

在这里插入图片描述

在这里插入图片描述

解调波形

在这里插入图片描述
在这里插入图片描述

根据观察发现,通过 V e r i l o g Verilog Verilog得出数据与对应位置的通过 M a t l a b Matlab Matlab得出的数据幅值相差三倍,根据分析可能是由于输出数据位宽定义不一致导致的,因此先对通过两种方法得出的数据进行归一化,归一化范围为 2 − 2 20 2-2^{20} 2220

最后得出误差约为万分之七左右:
在这里插入图片描述

实验总结

以前写 V e r i l o g Verilog Verilog都很简单,都是直接写在板子上跑,对于仿真文件了解也很少,时序也都乱写,这次写完这个工程对于仿真文件和时序也算有了一点新的理解

附录

V e r i l o g Verilog Verilog部分

顶层模块

//===============================
//	正交调制解调仿真实验
//	顶层模块
//	作者:何一飞
//	时间:2022-6-28
//===============================



module FIR_top(
	input									sys_clk,
	input									sys_rst_n,
	input 									data_valid,
	input  									fir_valid,
	input									ast_sink_sop,
	input									ast_sink_eop,
	input					[15: 0]			data,

	output									locked,
	output									clk_400K,
	output 	wire 	signed 	[15: 0]			signal1,
	output 	wire 	signed 	[15: 0]			signal2,
	output  wire	signed	[15: 0]			signal_output,
	output  wire	signed 	[15: 0]			signal_r,
	output  wire	signed 	[15: 0]			signal_i,	
	output	wire							ast_source_valid_1,
	output	wire 	signed 	[ 1: 0]			ast_source_error_1,
	output	wire 	signed 	[ 1: 0]			ast_source_error_2,
	output	wire 	signed 	[18: 0]			ast_source_data_1,
	output	wire 	signed 	[18: 0]			ast_source_data_2
	);
	

	wire	signed	[ 1: 0]			carrier_cos;
	wire	signed	[ 1: 0]			carrier_sin;

	
mixed umixed(
	.clk 			(sys_clk		),
	.clk_400K		(clk_400K		),
	.rst_n 			(sys_rst_n		),
	.data			(data			),
	.data_valid 	(data_valid 	),
	.carrier_cos 	(carrier_cos	), 
	.carrier_sin	(carrier_sin	),
	.signal_1		(signal1		),
	.signal_2		(signal2		),
	.signal_output	(signal_output	)
	);


decode udecode(
	.clk 			(sys_clk		),
	.clk_400K		(clk_400K		),
	.rst_n 			(sys_rst_n		),
	.signal_r		(signal_r		),
	.signal_i		(signal_i		),
	.carrier_cos 	(carrier_cos	), 
	.carrier_sin	(carrier_sin	),
	.signal_input	(signal_output	)
	);
	

carrier ucarrier(
	.clk 			(sys_clk		),
	.clk_400K		(clk_400K		),
	.rst_n 			(sys_rst_n		),
	.carrier_cos 	(carrier_cos	), 
	.carrier_sin	(carrier_sin	)
	);

	
PLL uPLL(
	.inclk0			(sys_clk		),
	.areset			(~sys_rst_n		),
	.c0				(clk_400K		),
	.locked			(locked			)
	);
	
	
fir fir_1(
	.clk                (sys_clk				),    	
	.reset_n            (sys_rst_n				),    	
	.ast_sink_data      (signal_r				),    	
	.ast_sink_valid     (fir_valid				),    	
	.ast_sink_error     (2'b00					),    	
	.ast_sink_sop       (ast_sink_sop			),    	
	.ast_sink_eop       (ast_sink_eop			),    	
	.ast_source_data    (ast_source_data_1		),   	
	.ast_source_valid   (ast_source_valid_1		),   	
	.ast_source_error   (ast_source_error_1		),   	
	.ast_source_sop     (						),   	
	.ast_source_eop     (						),    	
	.ast_source_channel (						)  		
	);	

fir fir_2(
	.clk                (sys_clk				),    	
	.reset_n            (sys_rst_n				),    	
	.ast_sink_data      (signal_i				),    	
	.ast_sink_valid     (fir_valid				),    	
	.ast_sink_error     (2'b00					),    	
	.ast_sink_sop       (ast_sink_sop			),    	
	.ast_sink_eop       (ast_sink_eop			),    	
	.ast_source_data    (ast_source_data_2		),   	
	.ast_source_valid   (						),   	
	.ast_source_error   (ast_source_error_2		),   	
	.ast_source_sop     (						),    	
	.ast_source_eop     (						),    	
	.ast_source_channel (						)  		
	);

endmodule

混频模块

//===============================
//	正交调制解调仿真实验
//	混频模块
//	作者:何一飞
//	时间:2022-6-28
//	时钟频率100MHz
//	正交载波频率400kHz
//===============================



module mixed(
	input											clk,
	input											clk_400K,
	input											rst_n,
	input							signed 	[15: 0]	data,
	input											data_valid,
	input							signed	[ 1: 0]	carrier_cos, carrier_sin,
	output						reg	signed 	[15: 0]	signal_1,
	output						reg	signed 	[15: 0]	signal_2,
	output						reg	signed 	[15: 0]	signal_output
	);


	wire							signed 	[15: 0]	signal;
	initial signal_1		=	0;
	initial signal_2		=	0;
	
	
	assign signal = (data-14'd8192);
	
	always @(posedge clk) begin
		if (!rst_n) begin
			signal_1		<=	16'd0;
			signal_2		<=	16'd0;
		end
		else begin
			signal_1 		<= signal*carrier_cos;
			signal_2 		<= signal*carrier_sin;
			signal_output 	<= signal*carrier_cos+signal*carrier_sin;
		end
	end
	
endmodule

载波控制模块

//===============================
//	正交调制解调仿真实验
//	载波控制模块
//	作者:何一飞
//	时间:2022-6-28
//	四个状态,特殊化为1,0,-1,0
//	400KHz时钟控制
//===============================




module carrier(
	input											clk,
	input											clk_400K,
	input											rst_n,
	output					reg		signed	[ 1: 0]	carrier_cos, carrier_sin
	);

	
	reg										[ 2: 0]	cnt_4_cos, cnt_4_sin;
	initial cnt_4_cos		=	0;
	initial cnt_4_sin		=	0;
	initial carrier_cos		=	0;
	initial carrier_sin		=	0;


	always @(posedge clk_400K)	begin
		if (!rst_n) begin
			cnt_4_sin 		<=	3'd0;
			cnt_4_cos		<=	3'd0;
		end
		else begin
			cnt_4_cos 		<=	cnt_4_cos+1'b1;
			cnt_4_sin 		<=	cnt_4_sin+1'b1;
			if(cnt_4_cos==3)begin
				cnt_4_cos	<=	3'd0;
			end
			if(cnt_4_sin==3)begin
				cnt_4_sin	<=	3'd0;
			end
		end
	end

	always @(posedge clk) begin
		if(!rst_n)begin
			carrier_cos	<=	2'd0;
			carrier_sin	<=	2'd0;
		end
		else begin
			case(cnt_4_cos)
				3'd0:	carrier_cos	<=	2'b1;
				3'd1:	carrier_cos	<=	2'b0;
				3'd2:	carrier_cos <=	-2'b1;
				3'd3:	carrier_cos	<=	2'b0;
			endcase

			case(cnt_4_sin)
				3'd0:	carrier_sin	<=	2'b0;
				3'd1:	carrier_sin	<=	2'b1;
				3'd2:	carrier_sin <=	2'b0;
				3'd3:	carrier_sin <=	-2'b1;
			endcase
		end	
	end

endmodule

解调模块

//===============================
//	正交调制解调仿真实验
//	解调模块
//	作者:何一飞
//	时间:2022-6-28
//	调制信号分别与两路同相载波相乘
//===============================

module decode(
	input											clk,
	input											clk_400K,
	input											rst_n,
	input							signed	[ 1: 0]	carrier_cos, carrier_sin,
	input							signed 	[15: 0]	signal_input,
	output						reg	signed 	[15: 0]	signal_r,
	output						reg	signed 	[15: 0]	signal_i
	);


	always @(posedge clk) begin
		if (!rst_n) begin
			signal_r		<=	16'd0;
			signal_i		<=	16'd0;
		end
		else begin
			signal_r <= signal_input*carrier_cos;
			signal_i <= signal_input*carrier_sin;
		end
	end
	
endmodule

T e s t b e n c h Testbench Testbench

//===============================
//	正交调制解调仿真实验
//	仿真文件
//	作者:何一飞
//	时间:2022-6-29
//===============================

`timescale 1 ps/ 1 ps
module FIR_top_vlg_tst();
reg eachvec;
reg  [15:0] 	data;
reg 				sys_rst_n;
reg 				sys_clk;
// wires
wire 				data_valid;
wire				fir_valid;
wire 				clk_400K;
wire 				sink_sop;
wire 				sink_eop;
wire 				locked;
wire				ast_source_valid_1;
wire [ 1: 0]	ast_source_error_1;
wire [ 1: 0] 	ast_source_error_2;
wire [15: 0] 	signal1;
wire [15: 0] 	signal2;                                            
wire [18: 0]  	ast_source_data_1;
wire [18: 0]  	ast_source_data_2;

wire	signed	[15: 0]			signal_output;
wire	signed 	[15: 0]			signal_r;
wire	signed 	[15: 0]			signal_i;

// assign statements (if any)                          
FIR_top i1 (
// port map - connection between master ports and signals/registers   
	.signal1 					(signal1					),
	.signal2 					(signal2					),
	.signal_r 					(signal_r				),
	.signal_i 					(signal_i				),
	.signal_output 			(signal_output			),
   .ast_sink_sop 				(sink_sop 				),          
   .ast_sink_eop 				(sink_eop 				), 
	.clk_400K 					(clk_400K 				),
	.locked 						(locked 					),
	.ast_source_valid_1 		(ast_source_valid_1	),
	.ast_source_data_1 		(ast_source_data_1	),
	.ast_source_data_2 		(ast_source_data_2	),
	.data 						(data 					),
	.data_valid 				(data_valid				),
	.fir_valid 					(fir_valid				),
	.sys_clk 					(sys_clk					),
	.sys_rst_n 					(sys_rst_n				)
);




//=====================================
// 100MHz sys_clk generating
   localparam   TCLK_HALF     = 5_000;
   initial begin
      sys_clk = 1'b0 ;
      forever begin
         # TCLK_HALF sys_clk = ~sys_clk ;
      end
   end

//=====================================
//  reset and finish

   initial begin
      sys_rst_n = 1'b0 ;
      # 30 ;
      sys_rst_n = 1'b1 ;
      //# (TCLK_HALF * 2 * 8  * SIMU_CYCLE) ;
      //$finish ;
		# 1_000_060_000
		$finish ;
   end

//=======================================
//================read data==============
   reg          [15:0] stimulus [0:38399] ;
   integer      i ;
   initial begin
      $readmemh("data_cw_38400.txt", stimulus) ;
      i = 1 ;
      data = stimulus[0] ;
      forever begin  
			@(negedge sys_clk) ;
			if(data_valid && i<38400)begin
				data	= stimulus[i] ;
				i=i+1;
			end
      end // forever begin
   end // initial begin


//=====================================
// valid
   reg   [ 7: 0]cnt_valid;
   initial cnt_valid <= 8'd0;
	initial begin
		# 60000; // PLL Delay
		forever begin
			@(posedge sys_clk);
			begin
				if(cnt_valid == 250)
					cnt_valid <= 8'd1;
				else
					cnt_valid <= cnt_valid + 1;
			end
		end
	end
   // wire data_valid && fir_valid;
   assign data_valid = (((cnt_valid >= 1)&&(cnt_valid <= 96)) ?1 : 0);
   assign fir_valid 	= (((cnt_valid >= 2)&&(cnt_valid <= 97)) ?1 : 0);


//=====================================
	// 捕获valid信号上升沿和下降沿
	reg        en_d0, en_d1; 
	//reg        en_d2, en_d3;
	//	捕获valid上升沿,得到一个时钟周期的脉冲信号
	assign sink_sop = (~en_d1) & en_d0;
	//	捕获valid下降沿,得到一个时钟周期的脉冲信号
	assign sink_eop = (~en_d0) & en_d1;

	//	对valid信号延迟两个时钟周期
	always @(posedge sys_clk) begin       
		 if (!sys_rst_n) begin
			  en_d0 <= 1'b0;                                  
			  en_d1 <= 1'b0;
		 end                                                      
		 else begin                                               
			  en_d0 <= fir_valid;                               
			  en_d1 <= en_d0;                           
		 end
	end

//===========================================
// write wave data to fir1res.txt, fir2res.txt

	integer fir1_file, fir2_file;
		initial fir1_file = $fopen("data_out_1.txt");
		initial fir2_file = $fopen("data_out_2.txt");
	always @(posedge sys_clk) begin
		if (!sys_rst_n) begin
			// reset
		end
		else if (ast_source_valid_1) begin
			$fwrite(fir1_file,"%f\n",$signed(ast_source_data_1));// %f 十进制保存,\n:换行符
			$fwrite(fir2_file,"%f\n",$signed(ast_source_data_2));// %f 十进制保存,\n:换行符
		end
	end

                                                   
endmodule


M a t l a b Matlab Matlab部分

生成原始信号数据

clear all; close all; clc
channel = 96;
f = 100e3
fs = 400e3
T_ca = 1/fs
t = (0:fs-1)*T_ca
t = t(1:400)
t2 = (0:96*fs-1)*T_ca/96
carrier1 = sin(2*pi*f*t);
carrier1 = carrier1(1: 400)
carrier2 = cos(2*pi*f*t);
carrier2 = carrier2(1: 400)

%% FIR
B=20000;
filter_order = 64;
filter_f=fir1(filter_order,B/(fs/2),'low'); 

%% CW
T = 1e-3;
fs = 400e3;
f0 = 10e3;%50e3;
Ts = 1/fs;
N = T/Ts;

fai = rand(1,channel)*pi;
for kk = 1:channel
    s(:,kk) = round((16384/2-1)*(cos(2*pi*f0*t+fai(kk))+0));
end

plot(t,s)
title('原始波形')

%% Decode
% carrier2 = repmat(carrier2, channel, 1);
result1 = s'.*repmat(carrier1, channel, 1).^2;
result2 = s'.*repmat(carrier2, channel, 1).^2;
% out1 = LPF(result1);
out1 = filter(LPF, result1');
out2 = filter(LPF, result2');
subplot(211)
plot(t, out1);  axis([0 100*T_ca -8000 8000])
subplot(212)
plot(t, out2);  axis([0 100*T_ca -8000 8000])

new = (reshape((s+8191)', 1, []))';
fir_out1 = (reshape(out1', 1, []))';
fir_out2 = (reshape(out2', 1, []))';

fid         = fopen('data_cw_38400.txt', 'wt') ;  %写数据文件
fprintf(fid, '%x\n', new) ;
fclose(fid) ;

fid_2         = fopen('out1_38400.txt', 'wt') ;  %写数据文件
fprintf(fid_2, '%f\n', fir_out1) ;
fclose(fid_2) ;

fid_3         = fopen('out2_38400.txt', 'wt') ;  %写数据文件
fprintf(fid_3, '%f\n', fir_out2) ;
fclose(fid_3) ;

save fir_data.txt -ascii new
save fir_out1.txt -ascii fir_out1
save fir_out2.txt -ascii fir_out2



function Hd = LPF

Fs = 400;               % Sampling Frequency

N     = 64;  % Order
Fpass = 20;  % Passband Frequency
Fstop = 25;  % Stopband Frequency
Wpass = 1;   % Passband Weight
Wstop = 1;   % Stopband Weight
dens  = 20;  % Density Factor

% Calculate the coefficients using the FIRPM function.
b  = firpm(N, [0 Fpass Fstop Fs/2]/(Fs/2), [1 1 0 0], [Wpass Wstop], ...
           {dens});
Hd = dfilt.dffir(b);

end

数据验证

square_ = [38400 1]

fid_F1 = fopen('data_out_1.txt','r');
[f_F1, count_F1]=fscanf(fid_F1, '%f %f', square_);
fclose(fid_F1);

fid_F2 = fopen('data_out_2.txt','r');
[f_F2, count_F2]=fscanf(fid_F2, '%f %f', square_);
fclose(fid_F1);

fid_M1 = fopen('out1_38400.txt','r');
[f_M1, count_M1]=fscanf(fid_M1, '%f %f', square_);
fclose(fid_F1);

fid_M2 = fopen('out2_38400.txt','r');
[f_M2, count_M2]=fscanf(fid_M2, '%f %f', square_);
fclose(fid_F1);


d_max = 2^20;
d_min = 2;

data_F1 = mapminmax(f_F1', d_min, d_max)
data_F2 = mapminmax(f_F2', d_min, d_max)
data_M1 = mapminmax(f_M1', d_min, d_max)
data_M2 = mapminmax(f_M2', d_min, d_max)

rate_1 = error(data_F1, data_M2)
rate_2 = error(data_F2, data_M1)


function rate = error(a, b)
    rate = mean(abs(a-b)./abs(b));
end

完整工程链接在这里:https://download.youkuaiyun.com/download/m0_51077616/85826926

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不想取名字的飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值