matlab实现端点检测

来源:互联网 发布:蓝月传奇神盾升级数据 编辑:程序博客网 时间:2024/06/11 03:13

端点检测

function [afterEndDet] =EndDetection(x) %================================i========================= % 端点检测 % Input:音频数据x,采样率fs % Output:经过端点检测提取的语音信号 %=========================================================%幅度归一化到[-1,1]x = double(x);x = x / max(abs(x));%常数设置FrameLen = 256;%帧长为256点FrameInc = 80;%帧移为80点amp1 = 10;%初始短时能量高门限amp2 = 2;%初始短时能量低门限zcr1 = 10;%初始短时过零率高门限zcr2 = 5;%初始短时过零率低门限maxsilence = 8;  % 8*10ms  = 80ms%语音段中允许的最大静音长度,如果语音段中的静音帧数未超过此值,则认为语音还没结束;如果超过了%该值,则对语音段长度count进行判断,若count<minlen,则认为前面的语音段为噪音,舍弃,跳到静音%状态0;若count>minlen,则认为语音段结束;minlen  = 15;    % 15*10ms = 150ms%语音段的最短长度,若语音段长度小于此值,则认为其为一段噪音status  = 0;     %初始状态为静音状态count   = 0;     %初始语音段长度为0silence = 0;     %初始静音段长度为0%计算过零率x1=x(1:end-1);x2=x(2:end);%分帧tmp1=enframe(x1,FrameLen,FrameInc);tmp2=enframe(x2,FrameLen,FrameInc);signs = (tmp1.*tmp2)<0;diffs = (tmp1 -tmp2)>0.02;zcr   = sum(signs.*diffs, 2);%一帧一个值%计算短时能量%一帧一个值%amp = sum(abs(enframe(filter([1 -0.9375], 1, x), FrameLen, FrameInc)), 2);amp = sum(abs(enframe(x, FrameLen, FrameInc)), 2);%调整能量门限amp1 = min(amp1, max(amp)/4);amp2 = min(amp2, max(amp)/8); %开始端点检测%For循环,整个信号各帧比较%根据各帧能量判断帧所处的阶段x1 = 0;x2 = 0;v_num=0;%记录语音段数v_Begin=[];%记录所有语音段的起点v_End=[];%记录所有语音段的终点%length(zcr)即为帧数for n=1:length(zcr)   goto = 0;   switch status   case {0,1}                   % 0 = 静音, 1 = 可能开始      if amp(n) > amp1          % 确信进入语音段         x1 = max(n-count-1,1);%          '打印每个x1*FrameInc'%          x1*FrameInc         status  = 2;         silence = 0;         count   = count + 1;      elseif amp(n) > amp2 | ... % 可能处于语音段             zcr(n) > zcr2         status = 1;         count  = count + 1;      else                       % 静音状态         status  = 0;         count   = 0;      end   case 2,                       % 2 = 语音段      if amp(n) > amp2 | ...     % 保持在语音段         zcr(n) > zcr2         count = count + 1;      else                       % 语音将结束         silence = silence+1;         if silence < maxsilence % 静音还不够长,尚未结束            count  = count + 1;         elseif count < minlen   % 语音长度太短,认为是噪声            status  = 0;            silence = 0;            count   = 0;         else                    % 语音结束            status  = 3;         end      end   case 3,      %break;      %记录当前语音段数据      v_num=v_num+1;   %语音段个数加一      count = count-silence/2;      x2 = x1 + count -1;      v_Begin(1,v_num)=x1*FrameInc;       v_End(1,v_num)=x2*FrameInc;      %不跳出 数据归零继续往下查找下一段语音      status  = 0;     %初始状态为静音状态      count   = 0;     %初始语音段长度为0      silence = 0;     %初始静音段长度为0   endend  if length(v_End)==0    x2 = x1 + count -1;    v_Begin(1,1)=x1*FrameInc;     v_End(1,1)=x2*FrameInc;end% subplot(311)    %subplot(3,1,1)表示将图排成3行1列,最后的一个1表示下面要画第1幅图% plot(x)% axis([1 length(x) -1 1])    %函数中的四个参数分别表示xmin,xmax,ymin,ymax,即轴的范围% ylabel('Speech');% for k=1:length(v_End)% line([v_Begin(1,k) v_Begin(1,k)], [-1 1], 'Color', 'g');%这里作用为用直线画出语音段的起点和终点,看起来更直观。第一个[]中的两个参数为线起止点的横坐标,%第二个[]中的两个参数为线起止点的纵坐标。最后两个参数设置了线的颜色。% line([v_End(1,k) v_End(1,k)], [-1 1], 'Color', 'red');% end% % subplot(312)   % plot(amp);% axis([1 length(amp) 0 max(amp)])% ylabel('Energy');% line([x1 x1], [min(amp),max(amp)], 'Color', 'red');% line([x2 x2], [min(amp),max(amp)], 'Color', 'red');% % subplot(313)% plot(zcr);% axis([1 length(zcr) 0 max(zcr)])% ylabel('ZCR');% line([x1 x1], [min(zcr),max(zcr)], 'Color', 'red');% line([x2 x2], [min(zcr),max(zcr)], 'Color', 'red');% figurelenafter=0;for len=1:length(v_End)    tmp=v_End(1,len)-v_Begin(1,len);    lenafter=lenafter+tmp;endlenafterafterEndDet=zeros(lenafter,1);%返回去除静音段的语音信号beginnum=0;endnum=0;     for k=1:length(v_End)        tmp=x(v_Begin(1,k):v_End(1,k));        beginnum=endnum+1        endnum=beginnum+v_End(1,k)-v_Begin(1,k)        afterEndDet(beginnum:endnum)=tmp;     endend

查到的源码基本上是只提取一小段的,自己进行了修改将一段语音中能力低于min门限剪切后,重新拼接成语音。
端点检测后的语音明显去除了空白段,但语音段之间连接不是很流畅(有点像机器人)。


不太确定是否因此起到了反作用。

从我自己的项目测试结果来看,这段代码并没有明显提高识别率。


在此仅作记录。


1 0