【问题标题】:how to extract frequency associated with fft values in python如何在python中提取与fft值相关的频率
【发布时间】:2011-04-11 07:54:50
【问题描述】:

我在 numpy 中使用了 fft 函数,这导致了一个复杂的数组。如何得到准确的频率值?

【问题讨论】:

    标签: python numpy fft


    【解决方案1】:

    频率只是数组的索引。在索引 n 处,频率为 2πn / 数组的长度(每单位的弧度)。考虑:

    >>> numpy.fft.fft([1,2,1,0,1,2,1,0])
    array([ 8.+0.j,  0.+0.j,  0.-4.j,  0.+0.j,  0.+0.j,  0.+0.j,  0.+4.j,
            0.+0.j])
    

    结果在索引 0、2 和 6 处具有非零值。有 8 个元素。这意味着

           2πit/8 × 0       2πit/8 × 2       2πit/8 × 6
        8 e           - 4i e           + 4i e
    y ~ ———————————————————————————————————————————————
                              8
    

    【讨论】:

    • 对不起。但是我看不清楚。你能告诉我上面的't'和'e'是什么吗?你为什么在方程 2πn/8 中引入 'i*t',SciPy 中有一个函数在做这个计算吗?
    • @ria: e 是 2.71828.... 见en.wikipedia.org/wiki/Euler%27s_formula。 t 是原始数组的索引,例如t=0 -> 1, t=1 -> 2, t=2 -> 1 等。基本上,如果你想得到频率,它们只是 0/8, 1/8, 2/8, .. ., 7/8.
    • @KennyTM:我明白了,指数'e'。我明白了。
    • 这是不正确的——FFT 的输出不是正常的频率顺序。见docs.scipy.org/doc/numpy-1.10.0/reference/…
    • numpy FFT 文档的非版本特定链接:numpy.org/doc/stable/reference/routines.fft.html
    【解决方案2】:

    np.fft.fftfreq 告诉您与系数相关的频率:

    import numpy as np
    
    x = np.array([1,2,1,0,1,2,1,0])
    w = np.fft.fft(x)
    freqs = np.fft.fftfreq(len(x))
    
    for coef,freq in zip(w,freqs):
        if coef:
            print('{c:>6} * exp(2 pi i t * {f})'.format(c=coef,f=freq))
    
    # (8+0j) * exp(2 pi i t * 0.0)
    #    -4j * exp(2 pi i t * 0.25)
    #     4j * exp(2 pi i t * -0.25)
    

    OP 询问如何以赫兹为单位找到频率。 我相信公式是frequency (Hz) = abs(fft_freq * frame_rate)

    这里有一些代码可以证明这一点。

    首先,我们制作一个 440 Hz 的波形文件:

    import math
    import wave
    import struct
    
    if __name__ == '__main__':
        # http://stackoverflow.com/questions/3637350/how-to-write-stereo-wav-files-in-python
        # http://www.sonicspot.com/guide/wavefiles.html
        freq = 440.0
        data_size = 40000
        fname = "test.wav"
        frate = 11025.0
        amp = 64000.0
        nchannels = 1
        sampwidth = 2
        framerate = int(frate)
        nframes = data_size
        comptype = "NONE"
        compname = "not compressed"
        data = [math.sin(2 * math.pi * freq * (x / frate))
                for x in range(data_size)]
        wav_file = wave.open(fname, 'w')
        wav_file.setparams(
            (nchannels, sampwidth, framerate, nframes, comptype, compname))
        for v in data:
            wav_file.writeframes(struct.pack('h', int(v * amp / 2)))
        wav_file.close()
    

    这将创建文件test.wav。 现在我们读入数据,对其进行 FFT,找到具有最大功率的系数, 并找到对应的fft频率,然后转换为赫兹:

    import wave
    import struct
    import numpy as np
    
    if __name__ == '__main__':
        data_size = 40000
        fname = "test.wav"
        frate = 11025.0
        wav_file = wave.open(fname, 'r')
        data = wav_file.readframes(data_size)
        wav_file.close()
        data = struct.unpack('{n}h'.format(n=data_size), data)
        data = np.array(data)
    
        w = np.fft.fft(data)
        freqs = np.fft.fftfreq(len(w))
        print(freqs.min(), freqs.max())
        # (-0.5, 0.499975)
    
        # Find the peak in the coefficients
        idx = np.argmax(np.abs(w))
        freq = freqs[idx]
        freq_in_hertz = abs(freq * frate)
        print(freq_in_hertz)
        # 439.8975
    

    【讨论】:

    • @~unutbu:但是我可以得到赫兹的频率值吗?我想做wav文件。
    • @PavelShvechikov:哎呀,是的。你是绝对正确的。谢谢指正。
    • 我找到了。基本上我的数据是 2 通道数据,但你的代码可能不适合我。
    • 我将 wav 生成脚本通道设置为 2,然后使用该脚本获得 wav 生成脚本中指定的频率。但是当我记录相同的。我得到的正是峰值频率值的一半。我可能会出什么问题。提前致谢
    • @unutbu 很抱歉这个话题的复兴。您的示例获取一个恒定为 440Hz 的 wav 文件的频率。如果我的 wav 文件有 20 个不同频率的样本,我如何按照它们出现的顺序提取所有频率?我可以用 np.fft.fft(signal) 绘制 DFT 和归一化,但这让我得到了频率和它们被观察到的次数,而不是实际的顺序。
    【解决方案3】:

    与 DFT 值相关的频率(在 python 中)

    fft,快速傅里叶变换,我们了解一个大型算法家族的成员,这些算法能够快速计算等采样的 DFT(离散傅里叶变换)信号。

    A DFTN 个复数列表转换为 N 个复数列表,同时理解这两个列表都是周期性的,周期为 N .

    这里我们处理fftnumpy实现。

    很多时候你会想到

    • 在长度为 N 的时域中定义的信号 x,在 a 恒定间隔dt,
    • 它的 DFT X(这里特指X = np.fft.fft(x)),其元素 以 dw 的采样率在频率轴上进行采样。

    一些定义

    • 信号x的周期(又名持续时间),在dt采样,N采样是

      T = dt*N
      
    • X 的基本频率(以 Hz 和 rad/s 为单位),您的 DFT 是

      df = 1/T
      dw = 2*pi/T # =df*2*pi
      
    • 最高频率是Nyquist frequency

      ny = dw*N/2
      

      (而且不是dw*N

    与 DFT 中特定元素相关的频率

    对于给定索引0<=n<N,与X = np.fft.fft(x) 中的元素对应的频率可以计算如下:

    def rad_on_s(n, N, dw):
        return dw*n if n<N/2 else dw*(n-N)
    

    或单次扫描

    w = np.array([dw*n if n<N/2 else dw*(n-N) for n in range(N)])
    

    如果您更喜欢以赫兹为单位考虑频率,s/w/f/

    f = np.array([df*n if n<N/2 else df*(n-N) for n in range(N)])
    

    使用这些频率

    如果您想修改原始信号x -> y 在频域中仅以频率函数的形式应用算子,则可以计算w

    Y = X*f(w)
    y = ifft(Y)
    

    介绍np.fft.fftfreq

    当然numpy 有一个方便的函数np.fft.fftfreq,它返回无量纲频率而不是维度频率,但它就像

    一样简单
    f = np.fft.fftfreq(N)*N*df
    w = np.fft.fftfreq(N)*N*dw
    

    因为df = 1/TT = N/spssps 是每秒的样本数)也可以这样写

    f = np.fft.fftfreq(N)*sps
    

    【讨论】:

    • 为什么需要条件:n
    • 为什么 ny = dw*N/2
    • @Doerthous 因为X 在频域中是周期性的,周期为N,所以您无法判断是否必须将X 的分量分配给频率为n*dw 的时域信号或频率(n+k*N)*dw。 Nyquist,早于 FFT 算法,在信息论的背景下注意到了这种行为,并引入了极限频率的概念,在该极限频率下,SAMPLED 重构信号与考虑到更高频率的重构信号相同(这里的关键字是 SAMPLED)。一本不错的数值分析教科书(甚至是维基百科)将为您提供相关的背景信息。
    • 经过多次谷歌搜索,我开始明白了。设fs为采样频率1/dt,频率f &gt;= fs/2混叠为负频率的分量为f = df*n &lt; fs/2 = 1/(2dt) = N/2T = df*N/2 =&gt; n &lt; N/2,对吗?
    • @gboffi,如何在 k 空间中找到 2D DFT 图像的谐波幅度和相位?
    猜你喜欢
    • 2014-05-04
    • 1970-01-01
    • 2016-05-02
    • 2013-01-13
    • 2013-04-01
    • 2016-07-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-25
    相关资源
    最近更新 更多