Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

speed limitations of periodic finite-sample output generation

I'm a biomedical engineering Masters student at the University of Alberta in Canada. I'm working on a project involving electrical stimulation for medical applications.

I've been trying to use Visual C++ (DAQmx functions) to program a NI-6723 32-channel analog output board to generate 16 channels of periodic voltage outputs. My required output waveform is a 300usec biphasic pulse with a repetition period of 20msec. I would like to have pulse width resolution of 20uSec so I've selected an output rate of 50kHz. My 16 channels generate interleaved pulses with 1msec between sequential channels resulting in 800 samples/channel and a bufferlength of 800x16.

The problem is: I need to be able to modulate the pulse amplitude during the inter-pulse interval so I can't use a continuous task (from what I understand). I've been using a 50Hz signal as a trigger for a finite-sample multichannel task. I'm finding that the overhead time required to write/start/stop the task every cycle is greater than the desired time between my pulses. The maximum rate that I've been able to drive my trigger and still generate a pulse on every rising edge is 22Hz (~45msec). Under other conditions I've been able to update every 30msec and was wondering if this is a limitation of the driver. I'm really hoping that there's some way around this problem. Maybe I'm going about it all wrong using a trigger signal but found it provided the most consistent timing.

I've also trying splitting my channels into two groups, one triggering off the rising edge and one off the falling edge in an effort to use a shorter buffer to reduce the task runtime. I needed to generate two tasks operating through individual program threads to do this but was only able to generate pulses through a single thread at a time. I suppose this is because I was trying to access already busy board resources multiple times.
Here's the code I'm using to generate my pulses

err= DAQmxCreateTask("",&taskHandle);
err= DAQmxCreateAOVoltageChan(taskHandle,"Dev2/ao1","",-10,10,DAQmx_Val_Volts, NULL);
err= DAQmxCfgSampClkTiming(taskHandle,"",rate,DAQmx_Val_Rising,DAQmx_Val_FiniteSamps,numSamples);
err= DAQmxCfgDigEdgeStartTrig(taskHandle, "/Dev2/PFI4",DAQmx_Val_Falling);

while(programRunning){
err= DAQmxWriteAnalogF64(taskHandle,numSamples,0,10.0,DAQmx_Val_GroupByChannel,data2,&written,NULL);
err= DAQmxStartTask(taskHandle));
err= DAQmxWaitUntilTaskDone(taskHandle,10.0);
err= DAQmxStopTask(taskHandle);
}

I'd really appreciate any comments or suggestions!!
Thanks,
Lisa
0 Kudos
Message 1 of 2
(2,746 Views)
It sounds like your best bet will be to use a continuous task and turn off regeneration of data from the buffer. With regeneration turned off, you aren't allowed to generate the same point in the buffer twice without writing to that point in the buffer again. I would also make your buffer 1000x16 to cover the full 20 milliseconds and just extend the last 200 points of each channel to be the same as your 800th point. With this strategy, you will write your first 20 milliseconds of data, start the task, and then continue to write to the buffer during each 20 millisecond interval to update the pulse amplitude of each waveform as appropriate. If you fail to write new data before it gets transferred to the device a second time, you will receive an error. This will tell you whether your application is keeping up or not. If you know the waveforms you want to generate well ahead of time, you can increase your buffer size and write multiple sets of waveforms before starting. This may give your application a little more breathing room if you're having trouble keeping up. If you're computing your waveform on the fly, then you'll probably have to be content with the 1000x16 buffer and hope you can keep up. Also, with this setup, you may decide you no longer need a start trigger. Some pseudo-code illustrating this concept is shown below:

err= DAQmxCreateTask("",&taskHandle);
err= DAQmxCreateAOVoltageChan(taskHandle,"Dev2/ao1","",-10,10,DAQmx_Val_Volts, NULL);
err= DAQmxCfgSampClkTiming(taskHandle,"",rate,DAQmx_Val_Rising,DAQmx_Val_ContSamps,numSamples);
err= DAQmxCfgDigEdgeStartTrig(taskHandle, "/Dev2/PFI4",DAQmx_Val_Falling);
err= DAQmxSetWriteRegenMode(taskHandle, DAQmx_Val_DoNotAllowRegen);
err= DAQmxWriteAnalogF64(taskHandle,numSamples,0,10.0,DAQmx_Val_GroupByChannel,data2,&written,NULL);
err= DAQmxStartTask(taskHandle));


while(programRunning){
//update value of data2 variable here as appropriate
err= DAQmxWriteAnalogF64(taskHandle,numSamples,0,10.0,DAQmx_Val_GroupByChannel,data2,&written,NULL);
}

err= DAQmxStopTask(taskHandle);


I hope this helps. Good luck!
Message 2 of 2
(2,746 Views)