matlab数字信号处理
前言:这一篇是研究matlab数字信号处理(音频)的一个学习总结。在数学方面天赋有限,理解了一些,但是没有做到最后,有兴趣的话可以拿去借鉴做得更完美一些。
这篇的主要目的是分析男女声音的区别,终极目标是实现男女声音的辨识,借鉴了很多人的程序,会在末尾注明参考链接。
1 matlab傅里叶变换
第一步是搞明白傅里叶变换是怎么工作的,原理这里不说了,只看方法和结果,参考的是matlab早期的一个官方文档,现在的文档已经做了改进,稍微复杂一些,道理差不多。
程序如下:
%模拟一个数字信号
t=0:0.001:0.6; %时间序列
x=sin(2*pi*50*t)+sin(2*pi*120*t);%数字信号,两个频率成分,分别为50Hz和120Hz
y=x+2*randn(size(t));%添加随机噪声
%绘制原始信号时域图
figure(1);
plot(1000*t,y);
title('原始信号');
ylabel('amplitude');
xlabel('time(s)');
%快速傅里叶变换
Y=fft(y,512);%此处取前512个采样点
Pyy=Y.*conj(Y)/512;%求能量值,conj是求共轭的意思
%绘制频谱图
figure(2);
f=1000*(0:511)/512;
plot(f,Pyy);
%绘制一半的频谱图
figure(3);
fh=1000*(0:256)/512;
plot(fh,Pyy(1:257));
原始信号:
频谱图:
频谱图.png
毫无疑问,频谱图是对称的。记得研一听懂这部分的时候,我兴奋了一下午,但是我真的想不起来为什么是对称的了,反正显然它是对称的。右边是因为求了复数的模才出来的。实在想知道怎么回事,自己去看吧:与时间无关的故事
所以这里我们显示一半的频谱看一下:
50
120
是不是堪称完美,学到这里我都迫不及待了,觉得分析音频肯定也就这么
回事。如果不考虑终极目标,是差不多。
2 音频分析
这里不提供完整的多人音频分析的内容,只单个分析。
首先是音频的来源,本来想着录音的,但是没有合适的环境,给女朋友录音倒是可以找个安静的地方是吧。但是给别的女生录音……不过最后找到了一个很好的素材,王者荣耀的英雄语音包。英雄语音包下载(密码:vfn3)
先上程序:
[y,fs]=audioread('G:\matlab_homework\matlab_home\audio\张良1.mp3');%读取音频,y数据,fs是采样率
%时域波形图
ft=y(:,1);%读取一个声道的音频
len=length(y);
t=(0:len-1)/fs;%时间序列
%原始信号时域图
figure(1);
plot(t,ft);
title('time');
xlabel('time(s)');
ylabel('amplitude');
%频域波形图
plen=len/32;%改成1就是整个图谱,这里只看前一部分
yf=fft(y,len);
yff=yf.*conj(yf)/len;
tf=(0:len-1)*fs/len;
figure(2);
plot(tf(1:plen),yff(1:plen));
title('fft');
xlabel('Hz');
ylabel('amplitude');
先来看看张良的,先看一下整个频域的图谱:
张良1
呦呵,图大了看不清,愚蠢的人类:
前1/32
大概这么一看,张良作为一个男孩子,他的声音频率主要集中在100-800Hz的样子。
迫不及待的翻出一个女孩子看看:
甄姬
哇塞,一看甄姬妹子的,好个性。仔细看看跟张良的分别,突然觉得这个任务很简单。
- 1 男孩纸的频谱貌似更分散一些
- 2 能量较高的位置貌似比女孩纸靠前一些
其实坐到这个程度本来可以改吧改吧交作业了,可是自己手贱了。
3 更进一步
首先看到这两张图,想到了人的声音肯定是有频率范围的,再者,想知道是不是已经有男女声音辨识的方法了。
于是找到了这张图:
男女声音频率分布
看上面的频谱,好像的确是这个样子。
这里有两个不认识的字,叫基音频率。据说基音就是物体整体发声的声音频率,它可以作为辨识男女声音的一项标准。
于是找到了以下程序:
%filename:manwoman.m
%different man from woman.
%===========================================================
clear;
% [x,fs,bits]=wavread('d.wav', [1 5000]); % 读入声音文件(*.wav)
[y,fs]=audioread('G:\matlab_homework\matlab_home\audio\张良2.mp3'); % 读入声音文件(*.wav)
sound(y,fs); % 数据通过声卡转换为声音
x=y;%fir_lpf(y,fs,400,50);%下面给出滤波函数
%===========================================================
% pause;
data1=x(:,1);
n=0:length(x)-1;
time=n/fs;
subplot(3,1,1) % 绘制2行1列的第1张子图
plot(time,data1) % 以时间为横轴,数据为纵轴作图
xlabel('Time (sec.)') % 标注横坐标
ylabel('Signal Level (Volts)') % 标注纵坐标
grid on % 添加网格
% pause;
% 对采集数据作滤波处理
blocksize =length(data1); % 计算窗函数长度
window = hanning(blocksize); % 计算汉宁窗函数(此函数为MATLAB自带)
data2=window.*data1; % 对数据先作加窗处理
wp=400; %100Hz--400Hz
wp=wp*2/fs;
%wp=3000*2/fs;
[b,a]=ellip(4,0.1,20,wp); % 构造椭圆滤波器
data=filter(b,a,data2); % 求加窗处理后的数据经过滤波器的响应
subplot(3,1,2) % 绘制2行1列的第1张子图
plot(time,data) % 以时间为横轴,数据为纵轴作图
xlabel('Time (sec.)') % 标注横坐标
%ylabel('Signal Level (Volts)') % 标注纵坐标
grid on % 添加网格
% pause;
[xmax,index]=max(data1);
timewin=floor(0.015*fs);
xwin=data1(index-timewin:index+timewin);
[y,lags]=xcov(xwin);
subplot(3,1,3)
plot(lags,y)
grid on
ylen=length(y);
halflen=(ylen+1)/2 +30;
yy=y(halflen: ylen);
[ymax,maxindex] = max(yy);
fmax=fs/(maxindex+30);
disp(['Maximum occurred at ', num2str(fmax), ' Hz'])
f=fmax;
justify=f; %Hz
if justify<180 %limitHz以下判断是男的
display '男'
else
display '女'
end
这个程序主要是通过自相关函数来求取基音频率,然后根据基因频率来辨识男女,我增加了一个低通滤波器,正确率大概有个百分之七八十吧。
低通滤波函数:
function [y]=fir_lpf(x,Fs,fs,fp)
%该函数采用hanning窗实现低通滤波
%x为输入信号,fs,为采样频率
%fs,fp分别为阻带截至频率和通带截至频率
%20150615 by boat
%求对应角频率
ws=fs*2*pi/Fs;
wp=fp*2*pi/Fs;
%求滤波器的最小阶数
B=ws-wp; %过渡带宽取二者中较小的
N=ceil(6.2*pi/B);
%计算滤波器系数
wc=(ws+wp)/2;
hn=fir1(N-1,wc,hanning(N));
y=filter(hn,1,x);
%freqz(hn)
3 翻船了
正当我开心的准备复制粘贴我的结果的时候,翻船了,因为我测试了达摩和露娜的音频。
达摩作为一个纯爷们,给了我这样的图谱:
达摩
能量最高的频率超过了500,这部分不管它,但是大多数峰值都在200以后。
所以说我感觉只寻找基音频率这个方法还是有些问题的,只适用于大多数情况。如果你对比多个人的音频频谱,会看到其实男生声音普遍会从比较低的频率就开始出现,通常在多个频率上能量比较高。
就这么多了,详细的看下面链接学习吧。