pyAudioKits是基于librosa和其他库的强大Python音频工作流支持。

API速查手册

通过pip安装:

pip install pyAudioKits

本项目的GitHub地址,如果这个项目帮助到了你,请为它点上一颗star,谢谢你的支持!如果你在使用过程中有任何问题,请在评论区留言或在GitHub上提issue,我将持续对该项目进行维护。

本节将介绍线性时不变系统理论,并引出LTI滤波器的概念。本节还将分别讨论FIR和IIR滤波器,并介绍使用pyAudioKits实现这两类滤波器的方法。该部分专业性较强,pyAudioKits对这一方面仅实现基本的支持。可以将pyAudioKits与SciPy的信号处理工具箱结合使用。

线性时不变系统

在信号与系统理论中,信号是一个或多个独立变量的函数,而系统则对于输入的信号产生响应,包括将信号代入函数、更改信号自变量,输出一个或多个信号。最基本的系统可以描述为python音源响度对齐 python调音器_开发语言

信号分为:

  1. 连续时间信号离散时间信号,区别是时间上是否连续。音频信号是连续时间信号,而在被我们采样为数字音频信号后就变成了离散时间信号。
  2. 确定信号随机信号,区别是是否随机。
  3. 周期信号非周期信号,区别是在全区间上是否存在周期。频率成分随时间改变的确定音频信号在经过分帧加窗后,在每一帧内可以视为周期信号。具有明显音高的平稳随机音频信号也具有准周期性
  4. 偶信号奇信号。由于我们对音频信号进行截断,数字音频信号的时间戳从python音源响度对齐 python调音器_python_02开始,因此不存在偶信号和奇信号之分。
  5. 因果信号(<0的部分全为0)和非因果信号(<0的部分有非0值)。同样地,由于我们对音频信号进行截断,因此数字音频信号都是因果的。
  6. 根据信号能量分类:有限能量信号、有限功率信号和无限信号(功率和能量都无限),这在第三节讨论功率和能量时已经介绍过。

系统分为:

  1. 记忆性系统无记忆系统:系统的输出是否过去和未来有关。
  2. 可逆非可逆系统:输出信号是否能通过输入信号被还原。
  3. 线性非线性系统:线性系统满足python音源响度对齐 python调音器_python_03
  4. 时不变时变系统:时不变系统满足python音源响度对齐 python调音器_线性系统_04
  5. 因果非因果系统:因果系统的输出取决于过去或现在(而非未来)的输入。
  6. BIBO稳定性:如果输入的信号有界,则输出的信号有界

线性时不变系统的特性使得我们可以通过求取其冲激响应函数来对其响应特点进行分析。所有离散信号都可以表示为一系列冲激函数python音源响度对齐 python调音器_开发语言_05的叠加:python音源响度对齐 python调音器_音视频_06。我们假设python音源响度对齐 python调音器_开发语言_07,而python音源响度对齐 python调音器_开发语言_08python音源响度对齐 python调音器_python音源响度对齐_09是线性时不变系统,则有python音源响度对齐 python调音器_python_10,且python音源响度对齐 python调音器_开发语言_11。因此只需知道简单冲激函数通过线性时不变系统的响应h,通过卷积运算python音源响度对齐 python调音器_开发语言_12就能求得复杂函数x通过线性时不变系统的响应。h可以用于描述系统线性时不变系统,任意信号x通过该系统就是作x与h的卷积

线性时不变(LTI)滤波器

离散时间傅里叶变换有一个非常重要的特性:时域的卷积等效为频域的相乘,即若python音源响度对齐 python调音器_线性系统_13,则有python音源响度对齐 python调音器_音视频_14。这一特性就是线性时不变滤波器设计的基础:

  1. python音源响度对齐 python调音器_音视频_15,因此我们可以通过设计python音源响度对齐 python调音器_音视频_16,使得python音源响度对齐 python调音器_开发语言_17能对python音源响度对齐 python调音器_python_18的各个频率成分幅度进行加权,从而使得python音源响度对齐 python调音器_python_19的各个频率成分具有理想的幅值,python音源响度对齐 python调音器_开发语言_17就被称为系统python音源响度对齐 python调音器_开发语言_21幅度响应
  2. python音源响度对齐 python调音器_开发语言_22,因此通过设计python音源响度对齐 python调音器_音视频_16同样可以使得python音源响度对齐 python调音器_开发语言_24在经过系统后得到的python音源响度对齐 python调音器_python音源响度对齐_25的各个频率成分具有理想的相位,python音源响度对齐 python调音器_python音源响度对齐_26就被称为系统python音源响度对齐 python调音器_开发语言_21相位响应

通常,我们希望滤波器具有线性相位响应特性,或者零相位响应特性。获取零相位响应特性可以使用双向滤波的方式,即进行一次正向卷积运算后再进行一次反向卷积运算,但这会使得幅度响应变为原来的二次方。

对于数字音频信号,由于计算机只能表示信号离散傅里叶变换的结果python音源响度对齐 python调音器_python_28python音源响度对齐 python调音器_线性系统_29,因此我们需要得到python音源响度对齐 python调音器_线性系统_30对应的python音源响度对齐 python调音器_音视频_31。对于离散傅里叶变换,有特性python音源响度对齐 python调音器_线性系统_32python音源响度对齐 python调音器_python音源响度对齐_33,其中python音源响度对齐 python调音器_python_34表示n对傅里叶变换点数N取余数,python音源响度对齐 python调音器_python音源响度对齐_35被称为循环卷积。当python音源响度对齐 python调音器_线性系统_36取全部样本时,就可以对信号一次性进行滤波。否则,可以对信号进行分帧加窗,在每帧按帧长进行傅里叶变换,分别进行滤波,然后对信号进行还原。

用z变换设计滤波器

python音源响度对齐 python调音器_python音源响度对齐_37进行离散时间傅里叶变换,得到python音源响度对齐 python调音器_音视频_38,其收敛条件是python音源响度对齐 python调音器_python音源响度对齐_37绝对可积。为了使得任意python音源响度对齐 python调音器_python音源响度对齐_37都可以进行类似的变换,只需要将其乘以实指数python音源响度对齐 python调音器_开发语言_41后再进行离散傅里叶变换即可。可以通过调整python音源响度对齐 python调音器_开发语言_42的大小来确保python音源响度对齐 python调音器_python音源响度对齐_43绝对可积。这样,就有python音源响度对齐 python调音器_线性系统_44,令python音源响度对齐 python调音器_线性系统_45,我们就得到了python音源响度对齐 python调音器_开发语言_46,这就是z变换。同样,信号python音源响度对齐 python调音器_python音源响度对齐_47python音源响度对齐 python调音器_python_48也可以通过z变换变换为python音源响度对齐 python调音器_线性系统_49python音源响度对齐 python调音器_音视频_50

离散时间傅里叶变换将信号变换到频域,频域是单变量的,单纯由python音源响度对齐 python调音器_音视频_51这一参数决定函数数值。而z变换则可以将系统和信号变换到z域,由于python音源响度对齐 python调音器_线性系统_45,z域有两个变量python音源响度对齐 python调音器_开发语言_42python音源响度对齐 python调音器_音视频_51,因此是一个平面,称为z平面,可以使用极坐标来描述:python音源响度对齐 python调音器_开发语言_42为幅值,而python音源响度对齐 python调音器_音视频_51为幅角。傅里叶变换则对应锁定python音源响度对齐 python调音器_python音源响度对齐_57时的z变换,对应围绕着极坐标原点的一个单位圆。python音源响度对齐 python调音器_音视频_51取不同值时,对应的python音源响度对齐 python调音器_音视频_59就在单位圆上旋转,以python音源响度对齐 python调音器_python音源响度对齐_60为周期,这也和之前第四节我们对python音源响度对齐 python调音器_python音源响度对齐_61特性的讨论一致。

z变换同样有和离散时间傅里叶变换类似的特性:时域的卷积等效为z域的相乘,即若python音源响度对齐 python调音器_线性系统_13,则有python音源响度对齐 python调音器_音视频_63

一个有理的z变换可以因式分解成python音源响度对齐 python调音器_python_64,其中python音源响度对齐 python调音器_音视频_65是所有零点,python音源响度对齐 python调音器_python_66使得分子为0;python音源响度对齐 python调音器_python_67是所有极点,python音源响度对齐 python调音器_开发语言_68使得分母为0。则对于z平面上的每一个点,其z变换的计算可以换成以所有零点、极点为起点,以z平面上某点为终点向量之间的计算

  1. 幅度:python音源响度对齐 python调音器_python_69
  2. 相位:python音源响度对齐 python调音器_线性系统_70

当取python音源响度对齐 python调音器_python音源响度对齐_57时,就可以得到系统的幅度响应和相位响应。也就是说当我们得到系统的所有零点和极点后,其特性就被确定了。因此,设计LTI滤波器可以通过设计零点和极点在z平面上的位置来完成。注意需要确保python音源响度对齐 python调音器_python音源响度对齐_57python音源响度对齐 python调音器_python音源响度对齐_43绝对可积。

FIR滤波器和IIR滤波器

假设常数python音源响度对齐 python调音器_线性系统_74,对python音源响度对齐 python调音器_python音源响度对齐_75的分子和分母进行展开,有python音源响度对齐 python调音器_python音源响度对齐_76,可记为python音源响度对齐 python调音器_python音源响度对齐_77

z变换的另一个重要的特性是,若python音源响度对齐 python调音器_python音源响度对齐_37的z变换为python音源响度对齐 python调音器_python音源响度对齐_75,则python音源响度对齐 python调音器_线性系统_80的z变换为python音源响度对齐 python调音器_python_81,因此在z域乘以一个python音源响度对齐 python调音器_python_82就相当于在时域延时1个样本点。若python音源响度对齐 python调音器_音视频_83,则有python音源响度对齐 python调音器_python音源响度对齐_84,即python音源响度对齐 python调音器_python_85,则有python音源响度对齐 python调音器_python音源响度对齐_86,即python音源响度对齐 python调音器_线性系统_87。则在python音源响度对齐 python调音器_python_88时,系统输入必定包含python音源响度对齐 python调音器_python_48的延时项,即系统存在反馈,此时系统被称为无限冲激响应(IIR)系统。只有当python音源响度对齐 python调音器_开发语言_90时,系统输入仅仅是python音源响度对齐 python调音器_python音源响度对齐_47及其延时项的加权和,此时系统被称为*有限冲激响应(FIR)系统。满足IIR系统或FIR系统特性的滤波器就称为IIR滤波器或FIR滤波器。

简单的FIR滤波器设计

pyAudioKits提供了通过指定python音源响度对齐 python调音器_音视频_92python音源响度对齐 python调音器_python音源响度对齐_93来设计FIR滤波器和IIR滤波器的函数。由于通过指定python音源响度对齐 python调音器_音视频_92python音源响度对齐 python调音器_python音源响度对齐_93来设计IIR滤波器较为困难,仅对固定python音源响度对齐 python调音器_python音源响度对齐_96并指定python音源响度对齐 python调音器_python音源响度对齐_97来设计FIR滤波器进行演示。

import pyAudioKits.audio as ak
import pyAudioKits.filters as flt
import pyAudioKits.analyse as aly

首先生成两个频率的信号的叠加。

signal = ak.create_Single_Freq_Audio(0.1,8,256,0.5) + ak.create_Single_Freq_Audio(0.1,32,256,0.5)
signal.plot()

python音源响度对齐 python调音器_开发语言_98

此时信号幅度谱具有两个峰值,且幅度是相同的。

aly.FFT(signal).plot()

python音源响度对齐 python调音器_python_99

差分是典型的高通滤波过程。一阶差分的系统函数为python音源响度对齐 python调音器_python音源响度对齐_100,对应差分方程为python音源响度对齐 python调音器_线性系统_101

signal_diff = flt.ltiFilter(signal, [1,-1], [1])    #构造线性时不变滤波器,设置分子系数为b0=1、b1=-1,设置分母系数为a0=1
signal_diff.plot()

python音源响度对齐 python调音器_音视频_102

对比原始信号和一阶差分后的信号的前5个样本。注意一阶差分后的信号的首位并不是有效的,使用0进行填充,有效信号整体上向右移动了1个样本,因此该系统并非是零相位响应的。

signal[:5].samples, signal_diff[:5].samples

'''
outputs:
(array([0.        , 0.09021971, 0.13826834, 0.1262677 , 0.07071068]),
 array([ 0.09021971,  0.09021971,  0.04804863, -0.01200064, -0.05555702]))
'''

绘制差分后信号的幅度谱。

aly.FFT(signal_diff).plot()

python音源响度对齐 python调音器_python音源响度对齐_103

可以看见低频成分被抑制,高频成分的幅度此时大于低频成分。

接下来尝试使用双向滤波来实现零相位响应。

signal_diff2 = flt.ltiFilter(signal, [1,-1], [1], zero_phase=True)
signal_diff2.plot()

python音源响度对齐 python调音器_python音源响度对齐_104

对比三个信号的前五和后五个样本。双向差分后,信号的首位和末位都不是有效的,因此有效信号整体居中。

signal[:5].samples, signal[-5:].samples, signal_diff[:5].samples, signal_diff[-5:].samples, signal_diff2[:5].samples, signal_diff2[-5:].samples

'''
outputs:
(array([0.        , 0.09021971, 0.13826834, 0.1262677 , 0.07071068]),
 array([-0.01243628, -0.07071068, -0.1262677 , -0.13826834, -0.09021971]),
 array([ 0.09021971,  0.09021971,  0.04804863, -0.01200064, -0.05555702]),
 array([-0.02004833, -0.0582744 , -0.05555702, -0.01200064,  0.04804863]),
 array([0.        , 0.04217108, 0.06004927, 0.04355638, 0.00271737]),
 array([ 0.03822607, -0.00271737, -0.04355638, -0.06004927,  0.        ]))
'''

由于幅度响应是原来的二次方,对低频成分的抑制程度更加强烈,现在低频成分幅度已远小于高频成分。

aly.FFT(signal_diff).plot()

python音源响度对齐 python调音器_开发语言_105

平滑是典型的低通滤波过程。以9点均值平滑为例,其系统函数为python音源响度对齐 python调音器_开发语言_106,对应差分方程为python音源响度对齐 python调音器_开发语言_107

signal_ma = flt.ltiFilter(signal, [1/9 for i in range(9)], [1]) #构造线性时不变滤波器,设置分子系数为b0~b8=1/9,设置分母系数为a0=1
signal_ma.plot()

python音源响度对齐 python调音器_线性系统_108

滤波后的信号和单频正弦波类似,查看其幅度谱可以发现,此时高频成分被过滤了很多。

aly.FFT(signal_ma).plot()

python音源响度对齐 python调音器_python_109

使用双向滤波同样可以使得该低通滤波器保持零相位响应。此外,如果平滑是中心化的,即python音源响度对齐 python调音器_python_110,则对应的滤波器也具有零相位响应,但这个系统就会是非因果的。

基于巴特沃斯滤波器设计IIR滤波器

IIR滤波器的设计需要考虑反馈,设计起来较为复杂,一般通过已有的模拟滤波器的变换来进行设计。pyAudioKits提供了以巴特沃斯滤波器为原型的IIR滤波器设计函数。

巴特沃斯滤波器需要指定阶数,我们先来看看不同阶数的巴特沃斯滤波器的效果区别。

首先生成白噪声,并绘制其幅度谱。

wn = ak.create_Single_Freq_Audio(0.1,440,44100,1) .addWgn(0.1) - ak.create_Single_Freq_Audio(0.1,440,44100,1)
aly.FFT(wn).plot()

python音源响度对齐 python调音器_python音源响度对齐_111

可以看见白噪声幅度谱均匀分布在[0,采样率/2]上。

首先构造一个1阶高通巴特沃斯滤波器来进行滤波,指定截止频率为11050Hz。对于高通滤波器而言,低频为阻带,高频为通带。滤波器将会抑制阻带的频率成分,阻带的功率相比通带将会衰减。而截止频率就是阻带功率相比通带衰减python音源响度对齐 python调音器_音视频_112的位置。

aly.FFT(flt.highPassButterN(wn, 1, 11050)).plot()

python音源响度对齐 python调音器_开发语言_113

虽然截止频率被指定为11050Hz,但直到5000Hz以下依然还具有较高的幅度。

接着尝试5阶高通巴特沃斯滤波器。

aly.FFT(flt.highPassButterN(wn, 5, 11050)).plot()

python音源响度对齐 python调音器_开发语言_114

可以看到此时从通带到阻带的衰减变得迅速。继续尝试10阶的滤波器。

aly.FFT(flt.highPassButterN(wn, 10, 11050)).plot()

python音源响度对齐 python调音器_python_115

通带到阻带的衰减变得更加迅速了。

同样的规律也适用于低通、带通和带阻滤波器。

aly.FFT(flt.lowPassButterN(wn, 1, 11050)).plot(), aly.FFT(flt.lowPassButterN(wn, 5, 11050)).plot(), aly.FFT(flt.lowPassButterN(wn, 10, 11050)).plot()

python音源响度对齐 python调音器_python_116


python音源响度对齐 python调音器_python音源响度对齐_117


python音源响度对齐 python调音器_python音源响度对齐_118

带通滤波器和带阻滤波器有两个截止频率。对于带通滤波器而言,两个截止频率之间为通带;对于带阻滤波器而言,两个频率之间为阻带。

aly.FFT(flt.bandPassButterN(wn, 1, 7500, 13500)).plot(), aly.FFT(flt.bandPassButterN(wn, 5, 7500, 13500)).plot(), aly.FFT(flt.bandPassButterN(wn, 10, 7500, 13500)).plot()

python音源响度对齐 python调音器_开发语言_119


python音源响度对齐 python调音器_开发语言_120


python音源响度对齐 python调音器_线性系统_121

aly.FFT(flt.bandStopButterN(wn, 1, 7500, 13500)).plot(), aly.FFT(flt.bandStopButterN(wn, 5, 7500, 13500)).plot(), aly.FFT(flt.bandStopButterN(wn, 10, 7500, 13500)).plot()

python音源响度对齐 python调音器_音视频_122


python音源响度对齐 python调音器_线性系统_123


python音源响度对齐 python调音器_python_124

通过尝试不同阶数来调节衰减速度比较麻烦,可以直接指定通带截止频率和阻带截止频率来设计滤波器。此外,通带功率的最大损失和阻带功率的最小衰减也是可以指定的。

aly.FFT(flt.highPassButter(wn, 11050, 5000, 1, 10)).plot()   #巴特沃斯高通滤波器,指定通带截止频率为11050Hz、阻带截止频率为5000Hz,通带功率最多损失1dB,阻带功率至少衰减10dB

python音源响度对齐 python调音器_音视频_125

aly.FFT(flt.highPassButter(wn, 11050, 10000, 1, 10)).plot()   #巴特沃斯高通滤波器,指定通带截止频率为11050Hz、阻带截止频率为10000Hz,通带功率最多损失1dB,
阻带功率至少衰减10dB

python音源响度对齐 python调音器_音视频_126

同样以11050Hz为通带截止频率,阻带截止频率为5000Hz时和阻带截止频率为10000Hz时相比,通带到阻带的衰减速度就慢得多。