【信道估计均衡】基于FPGA的MMSE信道估计均衡verilog实现

1.软件版本

matlab2013b,ISE14.7

2.本算法fpga实现过程

整个系统分为估计和均衡两个模块,其RTL电路图如下所示:

这个系统的各个管脚接口如下所示:

i_clk_40m:

系统时钟,为40M的时钟频率

i_rst:

复位信号,0的时候系统复位,1的时候正常工作

i_en:

系统使能信号,1的时候,系统正常工作

i_ram_data_re:

接收到的信号的实部

i_ram_data_im:

接收到的信号的虚部

i_symbol_real:

发送的信号的实部

i_symbol_imag:

发送的信号的虚部

o_ram_h_real:

信道估计输出的实部

o_ram_h_imag:

信道估计输出的虚部

o_clk_60m:

60M时钟,通过DCM,将40M转换为60M

o_start:

FFT工作信号

o_d_re:

将信道估计实部转换为频域值

o_d_im:

将信道估计虚部转换为频域值

o_f_re:

将信道估计的多径信号的实部转换为频域值

o_f_im:

将信道估计的多径信号的虚部转换为频域值

o_done_fft:

FFT计算完成使能信号

o_xk_re_d:

将信道估计实部转换为频域值的FFT变换

o_xk_im_d:

将信道估计虚部转换为频域值的FFT变换

o_xk_re_f:

将信道估计的多径信号的实部转换为频域值的FFT变换

o_xk_im_f:

将信道估计的多径信号的虚部转换为频域值的FFT变换

o_I_EQ_re:

均衡输出的实部

o_I_EQ_im:

均衡输出的虚部

o_start_ifft:

IFFT开始工作信号

o_done:

IFFT计算完成使能信号

o_xk_re:

IFFT计算完成使能信号的实部

o_xk_im:

IFFT计算完成使能信号的虚部

o_data:

最后的并行信号

o_signal_I:

最后的串行信号

系统的资源占用如下所示

整个系统包含如下的程序

这些文件的含义为:

信道估计与均衡顶层模块

信道估计顶层模块

除法模块

均衡顶层模块

时钟管理器模块

双口RAM模块

通过MMSE得到信道矩阵H的转换。

频域除非模块

信号均衡后输出模块

下面对各个模块进行简要的说明:

信道估计与均衡顶层模块

即系统的顶层模块,调用信道估计和信道均衡两个模块。

信道估计顶层模块

channel_est.v

对应的模块:即调用除法模块。

除法模块

div_unit.v

除法模块,用来进行信道估计。

均衡顶层模块

Channel_equalizer.v

        这个模块是均衡模块的顶层模块。调用下面的各个均衡子模块。

时钟管理器模块

clk_gen.v

这个模块主要通过DCM时钟IP核进行实现,产生所需要的时钟频率。

双口RAM模块

asyn_ram.v

        这个模块是数据存储管理模块,即将数据输入到双口RAM中,进行缓存,然后当需要进行数据处理的时候,产生地址,从RAM中读取对应的数据进行处理。

 

这里,主要通过调用RAM的IP核进行实现。

通过MMSE得到信道矩阵H的转换。

h_to_f.v

这个部分的主要程序,将信道估计得到的矩阵转换为频域的表达式。

频域除法模块

fft_div_ifft.v

        首先将信号进行FFT变换获得其频域信号,然后相除,最后对相除后的均衡信号进行IFFT变换。完成均衡计算。对应的verilog代码如下:

信号均衡后输出模块

fifo_output.v

        这个模块的主要功能就是将均衡后的数据进行输出,其主要原理就是通过FIFO模块,将数据进行输出,通过FIFO,可以有效的实现数据稳定的输出。对应的verilog代码如下:

3.仿真结论

仿真结果如下图所示:

4.部分源码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date:    22:26:02 06/04/2014 
// Design Name: 
// Module Name:    Channel_Est_equ 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//
module Channel_Est_equ(
                       i_clk_40m,
							  i_rst,
							  i_en,
							  i_ram_data_re,
							  i_ram_data_im,
							  i_symbol_real,
							  i_symbol_imag,
							  //est
							  o_ram_h_real,
							  o_ram_h_imag,
							  //equ
							  o_clk_60m,
							  o_start,
							  o_d_re,
							  o_d_im,
							  o_f_re,
							  o_f_im,
							  o_done_fft,
							  o_xk_re_d,
							  o_xk_im_d,
							  o_xk_re_f,
							  o_xk_im_f,
							  o_I_EQ_re,
							  o_I_EQ_im,
							  o_start_ifft,
							  o_done,
							  o_xk_re,
							  o_xk_im,
							  o_data,
							  o_signal_I	 
	                    );



input              i_clk_40m;
input              i_rst;
input              i_en;
input signed[11:0] i_ram_data_re;
input signed[11:0] i_ram_data_im;
input signed[11:0] i_symbol_real;
input signed[11:0] i_symbol_imag;
output signed[11:0]o_ram_h_real;
output signed[11:0]o_ram_h_imag;

//output of h_to_f
output               o_clk_60m;
output               o_start;
output signed [11:0] o_d_re;
output signed [11:0] o_d_im;
output signed [11:0] o_f_re;
output signed [11:0] o_f_im;
//output of fft
output               o_done_fft;
output signed [11:0] o_xk_re_d;
output signed [11:0] o_xk_im_d;
output signed [11:0] o_xk_re_f;
output signed [11:0] o_xk_im_f;
output               o_start_ifft;
//output of div
output signed [11:0] o_I_EQ_re;
output signed [11:0] o_I_EQ_im;
//output of ifft
output               o_done;
output signed [21:0] o_xk_re;
output signed [21:0] o_xk_im;
//output of fifo
output signed [21:0] o_data;
output               o_signal_I;

channel_est channel_est_u(
    .i_clk       (o_clk_60m), 
    .i_rst       (i_rst), 
    .i_data_real1(i_ram_data_re), 
    .i_data_imag1(i_ram_data_im), 
    .i_data_real2(i_symbol_real), 
    .i_data_imag2(i_symbol_imag), 
    .o_h_real    (o_ram_h_real), 
    .o_h_imag    (o_ram_h_imag)
    );


Channel_equalizer Channel_equalizer_u(
    .i_clk_40m     (i_clk_40m), 
    .i_rst         (i_rst), 
    .i_en          (i_en), 
    .i_ram_h0_re   (o_ram_h_real), 
    .i_ram_h0_im   (o_ram_h_imag), 
	 //多径设置参数
    .i_ram_hk_re   ({o_ram_h_real[11],o_ram_h_real[11:1]}), 
    .i_ram_hk_im   ({o_ram_h_imag[11],o_ram_h_imag[11:1]}), 
    .i_ram_delay   (10'd1), 
	 //=========================================
    .i_ram_data_re (i_ram_data_re), 
    .i_ram_data_im (i_ram_data_im), 
	 //=========================================
    .o_clk_5m      (), 
    .o_clk_60m     (o_clk_60m), 
    .o_rd_en       (), 
    .o_rd_add      (), 
    .o_ram_h0_re   (), 
    .o_ram_h0_im   (), 
    .o_ram_hk_re   (), 
    .o_ram_hk_im   (), 
    .o_ram_delay   (), 
    .o_ram_data_re (), 
    .o_ram_data_im (), 
    .o_start       (o_start), 
    .o_d_re        (o_d_re), 
    .o_d_im        (o_d_im), 
    .o_f_re        (o_f_re), 
    .o_f_im        (o_f_im), 
    .o_done_fft    (o_done_fft), 
    .o_xk_re_d     (o_xk_re_d), 
    .o_xk_im_d     (o_xk_im_d), 
    .o_xk_re_f     (o_xk_re_f), 
    .o_xk_im_f     (o_xk_im_f), 
    .o_I_EQ_re     (o_I_EQ_re), 
    .o_I_EQ_im     (o_I_EQ_im), 
    .o_start_ifft  (o_start_ifft), 
    .o_done        (o_done), 
    .o_xk_re       (o_xk_re), 
    .o_xk_im       (o_xk_im), 
    .o_data        (o_data), 
    .o_signal_I    (o_signal_I)
    );
	 
	 
endmodule
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date:    16:48:39 03/03/2015 
// Design Name: 
// Module Name:    h_to_f 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//
module h_to_f(i_clk,
              i_rst,
				  i_en,
				  i_h0_re,
				  i_h0_im,
				  i_hk_re,
				  i_hk_im,
				  i_delay,//K 
              i_data_re,
              i_data_im,				  
				  o_rd_en,                                // ram的读使能信号
				  o_rd_add,
				  o_start,
				  o_f_re,
				  o_f_im,
				  o_d_re,
				  o_d_im
            );
				
input               i_clk;
input               i_rst;
input               i_en;
input signed [11:0] i_h0_re;
input signed [11:0] i_h0_im;
input signed [11:0] i_hk_re;
input signed [11:0] i_hk_im;
input        [9:0]  i_delay;
input signed [11:0] i_data_re;
input signed [11:0] i_data_im;

output               o_rd_en;
output        [9:0] o_rd_add;
output               o_start;
output signed [11:0] o_f_re;
output signed [11:0] o_f_im;
output signed [11:0] o_d_re;
output signed [11:0] o_d_im;



reg signed [11:0] o_f_re = 12'd0;
reg signed [11:0] o_f_im = 12'd0;
reg signed [11:0] o_d_re = 12'd0;
reg signed [11:0] o_d_im = 12'd0;

reg               o_rd_en = 1'b0;
reg        [9:0]  o_rd_add = 10'd0;
reg               o_start = 1'b0;

reg        [5:0]  reg_t = 6'd0;

reg               start1 = 1'b0;
reg               start2 = 1'b0;
reg               start3 = 1'b0;

reg               o_rst_mul = 1'b0;                //乘法器的复位信号

reg     en1 = 1'b0;
reg     en2 = 1'b0;
wire    enable;
  
wire [5:0] k;
wire [5:0] t;

//wire [5:0] k1;
//wire [5:0] k2;
wire [5:0] t0;
wire [5:0] t1;
wire [5:0] t2;

wire signed [11:0] rcc;                             //保留一位符号位                    
wire signed [23:0] o_f_re_tmp;
wire signed [23:0] o_f_im_tmp;


assign k = i_delay/8;
assign t = i_delay%8;

//assign k1=k+1;
//assign k2=k+2;

assign t0=16-t;
assign t1=24-t;
assign t2=32-t;

always @(posedge i_clk)                 //对异步信号进行同步整形
	begin
		if(!i_rst)
			begin
				en1 <= 1'b0;
				en2 <= 1'b0;
			end
		else
			begin
				en1 <= i_en;
				en2 <= en1;
			end
	end
	
assign enable=en1&(!en2);


always @(posedge i_clk)
	begin
		if(!i_rst)
			begin
				o_rd_add  <= 10'd0;
				o_rst_mul <= 1'b0;
				o_rd_en   <= 1'b0;
			end
		else if(enable)
		         begin
						o_rd_add   <= 10'd1;
						o_rst_mul   <= 1'b0;
				      o_rd_en   <= 1'b1;
					end
			  else if(o_rd_add == 0||o_rd_add == 512)
			           begin
						      o_rd_add   <= 10'd0;
						      o_rst_mul   <= 1'b0;
				            o_rd_en   <= 1'b0;
						  end
					 else
					     begin
					         o_rd_add  <= o_rd_add + 10'd1;
								o_rst_mul <= 1'b1;
				            o_rd_en   <= 1'b1;
						  end
	end
	
always @(posedge i_clk)
	begin
		if(!i_rst)
			begin
				o_start  <= 1'b0;
				start1   <= 1'b0;
				start2   <= 1'b0;
				start3   <= 1'b0;
			end
		else
			begin
				start1  <= o_rd_en;
				start2  <= start1;
				start3  <= start2;
				o_start <= start3;
		
			end
	end




always @(posedge i_clk or negedge i_rst)	
	begin
		if(!i_rst)
			reg_t <= 6'd0;
		else if(o_rd_add == k)
			      reg_t <= t0;
		     else if (o_rd_add == k + 6'd1)
		              reg_t <= t1;
			       else if (o_rd_add == k + 6'd2)
			                reg_t <= t2;
					      else
					          reg_t <= 6'd0;
	end


rom_rrc unit (.clka(i_clk),
	           .ena(o_rd_en),
	           .addra(reg_t), // Bus [5 : 0] 
	           .douta(rcc)); // Bus [11 : 0] 
				  
mul_h_rrc re (.clk(i_clk),
	           .a(i_hk_re), // Bus [11 : 0] 
	           .b(rcc), // Bus [10 : 0] 
	           .ce(o_rst_mul),
	           .p(o_f_re_tmp)); // Bus [22 : 0] 
				 
mul_h_rrc im (.clk(i_clk),
	           .a(i_hk_im), // Bus [11 : 0] 
	           .b(rcc), // Bus [10 : 0] 
	           .ce(o_rst_mul),
	           .p(o_f_im_tmp)); // Bus [22 : 0]
				  
always @(posedge i_clk)
	begin
		if(!i_rst)
			begin
				o_f_re <= 12'd0;
				o_f_im <= 12'd0;
			end
		else if (o_rd_add == 8)                        //乘法器和rom???难邮?		         
		         begin
						o_f_re <= i_hk_re;             //截取12位        
						o_f_im <= i_hk_im;
					end
			  else if(o_rd_add > 8)
			           begin
					      o_f_re <= i_hk_re;
						   o_f_im <= i_hk_im;
					     end
					 else
				        begin
				            o_f_re <= i_hk_re;
			 	            o_f_im <= i_hk_im;
			            end
	end
	
reg signed [11:0] re_data1 = 12'd0;
reg signed [11:0] re_data2 = 12'd0;
reg signed [11:0] re_data3 = 12'd0;
reg signed [11:0] re_data4 = 12'd0;
reg signed [11:0] re_data5 = 12'd0;
reg signed [11:0] re_data6 = 12'd0;

always @(posedge i_clk)
	begin
		if(!i_rst)
			begin
				o_d_re    <= 12'd0;
				re_data1  <= 12'd0;
				re_data2  <= 12'd0;
				re_data3  <= 12'd0;
			   re_data4  <= 12'd0;
            re_data5  <= 12'd0;
				re_data6  <= 12'd0;
			end
		else
			begin
				re_data1 <= i_data_re;
				re_data2 <= re_data1;
				re_data3 <= re_data2;
				re_data4 <= re_data3;
				re_data5 <= re_data4;
				re_data6 <= re_data5;
				o_d_re    <= re_data6;
			end
	end
	
reg signed [11:0] im_data1 = 12'd0;
reg signed [11:0] im_data2 = 12'd0;
reg signed [11:0] im_data3 = 12'd0;
reg signed [11:0] im_data4 = 12'd0;
reg signed [11:0] im_data5 = 12'd0;
reg signed [11:0] im_data6 = 12'd0;

always @(posedge i_clk)
	begin
		if(!i_rst)
			begin
				o_d_im    <= 12'd0;
				im_data1  <= 12'd0;
				im_data2  <= 12'd0;
				im_data3  <= 12'd0;
            im_data4  <= 12'd0;
				im_data5  <= 12'd0;
				im_data6  <= 12'd0;
			end
		else
			begin
				im_data1 <= i_data_im;
				im_data2 <= im_data1;
				im_data3 <= im_data2;
				im_data4 <= im_data3;
				im_data5 <= im_data4;
				im_data6 <= im_data5;
				o_d_im   <= im_data6;
		
			end
	end


endmodule

5.参考文献

[1]邵际南. 基于FPGA的TD-LTE系统上行信道估计与均衡部分的实现[D]. 北京交通大学, 2011.A01-99

猜你喜欢

转载自blog.csdn.net/ccsss22/article/details/125109505