web-dev-qa-db-ja.com

pythonでFFTを使用して元の信号を再構成します

私は分析的に生成されたスペクトルを持っています。ここで、x軸はangular周波数、yは強度を表します。スペクトルは、信号の中心周波数と呼ばれるいくつかの周波数値を中心としています(上の青いグラフ画像。時間領域のデータに対してIFFTを実行し、その有用な部分をガウス曲線でカットしてから、FFTを元の領域に戻したいのですが、IFFT(FFT(信号))の後で中心周波数が失われるという問題があります。スペクトルを形状で取得しますが、常に0を中心としています(オレンジ色のグラフ) Spectrum 現在、これに対する私の解決策はかなり悪いです。元のx軸をキャッシュし、FFT呼び出しで復元します。これには明らかに多くの欠点があり、改善したいと思います。以下に、問題を示す小さなデモを含めました。私の質問は、これはよりエレガントな方法で解決できますか?プロセス中に中心周波数が失われない方法はありますか?

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()
4
Péter Leéh

fftfreqはあなたが思っていることをしていないと思います。 fft(ifft(y)xfxと同じです。再計算しないでください。 X軸は、別のドメインに移動してから再び戻っても変わりません。

また、fftfreqは、指定された長さと指定されたサンプル間隔の信号の離散フーリエ変換の周波数領域の座標を返すことに注意してください。逆は行われません。逆離散フーリエ変換を適用した後、それを使用して空間領域の座標を決定することはできません。 (それが返す間隔は有効ですが、座標のセットは無効です。)

_    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()
_

コードのもう1つの問題は、ifft(y)がx軸に沿った固定値のセットを想定していることです。あなたのxはこれと一致しません。したがって、取得する空間領域信号は意味がありません。

コードを実行すると、xが3.0から1.0まで0.0004777のステップで実行されることがわかります。領域(3.0、6.0)が領域(0.0、3.0)の共役対称コピーになるように、値が0.0から6.0になるようにデータを拡張する必要があります。この領域は、周波数領域の周期性(F [n] == F [n + N]、Nはサンプル数)に従って、負の周波数に対応します。領域(0.0、1.0)をゼロで埋めます。

周波数領域でこの標準化されたx軸が与えられると、xf = fftfreq(len(xt), d=(xt[1]-xt[0]))はx軸を再構築する必要があります。ただし、xtを適切に計算する必要があります:xt = np.linspace(0, 1/(x[1]-x[0]), len(x), endpoint=False)xは標準化されたDFT周波数軸)。

2
Cris Luengo