【音频处理】短时傅里叶变换

前言

上一篇博客讲了离散傅里叶变换,里面的实例是对整个信号进行计算,虽然理论上有N点傅里叶变换(本博客就不区分FFT和DFT了,因为它俩就是一个东东,只不过复杂度不同),但是我个人理解是这个N点是信号前面连续的N个数值,即N点FFT意思就是截取前面N个信号进行FFT,这样就要求我们的前N个采样点必须包含当前信号的一个周期,不然提取的余弦波参数与正确的叠加波的参数相差很大。

如果在N点FFT的时候,如果这N个采样点不包含一个周期呢?或者说我们的信号压根不是一个周期函数咋办?或者有一段是噪音数据呢?如果用FFT计算,就会对整体结果影响很大,然后就有人想通过局部来逼近整体,跟微积分的思想很像,将信号分成一小段一小段,然后对每一小段做FFT,就跟分段函数似的,无数个分段函数能逼近任意的曲线((⊙o⊙)…应该没错吧),这样每一段都不会互相影响到了。

下面的参考博客中有一篇的一句话很不错:在短时傅里叶变换过程中,窗的长度决定频谱图的时间分辨率和频率分辨率,窗长越长,截取的信号越长,信号越长,傅里叶变换后频率分辨率越高,时间分辨率越差;相反,窗长越短,截取的信号就越短,频率分辨率越差,时间分辨率越好,也就是说短时傅里叶变换中,时间分辨率和频率分辨率之间不能兼得,应该根据具体需求进行取舍。

国际惯例,参考博客:

基于MATLAB短时傅里叶变换和小波变换的时频分析

小波前奏–短时傅里叶变换

短时傅里叶变换原理解

matlab自带的短时傅里叶变换函数spectrogram

理论及实现

其实就是多了几个参数,需要指定的有:

  • 每个窗口的长度:nsc
  • 每相邻两个窗口的重叠率:nov
  • 每个窗口的FFT采样点数:nff

可以计算的有:

  • 海明窗:w=hamming(nsc, 'periodic')

  • 信号被分成了多少片: l e n ( S ) n s c n s c n o v

  • 短时傅里叶变换:

    X ( k ) = n = 1 N w ( n ) x ( n ) e x p ( j 2 π ( k 1 ) ( n 1 ) / N ) , 1 <= k <= N

    其实和FFT的公式一样,只不过多了个海明窗加权

直接撸代码:

①先设置参数:

%默认设置:
% nsc=floor(L/4.5);%海明窗的长度
% nov=floor(nsc/2);%重叠率
% nff=max(256,2^nextpow2(nsc));%N点采样长度
%也可手动设置
nsc=100;%海明窗的长度,即每个窗口的长度
nov=30;%重叠率
nff=256;%N点采样长度

这里面有个默认设置,就是调用matlab自带的短时傅里叶变换时,如果没指定相关参数,就会采用默认参数值,这个可以去mathwork官网看。

②计算海明窗以及初始化结果值:

h=hamming(nsc, 'periodic');%计算海明窗的数值,给窗口内的信号加权重
coln = 1+fix((L-nsc)/(nsc-nov));%信号被分成了多少个片段
%如果nfft为偶数,则S的行数为(nfft/2+1),如果nfft为奇数,则行数为(nfft+1)/2
%因为matlab的FFT结果是对称的,只需要一半
rown=nff/2+1;
STFT_X=zeros(rown,coln);%初始化最终结果

这里的信号被划分的片段数目可以按照卷积的方法计算

③对每个片段码公式:

%对每个片段进行fft变换
index=1;%当前片段第一个信号位置在原始信号中的索引
for i=1:coln
    %提取当前片段信号值,并用海明窗进行加权
    temp_S=S(index:index+nsc-1).*h';
    %进行N点FFT变换
    temp_X=fft(temp_S,nff);
    %取一半
    STFT_X(:,i)=temp_X(1:rown)';
    %将索引后移
    index=index+(nsc-nov);
end

可以发现我这里没码公式,因为上一篇博客证明了手撸的DFT与matlab自带的FFT公式一样,有高度强迫症的可以把上一篇博客的DFT写成一个函数,然后把此处的FFT换成你的函数名即可。注意这里的关键操作有两点:

  • 对当前窗口的输入信号进行海明加权
  • 窗口中输入信号的获取方法有点类似于卷积,卷积核大小是1*nsc,步长是nsc-nov

④正确性验证:与matlab自带的STFT函数spectrogram的结果进行比较:

%% matlab自带函数
[spec_s,spec_f,spec_t]=spectrogram(S,hamming(nsc, 'periodic'),nov,nff,Fs);
%减法,看看差距
plot(abs(spec_s)-abs(STFT_X))

这里写图片描述

啥也不说了,稳如狗

后记

感觉对于FFT的理解告一段落,先把蝶形算法搁着,下一步就是折腾常Q变换(Constant-Q transform)了,目前的用处是一个音乐的一拍可能有很多音组合而成,但是每个音的频率又不一样,那么就需要设置不同的窗口进行采样,相当于进行了多次STFT操作,只不过每次的窗口大小不同罢了,有兴趣可以看一波论文:《Calculation of a constant Q spectral transform 》,有张图介绍了CQT和DFT的区别,具体我还在研究。

这里写图片描述

猜你喜欢

转载自blog.csdn.net/zb1165048017/article/details/80682473