如题,这应该算是我前往语音这座大山的第一步,在此做出记录。
一、工作背景
由于需要进行单通道降噪的实验,但是现在只有纯净语音和噪声数据,而在阅读文章的过程中,大家并没有将这个细小的内容写道论文中(的确也不应该,做出来之后确实感觉蛮简单的),所以只能自己通过纯净语音和噪声合成自己需要的数据。
二、数据生成
需要复现的实验是基于单通道的语音增强,同时根据张晖老师博士学位论文,在合成数据时使用TIMIT语料库的核心训练集中的1000局作为训练用的目标语音。再将这些语音与各种噪声相混合(四种噪声随机一种),从NOISE-92中选取四种噪声:嘈杂噪声(babble noise)、工厂噪声(factory1)、驱动舰动力室噪声(destroyerops)和驱逐舰发动机噪声(destroyerengine)。
每种噪声3分55秒,将每种噪声的前50%为训练集混合使用,后50%为测试集混合使用,这样训练出的模型应该会有较好的泛化性。混合过程中分别使用-5dB、0dB作为信噪比进行混合。
2.1 计算公式
首先我们对于公式进行解释:
(2.1)
S
N
R
(
s
(
t
)
,
n
(
t
)
)
=
10
⋅
l
o
g
10
∑
t
s
2
(
t
)
∑
t
n
2
(
t
)
SNR(s(t),n(t))=10·log_{10}{\frac {\sum_t s^2(t)}{\sum_t n^2(t)}} \tag{2.1}
SNR(s(t),n(t))=10⋅log10∑tn2(t)∑ts2(t)(2.1)
- S N R SNR SNR为信噪比,单位为dB
- ∑ t s 2 ( t ) \sum_ts^2(t) ∑ts2(t)为纯净语音能量
-
∑
t
n
2
(
t
)
{\sum_t n^2(t)}
∑tn2(t)为噪声能量
为了合成特定信噪比的混合语音,我们需要对噪声能量进行调整,如:如需要q dB混合语音,调整噪声能量的大小为原来的 α \alpha α倍,即新的噪声信号为 α n ( t ) \alpha n(t) αn(t),新的公式为:
(2.2) q = 10 ⋅ l o g 10 ∑ t s 2 ( t ) α 2 ∑ t n 2 ( t ) q=10·log_{10}{\frac {\sum_t s^2(t)}{ \alpha^2 \sum_t n^2(t)}} \tag{2.2} q=10⋅log10α2∑tn2(t)∑ts2(t)(2.2)
根据(2.2)可以推出:
(2.3) α = ∑ t s 2 ( t ) 1 0 q 10 ∑ t n 2 ( t ) \alpha = \sqrt{\frac {\sum_t s^2(t)}{10^{\frac{q}{10}}\sum_t n^2(t)}} \tag{2.3} α=1010q∑tn2(t)∑ts2(t)(2.3)
2.2 数据准备
噪声数据:
可以看到,babble.wav是噪声的原始文件,babble_test.wav为babble.wav后50%切片,babble_train.wav为babble.wav为噪声的前50%切片,其它同理。
切片实现:
from scipy.io import wavfile
import numpy as np
import soundfile as sf
sample_rate, sig = wavfile.read('D:/毕设数据/noise/factory1.wav')
# 采样率:1S内对声音信号的采样次数
# print("采样率: %d" % sample_rate)
# print(sig.shape)
# print(sig)
#
# if sig.dtype == np.int16:
# print("PCM16位整形")
half = sig.shape[0]/2
data_train = sig[:int(half)]
data_test = sig[int(half):]
sf.write('D:/毕设数据/noise/factory1_train.wav', data_train, sample_rate)
sf.write('D:/毕设数据/noise/factory1_test.wav', data_test, sample_rate)
2.3 数据合成
import numpy as np
import soundfile as sf
import librosa
import random
import os
sound_name = 'SI'
def switch(item):
switcher = {
0: 'babble',
1: 'destroyerengine',
2: 'destroyerops',
3: 'factory1'
}
return switcher.get(item)
files = os.listdir('D:/毕设数据/TIMIT-TRAIN')
# 噪音的id
# [)
for i in range(0, 1000):
# 随机噪声类型
n_id = random.randint(0, 3)
n_name = switch(n_id)
# 原始语音
a, a_sr = librosa.load('D:/毕设数据/TIMIT-TRAIN/' + files[i], sr=16000)
# 噪音
b, b_sr = librosa.load('D:/毕设数据/noise/' + n_name + '_train' + '.wav', sr=16000)
# 随机取一段噪声,保证长度和纯净语音长度一致,保证不会越界
start = random.randint(0, b.shape[0] - a.shape[0])
# 切片
n_b = b[int(start):int(start)+a.shape[0]]
# 平方求和
sum_s = np.sum(a ** 2)
sum_n = np.sum(n_b ** 2)
# 信噪比为-5dB时的权重
x = np.sqrt(sum_s/(sum_n * pow(10, -0.5)))
noise = x * n_b
target = a + noise
sf.write('D:/毕设数据/train_data/-5dB/mix_sound/' + files[i].split('.')[0] + '_' + n_name + '.wav', target, 16000)
sf.write('D:/毕设数据/train_data/-5dB/sound/' + files[i].split('.')[0] + '.wav', a, 16000)
sf.write('D:/毕设数据/train_data/-5dB/noise/' + files[i].split('.')[0] + '_' + n_name + '_train' + '.wav', noise, 16000)
2.4 合成结果
混合语音合成结果:
噪声使用情况:
纯净语音: