【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域

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

API速查手册

通过pip安装:

pip install pyAudioKits

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

上节中对乐音和噪音的分析使用的方式均为时域分析的方法。本节我们将引入频域的概念,并介绍如何在频域分析音频信号。

傅里叶变换

连续时间信号傅里叶变换

我们说连续时间周期信号可以展开为频率为 ω 0 \omega_0 ω0的基波和频率为 ( k + 1 ) ω 0 ( k = 1 , 2 , . . . ) (k+1)\omega_0(k=1,2,...) (k+1)ω0k=1,2,...的谐波。也就是说我们不仅可以使用原来的 x ( t ) x(t) x(t)来表示连续时间周期信号,只要知道基波和谐波的频率以及振幅,就可以用频率和振幅来表示连续时间周期信号了。因此,我们现在假设有一个频率轴,上面有无数的频点 ω \omega ω,就可以尝试将原本时间轴上的一维信号 x ( t ) x(t) x(t)映射到频率轴上,变成 X ( j ω ) X(j\omega) X(),完成时域到频域的映射。

使用最小二乘法,保证时域表示和频域表示能量相差最小。为了达成这一条件的结论是:设所有频点的值为 a k a_k ak乘上 2 π 2\pi 2π。表示成频谱密度函数,有 X ( j ω ) = ∑ k = − ∞ ∞ 2 π a k δ ( ω − k ω 0 ) X(j\omega)=\displaystyle\sum_{k=-∞}^∞2\pi a_k\delta(\omega-k\omega_0) X()=k=2πakδ(ωkω0)。可见周期信号的频谱密度函数是离散的冲激函数线性叠加。该函数可以通过 x ( t ) = 1 2 π ∫ − ∞ ∞ X ( j ω ) e j ω t d ω x(t)=\frac{1}{2\pi}\displaystyle\int_{-∞}^∞X(j\omega)e^{j\omega t}d\omega x(t)=2π1X()etdω还原为时域中的傅里叶级数表示 x ( t ) = ∑ k = − ∞ ∞ a k e j k ω 0 t x(t)=\displaystyle\sum_{k=-∞}^∞a_ke^{jk\omega_0t} x(t)=k=akejkω0t

那么非周期信号能不能映射到频域呢?答案是肯定的。假如基波频率 ω 0 \omega_0 ω0无限小,即基波周期 T T T无限大,则可以表示任意(无论是否周期)信号的频域特性,此时就从傅里叶级数推广到了傅里叶变换:基波频率 ω 0 \omega_0 ω0无限小,因此 k ω 0 k\omega_0 kω0视为连续值 ω \omega ω X ( j ω ) = ∫ − ∞ ∞ x ( t ) e − j ω t d t X(j\omega)=\displaystyle\int_{-∞}^∞x(t)e^{-j\omega t}dt X()=x(t)etdt。此时得到连续时间傅里叶变换的综合方程 x ( t ) = 1 2 π ∫ − ∞ ∞ X ( j ω ) e j ω t d ω x(t)=\frac{1}{2\pi}\displaystyle\int_{-∞}^∞X(j\omega)e^{j\omega t}d\omega x(t)=2π1X()etdω分析方程 X ( j ω ) = ∫ − ∞ ∞ x ( t ) e − j ω t d t X(j\omega)=\displaystyle\int_{-∞}^∞x(t)e^{-j\omega t}dt X()=x(t)etdt。可见非周期信号的频谱密度函数是连续函数

当连续时间周期信号的周期逐渐扩大 ω 0 \omega_0 ω0就逐渐缩小,组成 X ( j ω ) X(j\omega) X()冲激函数就越密集。当周期无限大时, ω 0 \omega_0 ω0无限小, X ( j ω ) X(j\omega) X()成为连续函数,就得到了连续时间非周期信号频谱密度函数。

离散时间信号傅里叶变换

可是我们在计算机中储存的信号都是数字信号,也就是离散时间信号,它们怎么映射到频域呢?

还记得模拟信号到数字信号(在我们这里也就等价于连续时间信号到离散时间信号)使用了一个采样的操作。信号在时域乘上冲激串 p ( t ) = ∑ n = − ∞ + ∞ δ ( t − n T s ) p(t)=\displaystyle\sum_{n=-∞}^{+∞}\delta(t-nT_s) p(t)=n=+δ(tnTs)可以实现采样。采样后的时域表示为 x s ( t ) = x ( t ) p ( t ) = ∑ n = − ∞ + ∞ x ( t ) δ ( t − n T s ) x_s(t)=x(t)p(t)=\displaystyle\sum_{n=-∞}^{+∞}x(t)\delta(t-nT_s) xs(t)=x(t)p(t)=n=+x(t)δ(tnTs)。采样后的频域表示为 X s ( j ω ) = 1 2 π X ( j ω ) ∗ P ( j ω ) = 1 T s ∑ k = − ∞ + ∞ X ( j ( ω − k ω s ) ) X_s(j\omega)=\frac{1}{2\pi}X(j\omega)*P(j\omega)=\frac{1}{T_s}\displaystyle\sum_{k=-∞}^{+∞}X(j(\omega-k\omega_s)) Xs()=2π1X()P()=Ts1k=+X(j(ωkωs)),我们发现此时 X s ( j ω ) X_s(j\omega) Xs() X ( j ω ) X(j\omega) X()在频谱上以采样频率为基数的周期性延拓的结果,其周期为 ω s = 2 π / T s \omega_s=2\pi/T_s ωs=2π/Ts且一个周期内就包含了所有的频谱信息。此时得到离散时间信号傅里叶变换的综合方程 x [ n ] = 1 2 π ∫ 2 π T s X ( j ω ) e j ω n T s d ω x[n]=\frac{1}{2\pi}\displaystyle\int_{\frac{2\pi}{T_s}}X(j\omega)e^{j\omega nT_s}d\omega x[n]=2π1Ts2πX()ejωnTsdω分析方程 X ( j ω ) = ∑ n = − ∞ + ∞ x [ n ] e − j ω n T s X(j\omega)=\displaystyle \sum_{n=-∞}^{+∞}x[n]e^{-j\omega nT_s} X()=n=+x[n]ejωnTs

此时综合方程和分析方程与采样周期 T s T_s Ts是有关的。为了使它们与采样周期 T s T_s Ts无关,我们将频域也用因子 T s T_s Ts(即采样率的倒数)归一化,记为 X ( e j ω ) = X ( j ω T s ) X(e^{j\omega})=X(j\omega T_s) X(e)=X(Ts),得到离散时间信号傅里叶变换的综合方程 x [ n ] = 1 2 π ∫ 2 π X ( e j ω ) e j ω n d ω x[n]=\frac{1}{2\pi}\displaystyle\int_{2\pi}X(e^{j\omega})e^{j\omega n}d\omega x[n]=2π12πX(e)ejωndω分析方程 X ( e j ω ) = ∑ n = − ∞ + ∞ x [ n ] e − j ω n X(e^{j\omega})=\displaystyle \sum_{n=-∞}^{+∞}x[n]e^{-j\omega n} X(e)=n=+x[n]ejωn。此时 X ( e j ω ) X(e^{j\omega}) X(e)中, ω \omega ω的每 1 r a d / s 1 rad/s 1rad/s实际代表频率 1 2 π T s H z ( 1 T s r a d / s ) \frac{1}{2\pi T_s}Hz(\frac{1}{T_s}rad/s) 2πTs1Hz(Ts1rad/s) X ( e j ω ) X(e^{j\omega}) X(e) 2 π 2\pi 2π为周期。

离散傅里叶变换

现在问题又来了,还记得我们为什么要对模拟信号 x ( t ) , − ∞ < t < ∞ x(t),-∞x(t),<t<采样变成 x [ n ] , 0 ≤ n < N m a x x[n],0≤nx[n],0n<Nmax吗?这是因为计算机无法储存原来的模拟信号,因为模拟信号是连续的,可能还是无限的、非因果的。那么频谱密度函数 X ( e j ω ) , − ∞ < ω < ∞ X(e^{j\omega}),-∞<\omega<∞ X(e),<ω<实际上也面临着一样的问题。我们也需要对这个频谱密度函数进行一些“采样”操作。

令周期冲激串 p ~ [ n ] = ∑ r = − ∞ ∞ δ [ n − r N ] \tilde p[n]=\displaystyle\sum_{r=-∞}^∞\delta[n-rN] p~[n]=r=δ[nrN],则有 x ~ [ n ] = x [ n ] ∗ p ~ [ n ] \tilde x[n]=x[n]*\tilde p[n] x~[n]=x[n]p~[n],此时 X ~ ( e j ω ) = X ( e j ω ) P ~ ( e j ω ) = X ( e j ω ) ∑ k = − ∞ ∞ 2 π N δ ( ω − 2 π k N ) \tilde X(e^{j\omega})=X(e^{j\omega})\tilde P(e^{j\omega})=X(e^{j\omega})\displaystyle\sum_{k=-∞}^∞\frac{2\pi}{N}\delta(\omega-\frac{2\pi k}{N}) X~(e)=X(e)P~(e)=X(e)k=N2πδ(ωN2πk),则有 X [ k ] = X ( e j ω ) ∣ ω = 2 π k N X[k]=X(e^{j\omega})|_{\omega=\frac{2\pi k}{N}} X[k]=X(e)ω=N2πk,从而在频域完成采样。使用 W N W_N WN代替 e − j 2 π N e^{-j\frac{2\pi}{N}} ejN2π有:

X [ k ] = ∑ n = 0 N − 1 x ~ [ n ] e − j k ( 2 π N ) n = ∑ n = 0 N − 1 x ~ [ n ] W N k n X[k]=\displaystyle \sum_{n=0}^{N-1} \tilde x[n]e^{-jk(\frac{2\pi}{N})n}=\sum_{n=0}^{N-1} \tilde x[n]W_N^{kn} X[k]=n=0N1x~[n]ejk(N2π)n=n=0N1x~[n]WNkn

x ~ [ n ] = 1 2 π ∫ 2 π X ( e j ω ) ∣ ω = 2 π k N e j ω n d ω = 1 N ∑ k = 0 N − 1 X [ k ] e j k ( 2 π N ) n = 1 N ∑ k = 0 N − 1 X [ k ] W N − k n \tilde x[n]=\frac{1}{2\pi}\displaystyle\int_{2\pi}X(e^{j\omega})|_{\omega=\frac{2\pi k}{N}}e^{j\omega n}d\omega=\displaystyle\frac{1}{N}\displaystyle\sum_{k=0}^{N-1} X[k]e^{jk(\frac{2\pi}{N})n}=\frac{1}{N}\displaystyle\sum_{k=0}^{N-1} X[k]W_{N}^{-kn} x~[n]=2π12πX(e)ω=N2πkejωndω=N1k=0N1X[k]ejk(N2π)n=N1k=0N1X[k]WNkn

时域 N N N为周期进行周期延拓变为 x ~ [ n ] \tilde x[n] x~[n]。原本有 x [ n ] = { x d [ n ] 0 ≤ n < N m a x 0 o t h e r s x[n]=\begin{cases}x_d[n]\quad 0≤nx[n]={xd[n]0n<Nmax0others,现在则有 x ~ [ n ] = ∑ r = − ∞ ∞ x [ n − r N ] \displaystyle\tilde x[n]=\sum_{r=-∞}^∞x[n-rN] x~[n]=r=x[nrN]周期延拓后的信号 x ~ [ n ] \tilde x[n] x~[n]可能拥有和 x ( t ) x(t) x(t)不同的频率成分

原本 X ( e j ω ) X(e^{j\omega}) X(e)中, ω \omega ω的每 1 r a d / s 1 rad/s 1rad/s实际代表频率 1 2 π T s H z ( 1 T s r a d / s ) \frac{1}{2\pi T_s}Hz(\frac{1}{T_s}rad/s) 2πTs1Hz(Ts1rad/s),现在 X ~ [ k ] \tilde X[k] X~[k]中每个 k k k实际代表 1 T s N H z ( 2 π T s N r a d / s ) \frac{1}{T_sN}Hz(\frac{2\pi}{T_sN}rad/s) TsN1Hz(TsN2πrad/s)的频率。称每个k为频谱中的一个频点,实际代表的频率为频谱分辨率。采样不能完整地表示出频谱,有些时候会遗漏频谱中的频率成分,这被称为栅栏效应。然而时频域依然满足能量相等的条件,被遗漏的频率成分的能量就会被泄露到附近的频点上,从而导致信号出现新的频率成分,这被称为频谱泄漏

还记得 X ( e j ω ) X(e^{j\omega}) X(e)的周期为 2 π T s \frac{2\pi}{T_s} Ts2π吗?这意味着我们只需要取频谱中连续的 N N N个频点即可得到频谱的所有信息。加上实信号的频谱关于 ω = 0 \omega=0 ω=0对称,我们观察频谱时只需要取频谱中连续的 N / 2 N/2 N/2个频点即可,即绘制频谱时一般只取 X [ k ] , 0 ≤ k < N 2 X[k],0≤k<\frac{N}{2} X[k],0k<2N

由于 X [ k ] X[k] X[k]为复数,频谱还分为幅度谱相位谱,分别为 ∣ X [ k ] ∣ |X[k]| X[k] ∠ X [ k ] ( r a d / s ) \angle X[k] (rad/s) X[k](rad/s)

def periodicExtension(p,N): #模拟进行3次周期延拓的函数。p为需要周期延拓的信号,N则是周期延拓的周期
    L = 3 * N
    p = ak.concatenate([ak.create_Single_Freq_Audio(0,0,p.sr,L/p.sr),p,ak.create_Single_Freq_Audio(0,0,p.sr,L/p.sr)])
    p1 = p[0:L]
    for i in range(N,len(p.samples)-L,N):
        p1 = p1 + p[i:i+L]
    return p1
import pyAudioKits.analyse as aly

p1 = ak.create_Single_Freq_Audio(0.1,8,256,1)   #创建振幅为0.1,频率为8Hz,采样率为256Hz,持续时间1s的正弦信号
p1.plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第1张图片

aly.FFT(p1,16).plot()   #进行16点傅里叶变换,并默认绘制幅度谱

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第2张图片

x[n]采样自8Hz的正弦波x(t),在幅度谱上却体现不出8Hz的峰值。因为此时频谱分辨率为 256 / 16 = 16 H z 256/16=16Hz 256/16=16Hz,大于信号频率8Hz,因此出现栅栏效应和频谱泄漏。

periodicExtension(p1,16).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第3张图片

同时在时域我们也可以看到, x [ n ] x[n] x[n]在以16点为周期进行周期延拓得到的 x ~ [ n ] \tilde x[n] x~[n]不再以0.125s为周期。

aly.FFT(p1,32).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第4张图片

使用32点傅里叶变换时,此时频谱分辨率为 256 / 32 = 8 H z 256/32=8Hz 256/32=8Hz,正好等于信号频率8Hz。因此我们可以看到8Hz的峰值被体现了出来,不会观察到栅栏效应和频谱泄漏。

periodicExtension(p1,32).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第5张图片

从时域上我们可以看到 x ~ [ n ] \tilde x[n] x~[n]依然以0.125s为周期。

使用不同的频率轴刻度来观察真实频率 f f f、以角频率表示的真实频率 ω s \omega_s ωs、归一化频率 ω \omega ω、频点的对应关系。

aly.FFT(p1,32).plot(xlabel="frequency/(rad/s)") #使用角频率表示的频率

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第6张图片

aly.FFT(p1,32).plot(xlabel="normalized frequency/(rad/s)")  #归一化角频率,0~采样率/2 就对应 0~π

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第7张图片

aly.FFT(p1,32).plot(xlabel="freq point")	#频点。32点傅里叶变换在[0,采样率/2)之间有16个频点

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第8张图片

再来看信号中有两个频率成分(8Hz和32Hz的情况)。

p2 = p1 + ak.create_Single_Freq_Audio(0.1,32,256,1)
p2.plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第9张图片

aly.FFT(p2,16).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第10张图片

使用16点FFT时,频谱分辨率为 256 / 16 = 16 H z 256/16=16Hz 256/16=16Hz,小于信号频率32Hz且可以被32Hz整除,但大于信号频率8Hz。因此在32Hz处不会出现频谱泄漏和栅栏效应,但在8Hz处会。

aly.FFT(p2,32).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第11张图片

使用32点FFT时,频谱分辨率为 256 / 32 = 8 H z 256/32=8Hz 256/32=8Hz,小于信号频率且信号频率是频谱分辨率的整数倍,此时可以分辨出8Hz和32Hz的峰值,不会出现栅栏效应和频谱泄漏。

aly.FFT(p2,64).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第12张图片

使用64点FFT时,频谱分辨率为 256 / 64 = 4 H z 256/64=4Hz 256/64=4Hz,频谱进一步细化。

aly.FFT(p2).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第13张图片

默认情况下,使用全256点进行FFT,频谱分辨率为 256 / 256 = 1 H z 256/256=1Hz 256/256=1Hz,不会产生频谱泄漏和栅栏效应。

aly.FFT(p2,512).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第14张图片

periodicExtension(p2,512).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第15张图片

使用512点FFT相当于在256个样本后补256个0再进行周期延拓。此时信号中出现新的频率成分,因此产生频谱泄漏和栅栏效应。

p3 = p2[0:48]
aly.FFT(p3).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第16张图片

取前48个样本点对信号进行截断,此时使用全48点进行FFT,频谱分辨率为 256 / 48 = 5.3 H z 256/48=5.3Hz 256/48=5.3Hz 5.3 H z 5.3Hz 5.3Hz可以被32Hz整除,但不可以被8Hz整除。因此在32Hz处不会出现频谱泄漏和栅栏效应,但在8Hz处会。

p2.plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第17张图片

periodicExtension(p3,48).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第18张图片

周期延拓的结果也显示了新的频率成分。

aly.FFT(p3,32).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第19张图片

此时使用32点FFT依然不会观察到频谱泄漏和栅栏效应。

periodicExtension(p3,32).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第20张图片

周期延拓时不会出现新的频率成分。

aly.FFT(p3,256).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第21张图片

由于本身信号被截断为48点,再使用256点FFT也只是对补0后的信号进行FFT。因此必然出现新的频率成分。

说了这么多大家应该也已经发现了,从时域上看周期延拓带来的新的频率成分,和从频域上看由栅栏效应带来的频谱泄漏,其实是同一现象的两种解释罢了。那么有没有一个统一的方法量化这一影响呢?就是说所谓新的频率成分到底是多少?

还记得我们一开始对音频信号进行过截断吗?截断的时候用到了窗函数 w [ n ] w[n] w[n] x [ n ] = x d [ n ] w [ n ] x[n]=x_d[n]w[n] x[n]=xd[n]w[n],所以 X ( e j ω ) = 1 2 π ∫ 2 π X d ( e j θ ) W ( e j ( ω − θ ) ) d θ X(e^{j\omega})=\frac{1}{2\pi}\displaystyle\int_{2\pi}X_d(e^{j\theta})W(e^{j(\omega-\theta)})d\theta X(e)=2π12πXd(ejθ)W(ej(ωθ))dθ,也就是说 x [ n ] x[n] x[n]的频谱是 x d [ n ] x_d[n] xd[n]的频谱与窗函数频谱的卷积。 w [ n ] = { 1 0 ≤ n < N m a x 0 o t h e r s w[n]=\begin{cases}1\quad 0≤nw[n]={10n<Nmax0others的频谱为 W ( e j ω ) = 1 − e − j ω N m a x 1 − e − j ω W(e^{j\omega})=\frac{1-e^{-j\omega N_{max}}}{1-e^{-j\omega}} W(e)=1e1eNmax。假设 x d [ n ] = s i n ω 0 n x_d[n]=sin\omega_0n xd[n]=sinω0n采样自正弦波 x ( t ) = s i n ω 0 t x(t)=sin\omega_0t x(t)=sinω0t,其频谱为 X d ( e j ω ) = π j ∑ l = − ∞ + ∞ [ δ ( ω − ω 0 − 2 π l ) − δ ( ω + ω 0 − 2 π l ) ] X_d(e^{j\omega})=\frac{\pi}{j}\displaystyle\sum_{l=-∞}^{+∞}[\delta(\omega-\omega_0-2\pi l)-\delta(\omega+\omega_0-2\pi l)] Xd(e)=jπl=+[δ(ωω02πl)δ(ω+ω02πl)]。则 X ( e j ω ) = π j ∑ l = − ∞ + ∞ [ 1 − e − j ( ω − ω 0 − 2 π l ) N m a x 1 − e − j ( ω − ω 0 − 2 π l ) + 1 − e − j ( ω + ω 0 − 2 π l ) N m a x 1 − e − j ( ω + ω 0 − 2 π l ) ] X(e^{j\omega})=\frac{\pi}{j}\displaystyle\sum_{l=-∞}^{+∞}[\frac{1-e^{-j(\omega-\omega_0-2\pi l) N_{max}}}{1-e^{-j(\omega-\omega_0-2\pi l)}}+\frac{1-e^{-j(\omega+\omega_0-2\pi l) N_{max}}}{1-e^{-j(\omega+\omega_0-2\pi l)}}] X(e)=jπl=+[1ej(ωω02πl)1ej(ωω02πl)Nmax+1ej(ω+ω02πl)1ej(ω+ω02πl)Nmax]。如果采样取 ω = 2 π k N \omega=\frac{2\pi k}{N} ω=N2πk,则有 X [ k ] = X ( e j ω ) ∣ ∗ ω = 2 π k N = π j ∑ ∗ l = − ∞ + ∞ [ 1 − e − j ( 2 π k N − 2 π k 0 N − 2 π l ) N m a x 1 − e − j ( 2 π k N − 2 π k 0 N − 2 π l ) + 1 − e − j ( 2 π k N + 2 π k 0 N − 2 π l ) N m a x 1 − e − j ( 2 π k N + 2 π k 0 N − 2 π l ) ] = π j ∑ l = − ∞ + ∞ [ 1 − e − j ( 2 π k N − 2 π N 0 − 2 π l ) N m a x 1 − e − j ( 2 π k N − 2 π N 0 − 2 π l ) + 1 − e − j ( 2 π k N + 2 π N 0 − 2 π l ) N m a x 1 − e − j ( 2 π k N + 2 π N 0 − 2 π l ) ] \begin{aligned}X[k]=X(e^{j\omega})|*_{\omega=\frac{2\pi k}{N}}&=\frac{\pi}{j}\displaystyle\sum_*{l=-∞}^{+∞}[\frac{1-e^{-j(\frac{2\pi k}{N}-\frac{2\pi k_0}{N}-2\pi l) N_{max}}}{1-e^{-j(\frac{2\pi k}{N}-\frac{2\pi k_0}{N}-2\pi l)}}+\frac{1-e^{-j(\frac{2\pi k}{N}+\frac{2\pi k_0}{N}-2\pi l) N_{max}}}{1-e^{-j(\frac{2\pi k}{N}+\frac{2\pi k_0}{N}-2\pi l)}}]\\&=\frac{\pi}{j}\displaystyle\sum_{l=-∞}^{+∞}[\frac{1-e^{-j(\frac{2\pi k}{N}-\frac{2\pi}{N_0}-2\pi l) N_{max}}}{1-e^{-j(\frac{2\pi k}{N}-\frac{2\pi}{N_0}-2\pi l)}}+\frac{1-e^{-j(\frac{2\pi k}{N}+\frac{2\pi}{N_0}-2\pi l) N_{max}}}{1-e^{-j(\frac{2\pi k}{N}+\frac{2\pi}{N_0}-2\pi l)}}]\end{aligned} X[k]=X(e)ω=N2πk=jπl=+[1ej(N2πkN2πk02πl)1ej(N2πkN2πk02πl)Nmax+1ej(N2πk+N2πk02πl)1ej(N2πk+N2πk02πl)Nmax]=jπl=+[1ej(N2πkN02π2πl)1ej(N2πkN02π2πl)Nmax+1ej(N2πk+N02π2πl)1ej(N2πk+N02π2πl)Nmax],其中 k 0 = ω 0 N 2 π k_0=\frac{\omega_0N}{2\pi} k0=2πω0N X [ k ] X[k] X[k]中代表 ω 0 \omega_0 ω0的频点, N 0 = 2 π ω 0 N_0=\frac{2\pi}{\omega_0} N0=ω02π为以 x [ n ] x[n] x[n]中样本点数表示的正弦波周期。这样,当 N m a x N_{max} Nmax N N N的整数倍且 N m a x N_{max} Nmax N 0 N_0 N0整数倍时, X [ k ] X[k] X[k]仅在 ± k 0 + N l , l ∈ Z \pm k_0+Nl,l\in Z ±k0+Nl,lZ处有值,其余部分都是0,此时窗函数的频谱被隐藏了,我们只会看到 x d [ n ] x_d[n] xd[n]的频谱;其他情况下,窗函数的频谱则会被显示出来

也就是说,想要屏蔽窗函数的频谱,就必须满足:

  1. 截断点数是离散傅里叶变换点数的整数倍

  2. 截断点数是信号所有分量的周期的整数倍

不满足这些条件的情况下,我们就会在频谱上观测到窗函数的频谱,这就是周期延拓带来的“新的”频率成分,以及频谱泄漏产生的“新的”频率成分。第二个条件是非常苛刻的,实际应用中往往无法满足。因此观测到窗函数的频谱是非常非常正常的现象。

input1 = ak.create_Single_Freq_Audio(0.02,8,256,1)
aly.FFT(input1,256).plot(0, 256)

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第22张图片

对于采样率为 256 H z 256Hz 256Hz的音频,取傅里叶变换的点数 N = 256 N=256 N=256以计算幅度谱,则每个频点代表 1 H z 1Hz 1Hz的真实频率,幅度谱的频点 k = 0 k=0 k=0 k = 255 k=255 k=255就涵盖了 0 H z 0Hz 0Hz 255 H z 255Hz 255Hz上所有的功率信息。我们发现幅度谱上有两个峰值,其中左边的峰值出现在单音的频率 8 H z 8Hz 8Hz对应的频点上。实信号的幅度谱关于 ω = 0 \omega=0 ω=0偶对称,因此在对应 − 8 H z -8Hz 8Hz的频点上也会出现一个峰值,而这个峰值经过以采样率 256 H z 256Hz 256Hz为周期的周期延拓后,就出现在了 256 − 8 = 248 H z 256 - 8 = 248 Hz 2568=248Hz对应的频点上,即功率谱上右边的峰值。

import numpy as np

aly.FFT(input1,256).plot(0, 2*np.pi, xlabel="normalized frequency/(rad/s)")

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第23张图片

若使用归一化频率来作为横坐标,则我们发现幅度谱关于 ω = π \omega=\pi ω=π对称。事实上,如果我们绘制 ω ∈ ( − ∞ , ∞ ) \omega\in (-∞,∞) ω(,)的幅度谱,则还会发现幅度谱以 ω = 2 π \omega=2\pi ω=2π为周期,且关于 ω = n π , n ∈ Z \omega=n\pi, n\in \mathbb Z ω=,nZ偶对称。

import numpy as np

aly.FFT(input1,256).plot(0, 2*np.pi, plot_type = "phase", xlabel="normalized frequency/(rad/s)")

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第24张图片

实信号的相位谱也具有对称的特性,且也以 ω = 2 π \omega=2\pi ω=2π为周期,但它是关于 ω = n π , n ∈ Z \omega=n\pi, n\in \mathbb Z ω=,nZ奇对称的。

能量谱和功率谱

除了频谱之外,能量谱和功率谱也是能够在频域描述信号特点的函数。能量谱和功率谱的理论基础是帕塞瓦尔定理,即时域内信号能量等于频域内信号能量。对于能量有限信号而言,根据帕塞瓦尔定理,其能量为 E = ∫ − ∞ ∞ x 2 ( t ) d t = ∫ − ∞ ∞ ∣ X ( j ω ) ∣ 2 d ω E=\displaystyle\int_{-∞}^∞x^2(t)dt=\int_{-∞}^∞|X(j\omega)|^2d\omega E=x2(t)dt=X()2dω,而能量谱密度就为 G ( j ω ) = ∣ X ( j ω ) ∣ 2 G(j\omega)=|X(j\omega)|^2 G()=X()2。对于功率有限信号而言,首先将 x ( t ) x(t) x(t)截短为长度等于T的一个截短信号 x T ( t ) , − T / 2 < t < T / 2 x_T(t),-T/2xT(t),T/2<t<T/2,使其成为能量有限信号。根据帕塞瓦尔定理,其能量为 E = ∫ − ∞ ∞ x T 2 ( t ) d t = ∫ − ∞ ∞ ∣ X T ( j ω ) ∣ 2 d ω E=\displaystyle\int_{-∞}^{∞}x_T^2(t)dt=\int_{-∞}^{∞}|X_T(j\omega)|^2d\omega E=xT2(t)dt=XT()2dω,而信号功率为 P = lim ⁡ T → ∞ 1 T ∫ − ∞ ∞ ∣ X T ( j ω ) ∣ 2 d ω P=\displaystyle\lim_{T\rightarrow ∞}\frac{1}{T}\int_{-∞}^{∞}|X_T(j\omega)|^2d\omega P=TlimT1XT()2dω,则有功率谱密度 P ( j ω ) = lim ⁡ T → ∞ 1 T ∣ X T ( j ω ) ∣ 2 P(j\omega)=\displaystyle\lim_{T\rightarrow ∞}\frac{1}{T}|X_T(j\omega)|^2 P()=TlimT1XT()2

由于我们对音频信号进行了加窗截断,因此所有信号都是能量和功率有限信号。我们仅关心其功率谱密度,计算式为 P [ k ] = 1 N m a x ∣ X [ k ] ∣ 2 P[k]=\frac{1}{N_{max}}|X[k]|^2 P[k]=Nmax1X[k]2

import matplotlib.pyplot as plt

input1 = ak.create_Single_Freq_Audio(0.02,8,256,1)
aly.PSD(input1, 256).plot(0,32,xlabel="frequency/Hz")

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第25张图片

功率谱也可以使用增益的形式来表示。

aly.PSD(input1, 256, dB=True).plot(0,32,xlabel="frequency/Hz")

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第26张图片

当信号中同时有两个频率成分时,两个频率成分的功率信息都会被反映到功率谱上。

input2 = ak.create_Single_Freq_Audio(0.01,24,256,1)
aly.PSD(input1 + input2, 256).plot(0,32,xlabel="frequency/Hz")

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第27张图片

其中由于input2的振幅是input1的一半,所以 16 H z 16Hz 16Hz上的功率谱密度是 8 H z 8Hz 8Hz上的四分之一。

噪音的频域特性

和确定性周期信号以及具有明显音高的乐音不同,噪音是没有明显音高,即没有明显周期性的。乐音可以在幅度谱和功率谱上体现出明显的峰值,而噪音的频率成分则呈现连续而随机的分布。

白噪音的频率成分均匀分布在整个频率范围内。

monotone_without_wn = ak.create_Single_Freq_Audio(0.02,440,44100,1)
monotone_with_wn = monotone_without_wn.addWgn(10)   #在单音上加上信噪比为10dB的高斯白噪音
wn = monotone_with_wn - monotone_without_wn #减去单音,只留下白噪音
aly.FFT(wn).plot(), aly.PSD(wn).plot()

【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第28张图片【基于pyAudioKits的Python音频信号处理(四)】傅里叶变换:从时域到频域_第29张图片

你可能感兴趣的:(python,音视频)