当前位置:   article > 正文

基于FPGA的LMS自适应滤波器_fpga lms自适应滤波器

fpga lms自适应滤波器

在传统的数字滤波器设计中,最重要的就是滤波器的系数。不管是用matlab的fdatool工具实现,还是用别的滤波器系数生成工具产生该系数,过程都是比较麻烦的。而且生成滤波器系数以后,滤波器的幅频响应,相频响应都已经被固定,如果要修改滤波器的参数,必须要从重新对滤波器的系数进行计算和量化并生成coe文件,才可以更改滤波器。所以基于以上原因,可以设计一个自适应的数字滤波器 ,通过计算输出信号和期望信号的误差来进行对滤波器系数的更新。

下面简单介绍一下系数更新算法:

 从上面的公式我们可以看出,下一时刻的滤波器系数是上一个时刻的滤波器系数加步长因子(u)与误差和输入信号的乘积。(步长因子决定了滤波器的收敛情况,通常情况下,步长因子为输入信号的自相关矩阵的特征值分之2)

自适应滤波器的matlab仿真:

下面是对于LMS函数的实现:

  1. function [w,e,yn] = my_LMS(xn,dn)
  2. % 输入:
  3. % xn 输入信号
  4. % dn 理想信号
  5. % L 迭代次数
  6. % k 滤波器的阶数
  7. % 输出:
  8. % w 滤波器的系数矩阵 大小为 k×L 每一列代表一次迭代后的系数
  9. % e 误差信号 大小为 L×1 每一行代表一次迭代后产生的误差
  10. % yn 滤波器的输出信号
  11. %% 参数配置
  12. k=128; %滤波器阶数
  13. L=length(xn); %迭代次数=输入信号长度
  14. %% 初始化
  15. yn=zeros(1,L); %初始化滤波输出信号
  16. yn(1:k)=xn(1:k); %初始化输出信号前k位数据,保证
  17. w=zeros(1,k); %初始化权重
  18. e=zeros(1,L); %初始化误差
  19. %% 求收敛常数u
  20. fe = max(eig(xn*xn.'));%求解输入xn的自相关矩阵的最大特征值fe,A = eig(B),意为将矩阵B的特征值组成向量A
  21. u = 2*(1/fe);
  22. %% 迭代更新滤波器的参数
  23. for i=(k+1):L %要保证输入延时后的信号有效,所以实际的迭代次数只有(L-k)次,
  24. XN=xn((i-k+1):(i)); %将输入信号延迟,使得滤波器的每个抽头都有输入
  25. yn(i)=w*XN'; %计算出滤波器的输出
  26. e(i)=dn(i)-yn(i); %得出误差信号
  27. w=w+u*e(i)*XN; %迭代更新滤波器的系数
  28. end
  29. end

下面便调用上述函数:

要将所生成的正弦波和加噪后的正弦波量化,在后面的vivado中会用到该量化好的数据。

(要注意加噪后的量化信号,有的时候会出现错误(在vivado中无法读取),所以在生成的txt文件中自行修改错误的数据)

  1. clear;
  2. clc;
  3. close all;
  4. L=1024; %信号长度
  5. a=1; %原始信号幅度
  6. t=1:L;
  7. dn=a*sin(0.05*pi*t);%原始正弦信号
  8. subplot(411);plot(dn);axis([0,L,-a-1,a+1]);
  9. %fidc= fopen('C:/Users/Lenovo/Desktop/LMS/matlab/sin_data.txt','wt'); //将正弦波信号量化
  10. %for x = 1 : L
  11. % fprintf(fidc,'%x\n',round((dn+2.12)*58));
  12. %end
  13. %fclose(fidc);
  14. xn=awgn(dn,1); %添加信噪比5dB的白高斯噪声
  15. subplot(412);plot(xn);axis([0,L,-a-1,a+1]);
  16. title('信号加高斯白噪声后的时域波形');
  17. fidc= fopen('C:/Users/Lenovo/Desktop/LMS/matlab/add_noise_data.txt','wt'); //将加噪正弦波量化
  18. for x = 1 : L
  19. fprintf(fidc,'%x\n',round((xn+2.12)*58));
  20. end
  21. fclose(fidc);
  22. [w,e,yn] = my_LMS(xn,dn);%调用滤波算法
  23. subplot(413);plot(yn);axis([0,L,-a-1,a+1]);
  24. title('LMS算法自适应滤波后的输出时域波形');
  25. subplot(414);plot(e);axis([0,L,-a-1,a+1]);
  26. title('LMS算法自适应滤波后与原始信号误差');

matlab仿真波形:

 从上面的图我们可以看出该自适应滤波器已经完成了滤波。下面开始滤波器的fpga实现:

顶层模块:

  1. module lms_top(
  2. input clk_i,
  3. input rst_n_i,
  4. input signed [15:0] data_in, //输入待滤波数据
  5. input signed [15:0] data_ref, //参考数据
  6. output signed [15:0] error_o, //误差
  7. output signed [31:0] data_o //输出数据
  8. );
  9. wire signed [15:0] coef1;
  10. wire signed [15:0] coef2;
  11. wire signed [15:0] coef3;
  12. wire signed [15:0] coef4;
  13. wire signed [15:0] coef5;
  14. wire signed [15:0] coef6;
  15. wire signed [15:0] coef7;
  16. wire signed [15:0] coef8;
  17. wire signed [15:0] coef9;
  18. fir fir_inst (
  19. .clk_i (clk_i ),
  20. .rst_n_i (rst_n_i ),
  21. .data_in (data_in ),
  22. .coef1 (coef1 ),
  23. .coef2 (coef2 ),
  24. .coef3 (coef3 ),
  25. .coef4 (coef4 ),
  26. .coef5 (coef5 ),
  27. .coef6 (coef6 ),
  28. .coef7 (coef7 ),
  29. .coef8 (coef8 ),
  30. .coef9 (coef9 ),
  31. .data_o(data_o)
  32. );
  33. error_calcu error_calcu_inst (
  34. .clk_i (clk_i ),
  35. .rst_n_i (rst_n_i ),
  36. .data_in (data_o ), //data_in data_o
  37. .data_ref (data_ref ),
  38. .error_o ( error_o)
  39. );
  40. coef_update coef_update_inst(
  41. .clk_i (clk_i ),
  42. .rst_n_i (rst_n_i ),
  43. .error_o (error_o ),
  44. .data_in (data_in ),
  45. .coef1 (coef1 ),
  46. .coef2 (coef2 ),
  47. .coef3 (coef3 ),
  48. .coef4 (coef4 ),
  49. .coef5 (coef5 ),
  50. .coef6 (coef6 ),
  51. .coef7 (coef7 ),
  52. .coef8 (coef8 ),
  53. .coef9 (coef9 )
  54. );
  55. endmodule

FIR滤波器模块:

  1. module fir(
  2. input clk_i,
  3. input rst_n_i,
  4. input signed [15:0] data_in, //fir_i,
  5. input signed [15:0] coef1, //权值
  6. input signed [15:0] coef2,
  7. input signed [15:0] coef3,
  8. input signed [15:0] coef4,
  9. input signed [15:0] coef5,
  10. input signed [15:0] coef6,
  11. input signed [15:0] coef7,
  12. input signed [15:0] coef8,
  13. input signed [15:0] coef9,
  14. output reg [31:0] data_o //fir_o
  15. );
  16. reg[15:0] delay_pipeline1 ;//延时模块
  17. reg[15:0] delay_pipeline2 ;
  18. reg[15:0] delay_pipeline3 ;
  19. reg[15:0] delay_pipeline4 ;
  20. reg[15:0] delay_pipeline5 ;
  21. reg[15:0] delay_pipeline6 ;
  22. reg[15:0] delay_pipeline7 ;
  23. reg[15:0] delay_pipeline8 ;
  24. reg[15:0] delay_pipeline9 ;
  25. /*第一级流水,将输入信号进行延时,每到来一个时钟信号,
  26. 便将输入信号保存到delay_pipelin1中,然后将剩下的依次移动一位。*/
  27. always@(posedge clk_i or negedge rst_n_i)
  28. if(rst_n_i == 1'b0)
  29. begin
  30. delay_pipeline1 <= 16'b0 ;
  31. delay_pipeline2 <= 16'b0 ;
  32. delay_pipeline3 <= 16'b0 ;
  33. delay_pipeline4 <= 16'b0 ;
  34. delay_pipeline5 <= 16'b0 ;
  35. delay_pipeline6 <= 16'b0 ;
  36. delay_pipeline7 <= 16'b0 ;
  37. delay_pipeline8 <= 16'b0 ;
  38. delay_pipeline9 <= 16'b0 ;
  39. end
  40. else begin
  41. delay_pipeline1 <= data_in ;
  42. delay_pipeline2 <= delay_pipeline1 ;
  43. delay_pipeline3 <= delay_pipeline2 ;
  44. delay_pipeline4 <= delay_pipeline3 ;
  45. delay_pipeline5 <= delay_pipeline4 ;
  46. delay_pipeline6 <= delay_pipeline5 ;
  47. delay_pipeline7 <= delay_pipeline6 ;
  48. delay_pipeline8 <=delay_pipeline7 ;
  49. delay_pipeline9<= delay_pipeline8 ;
  50. end
  51. //乘积结果保存寄存器
  52. reg signed [31:0] multi_data1 ;
  53. reg signed [31:0] multi_data2 ;
  54. reg signed [31:0] multi_data3 ;
  55. reg signed [31:0] multi_data4 ;
  56. reg signed [31:0] multi_data5 ;
  57. reg signed [31:0] multi_data6 ;
  58. reg signed [31:0] multi_data7 ;
  59. reg signed [31:0] multi_data8 ;
  60. reg signed [31:0] multi_data9 ;
  61. //x(n) * h(n-k)
  62. always@(posedge clk_i or negedge rst_n_i)
  63. if(rst_n_i == 1'b0)
  64. begin
  65. multi_data1 <= 32'b0 ;
  66. end
  67. else begin
  68. multi_data1 <= delay_pipeline1 * coef1 ;
  69. end
  70. //x(1) * h(1)
  71. always@(posedge clk_i or negedge rst_n_i)
  72. if(rst_n_i == 1'b0)
  73. multi_data2 <= 32'b0 ;
  74. else
  75. multi_data2 <= delay_pipeline2 * coef2 ;
  76. //x(2) * h(2)
  77. always@(posedge clk_i or negedge rst_n_i)
  78. if(rst_n_i == 1'b0)
  79. multi_data3 <= 32'b0 ;
  80. else
  81. multi_data3 <= delay_pipeline3 * coef3 ;
  82. //x(3) * h(3)
  83. always@(posedge clk_i or negedge rst_n_i)
  84. if(rst_n_i == 1'b0)
  85. multi_data4 <= 32'b0 ;
  86. else
  87. multi_data4 <= delay_pipeline4 * coef4 ;
  88. //x(4) * h(4)
  89. always@(posedge clk_i or negedge rst_n_i)
  90. if(rst_n_i == 1'b0)
  91. multi_data5 <= 32'b0 ;
  92. else
  93. multi_data5 <= delay_pipeline5 * coef5 ;
  94. //x(5) * h(5)
  95. always@(posedge clk_i or negedge rst_n_i)
  96. if(rst_n_i == 1'b0)
  97. multi_data6 <= 32'b0 ;
  98. else
  99. multi_data6 <= delay_pipeline6 * coef6 ;
  100. //x(6) * h(6)
  101. always@(posedge clk_i or negedge rst_n_i)
  102. if(rst_n_i == 1'b0)
  103. multi_data7 <= 32'b0 ;
  104. else
  105. multi_data7 <= delay_pipeline7 * coef7;
  106. //x(7) * h(7)
  107. always@(posedge clk_i or negedge rst_n_i)
  108. if(rst_n_i == 1'b0)
  109. multi_data8 <= 32'b0 ;
  110. else
  111. multi_data8 <= delay_pipeline8 * coef8;
  112. //x(8) * h(8)
  113. always@(posedge clk_i or negedge rst_n_i)
  114. if(rst_n_i == 1'b0)
  115. multi_data9 <= 32'b0 ;
  116. else
  117. multi_data9 <= delay_pipeline9 * coef9 ;
  118. //将乘积累加,累加的结果就是滤波后的信号
  119. always@(posedge clk_i or negedge rst_n_i)
  120. if(rst_n_i == 1'b0)
  121. data_o <= 32'b0;
  122. else
  123. data_o <= multi_data1 + multi_data2 + multi_data3 +
  124. multi_data4 +multi_data5 + multi_data6 + multi_data7 +
  125. multi_data8 + multi_data9 ;
  126. endmodule

误差计算模块:

  1. module error_calcu(
  2. input clk_i,
  3. input rst_n_i,
  4. input signed [31:0] data_in, //滤波完成数据32
  5. input signed [15:0] data_ref, //参考数据
  6. output signed [15:0] error_o //误差输出
  7. );
  8. wire signed [15:0] error;
  9. //延时寄存参考数据
  10. reg signed [15:0] data_shift1;
  11. reg signed [15:0] data_shift2;
  12. reg signed [15:0] data_shift3;
  13. reg signed [15:0] data_shift4;
  14. reg signed [15:0] data_shift5;
  15. reg signed [15:0] data_shift6;
  16. reg signed [15:0] data_shift7;
  17. reg signed [15:0] data_shift8;
  18. reg signed [15:0] data_shift9;
  19. always @(posedge clk_i or negedge rst_n_i) begin
  20. if(rst_n_i == 1'b0)
  21. begin
  22. data_shift1 <= 16'd0;
  23. data_shift2 <= 16'd0;
  24. data_shift3 <= 16'd0;
  25. data_shift4 <= 16'd0;
  26. data_shift5 <= 16'd0;
  27. data_shift6 <= 16'd0;
  28. data_shift7 <= 16'd0;
  29. data_shift8 <= 16'd0;
  30. data_shift9 <= 16'd0;
  31. end
  32. else begin
  33. data_shift1 <= data_ref ;
  34. data_shift2 <= data_shift1;
  35. data_shift3 <= data_shift2;
  36. data_shift4 <= data_shift3;
  37. data_shift5 <= data_shift4;
  38. data_shift6 <= data_shift5;
  39. data_shift7 <= data_shift6;
  40. data_shift8 <= data_shift7;
  41. data_shift9 <= data_shift8;
  42. end
  43. end
  44. assign error = data_in - data_shift9;
  45. assign error_o = error;
  46. endmodule

系数更新模块:

  1. module coef_update( //系数更新模块
  2. input clk_i,
  3. input rst_n_i,
  4. input signed [15:0] error_o, //误差
  5. input signed [15:0] data_in, //待滤波数据
  6. //权值更新
  7. output reg [15:0] coef1,
  8. output reg [15:0] coef2,
  9. output reg [15:0] coef3,
  10. output reg [15:0] coef4,
  11. output reg [15:0] coef5,
  12. output reg [15:0] coef6,
  13. output reg [15:0] coef7,
  14. output reg [15:0] coef8,
  15. output reg [15:0] coef9
  16. );
  17. reg signed [15:0] mu; //遗忘因子(步长)
  18. reg [3:0] cnt; //计数器(计算一组滤波系数)
  19. reg [3:0] cnt_flag; //计数器标志信号
  20. reg cnt_flag_en; //计算使能信号
  21. //延时寄存输入数据
  22. reg signed [15:0] data_shift1;
  23. reg signed [15:0] data_shift2;
  24. reg signed [15:0] data_shift3;
  25. reg signed [15:0] data_shift4;
  26. reg signed [15:0] data_shift5;
  27. reg signed [15:0] data_shift6;
  28. reg signed [15:0] data_shift7;
  29. reg signed [15:0] data_shift8;
  30. reg signed [15:0] data_shift9;
  31. always @(posedge clk_i or negedge rst_n_i) begin
  32. if(rst_n_i == 1'b0)begin
  33. data_shift1 <= 16'd0;
  34. data_shift2 <= 16'd0;
  35. data_shift3 <= 16'd0;
  36. data_shift4 <= 16'd0;
  37. data_shift5 <= 16'd0;
  38. data_shift6 <= 16'd0;
  39. data_shift7 <= 16'd0;
  40. data_shift8 <= 16'd0;
  41. data_shift9 <= 16'd0;
  42. mu <= 16'd3; //步长不知道是多少,随便写了一个;
  43. end
  44. else begin
  45. data_shift1 <= data_in ;
  46. data_shift2 <= data_shift1;
  47. data_shift3 <= data_shift2;
  48. data_shift4 <= data_shift3;
  49. data_shift5 <= data_shift4;
  50. data_shift6 <= data_shift5;
  51. data_shift7 <= data_shift6;
  52. data_shift8 <= data_shift7;
  53. data_shift9 <= data_shift8;
  54. end
  55. end
  56. //权值更新
  57. //mu*error*data_in*2
  58. reg signed [15:0] coef1_reg;
  59. reg signed [15:0] coef2_reg;
  60. reg signed [15:0] coef3_reg;
  61. reg signed [15:0] coef4_reg;
  62. reg signed [15:0] coef5_reg;
  63. reg signed [15:0] coef6_reg;
  64. reg signed [15:0] coef7_reg;
  65. reg signed [15:0] coef8_reg;
  66. reg signed [15:0] coef9_reg;
  67. always @(posedge clk_i or negedge rst_n_i)
  68. if(rst_n_i == 1'b0)
  69. cnt <= 4'b0;
  70. else if(cnt == 4'd13)
  71. cnt <= 4'b0;
  72. else
  73. cnt <= cnt + 1'b1;
  74. always @(posedge clk_i or negedge rst_n_i)
  75. if(rst_n_i == 1'b0)
  76. cnt_flag <= 1'b0;
  77. else if(cnt == 4'd13)
  78. cnt_flag <= 1'b1;
  79. else
  80. cnt_flag <= 1'b0;
  81. always @(posedge clk_i or negedge rst_n_i)
  82. if(rst_n_i == 1'b0)
  83. cnt_flag_en <= 1'b0;
  84. else if(cnt_flag == 1'b1)
  85. cnt_flag_en <= 1'b1;
  86. else
  87. cnt_flag_en <= cnt_flag_en;
  88. always@(posedge clk_i or negedge rst_n_i)
  89. begin
  90. if(rst_n_i == 1'b0)
  91. begin
  92. coef1_reg <= 16'd0;//2
  93. coef2_reg <= 16'd0;
  94. coef3_reg <= 16'd0;
  95. coef4_reg <= 16'd0;
  96. coef5_reg <= 16'd0;
  97. coef6_reg <= 16'd0;
  98. coef7_reg <= 16'd0;
  99. coef8_reg <= 16'd0;
  100. coef9_reg <= 16'd0;
  101. end
  102. else begin
  103. coef1_reg <= (mu * error_o * data_shift1);
  104. coef2_reg <= (mu * error_o * data_shift2);
  105. coef3_reg <= (mu * error_o * data_shift3);
  106. coef4_reg <= (mu * error_o * data_shift4);
  107. coef5_reg <= (mu * error_o * data_shift5);
  108. coef6_reg <= (mu * error_o * data_shift6);
  109. coef7_reg <= (mu * error_o * data_shift7);
  110. coef8_reg <= (mu * error_o * data_shift8);
  111. coef9_reg <= (mu * error_o * data_shift9);
  112. end
  113. end
  114. always @(posedge clk_i or negedge rst_n_i)
  115. if(rst_n_i == 1'b0)
  116. begin
  117. coef1 <= 16'd0;//0
  118. coef2 <= 16'd0;
  119. coef3 <= 16'd0;
  120. coef4 <= 16'd0;
  121. coef5 <= 16'd0;
  122. coef6 <= 16'd0;
  123. coef7 <= 16'd0;
  124. coef8 <= 16'd0;
  125. coef9 <= 16'd0;
  126. end
  127. else if(cnt_flag_en == 1'b1)
  128. begin
  129. coef1 <= coef1 + coef1_reg;
  130. coef2 <= coef2 + coef2_reg;
  131. coef3 <= coef3 + coef3_reg;
  132. coef4 <= coef4 + coef4_reg;
  133. coef5 <= coef5 + coef5_reg;
  134. coef6 <= coef6 + coef6_reg;
  135. coef7 <= coef7 + coef7_reg;
  136. coef8 <= coef8 + coef8_reg;
  137. coef9 <= coef9 + coef9_reg;
  138. end
  139. endmodule

testbench:

  1. module tb_lms(
  2. );
  3. reg clk_i;
  4. reg rst_n_i;
  5. reg [15:0] data_in;
  6. reg [15:0] data_ref;
  7. wire [15:0] error_o;
  8. wire [31:0] data_o;
  9. reg [15:0] mem1[1:4096]; //设计一个rom放读入的数据
  10. reg [15:0] mem2[1:4096];
  11. reg [12:0] i;
  12. //例化FIR滤波器
  13. lms_top lms_top_inst(
  14. .clk_i(clk_i),
  15. .rst_n_i(rst_n_i),
  16. .data_in(data_in), //输入待滤波数据
  17. .data_ref(data_ref), //参考数据
  18. .error_o(error_o), //误差
  19. .data_o(data_o) //输出数据
  20. );
  21. initial
  22. begin
  23. $readmemh("C:/Users/Lenovo/Desktop/LMS/matlab/add_noise_data.txt",mem1);//将待滤波信号读入mem
  24. $readmemh("C:/Users/Lenovo/Desktop/LMS/matlab/sin_data.txt",mem2);
  25. rst_n_i= 0;
  26. clk_i= 0;
  27. #50;rst_n_i= 1;
  28. #50000;
  29. $stop;
  30. end
  31. initial
  32. forever
  33. #50 clk_i = ~clk_i;//时钟生成
  34. always@(posedge clk_i or negedge rst_n_i)
  35. if(!rst_n_i)
  36. data_in <= 16'b0 ;
  37. else
  38. data_in <= mem1[i]; //读入数据
  39. always@(posedge clk_i or negedge rst_n_i)
  40. if(!rst_n_i)
  41. data_ref <= 16'b0 ;
  42. else
  43. data_ref <= mem2[i]; //读入数据
  44. always@(posedge clk_i or negedge rst_n_i)
  45. if(!rst_n_i)
  46. i <= 12'd0;
  47. else
  48. i <= i + 1'd1;
  49. endmodule

整体RTL视图:

仿真:

 在这里我们可以看到data_in信号经过滤波器后,输出的data_o和期望信号data_ref的波形(已近很接近了),为什么输出不是一个完美的正弦波,其原因如下:1.步长因子。(在FPGA实现中我都步长因子设定为常数3)2.仿真时间(由于fpga的仿真时间一般都是以ns为单位的,滤波器的系数还没有迭代出一个完美系数)

(以上就是全部了,希望大佬们的指正。)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/787187
推荐阅读
相关标签
  

闽ICP备14008679号