语音经发声者的口唇辐射发出,空气作为语音信号传播的介质,在传播声音信号能量的同时也消耗能量,语音信号的频率越高,介质对声音能量的损耗越严重,预加重能在一定程度上弥补高频部分的损耗,保护声道的信息。假设输入信号第 𝑛个采样点为 𝑥[𝑛],预加重公式如下
y[𝑛]=𝑥[𝑛]−𝛼𝑥[𝑛−1], 𝛼=0.97 (𝛼的取值范围0.9-1)
其对应的传递函数为H(z) = 1 - 𝛼z^(-1)。传递函数的波形图如下:当z>60时,得到的结果几乎接近1,这是一个高通滤波器。
实现代码如下:
import matplotlib.pyplot as plt
import numpy as np
"""
plot H(z) = 1 - 0.97 * z^-1
"""
def fun_y(z):
y = []
for i in range(len(z)):
y.append(1 - 0.97 / z[i])
return y
z = list(np.arange(2, 100, 1))
plt.plot(z, fun_y(z))
plt.tight_layout()
plt.show()
预加重的实现代码如下:
import numpy as np
import wave
from matplotlib import pyplot as plt
def read_file(path):
f = wave.open(path, "rb") # 获取wav文件的参数(以tuple形式输出),依次为(声道数,采样精度,采样率,帧数,......)
params = f.getparams()
nchannels, samplewidth, framerate, nframes = params[:4]
str_data = f.readframes(nframes) # 读取波形数据
f.close()
wave_data = np.frombuffer(str_data, dtype=np.short) # 波形数据转数组
time = np.arange(0, nframes) * (1.0 / framerate)
return time, wave_data
def pre_emphasis(signal, coeff):
return np.append(signal[0], signal[1:] - coeff * signal[:-1])
def plot_aLL(time, signal, num, title, y): # 时间、信号、编号、标题
plt.subplot(num)
plt.plot(time, signal, y)
plt.xlabel('time/s')
plt.ylabel('Ampltitude')
plt.title(title)
plt.tight_layout()
plt.savefig("picture1")
if __name__ == "__main__":
path = "speech/noise.wav"
# path = "speech/hap_1.wav"
A = read_file(path)
plot_aLL(A[0], A[1], 211, "orignal_wav", '-g') # 绘制图片
signal = pre_emphasis(A[1], 0.96) # 预加重
plot_aLL(A[0], signal, 212, "after_emphasis", "-r") # 绘制图片
print(list(A[1]))
print(list(signal))
plt.tight_layout()
plt.show()
运行结果为如下图。从图中可以看出它的作用是语音信号的幅度整体上缩小了2-4倍,但是有部分信号保持原样,针对没有变化的这部分语音我进行查看。(预加重的效果并不是通过加重前后的波形查看的,而是通过对比加重前后的声压级来查看的)
我使用Audition软件打开语音文件,选中这部分语音,发现这部分是其他噪音。红框部分为噪声,其频率相对语音信号大很多,下图为对噪音进行预加重的结果图,根据结果显示,信号并没有缩小,这是因为频率太高的缘故(预加重相当于是一个高通滤波器)?如果有大佬知道原因请告知我一下!!!
对噪音进行预加重所得的结果:
在看深蓝学院推出的课程时,发现里面的预加重效果图如下:
于是我就去查找了一下如何绘制加重前后基于声压级的效果图,其中参考博客声压和声压级计算。考虑到如果求和得出的声压级是一个常数,我通过计算每一个采样点的声压级然后进行绘制其效果图,得到如下图:
但是和上图区别有点大,没有发现有明显提升,一下是运行的代码,若有大佬知道如何绘制预加重的效果图,请告诉我一下!!下面是代码的具体实现:
import numpy as np
import wave
from matplotlib import pyplot as plt
def read_file(path):
f = wave.open(path, "rb") # 获取wav文件的参数(以tuple形式输出),依次为(声道数,采样精度,采样率,采样点数,......)
params = f.getparams()
print(params)
nchannels, samplewidth, framerate, nframes = params[:4]
str_data = f.readframes(nframes) # 读取波形数据
f.close()
wave_data = np.frombuffer(str_data, dtype=np.short) # 波形数据转数组
nframe = np.arange(0, nframes)
print(len(wave_data))
print(len(nframe))
return nframe, wave_data
def pre_emphasis(signal, coeff):
return np.append(signal[0], signal[1:] - coeff * signal[:-1])
# 得到每个采样点的声压级 Pref = 2e-5
def get_SPL(signal):
SPL = []
for i in range(len(signal)):
SPL.append(20 * np.log10(np.sqrt(signal[i] ** 2) / 2e-5) + 1e-5) # 增加一个很小的数改变精度
return SPL
def plot_aLL(time, signal, num, title, y): # 时间、信号、编号、标题
plt.subplot(num)
plt.plot(time, signal, y)
plt.xlabel('time/s')
plt.ylabel('Ampltitude')
plt.title(title)
if __name__ == "__main__":
# path = "speech/noise.wav"
path = "speech/预加重.wav"
A = read_file(path)
plot_aLL(A[0], A[1], 221, "orignal_wav", '-g') # 绘制图片
signal = pre_emphasis(A[1], 0.96) # 预加重
plot_aLL(A[0], signal, 222, "after_emphasis", "-r") # 绘制图片
SPL = get_SPL(A[1])
plt.subplot(223)
plt.plot(A[0], SPL, "-g")
plt.xlabel('nframes')
plt.ylabel('sound pressure level(dB/Hz)')
plt.title("before_emphasis's SPL")
SPL2 = get_SPL(pre_emphasis(A[1], 0.97)) # 预加重后的声压级
plt.subplot(224)
plt.plot(A[0], SPL2, "-r")
plt.xlabel('nframes')
plt.ylabel('sound pressure level(dB/Hz)')
plt.title("after_emphasis's SPL")
plt.tight_layout()
plt.show()
若有写错之处,请各位大佬帮忙指正!!