interpolate_fft.py ダウンロード/コピー

interpolate_fft.py をダウンロード

interpolate_fft.py
interpolate_fft.py
  1"""
  2FFTを用いた周期関数の補間を実行するスクリプト。
  3
  4概要:
  5    このスクリプトは、入力ファイルから読み込んだ、または内部で生成したデータに対して、
  6    高速フーリエ変換(FFT)を使用して周期関数の補間を行います。
  7    補間されたデータと元のデータ、必要であれば厳密な関数をプロットして比較します。
  8
  9詳細説明:
 10    スクリプトは以下のいずれかの方法で入力データを取得します。
 11    1. コマンドライン引数またはデフォルトで指定されたExcelファイルからデータを読み込みます。
 12       do_mirror フラグがTrueの場合、読み込んだデータはミラーリングされて拡張されます。
 13    2. Excelファイルが指定されていない、または "generate" が指定された場合、
 14       periodic_function で定義されたサンプルデータが生成されます。
 15
 16    取得したデータはFFTによって周波数領域に変換され、
 17    指定された補間係数に基づいてパディングされた後、逆FFTによって時間領域に戻されます。
 18    これにより、元のデータ点よりも密な補間データが生成されます。
 19    最終的に、元のデータ、補間されたデータ、および生成された場合は厳密な関数のプロットが表示されます。
 20
 21関連リンク:
 22    interpolate_fft_usage
 23"""
 24
 25import sys
 26import numpy as np
 27import pandas as pd
 28import matplotlib.pyplot as plt
 29
 30#===================
 31# デフォルトパラメータ
 32#===================
 33INFILE_DEF = "interpolate_fft_test.xlsx"
 34DO_MIRROR_DEF = False
 35KRANGE_DEF = [-0.5, 0.5]
 36N_SAMPLES_DEF = 10
 37INTERP_FACTOR = 10
 38FIGSIZE_DEF = (4, 6)
 39
 40def periodic_function(k):
 41    """
 42    概要:
 43        特定の周期関数を計算します。
 44    詳細説明:
 45        入力値 k に基づいて、数式 -cos(2πk) * (1 + 5k^2) を評価し、その結果を返します。
 46        この関数は、周期的なデータ生成のためのサンプルとして使用されます。
 47    引数:
 48        :param k: 関数を評価する入力値。numpy.ndarray または float で指定します。
 49        :type k: numpy.ndarray or float
 50    戻り値:
 51        :returns: 関数の計算結果。入力 k と同じ型(numpy.ndarray または float)で返されます。
 52        :rtype: numpy.ndarray or float
 53    """
 54    return -np.cos(2.0 * np.pi * k) * (1.0 + 5.0 * k**2)
 55
 56def read_data(infile, do_mirror=False):
 57    """
 58    概要:
 59        指定されたExcelファイルからx-yデータを読み込みます。
 60    詳細説明:
 61        与えられた Excel ファイル (infile) から、最初の2列のデータをxとyとして読み込みます。
 62        読み込まれたデータは NaN 値を除去されます。
 63        do_mirror が True の場合、読み込んだデータはy軸に対してミラーリングされ、元のデータの前に結合されます。
 64        これにより、データセットが周期性を維持したまま拡張されます。
 65    引数:
 66        :param infile: 読み込むExcelファイルのパス。
 67        :type infile: str
 68        :param do_mirror: データをミラーリングして拡張するかどうかを示すフラグ。Trueの場合、データがミラーリングされます。
 69        :type do_mirror: bool
 70    戻り値:
 71        :returns: xデータとyデータのリストのタプル。エラーが発生した場合は空のリストのタプル。
 72        :rtype: tuple of list
 73    例外:
 74        :raises Exception: Excelファイルの読み込み中にエラーが発生した場合にコンソールにエラーメッセージを出力します。
 75    """
 76    try:
 77        df = pd.read_excel(infile)
 78        x = df.iloc[:,0].values.tolist()
 79        y = df.iloc[:,1].values.tolist()
 80        # NaNを除外
 81        x = [i for i in x if str(i) != 'nan']
 82        y = [i for i in y if str(i) != 'nan']
 83        
 84        if do_mirror:
 85            _x = [-x[i] for i in range(len(x) - 1, 0, -1)]
 86            _x.extend(x)
 87            _y = [y[i] for i in range(len(y) - 1, 0, -1)]
 88            _y.extend(y)
 89            return _x, _y
 90        else:
 91            return x, y
 92    except Exception as e:
 93        print(f"Error reading {infile}: {e}")
 94        return [], []
 95
 96def main():
 97    """
 98    概要:
 99        FFTを用いた周期関数の補間処理全体を制御し、結果を可視化します。
100    詳細説明:
101        この関数は、まずコマンドライン引数またはデフォルト設定から補間パラメータを初期化します。
102        次に、指定されたExcelファイルからデータを読み込むか、
103        periodic_function を使用してサンプルデータを生成します。
104        取得したデータに対して高速フーリエ変換 (FFT) を適用し、周波数領域でゼロパディングを行います。
105        その後、逆FFTを実行して補間された時間領域のデータを生成します。
106        最後に、元のデータ、補間されたデータ、および厳密な関数(存在する場合)をmatplotlibを用いてプロットし、
107        結果を可視化します。
108    """
109    # パラメータの初期化
110    infile = INFILE_DEF
111    do_mirror = DO_MIRROR_DEF
112    krange = KRANGE_DEF.copy()
113    n_samples = N_SAMPLES_DEF
114    
115    # コマンドライン引数の処理
116    argv = sys.argv
117    narg = len(argv)
118    if narg > 1: infile = argv[1] 
119    if narg > 2: do_mirror = bool(int(argv[2]))
120
121    print(f"\nInput mode: {infile}")
122
123    xe, ye = None, None
124    
125    # データの取得
126    if infile is not None and infile != "" and infile != "generate":
127        print(f"Reading from Excel: [{infile}]")
128        x_raw, y_raw = read_data(infile, do_mirror)
129        if not x_raw:
130            return
131            
132        krange[0], krange[1] = min(x_raw), max(x_raw)
133        n = len(x_raw)
134        # 周期性を考慮し最後の1点を除去してFFT
135        x = np.array(x_raw[:n-1])
136        y = np.array(y_raw[:n-1])
137        n_samples = len(x)
138    else:
139        print("Generating sample data")
140        x = np.linspace(krange[0], krange[1], n_samples, endpoint=False)
141        y = periodic_function(x)
142        # 比較用の厳密解
143        n_exact = n_samples * INTERP_FACTOR
144        xe = np.linspace(krange[0], krange[1], n_exact, endpoint=False)
145        ye = periodic_function(xe)
146
147    # FFT補間の実行
148    n_interp = len(x) * INTERP_FACTOR
149    y_fft = np.fft.fft(y)
150
151    # 周波数領域でのパディング(ゼロパディング)
152    y_fft_padded = np.zeros(n_interp, dtype=complex)
153    # 低周波成分を両端に配置
154    half = len(x) // 2
155    y_fft_padded[:half] = y_fft[:half]
156    y_fft_padded[-half:] = y_fft[-half:]
157
158    # 逆FFTによる時間領域への復元
159    x_interp = np.linspace(krange[0], krange[1], n_interp, endpoint=False)
160    # 強度を維持するため INTERP_FACTOR を乗じる
161    y_interp = np.fft.ifft(y_fft_padded) * INTERP_FACTOR
162
163    # 可視化
164    plt.figure(figsize=FIGSIZE_DEF)
165    plt.plot(x, y, 'o', label='input data', markersize=6)
166    plt.plot(x_interp, y_interp.real, '-', label='interpolated', marker='x', markersize=3, alpha=0.7)
167    if xe is not None:
168        plt.plot(xe, ye, '--', label='exact', alpha=0.5)
169        
170    plt.xlabel('x')
171    plt.ylabel('y')
172    plt.legend()
173    plt.title('FFT Interpolation of Periodic Function')
174    plt.tight_layout()
175    plt.show()
176
177if __name__ == "__main__":
178    main()