【问题标题】:Plot a fourier transform of a sin wav with matplotlib使用 matplotlib 绘制正弦波的傅立叶变换
【发布时间】:2021-04-16 01:11:02
【问题描述】:

我正在尝试基于scipy documentation 绘制符号波的傅立叶变换

import numpy as np
import matplotlib.pyplot as plt
import scipy.fft

def sinWav(amp, freq, time, phase=0):
    return amp * np.sin(2 * np.pi * (freq * time - phase))

def plotFFT(f, speriod, time):
    """Plots a fast fourier transform

    Args:
        f (np.arr): A signal wave
        speriod (int): Number of samples per second
        time ([type]): total seconds in wave
    """

    N = speriod * time
    # sample spacing
    T = 1.0 / 800.0
    x = np.linspace(0.0, N*T, N, endpoint=False)

    yf = scipy.fft.fft(f)
    xf = scipy.fft.fftfreq(N, T)[:N//2]
    plt.plot(xf, 2.0/N * np.abs(yf[0:N//2]))
    plt.grid()
    plt.xlim([1,3])
    plt.show()


speriod = 1000
time  = {
    0: np.arange(0, 4, 1/speriod),
    1: np.arange(4, 8, 1/speriod),
    2: np.arange(8, 12, 1/speriod)
}

signal = np.concatenate([
    sinWav(amp=0.25, freq=2, time=time[0]),
    sinWav(amp=1, freq=2, time=time[1]),
    sinWav(amp=0.5, freq=2, time=time[2])
])   # generate signal

plotFFT(signal, speriod, 12)

期望的输出

我想得到一个看起来像这样的傅立叶变换图

电流输出

但它看起来像这样


额外

这是我正在使用的罪波

【问题讨论】:

    标签: python matplotlib scipy fft continuous-fourier


    【解决方案1】:
    import numpy as np
    import matplotlib.pyplot as plt
    import scipy.fft
    
    def sinWav(amp, freq, time, phase=0):
        return amp * np.sin(2 * np.pi * (freq * time - phase))
    
    def plotFFT(f, speriod, time):
        """Plots a fast fourier transform
    
        Args:
            f (np.arr): A signal wave
            speriod (int): Number of samples per second
            time ([type]): total seconds in wave
        """
    
        N = speriod * time
        # sample spacing
        T = 1.0 / 800.0
        x = np.linspace(0.0, N*T, N, endpoint=False)
    
        yf = scipy.fft.fft(f)
        xf = scipy.fft.fftfreq(N, T)[:N//2]
    
        amplitudes = 1/speriod* np.abs(yf[:N//2])
      
        plt.plot(xf, amplitudes)
        plt.grid()
        plt.xlim([1,3])
        plt.show()
    
    
    speriod = 800
    time  = {
        0: np.arange(0, 4, 1/speriod),
        1: np.arange(4, 8, 1/speriod),
        2: np.arange(8, 12, 1/speriod)
    }
    
    signal = np.concatenate([
        sinWav(amp=0.25, freq=2, time=time[0]),
        sinWav(amp=1, freq=2, time=time[1]),
        sinWav(amp=0.5, freq=2, time=time[2])
    ])   # generate signal
    
    plotFFT(signal, speriod, 12)
    

    你应该有你想要的。您的振幅计算不正确,因为您的分辨率和周期不一致。

    更长的数据采集时间:

    import numpy as np
    import matplotlib.pyplot as plt
    import scipy.fft
    
    def sinWav(amp, freq, time, phase=0):
        return amp * np.sin(2 * np.pi * (freq * time - phase))
    
    def plotFFT(f, speriod, time):
        """Plots a fast fourier transform
    
        Args:
            f (np.arr): A signal wave
            speriod (int): Number of samples per second
            time ([type]): total seconds in wave
        """
    
        N = speriod * time
        # sample spacing
        T = 1.0 / 800.0
        x = np.linspace(0.0, N*T, N, endpoint=False)
    
        yf = scipy.fft.fft(f)
        xf = scipy.fft.fftfreq(N, T)[:N//2]
    
        amplitudes = 1/(speriod*4)* np.abs(yf[:N//2])
      
        plt.plot(xf, amplitudes)
        plt.grid()
        plt.xlim([1,3])
        plt.show()
    
    
    speriod = 800
    time  = {
        0: np.arange(0, 4*4, 1/speriod),
        1: np.arange(4*4, 8*4, 1/speriod),
        2: np.arange(8*4, 12*4, 1/speriod)
    }
    
    signal = np.concatenate([
        sinWav(amp=0.25, freq=2, time=time[0]),
        sinWav(amp=1, freq=2, time=time[1]),
        sinWav(amp=0.5, freq=2, time=time[2])
    ])   # generate signal
    
    plotFFT(signal, speriod, 48)
    

    【讨论】:

    • 它应该看起来像我发布的图,其中振幅为 3.5,频率为 2
    • 为什么这不适用于其他采样率?频率不应该与采样率无关吗?我认为 sr 只是确定了信号被分成的 x 轴的大小
    • 好吧,如果您正在处理连续数据,那么您是对的(在数学中也是如此)。但在物理学中,数据不是连续的。 FFT 指的是离散 FT,在特定的物理环境中。可以在这里找到我更改的原因:en.wikipedia.org/wiki/Nyquist_frequency 这都是关于这种关系的。事实上,你的转变是由于频谱“折叠”导致你不够符合奈奎斯特关系。
    • 我试图让我的图表看起来更连续,但我一直得到相同的块状图表
    • 换句话说,我想把 x 轴分成更小的部分
    【解决方案2】:

    您也可以交互式地绘制它。您可能需要安装pip install scikit-dsp-comm

    # !pip install scikit-dsp-comm
    # Make an interactive version of the above
    from ipywidgets import interact, interactive
    import numpy as np
    import matplotlib.pyplot as plt
    from scipy import fftpack
    
    plt.rcParams['figure.figsize'] = [10, 8]
    
    font = {'weight' : 'bold',
            'size'   : 14}
    plt.rc('font', **font)
    
    
    def pulse_plot(fm = 1000, Fs = 2010):
        tlen = 1.0  # length in seconds
        # generate time axis
        tt = np.arange(np.round(tlen*Fs))/float(Fs)
        # generate sine
        xt = np.sin(2*np.pi*fm*tt)
        plt.subplot(211)
        plt.plot(tt[:500], xt[:500], '-b')
        plt.plot(tt[:500], xt[:500], 'or', label='xt values')
        plt.ylabel('$x(t)$')
        plt.xlabel('t [sec]')
        strt2 = 'Sinusoidal Waveform $x(t)$'
        strt2 = strt2 + ', $f_m={}$ Hz, $F_s={}$ Hz'.format(fm, Fs)
        plt.title(strt2)
        plt.legend()
        plt.grid()
        X = fftpack.fft(xt)
        freqs = fftpack.fftfreq(len(xt)) * Fs
        plt.subplot(212)
        N = xt.size
        # DFT
        X = np.fft.fft(xt)
        X_db = 20*np.log10(2*np.abs(X)/N)
        #f = np.fft.fftfreq(N, 1/Fs)
        f = np.arange(0, N)*Fs/N
        plt.plot(f, X_db, 'b')
        plt.xlabel('Frequency in Hertz [Hz]')
        plt.ylabel('Frequency Domain\n (Spectrum) Magnitude')
        plt.grid()
        plt.tight_layout()
        
        
    interactive_plot = interactive(pulse_plot,fm = (1000,20000,1000), Fs = (1000,40000,10));
    output = interactive_plot.children[-1]
    # output.layout.height = '350px'
    interactive_plot    
    

    【讨论】:

    • 为什么是-300到0?
    • @Sam 因为 y 轴只是频谱幅度。如果你愿意,你可以让它成为线性的。
    • 应该还是350吧?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-17
    • 2020-08-18
    • 2019-07-02
    • 1970-01-01
    • 2019-09-22
    • 2015-04-04
    • 1970-01-01
    相关资源
    最近更新 更多