-
按一定信噪比混合语音信号
-
信噪比公式:
S N R ( s ( t ) , n ( t ) ) = 10 ⋅ l o g 10 ∑ t s 2 ( t ) ∑ t n 2 ( t ) (1.1) SNR(s(t),n(t)) =10 \cdot log_{10} \frac{∑_ts^2 (t)}{∑_tn^2 (t)} \tag{1.1} SNR(s(t),n(t))=10⋅log10∑tn2(t)∑ts2(t)(1.1) -
为了生成有特定信噪比的混合信号,如 q d B q dB qdB 的混合信号,调整噪声信号的能量大小,将噪声信号 n ( t ) n(t) n(t) 调整为原来的 α \alpha α 倍,即新的噪声信号为 α n ( t ) \alpha n(t) αn(t)(张晖老师论文),有:
q = 10 ⋅ l o g 10 ∑ t s 2 ( t ) α 2 ∑ t n 2 ( t ) (1.2) q=10\cdot log_{10} \frac{\sum_{t} \mathbf s^2(t)}{\alpha^2\sum_{t} \mathbf n^2(t)} \tag{1.2} q=10⋅log10α2∑tn2(t)∑ts2(t)(1.2)
故而得到:
α = ∑ t s 2 ( t ) 1 0 q 10 ⋅ ∑ t n 2 ( t ) (1.3) \alpha \mathbf =\sqrt{\frac{\sum_{t} \mathbf s^2(t)}{10^\frac{q}{10}\cdot\sum_{t} \mathbf n^2(t)}} \tag{1.3} α=1010q⋅∑tn2(t)∑ts2(t)(1.3) -
在纯净语料中挑选句子作为目标语音 s ( t ) s(t) s(t),在噪声语料中挑选噪声,根据所需信噪比缩放得到噪声信号 n ( t ) n(t) n(t),两者相加,即得到混合的带噪语音信号 y ( t ) = s ( t ) + n ( t ) y(t) =s(t) + n(t) y(t)=s(t)+n(t)。数据生成阶段得到三种数据:带噪语音信号 y ( t ) y(t) y(t)、目标语音信号 s ( t ) s(t) s(t) 和噪声信号 n ( t ) n(t) n(t)。
-
-
提取频谱特征:采用短时傅里叶变换
-
在语音分离中,一般采用短时傅里叶变换进行时频分解。短时傅里叶变换首先在时间上分帧,假设 w ( k ) w(k) w(k) 是一个对称实数窗口函数,长度(帧长)为 N N N,窗口每次移动(帧移) N / 2 N/2 N/2。对于一维信号 x ( k ) x(k) x(k),将它的第 t t t 个加窗块记作 S ( t , k ) S(t, k) S(t,k):
S ( t , k ) = x ( k ) ⋅ w ( k − t ⋅ N / 2 ) (2.1) S(t, k) = x(k) · w(k−t · N/2) \tag{2.1} S(t,k)=x(k)⋅w(k−t⋅N/2)(2.1)
-
之后再使用离散傅里叶变换在频率上分频:
X ( t , f ) = F ( S ( t , k ) ) (2.2) X(t, f) = F(S(t, k))\tag{2.2} X(t,f)=F(S(t,k))(2.2)
其中, F ( ⋅ ) F(·) F(⋅) 表示傅里叶变换。 X ( t , f ) X(t, f) X(t,f) 是一维信号 x ( k ) x(k) x(k) 在第 t t t 时间帧、第 f f f 个频段的短时傅里叶变换系数。
-
-
提取完频谱特征后,使用 p i c k l e pickle pickle 库将数据文件以 . p .p .p 的文件格式保存。
-
完整代码如下:
def cutNoise():
data_dir = config_s.data_dir # 数据目录
noise_dir = os.path.join(data_dir, 'noise') # 噪声所在目录
noise_files = os.listdir(noise_dir) # 噪声目录下的文件名称列表
for file in noise_files: # 遍历噪声列表文件,对噪声进行分割
sample_rate, y_data = wavfile.read(os.path.join(noise_dir, file))
half = y_data.shape[0] / 2
data_train = y_data[:int(half)] # 前半部分作为训练噪声
data_test = y_data[int(half):] # 后半部分作为测试噪声
tra_noise_dir = os.path.join(data_dir, 'noise_train')
tes_noise_dir = os.path.join(data_dir, 'noise_test')
create_folder(tra_noise_dir) # 创建保存训练噪声的目录
create_folder(tes_noise_dir) # 创建保存测试噪声的目录
tra_noise = os.path.join(tra_noise_dir, '%s_%s' % ('train', file))
tes_noise = os.path.join(tes_noise_dir, '%s_%s' % ('test', file))
sf.write(tra_noise, data_train, sample_rate) # 写入训练噪声
sf.write(tes_noise, data_test, sample_rate) # 写入测试噪声
pass
def AddNoise(data_type):
# 处理噪声,使得噪声长度与语音长度一致,将这些噪声中前 2 分钟的
# 部分与目标语音混合成信噪比为-5 dB 和 0 dB 的混合带噪语音,这些语音信号作为训练数据
# workspace = config_s.workspace # 工作空间
data_dir = config_s.data_dir # premix_data数据目录
snr = config_s.SNR
fs = config_s.fs
noise_dir = os.path.join(data_dir, 'noise_%s' % data_type)
noise_files = os.listdir(noise_dir)
# print(f'noise_dir:{noise_dir}')
# print(f'noise_files:{noise_files}')
for noise in noise_files:
# 给每一种语音加噪
noise_path = os.path.join(noise_dir, noise)
noise_audio = read_audio(noise_path)
# test_data
speech_dir = os.path.join(data_dir, '%s_data' % data_type)
speech_files = os.listdir(speech_dir)
for speech in speech_files:
speech_path = os.path.join(speech_dir, speech)
speech_audio = read_audio(speech_path)
# 截取相同语音长度的噪声
noise_len = len(noise_audio)
speech_len = len(speech_audio)
max_idx = noise_len - speech_len
idx = np.random.randint(low=0, high=max_idx) # 生成0到max_idx之间的随机数,这里设置max_idx是保证了不会超过噪音noise的最大长度
noise_audio_re = noise_audio[idx:idx + speech_len] # idx的最大值为max_idx,这使得提取的noise范围在原noise内
assert len(noise_audio_re) == speech_len # 断言,保证提取的noise长度等于speech的长度,否则出错
# 加噪
mix_audio_dB = speech_audio + noise_audio_re * _calc_alpha(SNR=snr, speech=speech_audio,
noise=noise_audio_re) # 加噪后的混合语音
noise_audio_dB = noise_audio_re * _calc_alpha(SNR=snr, speech=speech_audio,
noise=noise_audio_re) # 对应信噪比的噪声
mix_wav_dir = os.path.join(data_dir, 'mix_%s_wav' % data_type, '%ddB' % int(snr)) # 保存加噪后的混合语音目录
noise_wav_dir = os.path.join(data_dir, 'noise_%s_dB' % data_type, '%ddB' % int(snr)) # 保存混合信噪比后的噪音目录
create_folder(mix_wav_dir)
# print(f'Create mix_wav_dir successed!')
create_folder(noise_wav_dir)
tmp_spe = speech.split(".")[0]
tmp_noi = noise.split(".")[0]
mix_wav_path = os.path.join(mix_wav_dir, '%s.%s.wav' % (tmp_spe, tmp_noi))
noise_wav_path = os.path.join(noise_wav_dir, '%s.wav' % (tmp_noi))
sf.write(file=mix_wav_path, data=mix_audio_dB, samplerate=fs)
sf.write(file=noise_wav_path, data=noise_audio_dB, samplerate=fs)
# 提取频谱特征
speech_spec = _calc_stft(speech_audio) # speech_audio:干净语音数据
noise_spec = _calc_stft(noise_audio_dB) # noise_audio_dB:信噪比变换后的噪音数据
mix_spec = _calc_stft(mix_audio_dB) # mix_audio_dB:混合一定信噪比后的语音数据
# 写入特征,将干净语音特征、噪声特征及混合噪声后的语音特征合并保存在一个.p文件中
output_feat_name = os.path.join('%s.%s' % (tmp_spe, tmp_noi))
output_feat_path = os.path.join(data_dir, 'features', 'spectrograms', '%s' % data_type,
'%ddB' % int(snr), '%s.p' % output_feat_name)
create_folder(os.path.dirname(output_feat_path))
data = [speech_spec, noise_spec, mix_spec]
pickle.dump(data, open(output_feat_path, 'wb'), protocol=pickle.HIGHEST_PROTOCOL)
pass