Overlapping Absorption curves

Dear WaveMetrics-Team,

I am trying to unravel the proportions of two species of molecules within an absorption spectra. My first approach was to use the multipeakfit you provided, but I am not happy with the results. What I would like to do is the following:
I would like Igor to perform a fairly simple thing, namely fitting the ratio of two waves (A & B) such, that it matches a 3rd one (C) and extracting the absoulte and total number, i.e. C=x*A+y*B and to get x,y and y/x or x/y. I attached an exemplary scan: blue and yellow in the right ratio are supposed to give green.

I couldn't think of a simple way of doing this, nor did I find it in the forum - maybe I didin't use the right keywords.

Apart from that, I am a graduate student, that just started with Igor, so consider me a novice :).

Thanks in advance!
What I forgot to mention was: I am mearly interested in the region above 400 so the two peaks right.
Sounds more like a minimisation/optimisation problem rather then curve fitting, but this approach should work as well:

make aa, bb, cc       //make test data
setscale /i x, 0, 2, "", aa, bb, cc
aa = sin(x)*1/sqrt(x)
bb = sin(1.5*x)*sqrt(x)
cc = 0.3*aa+0.7*bb


create a user defined fitting function with two independent variable, which will result in something like this

Function test(w,one,two) : FitFunc
    Wave w
    Variable one
    Variable two

    //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(one,two) = x1*one+x2*two
    //CurveFitDialog/ End of Equation
    //CurveFitDialog/ Independent Variables 2
    //CurveFitDialog/ one
    //CurveFitDialog/ two
    //CurveFitDialog/ Coefficients 2
    //CurveFitDialog/ w[0] = x1
    //CurveFitDialog/ w[1] = x2

    return w[0]*one+w[1]*two
End


Then use the curve fitting dialogue, select function test, cc as Y data and aa and bb as X data to run it. You need to enter initial guesses for x1, x2. Maybe you have done something like this, but then you need to explain why you were not happy with the results.





It really is a curve fitting problem. Try this:
Function FitMixingRatio(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/ WAVE standardwave1, standardwave2
    //CurveFitDialog/
    //CurveFitDialog/ f(xx) = A*standardwave1(xx) + B*standardwave2(xx)
    //CurveFitDialog/ End of Equation
    //CurveFitDialog/ Independent Variables 1
    //CurveFitDialog/ xx
    //CurveFitDialog/ Coefficients 2
    //CurveFitDialog/ w[0] = A
    //CurveFitDialog/ w[1] = B

    WAVE standardwave1, standardwave2
   
    return w[0]*standardwave1(xx) + w[1]*standardwave2(xx)
End

This function makes some assumptions. The two standard waves must be waveforms- that is, they are defined by a single wave with the X values encoded by the wave's X scaling. If you don't know what that means, please go to Help->Getting Started and go through at least the first half of the Guided Tour.

There is no provision for dilation and offsetting- it is assumed that the data set is truly represented by simply mixing the two standards.

As written, the standard waves must be named exactly "standardwave1" and "standardwave2". Naturally, you can change the names if you wish.

This is not the most efficient implementation. If your data sets are very large a more complex implementation might be called for.

Copy the code above into your Procedure window. After compiling you will find FitMixingRatio in the list of fit functions in the Curve Fit dialog. To make it available whenever you run Igor, read this help:

DisplayHelpTopic "Fitting to a User-Defined Function"

then scroll down to find the sub-section "Making a User-Defined Function Always Available".

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
So thank you already, I understand the logic of the code and it seems beautifully simple and efficient! My dataset has less than 2000 data points, each. Is that a big set? I'll try in the next few hours and let you know how it worked out!
So, it works nicely. I have some things that are not working perfectly, but I guess that is exactly what you mentioned, John, concerning the shifts and the x-values.
I can't use the "real" x-wave (e.g. the wavelength) for the fit or it does not work. Thus the scaling of the x-values is different and it starts with x=0 instead of x=200.
I worked around that "graphically" by shifting it and plotting the fit wave with the calculated x-data, but I hope that I will learn how to do this automatically.
Was that what you meant, John?

Nevertheless, thank both of you for the quick and precise answer.
Yes, that's what I meant. The way I wrote the function assumes that your standard waves don't have an X wave. Here's a version that assumes that the standards DO have an X wave. Note that it assumes the SAME X wave for both. If they have separate X waves, I leave that to you as an exercise :)
Function FitMixingRatio(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/ WAVE standardwave1, standardwave2
    //CurveFitDialog/
    //CurveFitDialog/ f(xx) = A*standardwave1(xx) + B*standardwave2(xx)
    //CurveFitDialog/ End of Equation
    //CurveFitDialog/ Independent Variables 1
    //CurveFitDialog/ xx
    //CurveFitDialog/ Coefficients 2
    //CurveFitDialog/ w[0] = A
    //CurveFitDialog/ w[1] = B
 
    WAVE standardwave1, standardwave2
    WAVE standardXWave
   
    // if xx is outside the range of the X wave, it will return NAN. This is clearly an error on
    // the part of the user or programmer. Returning NAN for that case will cause the fit to
    // fail, which is really the only recourse.
    Variable xpoint = BinarySearchInterp(standardXWave, xx)
    if (numtype(xpoint) != 0)
        return NAN
    endif
 
    return w[0]*standardwave1[xpoint] + w[1]*standardwave2[xpoint]
End

It also still assumes that your standard waves have standard names; as before you can change the code to accommodate different names. There are tricky ways to accommodate waves with any name, but it probably isn't worth it.

And 2000 points is not a big data set; perhaps 2000000 would be big.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com