用python计算频谱的FFT

用python计算频谱的FFT,python,fft,Python,Fft,频谱显示了波纹,我们可以直观地量化为~50 MHz的波纹。我正在寻找一种方法来计算这些涟漪的频率,而不是通过目视检查数千个光谱。由于函数在频域中,采用FFT将使其返回时域(如果我是正确的,则使用时间反转)。我们如何获得这些涟漪的频率?要获得蓝色曲线图的适当频谱,您需要做两件事: 正确计算频谱图的频率(红色) 消除数据中的偏差,使光谱不受低噪声的污染 频率。那是因为你感兴趣的是波动,而不是缓慢的波动 请注意,当您计算fft时,您会得到包含每个频率的振幅和相位信息的复值。在您的情况下,红色图应该是振

频谱显示了波纹,我们可以直观地量化为~50 MHz的波纹。我正在寻找一种方法来计算这些涟漪的频率,而不是通过目视检查数千个光谱。由于函数在频域中,采用FFT将使其返回时域(如果我是正确的,则使用时间反转)。我们如何获得这些涟漪的频率?

要获得蓝色曲线图的适当频谱,您需要做两件事:

  • 正确计算频谱图的频率(红色)
  • 消除数据中的偏差,使光谱不受低噪声的污染 频率。那是因为你感兴趣的是波动,而不是缓慢的波动
  • 请注意,当您计算fft时,您会得到包含每个频率的振幅和相位信息的复值。在您的情况下,红色图应该是振幅谱(与相位谱相比)。为了得到它,我们取 fft系数

    此外,通过fft得到的频谱是双边对称的(因为信号是真实的)。你真的只需要一面就可以知道你的纹波峰值频率在哪里。我已经在代码中实现了这一点

    在处理完您的数据后,以下是我得到的:

    将熊猫作为pd导入
    将numpy作为np导入
    导入pylab作为plt
    导入plotly.graph_对象作为go
    从scipy导入信号为sig
    df=pd.read\u csv(“ripple.csv”)
    f=测向频率至μnumpy()
    data=df.data
    数据=sig.medfilt(数据)#中值滤波器,用于去除峰值
    图=go.Figure()
    图添加轨迹(go.Scatter(x=f,y=(data-data.mean()))
    图1.2.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1(
    xaxis_title=“频率单位为GHz”,yaxis_title=“dB”
    )#波澜起伏的蓝色地块
    图2(图3)
    #消除偏置以消除低频峰值
    data\u fft=np.fft.fft(data-data.mean())
    L=长度(数据)#样本数
    #计算双边谱
    tssp=abs(数据/L)
    #计算单边谱
    ossp=tssp[0:int(L/2)]
    ossp[1:-1]=2*ossp[1:-1]
    delta_freq=f[1]-f[0]#没有此频率计算是不正确的
    freqs=np.fft.fftfreq(f.shape[-1],delta_freq)
    #使用频率的前半部分,因为频谱是单边的
    plt.绘图(频率[:int(L/2)],ossp,“r-”)#红色绘图
    plt.xlim([0,50])
    plt.xticks(np.arange(0,50,1))
    plt.grid()
    plt.xlabel(“每频率的振荡”)
    plt.show()
    

    所以你可以看到有两个峰值:1到2赫兹之间的低频振荡
    你的纹波频率约为每千兆赫17次振荡。

    要获得蓝色曲线图的合适频谱,你需要做两件事:

  • 正确计算频谱图的频率(红色)
  • 消除数据中的偏差,使光谱不受低噪声的污染 频率。那是因为你感兴趣的是波动,而不是缓慢的波动
  • 请注意,当您计算fft时,您会得到包含每个频率的振幅和相位信息的复值。在您的情况下,红色图应该是振幅谱(与相位谱相比)。为了得到它,我们取 fft系数

    此外,通过fft得到的频谱是双边对称的(因为信号是真实的)。你真的只需要一面就可以知道你的纹波峰值频率在哪里。我已经在代码中实现了这一点

    在处理完您的数据后,以下是我得到的:

    将熊猫作为pd导入
    将numpy作为np导入
    导入pylab作为plt
    导入plotly.graph_对象作为go
    从scipy导入信号为sig
    df=pd.read\u csv(“ripple.csv”)
    f=测向频率至μnumpy()
    data=df.data
    数据=sig.medfilt(数据)#中值滤波器,用于去除峰值
    图=go.Figure()
    图添加轨迹(go.Scatter(x=f,y=(data-data.mean()))
    图1.2.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1(
    xaxis_title=“频率单位为GHz”,yaxis_title=“dB”
    )#波澜起伏的蓝色地块
    图2(图3)
    #消除偏置以消除低频峰值
    data\u fft=np.fft.fft(data-data.mean())
    L=长度(数据)#样本数
    #计算双边谱
    tssp=abs(数据/L)
    #计算单边谱
    ossp=tssp[0:int(L/2)]
    ossp[1:-1]=2*ossp[1:-1]
    delta_freq=f[1]-f[0]#没有此频率计算是不正确的
    freqs=np.fft.fftfreq(f.shape[-1],delta_freq)
    #使用频率的前半部分,因为频谱是单边的
    plt.绘图(频率[:int(L/2)],ossp,“r-”)#红色绘图
    plt.xlim([0,50])
    plt.xticks(np.arange(0,50,1))
    plt.grid()
    plt.xlabel(“每频率的振荡”)
    plt.show()
    

    所以你可以看到有两个峰值:1到2赫兹之间的低频振荡
    而你的纹波大约为每千兆赫17次振荡。

    问题产生于这样一个事实,即你正在测量的术语“频率”和数据的频率之间存在混淆

    您需要的是纹波频率,实际上是数据的周期

    有了这些,我们来看看如何修复fft

    正如所指出的,您必须确定数据的采样频率,并且还必须去除FFT结果中的低频分量

    要确定采样频率,可以通过将每个采样减去其前一个采样并计算平均值来确定采样周期。平均采样频率正好与之相反

    fs = 1 / np.mean(freq[1:] - freq[:-1])
    
    对于高通滤波器,可以使用巴特沃斯滤波器,这是一个很好的实现

    # Defining a high pass filter
    def butter_highpass(cutoff, fs, order=5):
        nyq = 0.5 * fs
        normal_cutoff = cutoff / nyq
        b, a = signal.butter(order, normal_cutoff, btype='high', analog=False)
        return b, a
    
    def butter_highpass_filter(data, cutoff, fs, order=5):
        b, a = butter_highpass(cutoff, fs, order=order)
        y = signal.filtfilt(b, a, data)
        return y
    
    接下来,在绘制fft时,您需要获取它的绝对值,这就是您所追求的。而且,因为它既给你积极的一面,也给你消极的一面,所以你可以只使用积极的一面。就x轴而言,它将是采样频率的0到一半。这是进一步探讨的问题

    现在,要确定纹波频率,只需获得FFT的峰值。您要查找的值(大约50MHz)将是纹波峰值的周期(以GHz为单位),因为您的原始数据以GHz为单位。对于这个例子,它实际上是
    fft_amp = np.abs(np.fft.fft(amp, amp.size))
    fft_amp = fft_amp[0:fft_amp.size // 2]
    fft_freq = np.linspace(0, fs / 2, fft_amp.size)
    
    
    peak = fft_freq[np.argmax(fft_amp)]
    
    ripple_period = 1 / peak * 1000
    
    print(f'The ripple period is {ripple_period} MHz')
    
    import numpy as np
    import pylab as plt
    from scipy import signal as signal
    
    
    # Defining a high pass filter
    def butter_highpass(cutoff, fs, order=5):
        nyq = 0.5 * fs
        normal_cutoff = cutoff / nyq
        b, a = signal.butter(order, normal_cutoff, btype='high', analog=False)
        return b, a
    
    def butter_highpass_filter(data, cutoff, fs, order=5):
        b, a = butter_highpass(cutoff, fs, order=order)
        y = signal.filtfilt(b, a, data)
        return y
    
    
    with open('ripple.csv', 'r') as fil:
        data = np.genfromtxt(fil, delimiter=',', skip_header=True)
    
    amp = data[:, 0]
    freq = data[:, 1]
    
    
    # Determine the sampling frequency of the data (it is around 500 Hz)
    fs = 1 / np.mean(freq[1:] - freq[:-1])
    
    # Apply a median filter to remove the noise
    amp = signal.medfilt(amp)
    
    # Apply a highpass filter to remove the low frequency components 5 Hz was chosen
    # as the cutoff fequency by visual inspection. Depending on the problem, you
    # might want to choose a different value
    
    cutoff_freq = 5
    amp = butter_highpass_filter(amp, cutoff_freq, fs)
    
    _, ax = plt.subplots(ncols=2, nrows=1)
    ax[0].plot(freq, amp)
    ax[0].set_xlabel('Frequency GHz')
    ax[0].set_ylabel('Intensity dB')
    ax[0].set_title('Filtered signal')
    
    # The FFT part is as follows
    
    fft_amp = np.abs(np.fft.fft(amp, amp.size))
    fft_amp = fft_amp[0:fft_amp.size // 2]
    fft_freq = np.linspace(0, fs / 2, fft_amp.size)
    
    ax[1].plot(fft_freq, 2 / fft_amp.size * fft_amp, 'r-')  # the red plot
    ax[1].set_xlabel('FFT frequency')
    ax[1].set_ylabel('Intensity dB')
    
    plt.show()
    
    peak = fft_freq[np.argmax(fft_amp)]
    
    ripple_period = 1 / peak * 1000
    
    print(f'The ripple period is {ripple_period} MHz')