python对语音文件加入高斯白噪声(含公式推导)

1. 信噪比概念及计算公式

信噪比(Signal-to-noise ratio,缩写为 SNR 或 S/N),也称作信杂比或讯杂比。
信噪比,为有用信号功率(Power of Signal)与噪声功率(Power of Noise)的比。因此为幅度(Amplitude)比的平方:
S N R = P s i g n a l P n o i s e = ( A s i g n a l A n o i s e ) 2 SNR=\frac{P_{signal}}{P_{noise}}=(\frac{A_{signal}}{A_{noise}})^2 SNR=PnoisePsignal=(AnoiseAsignal)2
它的单位一般使用分贝,其值为十倍对数信号与噪声功率比:
S N R = 10 ⋅ l o g 10 P s i g n a l P n o i s e = 10 ⋅ l o g 10 ( A s i g n a l A n o i s e ) 2 = 20 ⋅ l o g 10 ( A s i g n a l A n o i s e ) SNR=10\cdot log_{10}\frac{P_{signal}}{P_{noise}}=10\cdot log_{10}(\frac{A_{signal}}{A_{noise}})^2=20\cdot log_{10}(\frac{A_{signal}}{A_{noise}}) SNR=10log10PnoisePsignal=10log10(AnoiseAsignal)2=20log10(AnoiseAsignal)
公式中的各字母含义如下:


P s i g n a l P_{signal} Psignal:为信号功率(Power of Signal)。
P n o i s e P_{noise} Pnoise:为噪声功率(Power of Noise)。
A s i g n a l A_{signal} Asignal: 为信号幅度(Amplitude of Signal)。
A n o i s e A_{noise} Anoise: 为噪声幅度(Amplitude of Noise)。


2.已知信噪比,如何去产生固定功率的噪声

在我们想要向语音中添加一定信噪比的高斯白噪声,在这时,我们已知以下条件:

1.信噪比(假设我们要生成30dB信噪比的数据);
2.输入语音信号的功率;

我们下一步就是要去生成高斯白噪声,其生成可调用如下:

random_values = np.random.rand(len(voice_data))
#voice_data为我们输入的语音数据

计算语音信号的功率 P s P_s Ps 和生成噪声的功率 P n 1 P_{n1} Pn1 (设其长度均为N):
P s = Σ i = 1 N ( x i ) 2 N P n 1 = Σ i = 1 N ( n i ) 2 N \qquad P_s=\frac{Σ_{i=1}^{N}(x_i)^2}{N}\\\qquad\\\qquad P_{n1}=\frac{Σ_{i=1}^{N}(n_i)^2}{N} Ps=NΣi=1N(xi)2Pn1=NΣi=1N(ni)2
需要注意的是,此时我们生成的白噪声,其与语音信号的信噪比肯定不是我们需求的30dB,也就是说我们需要对噪声数据都乘一个数值k,使其功率满足我们的要求,那这个k值又该如何求解呢?
30 d B = 10 ⋅ l o g 10 P s P n 30dB=10\cdot log_{10}\frac{P_s}{P_n} 30dB=10log10PnPs
对上式整理可得:其中 P n P_n Pn 为我们最终需要的高斯白噪声的功率:
P n = P s 1 0 3 = Σ i = 1 N ( k ⋅ n i ) 2 N = ( k n 1 ) 2 + ( k n 2 ) 2 + ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ + ( k n N ) 2 N = k 2 ( n 1 2 + n 2 2 + ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ + n N 2 ) N = k 2 ⋅ P n 1 P_n=\frac{P_s}{10^3}\\\qquad\\= \frac{Σ_{i=1}^{N}(k\cdot n_i)^2}{N}\\\qquad\\= \frac{(kn_1)^2+(kn_2)^2+\cdot\cdot\cdot\cdot\cdot\cdot+(kn_N)^2}{N}\\\qquad\\= \frac{k^2(n_1^2+n_2^2+\cdot\cdot\cdot\cdot\cdot\cdot+n_N^2)}{N}\\\qquad\\=k^2\cdot P_{n1} Pn=103Ps=NΣi=1N(kni)2=N(kn1)2+(kn2)2++(knN)2=Nk2(n12+n22++nN2)=k2Pn1
对上边推导的式子进行整理,则有:
k 2 ⋅ P n 1 = P s 1 0 3 k = P s 1 0 3 ⋅ P n 1 k = P s 1 0 S N R 10 ⋅ P n 1 k^2\cdot P_{n1}=\frac{P_s}{10^3}\\\qquad\\k=\sqrt{\frac{P_s}{10^3\cdot P_{n1}}}\\\qquad\\k=\sqrt{\frac{P_s}{{10^{\frac{SNR}{10}}}\cdot P_{n1}}} k2Pn1=103Psk=103Pn1Ps k=1010SNRPn1Ps
求出这个k值之后,我们便可以对我们之前生成的噪声数据都乘这个数值k

random_values_we_need=random_values*k
#将我们的噪声数据都乘 k

然后将我们噪声数据与原始语音数据相加可得叠加噪声后的数据。

3.完整代码

import soundfile as sf
import math
import librosa
import numpy as np


def add_noise(audio_path, noise_path,out_path, SNR, sr=16000):
    #读取语音文件data和fs
    src, sr = librosa.core.load(audio_path, sr=sr)
    #
    random_values = np.random.rand(len(src))
    #计算语音信号功率Ps和噪声功率Pn1
    Ps = np.sum(src ** 2) / len(src)
    Pn1 = np.sum(random_values ** 2) / len(random_values)

    # 计算k值
    k=math.sqrt(Ps/(10**(SNR/10)*Pn1))
    #将噪声数据乘以k,
    random_values_we_need=random_values*k
    #计算新的噪声数据的功率
    Pn=np.sum(random_values_we_need**2)/len(random_values_we_need)
    #以下开始计算信噪比
    snr=10*math.log10(Ps/Pn)
    print("当前信噪比:",snr)

    #单独将噪音数据写入文件
    sf.write(noise_path,random_values_we_need, sr)
    #将噪声数据叠加到纯净音频上去
    outdata=src+random_values_we_need
    # 将叠加噪声的数据写入文件
    sf.write(out_path, outdata, sr)


def main():

    filename='./splits/train/京_0.wav'
    #纯净语音文件路径
    noisename='noise.wav'
    #产生的噪声数据路径
    outname='add_noise.wav'
    #叠加了噪声后的数据
    SNR=-5
    #选定信噪比
    add_noise(filename,noisename,outname,SNR)
    #调用函数,直接生成数据


if __name__=="__main__":
    main()

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王延凯的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值