原创 关于自适应FIR滤波器的FPGA设计

2013-5-31 10:43 2040 21 21 分类: FPGA/CPLD

 

        最近在学习进行自适应FIR滤波器的设计,下面是参考别人的设计“基于LMS算法的自适应噪声抵消器”,稍作修改之后得到的。阶数n=8;算法步长u=0.0078;输入输出信号均为16位;滤波器最高32位。主要系统输入:环境噪声信号data_in(用高斯信号来模拟)、经过噪声叠加的正弦信号desired_in(线性叠加)、步长step_size;系统输出:经过滤波的正弦信号error_out、误差e_out、拟合抽头系数w_out。其中关于定标、截位、步长的取值等方面有些疑问,希望大家能提些宝贵意见。
        自适应滤波的原理框图:
picture.jpg
 
        该设计的系统框图:
lms.jpg
        测试框架:
lms_tp.jpg
 
        ModelSim中的仿真波形:
wave.jpg
        经测试,除了μ=2^-7(即0.0078),滤波收敛效果较好的μ的取值范围:μ∈[2^-8,2^-6]。
       在实际设计中定标、截位和步长的取值很关键,在本次设计中,步长取μ=2^-7(即0.0078),定标采用Q4.11。在代码中,step_size = 16'h0010,由于采用Q4.11 ,因而u=0.0078。在LMS算法的抽头系数更新模块中,
   assign product_32 = data_in * step_size;
   assign product_16 = product_32[26:11];
   assign weight_in = (reset == 1'b1) ? 16'h0000 : (product_16 + weight_out);
关于系数每次更新累加,都截取噪声输入data_in与步长输入step_size相乘后32位乘积结果的[26:11]位。在LMS滤波器的顶层模块,
   assign product_32 = step_size * error_in;
   assign product_16 = product_32[26:11];
也都截取32位乘积结果的[26:11]位。
 
        问题:
1. 截位为什么截取32位乘积结果的[26:11]位?是跟步长定标采用Q4.11有关吗?截位标准是什么样的?如果8抽头换成17抽头,16位输入数据换成13位输入数据呢?
2. 定标是根据什么定的,怎么快速有效地定标?
3. 关于步长的取值,大了小了收敛效果都不好,除了一个个地试,有什么方法可以快速有效地给步长取值?查了资料,收敛条件为:0<μ<1/λmax,λmax是输入数据的自相关矩阵的最大特征值。具体地,在此次设计中,λmax该如何求?
        希望能跟大家交流,希望大家做过自适应FIR滤波器的,能帮帮忙,给些宝贵意见,谢谢!
 
  
 
 
        模块实现代码:
 
module lms(clk,reset,enable,data_in,desired_in,sine_display,step_size,error_out,e_out,w_out);
input  clk,reset,enable;
input   signed [15:0]  data_in,desired_in,step_size,sine_display;
output  signed [15:0]  error_out,e_out;
output  signed [127:0] w_out;
 
wire  signed [15:0] error_in,data_in_reg,
                  desired_in_reg,product_16;
wire signed [31:0] product_32,LMSx8_sum_out;
wire signed [127:0] LMSx8_link_out;
 
delayUnit data_reg_1 (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(data_in),
.delay_out(data_in_reg)
);
delayUnit data_reg_2 (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(desired_in),
.delay_out(desired_in_reg)
);
   assign product_32 = step_size * error_in;
   assign product_16 = product_32[26:11];
LMSx8 LMSx8   (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(data_in_reg),
.step_size(product_16),
.Sum_in(32'h0000_0000),
.Sum_out(LMSx8_sum_out),
.link_out(LMSx8_link_out)
);
   assign error_in = desired_in_reg - LMSx8_sum_out[26:11]; 
assign e_out = sine_display - error_out;
assign w_out = LMSx8_link_out;
delayUnit data_reg_3 (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(error_in),
.delay_out(error_out)
);
endmodule
///////////////////////////////////////////////////////////////////////////////////////////////////////
module LMSx8(clk,reset,enable,data_in,step_size,Sum_in,Sum_out,link_out);
input clk,reset,enable;
input  signed [15:0] data_in,step_size;
input   signed [31:0] Sum_in;
output  signed [31:0] Sum_out;
output  signed [127:0] link_out;
wire  signed [15:0] LMS_tap_1_delay_out, LMS_tap_2_delay_out, LMS_tap_3_delay_out, LMS_tap_4_delay_out,
                     LMS_tap_5_delay_out, LMS_tap_6_delay_out, LMS_tap_7_delay_out, LMS_tap_8_delay_out;
wire  signed [15:0] LMS_tap_1_weight_out, LMS_tap_2_weight_out, LMS_tap_3_weight_out, LMS_tap_4_weight_out,
LMS_tap_5_weight_out, LMS_tap_6_weight_out, LMS_tap_7_weight_out, LMS_tap_8_weight_out;
   wire signed [31:0] LMS_tap_1_out, LMS_tap_2_out, LMS_tap_3_out, LMS_tap_4_out,
LMS_tap_5_out, LMS_tap_6_out, LMS_tap_7_out, LMS_tap_8_out;
 
LMS_tap LMS_tap_1 (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(data_in), 
.step_size(step_size),
.delay_out(LMS_tap_1_delay_out),
.weight_out(LMS_tap_1_weight_out),
.tap_out(LMS_tap_1_out)
);
LMS_tap LMS_tap_2 (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(LMS_tap_1_delay_out), 
.step_size(step_size),
.delay_out(LMS_tap_2_delay_out),
.weight_out(LMS_tap_2_weight_out),
.tap_out(LMS_tap_2_out)
);
LMS_tap LMS_tap_3 (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(LMS_tap_2_delay_out), 
.step_size(step_size),
.delay_out(LMS_tap_3_delay_out),
.weight_out(LMS_tap_3_weight_out),
.tap_out(LMS_tap_3_out)
);
LMS_tap LMS_tap_4 (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(LMS_tap_3_delay_out), 
.step_size(step_size),
.delay_out(LMS_tap_4_delay_out),
.weight_out(LMS_tap_4_weight_out),
.tap_out(LMS_tap_4_out)
);
LMS_tap LMS_tap_5 (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(LMS_tap_4_delay_out), 
.step_size(step_size),
.delay_out(LMS_tap_5_delay_out),
.weight_out(LMS_tap_5_weight_out),
.tap_out(LMS_tap_5_out)
);
LMS_tap LMS_tap_6 (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(LMS_tap_5_delay_out), 
.step_size(step_size),
.delay_out(LMS_tap_6_delay_out),
.weight_out(LMS_tap_6_weight_out),
.tap_out(LMS_tap_6_out)
);
LMS_tap LMS_tap_7 (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(LMS_tap_6_delay_out), 
.step_size(step_size),
.delay_out(LMS_tap_7_delay_out),
.weight_out(LMS_tap_7_weight_out),
.tap_out(LMS_tap_7_out)
);
LMS_tap LMS_tap_8 (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(LMS_tap_7_delay_out), 
.step_size(step_size),
.delay_out(LMS_tap_8_delay_out),
.weight_out(LMS_tap_8_weight_out),
.tap_out(LMS_tap_8_out)
);
assign Sum_out = Sum_in + LMS_tap_1_out + LMS_tap_2_out +
        LMS_tap_3_out + LMS_tap_4_out + LMS_tap_5_out +
        LMS_tap_6_out + LMS_tap_7_out + LMS_tap_8_out;
 
assign link_out[127:112] = LMS_tap_1_weight_out;
assign link_out[111:96]  = LMS_tap_2_weight_out;
assign link_out[95:80]   = LMS_tap_3_weight_out; 
assign link_out[79:64]   = LMS_tap_4_weight_out;
assign link_out[63:48]   = LMS_tap_5_weight_out;
assign link_out[47:32]   = LMS_tap_6_weight_out; 
assign link_out[31:16]   = LMS_tap_7_weight_out;
assign link_out[15:0]    = LMS_tap_8_weight_out;
 
endmodule
///////////////////////////////////////////////////////////////////////////////////////////////////////////
module LMS_tap(clk,reset,enable,data_in,step_size,delay_out,weight_out,tap_out);
input clk,reset,enable;
input  signed [15:0] data_in,step_size;
output  signed [15:0] delay_out;
output  signed [15:0] weight_out;
output  signed [31:0] tap_out;
wire signed [15:0] weight_in,product_16;
   wire signed [31:0] product_32;
 
delayUnit delay_reg (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(data_in),
.delay_out(delay_out)
);
   assign product_32 = data_in * step_size;
   assign product_16 = product_32[26:11];
   assign weight_in = (reset == 1'b1) ? 16'h0000 : (product_16 + weight_out);
 
delayUnit data_reg  (
.clk(clk),
.reset(reset),
.enable(enable),
.data_in(weight_in),
.delay_out(weight_out)
);
assign tap_out = weight_out * data_in;
endmodule
///////////////////////////////////////////////////////////////////////////////////////////////////////////
module delayUnit(clk,reset,enable,data_in,delay_out);
input clk,reset,enable;
input [15:0] data_in;
output [15:0] delay_out;
reg [15:0] delay_out;
 
always @(posedge clk or posedge reset) 
begin
if (reset ==1'b1) 
begin
delay_out <= 0;
end
else 
begin
if (enable == 1'b1) 
begin
delay_out <= data_in;
end
end
end
endmodule
///////////////////////////////////////////////////////////////////////////////////////////////////////////
 
       测试代码:
`timescale 1 ns / 1 ns  //need to run 10 us
module lms_tb();
reg  clk,enable,reset;
reg  [15:0] data_in,desired_in,step_size,sine_display;
reg  [15:0] sine[0:999],noise[0:999];
wire [15:0] error_out;
integer i;
parameter CYCLE = 10;
 
lms TestUnit   (.clk(clk),
.data_in(data_in),
.desired_in(desired_in),
.enable(enable),
.reset(reset),
.step_size(step_size),
.error_out(error_out)
);
always #(CYCLE/2) clk = ~clk;
initial begin
clk = 1'b0;
reset = 1'b0;
enable = 1'b1;
#(CYCLE) reset = 1'b1;
#(CYCLE) reset = 1'b0;
end
initial begin
step_size = 16'h0010; //Q4.11 so u=0.0078
$readmemh("sine.hex",sine);
$readmemh("noise.hex",noise);
for(i=0;i<1000;i=i+1) begin
#(CYCLE) data_in = noise;
 sine_display = sine;
 desired_in = sine+noise;
end
end
endmodule
 
 
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
21
关闭 站长推荐上一条 /3 下一条