赞
踩
在传统的数字滤波器设计中,最重要的就是滤波器的系数。不管是用matlab的fdatool工具实现,还是用别的滤波器系数生成工具产生该系数,过程都是比较麻烦的。而且生成滤波器系数以后,滤波器的幅频响应,相频响应都已经被固定,如果要修改滤波器的参数,必须要从重新对滤波器的系数进行计算和量化并生成coe文件,才可以更改滤波器。所以基于以上原因,可以设计一个自适应的数字滤波器 ,通过计算输出信号和期望信号的误差来进行对滤波器系数的更新。
下面简单介绍一下系数更新算法:
从上面的公式我们可以看出,下一时刻的滤波器系数是上一个时刻的滤波器系数加步长因子(u)与误差和输入信号的乘积。(步长因子决定了滤波器的收敛情况,通常情况下,步长因子为输入信号的自相关矩阵的特征值分之2)
自适应滤波器的matlab仿真:
下面是对于LMS函数的实现:
- function [w,e,yn] = my_LMS(xn,dn)
-
- % 输入:
- % xn 输入信号
- % dn 理想信号
- % L 迭代次数
- % k 滤波器的阶数
- % 输出:
- % w 滤波器的系数矩阵 大小为 k×L 每一列代表一次迭代后的系数
- % e 误差信号 大小为 L×1 每一行代表一次迭代后产生的误差
- % yn 滤波器的输出信号
-
- %% 参数配置
- k=128; %滤波器阶数
- L=length(xn); %迭代次数=输入信号长度
-
- %% 初始化
- yn=zeros(1,L); %初始化滤波输出信号
- yn(1:k)=xn(1:k); %初始化输出信号前k位数据,保证
- w=zeros(1,k); %初始化权重
- e=zeros(1,L); %初始化误差
-
- %% 求收敛常数u
- fe = max(eig(xn*xn.'));%求解输入xn的自相关矩阵的最大特征值fe,A = eig(B),意为将矩阵B的特征值组成向量A
- u = 2*(1/fe);
-
- %% 迭代更新滤波器的参数
- for i=(k+1):L %要保证输入延时后的信号有效,所以实际的迭代次数只有(L-k)次,
- XN=xn((i-k+1):(i)); %将输入信号延迟,使得滤波器的每个抽头都有输入
- yn(i)=w*XN'; %计算出滤波器的输出
- e(i)=dn(i)-yn(i); %得出误差信号
- w=w+u*e(i)*XN; %迭代更新滤波器的系数
- end
-
- end

下面便调用上述函数:
要将所生成的正弦波和加噪后的正弦波量化,在后面的vivado中会用到该量化好的数据。
(要注意加噪后的量化信号,有的时候会出现错误(在vivado中无法读取),所以在生成的txt文件中自行修改错误的数据)
- clear;
- clc;
- close all;
-
- L=1024; %信号长度
- a=1; %原始信号幅度
- t=1:L;
- dn=a*sin(0.05*pi*t);%原始正弦信号
- subplot(411);plot(dn);axis([0,L,-a-1,a+1]);
- %fidc= fopen('C:/Users/Lenovo/Desktop/LMS/matlab/sin_data.txt','wt'); //将正弦波信号量化
- %for x = 1 : L
- % fprintf(fidc,'%x\n',round((dn+2.12)*58));
- %end
- %fclose(fidc);
-
- xn=awgn(dn,1); %添加信噪比5dB的白高斯噪声
-
- subplot(412);plot(xn);axis([0,L,-a-1,a+1]);
- title('信号加高斯白噪声后的时域波形');
- fidc= fopen('C:/Users/Lenovo/Desktop/LMS/matlab/add_noise_data.txt','wt'); //将加噪正弦波量化
- for x = 1 : L
- fprintf(fidc,'%x\n',round((xn+2.12)*58));
- end
- fclose(fidc);
-
- [w,e,yn] = my_LMS(xn,dn);%调用滤波算法
-
- subplot(413);plot(yn);axis([0,L,-a-1,a+1]);
- title('LMS算法自适应滤波后的输出时域波形');
-
- subplot(414);plot(e);axis([0,L,-a-1,a+1]);
- title('LMS算法自适应滤波后与原始信号误差');

matlab仿真波形:
从上面的图我们可以看出该自适应滤波器已经完成了滤波。下面开始滤波器的fpga实现:
顶层模块:
- module lms_top(
- input clk_i,
- input rst_n_i,
- input signed [15:0] data_in, //输入待滤波数据
- input signed [15:0] data_ref, //参考数据
- output signed [15:0] error_o, //误差
- output signed [31:0] data_o //输出数据
- );
-
- wire signed [15:0] coef1;
- wire signed [15:0] coef2;
- wire signed [15:0] coef3;
- wire signed [15:0] coef4;
- wire signed [15:0] coef5;
- wire signed [15:0] coef6;
- wire signed [15:0] coef7;
- wire signed [15:0] coef8;
- wire signed [15:0] coef9;
-
- fir fir_inst (
- .clk_i (clk_i ),
- .rst_n_i (rst_n_i ),
- .data_in (data_in ),
- .coef1 (coef1 ),
- .coef2 (coef2 ),
- .coef3 (coef3 ),
- .coef4 (coef4 ),
- .coef5 (coef5 ),
- .coef6 (coef6 ),
- .coef7 (coef7 ),
- .coef8 (coef8 ),
- .coef9 (coef9 ),
- .data_o(data_o)
- );
-
- error_calcu error_calcu_inst (
- .clk_i (clk_i ),
- .rst_n_i (rst_n_i ),
- .data_in (data_o ), //data_in data_o
- .data_ref (data_ref ),
- .error_o ( error_o)
- );
-
- coef_update coef_update_inst(
- .clk_i (clk_i ),
- .rst_n_i (rst_n_i ),
- .error_o (error_o ),
- .data_in (data_in ),
- .coef1 (coef1 ),
- .coef2 (coef2 ),
- .coef3 (coef3 ),
- .coef4 (coef4 ),
- .coef5 (coef5 ),
- .coef6 (coef6 ),
- .coef7 (coef7 ),
- .coef8 (coef8 ),
- .coef9 (coef9 )
- );
-
- endmodule

FIR滤波器模块:
- module fir(
- input clk_i,
- input rst_n_i,
- input signed [15:0] data_in, //fir_i,
-
- input signed [15:0] coef1, //权值
- input signed [15:0] coef2,
- input signed [15:0] coef3,
- input signed [15:0] coef4,
- input signed [15:0] coef5,
- input signed [15:0] coef6,
- input signed [15:0] coef7,
- input signed [15:0] coef8,
- input signed [15:0] coef9,
-
- output reg [31:0] data_o //fir_o
- );
-
-
- reg[15:0] delay_pipeline1 ;//延时模块
- reg[15:0] delay_pipeline2 ;
- reg[15:0] delay_pipeline3 ;
- reg[15:0] delay_pipeline4 ;
- reg[15:0] delay_pipeline5 ;
- reg[15:0] delay_pipeline6 ;
- reg[15:0] delay_pipeline7 ;
- reg[15:0] delay_pipeline8 ;
- reg[15:0] delay_pipeline9 ;
- /*第一级流水,将输入信号进行延时,每到来一个时钟信号,
- 便将输入信号保存到delay_pipelin1中,然后将剩下的依次移动一位。*/
- always@(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- begin
- delay_pipeline1 <= 16'b0 ;
- delay_pipeline2 <= 16'b0 ;
- delay_pipeline3 <= 16'b0 ;
- delay_pipeline4 <= 16'b0 ;
- delay_pipeline5 <= 16'b0 ;
- delay_pipeline6 <= 16'b0 ;
- delay_pipeline7 <= 16'b0 ;
- delay_pipeline8 <= 16'b0 ;
- delay_pipeline9 <= 16'b0 ;
- end
- else begin
- delay_pipeline1 <= data_in ;
- delay_pipeline2 <= delay_pipeline1 ;
- delay_pipeline3 <= delay_pipeline2 ;
- delay_pipeline4 <= delay_pipeline3 ;
- delay_pipeline5 <= delay_pipeline4 ;
- delay_pipeline6 <= delay_pipeline5 ;
- delay_pipeline7 <= delay_pipeline6 ;
- delay_pipeline8 <=delay_pipeline7 ;
- delay_pipeline9<= delay_pipeline8 ;
- end
- //乘积结果保存寄存器
- reg signed [31:0] multi_data1 ;
- reg signed [31:0] multi_data2 ;
- reg signed [31:0] multi_data3 ;
- reg signed [31:0] multi_data4 ;
- reg signed [31:0] multi_data5 ;
- reg signed [31:0] multi_data6 ;
- reg signed [31:0] multi_data7 ;
- reg signed [31:0] multi_data8 ;
- reg signed [31:0] multi_data9 ;
-
- //x(n) * h(n-k)
- always@(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- begin
- multi_data1 <= 32'b0 ;
- end
- else begin
- multi_data1 <= delay_pipeline1 * coef1 ;
- end
- //x(1) * h(1)
- always@(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- multi_data2 <= 32'b0 ;
- else
- multi_data2 <= delay_pipeline2 * coef2 ;
- //x(2) * h(2)
- always@(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- multi_data3 <= 32'b0 ;
- else
- multi_data3 <= delay_pipeline3 * coef3 ;
- //x(3) * h(3)
- always@(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- multi_data4 <= 32'b0 ;
- else
- multi_data4 <= delay_pipeline4 * coef4 ;
- //x(4) * h(4)
- always@(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- multi_data5 <= 32'b0 ;
- else
- multi_data5 <= delay_pipeline5 * coef5 ;
- //x(5) * h(5)
- always@(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- multi_data6 <= 32'b0 ;
- else
- multi_data6 <= delay_pipeline6 * coef6 ;
- //x(6) * h(6)
- always@(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- multi_data7 <= 32'b0 ;
- else
- multi_data7 <= delay_pipeline7 * coef7;
- //x(7) * h(7)
- always@(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- multi_data8 <= 32'b0 ;
- else
- multi_data8 <= delay_pipeline8 * coef8;
- //x(8) * h(8)
- always@(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- multi_data9 <= 32'b0 ;
- else
- multi_data9 <= delay_pipeline9 * coef9 ;
- //将乘积累加,累加的结果就是滤波后的信号
- always@(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- data_o <= 32'b0;
- else
- data_o <= multi_data1 + multi_data2 + multi_data3 +
- multi_data4 +multi_data5 + multi_data6 + multi_data7 +
- multi_data8 + multi_data9 ;
- endmodule

误差计算模块:
- module error_calcu(
- input clk_i,
- input rst_n_i,
- input signed [31:0] data_in, //滤波完成数据32
- input signed [15:0] data_ref, //参考数据
- output signed [15:0] error_o //误差输出
- );
-
- wire signed [15:0] error;
-
- //延时寄存参考数据
- reg signed [15:0] data_shift1;
- reg signed [15:0] data_shift2;
- reg signed [15:0] data_shift3;
- reg signed [15:0] data_shift4;
- reg signed [15:0] data_shift5;
- reg signed [15:0] data_shift6;
- reg signed [15:0] data_shift7;
- reg signed [15:0] data_shift8;
- reg signed [15:0] data_shift9;
-
- always @(posedge clk_i or negedge rst_n_i) begin
- if(rst_n_i == 1'b0)
- begin
- data_shift1 <= 16'd0;
- data_shift2 <= 16'd0;
- data_shift3 <= 16'd0;
- data_shift4 <= 16'd0;
- data_shift5 <= 16'd0;
- data_shift6 <= 16'd0;
- data_shift7 <= 16'd0;
- data_shift8 <= 16'd0;
- data_shift9 <= 16'd0;
- end
- else begin
- data_shift1 <= data_ref ;
- data_shift2 <= data_shift1;
- data_shift3 <= data_shift2;
- data_shift4 <= data_shift3;
- data_shift5 <= data_shift4;
- data_shift6 <= data_shift5;
- data_shift7 <= data_shift6;
- data_shift8 <= data_shift7;
- data_shift9 <= data_shift8;
- end
- end
-
- assign error = data_in - data_shift9;
- assign error_o = error;
-
- endmodule

系数更新模块:
- module coef_update( //系数更新模块
- input clk_i,
- input rst_n_i,
- input signed [15:0] error_o, //误差
- input signed [15:0] data_in, //待滤波数据
-
- //权值更新
- output reg [15:0] coef1,
- output reg [15:0] coef2,
- output reg [15:0] coef3,
- output reg [15:0] coef4,
- output reg [15:0] coef5,
- output reg [15:0] coef6,
- output reg [15:0] coef7,
- output reg [15:0] coef8,
- output reg [15:0] coef9
- );
-
- reg signed [15:0] mu; //遗忘因子(步长)
- reg [3:0] cnt; //计数器(计算一组滤波系数)
- reg [3:0] cnt_flag; //计数器标志信号
- reg cnt_flag_en; //计算使能信号
-
- //延时寄存输入数据
- reg signed [15:0] data_shift1;
- reg signed [15:0] data_shift2;
- reg signed [15:0] data_shift3;
- reg signed [15:0] data_shift4;
- reg signed [15:0] data_shift5;
- reg signed [15:0] data_shift6;
- reg signed [15:0] data_shift7;
- reg signed [15:0] data_shift8;
- reg signed [15:0] data_shift9;
-
- always @(posedge clk_i or negedge rst_n_i) begin
- if(rst_n_i == 1'b0)begin
- data_shift1 <= 16'd0;
- data_shift2 <= 16'd0;
- data_shift3 <= 16'd0;
- data_shift4 <= 16'd0;
- data_shift5 <= 16'd0;
- data_shift6 <= 16'd0;
- data_shift7 <= 16'd0;
- data_shift8 <= 16'd0;
- data_shift9 <= 16'd0;
- mu <= 16'd3; //步长不知道是多少,随便写了一个;
- end
- else begin
- data_shift1 <= data_in ;
- data_shift2 <= data_shift1;
- data_shift3 <= data_shift2;
- data_shift4 <= data_shift3;
- data_shift5 <= data_shift4;
- data_shift6 <= data_shift5;
- data_shift7 <= data_shift6;
- data_shift8 <= data_shift7;
- data_shift9 <= data_shift8;
- end
- end
- //权值更新
- //mu*error*data_in*2
- reg signed [15:0] coef1_reg;
- reg signed [15:0] coef2_reg;
- reg signed [15:0] coef3_reg;
- reg signed [15:0] coef4_reg;
- reg signed [15:0] coef5_reg;
- reg signed [15:0] coef6_reg;
- reg signed [15:0] coef7_reg;
- reg signed [15:0] coef8_reg;
- reg signed [15:0] coef9_reg;
-
- always @(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- cnt <= 4'b0;
- else if(cnt == 4'd13)
- cnt <= 4'b0;
- else
- cnt <= cnt + 1'b1;
-
- always @(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- cnt_flag <= 1'b0;
- else if(cnt == 4'd13)
- cnt_flag <= 1'b1;
- else
- cnt_flag <= 1'b0;
-
- always @(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- cnt_flag_en <= 1'b0;
- else if(cnt_flag == 1'b1)
- cnt_flag_en <= 1'b1;
- else
- cnt_flag_en <= cnt_flag_en;
-
- always@(posedge clk_i or negedge rst_n_i)
- begin
- if(rst_n_i == 1'b0)
- begin
- coef1_reg <= 16'd0;//2
- coef2_reg <= 16'd0;
- coef3_reg <= 16'd0;
- coef4_reg <= 16'd0;
- coef5_reg <= 16'd0;
- coef6_reg <= 16'd0;
- coef7_reg <= 16'd0;
- coef8_reg <= 16'd0;
- coef9_reg <= 16'd0;
- end
- else begin
- coef1_reg <= (mu * error_o * data_shift1);
- coef2_reg <= (mu * error_o * data_shift2);
- coef3_reg <= (mu * error_o * data_shift3);
- coef4_reg <= (mu * error_o * data_shift4);
- coef5_reg <= (mu * error_o * data_shift5);
- coef6_reg <= (mu * error_o * data_shift6);
- coef7_reg <= (mu * error_o * data_shift7);
- coef8_reg <= (mu * error_o * data_shift8);
- coef9_reg <= (mu * error_o * data_shift9);
- end
- end
- always @(posedge clk_i or negedge rst_n_i)
- if(rst_n_i == 1'b0)
- begin
- coef1 <= 16'd0;//0
- coef2 <= 16'd0;
- coef3 <= 16'd0;
- coef4 <= 16'd0;
- coef5 <= 16'd0;
- coef6 <= 16'd0;
- coef7 <= 16'd0;
- coef8 <= 16'd0;
- coef9 <= 16'd0;
- end
- else if(cnt_flag_en == 1'b1)
- begin
- coef1 <= coef1 + coef1_reg;
- coef2 <= coef2 + coef2_reg;
- coef3 <= coef3 + coef3_reg;
- coef4 <= coef4 + coef4_reg;
- coef5 <= coef5 + coef5_reg;
- coef6 <= coef6 + coef6_reg;
- coef7 <= coef7 + coef7_reg;
- coef8 <= coef8 + coef8_reg;
- coef9 <= coef9 + coef9_reg;
- end
-
- endmodule
-

testbench:
- module tb_lms(
- );
- reg clk_i;
- reg rst_n_i;
- reg [15:0] data_in;
- reg [15:0] data_ref;
- wire [15:0] error_o;
- wire [31:0] data_o;
- reg [15:0] mem1[1:4096]; //设计一个rom放读入的数据
- reg [15:0] mem2[1:4096];
- reg [12:0] i;
-
- //例化FIR滤波器
- lms_top lms_top_inst(
- .clk_i(clk_i),
- .rst_n_i(rst_n_i),
- .data_in(data_in), //输入待滤波数据
- .data_ref(data_ref), //参考数据
- .error_o(error_o), //误差
- .data_o(data_o) //输出数据
- );
- initial
- begin
- $readmemh("C:/Users/Lenovo/Desktop/LMS/matlab/add_noise_data.txt",mem1);//将待滤波信号读入mem
- $readmemh("C:/Users/Lenovo/Desktop/LMS/matlab/sin_data.txt",mem2);
- rst_n_i= 0;
- clk_i= 0;
- #50;rst_n_i= 1;
- #50000;
- $stop;
- end
-
- initial
- forever
- #50 clk_i = ~clk_i;//时钟生成
-
- always@(posedge clk_i or negedge rst_n_i)
- if(!rst_n_i)
- data_in <= 16'b0 ;
- else
- data_in <= mem1[i]; //读入数据
-
- always@(posedge clk_i or negedge rst_n_i)
- if(!rst_n_i)
- data_ref <= 16'b0 ;
- else
- data_ref <= mem2[i]; //读入数据
-
- always@(posedge clk_i or negedge rst_n_i)
- if(!rst_n_i)
- i <= 12'd0;
- else
- i <= i + 1'd1;
- endmodule

整体RTL视图:
仿真:
在这里我们可以看到data_in信号经过滤波器后,输出的data_o和期望信号data_ref的波形(已近很接近了),为什么输出不是一个完美的正弦波,其原因如下:1.步长因子。(在FPGA实现中我都步长因子设定为常数3)2.仿真时间(由于fpga的仿真时间一般都是以ns为单位的,滤波器的系数还没有迭代出一个完美系数)
(以上就是全部了,希望大佬们的指正。)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。