【问题标题】:Improving FFT resolution - scaling Y axis提高 FFT 分辨率 - 缩放 Y 轴
【发布时间】:2015-03-23 14:50:48
【问题描述】:

我正在尝试在 Python 中绘制 FM 信号的 Bessel 等效项的频域。

我遇到的第一个问题是提高 FFT 的分辨率以查看较小的带宽 - 我相信我已经通过将贝塞尔波函数的总和与一个大小为两倍的大型零填充数组连接起来解决了这个问题保存波形数据的数组。

但是,这会影响 Y 轴的缩放 - 当我增加零填充的大小时,Y 轴的大小会下降。 我可以将 Y 轴乘以什么因素来反转这个?到目前为止的实验让我走上了死胡同……

非常感谢!

import numpy as np
import matplotlib.pyplot as plt
import math as mt
import scipy.special as sc
def bWave(fc=10000, B=1.25):
    time = np.linspace(0, 0.5, 20001, True)
    data = np.zeros(len(time))
    retarr = np.column_stack((time,data)) 
    Vc = 6
    fm = 3
    for n in range(-5,5):
        for row in range(len(retarr)):
            retarr[row][1] += Vc*sc.jv(n,B)*mt.cos(2*mt.pi*
                (fc+n*fm)*retarr[row][0])
    return retarr
FM_array = bWave()
# ------------- SIGNAL PLOT  OF AM -----------------
scaling = 2 #default 2, cuts out symmetry from FFT
buffer_ratio = 1
padded_array =
    np.concatenate((FM_array[:,1],np.zeros(buffer_ratio*len(FM_array[:,1])))) #pad array with zeros
Y = np.fft.fft(padded_array) #perform FFT
N = len(Y)/scaling + 1 # get FFT length (avoid reflection)
T = FM_array[1][0] - FM_array[0][0] #get time interval of FFT
fa = 1/T #sampling frequency
Xaxis = np.linspace(0, fa/scaling, N, endpoint=True)  # create x axis vector from 0 to nyquist freq. (fa/2) with N values
plt.plot(Xaxis, (2.0/((N)*scaling)) * np.abs(Y[0:N]))  # multiply y axis by 2/N to get actual values
plt.grid(True)
plt.show()

【问题讨论】:

    标签: python numpy matplotlib fft bessel-functions


    【解决方案1】:

    几点:

    • 你确定bWave() 函数是正确的吗?您的 Bessel 函数与时间无关,因此您可以通过傅里叶变换余弦轻松找到封闭形式的解。
    • 不要用零填充,而是增加bWave() 信号的时间段(参见下面的代码)以提高频率分辨率。
    • 使用numpy 代替math 函数。它使您的代码更具可读性和速度。

    以下代码绘制了不同时间段的 FFT。时间段越长,峰值就越尖锐(余弦的傅里叶变换):

    import numpy as np
    import matplotlib.pyplot as plt
    import scipy.special as sc
    
    
    def bWave2(t, fc=10000, B=1.25):
        """ Useing only numpy """
        Vc, fm = 6, 3
        y = np.zeros(len(t))
        for n in range(-5,5):
            y += Vc*sc.jv(n,B)*np.cos(2*np.pi*(fc+n*fm)*t)
        return y
    
    
    fg, ax = plt.subplots(1, 1)
    
    fc=10000
    for q in range(0, 5):
        k = 15001*(1+q)
        t = np.linspace(0-0.25*q, 0.5+0.25*q, k)
        y = bWave2(t, fc)
    
        Y = np.fft.rfft(y)/N # since y is real, rfft() instead of fft is used
        f = np.fft.rfftfreq(k, t[1] - t[0]) # frequencies for rfft()
    
        ax.plot(f, np.abs(Y), label=u"$\\tau=${}".format(t[-1]-t[0]), alpha=.5)
    ax.set_xlim(fc-50, fc+50)
    ax.grid(True)
    ax.legend(loc="best")
    fg.canvas.draw()
    
    plt.show()
    

    请注意,rfft(y)/N 中的 /N 只是被添加以具有可比较的 FFT 值。由于采样率是恒定的,因此能量,即 |Y(f)|²,随着时间的增加而增加。在您的代码中,采样率发生了变化,信号的能量也随之变化。

    【讨论】:

    • 贝塞尔函数是正确的 - 但我明白你的意思是通过增加时间段来提高分辨率和准确性。不过,我的想法是否正确,当增加时间段(从而降低采样频率)时,您需要确保不允许最高频率超过奈奎斯特速率?
    • 没错。由于您的信号带宽较小,您可以对其进行解调(将其乘以sin(2*pi*f_c))以将其推入基带以限制采样率。
    猜你喜欢
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-04
    • 2017-11-25
    • 1970-01-01
    相关资源
    最近更新 更多