是否可以在以采样频率为时钟源的FPGA中创建IIR滤波器?


9

这个问题是关于使用非常具体的标准在带有DSP Slice的FPGA中实现IIR滤波器的。

假设您要制作的滤波器没有正向抽头,只有1个反向抽头,其公式如下:

y[n]=y[n1]b1+x[n]

(见图片)

以Xilinx的DSP48A1芯片为例-大多数硬IP DSP芯片都是相似的。

假设您有每个时钟以1个样本输入的模拟数据。我想设计一个在采样时钟上同步运行的IIR滤波器。

问题在于,为了以最大速率运行DSP Slice,您不能在同一周期上进行乘加运算。这些组件之间必须有一个管道寄存器。

因此,如果每个时钟有1个新样本,则每个时钟将需要产生1个输出。但是,在此设计中产生新的时钟之前,需要先前的输出2个时钟。

显而易见的解决方案是要么以双时钟速率处理数据,要么禁用流水线寄存器,以便您可以在同一周期内进行乘法和加法。

不幸的是,如果说您以全流水线DSP Slice的最大时钟速率进行采样,那么这两种解决方案都不可行。还有其他方法可以构建吗?

(如果您可以使用任意数量的DSP Slice设计可以以一半采样率运行的IIR滤波器,则可加分)

目标是在Xilinx Artix FPGA中为1 GSPS ADC运行补偿滤波器。当完全流水线化时,他们的DSP Slice可以运行在500 MHz以上。如果每个时钟有1个样本的解决方案,我想尝试扩展每个时钟2个样本的解决方案。使用FIR滤波器,这一切都非常容易。

单反馈IIR滤波器示例


1
只是为了澄清,没有理由为什么管道方法每个时钟周期都没有一个输出,对吗?您正在尝试将延迟降低到一个时钟周期而不是两个时钟周期,对吗?根据您的情况,如果您为b1使用整数,则可以将乘法转换为包含x [n]的巨型加法。
奥尔塔2014年

正确-由于每个时钟只有一个输入,因此每个时钟需要一个输出。延迟也不是问题。DSP Slice仅具有2输入加法器,而抽头通常是相当大的数字,因此您无法在1个时钟周期内加b1次。主要限制是输出需要在1个时钟周期内反馈,但要花2个时钟周期才能产生。
Marcus10110 2014年

1
我认为您仍然误解了管道的工作方式。流水线可能会增加延迟,但是允许您在每个时钟周期为每个输入获得1个输出。只是结果现在是2个时钟之后,而不是理想的1个时钟之后。输入将是这样的序列:x [0],x [1],x [2],x [3],x [4],而输出将在相同的时间间隔y [-2],y [-1],y [0],y [1],y [2]。您不会丢失任何样本。另外,您使用的是FPGA,因此,如果您想完成比DSP管道设计更多的工作,请利用fpga并行化工作负载。
奥尔塔2014年

该DSP能够在一个周期内进行融合乘法累加。尽管我尚不清楚DSP Slice的输出是否可以在单个周期内通过反馈连接到其自身的输入。
jbarlow 2014年

horta-一般来说,您对流水线是正确的,但是问题是在这种情况下,选项卡b1具有反馈-这意味着管道中的阶段取决于先前值的输出。如果始终需要2个时钟来产生前一个输出的下一个输出,则无论您添加了多少延迟,都无法每个时钟产生1个输出。jbarlow-没错,DSP Slice具有1周期融合选项。但是,在这种情况下,它运行得不够快。通过添加M寄存器(请参见数据表),您可以达到500 MHz,但是您不能相乘并添加相同的clk。
Marcus10110 2014年

Answers:


3

我还没有使用IIR滤波器,但是如果您只需要计算给定的方程式

y[n] = y[n-1]*b1 + x[n]

每个CPU周期一次,您可以使用流水线。

在一个周期中,您需要进行乘法运算,而在一个周期中,您需要对每个输入样本进行求和。这意味着当以给定的采样率计时时,您的FPGA必须能够在一个周期内完成乘法!然后,您只需并行执行当前样本的乘法运算和最后一个样本的乘法结果求和运算。这将导致2个周期的恒定处理滞后。

好的,让我们看一下公式并设计管道:

y[n] = y[n-1]*b1 + x[n]

您的管道代码可能如下所示:

output <= last_output_times_b1 + last_input
last_output_times_b1 <= output * b1;
last_input <= input

请注意,所有三个命令都需要并行执行,因此第二行中的“输出”将使用最后一个时钟周期的输出!

我对Verilog的工作不多,因此此代码的语法很可能是错误的(例如,缺少输入/输出信号的位宽;用于乘法的执行语法)。但是,您应该知道:

module IIRFilter( clk, reset, x, b, y );
  input clk, reset, x, b;
  output y;

  reg y, t, t2;
  wire clk, reset, x, b;

  always @ (posedge clk or posedge reset)
  if (reset) begin
    y <= 0;
    t <= 0;
    t2 <= 0;
  end else begin
    y <= t + t2;
    t <= mult(y, b);
    t2 <= x
  end

endmodule

PS:也许某些经验丰富的Verilog程序员可以编辑此代码,然后删除此注释以及代码上方的注释。谢谢!

PPS:如果因子“ b1”是一个固定常数,则可以通过实现一个特殊的乘法器来优化设计,该乘法器仅采用一个标量输入并仅计算“时间b1”。

对以下内容的答复:“不幸的是,这实际上等效于y [n] = y [n-2] * b1 + x [n]。这是由于额外的流水线级。” 作为对旧版本答案的评论

是的,这实际上适用于以下旧版本(错误!!):

  always @ (posedge clk or posedge reset)
  if (reset) begin
    t <= 0;
  end else begin
    y <= t + x;
    t <= mult(y, b);
  end

我希望现在也通过延迟第二个寄存器中的输入值来纠正此错误:

  always @ (posedge clk or posedge reset)
  if (reset) begin
    y <= 0;
    t <= 0;
    t2 <= 0;
  end else begin
    y <= t + t2;
    t <= mult(y, b);
    t2 <= x
  end

为了确保这次能够正常工作,让我们看一下前几个周期发生了什么。请注意,前两个周期会产生或多或少的(定义的)垃圾,因为先前的输出值(例如y [-1] == ??)不可用。寄存器y初始化为0,等效于假设y [-1] == 0。

第一周期(n = 0):

BEFORE: INPUT (x=x[0], b); REGISTERS (t=0, t2=0, y=0)

y <= t + t2;      == 0
t <= mult(y, b);  == y[-1] * b  = 0
t2 <= x           == x[0]

AFTERWARDS: REGISTERS (t=0, t2=x[0], y=0), OUTPUT: y[0]=0

第二周期(n = 1):

BEFORE: INPUT (x=x[1], b); REGISTERS (t=0, t2=x[0], y=y[0])

y <= t + t2;      ==     0  +  x[0]
t <= mult(y, b);  ==  y[0]  *  b
t2 <= x           ==  x[1]

AFTERWARDS: REGISTERS (t=y[0]*b, t2=x[1], y=x[0]), OUTPUT: y[1]=x[0]

第三周期(n = 2):

BEFORE: INPUT (x=x[2], b); REGISTERS (t=y[0]*b, t2=x[1], y=y[1])

y <= t + t2;      ==  y[0]*b +  x[1]
t <= mult(y, b);  ==  y[1]   *  b
t2 <= x           ==  x[2]

AFTERWARDS: REGISTERS (t=y[1]*b, t2=x[2], y=y[0]*b+x[1]), OUTPUT: y[2]=y[0]*b+x[1]

第四周期(n = 3):

BEFORE: INPUT (x=x[3], b); REGISTERS (t=y[1]*b, t2=x[2], y=y[2])

y <= t + t2;      ==  y[1]*b +  x[2]
t <= mult(y, b);  ==  y[2]   *  b
t2 <= x           ==  x[3]

AFTERWARDS: REGISTERS (t=y[2]*b, t2=x[3], y=y[1]*b+x[2]), OUTPUT: y[3]=y[1]*b+x[2]

我们可以看到,从cylce n = 2开始,我们得到以下输出:

y[2]=y[0]*b+x[1]
y[3]=y[1]*b+x[2]

相当于

y[n]=y[n-2]*b + x[n-1]
y[n]=y[n-1-l]*b1 + x[n-l],  where l = 1
y[n+l]=y[n-1]*b1 + x[n],  where l = 1

如上所述,我们引入了l = 1个周期的额外延迟。这意味着您的输出y [n]被延迟l = 1。这意味着输出数据是等效的,但延迟了一个“索引”。更清楚地说:输出数据被延迟2个周期,因为需要一个(正常)时钟周期,并且为中间级增加了1个额外的(滞后l = 1)时钟周期。

以下是以图形方式描述数据流向的草图:

数据流示意图

PS:感谢您仔细阅读我的代码。所以我也学到了一些东西!;-)让我知道此版本是否正确,或者是否还有其他问题。


做得好!不幸的是,y [n] = y [n-2] * b + x [n-1]实​​际上在功能上不等同于y [n] = y [n-1] * b + x [n]。IIR传递函数的形式实际上如下所示:y [n] = x [n] * b0 + x [n-1] * b1-y [n-1] * a1-y [n-2] * a2等等。您的窗体将b0和a1设置为0,而是使用b1和a2。但是,该转换实际上会产生非常不同的过滤器。如果有一种方法可以将第一个分母(a1)设置为零来计算滤波器,那么您的两种解决方案都可以完美地工作。
Marcus10110 2014年

好吧,您需要正确理解“延迟引入”问题。例如,“数据流处理”过滤器应仅转发其输入,因为y [n] = x [n]如果产生y [n] = x [n-1]作为输出将正常工作。输出仅延迟了1个周期(例如,输出索引相对于所有输入索引偏移了固定值)!在我们的示例中,这意味着您的函数y[n+l] = y[n-1] * b + x[n]具有固定的滞后值l,可以将其重写y[n] = y[n-1-l] * b + x[n-l]为l = 1,这是y[n] = y[n-2] * b + x[n-1]
SDwarfs 2014年

对于更复杂的IIR滤波器,您需要执行以下操作:y[n+l] = x[n] * b0 + x[n-1] * b1 - y[n-1] * a1 - y[n-2] * a2=> y[n] = x[n-l]*b0 + x[n-1-l] * b1 - y[n-1-l] * a1 - y[n-2-l]*a2。假设您可以并行执行所有三个乘法(1.阶段/ 1个周期),并且需要将两个乘积相加,那么您需要2个周期(1个周期:加/减前两个乘积结果,1个周期:加/减这两个加/减的结果),则需要再增加2个周期。所以l =(3-1)= 2给您y[n]=x[n-2]*b0+x[n-1-2]*b1-y[n-1-2]*a1-y[n-2-2]*a2=>y[n]=x[n-2]*b0+x[n-3]*b1-y[n-3]*a1-y[n-4]*a2
SDwarfs

当然,要使它起作用,您的FPGA必须能够并行执行:4个乘法和3个加法/减法。这意味着您需要4个乘法器和3个加法器的资源。
SDwarfs,2014年

0

是的,您可以以采样频率计时。

解决此问题的方法是操纵原始表达式,以便可以在保持所需输出顺序的同时插入流水线寄存器。

给定:y [n] = y [n-1] * b1 + x [n];

可以将其处理为:y [n] = y [n-2] * b1 * b1 + x [n-1] * b1 + x [n]。

为了验证这是相同的序列,请考虑一下前几个样本x [0],x [1],x [2]等发生了什么,其中在x [0]之前的所有x,y样本均为零。

对于原始表达式,顺序为:

y = x[0],

x[1] +x[0]*b1,

x[2] +x[1]*b1 +x[0]*b1*b1,

x[3] +x[2]*b1 +x[1]*b1*b1 +x[0]*b1*b1*b1, ...

很明显,有必要使b1 <1,否则它将无限制地增长。

现在考虑操纵表达式:

y = x[0],

x[0]*b1 +x[1],

x[0]*b1*b1 +x[1]*b1 +x[2],

x[0]*b1*b1*b1 +x[1]*b1*b1 +x[2]*b1 +x[3], ...

这是相同的顺序。

Xilinx库原语中的硬件解决方案将需要级联两个DSP48E。有关下面的端口和寄存器名称,请参见UG193 v3.6中的图1-1。第一个原语是乘以b1,然后再加上一个时钟。第二个是乘以b1 * b1,然后再加上一个时钟。此逻辑有4个时钟管线延迟。

-DSP48E#1

a_port1:= b1; -常数系数,设置AREG = 1

b_port1:= x; -设置属性BREG = 1

c_port1:= x; -设置CREG = 1

-DSP48E#1内部

reg_a1 <= a_port1;

reg_b1 <= b_port1;

reg_c1 <= c_port1;

reg_m1 <= reg_a1 * reg_b1;

reg_p1 <= reg_m1 + reg_c1; -第一个DSP48E的输出

-DSP48E#1结束

-DSP48E#2

a_port2:= reg_p2; -设置属性AREG = 0

                -- this means the output of register reg_p2

                -- directly feeds back to the multiplier

b_port2:= b1 * b1; -常量,设置BREG = 1

c_port2:= reg_p1; -设置CREG = 1

-DSP48E#2内部

reg_b2 <= b_port2;

reg_c2 <= c_port2;

reg_m2 <= a_port2 * reg_b2;

reg_p2 <= reg_m2 + reg_c2;

-DSP48E#2结束

reg_p1处的序列:

x [0],

x [1] + x [0] * b1,

x [2] + x [1] * b1,

x [3] + x [2] * b1,

等等

reg_p2处的序列是所需的结果。在第二个DSP48E内部,寄存器reg_m2具有一个序列:

x [0] * b1 * b1,

x [1] * b1 * b1 + x [0] * b1 * b1 * b1,

x [2] * b1 * b1 + x [1] * b1 * b1 * b1 + x [0] * b1 * b1 * b1 * b1

这个结果有一个很好的优雅。显然,DSP48E不会在同一时钟上进行乘法和加法运算,但这正是差分方程式所需要的。受控差分方程使我们能够容忍DSP48E中的M和P寄存器并全速时钟。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.