Mel滤波器组的设计与实现(基于MATLAB和Python)
1、Mel滤波器组介绍
在语音的频谱范围内设置若干带通滤波器
,
为滤波器的个数。每个滤波器具有三角形滤波特性,其中心频率为
,在Mel频率范围内,这些滤波器是等带宽的。每个带通滤波器的传递函数为
可以用下面的方法加以定义:
式中, 为滤波器频率范围的最低频率; 为滤波器频率范围的最高频率; 为DFT(或FFT)时的长度; 为采样频率; 函数为
的逆函数
为
2、Mel滤波器组的设计
我们设置采样率 ,滤波器频率范围的最低频率 ,滤波器频率范围的最高频率 ;设置滤波器个数 ,FFT的长度 。根据每个带通滤波器的传递函数可以计算出每个Mel滤波器的值,再由设置的滤波器个数可以形成一个Mel滤波器组。注意每个带通滤波器的传递函数值是在Mel频率域上计算的,计算完后再转到频率域上。
3、MATLAB实现
程序:
fs=8000;
fl=0; fh=fs/2;
bl=1125*log(1+fl/700);%将频率转换为Mel频率
bh=1125*log(1+fh/700);
p=24;%滤波器个数
nfft=256;%FFT点数
B=bh-bl;
y=linspace(0,B,p+2);%产生0到B之间p+2个数
Fb=700*(exp(y/1125)-1);%将Mel频率转换为频率
W2=nfft/2+1;%fs/2内对应的FFT点数
df=fs/nfft;
freq=(0:W2-1)*df;%采样频率值
bank=zeros(24,W2);%生成一个24行W2列的全零数组
for k=2:p+1%why从2开始?因为k-1
f1=Fb(k-1); f2=Fb(k+1); f0=Fb(k);
n1=floor(f1/df)+1;%f(m-1)在频域中的谱线索引号
n2=floor(f2/df)+1;%f(m+1)在频域中的谱线索引号
n0=floor(f0/df)+1;%f(m)在频域中的谱线索引号。f(m)是从0开始,而在MATLAB中数组的索引是从1开始,所以要加1,否则会出现index=0的错误
for i=1 : W2
if i>=n1 & i<=n0
bank(k-1,i)=(i-n1)/(n0-n1);
elseif i>n0 & i<=n2
bank(k-1,i)=(n2-i)/(n2-n0);
end
end
plot(freq,bank(k-1,:),'r','linewidth',2); hold on
end
grid;
结果:
4、Python实现
程序:
import numpy as np
import pylab as plt
fs = 8000
fl = 0
fh = fs/2
bl = 1125*np.log(1+fl/700) # 把 Hz 变成 Mel
bh = 1125*np.log(1+fh/700)
p = 24
NFFT=256
B = bh-bl
y = np.linspace(0,B,p+2)# 将梅尔刻度等间隔
#print(y)
Fb = 700*(np.exp(y/1125)-1)# 把 Mel 变成 Hz
#print(Fb)
W2 = int(NFFT / 2 + 1)
df = fs/NFFT
freq = []#采样频率值
for n in range(0,W2):
freqs = int(n*df)
freq.append(freqs)
bank = np.zeros((24,W2))
for k in range(1,p+1):
f1 = Fb[k-1]
f2 = Fb[k+1]
f0 = Fb[k]
n1=np.floor(f1/df)
n2=np.floor(f2/df)
n0=np.floor(f0/df)
for i in range(1,W2):
if i>=n1 and i<=n0:
bank[k-1,i]=(i-n1)/(n0-n1)
elif i>n0 and i<=n2:
bank[k-1,i]=(n2-i)/(n2-n0)
# print(k)
# print(bank[k-1,:])
plt.plot(freq,bank[k-1,:],'r')
plt.show()
结果: