【语音去噪】基于matlab谱减法语音去噪【含Matlab源码 571期】

379 阅读3分钟

一、简介

在语音去噪中最常用的方法是谱减法,谱减法是一种发展较早且应用较为成熟的语音去噪算法,该算法利用加性噪声与语音不相关的特点,在假设噪声是统计平稳的前提下,用无语音间隙测算到的噪声频谱估计值取代有语音期间噪声的频谱,与含噪语音频谱相减,从而获得语音频谱的估计值。谱减法具有算法简单、运算量小的特点,便于实现快速处理,往往能够获得较高的输出信噪比,所以被广泛采用。该算法经典形式的不足之处是处理后会产生具有一定节奏性起伏、听上去类似音乐的“音乐噪声”。

转换到频域后,这些峰值听起来就像帧与帧之间频率随机变化的多频音,这种情况在清音段尤其明显,这种由于半波整流引起的“噪声”被称为“音乐噪声”。从根本上,通常导致音乐噪声的原因主要有:
(1)对谱减算法中的负数部分进行了非线性处理
(2)对噪声谱的估计不准
(3)抑制函数(增益函数)具有较大的可变性
1 原理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2 流程图
在这里插入图片描述
3 谱减法的缺点
1)由于对负值进行半波整流,导致帧频谱的随机频率上出现小的、独立的峰值,变换到时域上面,这些峰值听起来就像帧与帧之间频率随机变化的多颤音,也就是通常所说的“音乐噪声”(Musical Noise)
2)另外,谱减法还存在一个小缺点就是使用带噪语音的相位作为增强后语音的相位,因此产生语音的质量可能比较粗糙,尤其是在低信噪比的条件下,可能会达到被听觉感知的程度,降低语音的质量。
为了更好的理解谱减法语音增强,这里对该算法进行简单仿真,仿真参数设置如下
在这里插入图片描述

二、源代码

clear all; clc; close all;

[xx, fs] = wavread('C5_2_y.wav');           % 读入数据文件
xx=xx-mean(xx);                         % 消除直流分量
x=xx/max(abs(xx));                      % 幅值归一化

IS=0.25;                                % 设置前导无话段长度
wlen=200;                               % 设置帧长为25ms
inc=80;                                 % 设置帧移为10ms
SNR=5;                                  % 设置信噪比SNR
N=length(x);                            % 信号长度
time=(0:N-1)/fs;                        % 设置时间

signal=awgn(x,SNR,'measured','db');               % 叠加噪声
snr1=SNR_Calc(x,signal);            % 计算初始信噪比
NIS=fix((IS*fs-wlen)/inc +1);           % 求前导无话段帧数

a=4; b=0.001;                           % 设置参数a和b
output=SpectralSub(signal,wlen,inc,NIS,a,b);% 谱减
snr2=SNR_Calc(x,output);            % 计算谱减后的信噪比
snr=snr2-snr1;
fprintf('snr1=%5.4f   snr2=%5.4f   snr=%5.4f\n',snr1,snr2,snr);
unction frameout=enframe(x,win,inc)

nx=length(x(:));            % 取数据长度
nwin=length(win);           % 取窗长
if (nwin == 1)              % 判断窗长是否为1,若为1,即表示没有设窗函数
   len = win;               % 是,帧长=win
else
   len = nwin;              % 否,帧长=窗长
end
if (nargin < 3)             % 如果只有两个参数,设帧inc=帧长
   inc = len;
end
nf = fix((nx-len+inc)/inc); % 计算帧数
frameout=zeros(nf,len);            % 初始化
indf= inc*(0:(nf-1)).';     % 设置每帧在x中的位移量位置
inds = (1:len);             % 每帧数据对应1:len
frameout(:) = x(indf(:,ones(1,len))+inds(ones(nf,1),:));   % 对数据分帧
if (nwin > 1)               % 若参数中包括窗函数,把每帧乘以窗函数
    w = win(:)';            % 把win转成行数据
    function frameout=filpframe(x,win,inc)

[nf,len]=size(x);
nx=(nf-1) *inc+len;                 %原信号长度
frameout=zeros(nx,1);
nwin=length(win);                   % 取窗长
if (nwin ~= 1)                           % 判断窗长是否为1,若为1,即表示没有设窗函数
    winx=repmat(win',nf,1);
    x=x./winx;                          % 除去加窗的影响
    x(find(isinf(x)))=0;                %去除除0得到的Inf
end

三、运行结果

在这里插入图片描述

四、备注

版本:2014a