语音信号处理
写作原因
知道了语音信号需要采样率和采样位数,知道了MFCC提取的整个流程,但是中间的幅值变化的细枝末节还是需要细究的,比如:
- matlab/python读取wav文件默认是浮点数,但是保存是整数?
- 调整音频幅度后,MFCC如何变化?
因为是备忘录属性,所以行文口语化,即废话多,重点模糊。
wav文件读取
wav格式
- 标头;
- 第一个区块:声道数量、采样率等信息;
- 第二个区块:数据,以小端序存储。
内容以区块(chunk)为最小单位,每一区块长度为4字节 ,从这可以看出,数据是 整数 还是 浮点数 ,取决于读取的方式。
读取wav文件(matlab/python)
养成读matlab源代码的习惯:
open function_name
matlab audioread()
audioread(filename, range, datatype)
前两项不做解释。仅关注数据读出类型时,使用 AUDIOREAD(FILENAME, DATATYPE),当DATATYPE='double'时,读出的数据为范围为0.0~1.0的浮点数;当DATATYPE='native'时,读出的数据是 采样位数 范围内的整数。
当不加DATATYPE参数时,读出的数据是浮点数。
% [Y, FS]=AUDIOREAD(FILENAME, DATATYPE) specifies the data type format of
% Y used to represent samples read from the file.
% If DATATYPE='double', Y contains double-precision normalized samples.
% If DATATYPE='native', Y contains samples in the native data type
% found in the file. Interpretation of DATATYPE is case-insensitive and
% partial matching is supported.
% If omitted, DATATYPE='double'.
python
python读wav文件的方式很多,librosa默认是读成浮点数的,待查证。
写入wav文件(matlab/python)
matlab audiowrite()
audiowrite(filename,y,Fs,varargin)
语音数据保存时,不需指定数据类型,数据类型信息包含在数据中,根据该函数的注释内容如下:
% Data Type of Y Valid Range for Y
% -----------------------------------
% uint8 0 <= Y <= 255
% int16 -32768 <= Y <= +32767
% int32 -2^32 <= Y <= 2^32-1
% single -1.0 <= Y <= +1.0
% double -1.0 <= Y <= +1.0
所以如果想用整数保存数据时,一定要先将数据转为目标格式。比如class(ones(1, 16000))查看数据类型,ones默认生成double数据,给它乘上大于1的整型数据,得出的结果依然是double类型,直接保存wav文件时,大于1.0的部分被截断,得不到想要的结果。
python
待补充。
audition查看语音幅值
调出 振幅统计 窗口
导航栏 -> 窗口 -> 振幅统计

audition的振幅统计计算如最下面的小字所示,参考的国际电联推荐标准《ITU-R BS.1770-3》。
MFCC
教材上已经有许多MFCC特征提取的步骤了,回过神来,尽是《信号与系统》的基础知识。所以难怪都默认大家能够推导出来吗,真是一段艰难的路程。
还有,不觉得最后这个C系数很难理解吗?每次教材里给出一堆三角形的Mel banks后,直接DCT然后就得出个系数,通常是一串向量/一个矩阵,真的很难理解。
看matlab一步一步计算,发现一个Mel bank对一帧频谱只得出一个结果,为什么是这样?然后刚才突然想到了:一帧频谱中,对每个刻度的频率只有一个系数来表示,那么一个Mel bank对应的就是一个刻度的频率,所以这个bank的系数就代表了能量,n 个Mel bank得出n个能量系数。所以多帧Mel bank的系数,就叫做Mel 频谱。
至于DCT系数,它对应的应该是傅里叶变换中的那个 e − j ω n e^{-j \omega n } e−jωn(写的是连续傅里叶变换的符号,不过都差不多啦),也就是它的n越多,恢复的信号和原信号的差别越小。
把一帧数目可能是512、1024、2048的频谱变成最多13个的mel频谱,再变回n个DCT系数的信号,语音真是大大压缩了啊。
话说偶尔也能想通这些事情,但是很快就会忘记,重复这样的循环,这次记下来应该就不会忘了吧。另外,突然卷积神经网络!每个卷积层,可以自行设定卷积核的数目,一个卷积核是3维的,宽、高和输入特征层的通道数。普通卷积,首先每个卷积核的通道和对应的特征通道进行计算,然后所有通道相加的结果,作为这个通道的输出。而深度可分离卷积中的depthwise层,只有 一个 卷积核,且每个通道与特征通道计算,但是最后 没有相加 。
与语音幅值的变化关系
参考赵力《语音信号处理实验教程》C3_4_y_4.m相关程序。
语音信号幅值比较
原语音简单乘以0.5,用以比较。

预加重
% 预加重滤波器
xx=double(x);
xx=filter([1 -0.9375],1,xx);
滤波器只在频域上起作用的话,时域的信号量岂不是降低了?虽然说是提高高频分量,但是低频分量怎么办啊。
!在一篇硕士毕业论文里看到了,预加重的目的是提升高频部分,使信号的频谱变得平坦,保持在低频到高频的整个频带中,能用同样的信噪比求频谱,以便于频谱分析。

分帧
处理输入数据的第一帧,画个图显示下。

一帧MFCC特征提取
% fft后频谱对称,所以只取一半
n2=fix(frameSize/2)+1;
% 计算每帧的MFCC参数
for i=1:size(xx,1)
y = xx(i,:);
s = y' .* hamming(frameSize);
t = abs(fft(s));
t = t.^2;
c1=dctcoef * log(bank * t(1:n2));
c2 = c1.*w';
m(i,:)=c2';
end
下面将根据这段程序对每个步骤绘图。
加海明窗

频谱取绝对值且平方

通过mel滤波器得到mel频谱
- 8个不同颜色绘制的mel滤波器
看起来不太像三角形,也许程序用的不是三角形。

- 新生成的频谱系数
这是对每个滤波器,最后只生成了一个系数值(为什么?)。

mel系数log化
matlab里用的都是log,但其实是ln

DCT倒谱
首先看一下DCT系数的样子,因为想输出12个MFCC系数,所以DCT有12行。显示的是第12行。

按行去对12行DCT系数相加,最后得到的结果都是约为0,所以!
d c t c o e f ∗ l o g _ s p e e c h 1 = d c t c o e f ∗ ( l o g _ s p e e c h 0.5 + l n 4 ) = d c t c o e f ∗ l o g _ s p e e c h 0.5 + d c t c o e f ∗ l n 4 ≈ d c t c o e f ∗ l o g _ s p e e c h 0.5 + 0 = d c t c o e f ∗ l o g _ s p e e c h 0.5 dctcoef * log\_speech_{1} \\ = dctcoef * (log\_speech_{0.5} + ln4 ) \\ = dctcoef * log\_speech_{0.5} + dctcoef * ln4 \\ \approx dctcoef * log\_speech_{0.5} + 0 \\=dctcoef * log\_speech_{0.5} dctcoef∗log_speech1=dctcoef∗(log_speech0.5+ln4)=dctcoef∗log_speech0.5+dctcoef∗ln4≈dctcoef∗log_speech0.5+0=dctcoef∗log_speech0.5
即原始语音无论乘以多少倍,在经过log,倍数变加减数;加减数乘以dctcoef后,数值约为0;因此语音的MFCC几乎无变化。


原本我以为频谱随着时域系数变化,体现了能量的变化,MFCC也一定随之变化。结果真是大大出乎我的意料。该试试,语音乘以
2
倍
数
2^{倍数}
2倍数什么样子了。
语音乘以 2 倍 数 2^{倍数} 2倍数,MFCC无改变。
本文探讨了语音信号处理中MFCC的提取过程,包括wav文件的读取、幅值变化对MFCC的影响。内容涵盖matlab和python的wav文件操作,以及Audition中查看语音幅值的方法。MFCC的详细步骤如预加重、分帧、海明窗、mel滤波器和DCT等被分析,揭示了即使语音幅度变化,MFCC特征也能保持相对稳定。
726

被折叠的 条评论
为什么被折叠?



