interpolate_fft.py ドキュメント

概要

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

詳細説明

interpolate_fft.py スクリプトは、以下のいずれかの方法で入力データを取得します。

  1. コマンドライン引数またはデフォルトで指定されたExcelファイルからデータを読み込みます。 do_mirror フラグが True の場合、読み込んだデータはミラーリングされて拡張されます。

  2. Excelファイルが指定されていない、またはコマンドライン引数で "generate" が指定された場合、 periodic_function() で定義されたサンプルデータが生成されます。

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

関連リンク

interpolate_fft_usage

スクリプトの実行方法

前提条件

このスクリプトを実行するには、Python環境がセットアップされている必要があります。 また、以下の非標準ライブラリがインストールされている必要があります。

  • numpy

  • pandas

  • matplotlib

  • openpyxl (pandas がExcelファイルを読み込むために必要)

インストール

必要なライブラリは pip を使用してインストールできます。

pip install numpy pandas matplotlib openpyxl

基本的な使い方

スクリプトはPythonインタープリタを使用して実行します。 引数を指定しない場合、デフォルトの設定またはサンプルデータ生成モードで動作します。

python interpolate_fft.py

コマンドライン引数

interpolate_fft.py は以下のコマンドライン引数を受け取ります。

  1. infile (位置引数、オプション):

    • 入力とするExcelファイルのパスを指定します。

    • デフォルトは "interpolate_fft_test.xlsx" です。

    • この引数に "generate" を指定すると、内部でサンプルデータが生成されます。

    • 空文字列 ("") または None と解釈される値もサンプルデータ生成として扱われます。

  2. do_mirror (位置引数、オプション):

    • 読み込んだデータをミラーリングして拡張するかどうかを制御します。

    • 0 を指定すると False として扱われ、ミラーリングは行われません。

    • 1 を指定すると True として扱われ、ミラーリングが行われます。

    • デフォルトは 0 (False) です。

使用例

  • 引数なしで実行 (デフォルトのExcelファイル読み込み、またはサンプルデータ生成):

    python interpolate_fft.py
    
  • 特定のExcelファイル my_data.xlsx からデータを読み込む:

    python interpolate_fft.py my_data.xlsx
    
  • 特定のExcelファイル my_data.xlsx からデータを読み込み、ミラーリングを有効にする:

    python interpolate_fft.py my_data.xlsx 1
    
  • 内部でサンプルデータを生成して使用する:

    python interpolate_fft.py generate
    

関数リファレンス

periodic_function(k)

概要

入力 k の値に基づいて、特定の周期関数の値を計算します。 具体的には -cos(2πk) * (1 + 5k^2) の計算を行います。

引数

  • k: numpy.ndarray または float - 関数を評価する入力値。

戻り値

  • numpy.ndarray または float - 関数の計算結果。入力 k の型に対応します。

read_data(infile, do_mirror=False)

概要

指定されたExcelファイルからデータを読み込みます。 Excelファイルの1列目を x データ、2列目を y データとして読み込み、それらのリストを返します。 読み込み時に NaN 値はデータから除外されます。 オプションでデータをミラーリングして拡張できます。

引数

  • infile: str - 読み込むExcelファイルのパス。

  • do_mirror: bool, optional - データをミラーリングして拡張するかどうかを決定します。 True の場合、元のデータは反転されて追加され、データセットが拡張されます。デフォルトは False です。

戻り値

  • tuple of list - 読み込まれた x データと y データのリストを格納するタプル。 Excelファイルの読み込み中にエラーが発生した場合、またはデータが見つからない場合は、空のリストのタプル ([], []) を返します。

main()

概要

スクリプトのメイン処理を制御する関数です。 コマンドライン引数を解析し、データの取得(Excelファイルからの読み込みまたはサンプルデータの生成)、FFT補間の実行、および結果の可視化を行います。

定数

以下の定数がスクリプト内で定義され、デフォルト値や設定として使用されます。

  • INFILE_DEF: "interpolate_fft_test.xlsx" - デフォルトの入力Excelファイル名。

  • DO_MIRROR_DEF: False - データのデフォルトのミラーリング設定。

  • KRANGE_DEF: [-0.5, 0.5] - サンプルデータを生成する際の k の範囲。

  • N_SAMPLES_DEF: 10 - サンプルデータを生成する際のデフォルトのデータ点数。

  • INTERP_FACTOR: 10 - FFT補間後のデータ点数を元のデータの INTERP_FACTOR 倍にするための係数。

  • FIGSIZE_DEF: (4, 6) - プロット図のデフォルトのサイズ (幅, 高さ)。

非標準ライブラリ

interpolate_fft.py は以下の非標準ライブラリを使用しています。

  • numpy: 高性能な数値計算を可能にするライブラリで、配列操作、数学関数、FFT関連の機能を提供します。

  • pandas: データ構造とデータ分析ツールを提供します。特にExcelファイルの読み込み (read_excel()) に使用されます。

  • matplotlib.pyplot: グラフ描画ライブラリで、データの可視化(プロット作成)に使用されます。

入出力仕様

入力ファイル形式

  • Excelファイル:

    • ファイル拡張子は .xlsx である必要があります。

    • スクリプトはExcelファイルの最初のシートを読み込みます。

    • データの1列目が x 値、2列目が y 値として扱われます。

    • 読み込み時に、これらの列内の NaN (Not a Number) 値は自動的に除外されます。

    • 期待されるフォーマット例:

      x

      y

      -0.5

      -0.25

      -0.4

      -0.1

      0.0

      1.0

      0.4

      -0.1

      0.5

      -0.25

出力

  • 標準出力 (stdout):

    • スクリプトの実行開始時に、現在使用されている入力モード (Excelファイル名または "generate") が表示されます。

    • Excelファイルからデータを読み込む場合、そのファイル名が "Reading from Excel: [ファイル名]" の形式で表示されます。

    • サンプルデータを生成する場合、"Generating sample data" と表示されます。

    • Excelファイルの読み込み中にエラーが発生した場合、エラーメッセージが "Error reading [ファイル名]: [エラー内容]" の形式で出力されます。

  • グラフィック出力:

    • matplotlib を用いて、FFT補間された周期関数のプロットがGUIウィンドウに表示されます。

    • プロットには以下の要素が含まれます。

      • 'input data': 元の入力データ点。丸マーカー ('o') で表示されます。

      • 'interpolated': FFTによって補間されたデータ。線 ('-') とバツマーカー ('x') で表示されます。

      • 'exact': サンプルデータが生成された場合にのみ表示される厳密な関数。破線 ('--') で表示され、補間結果との比較に使用されます。

    • プロットには x 軸と y 軸のラベル、凡例、および 'FFT Interpolation of Periodic Function' というタイトルが含まれます。

コード例

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