Auto-guess non-linear fit coefficients

How does Igor auto-guess coefficients for curve fitting? What is the algorithm used?
I guess Wavemetrics payed some employees quite a bit of money to code this by hand and to carefully tweak the algorithm :-)

Maybe if you post your formula, somebody has an idea how to do sufficient initial guesses...

HJ
HJDrescher wrote:
I guess Wavemetrics payed some employees quite a bit of money to code this by hand and to carefully tweak the algorithm :-)

Maybe if you post your formula, somebody has an idea how to do sufficient initial guesses...

Exactly.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com

In reply to by johnweeks

What are the best tools us users have at our disposal and where is the best place to look in the manual?

I am thinking that if I can find {the local and global extrema, the first numerical  derivative and its local and global extrema, etc.} and do math with those quantities, then I have a lot of tools to generate the initial coefficients for my fit function.

I understand that Igor has a lot of programmability, but I am wondering where to start and also wondering if this functionality is built in to the "Fit Expression" or "Edit Fit Function" interfaces.

Edit: With this edit,  I include my fit function. It is a pseudo-Voigt function

variable result
variable Lrntz
variable Gss
Lrntz = (II/3.14158265)*( Lg / ( (x-x0)^2 + Lg^2 ) )
Gss = (II/Gc/(2*3.14158265)^(1/2)) * 2.718281828459^( (-1)*(x-x0)^2/( 2*Gc^2 ) )
result = eta*Lrntz + (1-eta)*Gss +y0
f(x) = result

The guessing algorithms are hidden within Igor's source code. They depend quite a lot on the individual characteristics of the functions involved.

Perhaps if you posted your fit function, and if it's not too complicated, we might help you figure out something.

I am thinking that if I can find {the local and global extrema, the first numerical  derivative and its local and global extrema, etc.} and do math with those quantities

This is sounding a lot like finding peaks. Have you found the Multipeak Fit package? For a demo: File->Examples->Curve Fitting->Multi-peak Fit 2 Demo.

In reply to by lscanlonj

When I need starting guesses for pseudo-Voigt I first fit a Gaussian (built-in) and use the fit coefficients as starting guesses (depending on the form of the pseudo-Voigt you may have to make some transformation), and assume some shape parameter. If fitting fails for built-in Gaussian and Lorentzian functions, I think it is unlikely that you will find a good set of guesses for pseudo-Voigt.

I have written an Igor procedure to fit XPS spectra using pseudo-Voigt peaks: My experience with bad initial guesses is that the Gaussian-to-Lorentzian ratio often ends up stuck in a local minimum above 1 producing a saw-tooth shaped peak, even when constrained to below 1. Small peaks next to large peaks can also do weird things for bad initial guesses.

The way I dealt with it is to let the user select the number and initial positions of the peaks in the fit by placing a cursor at different positions in the spectrum and then clicking an Add Peak button for each position. That will add peaks with a height matching the intensity of the spectrum at the point and a fixed FWHM and GL ratio typical for XPS peaks.

When the user then clicks fit. My procedure runs two fits: The first is a rough fit with the positions and GL ratios held constant. This fit is then used as initial guesses for the final fit where all parameters are allowed to change.

Tony's suggestion of first fitting a pure Gaussian is also a really good suggestion.

My initial guess for a linear background is a straight line between the first and last data points, shifted down so the line doesn't cross the spectrum at any point. Before fitting a spectrum I also automatically shift the x-axis to center it around zero, so the slope and offset becomes more independent of each other. That also seems to stabilize the fit.

In reply to by lscanlonj

lscanlonj wrote:

Edit: With this edit,  I include my fit function. It is a pseudo-Voigt function

variable result
variable Lrntz
variable Gss
Lrntz = (II/3.14158265)*( Lg / ( (x-x0)^2 + Lg^2 ) )
Gss = (II/Gc/(2*3.14158265)^(1/2)) * 2.718281828459^( (-1)*(x-x0)^2/( 2*Gc^2 ) )
result = eta*Lrntz + (1-eta)*Gss +y0
f(x) = result

Is there a compelling reason to fit a pseudo-Voigt instead of Voigt? It used to be that the convolution involved was too slow, and so various approximate peak shapes were invented. But that was before processors got fast, and before the development of high-quality approximations like the one Igor uses internally. So now it's practical to fit sort-of-real Voigt peaks. And that way, you get Igor's auto-guessing.

I can't answer for Iscanlonj, but in my case for XPS spectra, I need the area to be a fit parameter I can fix, either absolute or in relation to other peaks. Last I looked most of the built-in peak functions used the amplitude as input instead of the area.

To include the Shirley background of the peaks as a fit parameter I also need the integral of the peak to be known. For a Gaussian peak the integral is erf(x) for a Lorentzian it's arctan(x). I don't know if the integral of a Voigt is readily available. For me, the benefit of being able to include the Shirley background in this way far outweighs the advantage of using a real Voigt instead of a pseudo-Voigt lineshape.

I go through the same considerations when choosing which asymmetric lineshapes to use, which is why I rarely use Doniach-Sunjic lineshapes.

While it's true that the built-in Voigt, Gauss and Lor fit functions don't have area as a parameter (I have been hanging fire on this for a while) the latest Multipeak Fit now shipping with the Igor 9 beta has that option. It also has Donjiac-Sunjic peak shape and Shirley background as well as several other new things.

All thanks to Stephan Thürmer (chozo) who seems to have had lock-down time on his hands.

Wait a moment...

DisplayHelpTopic "VoigtPeak" (Igor 8):

This function is equivalent to the built-in Voigt fitting function. See Built-in Curve Fitting Functions.
The coefficients are:
w[0]:    Vertical offset.
w[1]:    Peak area

Seems that area IS a fit parameter in the built-in version?

Well, that's not a built-in fit function, it's just a function. In fact, I added that so that I could write a user-defined fit function for Multipeak Fit like this:

Function MPFVoigtPeak(Wave pw, Wave yw, Wave xw) : FitFunc
    yw = VoigtPeak(pw, xw)
end

As it happens, since it is an all-at-once function, it runs pretty fast. Perhaps I should have used Multithread...

Adding that function allowed eliminating the MultipeakFit XOP. As you may be aware, XOPs are problematic in OS X Catalina.

On the other hand, yes, as that help topic suggests, the built-in Voigt fit function uses area as a coefficient. Since it is quite recent, I have the benefit of experience suggesting that is preferable to a lot of folks. However, it still uses the ratio of L/G widths instead of separate G and L widths.

Unfortunately, I still haven't gotten around to adding versions of Gauss and Lor that use area. I need to add GaussArea, LorArea and VoigtWidth built-in functions.

You can read about the built-in functions: DisplayHelpTopic "Built-in Curve Fitting Functions"

EDIT: Oops, one minute too late...

Yes! But Multipeak Fit, which would arguably be the choice for fitting more complex data, builds on the MPFXVoigtPeak function, which is defined in terms of amplitude. But now you also have an alternative in Multipeak Fit which uses the area (or, to be precise, just rearranges coefficients for said function)! Then you have VoigtFunc, which has you decide your flavor yourself, so to speak, by combining coefficients to the desired pre-factor. The Voigt is somewhat complicated in Igor ... :)