首先祝大家元宵节快乐,这是在本科的时候《离散信号处理》的一个作业,今天整理硬盘发现了,发上来给大家作为谱减法的入门参考。
拿到信号,第一步一般是先观察信号的频谱。
从上图可以看出,此噪声是一个宽带白噪声,幸运的是噪声并没有把有用的频谱成分淹没。
通过观察,有用信号的频谱振幅基本都在 200 以上,所以只要截取频谱幅度大于 200 的部分,就可以基本保留原始信号的主要信息,并且可以较好地过滤掉宽带白噪声。
截取结果如下图所示。
以上初步处理结果试听后,发现声音中仍然有尖锐的声音,这可能是由上图中的 6kHz 到 8kHz 以及2kHz附近的高频噪声导致的,所以,为了滤除高频噪声,还需要使信号通过一个低通滤波器。
数字频率即为归一化的频率,其定义为:
f d = f a / f s ∗ 2 f_d =f_a/f_s*2 fd=fa/fs∗2
其中, 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滤波器在通带内保持平缓,在约0.125时截止。从相频响应曲线可以看到滤波器在通带内的响应具有线性相位,这点可以保证滤波时相位不失真。
滤波最终结果的频谱如下图所示,从图中可以看到大于1kHz的杂音都被去除了。
接下来就可以聆听一下滤波后的结果。
按照惯例,第一步肯定是频谱分析。
可以看到,信号被中心频率约为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
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
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号开学,一开学了估计又没有时间写文章了。看到这了,不点个赞再走嘛?