语音的声学处理通常称为特征提取或者信号分析,特征是表示语音信号的一个时间片的矢量。常见的特征类型有LPC(线性预测编码)特征和PLP(感知线性预测编码),该特征称为声谱特征,使用形成波形的不同频度的分布来表示这个波形,这种频度分布称为声谱。

1. 基本概念

(1)声波

说话者使用特定的方式通过声门由口腔或鼻腔流出,就造成了空气压力变化,我们将描画空气压力对于时间的变化情况的方法来表示声波。声波在空气中是一种纵波,它的振动方向和传播方向是一致的。

波有两个重要的特征:频度(frequency)和振幅(amplitude)

频度:是1s内波本身重复的次数,或称为‘周’(cycle)

振幅:空气压力变化的大小是振幅,振幅越高,压力越大

人类感知特性::音高(pitch)是与频率有关,音强是和语音的响度有关。

(参考:语音识别:原理与应用)

(2)声谱

声谱特征是根据Fourier对于复杂波的深入研究提出来的。Fouries指出,每个复杂波都可以表示为很多频度不同的简单波的总和。声谱是一个波的这些不同频度成分的表示。声谱图也称为幅度谱或者幅值谱,横轴是时间,纵轴是频率,一般是指短时傅里叶变换后得到的不含相位信息的时频图,对于梅尔谱变换成为功率谱。

(3)频谱

频谱是频率密度的简称,就是频率的分布曲线。复杂振荡分解为振幅不同和频率不同的谐振荡,这些谐振荡的幅值按频率排列的图形叫频谱。

(4)周期图

周期图是一种信号功率谱密度估计方法。为得到功率谱固估值,先取信号序列的离散傅里叶变换,然后取其幅频特征的平方并除以序列长度N,由于序列的离散傅里叶具有周期性,因而这种功率谱也具有周期性,常称为周期图。

(5)常见指标

过零率(zero crossing rate)是信号符号变化的比率,即,在每帧中,语音信号从正变为负或从负变为正的次数。过零率越大,频率近似越高。

谱质心(Spectral Centroid)是描述音色属性的重要物理参数之一,是频率成分的重心,是在一定频率范围内通过能量加权平均的频率,其单位是Hz。它是声音信号的频率分布和能量分布的重要信息。谱质心描述了声音的明亮度,具有阴暗、低沉品质的声音倾向有较多低频内容,谱质心相对较低,具有明亮、欢快品质的多数集中在高频,谱质心相对较高。

声谱衰减是对声音信号形状(波形图)的一种衡量,表示低于总频谱能量的指定百分比的频率。

色度频率是音乐音频有趣且强大的表示,其中整个拼欧被投影到12个区间,代表音乐八度音的12个不同的半音(或色度)

2. 信号处理

输入的声波要进行数字化,就是进行模拟-数字转换,也称为声谱特征的抽取过程,抽取过程从声波本身开始,以特征矢量结束。模拟-数字转换的过程分为两步:采样(sampling)和量化(quantization)。

(1)采样

采样是指对模拟信号在时间域上的离散化过程,即把一个时间上连续、幅度上连续的模拟信号转换成时间上离散、幅度上连续的信号。

采样率是每秒采样点数,通常的采样率是8khz,16khz,采样的方法通常是奈奎斯特(Nyquist)定理,当采样率大于信号中最高频率的两倍时,采样之后的数字信号能够完整保留原始信号中的信息。

(2)量化

量化是将采样之后的实数值进行整数化的过程,量化之后还会有编码过程,常见的编码有PCM编码(脉冲编码调制),MP3编码等。

3.特征提取

语音识别需要进行特征提取,就是提取语音信号中有助于理解语音内容的部分而丢弃其他的东西,常见的语音特征提取方式如下图:

3.1 预处理

预处理过程是对语音信号进行预加重、分帧和加窗处理,目的是对信号进行合理分段。

(1)预加重

因为高频信号的能量通常较低,受到的抑制影响越大,因此需要增加高频部分的能量,即补偿语音信号高频部分的振幅。好处有:增加高频部分的能量使得能量分布更加均衡;防止傅里叶变换的数值计算不稳定;有可能增加信噪比,计算公式为

其中是预加重的系数,默认为0.97

(2)分帧

语音信号是一个非平稳信号,但是考虑在发浊音时声带有规律地振动,即基音频率在短时间范围内是相对固定的,语音信号具有短时平稳特性,认为10ms~30ms的语音信号是一个准稳态过程。短时分析主要采用分帧方式,相邻两帧之间的基因可能发生变化,为保证声学特征参数的平滑性,一般采用重叠取帧的方式。

将语音信号进行切割,且保证一定的重复率。核心参数有帧长(每帧的长度)和帧移(移动的距离)。对信号进行分帧,范围是20-40ms,通常采用25ms,考虑到信号的重叠性,每次移动10ms,通常一帧(信号的采样频率是16kHZ)有16000*25/1000=400个样本点。移动10ms,则16000*10/1000=160个样本点,则每次移动160个样本。

(换算详情:1s=1000ms,1khz=1000hz,赫兹是频率单位),如果最后一帧不够400个样本点,可以考虑用0补齐。

分帧方式相当于对语音信号进行了加矩形窗的处理,易出现频谱泄露,因此需要加窗函数。

(3)加窗

考虑到语音信号的短时平稳性,对每帧信号进行加窗处理,常见的窗函数有:汉明窗、汉宁窗、布莱克曼窗。公式为

其中,w[n]是窗函数,N是窗长,l是帧索引,L是帧移。

3.2 各类特征(更多细节实现看参考资料)

(1)前期资料

美尔尺度(Mel Scale)

美尔尺度是建立从人类的听觉感知的频率到声音实体频率直接的映射。通过把频率转换为美尔尺度,特征能够更好的匹配人类的听觉感知效果。从频率到梅尔频率的转换公式,

从梅尔频率到频率的转换公式为:

梅尔滤波器组

梅尔滤波器的长度与功率谱相等,每个滤波器只有对于需要采集的频率范围是非零,其余都是0。

计算梅尔滤波器组的参数

  • 转换,使用梅尔尺度公式将最小和最大频率转换为美尔尺度的频率,假设最值是300Hz,8kHz,梅尔频率是401.25Mel,2834.99Mel

  • 划分,若我们有10个滤波器,则需要12个点(加上最大、最小频率),并在最值范围内平均分配

  • 将梅尔频率转换为频率,

  • 创建滤波器组

第一个滤波器开始于第一个点(300Hz),峰值在第二个点(517Hz)结束于第三个点(781Hz),第一个滤波器开始于第二个点(517Hz),峰值在第三个点(781Hz)结束于第四个点(1103Hz),公式为

Bark频率

临时频带是在某一段频率范围内纯音和噪声功率相等,则该纯音处于刚好能被听到的临界状态,一个临界频带的宽带被称为一个Bark,Bark频率和线性频率的对应关系如下:

(2)FBank特征

FBank特征提取的步骤:

  • 对语音信号进行分帧处理

  • 用周期图法进行功率谱估计(短时傅里叶)

  • 对功率谱用Mel滤波器组进行滤波,计算每个滤波器里的能量(fBank特征)

  • 对每个滤波器的能量取log

(3)MFCC特征

MFCC特征提取的步骤:

  • 对语音信号进行分帧处理

  • 用周期图法进行功率谱估计(短时傅里叶)

  • 对功率谱用Mel滤波器组进行滤波,计算每个滤波器里的能量(fBank特征)

  • 对每个滤波器的能量取log

  • 进行离散余弦变换(DCT)

  • 保留DCT的第2-13个系数,去掉其他

(3)PLP特征

  • 对语音信号进行分帧处理

  • 用周期图法进行功率谱估计(短时傅里叶)

  • 临界频带分析(Bark滤波器)

  • 等响度预加重

  • 强度响度转换

  • 逆傅里叶变换

  • 线性预测,通过使线性预测到的采样点值在最小均方误差约束下逼近实际语音采样点值,可以求取一组唯一的预测系数,简称为线性预测编码(Linear prediction coding,LPC)

(4)区别与联系

滤波器:MFCC、FBank是用梅尔滤波器,PLP是Bark滤波器。

STFT:三者都采用短时傅里叶变换。

优点:FBank保留更多原始特征,适用于DNN建模;MFCC去相关性较好,适合GMM建模;PLP抗燥性更强。

4.librosa中的实现

4.1 流程图

4.2 相关函数的参数

(1)MFCC参数

4.3 实现细节

(1)MFCC函数

def mfcc(y=None, sr=22050, S=None, n_mfcc=20, dct_type=2, norm="ortho", lifter=0, **kwargs
):if S is None:S = power_to_db(melspectrogram(y=y, sr=sr, **kwargs))M = scipy.fftpack.dct(S, axis=0, type=dct_type, norm=norm)[:n_mfcc]if lifter > 0:M *= (1+ (lifter / 2)* np.sin(np.pi * np.arange(1, 1 + n_mfcc, dtype=M.dtype) / lifter)[:, np.newaxis])return Melif lifter == 0:return Melse:raise ParameterError("MFCC lifter={} must be a non-negative number".format(lifter))

(2)功率谱计算(melspectrogram)+滤波

该函数里边包含了功率谱计算和Mel滤波器进行滤波的过程,其中_spectrogram是进行功率谱计算,filters.mel则建立滤波器。

def melspectrogram(y=None,sr=22050,S=None,n_fft=2048,hop_length=512,win_length=None,window="hann",center=True,pad_mode="reflect",power=2.0,**kwargs):S, n_fft = _spectrogram(y=y,S=S,n_fft=n_fft,hop_length=hop_length,power=power,win_length=win_length,window=window,center=center,pad_mode=pad_mode,)# Build a Mel filtermel_basis = filters.mel(sr, n_fft, **kwargs)return np.dot(mel_basis, S)

功率谱计算主要是用短时傅里叶变换stft计算:

def _spectrogram(y=None,S=None,n_fft=2048,hop_length=512,power=1,win_length=None,window="hann",center=True,pad_mode="reflect"):if S is not None:# Infer n_fft from spectrogram shapen_fft = 2 * (S.shape[0] - 1)else:# Otherwise, compute a magnitude spectrogram from inputS = (np.abs(stft(y,n_fft=n_fft,hop_length=hop_length,win_length=win_length,center=center,window=window,pad_mode=pad_mode,))** power)return S, n_fft

mel滤波器是通过filter.mel进行滤波器建立:

def mel(sr,n_fft,n_mels=128,fmin=0.0,fmax=None,htk=False,norm="slaney",dtype=np.float32):if fmax is None:fmax = float(sr) / 2# Initialize the weightsn_mels = int(n_mels)weights = np.zeros((n_mels, int(1 + n_fft // 2)), dtype=dtype)# Center freqs of each FFT binfftfreqs = fft_frequencies(sr=sr, n_fft=n_fft)# 'Center freqs' of mel bands - uniformly spaced between limitsmel_f = mel_frequencies(n_mels + 2, fmin=fmin, fmax=fmax, htk=htk)fdiff = np.diff(mel_f)ramps = np.subtract.outer(mel_f, fftfreqs)for i in range(n_mels):# lower and upper slopes for all binslower = -ramps[i] / fdiff[i]upper = ramps[i + 2] / fdiff[i + 1]# .. then intersect them with each other and zeroweights[i] = np.maximum(0, np.minimum(lower, upper))if norm == "slaney":# Slaney-style mel is scaled to be approx constant energy per channelenorm = 2.0 / (mel_f[2 : n_mels + 2] - mel_f[:n_mels])weights *= enorm[:, np.newaxis]else:weights = util.normalize(weights, norm=norm, axis=-1)# Only check weights if f_mel[0] is positiveif not np.all((mel_f[:-2] == 0) | (weights.max(axis=1) > 0)):# This means we have an empty channel somewherewarnings.warn("Empty filters detected in mel frequency basis. ""Some channels will produce empty responses. ""Try increasing your sampling rate (and fmax) or ""reducing n_mels.")return weights

5. 实例

import librosa
import librosa.display as displayv = librosa.load('./english.wav')mfcc = librosa.feature.mfcc(v[0])import matplotlib.pyplot as pltdisplay.specshow(mfcc)
plt.colorbar()
# display.waveshow(v[0])

结果:

6.额外数学原理

6.1 短时傅里叶变换

声音信号是随时间变化,通过傅里叶变换只能将其转换到频域,失去了时域信息,无法看出频率分布随时间变化规律。短时傅里叶是把一段长信号分帧、加窗,再对每一帧做快速傅里叶变换(FFT),最后把每一帧的结果沿另一个维度堆叠起来,就得到了二维信号形式。

利用离散傅里叶变换(DFT)把每一帧信号变换到时域,公式是

其中,s(n)表示时域信号, si(n)是第i帧的数据,n范围是[1,400],Si(k)是第i帧的第k个复数,Pi(k)是第i帧的功率谱,h(n)是一个N点的窗函数,K是DFT的长度,计算功率谱:

经过短时傅里叶变换之后,得到一个复数,复数的实部代表频率的振幅,复数的虚部代表频率的相位,即得到功率谱。

参考:

语音信号的梅尔频率倒谱系数(MFCC)的原理讲解及python实现 - 凌逆战 - 博客园

MFCC特征提取教程 - 李理的博客

语音识别:原理与应用

语音处理入门——语音的声学处理相关推荐

  1. 从鸡尾酒会问题入门语音分离

    前言 谷歌这篇文章<Looking to Listen at the Cocktail Party: A Speaker-Independent Audio-Visual Model for S ...

  2. 语音处理入门概念整理(一)

    刚开始接触语音处理方面的内容,围观论文的时候,发现有很多专用名词不明白,想着先学习了解这方面的一些概念知识打打基础. 涉及概念参考来源:<语言学概论>.知乎语音类回答 1)语音识别ASR ...

  3. anki vector robot入门语音指令大全

    vector机器人功能不断完善. 一:刚开始支持一些基础指令,你跟他说话他能在本机识别,然后做出相应的响应.在说这部分指令之前,需要加上Hey Vector.(嘿,维课的),然后他会准备听取你的指令, ...

  4. 语音信号处理_书单 | 语音研究进阶指南

    作为人类最自然的交流方式,"听"和"说"包括了人类大脑皮层从听觉感知到语言处理和理解,再到声音生成这个"神奇"的认知过程.语音领域的探索和研 ...

  5. 波束形成、回声消除、声源定位及端到端等语音信号处理算法

    现今信息技术飞速发展,语音技术源源不断地融入到各个领域,语音信号处理是人机接口的关键技术,已广泛应用于直播.在线通话.智能音箱等产品中. (落地应用) 随着语音产品广泛落地应用,语音行业飞速发展,各大 ...

  6. TTS Text-to-speech(文字转语音)服务

    目录 中文帮助文档: 创建语音资源: 填写注册信息: 转到资源服务 编写测试代码(C#): C#需要的包[NuGet搜索:CognitiveServices] 视频连接: 官网链接:Speech St ...

  7. 音视频开发(39)---语音增强

    语音增强 1.1 语音增强概况   语音增强,英文名:Speech Enhancement,其本质就是语音降噪,换句话说,日常生活中,麦克风采集的语音通常是带有不同噪声的"污染"语 ...

  8. 从产品经理的角度,看手机端语音助手

    从产品经理的角度,看手机端语音助手 本文从PM的角度对手机端语音助手进行了思考,包括当前市场情况.PM在设计产品时的思路等. 一.手机端语音助手的现状 苹果siri的出现,带动了手机端智能助手的发展, ...

  9. 语音信号预处理大牛信息

    Zheng-Hua Tan 的主页: http://kom.aau.dk/~zt/index.htm#Research interests (谭政华博士曾经是美国麻省理工学院(MIT)计算机科学与人工 ...

最新文章

  1. PyTorch实现,GitHub 4000星:这是微软开源的计算机视觉库
  2. shiro 全局变量定义
  3. 【Groovy】编译时元编程 ( 编译 ASTTransformation | 打包 ASTTransformation 字节码文件 | 编译 Groovy 类同进行编译时处理 )
  4. Tez UI界面一直处于loading
  5. Java网络编程2---Socket-TCP编程
  6. 计算机专业直接工作简历,2017计算机专业工作简历
  7. 新发布AlbumOnNet 、dotnetCharting控件注册资料
  8. Base64与文件(docx)流的加密和解密
  9. 配置了tomcat,更改了默认端口为8070,还是访问不了
  10. Car-like Robot运动模型及应用分析
  11. 测试金士顿固态硬盘软件,金士顿固态硬盘优化工具(Kingston Toolbox)
  12. 注册码生成器及加密程序
  13. 【矩阵论】线性空间与线性变换(5)
  14. 程序员与颈椎病(一) 我得了什么病
  15. 弗洛伊德求最小简单环
  16. linux上的客户端连接window上的服务器
  17. JavaScript设计模式——工厂模式
  18. 使用main方法启动spring程序
  19. 吐血之作 | 流系统Spark/Flink/Kafka/DataFlow端到端一致性实现对比
  20. 电影《铃芽之旅》观后感

热门文章

  1. 男性早孕-从软件与程序的区别说起
  2. 收集最全的Joomla教材网站和joomla模板网站
  3. String(byte[] bytes, int offset, int length)
  4. Ubuntu17.04 之 systemd 设置开机启动
  5. Linux中chown和chmod的区别和用法
  6. loewe测试软件,实测Loewe三角包 最轻的小包最贴心的设计
  7. android按钮响应事件吗,Android 按钮响应事件的几种方式
  8. php注入教程,php注入点构造代码实例详解
  9. html+监听+页面滚动到底部,解决HTML5中滚动到底部的事件问题
  10. springboot+thymeleaf+pageHelper带条件分页查询