scipy.signal.

zpk2sos#

scipy.signal.zpk2sos(z, p, k, pairing=None, *, analog=False)[源代码]#

从系统的零点、极点和增益返回二阶节

参数:
zarray_like

传递函数的零点。

parray_like

传递函数的极点。

kfloat

系统增益。

pairing{None, ‘nearest’, ‘keep_odd’, ‘minimal’}, 可选

用于将极点和零点配对成节的方法。如果 analog 为 False 且 pairing 为 None,则 pairing 设置为 ‘nearest’;如果 analog 为 True,则 pairing 必须为 ‘minimal’,如果为 None,则将其设置为 ‘minimal’。

analogbool, 可选

如果为 True,则系统为模拟系统,否则为离散系统。

在 1.8.0 版本中添加。

返回:
sosndarray

二阶滤波器系数数组,形状为 (n_sections, 6)。有关 SOS 滤波器格式规范,请参阅 sosfilt

另请参阅

sosfilt

注释

用于将 ZPK 转换为 SOS 格式的算法旨在最大限度地减少由于数值精度问题引起的误差。配对算法尝试最小化每个双二次节的峰值增益。这是通过将极点与最近的零点配对来实现的,首先是离散时间系统中最接近单位圆的极点,以及连续时间系统中最接近虚轴的极点。

pairing='minimal' 的输出可能不适用于 sosfilt,并且 analog=True 的输出永远不适用于 sosfilt

算法

pairing='nearest'pairing='keep_odd'pairing='minimal' 算法中的步骤大多是共享的。'nearest' 算法尝试最小化峰值增益,而 'keep_odd' 在奇数阶系统应保留一个节作为一阶的约束下最小化峰值增益。'minimal''keep_odd' 类似,但不会引入额外的极点或零点

算法步骤如下

作为 pairing='nearest'pairing='keep_odd' 的预处理步骤,根据需要向原点添加极点或零点,以获得相同数量的极点和零点进行配对。如果 pairing == 'nearest' 并且有奇数个极点,则在原点添加一个额外的极点和一个零点。

然后迭代执行以下步骤,直到没有更多的极点或零点为止

  1. 取(下一个剩余的)最接近单位圆(或虚轴,对于 analog=True)的极点(复数或实数)以开始新的滤波器节。

  2. 如果极点是实数,并且没有其他剩余的实极点 [1],则将最近的实零点添加到该节,并将其保留为一阶节。请注意,在此步骤之后,我们保证将剩余偶数个实极点、复极点、实零点和复零点,用于后续的配对迭代。

  3. 否则

    1. 如果极点是复数,并且零点是唯一剩余的实零点*,则将极点与下一个最近的零点配对(保证是复数)。这是必要的,以确保将有一个实零点保留,最终创建一个一阶节(从而保持奇数阶)。

    2. 否则,将极点与最近的剩余零点(复数或实数)配对。

    3. 通过向当前节中的极点和零点添加另一个极点和零点来完成二阶节

      1. 如果当前极点和零点都是复数,则添加它们的共轭。

      2. 否则,如果极点是复数且零点是实数,则添加共轭极点和下一个最近的实零点。

      3. 否则,如果极点是实数且零点是复数,则添加共轭零点和最接近这些零点的实极点。

      4. 否则(我们必须有实极点和实零点),添加下一个最接近单位圆的实极点,然后添加最接近该极点的实零点。

在 0.16.0 版本中添加。

示例

为采样率为 8000 Hz 的系统设计一个 6 阶低通椭圆数字滤波器,该滤波器的通带截止频率为 1000 Hz。通带中的纹波不应超过 0.087 dB,并且阻带中的衰减应至少为 90 dB。

在以下对 ellip 的调用中,我们可以使用 output='sos',但在此示例中,我们将使用 output='zpk',然后使用 zpk2sos 转换为 SOS 格式

>>> from scipy import signal
>>> import numpy as np
>>> z, p, k = signal.ellip(6, 0.087, 90, 1000/(0.5*8000), output='zpk')

现在转换为 SOS 格式。

>>> sos = signal.zpk2sos(z, p, k)

各节分子系数

>>> sos[:, :3]
array([[0.0014152 , 0.00248677, 0.0014152 ],
       [1.        , 0.72976874, 1.        ],
       [1.        , 0.17607852, 1.        ]])

系数的对称性是因为所有零点都在单位圆上。

各节分母的系数

>>> sos[:, 3:]
array([[ 1.        , -1.32544025,  0.46989976],
       [ 1.        , -1.26118294,  0.62625924],
       [ 1.        , -1.2570723 ,  0.8619958 ]])

下一个示例显示了 pairing 选项的效果。我们有一个具有三个极点和三个零点的系统,因此 SOS 数组的形状将为 (2, 6)。这意味着在 SOS 表示中实际上在原点有一个额外的极点和一个额外的零点。

>>> z1 = np.array([-1, -0.5-0.5j, -0.5+0.5j])
>>> p1 = np.array([0.75, 0.8+0.1j, 0.8-0.1j])

使用 pairing='nearest'(默认值),我们得到

>>> signal.zpk2sos(z1, p1, 1)
array([[ 1.  ,  1.  ,  0.5 ,  1.  , -0.75,  0.  ],
       [ 1.  ,  1.  ,  0.  ,  1.  , -1.6 ,  0.65]])

第一节的零点为 {-0.5-0.05j, -0.5+0.5j},极点为 {0, 0.75},第二节的零点为 {-1, 0},极点为 {0.8+0.1j, 0.8-0.1j}。请注意,原点处的额外极点和零点已分配给不同的节。

使用 pairing='keep_odd',我们得到

>>> signal.zpk2sos(z1, p1, 1, pairing='keep_odd')
array([[ 1.  ,  1.  ,  0.  ,  1.  , -0.75,  0.  ],
       [ 1.  ,  1.  ,  0.5 ,  1.  , -1.6 ,  0.65]])

原点处的额外极点和零点位于同一节中。第一节实际上是一阶节。

使用 pairing='minimal',一阶节在原点处没有额外的极点和零点

>>> signal.zpk2sos(z1, p1, 1, pairing='minimal')
array([[ 0.  ,  1.  ,  1.  ,  0.  ,  1.  , -0.75],
       [ 1.  ,  1.  ,  0.5 ,  1.  , -1.6 ,  0.65]])