Help wth linear combination analysis

Hi,

I have a spectrum (Stot) that's a linear combination of two known spectra (Sa and Sb). I would like to fit Stot , Stot = kSa + (1-k)Sb, and extract k and 1-k for Sa and Sb respectively from this fit. Need help!

Thanks in advance for the help

LJ
Since you know Sa and Sb you can define functions based on them
function Sa_function(x)
variable x
wave Sa=root:Sa //that is the wave where you have Sa
return Sa(x)
end

same thing for Sb.
And then you use them to define your fit function. You can use "new fit function" and it will generate the following code in your procedure window:
Function New_fit_func(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) = k*Sa(x)+(1-k)*Sb(x)
    //CurveFitDialog/ End of Equation
    //CurveFitDialog/ Independent Variables 1
    //CurveFitDialog/ x
    //CurveFitDialog/ Coefficients 1
    //CurveFitDialog/ w[0] = k

    return w[0]*Sa_function(x)+(1-w[0])*Sb_function(x)
End

You have only one fit parameter (w[0]).
That should do it.

Julien
Thank you Julien, this has set me on the right track for this analysis. When trying to compile, an error is returned highlighting Sa as an "unknown/inappropriate name or symbol"


julien wrote:
Since you know Sa and Sb you can define functions based on them
function Sa_function(x)
variable x
wave Sa=root:Sa //that is the wave where you have Sa
return Sa(x)
end

same thing for Sb.
And then you use them to define your fit function. You can use "new fit function" and it will generate the following code in your procedure window:
Function New_fit_func(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) = k*Sa(x)+(1-k)*Sb(x)
    //CurveFitDialog/ End of Equation
    //CurveFitDialog/ Independent Variables 1
    //CurveFitDialog/ x
    //CurveFitDialog/ Coefficients 1
    //CurveFitDialog/ w[0] = k

    return w[0]*Sa_function(x)+(1-w[0])*Sb_function(x)
End

You have only one fit parameter (w[0]).
That should do it.

Julien
You should post a copy of your code, so we can help debug it.

Please enclose the code between igor code tags so it displays correctly. These are "igor" and "/igor" surrounded by <>.
Code follows. I've attached an image of the spectra for Sa and Sb, which don't have analytical expressions. Thank you for the advice

function Sa_function(x)
variable x
wave Sa=root:Sa
return Sa(x)
end

function Sb_function(x)
variable x
wave Sb=root:Sb
return Sb(x)
end


Function LinearCombo(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) = k*Sa(x)+(1-k)*Sb(x)
    //CurveFitDialog/
    //CurveFitDialog/ End of Equation
    //CurveFitDialog/ Independent Variables 1
    //CurveFitDialog/ x
    //CurveFitDialog/ Coefficients 1
    //CurveFitDialog/ w[0] = k

    return w[0]*Sa(x)+(1-w[0])*Sb(x)
   
End




jtigor wrote:
You should post a copy of your code, so we can help debug it.

Please enclose the code between igor code tags so it displays correctly. These are "igor" and "/igor" surrounded by <>.
SaSb.png (25.46 KB)
At the end of your code defining the fit function you have:
LJ0630 wrote:


    return w[0]*Sa(x)+(1-w[0])*Sb(x)
   




These are not the names of the defined functions.

You should have:

    return w[0]*Sa_function(x)+(1-w[0])*Sb_function(x)
   


Sa and Sb are the waves' names, not the functions' names.

Thank you, my apologies, the new fit function did not generate the code with the function names, I have changed this and it compiles. Unfortunately, the results of the fit do not match what I get when I manually do the linear combination. I don't think the code is getting the source data correctly. The Y data points in Sa and Sb spectra are not evenly spaced. I think the code needs to reference the XY (wavelength,signal) data in the code. Is there a way to reference the XY data?


julien wrote:
At the end of your code defining the fit function you have:
LJ0630 wrote:


    return w[0]*Sa(x)+(1-w[0])*Sb(x)
   




These are not the names of the defined functions.

You should have:

    return w[0]*Sa_function(x)+(1-w[0])*Sb_function(x)
   


Sa and Sb are the waves' names, not the functions' names.
I assume then that you have a wave to give the x_scaling and that you display your data (picture you gave) doing:
display wave_y vs wave_x

If your wave giving the x axis is monotonic (I suspect it is since you talk about wavelength) you might succeed using the following to define your functions
function Sa_function(x)
variable x
wave Sa=root:Sa
wave Sa_xwave=root:Sa_xwave //this is the wave where you store the x-scaling
Findlevel  Sa_xwave, x
return Sa(V_levelX)
end


That said, I would strongly suggest that you resample your data using interpolation, in order to have evenly spaced data points. That is what I usually do to deal with nm/eV.
That will make things much easier.
FindLevel does a linear search through a wave. As long as the X values are monotonic, this should be faster:
Function getInterpY(Variable xx)

    WAVE Sa_X, Sa
    Variable pointWithFraction = BinarySearchInterp(Sa_X, xx)
    return Sa[pointWithFraction]
end


John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Thank you Julien this has improved the fitting.


julien wrote:
I assume then that you have a wave to give the x_scaling and that you display your data (picture you gave) doing:
display wave_y vs wave_x

If your wave giving the x axis is monotonic (I suspect it is since you talk about wavelength) you might succeed using the following to define your functions
function Sa_function(x)
variable x
wave Sa=root:Sa
wave Sa_xwave=root:Sa_xwave //this is the wave where you store the x-scaling
Findlevel  Sa_xwave, x
return Sa(V_levelX)
end


That said, I would strongly suggest that you resample your data using interpolation, in order to have evenly spaced data points. That is what I usually do to deal with nm/eV.
That will make things much easier.

Thanks John, this certainly speeds things up. While the fitting is quite improved, the fitting results don't quite match up with the results I get with the manual calculation. I think this is most likely attributed to my x-scaling. I have an x wave with data points 352.826, 353.309, 353.782, 354.274nm...., x data points are separated by about 0.50 nm. I've tried 'XY Pair to Waveform' and interpolation but my fits are still off. Any suggestions?

Also, I have Stot at a series of time points. Is there a way to fit more than one spectrum at a time?


johnweeks wrote:
FindLevel does a linear search through a wave. As long as the X values are monotonic, this should be faster:
Function getInterpY(Variable xx)

    WAVE Sa_X, Sa
    Variable pointWithFraction = BinarySearchInterp(Sa_X, xx)
    return Sa[pointWithFraction]
end


John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Too be able to say anything about the fit, we would need an Igor experiment file containing a data set, your fitting function, and a representative FuncFit command that leads to a less-than-perfect fit. If it's not completely obvious to the most casual observer, it would be good to note what you think is wrong with the fit.

As far as fitting lots of data sets, check out the Batch Curve Fitting package. Start with the demo: File->Example Experiments->Curve Fitting->Batch Curve Fitting Demo.

If you mean that you wish to do a single fit that includes many data sets, then you need the Global Fit package. File->Example Experiments->Curve Fitting->Global Fit Demo.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com