Verilog正交调制解调

这篇具有很好参考价值的文章主要介绍了Verilog正交调制解调。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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)

实验原理

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

在调制端,分别输入信号的实部和虚部,实部和虚部信号分别与 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滤波器模块,锁相环模块

顶层模块

对各模块进行例化
Verilog正交调制解调

混频模块

输入信号处理
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;

Verilog正交调制解调

载波控制模块

载波幅值

载波频率为 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

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

Verilog正交调制解调

解调模块

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

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

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

Verilog正交调制解调

滤波器模块

实验采用 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的滤波器设计工具生成

滤波器

Verilog正交调制解调

例化信号

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

Verilog正交调制解调

锁相环模块

试验中需要一个 400 k H z 400kHz 400kHz的时钟控制载波信号取值,因此用到了锁相环
Verilog正交调制解调

锁相环的使用是存在延时的,而非reset信号拉高后就会输出 400 k H z 400kHz 400kHz时钟,如图所示:
Verilog正交调制解调

因此在定义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仿真得出数据进行对比

原始数据

Verilog正交调制解调

Verilog正交调制解调

解调波形

Verilog正交调制解调
Verilog正交调制解调

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

最后得出误差约为万分之七左右:
Verilog正交调制解调

实验总结

以前写 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.csdn.net/download/m0_51077616/85826926文章来源地址https://www.toymoban.com/news/detail-414424.html

到了这里,关于Verilog正交调制解调的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • m基于FPGA的64QAM调制解调通信系统verilog实现,包含testbench,不包含载波同步

    目录 1.算法仿真效果 2.算法涉及理论知识概要 2.1、64QAM调制解调系统的设计 2.1 信号生成 2.2 信号调制 2.3 信号解调 3.Verilog核心程序 4.完整算法代码文件 本系统进行了两个平台的开发,分别是: Vivado2019.2 Quartusii18.0+ModelSim-Altera 6.6d  Starter Edition 其中Vivado2019.2仿真结果如下:

    2024年02月01日
    浏览(50)
  • 基于FPGA的FSK调制解调系统verilog开发

    目录 1.算法仿真效果 2.verilog核心程序 3.算法涉及理论知识概要 4.完整verilog VIVADO2019.2仿真结果如下:       频移键控是利用载波的频率变化来传递数字信息。数字频率调制是数据通信中使用较 早的一种通信方式,由于这种调制解调方式容易实现,抗噪声和抗衰减性能较强,

    2024年02月05日
    浏览(77)
  • 利用matlab实现AM调制解调

    基本原理 幅度调制(AM)是用调制信号去控制高频载波的振幅,使之随调制信号作线性变化的过程。     上图给出了AM调制解调的原理模型,从图中可知发送信号m(t)和直流分量A 0 叠 加 后乘以高频载波cos(w c t)后即可形成AM调制信号。 具体时域波形为   对应的频谱波形为   在解

    2023年04月08日
    浏览(49)
  • Gnuradio 和 USRP 实现FM的调制与解调

    1. 硬件设备:HM B200mini; 天线 2. 软件环境: ubuntu 20.04; gnuradio 3.8; uhd 4.0; a. UHD: USRP Source USRP Source 块将通过在选定的天线上以特定频率、采样率和增益采样RF信号来产生基带样本。 b. Ratinal Resampler 因为USRP速率不是音频接收器速率的整数倍, 所以这里需要进行重采样。 c. WBFM Rec

    2024年02月12日
    浏览(36)
  • 基于matlab实现双路音频信号的AM调制与解调

    使用audioread读取音频信号,将采样率设置为100kHz,并利用awgn函数为信号添加高斯白噪声。 分别绘制两路音频信号的时频域图。 结果如下: 设置两路不同频率的载波,这里设置频率分别为35kHz和25kHz,载波频率可以根据需要进行更改,但是注意需要满足奈奎斯特采样定理,即

    2023年04月08日
    浏览(53)
  • 【USRP】调制解调系列7:GMSK、MSK、基于labview的实现

    在数字调制中,最小频移键控(Minimum-Shift Keying,缩写:MSK)是一种连续相位的频移键控方式,在1950年代末和1960年代产生。与偏移四相相移键控(OQPSK)类似,MSK同样将正交路基带信号相对于同相路基带信号延时符号间隔的一半,从而消除了已调信号中180°相位突变的现象。

    2024年02月11日
    浏览(38)
  • 西电B测——基于simulink的2PSK和2DPSK调制解调系统实现

    这是学校的B级测试实验,仅供学习交流使用 误码率曲线绘制需要用到bertool工具: bertool工具教程: 通信专业Simulink---画误码率曲线(使用bertool工具)_Enpiyahh的博客-CSDN博客_simulink误码率曲线 报告和仿真文件下载链接: 链接:https://pan.baidu.com/s/1Fo5ixtqQpegDMYFd15cctA?pwd=FCNN  提取码

    2024年02月02日
    浏览(40)
  • 【USRP】调制解调系列3:2FSK、4FSK、8FSK,基于labview的实现

    FSK(Frequency-shift keying)是信息传输中使用得较早的一种调制方式,它的主要优点是: 实现起来较容易,抗噪声与抗衰减的性能较好。在中低速数据传输中得到了广泛的应用。最常见的是用两个频率承载二进制1和0的双频FSK系统。 FSK 信号:S(t)=cos(ω0t+2πfi·t) 【USRP】调制解调系列

    2024年02月10日
    浏览(37)
  • 基于System Generator的1024QAM-FM软件无线电联合调制解调系统的FPGA实现

    目录 一、理论基础 1.1环路滤波器 1.2环鉴相器介绍 1.3 Ganrder  二、核心模型

    2024年02月13日
    浏览(46)
  • 【调制解调】AM 调幅

    学习数字信号处理算法时整理的学习笔记。同系列文章目录可见 《DSP 学习之路》目录,代码已上传到 Github - ModulationAndDemodulation。本篇介绍 AM 调幅信号的调制与解调,内附全套 MATLAB 代码。 目录 说明 1. AM 调制算法 1.1 算法描述 1.2 调制信号 m(t) 为确知信号时 1.3 调制信号 m

    2024年02月13日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包