Question about "Fitting Sums of Fit Functions" (FuncFit)
I would like to fit a spectrum with a sum of several waves. Until the actual fit, I can also read in different numbers of waves and pass them on to the actual user function that is to perform the fit.
For this I would actually pass the fit as a string to the FuncFit, but unfortunately I don't quite understand the requirements that the string must fulfil in the end.
If I were to display this fit normally, it would look like this, for example:
Wave w
Variable x
wave wave0=path
wave wave1=path
return w[0]*wave0(x)+w[1]*wave1(x)+w[2]
End
And be called using this function:
FuncFit/Q f_fit_function_name wave[v_start,v_end] /D /C={M_FitConstraint,W_FitConstraint}
If I have understood correctly, I can also trigger such a function via a string:
FuncFit/Q {string=fitSpecStr} wave[v_start,v_end] /D /C={M_FitConstraint,W_FitConstraint}
There is something about it in this chapter in the manual:
DisplayHelpTopic "FuncFit" //Fitting Sums of Fit Functions
The function could be represented like this:
{{func1, coef1, keyword =value },{func2, coef2, keyword =value }, ...}
Or the expression can be entered via a string:
with fitSpecStr = "{func1, coef1, keyword =value },{func2, coef2, keyword =value }, ..."
But I'm not really getting anywhere here. I can leave out the keywords, but the comma has to stay? Or does the statement apply to all other commas?
or
"{wave0, w[0]},{wave1, w[1]},{wave2, w[2]}"
Can "func" be a wave? Or do I have to define the wave as a wave?
"{wave wave0, w[0]},{wave wave1, w[1]},{wave wave2, w[2]}"
Do I have to specify the x-dependency?
"{wave0(x), w[0]},{wave1(x), w[1]},{wave2(x), w[2]}"
Is coef the same as w[n] or is it something like W_coef[n]?
"{wave0(x), W_Coef[0]},{wave1(x), W_Coef[1]},{wave2(x), W_Coef[2]}"
How can I represent an offset as a function? Simply a "1"?
"{wave0(x), W_Coef[0]},{wave1(x), W_Coef[1]},{1, W_Coef[2]}"
I have tried various things, but always get the same error:
error: expected fitting function
And directly another question: Is a FuncFit based on a string Threadsafe?
I know the questions are very specific, but still hope someone can help me.
Can you save a global wave reference wave filled with references to the waves to be fit?
Then you invoke the fit function with an appropriately dimensioned coefficient wave, the fit function looks up the wave reference wave, and loops though the waves adding together values at x, each multiplied by a fit coefficient.
April 1, 2021 at 04:39 am - Permalink
So you mean a multidimensional reference wave where each column contains one reference wave?
Wave w
Variable x
wave reference=path
variable index
string s_return
for (index=0;index<(dimsize(reference,1));index+=1)
s_return+="w["+num2str(index)+"]*reference[x]["+num2str(index)+"]+"
endfor
s_return+="w["+num2str(index)+"]"
return $s_return
End
That would be a good solution, but how do I assemble a return in this case? I can't set the loop around a return, isn't is? (The frist return of the loop will end the function.) Igor doesn't want to translate a string like in my example. Probably this problem is super simple, but in the DisplayHelpTopic "return" I could not find anything about the form in which the expression has to be passed. Any idea?
Thanks!
April 1, 2021 at 06:18 am - Permalink
i mean something like this
wave /WAVE refs = pathToWaveRefsWave
variable i
variable total = w_coef[numpnts(w_coef)-1]
for(i=numpnts(refs);i>=0;i--)
wave w = refs[i]
total += w_coef[i] * w(x)
endfor
return total
end
see also
DisplayHelpTopic "Wave Reference Waves"
April 1, 2021 at 06:32 am - Permalink
Note: I understood from your question that you want to perform a fit like the one in the first function in your post, but with an arbitrary selection of waves rather than wave0 and wave1. Maybe that wasn't what you meant?
April 1, 2021 at 06:42 am - Permalink
So there was my error of thought. Then I will implement it with this much simpler solution. Thank you!
April 1, 2021 at 06:44 am - Permalink
Back from vacation...
I will note that the Sum of Fit Functions facility is for a different purpose. It was created originally with Multipeak Fit in mind; each of the summed fit functions represents a single peak or a background function. The string is used to list all the fit functions and coefficient waves required.
If you wanted to make your life very complicated, you could write a fit function that computes the multiplier for one of your reference waves, and then use the sum of fit functions feature to add them together. But that would be difficult to set up, and probably much slower. The WAVE wave is a much better solution.
April 5, 2021 at 04:29 pm - Permalink
I am attaching this question in this thread because it is thematically related to it:
Is there a way to create a comparable dynamic function for an all-at-once function?
According to the manual, a-a-o functions cannot be created or edited within the Curve Fitting dialog. But can they be created within a FuncFit function?
At my first attempts I get the error that the variable must not contain a complete wave. I am now unsure if I am trying something here that cannot work at all.
Wave pw,yw,xw
wave /WAVE list=root:listwave
variable index
variable v_return=0
for (index=0;index<(dimsize(list,0));index++)
wave w=list[index]
//next line: error "ambiguous wave point number" for "w"
v_return+=pw[index]*w
endfor
v_return+=pw[(dimsize(list,0))]
yw = v_return
end
The idea here is that it will end up working like this function:
wave pw, yw, xw
wave w1=root:wave0
yw = pw[0]*w1 + ... + pw[n]
End
To me, this looks like an actually similar result when comparing normal fit functions with a-a-o fit funcitions (the end result now says "yw =" instead of "return"). But that is perhaps too simple a thought.
Edit: Wouldn't it be possible to make the execute command compatible with FuncFits in a future Igor (sub)version?
wave pw, yw, xw
wave w1=root:wave0
string s_execute="yw = pw[0]*wave0+pw[1]"
execute s_execute
end
That would make such dynamic problems easier, perhaps?
September 14, 2021 at 04:15 am - Permalink
I am not sure what you are trying to do, but your first example contains a few things which cannot work (at least in this way):
v_return+=pw[index]*w
You are trying to assign a whole wave to a variable, which does not make sense. You need to specify the point of the wave which you like to assign such as w[0]. Next:
yw = v_return
You are assigning the variable to your output wave, which makes all points of the wave the same. I don't think this is what you want (unless you want a horizontal line). An all-at-once fitting function writes the result of some calculation into the wave (as the name says) all-at-once, so ideally you want to give a resulting value to each point of yw. Also, you are not using xw at all, which does not seem right (how is the x-axis involved in your calculation).
September 14, 2021 at 06:27 am - Permalink
For a point-by-point func fit, you can create what is fitted with return using a variable. This was the solution of tony, which works well. In which form would it have to be passed for an all-in-ones fit function? I think this point is my biggest problem: I have no idea. Of course, it may be that this easy solution works for a normal FuncFit, but not for an all-at-ones.
(I would prefer a way via a string, but that doesn't work, I think.)
It seems that the xw has to come in brackets after each wave:
wave pw, yw, xw
wave w1=root:wave0
...
yw = pw[0]*w1(xw) + ... + pw[n]
End
September 14, 2021 at 07:04 am - Permalink
In reply to I am attaching this question… by ggermer
Wave pw,yw,xw
wave /WAVE list=root:listwave
variable index
for (index=0;index<(dimsize(list,0));index++)
wave w=list[index]
yw+=pw[index]*w
endfor
end
Edit: I think it's okay to ignore xw if you know that points in each of listwaves correspond to points in yw.
Unless you need an all-in-one fit, probably better to stick with the normal fitting function.
September 14, 2021 at 07:10 am - Permalink
In reply to function f_fitFunc_lc_MT_new… by tony
if you want to fit subranges you will need something like this:
wave /WAVE list=root:listwave
int index, imax
imax = dimsize(list,0)
for (index=0;index<imax;index++)
wave w = list[index]
yw += pw[index] * w(xw[p])
endfor
end
September 14, 2021 at 08:12 am - Permalink
Thank you very much, I will try that.
What are the disadvantages of an all-in-one fit compared to a normal fit? I was hoping to save time while keeping the quality of the coefficients the same.
September 14, 2021 at 08:58 am - Permalink
Yes, an all-at-once fit function is faster if you are fitting many points because all the model values are computed with one call to your fitting function. But the standard fit function that returns one model value for one value of the independent variable is much easier to use outside of curve fitting because you can simply assign the result to a variable or to a wave with a standard wave assignment. With the AAO style function, you MUST create an X wave to pass to the function even if your values are evenly spaced in X.
You have probably figured out that in an AAO function, the return value is irrelevant. All the action happens in an assignment to the YW wave.
Adding quite a lot of complexity that may or may not be justified: another approach would be a structure fit function. The standard parts of the fit function are encapsulated at the top of a structure, and then you can add arbitrary items to the structure. Such items might include a reference to the WAVE wave containing your list of waves, and maybe information on a subset of that list if that might be useful. The BIG downside is that you can't create a stand-alone structure in Igor, so you have to write a wrapper function that creates the structure and then invokes FuncFit.
Seeing all these lists of waves and arbitrary numbers of coefficients required to fit the arbitrary sums compels me to give a warning:
You MUST use ALL the coefficients in your fit expression. Any unused points in your coefficient wave will result in a zero derivative and a guaranteed Singular Matrix error. So you will have to make sure the coefficient wave and the number of terms you want to sum always agree with each other. One way to do that is to write a wrapper function that sets up the required conditions. Now a structure fit function is sounding more appealing...
September 14, 2021 at 01:37 pm - Permalink
Thank you for the explanation.
I know the problems with the errors for FitFunctions with a wrong number of input parameters. Therefore, I have an input window that makes sure that the appropriate length of the waves is generated before the fits. (And a function that converts limit inputs to matrix format.)
Tony's solution seems to be compatible with minor changes, fortunately, so the AAO fit works and save time (factor 3). Many thanks again at this point! So I hope I don't need the structures, but will look at them.
September 14, 2021 at 02:14 pm - Permalink