从wav文件中去除噪声,MATLAB

14

我只将MATLAB用作计算器,因此我对该程序不太熟悉。希望有善良的人能指导我一下,因为目前谷歌并不是我的朋友。

在下面的链接中,我有一个包含人声和一些背景噪声的wav文件。我想去除噪声。是否有人可以告诉我如何在MATLAB中完成?

https://www.dropbox.com/s/3vtd5ehjt2zfuj7/Hold.wav


听起来说话的人和背景噪声在频谱的不同侧。也许尝试对信号进行频率分解,并带通滤除与噪声有关的那些频率。 - rayryeng
1
你可能会因为这个问题而讨厌我 :/ 但是你怎么做呢? - user3338501
这可能是我的一个愚蠢问题... 你有信号和系统的经验吗?傅里叶变换? - rayryeng
我知道傅里叶变换,但是我已经很多年没和它打交道了。 - user3338501
1个回答

47
这是一种不太完美的解决方案,尤其是因为部分噪音嵌入到文件中与你所听到的语音频率相同,但还是试试吧。我所说的频谱是指如果你听到声音,则背景噪音会有一个非常低的嗡嗡声。这位于频谱的低频范围内,而语音则具有更高的频率。因此,我们可以应用带通滤波器来消除低噪音,捕获大部分语音,并取消任何在较高频率上嘈杂的频率。
以下是我所做的步骤:
  1. 使用audioread读取音频文件。
  2. 播放原始声音,以便我能听到它的声音。通过创建一个audioplayer对象来完成此操作。
  3. 绘制左右声道,以查看时间域中的声音信号……如果有任何线索的话。查看这些通道,它们似乎都是相同的,因此看起来只是将单个麦克风映射到两个通道。
  4. 我进行了傅里叶变换并查看了频率分布。
  5. 使用(4)大致确定应该截断哪些频率。
  6. 设计一个带通滤波器来切掉这些频率。
  7. 过滤信号,然后通过构建另一个audioplayer对象来播放它。

那么让我们开始吧!


步骤 #1

%% Read in the file
clearvars;
close all;
[f,fs] = audioread('Hold.wav');
audioread会为您读取音频文件。只需在''中指定您想要的文件即可。还要确保您设置的工作目录是存储该文件的位置。clearvars,close all只是为我们进行清理。它关闭了所有窗口(如果有打开的窗口),并清除了MATLAB工作区中的所有变量。f将是读入MATLAB的信号,而fs是您信号的采样频率。这里的f是一个二维矩阵。第一列是左声道,第二列是右声道。通常,您音频文件中的总通道数由通过audioread读取的此矩阵中的总列数表示。
%% Play original file
pOrig = audioplayer(f,fs);
pOrig.play;

这一步将帮助您创建一个audioplayer对象,该对象使用读取的信号(f)和采样频率fs,并输出存储在pOrig中的对象。然后使用pOrig.play在MATLAB中播放文件以便您能够听到它。
%% Plot both audio channels
N = size(f,1); % Determine total number of samples in audio file
figure;
subplot(2,1,1);
stem(1:N, f(:,1));
title('Left Channel');
subplot(2,1,2);
stem(1:N, f(:,2));
title('Right Channel');

stem 是在 MATLAB 中绘制离散点的一种方法。每个时间点都有一个圆圈画在该时间点处,从水平轴到该时间点处绘制一条垂直线。subplot 是一种将多个图形放置在同一个窗口中的方法。我不会在这里详细介绍它,但您可以通过参考 这篇我写的 StackOverflow 帖子 了解 subplot 的详细工作原理。上面的代码生成下面所示的图形:

signals

上述代码非常简单明了。我只是在每个子图中单独绘制每个通道。

步骤 #4

%% Plot the spectrum
df = fs / N;
w = (-(N/2):(N/2)-1)*df;
y = fft(f(:,1), N) / N; % For normalizing, but not needed for our analysis
y2 = fftshift(y);
figure;
plot(w,abs(y2));

以上代码可能看起来最令人生畏。如果您还记得信号和系统,那么在我们的信号中表示的最大频率是采样频率除以2。这被称为奈奎斯特频率。您的音频文件的采样频率为48000 Hz,这意味着您的音频文件中表示的最大频率为24000 Hz。fft代表快速傅里叶变换。将其视为计算傅里叶变换的非常有效的方法。传统公式要求您对输出中的每个元素执行多个求和。FFT将通过要求更少的操作来高效地计算此内容,并仍然为您提供相同的结果。

我们使用fft来查看信号的频谱。您可以通过指定要作为第一个参数的输入信号,后跟第二个参数以评估多少点来调用fft。通常,您将FFT中的点数指定为信号的长度。我通过检查声音矩阵中有多少行来实现这一点。当您绘制频率谱时,为了简化操作,我只取了一个通道,因为另一个通道是相同的。这作为fft的第一个输入。此外,请注意,我除以N,因为这是规范化信号的正确方法。但是,由于我们只想拍摄频域的样片,所以您不需要这样做。但是,如果您打算稍后使用它来计算某些内容,那么您绝对需要这样做。
I wrote some additional code as the spectrum by default is uncentered. I used fftshift so that the centre maps to 0 Hz, while the left spans from 0 to -24000Hz while the right spans from 0 to 24000 Hz. This is intuitively how I see the frequency spectrum. You can think of negative frequencies as frequencies that propagate in the opposite direction. Ideally, the frequency distribution for a negative frequency should equal the positive frequency. When you plot the frequency spectrum, it tells you how much contribution that frequency has to the output. That is defined by the magnitude of the signal. You find this by taking the abs function. The output that you get is shown below.

enter image description here

如果你看一下这个图表,你会发现在低频范围内有很多尖峰。这对应着你的嗡鸣声,而声音可能映射到更高的频率范围,因为听到的声音并不多。
第五步:
通过试错和查看第五步,我发现从700 Hz及以下的所有内容都对应着嗡嗡声,而更高的噪音贡献来自于12000 Hz及以上的频率。
第六步:
您可以使用信号处理工具箱中的butter函数来帮助您设计带通滤波器。但是,如果您没有此工具箱,请参考此StackOverflow文章,了解如何使用用户制作的函数实现相同的功能。然而,该滤波器的顺序仅为2。假设您有可用的butter函数,则需要确定您想要的滤波器顺序。顺序越高,它执行的工作就越多。我选择n = 7作为起点。您还需要归一化您的频率,使奈奎斯特频率映射到1,而其他所有内容都映射在0到1之间。完成后,您可以这样调用butter:
[b,a] = butter(n, [beginFreq, endFreq], 'bandpass');

bandpass标志表示您想设计一个带通滤波器,beginFreqendFreq映射到您想要的带通滤波器的归一化开始和结束频率。在我们的情况下,这是beginFreq = 700 / NyquistendFreq = 12000 / Nyquistb,a是用于执行此任务所需的系数。您将需要这些系数进行下一步操作。

%% Design a bandpass filter that filters out between 700 to 12000 Hz
n = 7;
beginFreq = 700 / (fs/2);
endFreq = 12000 / (fs/2);
[b,a] = butter(n, [beginFreq, endFreq], 'bandpass');

第七步

%% Filter the signal
fOut = filter(b, a, f);

%% Construct audioplayer object and play
p = audioplayer(fOut, fs);
p.play;

您可以使用filter来使用第6步得到的内容对信号进行过滤。 fOut 将是您过滤后的信号。如果您想要听它播放,您可以基于此输出信号构建一个与输入相同采样频率的audioplayer。然后在MATLAB中使用p.play来听取它。
请尝试一下并看看它是如何工作的。您可能需要在第6步和第7步中进行最多的尝试。这不是一个完美的解决方案,但希望足以让您入门。
祝你好运!

哇,第一次尝试就成功了,非常感谢您的时间和帮助 :) 我在想,有没有办法放大最终信号?(增加音量) - user3338501
@user3338501 - 这是可能的,但当你到达人声部分时,它可能不起作用,因为噪音在时间域中嵌入了她的声音...这就是为什么我决定去频域的原因。 - rayryeng
我可以问一下怎么做吗? - user3338501
@user3338501 - 那需要单独发一篇帖子来解释。我现在正在工作,所以我必须稍后再为您发布另一篇帖子...可能是在周末。你能等吗? - rayryeng
这将非常好,如果你有时间的话,周末是完美的 :) 我真的很想知道如何操作信号的程序,但很难理解许多在线帖子,你能推荐一本基于Matlab的书吗? - user3338501
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接