Skip to content Skip to sidebar Skip to footer

How Can I Fit A Good Lorentzian On Python Using Scipy.optimize.curve_fit?

I'm trying to fit a Lorentzian function with more than one absorption peak (Mössbauer spectra), but the curve_fit function it not working properly, fitting just few peaks. How can

Solution 1:

This code uses leastsq instead of curve_fit as the latter one requires a fixed number of parameters. Here I do not want this as I let the code "decide" how many peaks are there. Note that I scaled the data to simplify the fit. The true fitting parameters are calculated easily be scaling back ( and standard error propagation )

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

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

defmulti_lorentz( x, params ):
    off = params[0]
    paramsRest = params[1:]
    assertnot ( len( paramsRest ) % 3 )
    return off + sum( [ lorentzian( x, *paramsRest[ i : i+3 ] ) for i inrange( 0, len( paramsRest ), 3 ) ] )

defres_multi_lorentz( params, xData, yData ):
    diff = [ multi_lorentz( x, params ) - y for x, y inzip( xData, yData ) ]
    return diff

xData, yData = np.loadtxt('HEMAT_1.dat', unpack=True )
yData = yData / max(yData)

generalWidth = 1

yDataLoc = yData
startValues = [ max( yData ) ]
counter = 0whilemax( yDataLoc ) - min( yDataLoc ) > .1:
    counter += 1if counter > 20: ### max 20 peak...emergency break to avoid infinite loopbreak
    minP = np.argmin( yDataLoc )
    minY = yData[ minP ]
    x0 = xData[ minP ]
    startValues += [ x0, minY - max( yDataLoc ), generalWidth ]
    popt, ier = leastsq( res_multi_lorentz, startValues, args=( xData, yData ) )
    yDataLoc = [ y - multi_lorentz( x, popt ) for x,y inzip( xData, yData ) ]

print popt
testData = [ multi_lorentz(x, popt ) for x in xData ]

fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1 )
ax.plot( xData, yData )
ax.plot( xData, testData )
plt.show()

Providing

[ 9.96855817e-01  4.94106598e+02 -2.82103813e-01  4.66272773e+00
  2.80688160e+01 -2.72449246e-01  4.71728295e+00  1.31577189e+02
 -2.29698620e-01  4.20685229e+00  4.01421993e+02 -1.85917255e-01
  5.57859380e+00  2.29704607e+02 -1.47193792e-01  3.91112196e+00
  3.03387957e+02 -1.37127711e-01  4.39571905e+00]

and

Fitted data

Post a Comment for "How Can I Fit A Good Lorentzian On Python Using Scipy.optimize.curve_fit?"