语音经发声者的口唇辐射发出,空气作为语音信号传播的介质,在传播声音信号能量的同时也消耗能量,语音信号的频率越高,介质对声音能量的损耗越严重,预加重能在一定程度上弥补高频部分的损耗,保护声道的信息。假设输入信号第 𝑛个采样点为 𝑥[𝑛],预加重公式如下

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()

若有写错之处,请各位大佬帮忙指正!!

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐