幅度谱、相位谱、能量谱等语音信号处理中的基础知识

写在前面的话

  准备根植于语音信号处理这一领域,所以在此对于自己已了解的频谱特征进行总结。非通信专业,若有疏漏,希望可以在评论区指出,谢谢。

一、时域信号获取

  在科研方面,我们用的语音信号一般均是.wav.pcm格式。就个人而言,使用.wav最为频繁。

1.1 python读取.wav文件
1.1.1 soundfile
import soundfile as sf
clean_sig, sr = sf.read('./datasets/SX97_-5_leopard_014930_speech.wav')
print('内容:' + str(clean_sig))
print('形状:' + str(clean_sig.shape))
print('采样率:' + str(sr))
print('类型:' + str(clean_sig.dtype))

输出:

内容:[ 3.05175781e-05 -3.05175781e-05 -6.10351562e-05 ...  3.05175781e-05
  3.05175781e-05  1.83105469e-04]
形状:(32871,)
采样率:16000
类型:float64
1.1.2 scipy
from scipy.io import wavfile
# 注意此方法返回的结果,采样率是第一个参数,信号是第二个参数
sr, clean_sig = wavfile.read('./datasets/SX97_-5_leopard_014930_speech.wav')
print('内容:' + str(clean_sig))
print('形状:' + str(clean_sig.shape))
print('采样率:' + str(sr))
print('类型:' + str(clean_sig.dtype))

输出:

内容:[ 1 -1 -2 ...  1  1  6]
形状:(32871,)
采样率:16000
类型:int16
1.1.3 总结

  可以看到两种方法读出来的数据形状一样,但是内容差距很大。原因是,wav音频绝大部分以16位整形数据存在文件中。soundfile读取出来的是原始音频信息,而‘scipy.io’中读出来的整数,其实scipy.io中读出来的是将数值等比例缩放了 2 15 2^{15} 215倍,也就是乘了 2 15 2^{15} 215=32768,如: 3.05175791 ∗ 1 0 − 5 ∗ 32768 = 1.0000000319 3.05175791 * 10^{-5} * 32768 = 1.0000000319 3.0517579110532768=1.0000000319
因此可以看出,soundfile的方法读出来的数据要比scipy.io读出来的更为精确。
  对于读出的数据每个值,我们称之为采样点sr采样率,两者的关系是:采样率是指在1秒内,对信号采样的次数,如:16000采样率(16kHz)表示在1秒的时间内,对信号采样16000次,即16000个采样点表示1秒种的语音

二、频谱特征

  频谱特征是指在频域上的信号特征,我们采用短时傅里叶变换(short-time Fourier transform, STFT)将时域信号变换到频域上。有关傅里叶变换的知识以后总结。

2.1 傅里叶变换后的信号

  在这里,我们使用librosa包中的stft方法将时域信号变换到频域。

import soundfile as sf
import librosa
clean_sig, sr = sf.read('./datasets/SX97_-5_leopard_014930_speech.wav')
clean_spec = librosa.stft(clean_sig, win_length=320, hop_length=160, n_fft=320)
print('内容:' + str(clean_spec))
print('形状:' + str(clean_spec.shape))

输出:

内容:[[ 8.76316987e-03+0.0000000e+00j  1.29083162e-02+0.0000000e+00j
   9.13359132e-03+0.0000000e+00j ...  7.62358448e-03+0.0000000e+00j
   7.58317392e-03+0.0000000e+00j  1.10339485e-02+0.0000000e+00j]
 [-1.75022508e-03+4.3040286e-19j -7.37327803e-03-1.4874971e-03j
  -4.45753196e-03+1.2122139e-03j ... -3.66999581e-03+6.7065289e-04j
  -2.64038169e-03+1.6806803e-04j -5.55054098e-03-1.2115777e-04j]
 [-4.30344604e-03-6.1006659e-19j  5.33141894e-04+2.7573726e-04j
   8.00883863e-04-1.3510550e-03j ... -3.78675119e-04-2.0164346e-04j
  -1.67590310e-03+4.1538148e-04j -4.49120067e-04+4.6450400e-04j]
 ...
 [ 9.26596869e-04-1.7111648e-19j -7.02931487e-04-9.0587000e-06j
   7.64308905e-04-1.3586872e-04j ... -3.17405735e-04+6.6111665e-05j
  -6.93979207e-04+7.6773483e-04j -7.75805966e-04-7.5752003e-05j]
 [-8.64989765e-04+5.0811411e-20j  2.63431924e-04-1.3580784e-04j
  -2.29876296e-05+6.2994589e-04j ...  4.75295201e-05-3.6528043e-04j
   4.57464193e-04-7.0705859e-04j  9.95153969e-05+4.5833897e-04j]
 [ 9.03499953e-04+0.0000000e+00j -1.09811270e-04+0.0000000e+00j
  -3.26593174e-04+0.0000000e+00j ... -1.62867364e-04+0.0000000e+00j
   1.52526351e-04+0.0000000e+00j  4.80814284e-04+0.0000000e+00j]]
形状:(161, 206)
类型:complex64

可以看到,经过傅里叶变换后,信号类型变成了complex64,也就是复数。

2.2 幅度谱(magnitude spectrogram)

 有时候文章里还使用amplitude,在语音信号处理领域也译为幅度谱

  将信号变换到频域上之后,对信号进行取模操作即可获取幅度谱。

import numpy as np
import soundfile as sf
import librosa
clean_sig, sr = sf.read('./datasets/SX97_-5_leopard_014930_speech.wav')
clean_spec = librosa.stft(clean_sig, win_length=320, hop_length=160, n_fft=320)
mag = np.abs(clean_spec)
print('内容:' + str(mag))
print('形状:' + str(mag.shape))
print('类型:' + str(mag.dtype))

输出:

内容:[[0.00876317 0.01290832 0.00913359 ... 0.00762358 0.00758317 0.01103395]
 [0.00175023 0.00752183 0.00461942 ... 0.00373077 0.00264573 0.00555186]
 [0.00430345 0.00060023 0.00157059 ... 0.00042902 0.00172661 0.00064612]
 ...
 [0.0009266  0.00070299 0.00077629 ... 0.00032422 0.0010349  0.0007795 ]
 [0.00086499 0.00029638 0.00063037 ... 0.00036836 0.00084214 0.00046902]
 [0.0009035  0.00010981 0.00032659 ... 0.00016287 0.00015253 0.00048081]]
形状:(161, 206)
类型:float32
2.3 相位谱(phase spectrogram)

  将信号变换到频域上之后,对信号进行取相位角操作即可获取信号的相位谱(相位信息)。

import numpy as np
import soundfile as sf
import librosa
clean_sig, sr = sf.read('./datasets/SX97_-5_leopard_014930_speech.wav')
clean_spec = librosa.stft(clean_sig, win_length=320, hop_length=160, n_fft=320)
phase = np.angle(clean_spec)
print('内容:' + str(phase))
print('形状:' + str(phase.shape))
print('类型:' + str(phase.dtype))

输出为:

内容:[[ 0.0000000e+00  0.0000000e+00  0.0000000e+00 ...  0.0000000e+00
   0.0000000e+00  0.0000000e+00]
 [ 3.1415927e+00 -2.9425230e+00  2.8760667e+00 ...  2.9608476e+00
   3.0780256e+00 -3.1197679e+00]
 [-3.1415927e+00  4.7730723e-01 -1.0356996e+00 ... -2.6522865e+00
   2.8986335e+00  2.3393579e+00]
 ...
 [-1.8467198e-16 -3.1287065e+00 -1.7592894e-01 ...  2.9362411e+00
   2.3057790e+00 -3.0442581e+00]
 [ 3.1415927e+00 -4.7599661e-01  1.6072716e+00 ... -1.4414054e+00
  -9.9653566e-01  1.3569930e+00]
 [ 0.0000000e+00  3.1415927e+00  3.1415927e+00 ...  3.1415927e+00
   0.0000000e+00  0.0000000e+00]]
形状:(161, 206)
类型:float32
2.5 能量谱(power spectrogram)

  对信号的幅度谱做平方操作,即可获取能量谱。

import numpy as np
import soundfile as sf
import librosa
clean_sig, sr = sf.read('./datasets/SX97_-5_leopard_014930_speech.wav')
clean_spec = librosa.stft(clean_sig, win_length=320, hop_length=160, n_fft=320)
mag = np.abs(clean_spec)
energy = mag ** 2
print('内容:' + str(energy))
print('形状:' + str(energy.shape))
print('类型:' + str(energy.dtype))

输出:

内容:[[7.67931488e-05 1.66624624e-04 8.34224920e-05 ... 5.81190397e-05
  5.75045269e-05 1.21748017e-04]
 [3.06328775e-06 5.65778791e-05 2.13390540e-05 ... 1.39186450e-05
  6.99986276e-06 3.08231829e-05]
 [1.85196477e-05 3.60271315e-07 2.46676450e-06 ... 1.84054940e-07
  2.98119289e-06 4.17472791e-07]
 ...
 [8.58581757e-07 4.94194751e-07 6.02628347e-07 ... 1.05117145e-07
  1.07102392e-06 6.07613288e-07]
 [7.48207299e-07 8.78401494e-08 3.97360225e-07 ... 1.35688850e-07
  7.09205381e-07 2.19977920e-07]
 [8.16312138e-07 1.20585151e-08 1.06663101e-07 ... 2.65257789e-08
  2.32642883e-08 2.31182369e-07]]
形状:(161, 206)
类型:float32
2.6 梅尔谱(mel spectrogram)

  将幅度谱通过梅尔滤波器组,得到的结果就是梅尔谱。

import soundfile as sf
import librosa
clean_sig, sr = sf.read('./datasets/SX97_-5_leopard_014930_speech.wav')
clean_mel_spec = librosa.feature.melspectrogram(clean_sig, sr=sr, win_length=320, hop_length=160, n_fft=320)
print('内容:' + str(clean_mel_spec))
print('形状:' + str(clean_mel_spec.shape))
print('类型:' + str(clean_mel_spec.dtype))

输出:

内容:[[0.0000000e+00 0.0000000e+00 0.0000000e+00 ... 0.0000000e+00
  0.0000000e+00 0.0000000e+00]
 [1.1288448e-07 2.0849377e-06 7.8636032e-07 ... 5.1291261e-07
  2.5795026e-07 1.1358577e-06]
 [1.8121774e-08 3.3470297e-07 1.2623741e-07 ... 8.2339810e-08
  4.1409734e-08 1.8234354e-07]
 ...
 [5.3398366e-09 2.5303654e-08 1.8074982e-08 ... 5.1210187e-09
  4.2730499e-09 7.5652693e-09]
 [9.4773158e-09 1.9163979e-08 9.7578639e-09 ... 3.4058807e-09
  7.2911930e-09 1.6748615e-08]
 [4.6306328e-09 2.6178222e-08 1.1558068e-08 ... 4.3883781e-09
  1.4969601e-08 2.6740691e-08]]
形状:(128, 206)
类型:float32

  在此处是直接使用的librosa.feature.melspectrogram方法,其实去看该方法的实现就可以看到,先做了_spectrogram(),然后做了‘filters.mel()’。而_spectrogram()方法是做了abs(stft())

2.7 梅尔倒谱系数(Mel-scale Frequency Cepstral Coefficients, MFCC)

  MFCC,是对梅尔谱特征取对数操作后,提取倒谱参数(DCT)

import soundfile as sf
import librosa
clean_sig, sr = sf.read('./datasets/SX97_-5_leopard_014930_speech.wav')
clean_mfcc = librosa.feature.mfcc(clean_sig, sr=sr, n_mfcc=40)
print('内容:' + str(clean_mfcc))
print('形状:' + str(clean_mfcc.shape))
print('类型:' + str(clean_mfcc.dtype))

输出:

内容:[[-7.4360229e+02 -7.4118781e+02 -7.4623761e+02 ... -6.4906628e+02
  -6.8241693e+02 -7.1324139e+02]
 [ 1.0094034e+01  1.1340399e+01  9.1006794e+00 ...  5.2873005e+01
   4.1353008e+01  3.2668667e+01]
 [ 2.4416672e+01  2.3510887e+01  1.7528904e+01 ... -3.7687920e+01
  -2.2165060e+01 -5.7691031e+00]
 ...
 [-9.3942904e-01  1.3458931e-01  3.1641185e+00 ...  3.6823349e+00
   1.2929006e+00 -3.8065696e-01]
 [-4.0057945e+00 -2.4740624e+00  2.5400662e+00 ...  5.5418024e+00
   1.1933881e+00 -9.6134186e-01]
 [ 1.9161583e+00  6.8438768e-01 -2.7315216e+00 ...  2.4877858e+00
   1.9765708e+00 -6.7191064e-01]]
形状:(40, 65)
类型:float32

三、总结

流程图

  • 48
    点赞
  • 117
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值