FPGA实现FIR滤波

10 篇文章 1 订阅
9 篇文章 1 订阅
本文详细介绍了FIR滤波器的工作原理,并提供了使用Verilog语言编写的FIR滤波器的源代码示例。通过步骤展示了如何在FPGA上设计和实现一个8位数据宽度的FIR滤波器,包括抽取系数的设置和数据缓存与处理过程。同时附有MATLAB测试代码,供读者理解和实践。
摘要由CSDN通过智能技术生成

FPGA实现FIR滤波

什么是FIR滤波?

FIR(Finite Impulse Response) Filter:有限冲激响应滤波器。
FIR滤波器这里就不赘述其原理了,晚上有很多解释的。我这里给两个我参考的,并且认为还不错的

  1. 一个视频教你理解两种数字滤波器,学数字信号处理必看

  2. FIR数字信号滤波器

FIR滤波器的verilog实现

源代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/05/10 10:23:52
// Design Name: 
// Module Name: FIR
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module FIR(
    input   clk,
    input   rst_n,
    input  [DATA_WIDTH:1] data_in,
    
    output reg [DATA_WIDTH + 8:1] filtered_data,
    output reg filtered_data_valid 
    );
//定义parameter
    parameter DATA_WIDTH = 8;   //数据位宽
    parameter b0 = 0;   //FIR抽头参数
    parameter b1 = 8;
    parameter b2 = 22;
    parameter b3 = 38;
    parameter b4 = 50;
    parameter b5 = 38;
    parameter b6 = 22;
    parameter b7 = 8;
    parameter b8 = 0;
//将数据缓存
    reg [DATA_WIDTH:1] data_reg [9:0];
    integer i,j;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (i = 0;i <=9 ;i = i + 1 ) begin
                data_reg[i] <= 0;
            end
        end
        else begin
            data_reg[0] <= data_in;
            for (j = 1; j <= 9 ;j = j + 1) begin
                data_reg[j] <= data_reg[j-1];
            end
        end
    end

//进行FIR处理
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            filtered_data <= 0;
            filtered_data_valid <= 0;
        end
        else begin
            filtered_data <= b0 * data_reg[0] + b1 * data_reg[1] + b2 * data_reg[2] + b3 * data_reg[3] + 
                             b4 * data_reg[4] + b5 * data_reg[5] + b6 * data_reg[6] + b7 * data_reg[7] + 
                             b8 * data_reg[8];
            filtered_data_valid <= 1;
        end
    end


endmodule

测试代码

MATLAB生成信号源
clc;
clear all;

s_p = 0:255; %正弦波一个周期的采样点
N = 2^8;
sin_data = sin(2*pi*s_p/N);

%生成噪声信号
y2=randn(1, N);%生成一个白噪声数组(白噪声的随机数范围是[-3,3]),数组长度为N
subplot(3,1,2);
plot(1:N, y2);

%生成正弦波信号和噪声信号复合的信号
y=sin_data+y2/10;
subplot(3,1,3);
plot(1:N, y);

%定点化
fix_y = fix(y*127) + 150;
plot(1:N,fix_y);

%写到文件
fid = fopen('sin_sp_ram_256X8.coe','wt');
fprintf(fid,'MEMORY_INITIALIZATION_RADIX=10;\n'); 
fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n');
for i=1:1:N
    fprintf(fid, "%d",fix_y(i));
    if i == N
        fprintf(fid,';');
    else 
        fprintf(fid,',\n');
    end
end
fclose(fid);
Testbench

当然,抽头数据是随便设的

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/05/10 21:27:44
// Design Name: 
// Module Name: FIR_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module FIR_tb;
  // Parameters
  localparam  DATA_WIDTH = 32;
  localparam  b0 = 0;
  localparam  b1 = 0;
  localparam  b2 = 1;
  localparam  b3 = 3;
  localparam  b4 = 8;
  localparam  b5 = 3;
  localparam  b6 = 1;
  localparam  b7 = 0;
  localparam  b8 = 0;

  // Ports
  reg clk = 0;
  reg rst_n = 0;
  wire  [DATA_WIDTH:1] data_in;
  wire [DATA_WIDTH:1] filtered_data;
  wire filtered_data_valid;

  FIR 
  #(
    .DATA_WIDTH(DATA_WIDTH ),
    .b0(b0 ),
    .b1(b1 ),
    .b2(b2 ),
    .b3(b3 ),
    .b4(b4 ),
    .b5(b5 ),
    .b6(b6 ),
    .b7(b7 ),
    .b8(b8 )
  )
  FIR_dut (
    .clk (clk ),
    .rst_n (rst_n ),
    .data_in (data_in ),
    .filtered_data (filtered_data ),
    .filtered_data_valid  ( filtered_data_valid)
  );

reg [7:0] addra;
always @(posedge clk or negedge rst_n) begin
  if (!rst_n) begin
    addra <= 0;
  end
  else begin
    addra <= addra + 1; 
  end
end

wire [31:0] douta;
//调用FIFO
  FIR_tb_ram your_instance_name (
  .clka(clk),    // input wire clka
  .wea(0),      // input wire [0 : 0] wea
  .addra(addra),  // input wire [7 : 0] addra
  .dina(0),    // input wire [31 : 0] dina
  .douta(douta)  // output wire [31 : 0] douta
);
assign data_in[DATA_WIDTH:1] = douta[31:0];

  initial begin
    begin
      #500 rst_n = 1;
    end
  end

  always
    #5  clk = ! clk ;

endmodule

测试波形

请添加图片描述

  • 9
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
FPGA中可使用Verilog或VHDL语言实现FIR滤波算法。FIR滤波器由一个系数序列和一个延迟线单元组成。FPGA中,输入信号首先通过延迟线单元进行延迟,然后乘以系数序列的对应系数,再将各项积相加,得到输出信号。 例如,在Verilog中实现32阶FIR滤波器,可使用以下代码: ```verilog module fir_filter(input clk, input signed [15:0] data_in, output signed [15:0] data_out); reg signed [15:0] shift_reg [31:0]; reg signed [15:0] coef [31:0] = {32'd177, 32'd824, 32'd1897, 32'd3031, 32'd4183, 32'd5069, 32'd5487, 32'd5309, 32'd4525, 32'd3246, 32'd1604, -32'd190, -32'd1271, -32'd2210, -32'd2739, -32'd2727, -32'd2188, -32'd1218, 32'd0, 32'd1218, 32'd2188, 32'd2727, 32'd2739, 32'd2210, 32'd1271, 32'd190, -32'd1604, -32'd3246, -32'd4525, -32'd5309, -32'd5487, -32'd5069, -32'd4183, -32'd3031, -32'd1897, -32'd824, -32'd177}; //系数序列 always @(posedge clk) begin shift_reg[0] <= data_in; for (i = 1; i < 32; i=i+1) begin shift_reg[i] <= shift_reg[i-1]; end end always @(posedge clk) begin data_out <= 0; for (i = 0; i < 32; i=i+1) begin data_out <= data_out + shift_reg[i] * coef[i]; end end endmodule ``` 在该代码中,需要首先定义系数序列。在`always`块中,首先对输入信号进行了延迟,然后在第二个`always`块中乘以对应的系数并添加到`data_out`变量中,最终得到输出信号。 需要注意的是,该代码中的数据类型为`signed [15:0]`,表示有符号的16位数据。需要根据实际需求进行调整。另外,该实现方式只是一种比较简单的实现方法,对于实际应用中更复杂的FIR滤波算法,可能需要采用更复杂的实现方式。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值