当前位置: 首页 > 知识库问答 >
问题:

在Python 3中使用Scipy将多个洛伦兹函数拟合到布里渊光谱

韶兴德
2023-03-14

我正在尝试使用scipy拟合布里渊光谱(具有多个峰)。优化曲线拟合。我有多个光谱和几个峰,我试图用洛伦兹函数拟合它们(每个峰一个洛伦兹函数)。我正在尝试自动化批量分析过程(即,使用scipy的峰值查找算法获得峰值位置、峰值宽度和峰值高度,并将其用作拟合的初始猜测)。我现在正在研究一个光谱,看看总体思路是否可行,然后我会将其扩展为自动光谱,并处理我所有的光谱。到目前为止,我已经做到了:

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
from scipy.optimize import curve_fit

#import y data from linked google sheet 
y_data = np.loadtxt( 'y_peo.tsv' )
#define x data 
x_data = np.arange( len( y_data ) )

#find peak properties (peak position, amplitude, full width half maximum ) to use as 
#initial guesses for the curve_fit function 
pk, properties = find_peaks(y_data, height = 3, width = 3, prominence=0.1 ) #pk returns peaks position, properties returns 
#other properties associated with the peaks
I = properties ['peak_heights'] #amplitude
fwhm = (properties['widths']) #full width half maximum 

#define sum of lorentzians
def func(x, *params): 
    y = np.zeros_like(x)
    for i in range(0, len(params), 3):
        x_0 = params[i]
        I = params[i+1]
        y_0 = params[i+2]
        y = y + (I*y_0**2)/(y_0**2 +(x-x_0)**2) 
    return y

#initial guess list, to be populated with parameters found above (pk, I, fwhm)
guess = [] 

for i in range(len(pk)): 
    guess.append(pk[i])
    guess.append(I[i])
    guess.append(fwhm[i]) 

#convert list to array
guess=np.array(guess)

#fit
popt, pcov = curve_fit(func, x_data, y_data, p0=guess, method = 'lm',  maxfev=1000000)
print(popt)
fit = func(x_data, *popt)

#plotting
fig= plt.figure(figsize=(10,5))
ax= fig.add_subplot(1,1,1)
ax.plot(pk, y_data[pk], 'o', ms=5)
ax.plot(x_data, y_data, 'ok', ms=1)
ax.plot(x_data, fit , 'r--', lw=0.5)

其中y_peo是因变量(以下是作为google工作表文件的值:https://docs.google.com/spreadsheets/d/1UB2lqs0Jmhthed7B0U9rznqcbpEMRmRX99c-iOBHLeE/edit?usp=sharing)像素是自变量(代码中创建的任意值数组)。这就是我得到的:光谱拟合的结果。知道为什么最后一个三元组没有按预期安装吗?我检查过了,所有的峰都被scipy正确地找到了。信号find_peaks函数-因此我认为问题在于scipy。优化曲线拟合,因为我必须增加maxfev的数量以适应“工作”。你知道如何以更聪明的方式解决这个问题吗?

提前感谢,,

朱塞佩。

共有1个答案

羊毅庵
2023-03-14

通过一些小的修改,OP的代码运行得很好。现在看来:

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import leastsq
from scipy.signal import find_peaks

def lorentzian( x, x0, a, gam ):
    return a * gam**2 / ( gam**2 + ( x - x0 )**2 )

def multi_lorentz( x, params ):
    off = params[0]
    paramsRest = params[1:]
    assert not ( len( paramsRest ) % 3 )
    return off + sum( [ lorentzian( x, *paramsRest[ i : i+3 ] ) for i in range( 0, len( paramsRest ), 3 ) ] )

def res_multi_lorentz( params, xData, yData ):
    diff = [ multi_lorentz( x, params ) - y for x, y in zip( xData, yData ) ]
    return diff

y0 = np.loadtxt( 'y_peo.tsv' )
yData = np.loadtxt( 'y_peo.tsv' )
xData = np.arange( len( yData ) )

yGround = min( yData )
yData = yData - yGround
yAmp = max( yData )
yData = yData / yAmp 

#initial properties of peaks 
pk, properties = find_peaks( yData, height = .05, width = 3 )#, prominence=0.1 )
#extract peak heights and fwhm 
I = properties [ 'peak_heights' ]
fwhm = properties[ 'widths' ]

guess = [0]
for i in range( len( pk ) ): 
    guess.append( pk[i] )
    guess.append( I[i] )
    guess.append( fwhm[i] ) 

guess=np.array( guess )

popt, pcov = leastsq( res_multi_lorentz, x0=guess, args=( xData, yData ) )
print( popt )


testData = [ multi_lorentz( x, popt ) for x in xData ]
fitData = [ yGround + yAmp * multi_lorentz( x, popt ) for x in xData ]

fig= plt.figure( figsize=( 10, 5 ) )
ax= fig.add_subplot( 2, 1, 1 )
bx= fig.add_subplot( 2, 1, 2 )
ax.plot( pk, yData[pk], 'o', ms=5 )
ax.plot( xData, yData, 'ok', ms=1 )
ax.plot( xData, testData , 'r--', lw=0.5 )
bx.plot( xData, y0, ls='', marker='o', markersize=1 )
bx.plot( xData, fitData )
plt.show()

[9.39456104e-03 6.55864388e+01 5.73522507e-02 5.46727721e+00
 1.21329586e+02 2.97187567e-01 2.12738107e+00 1.76823266e+02
 1.57244131e-01 4.55424037e+00 3.51556692e+02 3.08959955e-01
 4.39114581e+00 4.02954496e+02 9.02677035e-01 2.27647259e+00
 4.53994668e+02 3.74379310e-01 4.02432791e+00 6.15694190e+02
 4.51943494e-01 4.06522919e+00 6.63307635e+02 1.05793098e+00
 2.32168786e+00 7.10644233e+02 4.33194434e-01 4.17050014e+00
 8.61276198e+02 1.79240633e-01 4.26617114e+00 9.06211127e+02
 5.03070470e-01 2.10563379e+00 9.50973864e+02 1.78487912e-01
 4.01254815e+00]

 类似资料:
  • 我试图用一个以上的吸收峰(穆斯堡尔谱)拟合洛伦兹函数,但曲线拟合函数不能正常工作,只能拟合几个峰。我怎样才能适应它? 图:尝试调整多重洛伦兹 下面我展示我的代码。请帮帮我。 我的数据--

  • 问题内容: 在python中,我有一个具有许多参数的函数。我想将此函数适合数据集,但只使用一个参数,其余的参数我要自己提供。这是一个例子: 在这种情况下,我希望只对它进行拟合,并且参数采用循环变量的值。如何才能做到这一点? 问题答案: 您可以包装一个lambda,如下所示: Lambda是一个匿名函数,在Python中只能用于简单的单行函数。基本上,通常在不需要为函数分配名称时通常用于减少代码量。

  • 问题内容: 我有一组近似于2D曲线的点。我想将Python与numpy和scipy配合使用,以找到近似适合这些点的三次贝塞尔曲线路径,在该路径中,我指定两个端点的确切坐标,并返回其他两个控制点的坐标。 我最初以为可以做我想做的事,但是似乎迫使曲线穿过每个数据点(因为我想您希望进行插值)。我以为我走错了路。 我的问题与此相似:如何将贝塞尔曲线拟合到一组数据?,除了他们说他们不想使用numpy。我的偏

  • 问题内容: 有没有更有效的方法来对预先指定的bin中的数组取平均值?例如,我有一个数字数组以及一个与该数组中bin的开始和结束位置相对应的数组,我只想取这些bin中的均值?我下面有执行此操作的代码,但我想知道如何减少和改进它。谢谢。 问题答案: 它可能更快更容易使用: 替代方法是使用: 自己尝试哪个更快… :)

  • 问题内容: 我有一个包含多个包含整数(a1,a2,a3等)的字段的postgresql表。 我想一次跨多个列运行汇总函数(均值,标准差等)。(其中一些可能具有合理数量的空值,因此我不想只生成列平均值然后再对它们求平均值)。 我可以得到一组整数 但是我然后无法获取聚合函数以将此作为输入。 谁能给我任何有关如何使它工作的提示? 问题答案: 使用子查询,您可以使用所有行: 您还可以对行进行分组,例如:

  • 虽然可视化曼德布洛特(Mandelbrot)集合与机器学习没有任何关系,但这对于将TensorFlow应用在数学更广泛的领域是一个有趣的例子。实际上,这是tensorflow一个非常直截了当的可视化运用。(我们最终也许会提供一种更加精心设计的运用方式来生成真正更加美丽的图像。) 说明:本教程使用了IPython的notebook。 基本步骤 首先,我们需要导入一些库。 # 导入仿真库 import