You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何IIR滤波器输出出现无关项?附Verilog实现及测试代码

IIR滤波器Verilog实现与输出无关项问题分析

设计代码

module IIR_filter(xn, clk, rst_n, yn);
  input signed [3:0]xn;
  input clk,rst_n;
  output reg signed [3:0]yn;
  reg signed [3:0]y_1,y_2,x_1,x_2,x_3;
  
  always @(*)begin
    yn = xn - (x_1) + (x_2) + (x_3)+ (y_1>>>1) + (y_2>>>2);
  end
  always @(posedge clk or negedge rst_n)
    begin 
      if(rst_n == 0)
        begin
          y_1 <=0;y_2<=0;x_1<=0;x_2<=0;x_3<=0;
        end
      else
        begin
          y_1 <=yn; y_2<=y_1;
          x_1<=xn; x_2<=x_1; x_3<=x_2;
        end
    end
endmodule

测试平台代码

// Code your testbench here
// or browse Examples
module IIR_filter_tb();
  reg [3:0]xn;
  reg clk,rst_n;
  wire [3:0]yn;
  integer i;
  IIR_filter test(.xn(xn),
                  .clk(clk),
                  .rst_n(rst_n),
                  .yn(yn)); 
  initial 
begin 
  clk = 0;
  #5 rst_n = 0;
  xn = 4'b0000;
  rst_n=1;
  for(i = 0; i<4;i=i+1)
    #20 xn = i;
  $display("yn = %d", yn);
    $finish; 
end 
  always
    begin
    #10 clk = ~clk;
  end
endmodule

问题现象

滤波器输出出现don't-care(无关项),怀疑与移位运算符实现方式、递归结果逐寄存器传递逻辑有关。

问题分析

  • 位宽溢出与符号扩展异常:所有运算变量都是4位有符号数,算术右移及加减运算的中间结果位宽不足,直接截断会导致溢出,部分位变为无关项;算术右移时符号位扩展未被正确保留,也会引入不确定值。
  • 组合逻辑与时序逻辑竞争:yn由组合逻辑直接计算,同时y_1在时钟沿采样yn反馈回组合逻辑,电路毛刺或时序不满足时,组合逻辑的不稳定值会被寄存器采样,进而输出无关项。
  • 测试平台时序缺陷:复位时间过短(仅5ns),寄存器可能未完成初始化;仅在循环结束后打印一次输出,无法捕捉时序过程中无关项出现的具体节点。

解决方法

1. 扩展中间运算位宽

引入高位宽变量存储中间计算结果,避免溢出,最后再截断到输出位宽:

module IIR_filter(xn, clk, rst_n, yn);
  input signed [3:0]xn;
  input clk,rst_n;
  output reg signed [3:0]yn;
  reg signed [3:0]y_1,y_2,x_1,x_2,x_3;
  reg signed [7:0] yn_temp; // 扩展位宽存储中间结果
  
  always @(*)begin
    yn_temp = xn - x_1 + x_2 + x_3 + (y_1>>>1) + (y_2>>>2);
    yn = yn_temp[3:0]; // 截断到4位输出
  end
  
  always @(posedge clk or negedge rst_n)
    begin 
      if(rst_n == 0)
        begin
          y_1 <=0;y_2<=0;x_1<=0;x_2<=0;x_3<=0;
        end
      else
        begin
          y_1 <=yn; y_2<=y_1;
          x_1<=xn; x_2<=x_1; x_3<=x_2;
        end
    end
endmodule

2. 消除组合逻辑直接输出的不稳定

将yn改为寄存器输出,避免组合逻辑毛刺直接传递:

module IIR_filter(xn, clk, rst_n, yn);
  input signed [3:0]xn;
  input clk,rst_n;
  output wire signed [3:0] yn; // 改为wire输出
  reg signed [3:0] yn_reg, y_1,y_2,x_1,x_2,x_3;
  reg signed [7:0] yn_temp;
  
  always @(*)begin
    yn_temp = xn - x_1 + x_2 + x_3 + (y_1>>>1) + (y_2>>>2);
    yn_reg = yn_temp[3:0];
  end
  
  always @(posedge clk or negedge rst_n) begin 
    if(rst_n == 0) begin
      y_1 <=0;y_2<=0;x_1<=0;x_2<=0;x_3<=0;
      yn_reg <= 0; // 初始化输出寄存器
    end else begin
      y_1 <= yn_reg; y_2 <= y_1;
      x_1 <= xn; x_2 <= x_1; x_3 <= x_2;
    end
  end
  
  assign yn = yn_reg; // 寄存器输出
endmodule

3. 修正测试平台

延长复位时间,增加时序观测点:

module IIR_filter_tb();
  reg [3:0]xn;
  reg clk,rst_n;
  wire [3:0]yn;
  integer i;
  IIR_filter test(.xn(xn),
                  .clk(clk),
                  .rst_n(rst_n),
                  .yn(yn)); 
  initial 
  begin 
    clk = 0;
    rst_n = 0;
    xn = 4'b0000;
    #20 rst_n = 1; // 延长复位时间确保初始化完成
    for(i = 0; i<4;i=i+1) begin
      #20 xn = i;
      $display("At time %t, xn = %d, yn = %d", $time, xn, yn); // 每次输入变化时观测输出
    end
    #20 $finish; 
  end 
  always #10 clk = ~clk;
endmodule

4. 兼容老版本编译器的移位实现

若编译器对算术右移支持存在问题,手动实现符号扩展右移:

// 替换(y_1>>>1)为手动符号扩展右移
(y_1[3] ? 4'b1000 : 4'b0000) | (y_1 >> 1)

内容的提问来源于stack exchange,提问作者Fatima Ismail

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 01:58:11