简体   繁体   English

在python中用FFT重建原始信号

[英]Reconstruct original signal with FFT in python

I have an analitically generated spectrum, where x axis represents angular frequency, y represents intensity.我有一个分析生成的频谱,其中 x 轴表示角频率,y 表示强度。 The spectrum is centered around some frequency value, which is often called central frequency of the signal (blue graph on the picture).频谱以某个频率值为中心,这通常称为信号的中心频率(图片上的蓝色图表)。 I want to perform IFFT on the data to time domain, cut its useful part with a gaussian curve, then FFT back to the original domain .我想对数据执行 IFFT 到时域,用高斯曲线切割它的有用部分,然后 FFT 回到原始域。 My problem is that after IFFT(FFT(signal)) the central frequency is lost: I get back the spectrum by shape, but it's always centered around 0 (orange graph).我的问题是,在 IFFT(FFT(signal)) 之后,中心频率丢失了:我按形状取回频谱,但它始终以 0 为中心(橙色图)。 光谱 Currently my solution to this is quite bad: I cache the original x axis and I restore it upon FFT calls.目前我对此的解决方案非常糟糕:我缓存了原始的 x 轴,并在 FFT 调用时恢复它。 This obviously has many downsides, and I want to improve it.这显然有很多缺点,我想改进它。 Below I included a small demo which demonstrates the problem.下面我包含了一个演示问题的小演示。 My question is: can this be solved in a more elegant way?我的问题是:这可以以更优雅的方式解决吗? Is there a way central frequency is not lost during the process?有没有办法在这个过程中不丢失中心频率?

import numpy as np
from scipy.fftpack import fft, ifft, fftshift, fftfreq
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

C_LIGHT = 299.793

def generate_data(start, stop, center, delay, GD=0, resolution=0.1):
    window = 8 * np.log(2) / 50
    lamend = 2 * np.pi * C_LIGHT / start
    lamstart = 2 * np.pi * C_LIGHT/stop
    lam = np.arange(lamstart, lamend + resolution, resolution) 
    omega = 2 * np.pi * C_LIGHT / lam 
    relom = omega - center
    _i = np.exp(-(relom) ** 2 / window)
    i = 2 * _i + 2 * np.cos(relom * GD + (omega * delay)) * np.sqrt(_i * _i)
    return omega, i


if __name__ == '__main__':

    # Generate data
    x, y = generate_data(1, 3, 2, 800, GD=0)

    # Linearly interpolate to be evenly spaced
    xs = np.linspace(x[0], x[-1], len(x))
    intp = interp1d(x, y, kind='linear')
    ys = intp(xs)
    x, y = xs, ys
    plt.plot(x, y, label='original')

    # IFFT 
    xt = fftfreq(len(x), d=(x[0]-x[1])/(2*np.pi))
    yt = ifft(y)
    # plt.plot(xt, np.abs(yt))

    # FFT back
    xf = fftshift(fftfreq(len(xt), d=(xt[0]-xt[1])/(2*np.pi)))
    yf = fft(yt)
    plt.plot(xf, np.abs(yf), label='after transforms')
    plt.legend()
    plt.grid()
    plt.show()

I think that fftfreq does not do what you think it does.我认为fftfreq没有做你认为的那样。 The xf for fft(ifft(y) is identical to x , you should not try to re-compute it. The x-axis doesn't change when going to another domain and then back again. fft(ifft(y)xfx相同,您不应该尝试重新计算它。转到另一个域然后再返回时,x 轴不会改变。

Also, do note that fftfreq returns the coordinates in the frequency domain for the discrete Fourier transform of a signal of a given length and with a given sample spacing.另外,请注意fftfreq返回给定长度和给定样本间距的信号的离散傅立叶变换的频域坐标。 It does not do the reverse, you cannot use it to determine the coordinates in the spatial domain after applying the inverse discrete Fourier transform.它不会做相反的事情,在应用逆离散傅立叶变换后,您不能使用它来确定空间域中的坐标。 (The spacing it returns is valid, but the set of coordinates is not.) (它返回的间距有效,但坐标集无效。)

    plt.plot(x, y, label='original')

    # IFFT 
    yt = ifft(y)
    # plt.plot(np.abs(yt))

    # FFT back
    yf = fft(yt)
    plt.plot(x, np.real(yf), label='after transforms')
    plt.legend()
    plt.grid()
    plt.show()

Another problem with your code is that ifft(y) assumes a fixed set of values along the x-axis.您的代码的另一个问题是ifft(y)假定沿 x 轴的一组固定值。 Your x does not match this.您的x与此不符。 Thus, the spatial-domain signal you obtain is not meaningful.因此,您获得的空间域信号没有意义。

Running your code, I see that x runs from 3.0 to 1.0 in steps of 0.0004777.运行您的代码,我看到x以 0.0004777 的步长从 3.0 运行到 1.0。 You will have to augment your data so that the values run from 0.0 to 6.0, with the region (3.0, 6.0) being the conjugate symmetric copy of the region (0.0, 3.0).您必须增加数据,使值从 0.0 运行到 6.0,区域 (3.0, 6.0) 是区域 (0.0, 3.0) 的共轭对称副本。 This region corresponds to the negative frequencies, according to the periodicity of the frequency domain (F[n]==F[n+N], with N the number of samples).该区域对应于负频率,根据频域的周期性(F[n]==F[n+N],其中 N 为样本数)。 Fill the region (0.0, 1.0) with zeros.用零填充区域 (0.0, 1.0)。

Given this standardized x-axis in the frequency domain, xf = fftfreq(len(xt), d=(xt[1]-xt[0])) should reconstruct the x-axis.给定频域中这个标准化的 x 轴, xf = fftfreq(len(xt), d=(xt[1]-xt[0]))应该重建 x 轴。 But you need to compute xt appropriately: xt = np.linspace(0, 1/(x[1]-x[0]), len(x), endpoint=False) (with x the standardized DFT frequency axis).但是您需要适当地计算xtxt = np.linspace(0, 1/(x[1]-x[0]), len(x), endpoint=False)x是标准化的 DFT 频率轴)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM