MATLAB:从wav文件中消除高频噪声

时间:2018-11-15 17:16:00

标签: matlab audio filter signal-processing wav

我正在尝试消除the following file中的高频噪声。

这是一个女人在看新闻的文件,高声的声音在上面大声播放。在文件结尾处,其他人开始讲话,但是使用的是另一种语言。

我想过滤掉这种尖锐的声音,并能够清晰地听到女人在读新闻。查看频域:

Unfiltered

我尝试使用低通滤波器和带阻滤波器。带阻滤波器产生的信号不再具有高音调振铃,但是音频不是很清晰,很难弄清正在说什么-低通滤波器也是如此。我猜想这是由于我不仅滤除了噪声,而且滤除了语音的谐波。滤波后还要放大音频信号,因为它比以前更安静。

我是否有某种巧妙的方法来重建语音的和声,以便更清楚地听到正在说的内容?还是我有一个聪明的方法来过滤信号而不损失太多音频清晰度?

如果需要,我可以包含在matlab中使用的任何代码。

注意:

  • 我在链接的图像中将信号移至0

  • 我确实使用filtfilt()而不是filter()

  • 我将butter()用于过滤器

1 个答案:

答案 0 :(得分:0)

鉴于样品中干扰的动态性质,固定滤波器不会产生非常令人满意的结果。为了提高性能,您需要根据干扰估算值动态调整过滤参数。

幸运的是,在这种情况下,干扰非常强烈,并且呈现出相当规则的模式,这使得估计起来更加容易。这可以从信号的spectrogram中看出。 对于以下推导,我们将假设wavfile的样本已存储在数组x中,并且采样率为fs(在提供的样本中为8000Hz)。

[Sx,f,t] = spectrogram(x, triang(1024), 1023, [], fs, 'onesided');

enter image description here

鉴于干扰很强,可以通过在每个时间片中找到峰值频率来获得干扰的频率:

frequency = zeros(size(Sx,2),1);
for k = 1:size(Sx,2)
    [pks,loc] = findpeaks(Sx(:,k));
    frequency(k) = fs * (loc(1)-1);
end

看到干扰是周期性的,我们可以使用离散傅立叶变换来分解该信号:

M = 32*fs;
Ff = fft(frequency, M);
plot(fs*[0:M-1]/M, 20*log10(abs(Ff));
axis(0, 2);
xlabel('frequency (Hz)');
ylabel('amplitude (dB)');

enter image description here

使用前两个谐波作为近似值,我们可以将干扰信号的频率建模为:

T = 1.0/fs
t = [0:length(x)-1]*T
freq = 750.0127340203496
       + 249.99913423501602*cos(2*pi*0.25*t - 1.5702946346796276)
       + 250.23974282864816*cos(2*pi*0.5 *t - 1.5701043282285363);

在这一点上,我们将足以创建一个具有中心频率的窄带滤波器(随着我们不断更新滤波器系数,该中心频率将动态变化),该中心频率由该频率模型提供。但是请注意,不断地重新计算和更新滤波器系数是一个相当昂贵的过程,并且鉴于干扰很强,可以通过锁定干扰相位来做得更好。这可以通过将原始信号的小块与所需频率的正弦和余弦相关联来完成。然后我们可以稍微调整相位,使正弦/余弦与原始信号对齐。

% Compute the phase of the sine/cosine to correlate the signal with
delta_phi = 2*pi*freq/fs;
phi = cumsum(delta_phi);

% We scale the phase adjustments with a triangular window to try to reduce
% phase discontinuities. I've chosen a window of ~200 samples somewhat arbitrarily,
% but it is large enough to cover 8 cycles of the interference around its lowest
% frequency sections (so we can get a better estimate by averaging out other signal
% contributions over multiple interference cycles), and is small enough to capture
% local phase variations.
step = 50;
L    = 200;
win  = triang(L);
win  = win/sum(win);

for i = 0:floor((length(x)-(L-step))/step)
    % The phase tweak to align the sine/cosine isn't linear, so we run a few
    % iterations to let it converge to a phase locked to the original signal
    for iter = 0:1
        xseg   = x[(i*step+1):(i*step+L+1)];
        phiseg = phi[(i*step+1):(i*step+L+1)];
        r1 = sum(xseg .* cos(phiseg));
        r2 = sum(xseg .* sin(phiseg));
        theta = atan2(r2, r1);

        delta_phi[(i*step+1):(i*step+L+1)] = delta_phi[(i*step+1):(i*step+L+1)] - theta*win;
        phi = cumsum(delta_phi);
    end
end

最后,我们需要估计干扰的幅度。在这里,我们选择在语音开始前有一点停顿的最初0.15秒内执行估算,以便估算不会因语音幅度而产生偏差:

tmax = 0.15;
nmax = floor(tmax * fs);
amp  = sqrt(2*mean(x[1:nmax].^2));
% this should give us amp ~ 0.250996990794946

然后,这些参数使我们能够相当精确地重建干扰,并通过直接相减从原始信号中相应地消除干扰:

y = amp * cos(phi)
x = x-y

enter image description here

聆听结果输出,您可能会注意到仍然有微弱的杂音,但与原始干扰相比没有任何变化。显然,这是一个相当理想的情况,其中干扰的参数非常容易估算,结果几乎看起来都太好了,难以置信。随机干扰模式更多时,您可能无法获得相同的性能。

注意:用于此处理的python脚本(以及相应的.wav文件输出)可以在here中找到。