11-19-2021 10:28 AM
Hi everyone,
When I write a finite train of analog pulses, the WaitUntilDone() function goes through without stop, leaves partial generated pulses. If I call Thread.Sleep and wait for the time length equal to the pulse train, everything works out. I know it is not the best practice and is flaw by its nature, so I want to know how to use WaitUntilDone() correctly (or just get things right).
class StimulationPulses
{
public static double[] pulses = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 }; // 200Hz pulses, 1ms each, 25ms in total
public double[] generatePulses(double factor)
{
double[] generatedPulses = new double[pulses.Length];
for (int i = 0; i < pulses.Length; i++)
{
generatedPulses[i] = factor * pulses[i];
}
return generatedPulses;
}
}
[Serializable]
class StimulationControlFrame
{
public double normalised_current_level;
public void ApplyControlData(AnalogSingleChannelWriter writer, Task outTask)
{
StimulationPulses pulseSignalGenerator = new StimulationPulses();
writer.WriteMultiSample(false, pulseSignalGenerator.generatePulses(normalised_current_level));
outTask.Start();
Thread.Sleep(StimulationPulses.pulses.Length); // without this sleeping stmt, pulses usually generated partially
outTask.WaitUntilDone();
outTask.Stop();
}
}
the above is the code I am using, let me know if you want to know other part of the code (e.g. channel setup etc.)
11-19-2021 10:36 AM
We definitely need the rest of the code, because we are missing the crucial part of the code - how you configure the DAQmx task
11-19-2021 10:44 AM
Thank you for the prompt reply.
Channel setup:
/* Analog Out Channel setup */
_analogOutTask = new Task();
// Create a virtual channel
_analogOutTask.AOChannels.CreateVoltageChannel(
"Dev1/ao0",
"StimulationOutput",
Convert.ToDouble(-outputChannelMaxVolt),
Convert.ToDouble(outputChannelMaxVolt),
AOVoltageUnits.Volts);
// Configure the sample clock
_analogOutTask.Timing.ConfigureSampleClock(
String.Empty, /* means the internal clock */
sampleRate,
SampleClockActiveEdge.Rising,
SampleQuantityMode.FiniteSamples, StimulationPulses.pulses.Length);
// Verify the task
_analogOutTask.Control(TaskAction.Verify);
// Create the writer
_analogOutWriter = new AnalogSingleChannelWriter(_analogOutTask.Stream);
_analogOutWriter is then passed to StimulationControlFrame.ApplyControlData through:
controlFrame.ApplyControlData(_analogOutWriter, _analogOutTask);
Sometimes, when the pulses generated partially and is on the high voltage, it just stay there instead of returning to zero. I guess I need to modify Idle state configuration, but I can't find reference on how to do it correctly at this point.
11-19-2021 11:04 AM
Few things to ensure,
11-22-2021 08:45 AM
Thank you for the reply.
1. I have double checked it matches the sample size I generated (25 samples in total).
2. sampleRate is set to 1000, it is because I am repeating 1, 0, 0, 0, 0 pattern. So that is 200Hz pulses with sample rate being 1000 per second.
3. By reading back Task.Timing.SampleClockRate property, it is set to 1000. Everything makes sense except the Task thinks itself done earlier than actual IO completion. I added debug output in comments:
class StimulationPulses
{
public static double[] pulses = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 }; // 25 samples
public double[] generatePulses(double factor)
{
double[] generatedPulses = new double[pulses.Length];
for (int i = 0; i < pulses.Length; i++)
{
generatedPulses[i] = factor * pulses[i];
}
return generatedPulses;
}
}
[Serializable]
class StimulationControlFrame
{
public double normalised_current_level;
public void ApplyControlData(AnalogSingleChannelWriter writer, Task outTask)
{
StimulationPulses pulseSignalGenerator = new StimulationPulses();
Console.WriteLine(outTask.Timing.SampleClockRate.ToString()); // Print 1000
Console.WriteLine(outTask.Timing.SamplesPerChannel.ToString()); // Print 25
Console.WriteLine(outTask.IsDone.ToString()); // Print True
Console.WriteLine(pulseSignalGenerator.generatePulses(normalised_current_level).Length.ToString()); // Print 25
writer.WriteMultiSample(false, pulseSignalGenerator.generatePulses(normalised_current_level)); // 25 samples
outTask.Start();
Console.WriteLine(outTask.IsDone.ToString()); // Can print both False or True
// Thread.Sleep(StimulationPulses.pulses.Length); Without this command, incomplete pulse generation happens
outTask.WaitUntilDone();
Console.WriteLine(outTask.IsDone.ToString()); // Print True
outTask.Stop();
}
}
The model we are using is USB-6212 BNC version.
4. Yes, we have 0s in the end as the pattern is 1, 0, 0, 0, 0. The problem is when it happens to be stopped at 1's samples, it retains 1 Volts, which is a huge safety problem. I am thinking to use an ad-hoc solution by writing another 0 to avoid any dangerous things from happening.
11-25-2021 11:16 AM
Anyone else have any comments or reminders to bring up? Would be much appreciated. Otherwise I am going to open a bug report case with NI.