"""
ガウス関数またはローレンツ関数を用いたデータの畳み込み(平滑化)スクリプト。
概要:
入力データに対して指定した関数を畳み込み、ノイズの除去やブロードニングのシミュレーションを行います。
DOS(状態密度)などの鋭いピークを持つデータの視認性を高めるのに適しています。
詳細説明:
1. Excel等の入力ファイルから 2 列の数値データ(x, y)を読み込みます。
2. ガウス関数(デフォルト)またはローレンツ関数を窓関数として生成します。
3. 数値的な畳み込み積分を実行し、平滑化された y データを算出します。
4. 結果を Excel ファイル(テンプレート対応)に保存し、グラフを表示します。
関連リンク: :doc:`convolution_usage`
"""
import sys
import numpy as np
import pandas as pd
from math import sqrt, exp, pi
import matplotlib.pyplot as plt
# 自作ライブラリ(パスが通っていることが前提)
from tklib.tkvariousdata import tkVariousData
from tklib.tkapplication import tkApplication
#======================
# デフォルトパラメータ
#======================
INFILE_DEF = 'dos.xlsx'
OUTFILE_TEMPLATE = "StandardGraph.xlsm"
FUNC_TYPE_DEF = 'gauss'
WIDTH_DEF = 0.2
[ドキュメント]
def convolve_func(x, width, func_type='gauss'):
"""
畳み込みに使用する重み関数(窓関数)の値を計算します。
:param x: float: 中心からの距離。
:param width: float: 関数の幅パラメータ。
:param func_type: str: 'gauss' または 'lorentz'。
:returns: float: 重み。
"""
if func_type == 'lorentz':
coeff = 1.0 / (width * pi)
dvx = x / width
return coeff * (1.0 / (1.0 + dvx * dvx))
else:
coeff = 1.0 / (sqrt(pi) * width)
dvx = x / width
return coeff * exp(-dvx*dvx)
[ドキュメント]
def convolution(x, y, width, func_type):
"""
数値データの畳み込み積分を実行します。
詳細説明:
幅の 5 倍の範囲を有効な積分範囲とし、各データ点に対して
周辺のデータの重み付き平均(積分)を計算します。
"""
ndata = len(x)
dx = x[1] - x[0]
# 積分範囲をインデックス数に変換
di = int((width * 5.0) / dx + 1.1)
ys = [0.0] * ndata
for j in range(ndata):
y0 = y[j]
# 周辺範囲に重みを配分
for k in range(-di, di + 1):
if j + k < 0 or j + k >= ndata:
continue
# 重み関数の寄与を計算
f = dx * convolve_func(dx * k, width, func_type)
ys[j+k] += y0 * f
return ys
[ドキュメント]
def main():
"""
メイン実行ルーチン。引数解析、計算、保存、プロットを制御します。
"""
app = tkApplication()
# 引数の取得
argv = sys.argv
n = len(argv)
infile = argv[1] if n >= 2 else INFILE_DEF
width = float(argv[2]) if n >= 3 else WIDTH_DEF
func_type = argv[3] if n >= 4 else FUNC_TYPE_DEF
logfile = app.replace_path(infile)
outfile = app.replace_path(infile, template=["{dirname}", "{filebody}-convoluted.xlsm"])
# 出力をログファイルにリダイレクト(必要に応じて)
print(f"Open logfile [{logfile}]")
app.redirect(targets=["stdout", logfile], mode='w')
print(f"\nConvoluting data in [{infile}]")
print(f"Function Type: {func_type}, Width: {width}")
# データの読み込み
data_reader = tkVariousData(infile)
header, datalist = data_reader.Read_minimum_matrix(close_fp=True)
x, y = datalist[0], datalist[1]
# 畳み込み実行
ys = convolution(x, y, width, func_type)
# 保存処理
print(f"Save to [{outfile}]")
tkVariousData().to_excel(outfile, ['x', 'y(input)', 'y(convoluted)'], [x, y, ys], template=OUTFILE_TEMPLATE)
# グラフプロット
fig, ax1 = plt.subplots(figsize=(8, 6))
ax1.plot(x, y, label='Raw data', linestyle='-', linewidth=0.5, marker='o', markersize=0.5, alpha=0.5)
ax1.plot(x, ys, label=f'Convoluted ({func_type})', linewidth=1.5)
ax1.set_xlabel("x")
ax1.set_ylabel("y")
ax1.legend()
plt.tight_layout()
plt.show(block=False)
print("\nPress ENTER to exit>>")
input()
if __name__ == '__main__':
main()