谱熵与过零率进行语音信号的端点检测

采用双门限法的思路:
检测流程图
首先通过噪声段(随机性大,混乱度高)的谱熵大于语音段,区分出语音的浊音与噪声,保留浊音,另一部分主要是发音起始和终止时的清音阶段与噪声,再由清音的短时过零率低于噪声段,将清音与噪声分离,保留清音,由此就得到了完整的语音段,实现了语音段的端点检测,可以自动去除噪声段。

谱熵定义:在这里插入图片描述在这里插入图片描述

按照矩阵运算的思路编辑程序:先计算分帧矩阵的fft结果,转为dB单位(实验测试了使用dB作为单位效果明显)平方后得到矩阵Y对Y每列的前N/2行相加得概率计算的分母cigmaY再把cigY拓展成N行,便于与Y做./的矩阵运算得到概率矩阵P代入最终的谱熵计算公式即可。代码如下:freq=fft(frame_w,N); %将数据由时域转换到频域spect=real(10log10(freq));%将频域结果单位换dB
Y=spect
conj(spect);%计算能量sumY=sum(Y(1:end/2,:));sumY=sumY(ones(1,N),:);
P=Y./sumY;%计算样本点概率
H=-sum(P(1:end/2,:).*(log2(P(1:end/2,:))));%代入谱熵定义的公式

检测过程根据双门限法的思想,对分帧矩阵做一次帧数的遍历,假如某帧的谱熵小于了高谱熵门限,则可能进入了语音段,继续遍历,假如某帧的谱熵小于了低谱熵门限,确定已经进入了语音段,记录下该帧的位置,从该位置向前遍历,假如某帧的短时过零率大于了过零率门限,确定该帧为噪声首部结束的位置,记录改帧位置为noiseEnd,跳出向前遍历。 接着对噪声尾部处理的思路类似,假如某帧的谱熵小于低谱熵门限,而它的下一帧谱熵高于门限,确定该帧在语音片段,开始向后遍历,加入过零率大于了过零率门限,记录该帧位置为noiseBegin,跳出所有遍历。

思路还是非常清晰的,代码写起来不难。
先给一遍实验流程中得出的图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

下边上完整代码(仅供参考,实验中用到的语音数据为:oh.mat,你自己做可能需要修改相应的门限参数)
此外实验中需要的语音信号分帧函数,我有篇索引分帧法的博文里边有讲解和代码
传送门

%Ocross:短时过零率
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%输入参数:
% frame_w              分帧矩阵
%输出参数:
% zerocross       过零率序列
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function [zerocross]=Ocross(frame_w)
[frame_length,frame_number]=size(frame_w);
zerocross=zeros(1,frame_number);
for i=1 : frame_number     
    u=frame_w(:,i);        % 取出一帧
    for j=1 : frame_length-1
        if u(j)* u(j+1)< 0       % 判断是否为过零点
            zerocross(i)=zerocross(i)+1;   % 是过零点,记录1次
        end % end过零判断
    end     % end单帧循环
end         % end帧数循环
% Experiment 4 endpointDetection
% Apr.18 2020
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
clear
close all
clc
 
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%
load('oh.mat','data');
fs=10000;
N=1024;
 
 
width = 3;     % Width in inches
height = 3;    % Height in inches
alw = 0.75;    % AxesLineWidth
fsz = 13;      % Fontsize
lw = 1.2;      % LineWidth 1.5
msz = 7;       % MarkerSize
 
frame_time=20e-3;
[frame_m,frame_w,frame_length,frame_shift,frame_number]=enframe(data,fs,20e-3,10e-3,'hamming');
% 调用分帧加窗函数,获取分帧矩阵、分帧加窗矩阵、帧长、帧数
timeAxis=(1:frame_number)*20e-3;
zerocross=Ocross(frame_w);
plot(data)
legend('原始语音时域图','Location','best')
xlabel('时间(采用点数)');
ylabel('幅度');
 
mag=sum(abs(frame_w));%幅度
f = (0:N/2-1)/N*fs;  %计算频率序列
freq=fft(frame_w,N); %将数据由时域转换到频域
spect=real(10*log10(freq));%将频域结果单位换算为dB
Y=spect.*conj(spect);%计算能量
sumY=sum(Y(1:end/2,));
sumY=sumY(ones(1,N),);
P=Y./sumY;%计算样本点概率
H=-sum(P(1:end/2,:).*(log2(P(1:end/2,:))));%代入谱熵定义的公式
figure();
plot(timeAxis,H)
legend('谱熵时域图','Location','best')
xlabel('时间/s');
ylabel('幅度');
figure()
subplot(211)
plot(timeAxis,mag)
subplot(212)
plot(timeAxis,H)
EntropyHigh=max(H)*0.995;%谱熵高门限
EntropyLow=min(H)*1.06;%谱熵低门限
hold on
plot([timeAxis(1), timeAxis(end)], [EntropyHigh, EntropyHigh], 'r', 'LineWidth',lw, 'MarkerSize', msz);
plot([timeAxis(1), timeAxis(end)], [EntropyLow, EntropyLow], 'g', 'LineWidth',lw, 'MarkerSize', msz);
legend('谱熵与赋值对比时域图','高谱熵门限','低谱熵门限','Location','best')
xlabel('时间/s');
ylabel('幅度');
figure()
T=24;%设置过零率门限
plot(timeAxis,zerocross)
hold on
plot([timeAxis(1), timeAxis(end)], [T, T], 'r', 'LineWidth',lw, 'MarkerSize', msz);
legend('过零率','门限','Location','best')
xlabel('时间/s');
ylabel('幅度');
 
figure()
plot(data)
hold on
for i=1:frame_number
    if(H(i)<EntropyLow && H(i-1)>EntropyLow )
        noiseEnd=i-1;
        for j=noiseEnd:-1:1
            if(zerocross(j)>T)
                noiseEnd=j;
                break
            end
        end
    end
    if(H(i)<EntropyLow && H(i+1)>EntropyLow )
        noiseBegin=i+1;
        for j=noiseBegin:frame_number
            if(zerocross(j)>T)
                noiseBegin=j;
                break
            end
        end
        break
    end
end
endIndex=noiseEnd*(frame_length+1)/2;
beginIndex=noiseBegin*(frame_length+1)/2;
noise1=data(1:endIndex);
noise2=data(beginIndex:length(data));
plot(noise1,'r')
hold on
plot(beginIndex:length(data),noise2,'g')
legend('原始语音','首噪声段','尾噪声段','Location','best')
xlabel('时间(采样点数)');
ylabel('幅度');
figure()
oh_clean=data(endIndex:beginIndex);
plot(oh_clean)
legend('cleanData','Location','best')
xlabel('时间(采样点数)');
ylabel('幅度');
save('oh_clean')
  • 14
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值