Python 从FFT中找出信号的周期

Python 从FFT中找出信号的周期,python,signal-processing,fft,Python,Signal Processing,Fft,我有一个周期信号,我想找出周期。 由于存在边界效应,我首先通过查看第一个和最后一个极小值来切割边界并保持N个周期 然后,我计算FFT 代码: 我知道列表中的两个点之间有多少时间(即采样频率,在本例中为190 Hz)。我认为fft应该给我一个峰值,对应于一个周期中的点数,从而给我点数和周期。 然而,这根本不是我观察到的结果: 我目前的猜测是,0处的峰值对应于我信号的平均值,7处的小峰值应该是我的周期(尽管重复模式仅包括5个点) 我做错了什么?谢谢 您的数据是正确的,只是您没有正确地预处理它:

我有一个周期信号,我想找出周期。

由于存在边界效应,我首先通过查看第一个和最后一个极小值来切割边界并保持N个周期

然后,我计算FFT

代码:

我知道列表中的两个点之间有多少时间(即采样频率,在本例中为190 Hz)。我认为fft应该给我一个峰值,对应于一个周期中的点数,从而给我点数和周期。 然而,这根本不是我观察到的结果:

我目前的猜测是,0处的峰值对应于我信号的平均值,7处的小峰值应该是我的周期(尽管重复模式仅包括5个点)


我做错了什么?谢谢

您的数据是正确的,只是您没有正确地预处理它:

  • 第一个巨峰是信号的DC/平均值。如果在计算DFT之前减去它,它就会消失
  • 在进行DFT之前不加窗信号将在DFT频谱中产生振铃,降低峰值并提高“非峰值”
  • 如果包括这两个步骤,结果应该会比您预期的更好:

    import numpy as np
    import scipy.signal
    
    from matplotlib import pyplot as plt
    
    L = np.array([2.762, 2.762, 1.508, 2.758, 2.765, 2.765, 2.761, 1.507, 2.757, 2.757, 2.764, 2.764, 1.512, 2.76, 2.766, 2.766, 2.763, 1.51, 2.759, 2.759, 2.765, 2.765, 1.514, 2.761, 2.758, 2.758, 2.764, 1.513, 2.76, 2.76, 2.757, 2.757, 1.508, 2.763, 2.759, 2.759, 2.766, 1.517, 4.012])
    L = np.round(L, 1)
    # Remove DC component
    L -= np.mean(L)
    # Window signal
    L *= scipy.signal.windows.hann(len(L))
    
    fft = np.fft.rfft(L, norm="ortho")
    
    plt.plot(L)
    plt.figure()
    plt.plot(abs(fft))
    

    您将注意到,您将看到一个峰值约为
    8
    ,另一个峰值为
    16
    的两倍。这也是预期的:周期信号在
    n*周期
    采样后始终是周期性的,其中n是任何自然数。在您的例子中:
    n*8

    FFT幅值结果中的峰值表示频率,它是周期的倒数。将频率指数倒数乘以FFT窗口长度,得到窗口长度相同单位的周期结果。

    一旦去除信号的DC部分,该函数可以与自身卷积以捕获周期。事实上,卷积将在周期的每个倍数处出现峰值。FFT可用于计算卷积

    fft = np.fft.rfft(L, norm="ortho")
    
    def abs2(x):
        return x.real**2 + x.imag**2
    
    selfconvol=np.fft.irfft(abs2(fft), norm="ortho")
    
    第一个输出不是很好,因为图像的大小不是周期的倍数

    正如Nils-Werner所注意到的,可以使用窗口来限制光谱泄漏的影响。作为替代方案,可以使用周期的第一个粗略估计来中继信号,并且正如我在中回答的那样,可以重复该过程

    从那里,得到周期归结为找到第一个最大值。以下是一种方法:

    import numpy as np
    import scipy.signal
    
    from matplotlib import pyplot as plt
    
    L = np.array([2.762, 2.762, 1.508, 2.758, 2.765, 2.765, 2.761, 1.507, 2.757, 2.757, 2.764, 2.764, 1.512, 2.76, 2.766, 2.766, 2.763, 1.51, 2.759, 2.759, 2.765, 2.765, 1.514, 2.761, 2.758, 2.758, 2.764, 1.513, 2.76, 2.76, 2.757, 2.757, 1.508, 2.763, 2.759, 2.759, 2.766, 1.517, 4.012])
    L = np.round(L, 1)
    # Remove DC component, as proposed by Nils Werner
    L -= np.mean(L)
    # Window signal
    #L *= scipy.signal.windows.hann(len(L))
    
    fft = np.fft.rfft(L, norm="ortho")
    
    def abs2(x):
        return x.real**2 + x.imag**2
    
    selfconvol=np.fft.irfft(abs2(fft), norm="ortho")
    selfconvol=selfconvol/selfconvol[0]
    
    plt.figure()
    plt.plot(selfconvol)
    plt.savefig('first.jpg')
    plt.show()
    
    
    # let's get a max, assuming a least 4 periods...
    multipleofperiod=np.argmax(selfconvol[1:len(L)/4])
    Ltrunk=L[0:(len(L)//multipleofperiod)*multipleofperiod]
    
    fft = np.fft.rfft(Ltrunk, norm="ortho")
    selfconvol=np.fft.irfft(abs2(fft), norm="ortho")
    selfconvol=selfconvol/selfconvol[0]
    
    plt.figure()
    plt.plot(selfconvol)
    plt.savefig('second.jpg')
    plt.show()
    
    
    #get ranges for first min, second max
    fmax=np.max(selfconvol[1:len(Ltrunk)/4])
    fmin=np.min(selfconvol[1:len(Ltrunk)/4])
    xstartmin=1
    while selfconvol[xstartmin]>fmin+0.2*(fmax-fmin) and xstartmin< len(Ltrunk)//4:
        xstartmin=xstartmin+1
    
    xstartmax=xstartmin
    while selfconvol[xstartmax]<fmin+0.7*(fmax-fmin) and xstartmax< len(Ltrunk)//4:
        xstartmax=xstartmax+1
    
    xstartmin=xstartmax
    while selfconvol[xstartmin]>fmin+0.2*(fmax-fmin) and xstartmin< len(Ltrunk)//4:
        xstartmin=xstartmin+1
    
    period=np.argmax(selfconvol[xstartmax:xstartmin])+xstartmax
    
    print "The period is ",period
    
    将numpy导入为np
    导入scipy.signal
    从matplotlib导入pyplot作为plt
    [2.762,2.765,2.765,2.765,2.765,2.765,2.765,2.761,2.761,1.761,1.507,2.507,2.757,2.757,2.757,2.767,2.767,2.762.762,2.761,1.761,1.761,1.507 7 7 7,1.7 7,1.7 7 7 7,2.7 7,2.7 7 7,2.7 7 7,2.764,2.764,2.764,2.764,2.764,2.764,2.764,2.764,2,2.764,2.7,2.7,2.7,2.7,2.764,2.7,2.7,2.7,2.7,2.7,2.764,2.7,4.012])
    L=np圆(L,1)
    #按照Nils-Werner的建议,移除直流组件
    L-=np.平均值(L)
    #窗口信号
    #L*=scipy.signal.windows.hann(len(L))
    fft=np.fft.rfft(L,norm=“正交”)
    def abs2(x):
    返回x.real**2+x.imag**2
    自卷积=np.fft.irfft(abs2(fft),norm=“正交”)
    自车队=自车队/自车队[0]
    plt.图()
    plt.plt.plot(自车队)
    plt.savefig('first.jpg'))
    plt.show()
    #让我们得到一个最大值,假设至少有4个周期。。。
    multipleofperiod=np.argmax(自卷积[1:len(L)/4])
    Ltrunk=L[0:(len(L)//多周期)*多周期]
    fft=np.fft.rfft(Ltrunk,norm=“正交”)
    自卷积=np.fft.irfft(abs2(fft),norm=“正交”)
    自车队=自车队/自车队[0]
    plt.图()
    plt.plt.plot(自车队)
    plt.savefig('second.jpg'))
    plt.show()
    #获取第一个最小值和第二个最大值的范围
    fmax=np.max(自卷积[1:len(Ltrunk)/4])
    fmin=np.min(自卷积[1:len(Ltrunk)/4])
    xstartmin=1
    而自卷积[xstartmin]>fmin+0.2*(fmax-fmin)和xstartmin
    原来的周期是5,不是8。哦,我跳过了信号裁剪。等等,也许这和信号的不平衡结构有关?(每1个低值对应4个高值)?它是不平衡的,但仍然是周期性的。我的信号处理课程落后了一点,但是fft应该会让我在信号频率和谐波方面有一个尖峰。谢谢你的解决方案。然而,我无法生成没有频率泄漏的第二个图形。我没有得到的第二个部分是主干:
    Ltrunk==L
    按照您定义它的方式
    Ltrunk
    的长度是
    (len(L)/multipleofperiod)*multipleofperiod
    。但它是一个整数除法:只要
    len(L)
    不是
    multipleofperiod
    的倍数,
    len(Ltrunk)
    就不同于
    len(L)
    。事实上,如果第一次传递产生的
    multipleofperiod
    是准确的,则它是
    multipleofperiod
    的倍数,即周期的倍数。然后,消除光谱泄漏。否则,如果估计的
    multipleofperiod
    与周期显著不同,则第二次估计也将受到频谱泄漏的困扰。这可能只是我的python中的一个问题,但如果a和b不是整数,我就不能使用列表[a:b]。。。每次都会出错,我想我明白了!您可能正在使用Python3,其中
    /
    表示浮点除法。你能试着用
    /
    吗?
    import numpy as np
    import scipy.signal
    
    from matplotlib import pyplot as plt
    
    L = np.array([2.762, 2.762, 1.508, 2.758, 2.765, 2.765, 2.761, 1.507, 2.757, 2.757, 2.764, 2.764, 1.512, 2.76, 2.766, 2.766, 2.763, 1.51, 2.759, 2.759, 2.765, 2.765, 1.514, 2.761, 2.758, 2.758, 2.764, 1.513, 2.76, 2.76, 2.757, 2.757, 1.508, 2.763, 2.759, 2.759, 2.766, 1.517, 4.012])
    L = np.round(L, 1)
    # Remove DC component, as proposed by Nils Werner
    L -= np.mean(L)
    # Window signal
    #L *= scipy.signal.windows.hann(len(L))
    
    fft = np.fft.rfft(L, norm="ortho")
    
    def abs2(x):
        return x.real**2 + x.imag**2
    
    selfconvol=np.fft.irfft(abs2(fft), norm="ortho")
    selfconvol=selfconvol/selfconvol[0]
    
    plt.figure()
    plt.plot(selfconvol)
    plt.savefig('first.jpg')
    plt.show()
    
    
    # let's get a max, assuming a least 4 periods...
    multipleofperiod=np.argmax(selfconvol[1:len(L)/4])
    Ltrunk=L[0:(len(L)//multipleofperiod)*multipleofperiod]
    
    fft = np.fft.rfft(Ltrunk, norm="ortho")
    selfconvol=np.fft.irfft(abs2(fft), norm="ortho")
    selfconvol=selfconvol/selfconvol[0]
    
    plt.figure()
    plt.plot(selfconvol)
    plt.savefig('second.jpg')
    plt.show()
    
    
    #get ranges for first min, second max
    fmax=np.max(selfconvol[1:len(Ltrunk)/4])
    fmin=np.min(selfconvol[1:len(Ltrunk)/4])
    xstartmin=1
    while selfconvol[xstartmin]>fmin+0.2*(fmax-fmin) and xstartmin< len(Ltrunk)//4:
        xstartmin=xstartmin+1
    
    xstartmax=xstartmin
    while selfconvol[xstartmax]<fmin+0.7*(fmax-fmin) and xstartmax< len(Ltrunk)//4:
        xstartmax=xstartmax+1
    
    xstartmin=xstartmax
    while selfconvol[xstartmin]>fmin+0.2*(fmax-fmin) and xstartmin< len(Ltrunk)//4:
        xstartmin=xstartmin+1
    
    period=np.argmax(selfconvol[xstartmax:xstartmin])+xstartmax
    
    print "The period is ",period