
Fitting dispersive line shapes in MPF2 using user-defined functions

mmcanally
Relatively new to using Igor Pro and I've run into an issue in fitting some of my spectral data.
My spectral data typically consists of between 3 and 12 dispersive line shapes (specifically Fano) that I'd like to fit.
Using the basic curve fitting tool I can enter in expressions that have variables to fit up to five Fano peaks, however I've got some spectra that have N>5. The limitation in using the basic curve fitting tool comes from having too long of an expression for more than five peaks. This seemed like a great place to use MPF2 since it also spits out residuals and has a nice UI. So I programmed what I thought were the appropriate functions for a Fano line shape and tried testing out (repeatedly) on a sample set of two peaks. Unfortunately, I can never get the procedure to move forward with any fits that look remotely close to fitting the data. Side-by-side in the .pxp is an example of a satisfactory fit using the brute force Curve Fitting dialog and a two peak Fano fitting function.
Any advice would be greatly appreciated.
Thanks, and happy holidays/New Year!
Mike
My Fano inputs for basic curve fitting and MPF2:
//Dialog from the manual/simple curve fitting commands under Analysis->Curve Fitting for a two peak Fano profile Function FanoFit2(w,x) : FitFunc Wave w Variable x //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog. //CurveFitDialog/ Equation: //CurveFitDialog/ f(x) = (A1*(((q+((x-z1)/(g1/2)))^2)/(1+((x-z1)/(g1/2))^2)))+(A2*(((q+((x-z2)/(g2/2)))^2)/(1+((x-z2)/(g2/2))^2)))+m*x+c*x^2+d //CurveFitDialog/ End of Equation //CurveFitDialog/ Independent Variables 1 //CurveFitDialog/ x //CurveFitDialog/ Coefficients 10 //CurveFitDialog/ w[0] = q //CurveFitDialog/ w[1] = m //CurveFitDialog/ w[2] = c //CurveFitDialog/ w[3] = d //CurveFitDialog/ w[4] = A1 //CurveFitDialog/ w[5] = g1 //CurveFitDialog/ w[6] = z1 //CurveFitDialog/ w[7] = A2 //CurveFitDialog/ w[8] = g2 //CurveFitDialog/ w[9] = z2 return (w[4]*(((w[0]+((x-w[6])/(w[5]/2)))^2)/(1+((x-w[6])/(w[5]/2))^2)))+(w[7]*(((w[0]+((x-w[9])/(w[8]/2)))^2)/(1+((x-w[9])/(w[8]/2))^2)))+w[1]*x+w[2]*x^2+w[3] End //(12/27/14) Attempt to add Fano peak fitting functionality to MPF2 package of Igor Pro template taken from manual and YonatanHo IgorExchange forum post // ********* FANO ********* Function/S Fano_PeakFuncInfo(InfoDesired) Variable InfoDesired String info="" Switch (InfoDEsired) case PeakFuncInfo_ParamNames: info = "Location;Gamma;Amplitude;q" //Location=peak center, Amplitude=peak amplitude, Gamma=Gamma parameter of the Fano line shape, q=Fano asymmetry parameter break; // case PeakFuncInfo_PeakFName: // BUT you must maintain their order of apperance in the parameter w[] wave! info = "Fano_Peak" break; case PeakFuncInfo_GaussConvFName: info = "SimpleLorentzianGuess" break; case PeakFuncInfo_ParameterFunc: info = "Fano_PeakParams" break; case PeakFuncInfo_DerivedParamNames: info = "Location;Gamma;Amplitude;q" // break; default: break; endSwitch return info end Function SimpleLorentzianGuess(w) // Let's assume that a simple Lorentzian is a good guess to start with... (Derivative of Lorentzian might be better but how to implement?) Wave w //Note that the wave is already pre-filled with parameters from the automatic or "by-hand" guess from the side of MPF //assuming a possibly asymmetric Gaussian. //Parameters w[0],w[1],w[2], are corresponding to position, width, and height respectively, Redimension/N=4w // w[0] = Position==>Location // w[1] = Width==>Gamma // w[2] = Height==>Amplitude // w[3] = Constant ==> Fano asymmetry parameter (Note: no relation to parameters of Lorentzian/Gaussian guess) // width of Lorenzian needs to be modified from the estimated Gaussian width (Remember: MPF2 uses Gaussians for auto initial guess) w[2] = w[1]*w[2]*sqrt(pi) return 0 end Function Fano_Peak(w, yw, xw) // The w wave is a 4 object wave that has the fit parameters. Use w[0] to w[3], i.e.; // w[0] = Location // w[1] = Gamma // w[2] = Amplitude // w[3] = Fano asymmetry parameter Wave w, yw, xw yw = w[2]*(((w[3]+((x-w[0])/(w[1]/2)))^2)/(1+((x-w[0])/(w[1]/2))^2)) //Taken from Nano Lett 2012 end Function Fano_PeakParams(cw, sw, outWave) //cw is the wave parameter from the fit, Wave cw, sw, outWave //sw is the standard deviations for the parameters - both are 12 wave parameters as defined in "PeakFuncInfo_DerivedParamNames" //Location (Central position of dispersive lineshape)- outWave[0][0] = cw[0] // This is actually the peak center of a Lorentian. <- Probably the big issue right now in failing. Could a derivative of Lorentzian be used for initial guess instead? outWave[0][1] = sqrt(sw[0][0]) // The error is treated accordingly. //Amplitude (Take a guess) outWave[2][0] = cw[2] outWave[2][1] = NaN //Gamma (linewidth) outWave[1][0] = cw[1] outWave[2][1] = NaN //q (Fano asymmetry parameter) outWave[3][0] = cw[3] outWave[3][1] = NaN End
The basic problem with your attempt was using "x" in the fit function equation instead of "xw". I also added an arbitrary initialization of the q factor, simply setting it to -0.7 which seems to be about appropriate judging from the regular fit you included in the experiment file.
The function to turn the auto-locate info into a good initial guess will probably never work well, as auto-locate expects peaks to look sort of like a Gaussian, that is, it doesn't expect the "derivative of a peak" shape that has a peak followed by a valley.
I see that in your simple fit function there is only one value of q. There isn't a good way to achieve that in MPF2. I managed it for your two-peak fit by entering this in the inter-peak constraint box:
P0K3>P1K3;P0K3<P1K3;
That makes the q for peak 0 both greater and less than the q for peak 1, a tricky way to get an equality constraint without holding the coefficients. You would need such a list having similar expressions for every pair between peak 0 and all the other peaks.
I have attached a modification of the experiment file that has my code changes (small but important!) and my fit that looks a lot like your simple curve fit in Graph0.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
January 5, 2015 at 03:30 pm - Permalink