I want to use Igor to determine the change in position and width of x-ray diffraction peaks during an in-situ experiment. To do this, I want to convolve my initial diffraction pattern with a Gaussian or Lorentzian function and fit this to a diffractogram obtained later on in the experiment. I have been reading about the All-at-Once Fitting functions involving convolutions, but it seems like they take a single input and fit it to the convolution of two well defined functions. Is there a way to fit the convolution of a data set and a well-defined function to a second data set? Or will the noise and other non-ideality of the initial data make the convolution too difficult?
I can't tell you if about the last bit- it would depend entirely on the details of your data.
You can certainly write an all-at-once fit function to convolve a pre-existing data set with the data you are trying to fit. I guess you are trying to fit with a measured impulse response function rather than an analytic function? To do this, you need to access your impulse response data set from inside the fit function using a WAVE statement. To read more about this:
DisplayHelpTopic "Accessing Global Variables And Waves"
You will, indeed, need to be very careful with the convolution. I would work out the details of the convolution first, and try fitting only when you are confident that the convolution itself is working as you want it to.
The need for a WAVE statement to make a wave reference to your impulse response data set introduces a dependency into the fit function that can be troublesome. It tends to lock you into a single data set, or at least into a single name for the data set. Before fitting, if you have more than one of those data sets you have to make sure that you have it set up correctly.
You can avoid some of those problems using an all-at-once structure fit function. But using a structure fit function introduces other complexities, such as the need for a driver function that sets up the structure and then calls FuncFit.
Would you be able to approach this differently? Fit a peak (or two or three or so) of your starting data with an appropriate function. Then, carry the analytical expression for the initial condition forward with a convolution to fit the evolution of the same peak over real time.
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
Yes, I am considering this as well. I can get pretty good fits with the Pseudo-Voigt functions, so I will try that first.
Nick
OK. Another thought then. Pseudo-Voigt is a convolution of Gauss + Lorentz. So, fit your initial peak with a convolution of the two. Then hold the Lorentz component constant and evolve only the Gauss convolution component with time. Presumably, this would model the physics in a truer way??? What I am thinking is this. The Lorentz component is intrinsic and unchanging while the Gauss has both an intrinsic (static) instrument transmission function + an experiment "evolution" function.
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
Can't let this pass, Jeff. Pseudo-Voigt is a weighted sum of Gauss and Lorentz peaks used to approximate a real Voigt.
The rest of your posting is good!
You can fit a more-nearly-real Voigt by constructing a user-define fitting function based on VoigtFunc in Igor 7. To get the area as a direct fit coefficient, it could be like this:
Function myVoigtFit(w,xx) : FitFunc Wave w Variable xx
//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/ Variable ratio = sqrtln2/gw //CurveFitDialog/ Variable xprime = ratio*(xx-x0) //CurveFitDialog/ Variable voigtY = ratio*shape //CurveFitDialog/ f(xx) = y0 + area*sqrtln2pi*VoigtFunc(xprime, voigtY) //CurveFitDialog/ End of Equation //CurveFitDialog/ Independent Variables 1 //CurveFitDialog/ xx //CurveFitDialog/ Coefficients 5 //CurveFitDialog/ w[0] = y0 //CurveFitDialog/ w[1] = area //CurveFitDialog/ w[2] = x0 //CurveFitDialog/ w[3] = gw (FWHM) //CurveFitDialog/ w[4] = shape (Lw/Gw)
You can hold the Gaussian width here very easily. Keeping the Lorentzian width constant would be more difficult; it might require re-writing the fit function in terms of Lor width insteand of Gauss width.
OK. Another thought then. Pseudo-Voigt is a convolution of Gauss + Lorentz. So, fit your initial peak with a convolution of the two. Then hold the Lorentz component constant and evolve only the Gauss convolution component with time. Presumably, this would model the physics in a truer way??? What I am thinking is this. The Lorentz component is intrinsic and unchanging while the Gauss has both an intrinsic (static) instrument transmission function + an experiment "evolution" function.
Yes, this seems like an interesting approach (bearing in mind John's comment about the sum versus convolution). If I expect size or strain broadening I can fix either the Gaussian or Lorentzian components of the Pseudo-Voigt or Voigt fit. Would I just pass the results of the initial fit to the all-at-once convolution fitting function in the parameter wave, and hold those constant in the FuncFit command? This seems like it would be a bit easier than importing the intensity wave each time.
... Would I just pass the results of the initial fit to the all-at-once convolution fitting function in the parameter wave, and hold those constant in the FuncFit command? This seems like it would be a bit easier than importing the intensity wave each time.
In a nutshell ... yes and yes. That is the overall gist of my suggestion. Fit the initial peak. Generate a model with fixed parameters. Then, convolve to the fixed initial model over time rather than to the initial experimental data. During the convolution+fit, the parameters of the initial peak are passed as constants. The parameters to the convolution peak are the only ones that are allowed to change.
I'm also guessing that a pseudo-Voigt is a first-order approximation to the truth. It packages the convolution Gauss*Lorentz in a "one kind of peak" shape because doing a convolution+fit is a real bear to do right. Since you are going to do a convolution+fit anyway, do it right on the initial peak AND subsequently convolve ONLY the component that is to "evolve" according to physics.
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
I should point out that the voigt fit function I posted is not pseudo-Voigt, it is a very good approximation to a real convolved Voigt. But it does it without doing a convolution. If you have Igor 7:
I should point out that the voigt fit function I posted is not pseudo-Voigt, it is a very good approximation to a real convolved Voigt. ...
Apologies. I'm a bit late to this new game (still). And, I'm running on three firestorm deadlines in the coming weekend. I seem to miss a lot that I apparently then have to be hit twice again or more with.
The insights about the new function and Igor7 are appreciated. I look forward to making use of them soon.
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
I should point out that the voigt fit function I posted is not pseudo-Voigt, it is a very good approximation to a real convolved Voigt. But it does it without doing a convolution. If you have Igor 7:
DisplayHelpTopic "VoigtFunc"
Is this new Voigt function used in the Multipeak Fit 2 package in Igor 7?
The voigt peak shape used by Multipeak Fit is an implementation of a Voigt peak with inputs and height scaled to give it real-world values. But in fact, the scaling presently used by Multipeak Fit is clumsy and doesn't really correspond to "real world" values; it's just scaled so it can take on any width, height and shape. Igor 8 will have a built-in voigt fitting function that fits peak area, Gaussian width and ratio of Lorenzian to Gaussian width. I hope to add a peak shape to Multipeak Fit that will fit this more convenient version of Voigt.
You can certainly write an all-at-once fit function to convolve a pre-existing data set with the data you are trying to fit. I guess you are trying to fit with a measured impulse response function rather than an analytic function? To do this, you need to access your impulse response data set from inside the fit function using a WAVE statement. To read more about this:
DisplayHelpTopic "Accessing Global Variables And Waves"
You will, indeed, need to be very careful with the convolution. I would work out the details of the convolution first, and try fitting only when you are confident that the convolution itself is working as you want it to.
The need for a WAVE statement to make a wave reference to your impulse response data set introduces a dependency into the fit function that can be troublesome. It tends to lock you into a single data set, or at least into a single name for the data set. Before fitting, if you have more than one of those data sets you have to make sure that you have it set up correctly.
You can avoid some of those problems using an all-at-once structure fit function. But using a structure fit function introduces other complexities, such as the need for a driver function that sets up the structure and then calls FuncFit.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
October 25, 2016 at 09:34 am - Permalink
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
October 25, 2016 at 07:45 pm - Permalink
Yes, I am considering this as well. I can get pretty good fits with the Pseudo-Voigt functions, so I will try that first.
Nick
October 27, 2016 at 11:00 am - Permalink
OK. Another thought then. Pseudo-Voigt is a convolution of Gauss + Lorentz. So, fit your initial peak with a convolution of the two. Then hold the Lorentz component constant and evolve only the Gauss convolution component with time. Presumably, this would model the physics in a truer way??? What I am thinking is this. The Lorentz component is intrinsic and unchanging while the Gauss has both an intrinsic (static) instrument transmission function + an experiment "evolution" function.
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
October 27, 2016 at 05:21 pm - Permalink
Can't let this pass, Jeff. Pseudo-Voigt is a weighted sum of Gauss and Lorentz peaks used to approximate a real Voigt.
The rest of your posting is good!
You can fit a more-nearly-real Voigt by constructing a user-define fitting function based on VoigtFunc in Igor 7. To get the area as a direct fit coefficient, it could be like this:
Wave w
Variable xx
//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/ Variable ratio = sqrtln2/gw
//CurveFitDialog/ Variable xprime = ratio*(xx-x0)
//CurveFitDialog/ Variable voigtY = ratio*shape
//CurveFitDialog/ f(xx) = y0 + area*sqrtln2pi*VoigtFunc(xprime, voigtY)
//CurveFitDialog/ End of Equation
//CurveFitDialog/ Independent Variables 1
//CurveFitDialog/ xx
//CurveFitDialog/ Coefficients 5
//CurveFitDialog/ w[0] = y0
//CurveFitDialog/ w[1] = area
//CurveFitDialog/ w[2] = x0
//CurveFitDialog/ w[3] = gw (FWHM)
//CurveFitDialog/ w[4] = shape (Lw/Gw)
Variable voigtX = 2*sqrtln2*(xx-w[2])/w[3]
Variable voigtY = sqrtln2*w[4]
return w[0] + (w[1]/w[3])*2*sqrtln2pi*VoigtFunc(voigtX, voigtY)
End
You can hold the Gaussian width here very easily. Keeping the Lorentzian width constant would be more difficult; it might require re-writing the fit function in terms of Lor width insteand of Gauss width.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
October 28, 2016 at 09:45 am - Permalink
Yes, this seems like an interesting approach (bearing in mind John's comment about the sum versus convolution). If I expect size or strain broadening I can fix either the Gaussian or Lorentzian components of the Pseudo-Voigt or Voigt fit. Would I just pass the results of the initial fit to the all-at-once convolution fitting function in the parameter wave, and hold those constant in the FuncFit command? This seems like it would be a bit easier than importing the intensity wave each time.
Nick
October 28, 2016 at 11:28 am - Permalink
In a nutshell ... yes and yes. That is the overall gist of my suggestion. Fit the initial peak. Generate a model with fixed parameters. Then, convolve to the fixed initial model over time rather than to the initial experimental data. During the convolution+fit, the parameters of the initial peak are passed as constants. The parameters to the convolution peak are the only ones that are allowed to change.
I'm also guessing that a pseudo-Voigt is a first-order approximation to the truth. It packages the convolution Gauss*Lorentz in a "one kind of peak" shape because doing a convolution+fit is a real bear to do right. Since you are going to do a convolution+fit anyway, do it right on the initial peak AND subsequently convolve ONLY the component that is to "evolve" according to physics.
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
October 28, 2016 at 02:06 pm - Permalink
DisplayHelpTopic "VoigtFunc"
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
October 28, 2016 at 02:29 pm - Permalink
Apologies. I'm a bit late to this new game (still). And, I'm running on three firestorm deadlines in the coming weekend. I seem to miss a lot that I apparently then have to be hit twice again or more with.
The insights about the new function and Igor7 are appreciated. I look forward to making use of them soon.
--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
October 28, 2016 at 02:52 pm - Permalink
Is this new Voigt function used in the Multipeak Fit 2 package in Igor 7?
November 14, 2016 at 05:52 pm - Permalink
https://en.wikipedia.org/wiki/Faddeeva_function
The voigt peak shape used by Multipeak Fit is an implementation of a Voigt peak with inputs and height scaled to give it real-world values. But in fact, the scaling presently used by Multipeak Fit is clumsy and doesn't really correspond to "real world" values; it's just scaled so it can take on any width, height and shape. Igor 8 will have a built-in voigt fitting function that fits peak area, Gaussian width and ratio of Lorenzian to Gaussian width. I hope to add a peak shape to Multipeak Fit that will fit this more convenient version of Voigt.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
November 17, 2016 at 05:06 pm - Permalink