代码之家  ›  专栏  ›  技术社区  ›  Han Zhengzu

如何通过傅里叶变换去除周期信号中的噪声,获得更好的滤波效果

  •  0
  • Han Zhengzu  · 技术社区  · 4 年前

    我正在使用Python通过傅里叶变换过滤信号。

    原始信号是由一些仪器产生的,这些仪器应该包含基于周期的波动信号。示例如下所示:

    enter image description here

    我的目标是提取每个周期的每个平台作为一个单独的样本。在基于FFT的方法中,我尝试先得到一条更平滑的曲线,然后使用微分法得到突变点(最大/最小微分值)。基于起始点和结束点(如下图所示),我可以识别包含几个数据点的每个样本 enter image description here

    然而,这种方法遇到了问题,因为原始信号还包含一些非感测信号,这些信号不有用,但导致FFT滤波的结果更差。

    下面是我使用的部分数据和整个时间序列的代码和结果。在子图2中我们可以看到,由于最终噪声的影响,滤波后的信号不能反映原始信号周期的实际变化。

    import pandas as pd
    import numpy as np
    from scipy import fftpack
    from scipy.signal import find_peaks, general_gaussian, fftconvolve
    
    test = pd.read_csv("https://raw.githubusercontent.com/envhyf/Notebook/master/example_raw_signal.csv")
    
    def fft_filter(sig):
        time_step = 1
        period = len(sig)
        time_vec  = np.arange(0, period,time_step)
    
        # reference: https://scipy-lectures.org/intro/scipy/auto_examples/plot_fftpack.html
        sig_fft = fftpack.fft(sig)
        
        power = np.abs(sig_fft)**2
        sample_freq = fftpack.fftfreq(sig.size, d=time_step)
    
        
        pos_mask = np.where(sample_freq > 0)
        freqs = sample_freq[pos_mask]
        peak_freq = freqs[power[pos_mask].argmax()]
        
        high_freq_fft = sig_fft.copy()
        high_freq_fft[np.abs(sample_freq) > peak_freq] = 0
        filtered_sig = fftpack.ifft(high_freq_fft)
    
        return filtered_sig
    
    fig = plt.figure(figsize=(12, 6))
    
    ##########only extract part of the signal#######################
    ax = plt.subplot(211)
    sig          = cutting_sig(test).F2.values[0:600]
    sig_filtered = fft_filter(sig)
    period    = len(sig)
    time_step = 1
    time_vec  = np.arange(0, period,time_step)
    
    
    plt.plot(time_vec, sig, label='Original signal')
    plt.plot(time_vec,sig_filtered , linewidth=2, label='Filtered signal')
    
    
    deriv = np.diff(sig_filtered)
    pos_peaks, pos_details = find_peaks(deriv)
    neg_peaks, neg_details = find_peaks(-deriv)
    plt.scatter(time_vec[pos_peaks], sig_filtered[pos_peaks],color = 'r')
    plt.scatter(time_vec[neg_peaks], sig_filtered[neg_peaks],color = 'k')
    
    plt.title('Part of the data')
    plt.xlabel('Time [s]')
    plt.legend(loc='best')
    
    #######################################################################
    ax = plt.subplot(212)
    sig          = cutting_sig(test).F2.values#[0:600]
    sig_filtered = fft_filter(sig)
    period    = len(sig)
    time_step = 1
    time_vec  = np.arange(0, period,time_step)
    
    
    plt.plot(time_vec, sig, label='Original signal')
    plt.plot(time_vec,sig_filtered , linewidth=2, label='Filtered signal')
    
    
    deriv = np.diff(sig_filtered)
    pos_peaks, pos_details = find_peaks(deriv)
    neg_peaks, neg_details = find_peaks(-deriv)
    plt.scatter(time_vec[pos_peaks], sig_filtered[pos_peaks],color = 'r')
    plt.scatter(time_vec[neg_peaks], sig_filtered[neg_peaks],color = 'k')
    plt.title('Whole series')
    
    plt.legend()
    
    plt.tight_layout()
    
    plt.show()
    
    

    enter image description here

    所以,我的问题是如何预先去除这些噪声,然后进行FFT滤波以达到我的目标?我想不出摆脱那些坏数据点的方法。如有任何建议或意见,将不胜感激。

    0 回复  |  直到 4 年前