训练信号处理模型或者ASR等时常需要添加某个范围内任意信噪比的加性噪声,写个简单的函数便于使用。

import numpy as np
import soundfile as sf
import math
import random

def generate_noisy(noise_file, wav_file, snr, avoid_clipping=True, random_index=True):
    speech, sfs = sf.read(wav_file)
    noise, nfs = sf.read(noise_file)
    assert sfs == nfs
    s_len = len(speech)
    n_len = len(noise)
    if s_len <= n_len:
        if random_index and n_len > s_len + 1:
            random_index = random.randint(0, n_len - s_len - 1)
            noise = noise[random_index: random_index + s_len]
        else:
            noise = noise[:s_len]
    else:
        num_repeat = s_len // n_len
        res = s_len - num_repeat * n_len
        noise = np.concatenate([np.concatenate([noise] * num_repeat), noise[:res]])
    speech_power = np.sum(speech ** 2)
    noise = noise / np.sqrt(np.sum(noise ** 2) + 1e-8) * np.sqrt(speech_power + 1e-8)
    noise = noise / np.power(10, snr / 20.)
    noisy = speech + noise
    if avoid_clipping:
        max_scale = max(np.max(np.abs(speech)), np.max(np.abs(noise)), np.max(np.abs(noisy)))
        noisy = noisy / max_scale * 0.9
        speech = speech / max_scale * 0.9
        noise = noise / max_scale * 0.9
    return noisy, speech, noise

可以对生成的含噪音频做个简单的信噪比检验。

def check_snr(mix, clean):
    noise_power = np.sum((mix - clean) ** 2)
    clean_power = np.sum(clean ** 2)
    snr = 10 * math.log10(clean_power / (noise_power + 1e-8))
    return snr

 

更多推荐