Programming for the evolution of spectrum with time

Hi,
I have a data set of the energy spectrum obtained at different time steps. The shape of the spectrum changes with time. I have the parameters obtained from the multipeak fit2 using exponentially modified gaussian equation. Since the data is obtained from the same condition, I decided to chose the same gaussian width, position and exponential decay parameter for the fit to a particular peak. Now I need to write a code on how the energy spectrum evolves with time. I went through the help section in igor to understand how the programming works; however as I do not have a strong foundation in programming, I have no clear idea on how to start. Can anyone help me with this? Also please suggest me if my fitting is correct because I have doubt as the chi-square value for the fit is in thousands.
I have attached the igor file that contains the data.
Thanks in advance.
Tika
Test_1.pxp
[quote=s.r.chinn]see the Time-Frequency toolkit at http://www.igorexchange.com/project/TFPlot[/quote]
Thanks Chinn for the link. I downloaded the TFPlot file and checked but it didn't help. In fact, I need to figure out how the energy spectrum, that follows exponentially modified gaussian function, will change the shape with the time.
Thanks.
Perhaps what you want is MPF2_AutoMPFit(), which is part of the Multipeak Fit 2 package. It is somewhat difficult to use... If your spectra are in one wave per time step, you can feed all the waves into that function and it will do the whole batch. Creating the summary of all the data can be difficult, though.

In the Multipeak Fit 2 package control panel, click the Help button. Follow the link near the top of the help to the section on MPF2_AutoMPFit().

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
johnweeks wrote:
Perhaps what you want is MPF2_AutoMPFit(), which is part of the Multipeak Fit 2 package. It is somewhat difficult to use... If your spectra are in one wave per time step, you can feed all the waves into that function and it will do the whole batch. Creating the summary of all the data can be difficult, though.

In the Multipeak Fit 2 package control panel, click the Help button. Follow the link near the top of the help to the section on MPF2_AutoMPFit().

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com

Hi,
I can see the MPF2_AutoMPFit() in the help section but I can't have access to this command while fitting. What I can select is Analysis, Packages, MultiPeak Fitting, Multipeak Fitting2 which then opens with a panel Start MultiPeak fit from when I can auto locate the peaks or select it manually. Am I in the right direction?
Thanks
As I understand, you want to fit each spectrum, obtain the fitting parameters and their uncertainties, and analyze how those parameters change with time. Also, I understand that you have no programming experience (certainly not in Igor Pro) but that you have a strong interest to do the programming, are willing to devote the time needed, and have an urgent but not immediate need to get the results. In this case, I might recommend this approach to start.

* Create a function that you can call from the command line to fit just ONE of your spectra. For example, FitMySpectrum(...). The (...) input could be nothing or it could be the name of the spectrum wave. The return from this function would be a print of all of the fit parameters and their uncertainty values. You can used the Multipeak package but ... that is overkill. When you really want to learn how to automate this, you should start by learning how to write your own fitting function.
* Run FitMySpectrum(...) manually to fit each spectrum.
* Record the results in a spreadsheet-like manner either in Igor Pro or in a spreadsheet app in a way to import to Igor Pro. The results would be a set of columns time, K1, dK1, K2, dK2, ... where Kj is the fit constant and dKj is its uncertainty.
* Plot Kj versus time with error bars dKj in Igor Pro (or in your spreadsheet app).

Once you have convinced yourself that you have this manual process working, the next level of programming can begin. For this, you will be wise to make one fundamental change.

* Store your waves in Folders with names that do NOT have () and do NOT start with numbers. For example, instead of 1ps(2) the folder might be named t1ps_2. This naming convention avoids later issues about using "liberal" names (look up liberal names in the Igor help or manual).

After this, you can write a function to move through your folders starting at the root level and run FitMySpectrum(...) on the wave set(s) inside. Also, you can have the fitting results stored automatically in Igor Pro waves so that you do not have to print them, copy them over, and re-load them back in to Igor Pro by hand.

So, to recap ...

* Learn how to write the function required to fit ONE spectrum and use it to fit each spectrum in your data set.
--> print the results to the command line and graph or analyze them in Igor Pro or elsewhere
* Learn how to write a function that moves through different data folders.
* Learn how to store results inside Igor Pro.

Your best starting point when you have no foundation in coding but really do want to do this on your own is to stay firmly focused on the first task.

When you must have the results by yesterday ... well ... this becomes an entirely different problem.

Does this help focus on what to do next?

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
jjweimer wrote:
As I understand, you want to fit each spectrum, obtain the fitting parameters and their uncertainties, and analyze how those parameters change with time. Also, I understand that you have no programming experience (certainly not in Igor Pro) but that you have a strong interest to do the programming, are willing to devote the time needed, and have an urgent but not immediate need to get the results. In this case, I might recommend this approach to start.

* Create a function that you can call from the command line to fit just ONE of your spectra. For example, FitMySpectrum(...). The (...) input could be nothing or it could be the name of the spectrum wave. The return from this function would be a print of all of the fit parameters and their uncertainty values. You can used the Multipeak package but ... that is overkill. When you really want to learn how to automate this, you should start by learning how to write your own fitting function.
* Run FitMySpectrum(...) manually to fit each spectrum.
* Record the results in a spreadsheet-like manner either in Igor Pro or in a spreadsheet app in a way to import to Igor Pro. The results would be a set of columns time, K1, dK1, K2, dK2, ... where Kj is the fit constant and dKj is its uncertainty.
* Plot Kj versus time with error bars dKj in Igor Pro (or in your spreadsheet app).

Once you have convinced yourself that you have this manual process working, the next level of programming can begin. For this, you will be wise to make one fundamental change.

* Store your waves in Folders with names that do NOT have () and do NOT start with numbers. For example, instead of 1ps(2) the folder might be named t1ps_2. This naming convention avoids later issues about using "liberal" names (look up liberal names in the Igor help or manual).

After this, you can write a function to move through your folders starting at the root level and run FitMySpectrum(...) on the wave set(s) inside. Also, you can have the fitting results stored automatically in Igor Pro waves so that you do not have to print them, copy them over, and re-load them back in to Igor Pro by hand.

So, to recap ...

* Learn how to write the function required to fit ONE spectrum and use it to fit each spectrum in your data set.
--> print the results to the command line and graph or analyze them in Igor Pro or elsewhere
* Learn how to write a function that moves through different data folders.
* Learn how to store results inside Igor Pro.

Your best starting point when you have no foundation in coding but really do want to do this on your own is to stay firmly focused on the first task.

When you must have the results by yesterday ... well ... this becomes an entirely different problem.

Does this help focus on what to do next?

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH


Thank you Prof. Weimer for clear picture on how to proceed on. Since I am a beginner in programming, it took some time for me to go through the manual. I wrote a function 'FitMySpectrum' which does not show any error while compiling. I tried to call the function in the command line using 'Print FitMySpectrum()' but it returned NAN. In fact I do not know on how to use the function to fit the data 'col_40ps' because it does not pop up any box where I can enter the fitting parameters as in MultipeakFitting. Can you please suggest me further? Here is the function I wrote.
Thank you
#pragma rtGlobals=3     // Use modern global access method and strict wave access.
    Function FitMySpectrum()   
          Wave col_40ps
          Variable p1,p2,p3,p4 //fitting parameters
          Variable x //time
          //Variable p1 = xo           //Xoffset
         //Variable p2 = A            //amplitude
        //Variable p3 = s            // sigma parameter that determines the shape
        //Variable p4 = T           //Tau exponential decay constant
        Variable w1 = exp(0.5*(p3/p4)^2-(x-p1)/p4)
        Variable w2 = erfc(0.707*(p3/p4-(x-p1)/p3))
        Variable w3 = 0.5*p2/p4
        Variable w4 = w1*w2*w3     //exponentially modified gaussian function
   
    return w4
end
Tika wrote:

Thank you Prof. Weimer for clear picture on how to proceed on. Since I am a beginner in programming, it took some time for me to go through the manual. I wrote a function 'FitMySpectrum' which does not show any error while compiling. I tried to call the function in the command line using 'Print FitMySpectrum()' but it returned NAN. In fact I do not know on how to use the function to fit the data 'col_40ps' because it does not pop up any box where I can enter the fitting parameters as in MultipeakFitting. Can you please suggest me further? Here is the function I wrote.
Thank you
#pragma rtGlobals=3     // Use modern global access method and strict wave access.
    Function FitMySpectrum()   
          Wave col_40ps
          Variable p1,p2,p3,p4 //fitting parameters
          Variable x //time
          //Variable p1 = xo           //Xoffset
         //Variable p2 = A            //amplitude
        //Variable p3 = s            // sigma parameter that determines the shape
        //Variable p4 = T           //Tau exponential decay constant
        Variable w1 = exp(0.5*(p3/p4)^2-(x-p1)/p4)
        Variable w2 = erfc(0.707*(p3/p4-(x-p1)/p3))
        Variable w3 = 0.5*p2/p4
        Variable w4 = w1*w2*w3     //exponentially modified gaussian function
   
    return w4
end


With the quick disclaimer that I have never used a custom fitting function I offer the following advice... a quick perusal of the manual (see "User-Defined Fitting Function" in the manual/help files) shows the function name should have " : FitFunc" appended in order for it to appear in the list of fit functions in the Curve Fitting dialog, as in:

        Function FitMySpectrum() : FitFunc

Additionally, your custom fit function must be set up to accept certain input parameters. It's best to read over the manual sections on user defined fitting functions for more precise info on this aspect.

Hope this helps move your project along!

Jeff
jtigor wrote:
Tika wrote:

Thank you Prof. Weimer for clear picture on how to proceed on. Since I am a beginner in programming, it took some time for me to go through the manual. I wrote a function 'FitMySpectrum' which does not show any error while compiling. I tried to call the function in the command line using 'Print FitMySpectrum()' but it returned NAN. In fact I do not know on how to use the function to fit the data 'col_40ps' because it does not pop up any box where I can enter the fitting parameters as in MultipeakFitting. Can you please suggest me further? Here is the function I wrote.
Thank you
#pragma rtGlobals=3     // Use modern global access method and strict wave access.
    Function FitMySpectrum()   
          Wave col_40ps
          Variable p1,p2,p3,p4 //fitting parameters
          Variable x //time
          //Variable p1 = xo           //Xoffset
         //Variable p2 = A            //amplitude
        //Variable p3 = s            // sigma parameter that determines the shape
        //Variable p4 = T           //Tau exponential decay constant
        Variable w1 = exp(0.5*(p3/p4)^2-(x-p1)/p4)
        Variable w2 = erfc(0.707*(p3/p4-(x-p1)/p3))
        Variable w3 = 0.5*p2/p4
        Variable w4 = w1*w2*w3     //exponentially modified gaussian function
   
    return w4
end


With the quick disclaimer that I have never used a custom fitting function I offer the following advice... a quick perusal of the manual (see "User-Defined Fitting Function" in the manual/help files) shows the function name should have " : FitFunc" appended in order for it to appear in the list of fit functions in the Curve Fitting dialog, as in:

        Function FitMySpectrum() : FitFunc

Additionally, your custom fit function must be set up to accept certain input parameters. It's best to read over the manual sections on user defined fitting functions for more precise info on this aspect.

Hope this helps move your project along!

Jeff

Thanks Jeff. I modified my code and now I can see how The ''Function FitMySpectrum() : FitFunc'' loads my function in the curve fitting dialog box. I can fit my defined EMG function however there is another problem. I have multiple peaks (two) and my function is defined only for a single peak, so fitting does not make sense. I tried making use of while loop taking help from the procedure file of EMG to include two peaks, but it did not work. Can anyone suggest me how can my code be modified for fitting two peaks? Also I am wondering how could I call the function directly from the command line. Here is my code. Thanks.
#pragma rtGlobals=3     // Use modern global access method and strict wave access.
Function FitMySpectrum(p, x) : FitFunc 

    WAVE p     //fitting parameters
    //Variable p[0] = xo           //Xoffset
    //Variable p[1] = A            //amplitude
    //Variable p[2] = s            // sigma parameter that determines the shape
    //Variable p[3] = T           //exponential decay constant
   
    Variable x                                      
    Variable w1, w2, w3, q                   // local variable
   
    // Body code
     
    w1 = exp(0.5*(p[2]/p[3])^2-(x-p[0])/p[3])  
    w2 = erfc(0.707*(p[2]/p[3]-(x-p[0])/p[2]))
    w3 = 0.5*p[1]/p[3]
    q = (w3*w1)*w2
   
    return q
End
For two peaks, use the modification below. You must supply additional parameters in the coefficient wave to handle two peaks. Note: p, q, and x are reserved names in Igor Pro!

Function FitTwoPeaks(ww, xx) : FitFunc 
    WAVE ww     //fitting parameters
        variable xx

    //Variable ww[0] = xo           //Xoffset
    //Variable ww[1] = Ao            //amplitude
    //Variable ww[2] = so            // sigma parameter that determines the shape
    //Variable ww[3] = To           //exponential decay constant
    //Variable ww[4] = x1           //Xoffset
    //Variable ww[5] = A1            //amplitude
    //Variable ww[6] = s1            // sigma parameter that determines the shape
    //Variable ww[7] = T1           //exponential decay constant

    Variable xx                                      
    Variable w1=0, w2=0, w3=0, qq, ic                  // local variable
 
    // Body code
 
        for(ic=0;ic<2;ic+=1)
        w1 += exp(0.5*(ww[2+ic*4]/ww[3+ic*4])^2-(xx - ww[0+ic*4])/ww[3+ic*4])  
        w2 += erfc(0.707*(ww[2+ic*4]/ww[3+ic*4]-(xx - ww[0+ic*4])/ww[2+ic*4]))
        w3 += 0.5*ww[1+ic*4]/ww[3+ic*4]
        endfor
    qq = (w3*w1)*w2

    return qq
end


Assume your data is in a scaled wave called mySpectrum. Move to the folder that contains that wave. Here is a summary of the input to run this from the command line.

make/N=8/D/O wcoeff // this is the coefficient wave
wcoeff = {...} // provide initial guesses for coefficients ... read the manual to see how to do this
FuncFit FitTwoPeaks, wcoeff, mySpectrum /D


--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH
jjweimer wrote:
For two peaks, use the modification below. You must supply additional parameters in the coefficient wave to handle two peaks. Note: p, q, and x are reserved names in Igor Pro!

Function FitTwoPeaks(ww, xx) : FitFunc 
    WAVE ww     //fitting parameters
        variable xx

    //Variable ww[0] = xo           //Xoffset
    //Variable ww[1] = Ao            //amplitude
    //Variable ww[2] = so            // sigma parameter that determines the shape
    //Variable ww[3] = To           //exponential decay constant
    //Variable ww[4] = x1           //Xoffset
    //Variable ww[5] = A1            //amplitude
    //Variable ww[6] = s1            // sigma parameter that determines the shape
    //Variable ww[7] = T1           //exponential decay constant

    Variable xx                                      
    Variable w1=0, w2=0, w3=0, qq, ic                  // local variable
 
    // Body code
 
        for(ic=0;ic<2;ic+=1)
        w1 += exp(0.5*(ww[2+ic*4]/ww[3+ic*4])^2-(xx - ww[0+ic*4])/ww[3+ic*4])  
        w2 += erfc(0.707*(ww[2+ic*4]/ww[3+ic*4]-(xx - ww[0+ic*4])/ww[2+ic*4]))
        w3 += 0.5*ww[1+ic*4]/ww[3+ic*4]
        endfor
    qq = (w3*w1)*w2

    return qq
end


Assume your data is in a scaled wave called mySpectrum. Move to the folder that contains that wave. Here is a summary of the input to run this from the command line.

make/N=8/D/O wcoeff // this is the coefficient wave
wcoeff = {...} // provide initial guesses for coefficients ... read the manual to see how to do this
FuncFit FitTwoPeaks, wcoeff, mySpectrum /D


--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAH

TRK
Thank you Weimer for modifying the code. The coding worked fine after inserting ''//'' in the Variable xx since it appeared twice. However a small change in my fitting parameter brings a drastic change in my curve which did not make sense. Also the peak location and y value do not match. Keeping hold of the peak location (K0=2.05 and K4=2.25)entirely changes the shape of the curve. For illustration, I have attached the igor file that contains the fit. I checked if there was a mistake in my EMG equation but it was consistent with the standard one.
Since the coding did not allow me to play with the parameters, I decided to modify the EMG equation which I found in the help section of igor. I wanted to try with this because the built in Multipeak Fitting with EMG equation fits well my data points. However the problem is, while fitting it reads: "The fit function returned NaN for at least one value of x". Despite of spending many hours to solve this issue, I could not fix and once again I decided to post on this forum and get help.
In brief, how do I get rid of NaN values which appears in fitting while running the code below.
Thank you.
#pragma rtGlobals=3     // Use modern global access method and strict wave access.


Function FitTwoPeaks(ww, xx) : FitFunc 
    WAVE ww     //fitting parameters
        variable xx
 
    //Variable ww[0] = xo           //Xoffset, peak location
    //Variable ww[1] = w            //width
    //Variable ww[2] = A            // Amplitude
    //Variable ww[3] = To           //shape
       //Variable ww[4] = x1          //Xoffset, peak location
    //Variable ww[5] = w1            //width
    //Variable ww[6] = A1           // Amplitude
    //Variable ww[7] = T1           //shape
                                       
    Variable w1=0, w2=0, w3=0, qq, ic                  // local variable
 
    // Body code
 
        for(ic=0;ic<2;ic+=1)
        w1 += exp((0.5*(ww[1+ic*4]/ww[3+ic*4])^2+(ww[0+ic*4]-xx)/ww[3+ic*4]))
        w2 += erfc((0.707*(ww[3+ic*4])*(ww[0+ic*4]-xx)/ww[1+ic*4])+ww[1+ic*4]/ww[3+ic*4])
        w3 += 0.5*ww[2+ic*4]*(ww[1+ic*4]/(ww[3+ic*4]))
        endfor
    qq = w3*w1*w2
 
    return qq
end
Test4.pxp
In the experiment file you posted, I see two Multipeak Fit sets, and both give no problems when you click the Fit button. Please tell us how to reproduce the problem you are having with Multipeak Fit. If the EMG peak shape works for you, Multipeak Fit is probably the easiest way for you to proceed.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
johnweeks wrote:
In the experiment file you posted, I see two Multipeak Fit sets, and both give no problems when you click the Fit button. Please tell us how to reproduce the problem you are having with Multipeak Fit. If the EMG peak shape works for you, Multipeak Fit is probably the easiest way for you to proceed.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com

TRK
Hi John,
Multipeak Fit sets works fine but I wanted to use my code to fit the spectrum because later I wanted to run a code to see how the peak changes with time as I have the data in which the peak intensity changes with time.
Fitting with my own code has the problem. I selected, Analysis, Curve Fitting, FitTwoPeaks (function defined by me), Coefficients (wcoeff_0=2.05 in place of 2.14 and wcoeff_4=2.25 in place of 1.26) because 2.05 and 2.25 are the actual peak positions. Then I hit 'Do It'. Doing this, changes the shape of the curve. I have attached the file in which I have only the fit from the user defined function.
Thank you.
Tika
Test4 (1).pxp
My favorite technique for debugging such things is to put a test into the fit function and then break into the debugger when the test detects a bad number. So modify your function like this:
Function FitTwoPeaks(ww, xx) : FitFunc 
    WAVE ww     //fitting parameters
        variable xx
 
    //Variable ww[0] = xo           //Xoffset
    //Variable ww[1] = Ao            //amplitude
    //Variable ww[2] = so            // sigma parameter that determines the width
    //Variable ww[3] = To           //exponential decay constant
    //Variable ww[4] = x1           //Xoffset
    //Variable ww[5] = A1            //amplitude
    //Variable ww[6] = s1            // sigma parameter that determines the width
    //Variable ww[7] = T1           //exponential decay constant
 
    //Variable xx                                      
    Variable w1=0, w2=0, w3=0, qq, ic                  // local variable
 
    // Body code
 
        for(ic=0;ic<2;ic+=1)
        w1 += exp(0.5*(ww[2+ic*4]/ww[3+ic*4])^2-(xx - ww[0+ic*4])/ww[3+ic*4])  
        w2 += erfc(0.707*(ww[2+ic*4]/ww[3+ic*4]-(xx - ww[0+ic*4])/ww[2+ic*4]))
        w3 += 0.5*ww[1+ic*4]/ww[3+ic*4]
        endfor
    qq = (w3*w1)*w2
    if (numtype(qq))
        print "Oops"
    endif
 
    return qq
end

Now right-click in a procedure window and select Enable Debugger. Put a breakpoint on Print "Oops" and do the fit. When coefficients result in a return value that is NaN or Inf, you will break into the debugger. Now you can examine the coefficients and see what's happening.

When I did this, w1 was Inf. I didn't look at it in detail; my guess is that some coefficient got too big and the exp() function overflowed.

You will want to suppress the Curve Fit Progress window, as it may cause a lock-up condition with the debugger.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
johnweeks wrote:
My favorite technique for debugging such things is to put a test into the fit function and then break into the debugger when the test detects a bad number. So modify your function like this:
Function FitTwoPeaks(ww, xx) : FitFunc 
    WAVE ww     //fitting parameters
        variable xx
 
    //Variable ww[0] = xo           //Xoffset
    //Variable ww[1] = Ao            //amplitude
    //Variable ww[2] = so            // sigma parameter that determines the width
    //Variable ww[3] = To           //exponential decay constant
    //Variable ww[4] = x1           //Xoffset
    //Variable ww[5] = A1            //amplitude
    //Variable ww[6] = s1            // sigma parameter that determines the width
    //Variable ww[7] = T1           //exponential decay constant
 
    //Variable xx                                      
    Variable w1=0, w2=0, w3=0, qq, ic                  // local variable
 
    // Body code
 
        for(ic=0;ic<2;ic+=1)
        w1 += exp(0.5*(ww[2+ic*4]/ww[3+ic*4])^2-(xx - ww[0+ic*4])/ww[3+ic*4])  
        w2 += erfc(0.707*(ww[2+ic*4]/ww[3+ic*4]-(xx - ww[0+ic*4])/ww[2+ic*4]))
        w3 += 0.5*ww[1+ic*4]/ww[3+ic*4]
        endfor
    qq = (w3*w1)*w2
    if (numtype(qq))
        print "Oops"
    endif
 
    return qq
end

Now right-click in a procedure window and select Enable Debugger. Put a breakpoint on Print "Oops" and do the fit. When coefficients result in a return value that is NaN or Inf, you will break into the debugger. Now you can examine the coefficients and see what's happening.

When I did this, w1 was Inf. I didn't look at it in detail; my guess is that some coefficient got too big and the exp() function overflowed.

You will want to suppress the Curve Fit Progress window, as it may cause a lock-up condition with the debugger.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com

TRK
Thank you John. The problem is now fixed by lowering the parameter for the exponential term.