為了實現我們相對來說是純凈音頻的噪聲添加,我們分三步走:
-
第一步,讀取原始音頻,並輸出相關圖像
-
第二步,加入指定信噪比的高斯白噪聲,並輸出相關圖像
-
第三步,加入其他的噪聲類,並輸出相關圖像
一、讀取原始音頻
讀取原始音頻的方法一般可以分成四類:scipy、pysoundfile、wave和librosa。
注:代碼里標粗部分就是讀取方式
1).scipy讀取原始音頻
from scipy.io import wavfile
import numpy as np
import matplotlib.pyplot as plt
sample_rate, sig = wavfile.read('C:/Users/Lenovo/Desktop/test_0_desc_30_100.wav')
print("采樣率: %d" % sample_rate)
print(sig)
if sig.dtype == np.int16:
print("PCM16位整形")
if sig.dtype == np.float32:
print("PCM32位浮點")
plt.figure(1)
plt.subplot(4,1,1)
plt.plot(sig[:,0])
plt.ylabel('Frequency(Hz)')
plt.xlabel('Time(s)')
plt.subplot(4,1,2)
plt.plot(sig[:,1])
plt.ylabel('Frequency(Hz)')
plt.xlabel('Time(s)')
plt.subplot(4,1,3)
plt.plot(sig[:,2])
plt.ylabel('Frequency(Hz)')
plt.xlabel('Time(s)')
plt.subplot(4,1,4)
plt.plot(sig[:,3])
plt.ylabel('Frequency(Hz)')
plt.xlabel('Time(s)')
plt.show()
#結果顯示
采樣率: 44100
[[ 7 -9 3 -35]
[ 25 1 8 2]
[-32 -3 6 -6]
...
[ 5 7 5 20]
[ 3 -11 16 20]
[-21 9 -8 2]]
PCM16位整形
因為音頻是4通道的,所以圖片分布為[1,2;3,4]
2).pysoundfile讀取音頻
import soundfile as sf
import matplotlib.pyplot as plt
sig, sample_rate = sf.read('C:/Users/Lenovo/Desktop/test_0_desc_30_100.wav')
print("采樣率:%d" % sample_rate)
print(sig)
plt.figure(1)
plt.subplot(2,2,1)
plt.plot(sig[:,0])
plt.ylabel('Frequency1(Hz)')
plt.xlabel('Time1(s)')
plt.subplot(2,2,2)
plt.plot(sig[:,1])
plt.ylabel('Frequency2(Hz)')
plt.xlabel('Time2(s)')
plt.subplot(2,2,3)
plt.plot(sig[:,2])
plt.ylabel('Frequency3(Hz)')
plt.xlabel('Time3(s)')
plt.subplot(2,2,4)
plt.plot(sig[:,3])
plt.ylabel('Frequency4(Hz)')
plt.xlabel('Time4(s)')
plt.show()
#結果顯示
采樣率:44100
[[ 2.13623047e-04 -2.74658203e-04 9.15527344e-05 -1.06811523e-03]
[ 7.62939453e-04 3.05175781e-05 2.44140625e-04 6.10351562e-05]
[-9.76562500e-04 -9.15527344e-05 1.83105469e-04 -1.83105469e-04]
...
[ 1.52587891e-04 2.13623047e-04 1.52587891e-04 6.10351562e-04]
[ 9.15527344e-05 -3.35693359e-04 4.88281250e-04 6.10351562e-04]
[-6.40869141e-04 2.74658203e-04 -2.44140625e-04 6.10351562e-05]]
圖片分布位置同上
3).wave讀取音頻
import wave
import numpy as np
import matplotlib.pyplot as plt
f = wave.open(r"D:/奇怪的東西/雜/ov1_split1/doa_data/wav_ov1_split1_30db/test_0_desc_30_100.wav", "rb")
params = f.getparams()
nchannels, sampwidth, framerate, nframes = params[:4]
strData = f.readframes(nframes)#讀取音頻,字符串格式
waveData = np.fromstring(strData,dtype=np.int16)#將字符串轉化為int
waveData = waveData*1.0/(max(abs(waveData)))#wave幅值歸一化
waveData = np.reshape(waveData,[nframes,nchannels])
f.close()
print('采樣率:',framerate)
plt.figure(1)
plt.subplot(2,2,1)
plt.plot(waveData[:,0])
plt.ylabel('Frequency1(Hz)')
plt.xlabel('Time1(s)')
plt.subplot(2,2,2)
plt.plot(waveData[:,1])
plt.ylabel('Frequency2(Hz)')
plt.xlabel('Time2(s)')
plt.subplot(2,2,3)
plt.plot(waveData[:,2])
plt.ylabel('Frequency3(Hz)')
plt.xlabel('Time3(s)')
plt.subplot(2,2,4)
plt.plot(waveData[:,3])
plt.ylabel('Frequency4(Hz)')
plt.xlabel('Time4(s)')
plt.show()
#結果顯示
采樣率: 44100
圖片分布順序同上:
4).librosa讀取音頻
import librosa.display
import matplotlib.pyplot as plt
import numpy as np
path = "D:/奇怪的東西/雜/ov1_split1/doa_data/wav_ov1_split1_30db/test_0_desc_30_100.wav"
fs = 44100 # 按多少采樣率來加載音頻,如果為none,則默認為22050
sig1,sr1 = librosa.load(path, sr=fs, mono=True, offset=0.0, duration=None)
sig2,sr2 = librosa.load(path, sr=fs, mono=False, offset=0.0, duration=None)
print(sig1.shape)
print(type(sig1))
print(sig2.shape)
print(type(sig2))
original_fs = librosa.get_samplerate(path) # 讀取原始音頻的采樣率
print('原始音頻采樣率:',original_fs)
plt.figure(1)
plt.subplot(2,1,1)
librosa.display.waveplot(sig1, sr=fs, x_axis='time', offset=0.0, ax=None)
plt.subplot(2,1,2)
librosa.display.waveplot(sig2, sr=fs, x_axis='time', offset=0.0, ax=None)
plt.show()
#結果顯示
(1255275,)
<class 'numpy.ndarray'>
(4, 1255275)
<class 'numpy.ndarray'>
原始音頻采樣率: 44100
由於librosa.display.waveplot只有打印單音頻和立體聲的形式,所以多通道的音頻只能是一個合成立體聲,如圖,第一個為單音頻,第二幅圖為立體聲
如果想看多個通道的圖,可以將librosa.display.waveplot都替換為plt.plot,可以生成如下圖例(上圖中的第二幅展開圖):
二、加入指定信噪比的高斯白噪聲
加入指定信噪比的高斯白噪聲,我們首先可以定義一個高斯白噪聲加入的文件,此處我命名為awgn.py文件,這個文件是由matlab中awgn函數改編過來的,可以直接復制粘貼使用,效果已經反復驗證,是正確的。
import numpy as np
def awgn(x, snr, out='signal', method='vectorized', axis=0):
# Signal power
if method == 'vectorized':
N = x.size
Ps = np.sum(x ** 2 / N)
elif method == 'max_en':
N = x.shape[axis]
Ps = np.max(np.sum(x ** 2 / N, axis=axis))
elif method == 'axial':
N = x.shape[axis]
Ps = np.sum(x ** 2 / N, axis=axis)
else:
raise ValueError('method \"' + str(method) + '\" not recognized.')
# Signal power, in dB
Psdb = 10 * np.log10(Ps)
# Noise level necessary
Pn = Psdb - snr
# Noise vector (or matrix)
n = np.sqrt(10 ** (Pn / 10)) * np.random.normal(0, 1, x.shape)
if out == 'signal':
return x + n
elif out == 'noise':
return n
elif out == 'both':
return x + n, n
else:
return x + n
然后,開始在原始音頻加入高斯白噪聲,這里就以第三種讀取音頻方式wave為例,添加指定信噪比為20dB和0dB的高斯白噪聲,其他讀取音頻的添加方式一樣。
import wave
import numpy as np
import matplotlib.pyplot as plt
from awgn import awgn
f = wave.open(r"D:/奇怪的東西/雜/ov1_split1/doa_data/wav_ov1_split1_30db/test_0_desc_30_100.wav", "rb")
params = f.getparams()
nchannels, sampwidth, framerate, nframes = params[:4]
strData = f.readframes(nframes)#讀取音頻,字符串格式
waveData = np.fromstring(strData,dtype=np.int16)#將字符串轉化為int
waveData = waveData*1.0/(max(abs(waveData)))#wave幅值歸一化
waveData = np.reshape(waveData,[nframes,nchannels]).T
snr = 0 #可以改成自己想要的
waveData2 = awgn(waveData, snr, out='signal', method='vectorized', axis=0)
f.close()
plt.figure(1)
plt.subplot(4,1,1)
plt.plot(waveData[0])
plt.ylabel('Frequency(Hz)')
plt.xlabel('Time(s)')
plt.subplot(4,1,2)
plt.plot(waveData[1])
plt.ylabel('Frequency(Hz)')
plt.xlabel('Time(s)')
plt.subplot(4,1,3)
plt.plot(waveData[2])
plt.ylabel('Frequency(Hz)')
plt.xlabel('Time(s)')
plt.subplot(4,1,4)
plt.plot(waveData[3])
plt.ylabel('Frequency(Hz)')
plt.xlabel('Time(s)')
plt.figure(2)
plt.subplot(4,1,1)
plt.plot(waveData2[0])
plt.ylabel('Frequency(Hz)')
plt.xlabel('Time(s)')
plt.subplot(4,1,2)
plt.plot(waveData2[1])
plt.ylabel('Frequency(Hz)')
plt.xlabel('Time(s)')
plt.subplot(4,1,3)
plt.plot(waveData2[2])
plt.ylabel('Frequency(Hz)')
plt.xlabel('Time(s)')