热度 21
2013-5-31 10:43
2019 次阅读|
0 个评论
最近在学习进行自适应FIR滤波器的设计,下面是参考别人的设计“基于LMS算法的自适应噪声抵消器”,稍作修改之后得到的。阶数n=8;算法步长u=0.0078;输入输出信号均为16位;滤波器最高32位。主要系统输入:环境噪声信号data_in(用高斯信号来模拟)、经过噪声叠加的正弦信号desired_in(线性叠加)、步长step_size;系统输出:经过滤波的正弦信号error_out、误差e_out、拟合抽头系数w_out。其中关于定标、截位、步长的取值等方面有些疑问,希望大家能提些宝贵意见。 自适应滤波的原理框图: 该设计的系统框图: 测试框架: ModelSim中的仿真波形: 经测试,除了μ=2^-7(即0.0078),滤波收敛效果较好的μ的取值范围:μ∈ 。 在实际设计中定标、截位和步长的取值很关键,在本次设计中,步长取μ=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 ; assign weight_in = (reset == 1'b1) ? 16'h0000 : (product_16 + weight_out); 关于系数每次更新累加,都截取噪声输入data_in与步长输入step_size相乘后32位乘积结果的 位。在LMS滤波器的顶层模块, assign product_32 = step_size * error_in; assign product_16 = product_32 ; 也都截取32位乘积结果的 位。 问题: 1. 截位为什么截取32位乘积结果的 位?是跟步长定标采用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 data_in,desired_in,step_size,sine_display; output signed error_out,e_out; output signed w_out; wire signed error_in,data_in_reg, desired_in_reg,product_16; wire signed product_32,LMSx8_sum_out; wire signed 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 ; 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 ; 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 data_in,step_size; input signed Sum_in; output signed Sum_out; output signed link_out; wire signed 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 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 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 = LMS_tap_1_weight_out; assign link_out = LMS_tap_2_weight_out; assign link_out = LMS_tap_3_weight_out; assign link_out = LMS_tap_4_weight_out; assign link_out = LMS_tap_5_weight_out; assign link_out = LMS_tap_6_weight_out; assign link_out = LMS_tap_7_weight_out; assign link_out = 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 data_in,step_size; output signed delay_out; output signed weight_out; output signed tap_out; wire signed weight_in,product_16; wire signed 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 ; 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 data_in; output delay_out; reg 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 data_in,desired_in,step_size,sine_display; reg sine ,noise ; wire 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;i1000;i=i+1) begin #(CYCLE) data_in = noise ; sine_display = sine ; desired_in = sine +noise ; end end endmodule