资讯详情

Verilog正交调制解调

F P G A FPGA 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 400kH 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) ModelSim−IntelFPGAStarterEdition10.5b(QuartusPrime18.0)

实验原理

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

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

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

实验结果与分析

本次试验中并非严格按照正交调制解调的的原理进行实验,试验中的两路基带信号为 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 1−16384,即 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 2500000∗400+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 16∗38400为寄存器中共后续使用

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} 2−220

最后得出误差约为万分之七左右:

实验总结

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

附录

标签: 接近开关移位传感器vlg10

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台