Python语音基础操作--6.3ADPCM编码

《语音信号处理试验教程》(梁瑞宇等)的代码主要是Matlab实现的,现在Python比较热门,所以把这个项目大部分内容写成了Python实现,大部分是手动写的。使用CSDN博客查看帮助文件:

Python语音基础操作–2.1语音录制,播放,读取
Python语音基础操作–2.2语音编辑
Python语音基础操作–2.3声强与响度
Python语音基础操作–2.4语音信号生成
Python语音基础操作–3.1语音分帧与加窗
Python语音基础操作–3.2短时时域分析
Python语音基础操作–3.3短时频域分析
Python语音基础操作–3.4倒谱分析与MFCC系数
Python语音基础操作–4.1语音端点检测
Python语音基础操作–4.2基音周期检测
Python语音基础操作–4.3共振峰估计
Python语音基础操作–5.1自适应滤波
Python语音基础操作–5.2谱减法
Python语音基础操作–5.4小波分解
Python语音基础操作–6.1PCM编码
Python语音基础操作–6.2LPC编码
Python语音基础操作–6.3ADPCM编码
Python语音基础操作–7.1帧合并
Python语音基础操作–7.2LPC的语音合成
Python语音基础操作–10.1基于动态时间规整(DTW)的孤立字语音识别试验
Python语音基础操作–10.2隐马尔科夫模型的孤立字识别
Python语音基础操作–11.1矢量量化(VQ)的说话人情感识别
Python语音基础操作–11.2基于GMM的说话人识别模型
Python语音基础操作–12.1基于KNN的情感识别
Python语音基础操作–12.2基于神经网络的情感识别
Python语音基础操作–12.3基于支持向量机SVM的语音情感识别
Python语音基础操作–12.4基于LDA,PCA的语音情感识别

代码可在Github上下载busyyang/python_sound_open

自适应差分脉冲编码调制(Adaptive Differential Pulse Code Modulation, ADPCM)结合了ADM的差分信号与PCM的二进制编码的方法,采用预测编码来压缩数据量。体现在使用预测技术减少量化编码器输入信号的冗余度,将差值信号编码以提高效率,降低编码信号速率,广泛应用与语音和图像信号的数字化。

自适应量化

在语音信号量化器中,为了适应信号的动态范围,需要把量化阶距选的足够大,另外为了减少量化噪声,有希望减小量化阶距。语音信号在很宽的范围内幅值变化,为了适应这样的变化,就是使用自适应量化器。也就是让量化阶距与输入信号的幅度变化向匹配,一个等效的方法是,在一个固定的量化器前加入一个自适应的增益控制,是的进入量化器的输入信号方差保持为固定常数。

根据对 Δ ( n ) \Delta (n) Δ(n) G ( n ) G(n) G(n)的估计方法不同,自适应量化有两类:1. 输入幅值或方差由输入本身估算——前反馈自适应量化器(AQF);2. 量化阶距根据量化器输出 x ^ ( n ) \hat x(n) x^(n)来进行自适应调整,或等效用输出码字 c ( n ) c(n) c(n)进行自适应调整——反馈自适应量化器(AQB)。

差值脉冲编码调制

差值脉冲编码调制器(DPCM)是指量化器具有两个以上电平的差值量化系统。与直接量化PCM相比,带固定预测器的DPCM系统在信噪比方面可以有4-11dB的改善。在从没有预测到一阶预测时,预测阶数一直增到4或5得到较小的附加增益,信噪比上的增益意味着可用较少位数得到给定的SNR,其位数少于在使用同样量化器直接对话音波形进行量化时所需要的值。例如对于带均匀固定量化器的差值PCM系统来说,与直接作用在输入端的电平数日相同的量化器相比,差值PCM系统信噪比大约要改善6dB。差值方案具有如PCM那样的性能, 即每增加一位码SNR提高6dB,并且信噪比同样依赖于信号电平。类似地,在差值结构中采用p律量化器可使SNR改善6dB,同时其信噪比特性对输入信号也是不敏感的。

由于讲话者和语音内容不同以及语音通信巾罔有的信号电平变化,若要使输入信号电平
在很宽范嗣内变化时系统仍然能达到最好的性能,需要采用自适应预测和自适应量化,种系统因而被称为ADPCM。

自适应差值脉冲编码调制

预测方程为:
x ˉ ( n ) = ∑ k = 1 p a k ( n ) x ^ ( n − k ) \bar x(n)=\sum^p_{k=1}a_k(n)\hat x(n-k) xˉ(n)=k=1pak(n)x^(nk)

预测器系数自适应时,通常加色短时间内语音信号的性质保持恒定。采用短时间内方均预测误差最小的准则选择预测器系数,最佳预测其系数满足:
R n ( j ) = ∑ k = 1 p a k ( n ) R n ( j , k ) , j = 1 , 2 , . . . , p R_n(j)=\sum_{k=1}^pa_k(n)R_n(j,k),j=1,2,...,p Rn(j)=k=1pak(n)Rn(j,k),j=1,2,...,p

R n ( j ) = ∑ m = − ∞ ∞ x ( m ) w ( n − m ) x ( j + m ) w ( n − m − j ) , 0 ⩽ j ⩽ p R_n(j)=\sum_{m=-\infty}^{\infty}x(m)w(n-m)x(j+m)w(n-m-j),0\leqslant j\leqslant p Rn(j)=m=x(m)w(nm)x(j+m)w(nmj),0jp

import numpy as np


def adpcm_decoder(code, sign_bit):
    """
    APDCM解码函数
    :param code:
    :param sign_bit:
    :return:
    """
    l = len(code)
    y = np.zeros(l)
    ss2 = np.zeros(l)
    ss2[0] = 1
    # 生成步长查找表
    index = [-1, 4]
    currentIndex = 0
    startval = 1
    endval = 127
    base = np.exp(np.log(2) / 8)
    # 近似步长
    const = startval / base
    numSteps = int(round(np.log(endval / const) / np.log(base)))
    n = [i + 1 for i in range(numSteps)]
    base = np.exp(np.log(endval / startval) / (numSteps - 1))
    const = startval / base
    tabel2 = np.round(const * np.power(base, n))

    for n in range(1, l):
        neg = code[n] >= sign_bit
        if neg:
            temp = code[n] - sign_bit
        else:
            temp = code[n]
        temp2 = (temp + 0.5) * ss2[n - 1]
        if neg:
            temp2 = -temp2
        y[n] = y[n - 1] + temp2
        if y[n] > 127:
            y[n] = 127
        elif y[n] < -127:
            y[n] = -127
        # 计算新的步长
        currentIndex += index[int(temp)]
        if currentIndex < 0:
            currentIndex = 0
        elif currentIndex > numSteps:
            currentIndex = numSteps
        ss2[n] = tabel2[currentIndex]
    return y / 128


def adpcm_encoder(x, sign_bit):
    """
    APDCM编码函数
    :param x:
    :param sign_bit:
    :return:
    """
    x *= 128
    l = len(x)
    # 生成步长查找表
    index = [-1, 4]
    currentIndex = 1
    startval = 1
    endval = 127
    base = np.exp(np.log(2) / 8)
    # 近似步长
    const = startval / base
    numSteps = int(round(np.log(endval / const) / np.log(base)))
    n = [i + 1 for i in range(numSteps)]
    base = np.exp(np.log(endval / startval) / (numSteps - 1))
    const = startval / base
    tabel2 = np.round(const * np.power(base, n))

    ss = np.zeros(l)
    ss[0] = tabel2[0]
    z = np.zeros(l)
    code = np.zeros(l)
    d = np.zeros(l)
    neg = 0
    for n in range(1, l):
        d[n] = x[n] - z[n - 1]
        if d[n] < 0:
            neg = 1
            code[n] += sign_bit
            d[n] = -d[n]
        else:
            neg = 0
        if d[n] >= ss[n - 1]:
            code[n] += 1
        if neg:
            temp = code[n] - sign_bit
        else:
            temp = code[n]
        temp2 = (temp + 0.5) * ss[n - 1]
        if neg:
            temp2 = -temp2
        z[n] = z[n - 1] + temp2
        if z[n] > 127:
            z[n] = 127
        elif z[n] < -127:
            z[n] = -127
        # 计算新的步长
        currentIndex += index[int(temp)]
        if currentIndex < 0:
            currentIndex = 0
        elif currentIndex > numSteps:
            currentIndex = numSteps
        ss[n] = tabel2[currentIndex]
    return code

from chapter2_基础.soundBase import *
from chapter3_分析实验.lpc import lpc_coeff

from chapter6_语音编码.ADPCM import *

plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

data, fs = soundBase('C6_3_y.wav').audioread()
N = len(data)
time = [i / fs for i in range(N)]  # 设置时间
sig_bit = 2

ss = adpcm_encoder(data, sig_bit)
yy = adpcm_decoder(ss, sig_bit)

plt.subplot(2, 1, 1)
plt.plot(time, data / np.max(data), 'k')
plt.plot(time, yy / np.max(yy), 'c')
plt.title('ADPCM解码')
plt.legend(['信号', '解码信号'])
plt.subplot(2, 1, 2)
plt.plot(data / np.max(data) - yy / np.max(yy))
plt.title('误差')
plt.show()

在这里插入图片描述

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值