噪声分段&按一定信噪比混合噪声&提取频谱特征

  1. 按一定信噪比混合语音信号

    • 信噪比公式:
      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))=10log10tn2(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=10log10α2tn2(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} α=1010qtn2(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)

  2. 提取频谱特征:采用短时傅里叶变换

    • 在语音分离中,一般采用短时傅里叶变换进行时频分解。短时傅里叶变换首先在时间上分帧,假设 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(ktN/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 个频段的短时傅里叶变换系数。

  3. 提取完频谱特征后,使用 p i c k l e pickle pickle 库将数据文件以 . p .p .p 的文件格式保存。

  4. 完整代码如下:

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

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对一个信号频谱信噪比,可以采用以下步骤: 1. 首先,确定信号的频带范围,并选择一个只包含噪声的参考频带。 2. 对信号频谱和参考频带的频谱进行功率谱密度估计,可以使用Matlab中的pwelch函数或periodogram函数进行估计。 3. 计算信号功率和噪声功率。信号功率可以通过信号频谱信号频带范围内的积分得到,噪声功率可以通过参考频带的功率谱密度乘以信号频带范围内的带宽得到。 4. 计算信噪比信噪比可以用信号功率除以噪声功率得到。 下面是一个示例代码: ```matlab % 生成信号数据 t = 0:0.001:1; f1 = 10; f2 = 50; s = sin(2*pi*f1*t) + sin(2*pi*f2*t); % 添加高斯白噪声 noise_power = 0.1; n = sqrt(noise_power)*randn(size(t)); x = s + n; % 对信号进行功率谱密度估计 Fs = 1000; % 采样率 N = length(x); % 信号长度 f = 0:Fs/N:Fs/2; [Pxx, F] = periodogram(x,[],length(x),Fs); % 计算信噪比 signal_band = (f>=8 & f<=12) | (f>=48 & f<=52); % 信号频带范围 noise_band = (f>=150 & f<=200); % 噪声参考频带 signal_power = trapz(Pxx(signal_band)); % 计算信号功率 noise_power_density = mean(Pxx(noise_band)); % 计算噪声功率谱密度 noise_power = noise_power_density * (sum(signal_band)/length(f)) * Fs; % 计算噪声功率 SNR = signal_power / noise_power; % 计算信噪比 % 绘制信号频谱噪声参考频带 figure; plot(f, 10*log10(Pxx)); hold on; plot(f(signal_band), 10*log10(Pxx(signal_band)), 'r'); plot(f(noise_band), 10*log10(Pxx(noise_band)), 'g'); xlabel('Frequency (Hz)'); ylabel('Power/Frequency (dB/Hz)'); legend('Signal Spectrum', 'Signal Band', 'Noise Band'); % 显示信噪比 fprintf('Signal power = %.2f\n', signal_power); fprintf('Noise power = %.2f\n', noise_power); fprintf('SNR = %.2f dB\n', 10*log10(SNR)); ``` 在这个示例中,我们生成了一个包含两个正弦波的信号,并给它添加了高斯白噪声。然后,我们使用periodogram函数对信号进行功率谱密度估计,并使用信号频带范围和噪声参考频带来计算信噪比。最后,我们绘制了信号频谱噪声参考频带,并显示了信噪比

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值