【问题标题】:Wrong Voigt output/convolution with asymmetric x input错误的 Voigt 输出/卷积与不对称 x 输入
【发布时间】:2019-04-08 21:58:16
【问题描述】:

目前我正在对我的数据进行高斯或洛伦兹拟合,但两者都不够好,我想切换到 Voigt 拟合,即两者的卷积。

我从https://www.originlab.com/doc/Origin-Help/Voigt-FitFunc 检索到 Voigt 函数并将其写入 python。

import numpy as np
import matplotlib.pyplot as plt

def lorentz_voigt(x, A, xc, wL):
    return (2*A / np.pi) * (wL / ((4*(x.astype(float) - xc)**2) + wL**2))

def gauss_voigt(x, wG):
    return np.sqrt((4*np.log(2)) / np.pi) * ((np.exp(-(((4*np.log(2)) / (wG**2))*(x.astype(float))**2))) / (wG))

def Voigt(x, xc, A, wG, wL):
    return np.convolve(lorentz_voigt(x, A, xc, wL), gauss_voigt(x, wG), 'same')

symx = np.linspace(-100, 100, 1001)
asymx = np.linspace(0, 100, 1001)
symy = Voigt(symx, 50, 1, 5, 5)
asymy = Voigt(asymx, 50, 1, 5, 5)
plt.clf()
plt.plot(symx, symy)
plt.plot(asymx, asymy)

如下图所示,带有不对称 x 轴输入的 Voigt 函数(橙色)无法再现正确的 Voigt 轮廓,如蓝色所示。

我的数据是 600-4000 cm-1 的波数,我想知道是否需要在 -4000 到 600 cm-1 因为这是卷积的纯数学限制,还是我的代码有错误/解决方案?

【问题讨论】:

  • 能否请您发布一个指向您的数据的链接?
  • @JamesPhillips 图中看到的数据是在上面的脚本中创建的。在这个故障排除阶段,来自实验的实际数据是无关紧要的。 Voigt 函数被传递给 curve_fit,但是该函数不会重新创建正确的配置文件,因此拟合失败。
  • 还有另一种计算 voigt 线形的方法,它不涉及卷积:V(x,sig,gam) = Re(w(z))/(sig*sqrt(2*pi)) 其中z = (x+i*gam)/(sig*sqrt(2)) 和Re(w(z)) 是Faddeeva 函数的实部。后者在 scipy 中为 scipy.special.wofz。
  • curve_fit使用的默认初始参数默认都是1.0,并不是在所有情况下都是最优的。 Scipy 的 optimize.differential_evolution 遗传算法可用于确定初始参数估计值,我曾希望使用您的实验数据举一个例子,因此我要求提供相同的链接。
  • @Terranees 看起来您正在使用拉曼光谱并且不想使用 Origin。看看peak-o-mat。它是用python编写的。

标签: python python-3.x math curve-fitting convolution


【解决方案1】:

卷积对 x 轴一无所知。最好让它返回完整的卷积,而不是将其缩小到原始的 x 范围,例如:

import numpy as np
import matplotlib.pyplot as plt

def lorentz_voigt(x, A, xc, wL):
    return (2*A / np.pi) * (wL / ((4*(x.astype(float) - xc)**2) + wL**2))

def gauss_voigt(x, xc, wG):
    return np.sqrt((4*np.log(2)) / np.pi) * ((np.exp(-(((4*np.log(2)) / (wG**2))*((x-xc).astype(float))**2))) / (wG))

def Voigt(x, xc, A, wG, wL):
    return np.convolve(lorentz_voigt(x, A, xc, wL), gauss_voigt(x, xc, wG), 'full')

symx = np.linspace(-100, 100, 1001)
asymx = np.linspace(0, 200, 1001)
symy = Voigt(symx, 50, 1, 5, 5)[::2]
asymy = Voigt(asymx, 50, 1, 5, 5)[::2]

plt.clf()
plt.plot(symx, symy,'r')
plt.plot(asymx, asymy,'b--')

另请注意,您对 gauss_voigt 的定义错过了中心坐标xc。

正如我在上面的评论中所说,还有另一种计算 voigt 函数的方法,它不基于卷积。卷积在计算时间方面很昂贵,当用作拟合模型时会变得很烦人。以下示例代码不需要卷积。

import matplotlib.pyplot as plt
import numpy as np
from scipy.special import wofz

def voigt(x, amp, pos, fwhm, shape):
    tmp = 1/wofz(np.zeros((len(x))) +1j*np.sqrt(np.log(2.0))*shape).real
    return tmp*amp*wofz(2*np.sqrt(np.log(2.0))*(x-pos)/fwhm+1j*np.sqrt(np.log(2.0))*shape).real

x = np.linspace(0, 100, 1001)
y0 = voigt(x, 1, 50, 5, 0)
y1 = voigt(x, 1, 50, 5, 1)
plt.plot(x,y0,'k',label='shape = 0')
plt.plot(x,y1,'b',label='shape = 1')
plt.legend(loc=0)
plt.show()

【讨论】:

  • 我的印象是“相同”模式会做同样的事情,但显然不是。我确实注意到originlab.com/doc/Origin-Help/Voigt-FitFunc 上给出的函数的高斯分量中缺少 xc。我认为这是因为高斯已针对卷积或类似的东西进行了归一化。你有理由将 xc 添加到 gauss_voigt 吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-06
  • 2023-03-17
  • 2018-02-03
  • 1970-01-01
相关资源
最近更新 更多