Time Resolved Experiments with Igor (DAQ): How to structure the source code
LausX
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
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.
November 28, 2013 at 06:13 pm - Permalink
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?
November 29, 2013 at 02:02 am - Permalink
November 29, 2013 at 03:30 am - Permalink
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.
November 29, 2013 at 03:45 am - Permalink
- 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.
November 29, 2013 at 04:53 am - Permalink
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,
November 29, 2013 at 09:53 am - Permalink