Python scipy.integrate伪Voigt函数,积分变为0

Python scipy.integrate伪Voigt函数,积分变为0,python,numpy,scipy,data-fitting,integrate,Python,Numpy,Scipy,Data Fitting,Integrate,我正在用Python编写一个脚本,使用Scipy、Numpy和Matplotlib将峰值形状拟合到光谱数据。它可以同时拟合多个峰值。峰值轮廓(目前)是伪Voigt,它是高斯(又名正态)和洛伦兹(又名柯西)分布的线性组合 我有一个选项开关,我可以让软件优化高斯和洛伦兹的贡献,或者将其设置为固定值(其中0=纯高斯,1=纯洛伦兹)。工作正常,绘制拟合峰值的效果与预期一致。当我尝试使用scipy.integrate计算峰值积分时,问题开始了 到目前为止,我尝试了scipy.integrate.quad、

我正在用Python编写一个脚本,使用Scipy、Numpy和Matplotlib将峰值形状拟合到光谱数据。它可以同时拟合多个峰值。峰值轮廓(目前)是伪Voigt,它是高斯(又名正态)和洛伦兹(又名柯西)分布的线性组合

我有一个选项开关,我可以让软件优化高斯和洛伦兹的贡献,或者将其设置为固定值(其中0=纯高斯,1=纯洛伦兹)。工作正常,绘制拟合峰值的效果与预期一致。当我尝试使用
scipy.integrate
计算峰值积分时,问题开始了

到目前为止,我尝试了scipy.integrate.quad、scipy.integrate.quadrature、scipy.integrate.fixed_quad和scipy.integrate.romberg。当峰值为纯高斯时,积分变得类似于
1.73476E-34
(不总是相同的数字),即使对于面积明显大于相邻非纯高斯峰值但返回10到1000阶有限积分的峰值也是如此。以下是相关部分的外观:

# Function defining the peak functions for plotting and integration
# WavNr: Wave number, the x-axis over which shall be integrated
# Pos: Peak center position
# Amp: Amplitude of the peak
# GammaL: Gamma parameter of the Lorentzian distribution
# FracL: Fraction of Lorentzian distribution
def PseudoVoigtFunction(WavNr, Pos, Amp, GammaL, FracL):
    SigmaG = GammaL / np.sqrt(2*np.log(2)) # Calculate the sigma parameter  for the Gaussian distribution from GammaL (coupled in Pseudo-Voigt)
    LorentzPart = Amp * (GammaL**2 / ((WavNr - Pos)**2 + GammaL**2)) # Lorentzian distribution
    GaussPart = Amp * np.exp( -((WavNr - Pos)/SigmaG)**2) # Gaussian distribution
    Fit = FracL * LorentzPart + (1 - FracL) * GaussPart # Linear combination of the two parts (or distributions)
    return Fit
这是plot函数通过以下方式调用的:

Fit = PseudoVoigtFunction(WavNr, Pos, Amp, GammaL, FracL)
这很好用。积分器也通过以下方式调用:

PeakArea, PeakAreaError = integrate.quad(PseudoVoigtFunction, -np.inf, np.inf, args=(Pos, Amp, GammaL, FracL))
或者scipy.integrate提供的任何其他变体,都具有相同的结果,如果FracL=0,那么PeakArea=(几乎)0

我敢肯定,问题在于我太笨了,没有弄清楚scipy.integrate如何处理比我能找到的示例稍微复杂的函数。希望有人看到我没有看到的明显错误。我花了两天时间搜索stackoverflow和Scipy文档,重新整理并完全重写了代码,但结果一无所获。我怀疑scipy.integrate中的arg在某种程度上与问题有关,但就我所知,它们似乎排列正确

提前感谢,,
Os

我相信您一定知道,间隔(-inf,inf)相当大高斯衰减非常快,因此除了峰值附近的间隔外,高斯与0在数值上是无法区分的。我怀疑
quad
根本看不到你的巅峰

一个简单的解决方法是将积分分成两个区间(-inf,pos)和(pos,inf)。(您的函数是关于
Pos
的对称函数,因此实际上只需要(-inf,Pos)上的整数的两倍。)

这里有一个例子。我不知道这些参数值是否接近您使用的典型值,但它们说明了这一点

In [259]: pos = 1500.0

In [260]: amp = 4.0

In [261]: gammal = 0.5

In [262]: fracl = 0  # Pure Gaussian
quad
认为积分为0:

In [263]: quad(PseudoVoigtFunction, -np.inf, np.inf, args=(pos, amp, gammal, fracl))
Out[263]: (0.0, 0.0)
而是通过(-inf,pos)和(pos,inf)进行集成:


所以(-inf,inf)上的积分大约是3.010767。

我相信你知道,区间(-inf,inf)相当大。:)高斯衰减非常快,因此除了峰值附近的间隔外,高斯与0在数值上是无法区分的。我怀疑
quad
根本看不到你的巅峰

一个简单的解决方法是将积分分成两个区间(-inf,pos)和(pos,inf)。(您的函数是关于
Pos
的对称函数,因此实际上只需要(-inf,Pos)上的整数的两倍。)

这里有一个例子。我不知道这些参数值是否接近您使用的典型值,但它们说明了这一点

In [259]: pos = 1500.0

In [260]: amp = 4.0

In [261]: gammal = 0.5

In [262]: fracl = 0  # Pure Gaussian
quad
认为积分为0:

In [263]: quad(PseudoVoigtFunction, -np.inf, np.inf, args=(pos, amp, gammal, fracl))
Out[263]: (0.0, 0.0)
而是通过(-inf,pos)和(pos,inf)进行集成:


所以(-inf,inf)上的积分约为3.010767。

谢谢Warren,这解决了问题!但我还是不明白为什么。我确实注意到,当我使用一个非常窄的范围时,比如说-GammaL到GammaL,我得到的结果对于这个范围来说似乎是合理的,但是在这个范围的10倍时,积分已经降到零了。理论上不应该是这样,;当函数接近0时,积分不应再变大,但绝对不应变小甚至消失。嗯,我想这与四元算法的工作方式有关,到目前为止,我一直懒得去挖掘源代码。(待续)(续)正如你所说,它可能只是看不到无限大空间中的高斯峰。奇怪的是,寻找和整合洛伦兹峰似乎没有问题。可能应在scipy.integrate参考指南中增加将两个半边与峰值中心进行积分的技巧。无论如何,非常感谢,这很可能让我的项目免于死亡,也让我免于疯狂!谢谢沃伦,这解决了问题!但我还是不明白为什么。我确实注意到,当我使用一个非常窄的范围时,比如说-GammaL到GammaL,我得到的结果对于这个范围来说似乎是合理的,但是在这个范围的10倍时,积分已经降到零了。理论上不应该是这样,;当函数接近0时,积分不应再变大,但绝对不应变小甚至消失。嗯,我想这与四元算法的工作方式有关,到目前为止,我一直懒得去挖掘源代码。(待续)(续)正如你所说,它可能只是看不到无限大空间中的高斯峰。奇怪的是,寻找和整合洛伦兹峰似乎没有问题。可能应在scipy.integrate参考指南中增加将两个半边与峰值中心进行积分的技巧。无论如何,非常感谢,这很可能让我的项目免于死亡,也让我免于疯狂!