语音的特征提取

it2024-11-12  4

获得语音信号的fbank特征和MFCC特征的一般步骤是:预加重、分帧、加窗、短时傅里叶变换(STFT)、mel滤波、去均值等。对fbank做离散余弦变换(DCT)即可获得mfcc特征。 PS:“log mel-filter bank outputs”和“FBANK features”说的是同一个东西。

Step0 MFCC

倒谱参数:

MFCCs(Mel Frequency Cepstral Coefficents):是在Mel标度频率域提取出来的倒谱参数,是一种在自动语音和说话人识别中广泛使用的特征。

Mel标度描述了人耳频率的非线性特性,它与频率的关系可用下式近似表示: M e l ( f ) = 2595 × l g ( 1 + f 700 ) Mel(f)=2595×lg(1+\frac{f}{700}) Mel(f)=2595×lg(1+700f) 在这个频域内,人对音调的感知度为线性关系。

Step1 预加重

针对录音时高频信号丢失:

在音频录制过程中,高频信号更容易衰减,而像元音等一些因素的发言包含了较多的高频信号的成分,高频信号的丢失,可能会导致音素的共振峰并不明显,使得声学模型对这些音素的建模能力不强。

预加重处理其实是将语音信号通过一个高通滤波器,可以提高信号高频部分的能量,给定时域输入信号x[n],预加重之后信号为: y ( t ) = x ( t ) − α x ( t − 1 ) , 0.9 ≤ α ≤ 1.0 y(t)=x(t)-\alpha x(t-1), 0.9\le \alpha \le 1.0 y(t)=x(t)αx(t1),0.9α1.0 公式理解:

信号频率的高低主要是由信号电平变化的速度所决定,对信号做一阶差分时,高频部分(变化快的地方)差分值大,低频部分(变化慢的地方)差分值小,达到平衡频谱的作用。

pre_emphasis = 0.97 sig = np.append(sig[0], sig[1:] - pre_emphasis * sig[:-1]) plot_time(sig, fs)

Step2 分针加窗

分帧:帧长0.025s、帧移0.01s

为了减少语音信号整体的非稳态、时变的影响,从而对语音信号进行分段处理,其中每一段称为一帧,一般取25ms。为了使帧与帧之间平滑过渡,保持其连续性,分帧一般采用交叠分段的方法,保证相邻两帧相互重叠一部分。相邻两帧的起始位置的时间差称为帧移,一般取10ms. frame_size, frame_stride = 0.025, 0.01 frame_length, frame_step = int(round(frame_size * sample_rate)), int(round(frame_stride * sample_rate)) signal_length = len(emphasized_signal) num_frames = int(np.ceil(np.abs(signal_length - frame_length) / frame_step)) + 1 pad_signal_length = (num_frames - 1) * frame_step + frame_length z = np.zeros((pad_signal_length - signal_length)) pad_signal = np.append(emphasized_signal, z) indices = np.arange(0, frame_length).reshape(1, -1) + np.arange(0, num_frames * frame_step, frame_step).reshape(-1, 1) frames = pad_signal[indices] print(frames.shape)

加窗:

在分帧之后,为了让帧两端平滑地衰减,取得更高质量的频谱。之后会对加窗的数据进行FFT,它假设一个窗内的信号是代表一个周期的信号(也就是说窗的左端和右端应该大致能连在一起)。而通常一小段音频数据没有明显的周期性,加后,数据形状就有点周期的感觉了。常用的窗有:矩形窗、汉明(Hamming)窗、汉宁窗(Hanning)

以汉明窗为例,其窗函数为: w ( n , α ) = { ( 1 − α ) − α × c o s ( 2 π n N − 1 ) , 0 ≤ n ≤ N − 1 0 , n = else w(n,\alpha) = \begin{cases} (1-\alpha)-\alpha×cos(\frac{2\pi n}{N-1}),0\le n\le N-1\\ 0,n =\text{else}\\ \end{cases} w(n,α)={(1α)α×cos(N12πn),0nN10,n=else N是窗的宽度。一般 α \alpha α取0.46。

hamming = np.hamming(frame_length) # hamming = 0.54 - 0.46 * np.cos(2 * np.pi * np.arange(0, frame_length) / (frame_length - 1)) frames *= hamming

Step3 STFT

了解FFT 对于每一帧的加窗信号,进行N点FFT变换,也成短时傅里叶变换STFT,N通常取256或512,然后用如下的公式计算能量谱: P = ∣ F F T ( x i ) ∣ 2 N P=\frac{|FFT(x_{i})|^{2}}{N} P=NFFT(xi)2

NFFT = 512 mag_frames = np.absolute(np.fft.rfft(frames, NFFT)) pow_frames = ((1.0 / NFFT) * (mag_frames ** 2))

Step4 提取FBank特征

在能量谱上应用Mel滤波器组,就能提取到FBank特征。

Mel滤波器组就是一系列的三角形滤波器,通常有40个或80个,在中心频率点响应值为1,在两边的滤波器中心点衰减到0。

具体的公式可写为 H m ( k ) = { 0 k < f ( m − 1 ) k − f ( m − 1 ) f ( m ) − f ( m − 1 ) f ( m − 1 ) ≤ k < f ( m ) 1 k = f ( m ) f ( m + 1 ) − k f ( m + 1 ) − f ( m ) f ( m ) < k ≤ f ( m + 1 ) 0 k > f ( m + 1 ) H_{m}(k)= \begin{cases} 0&k< f(m-1)\\ \frac{k-f(m-1)}{f(m)-f(m-1)}&f(m-1)\le k <f(m)\\ 1&k=f(m)\\ \frac{f(m+1)-k}{f(m+1)-f(m)}&f(m)<k\le f(m+1)\\ 0&k>f(m+1) \end{cases} Hm(k)=0f(m)f(m1)kf(m1)1f(m+1)f(m)f(m+1)k0k<f(m1)f(m1)k<f(m)k=f(m)f(m)<kf(m+1)k>f(m+1) 最后在能量谱上应用Mel滤波器组,其公式为: Y t ( m ) = ∑ k = 1 N H m ( k ) ∣ X t ( k ) ∣ 2 Y_{t}(m)=\sum_{k=1}^{N}H_{m}(k)|X_{t}(k)|^{2} Yt(m)=k=1NHm(k)Xt(k)2 其中,k表示FFT变换后的编号,m表示mel滤波器的编号。

low_freq_mel = 0 high_freq_mel = 2595 * np.log10(1 + (sample_rate / 2) / 700) nfilt = 40 mel_points = np.linspace(low_freq_mel, high_freq_mel, nfilt + 2) # 所有的mel中心点,为了方便后面计算mel滤波器组,左右两边各补一个中心点 hz_points = 700 * (10 ** (mel_points / 2595) - 1) fbank = np.zeros((nfilt, int(NFFT / 2 + 1))) # 各个mel滤波器在能量谱对应点的取值 bin = (hz_points / (sample_rate / 2)) * (NFFT / 2) # 各个mel滤波器中心点对应FFT的区域编码,找到有值的位置 for i in range(1, nfilt + 1): left = int(bin[i-1]) center = int(bin[i]) right = int(bin[i+1]) for j in range(left, center): fbank[i-1, j+1] = (j + 1 - bin[i-1]) / (bin[i] - bin[i-1]) for j in range(center, right): fbank[i-1, j+1] = (bin[i+1] - (j + 1)) / (bin[i+1] - bin[i])

Step5 MFCC特征

num_ceps = 12 mfcc = dct(filter_banks, type=2, axis=1, norm='ortho')[:, 1:(num_ceps+1)] cep_lifter = 23 (nframes, ncoeff) = mfcc.shape n = np.arange(ncoeff) lift = 1 + (cep_lifter / 2) * np.sin(np.pi * n / cep_lifter) mfcc *= lift

一般对于ASR来说,对MFCC进行一个正弦提升(sinusoidal liftering)操作,可以提升在噪声信号中最后的识别率:

最新回复(0)