单极 IIR 滤波器,定点设计

信息处理 过滤器设计 无限脉冲响应 零极点 固定点 浮点
2022-02-22 19:29:27

我们想做一个单极点 IIR 滤波器的定点实现:

y[n]=ax[n]+(1a)y[n1];0<a<1

要考虑的主要设计考虑因素是什么?特别是,对于较小的 a 还是较大的 a ,定点设计是否更具挑战性?

4个回答

实现 IIR 滤波器时要考虑的一件事是量化和限制循环,无论顺序如何。

让我向您展示一个使用原始过滤器的快速示例

y[n]=ax[n]+(1a)y[n1]

设 a = 0.005 并假设我们使用 16 位有符号系数。

afixedpoint=a32768=164

假设输入和输出是 16 位整数。它们将从 -32768 变为 32767。之前的输出在这种情况下也是一个 16 位整数。实现看起来像这样,其中 temp 是一个 32 位整数。所有其他变量都是 16 位整数。y[n1]

temp=afixedpointx[n]+(32768afixedpoint)y[n1]

y[n]=round(temp/32768)

让我们用阶跃响应来试试这个实现

定点 IIR 滤波器的阶跃响应

看起来不错,对吧?也许我们应该放大。

定点 IIR 滤波器的阶跃响应(放大)

即使原始滤波器的增益为 1,我们也没有达到 32767。这称为极限环。对于 1 阶 IIR 滤波器,极限环采用您无法摆脱的 DC 偏移的形式。对于具有复极点的 IIR 滤波器,极限环采用您无法摆脱的小振荡形式。存储在 16 位上的事实引起的。如果我们将的分辨率提高到 32 位,就可以解决问题。另一种解决方案是使用分数节省。y[n1]y[n1]

如果输入从 32767 变为 0,我们将遇到同样的问题,输出将接近 0,但实际上不会达到 0。

提高分辨率

如果我们不将输出存储在 16 位上,而是将其存储在 24 位上,并将此变量命名为 acc(提高 y[n] 的分辨率)。

temp=afixedpointx[n]256+(32768afixedpoint)acc

acc=temp/32768

y[n]=round(acc/(256))

具有更高分辨率的阶跃响应

正如我们所看到的,随着分辨率的提高,即使系数仍然是 16 位,我们也可以达到 32767。然而,要付出的代价是具有更高分辨率的中间变量,计算可能会更慢。

节省分数

最后,有一种巧妙的方法可以最小化 IIR 所需的附加分辨率,尤其是当极点靠近单位圆时。它被称为分数节省。想法是记住前一个样本的舍入误差,并将其应用于下一次计算,以减少量化效应。需要一个称为错误的附加变量,但您不需要增加先前输出的分辨率。因此,如果 x 用 16 位表示,那么 y[n] 也可以存储在 16 位上。在此示例中,错误变量也将用 16 位表示。正如 Robert Bristow-Johnson 所指出的,分数节省是噪声整形的一种形式

temp=afixedpointx[n]+(32768afixedpoint)y[n1]error[n1]

y[n]=round(temp/32768)

error[n]=y[n]32768temp

节省分数的 IIR 阶跃响应

特别是,对于较小的 a 还是较大的 a ,定点设计是否更具挑战性?

越小越差:越接近,pol 越接近单位圆,您的时域振铃就越多。a0

要考虑的主要设计考虑因素是什么?

一阶低通 IIR 滤波器相对温和。脉冲响应的总和绝对和是统一的,因此您无法裁剪输出。需要注意的一件事是潜在的极限循环。这可以通过四舍五入的方式来控制:“向零舍入”是最安全的选择。

这是我关于使用分数节省实现定点直流阻塞一阶 HPF 的原始帖子

Lyons 和 Yates 后来写了一篇关于直流阻塞滤波器的 IEEE Sig Proc 文章,这是其中的主题之一。

// let's say sizeof(short) = 2 (16 bits) and sizeof(long) = 4 (32 bits)
short x[], y[];
long acc, A, prev_x, prev_y;
double pole;
unsigned long n, num_samples;
pole = 0.9999;
A = (long)(32768.0*(1.0 - pole));
acc = 0;
prev_x = 0;
prev_y = 0;
for (n=0; n<num_samples; n++)
    {
    acc   -= prev_x;
    prev_x = (long)x[n]<<15;
    acc   += prev_x;
    acc   -= A*prev_y;
    prev_y = acc>>15;               // quantization happens here
    y[n]   = (short)prev_y;
    // acc has y[n] in upper 17 bits and -e[n] in lower 15 bits
    }

过去,乘法比加法或按位运算要昂贵得多。对于整数(和定点)实现,可以这样利用:

时,可以通过单次加法和单次移位来实现极其有效的实现。a=1/2

y[n]=(x[n]+y[n1])>>1

类似地,分母中具有 2 次幂的分数也可以有效地完成。例如,可以这样完成:a=7/8

y[n]=((x[n]<<3)x[n]+y[n1])>>3

还有很多其他的可能性。我倾向于使用选项。a=1/2

显然,你有多少净空是一个主要考虑因素,所以像这样的事情需要 8 位净空,而有定点分数不会受此影响,但它会花费你一两次乘法。请注意,该等式也可以改写为:a=255/256

y[n]=y[n1]+a(x[n]y[n1])

这以减法为代价节省了乘法。