jsap_crystal.interpolate_fft のソースコード

"""
FFTを用いた周期関数の補間を実行するスクリプト。

概要:
    このスクリプトは、入力ファイルから読み込んだ、または内部で生成したデータに対して、
    高速フーリエ変換(FFT)を使用して周期関数の補間を行います。
    補間されたデータと元のデータ、必要であれば厳密な関数をプロットして比較します。

詳細説明:
    スクリプトは以下のいずれかの方法で入力データを取得します。
    1. コマンドライン引数またはデフォルトで指定されたExcelファイルからデータを読み込みます。
       `do_mirror` フラグがTrueの場合、読み込んだデータはミラーリングされて拡張されます。
    2. Excelファイルが指定されていない、または "generate" が指定された場合、
       `periodic_function` で定義されたサンプルデータが生成されます。

    取得したデータはFFTによって周波数領域に変換され、
    指定された補間係数に基づいてパディングされた後、逆FFTによって時間領域に戻されます。
    これにより、元のデータ点よりも密な補間データが生成されます。
    最終的に、元のデータ、補間されたデータ、および生成された場合は厳密な関数のプロットが表示されます。

関連リンク:
    :doc:`interpolate_fft_usage`
"""

import sys
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#===================
# デフォルトパラメータ
#===================
INFILE_DEF = "interpolate_fft_test.xlsx"
DO_MIRROR_DEF = False
KRANGE_DEF = [-0.5, 0.5]
N_SAMPLES_DEF = 10
INTERP_FACTOR = 10
FIGSIZE_DEF = (4, 6)

[ドキュメント] def periodic_function(k): """ 特定の周期関数を計算します。 概要: `k` の値に基づいて `-cos(2πk) * (1 + 5k^2)` という周期関数の値を計算します。 :param k: `numpy.ndarray` または `float` - 関数を評価する入力値。 :returns: `numpy.ndarray` または `float` - 関数の計算結果。 """ return -np.cos(2.0 * np.pi * k) * (1.0 + 5.0 * k**2)
[ドキュメント] def read_data(infile, do_mirror=False): """ 指定されたExcelファイルからデータを読み込みます。 概要: Excelファイルの1列目と2列目からxとyのデータを読み込み、NaN値を除外します。 :param infile: `str` - 読み込むExcelファイルのパス。 :param do_mirror: `bool`, optional - データをミラーリングして拡張するかどうか。 :returns: `tuple` of `list` - xデータとyデータのリスト。 """ try: df = pd.read_excel(infile) x = df.iloc[:,0].values.tolist() y = df.iloc[:,1].values.tolist() # NaNを除外 x = [i for i in x if str(i) != 'nan'] y = [i for i in y if str(i) != 'nan'] if do_mirror: _x = [-x[i] for i in range(len(x) - 1, 0, -1)] _x.extend(x) _y = [y[i] for i in range(len(y) - 1, 0, -1)] _y.extend(y) return _x, _y else: return x, y except Exception as e: print(f"Error reading {infile}: {e}") return [], []
[ドキュメント] def main(): """ データの取得、FFT補間、および結果の可視化を制御します。 """ # パラメータの初期化 infile = INFILE_DEF do_mirror = DO_MIRROR_DEF krange = KRANGE_DEF.copy() n_samples = N_SAMPLES_DEF # コマンドライン引数の処理 argv = sys.argv narg = len(argv) if narg > 1: infile = argv[1] if narg > 2: do_mirror = bool(int(argv[2])) print(f"\nInput mode: {infile}") xe, ye = None, None # データの取得 if infile is not None and infile != "" and infile != "generate": print(f"Reading from Excel: [{infile}]") x_raw, y_raw = read_data(infile, do_mirror) if not x_raw: return krange[0], krange[1] = min(x_raw), max(x_raw) n = len(x_raw) # 周期性を考慮し最後の1点を除去してFFT x = np.array(x_raw[:n-1]) y = np.array(y_raw[:n-1]) n_samples = len(x) else: print("Generating sample data") x = np.linspace(krange[0], krange[1], n_samples, endpoint=False) y = periodic_function(x) # 比較用の厳密解 n_exact = n_samples * INTERP_FACTOR xe = np.linspace(krange[0], krange[1], n_exact, endpoint=False) ye = periodic_function(xe) # FFT補間の実行 n_interp = len(x) * INTERP_FACTOR y_fft = np.fft.fft(y) # 周波数領域でのパディング(ゼロパディング) y_fft_padded = np.zeros(n_interp, dtype=complex) # 低周波成分を両端に配置 half = len(x) // 2 y_fft_padded[:half] = y_fft[:half] y_fft_padded[-half:] = y_fft[-half:] # 逆FFTによる時間領域への復元 x_interp = np.linspace(krange[0], krange[1], n_interp, endpoint=False) # 強度を維持するため INTERP_FACTOR を乗じる y_interp = np.fft.ifft(y_fft_padded) * INTERP_FACTOR # 可視化 plt.figure(figsize=FIGSIZE_DEF) plt.plot(x, y, 'o', label='input data', markersize=6) plt.plot(x_interp, y_interp.real, '-', label='interpolated', marker='x', markersize=3, alpha=0.7) if xe is not None: plt.plot(xe, ye, '--', label='exact', alpha=0.5) plt.xlabel('x') plt.ylabel('y') plt.legend() plt.title('FFT Interpolation of Periodic Function') plt.tight_layout() plt.show()
if __name__ == "__main__": main()