【音频滤波】两个谱减法滤波的例子~如何用谱减法滤除宽带or窄带噪声?

3 篇文章 0 订阅
1 篇文章 0 订阅

前言

首先祝大家元宵节快乐,这是在本科的时候《离散信号处理》的一个作业,今天整理硬盘发现了,发上来给大家作为谱减法的入门参考。

示例1(宽带白噪声的滤除)

频谱分析

拿到信号,第一步一般是先观察信号的频谱。
宽带白噪声污染下的信号频谱
从上图可以看出,此噪声是一个宽带白噪声,幸运的是噪声并没有把有用的频谱成分淹没。

谱减法初步处理

通过观察,有用信号的频谱振幅基本都在 200 以上,所以只要截取频谱幅度大于 200 的部分,就可以基本保留原始信号的主要信息,并且可以较好地过滤掉宽带白噪声。
截取结果如下图所示。
截取频谱幅度大于 200 的部分后
以上初步处理结果试听后,发现声音中仍然有尖锐的声音,这可能是由上图中的 6kHz 到 8kHz 以及2kHz附近的高频噪声导致的,所以,为了滤除高频噪声,还需要使信号通过一个低通滤波器。

低通滤波处理

数字频率

数字频率即为归一化的频率,其定义为:
f d = f a / f s ∗ 2 f_d =f_a/f_s*2 fd=fa/fs2
其中, f s f_s fs表示信号的采样率,单位为(Hz); f a f_a fa为模拟频率,其最大值为采样率的一半; f d f_d fd表示模拟频率 f a f_a fa所对应的数字频率。

低通滤波器的设计

通过观察“初步处理后的频谱”,需要设置一个截止到1kHz的0.8kHz低通滤波器,因为信号的采样率为16kHz,所以数字频率分别为1kHz对应0.125,0.8kHz对应0.1。
设计出的FIR滤波器的分析如下图所示,上面的是幅频响应曲线,下面的是相频响应曲线。
FIR滤波器的幅频响应与相频响应图
观察幅频响应曲线可以发现该FIR滤波器在通带内保持平缓,在约0.125时截止。从相频响应曲线可以看到滤波器在通带内的响应具有线性相位,这点可以保证滤波时相位不失真。

滤波结果

滤波最终结果的频谱如下图所示,从图中可以看到大于1kHz的杂音都被去除了。
滤波结果频谱
接下来就可以聆听一下滤波后的结果。

示例2(窄带噪声的滤除)

频谱分析

按照惯例,第一步肯定是频谱分析。
原信号频谱
可以看到,信号被中心频率约为1.2kHz的窄带噪声所污染,同时,有用的频谱成分的幅度都在 1000 以下,所以用谱减法截取幅度在1000以下的频谱成分。

初步处理结果

初步处理结果如下图所示,截取后对音频进行试听,发现仍然有刺耳的交流成分,猜测是 1.2kHz 附近的
残留噪声在作怪,于是对信号进行二次截取。
初步处理结果频谱

最终处理结果

为了保留信号最重要的成分,二次截取选择的开始频率为 1kHz,截取幅度小于 450 的频谱成分。二次截取后的频谱如下图所示,此为滤波的最终结果。
最终处理结果频谱
接下来就可以聆听一下滤波后的结果了。

代码

示例1的主运行文件为soundHandle.m
示例2为soundHandle2.m

下载链接

GitHub:https://github.com/highskyno1/spectral-subtraction
度盘:https://pan.baidu.com/s/1LBkkCbTOAsxawiDDz9m7LA
提取码:e2pg

示例1代码

soundHandle.m

clear;
close;
[y,fs]=audioread('./处理前1.wav');
fq = fft(y);
%获取频谱的半长度
length_half = floor(length(fq)/2);
%计算数字频率
f_x = fs/2*(0:length_half-1)/length_half;
figure(1);
%观察信号的频谱
plot(f_x,abs(fq(1:length_half)));
title('原始信号的频谱');
xlabel('频率(Hz)');
ylabel('幅度');
%初始化频谱输出
fo = zeros(1,length(y));
for i = 1:1:length(y)
    if(abs(fq(i)) >= 200)
        fo(i) = fq(i);  %截取大于幅度200的频率成分
    end
end
figure(2);
%观察截取到的频谱
plot(f_x,abs(fo(1:length_half)));
title('初步处理后的频谱');
xlabel('频率(Hz)');
ylabel('幅度');
%把初步处理的结果变换回时域
yo = ifft(fo);
%把初步处理的结果进行低通滤波
%获取FIR滤波序列
h = lowPass(0.1,0.125,0.017,0.017);
%分析滤波器
figure(4);
freqz(h);
%用卷积实现滤波
yo = conv(h,yo);
yof = fft(yo);
figure(3);
%观察低通滤波的结果的频谱
plot(f_x,abs(yof(1:length_half)));
title('最终输出的频谱');
xlabel('频率(Hz)');
ylabel('幅度');
%播放并保存结果
sound(yo,fs);
audiowrite('./处理后1.wav',yo,fs);

lowPass.m

function h = lowPass(Fp,Fs,ds,dp)
%lowPass 返回按要求设计的数字FIR滤波器实现对输入信号的低通滤波
%     Fp 低通数字频率
%     Fs 通带截止数字频率
%     ds 阻带波动
%     dp 通带波动
    f = [Fp Fs];
    a = [1 0];
    dev = [dp ds];
    [N,fo,ao,w] = remezord(f,a,dev);
    h = remez(N,fo,ao,w);   %时域的滤波器
end

示例2代码

clear;
close;
[y,fs]=audioread('./处理前2.wav');
fq = fft(y);
f_len_half = floor(length(fq)/2);
f_x = fs/2*(0:f_len_half-1)/f_len_half;
figure(1);
%观察声音的频谱
plot(f_x,abs(fq(1:f_len_half)));
title('原声音信号的频谱');
xlabel('频率(Hz)');
ylabel('幅度');
%截取频谱幅度小于800的部分
fo = zeros(1,length(fq));
for i=1:1:length(fq)
    if abs(fq(i)) < 1000
        fo(i) = fq(i);
    end
end
figure(2);
plot(f_x,abs(fo(1:f_len_half)));%处理后的频谱
title('初步处理后的频谱');
xlabel('频率(Hz)');
ylabel('幅度');
%截取大于1kHz部分的幅度小于500的部分频谱
low = 30000;    %对应1kHz
fo2 = [fo(1:low),zeros(1,length(fo)-2 * low),fo(length(fo)-low+1:length(fo))];
for i=low + 1:1:length(fo)-low
    if abs(fo(i)) < 450
        fo2(i) = fo(i);
    end
end
yout = ifft(fo2);%把信号从频域返回至时域
figure(3);
yof = fft(yout);
long3 = floor(length(yof)/2);
fout = fs/2/long3*(0:long3-1);
plot(fout,abs(yof(1:long3)));
title('最终处理结果的频谱');
xlabel('频率(Hz)');
ylabel('幅度');
sound(yout,fs);
audiowrite('./处理后2.wav',yout,fs);

后语

现在还是研究生的寒假,学校3月1号开学,一开学了估计又没有时间写文章了。看到这了,不点个赞再走嘛?

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值