【问题标题】:How to apply low-pass filter to a sound record on python?如何将低通滤波器应用于python上的录音?
【发布时间】:2020-03-14 19:08:00
【问题描述】:

我必须减少录音中的白噪声。因为我使用了傅立叶变换。但我不知道如何使用 fft 函数在频域中的返回值。如何使用 fft 数据来减少噪音?

这是我的代码

from scipy.io import wavfile
import matplotlib.pyplot as plt
import simpleaudio as sa
from numpy.fft import fft,fftfreq,ifft

#reading wav file

fs,data=wavfile.read("a.wav","wb")

n=len(data)

freqs=fftfreq(n)

mask=freqs>0

#calculating raw fft values
fft_vals=fft(data)

#calculating theorical fft values

fft_theo=2*np.abs(fft_vals/n)

#ploting

plt.plot(freqs[mask],fft_theo[mask])
plt.show()```

【问题讨论】:

    标签: signal-processing fft noise noise-reduction whitenoise


    【解决方案1】:

    此类问题最好构建一个综合示例,这样您就不必发布大数据文件,人们仍然可以关注您的问题 (MCVE)。

    绘制中间结果也很重要,因为我们讨论的是对复数的运算,所以我们经常需要分别取 re、im 部分或绝对值和角度。

    实函数的傅立叶变换很复杂,但对于正频率和负频率是对称的。人们也可以从信息论的角度来看待这一点:你不希望 N 个独立的实数及时产生 2N 个独立的实数来描述频谱。

    虽然您通常绘制频谱的绝对平方或绝对平方(电压与功率),但您可以在应用过滤器时使其复杂化。在通过 IFFT 反向转换为时间后,要绘制它,您必须再次将其转换为实数,在这种情况下采用绝对值。

    如果您在时域中设计滤波器内核(高斯的 FFT 将是高斯),滤波器的 FFT 与频谱的乘积的 IFFT 将只有非常小的虚部,然后您可以取实部(从物理学的角度来看更有意义,从实部开始,以实部结束)。

    import numpy as np
    import matplotlib.pyplot as p
    %matplotlib inline
    
    T=3 # secs
    d=0.04 # secs
    n=int(T/d)
    print(n)
    t=np.arange(0,T,d)  
    fr=1 # Hz
    y1= np.sin(2*np.pi*fr*t) +1          # dc offset helps with backconversion, try setting it to zero
    y2= 1/5*np.sin(2*np.pi*7*fr*t+0.5) 
    y=y1+y2 
    f=np.fft.fftshift(np.fft.fft(y))
    freq=np.fft.fftshift(np.fft.fftfreq(n,d))
    
    filter=np.exp(- freq**2/6)  # simple Gaussian filter in the frequency domain
    filtered_spectrum=f*filter  # apply the filter to the spectrum
    
    filtered_data =  np.fft.ifft(filtered_spectrum)  # then backtransform to time domain
    
    
    p.figure(figsize=(24,16))
    
    p.subplot(321)
    p.plot(t,y1,'.-',color='red', lw=0.5, ms=1, label='signal')  
    p.plot(t,y2,'.-',color='blue', lw=0.5,ms=1, label='noise') 
    p.plot(t,y,'.-',color='green', lw=4, ms=4, alpha=0.3, label='noisy signal') 
    p.xlabel('time (sec)')
    p.ylabel('amplitude (Volt)')
    p.legend()
    
    p.subplot(322)
    p.plot(freq,np.abs(f)/n, label='raw spectrum')
    p.plot(freq,filter,label='filter')
    p.xlabel(' freq (Hz)')
    p.ylabel('amplitude (Volt)');
    p.legend()
    
    p.subplot(323)
    p.plot(t,  np.absolute(filtered_data),'.-',color='green', lw=4, ms=4, alpha=0.3, label='cleaned signal')
    p.legend()
    
    p.subplot(324)
    p.plot(freq,np.abs(filtered_spectrum), label = 'filtered spectrum')
    p.legend()
    
    
    p.subplot(326)
    p.plot(freq,np.log( np.abs(filtered_spectrum)), label = 'filtered spectrum') 
    p.legend()
    p.title(' in the log plot the noise is still visible');
    

    【讨论】:

    • 非常感谢您提供了很多帮助 :)。它改变了我心中的一切。因此,如果我将此代码实现到声音文件,我的 d 值将是 1/Fs 对吗?
    • 我应该每次都为我的声音添加一个直流值吗? y1= np.sin(2*np.pifrt) +1 # 直流偏移有助于反向转换,尝试将其设置为零 像这里
    • 实际上,我将不得不再次考虑 DC,这只是一个有效的修复程序。频率间隔是总时间的 1,所以在我的符号中 freq[1]-freq[0] 应该是 1/T。时间间隔是整个频率范围的一倍。频率范围从 - 1/2d 到 +1/2d,因此整体宽度为 1/d。
    猜你喜欢
    • 2014-03-14
    • 2011-02-15
    • 2019-04-29
    • 2016-02-29
    • 2017-07-10
    • 2010-10-23
    • 1970-01-01
    • 2013-07-23
    • 2021-06-12
    相关资源
    最近更新 更多