Time Resolved Experiments with Igor (DAQ): How to structure the source code

Dear All,

for a new time resolved (TR) experiment I have to program the software in Igor. Especially the DAQ part is completely new for me and I struggle already a while with this problem. But all my solutions are not satisfying me:

To record the time resolved data the program has to control one device by the Nidaq MX Tools and one by the GPIB2 and related commands.
For one complete TR-Experiment I thick I need at least two nested loops: the inner loops just record for a constant time delay the measured value every few milliseconds (averaging) and the outer loop sets the new time delay. Afterwards this could be extended to a third loop which loops over a to-do-list.
I tried to realize this with CtrlBackgroundTasks with and without Independent Modules but for both solutions Igor is completely busy and you cannot work with it anymore. In a first attempt I put both loops into the backgroundtask and for the second approach I tried just to use the backgroundtask for the averaging measurements (most inner loop) at constant delay time, after that close the backgroundtask put the new time delay position and start the backgroundtask again. But this is also not good and is maybe not the idea of backgroundtasks.

A third possibility could maybe a preemetive backgroundtask but this I couldn’t realize.

If this would be running than also I could use two other backgroundtask to check the laser and polarization.
I hope there are some guys which have experience with “fast” DAQ in Igor and have some good ideas.

Thanks

How is you experiment set up? For me it reads as if you try to do the timing of the experiment with help of the PC/Igor. Isn't there some external source which you could sync to?

Anyway, it is not intended to put code which needs a long time to execute (such as loops for averaging) into a background task, as you already have found out. Also, setting DAQ code up just as loops will lock up you program for a while. I think, there should be no necessity for loops within a background task generally. Averaging data or synching/updating time information can be easily carried over to the next cycle, i.e., you don't have to stall the background task for such things. Also, you don't have to stop and restart your tasks (not until you need user input or you want to stop the measurement), as modifications even to the task itself (changing delay etc.) can be done from within the task. As a background task will continue running and constantly execute with a set (but not extremely precise, as I heard) time delay in between, the approach should be to slice you problem into preparation, constantly acquiring data from / synching to the experiment (background task), and post processing. I have programmed DAQ-code for simultaneous use of multiple devices, but timing was not that critical (sub-seconds). I get the feeling that your problem goes already beyond that. How fast is "fast"? Do you really need to respond to something within milliseconds? That will be difficult. If it's just the data that comes in that fast, you could write to some buffer and do the rest later / slower.

Hi chozo,

Actually I build a time-resolved Moke (Magneto-Optic Kerr effect) setup. This experiment allows to measure the change of magnetization of a sample with time after heating by a laser pulse. In the static case a laser beam with a known polarization hits the sample and then measure the change of polarization with a photodiode (read out of a Lock-In).
For the time resolved setup the laser beam is divided in two beams, one is called the pump-and the other one the probe beam. Now with an optical delay line (just two moveable mirrors) you can change the path length of one of the beams and this gives you the delay time dt- both pulses will hit the sample at different times-
To measure a complete time resolved scan the delay time will be increased from dt = 0 to an arbitrary value, for example.
The laser beam itself is a pulsed beam with a repetition rate between some kHz and MHz, this means the width of one pulse is between some milliseconds down to some nanoseconds. But to reduce the noise in the measurement we use a photoelastic modulator (PEM) which operates with a frequency of 50 kHz or 100 kHz. This frequency is looked together with the averaged signal of the photodiode (the photodiode average already a lot of single laser pluses) and determines the time of one readout. Of course you could average already with the Lock-In but to see what’s going on it would be good to measure this averaged signal.
That means with Igor I have to set the new time delay (with Nidaq MX) and read the output of the Lock-In several times, set the new delay time and measure again.

Till now, I tried to slice the problem as you mentioned but still I put everything in the background task. I also tried to avoid the loops in the background task and use the task just for averaging but afterwards I thought I have to stop the task set the new delay time and start the task again. (I tried that the worker functions called by itself the stop function and also call the calling function again which will set the new delay time)
Maybe is a good idea two have at least two background tasks, one reads from a buffer with a low frequency and the other one reads with a frequency of one tick. But how to set the new delay in this sceme?
If you would'nt care about the aquisition frequency how would you avoid the loops or not to stop and restart the background tasks?
Your explanation is still unclear. From what I can gather, the high-frequency processing is done with down-conversion and the lock-in (the GPIB2 instrument?) and the NIDAQ does the rest (function unclear).

Here is one possibility: set up the NIDAQ to do its periodic task (e.g. a wave scan), and use a Tools MX end-of-scan hook function that will read the lock-in, and automatically return to the next scan. No Igor background tasks required.
OK, now I understand the intended use a bit better. 'Time-resolved' was a bit misleading without the information that a delay-line laser setup is used. This basically reduces the problem to a typical scanning- and acquisition-task, with the added difficulty of fast data read-out at each position. Which read-out frequency are you aiming for at a given step? I think anything beyond ~100 Hz is overkill (see also this thread: http://www.igorexchange.com/node/5434), and definitely your full 100 kHz is out of question. If you have some means to store individual read-out values somewhere (oscilloscope or something?) and just read the whole table at a much slower rate it would reduce the difficulty considerably. As you would still get the individual values into Igor this way, detailed analysis would be no problem. As for the program layout, I would take an approach like this:

Function Init
    - prepare things inside igor, like waves etc.
    - reset variables from a previous run
    - initialize equipment (e.g. move laser delay line to the start, maybe with some sleep() thrown in)
    - (give the user some feedback)
    - start background task
End

Function Background
    STRUCT backstruct - use to hold some run time parameters
    - initialize structure on the first run
   
    The rest is managed via conditions which are checked every cycle (e.g., if-else / switches):
    - formulate conditions for abort or end or measurement (e.g. delay line has moved x steps)
    (which stops the task and do some post-processing)
   
    - if there is data (GPIB?)
        - read the data and store it somewhere (maybe even in a run time variable for now)
        - this of course restricts data read-out speed to the timing of the background task
        (if you get the time-critical data-saving outsourced to somewhere, this is no problem
        and you can keep the refresh rate down to several ticks)
   
    - if for the current step enough time has elapsed (ticks) or upon some device has reacted (e.g. GPIB trigger)
        - move delay line to the next step (call Nidaq)
        - trigger next acquisition cycle
       
    - if no condition applies, just do nothing / return 0 (no need to stop anything)
    (the background task keeps running until something happens)
End

Function Postprocess (after all steps of a measurement have finished)
    - analyze / store or save / display the data
    - stop your equipment if necessary
    - (send a smiley to the user)
End


Note that I didn't write anything about loops in there. I use exactly zero loops in the whole acquisition part of my program.

Hope that helps.
Thanks chozo and s.r. chinn for your ideas. With your new inputs I found this solution:

Function DataAcqBackgroundTask(s)
    STRUCT WMBackgroundStruct &s
    Variable runNumber = getRunNumber()
    Variable maxRun = getTimeSteps()
    if (runNumber < maxRun)
        Variable avRunNumber = getAverageCycles()
        Variable maxAvRuns   = getMaxAverageCycles()
        if (avRunNumber <= maxAvRuns)
            setAV(enoise(1))
            setAVRunNumber()
        else
            updateLiveStream(runNumber, getAv()/maxAvRuns)
            clearAvRunNumber()
            clearAv()
            setRunNumber(runNumber+1)
            //setDelayLine()
        endif
    else
        DataAcqStopBackgroundTask()
        finishDataAcq()
    endif
    return 0
End


and the first testruns are very promisingly.

Thanks a lot,