04-17-2017 06:45 PM
I start a two channel analog input task with the code below. The only input parameter is the period [seconds] that I would like to monitor. I use settings between .2 seconds and .00001 seconds (20Hz - 10,000Hz). For most of these settings, starting and stopping the monitor task takes between 23-154 ms, which is quite acceptable for my purposes. However, for the one setting of .000133 seconds (7500Hz), the task takes more than 3 seconds to start and stop, which is unacceptable for my application. I am using the USB6343 DAQ which has a 500kSample (2us) max sampling rate. The math works out to 34 samples per channel at the problem setting and somewhere between 25-12,500 samples per channnel at the good settings. Any idea why it is so slow for this one case and not the others?
private static void StartOutputMonitor(double period /*seconds*/)
{
m_monitor = new Task();
m_monitor.AIChannels.CreateVoltageChannel(m_daq.AIPhysicalChannels[0], "monitorCurrent0",
AITerminalConfiguration.Differential, -10, 10, AIVoltageUnits.Volts);
m_monitor.AIChannels.CreateVoltageChannel(m_daq.AIPhysicalChannels[1], "monitorImpedance0",
AITerminalConfiguration.Differential, -10, 10, AIVoltageUnits.Volts);
var samplingRate = m_daq.AIMaximumMultiChannelRate / m_monitor.AIChannels.Count;
m_monitor.Timing.ConfigureSampleClock("", samplingRate, SampleClockActiveEdge.Falling,
SampleQuantityMode.FiniteSamples);
m_monitor.Timing.SamplesPerChannel = (int) Math.Round(period * samplingRate);
m_monitor.Control(TaskAction.Verify);
m_monitor.Start();
m_monitorReader = new AnalogMultiChannelReader(m_monitor.Stream)
{ SynchronizeCallbacks = false //allow waveform monitoring on a worker thread.};
m_waveformMonitorData = new double[m_monitor.AIChannels.Count, m_monitor.Timing.SamplesPerChannel];
m_monitorReader.BeginMemoryOptimizedReadMultiSample((int)m_monitor.Timing.SamplesPerChannel,
MonitorCallback, m_monitor, m_waveformMonitorData);
}
Solved! Go to Solution.
04-18-2017 03:17 PM
In order to clarify whether this is a problem with the device or the software, I would recommend using one of the shipping examples for analog inputs and test the device for the problem parameter of 7500Hz. Do you see the same behavior in this case?
04-18-2017 04:04 PM
I tried a couple of the examples and I don't see it. Since my code works fine for me at all but this one setting I am assuming it is an obscure interaction in the driver. There is a waveform generation task going on independently. The signal I am monitoring is a current amplifier output that is driven by the generated waveform.
Typical parameter values are amplitude = .5, pulsewidth = 40, frequency = 20-10000 (problem at 7500)
public static void StartSingleStim(double amplitude /*Volts*/, int frequency /*Herz*/,
double pulseWidth /*microseconds*/)
{
StopStim(); //cease all existing stimulation
var period = 1.0 / frequency; //desired period
m_stim = new Task();
m_gate = new Task();
m_frequency = new Task();
m_stim.AOChannels.CreateVoltageChannel(m_daq.AOPhysicalChannels[0], "stim0", -MaxOutputVoltage, MaxOutputVoltage, AOVoltageUnits.Volts);
m_stim.Control(TaskAction.Verify);
//to minimize timing error we need to make the pulse width an even multiple of the sampling clock time
var n = (int) Math.Floor(8000 * pulseWidth * 1e-6 / period);
//determine how many ticks are used to make the pulse width
//If necessary, decrease the sampling multiple to to stay below the DAQ's maximum sampling rate
var maxSamplingRate = m_daq.AIMaximumMultiChannelRate;
n = Math.Min(n, (int) Math.Floor(maxSamplingRate * pulseWidth * 1e-6));
var tickTime = pulseWidth * 1e-6 / n;
var samplingRate = 1 / tickTime;
m_stim.Timing.ConfigureSampleClock("", samplingRate, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples);
tickTime = 1 / m_stim.Timing.SampleClockRate;
var periodTicks = (int) Math.Round(period / tickTime);
period = periodTicks * tickTime; //actual period given hardware limitations
//DAQ can sometimes shutoff if the number of samples is too small. This problem is PC dependent, not DAQ dependent.
//For frequencies above 4kHz we will define two or three complete periods instead of one to increase the sample count.
var periodCount = (int) Math.Ceiling(.25e-3 / period);
var pulseTicks = (int) Math.Round(pulseWidth * 1e-6 / tickTime);
m_frequency.COChannels.CreatePulseChannelFrequency(m_daq.COPhysicalChannels[3], "stimFreq0", COPulseFrequencyUnits.Hertz,
COPulseIdleState.Low, 0, (double) frequency / periodCount, 0.5);
m_frequency.Control(TaskAction.Verify);
m_frequency.Timing.ConfigureImplicit(SampleQuantityMode.ContinuousSamples, 100);
var gapTicks = (periodTicks - 2 * pulseTicks) / 2;
var leftoverTicks = periodTicks - pulseTicks * 2 - gapTicks - 3;
var waveform = new double[periodTicks * periodCount - leftoverTicks];
var i = 0;
for (var cycle = 0; cycle < periodCount; cycle++)
{
for (var tick = 0; tick < pulseTicks; tick++)
waveform[i++] = -amplitude;
for (var tick = 0; tick < gapTicks; tick++)
waveform[i++] = 0.0;
for (var tick = 0; tick < pulseTicks; tick++)
waveform[i++] = amplitude;
while (i % periodTicks != 0 && i < waveform.Length)
waveform[i++] = 0.0;
}
var writer = new AnalogSingleChannelWriter(m_stim.Stream);
writer.WriteMultiSample(false, waveform);
m_stim.Timing.SampleQuantityMode = SampleQuantityMode.FiniteSamples;
m_stim.Timing.SamplesPerChannel = waveform.Length;
m_stim.Triggers.StartTrigger.Type = StartTriggerType.DigitalEdge;
m_stim.Triggers.StartTrigger.Retriggerable = true;
m_stim.Triggers.StartTrigger.DigitalEdge.Edge = DigitalEdgeStartTriggerEdge.Rising;
m_stim.Triggers.StartTrigger.DigitalEdge.Source = "/" + m_frequency.COChannels[0].PhysicalName + "InternalOutput";
m_stim.Control(TaskAction.Verify);
m_stim.Start();
m_frequency.Start();
StartOutputMonitor(period);
}
04-20-2017 03:43 PM
Would it make a difference to commit the task to start and commit to stop? Perhaps allocating memory to the task will help.
04-21-2017 11:52 AM
What seems to happen is that the commit takes about 2/3 of the time and the remaining third is taken by the start, but overall it is the same length of time to start the task. As far as using commit to stop, that is not allowed while the task is running.
04-21-2017 05:48 PM
I found a workaround! We have known that if the output buffer is too small the stimulation can arbitrarily shutoff. I increased my minimum output buffer size from 250ms worth of samples to 330 ms worth of samples and everything works fine. So, the problems with the analog input seems to have been some sort of bizarre interaction with the monitoring and whatever bugginess h happens when the output buffer is too small.