06-11-2018 12:34 PM
Hello friends,
I need to be able to generate analog & digital waveforms, create & configure a task, and write the generated waveforms to a cDAQ within 165ms. I am using the WriteMultiSample(bool autoStart, double[,] data) function for analog output. I am using the WriteWaveform(bool autoStart, DigitalWaveform[] data) function for digital output. I am finding that these write functions typically take around 150ms to execute (measured using the System.Stopwatch class). This is making it difficult for me to meet the 165ms requirement.
How might I improve the performance of writing data?
06-12-2018 05:36 PM
HI b!tmaster,
Are you ever specifying the sample clock rate or any other timing properties for your analog or digital output tasks? If so, how have you set up your timing properties?
06-12-2018 05:36 PM
Also, what hardware are you using?
06-12-2018 11:21 PM
Hey Adena,
I'll answer your second question first. The device I am using is a cDAQ-9174 with an analog output NI 9263 module and a NI 9401 digital I/O module.
As for your first question, I specify the sample clock rate and other timing properties when I create the NI tasks before I write any data to them. The following code includes the timing properties for my analog output task.
public void Configure() { if (_task != null) { _task.Dispose(); _task = null; } _task = new Task("AnalogOutputTask"); _task.AOChannels.CreateVoltageChannel(_hardwareInfo.AnalogOutputModuleName + "/ao0", "ao0", -10, 10, AOVoltageUnits.Volts); _task.AOChannels.CreateVoltageChannel(_hardwareInfo.AnalogOutputModuleName + "/ao1", "ao1", -10, 10, AOVoltageUnits.Volts); _task.Timing.ConfigureSampleClock("", _hardwareInfo.AnalogOutputSamplingRate, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples, AnalogOutputSamples.GetLength(1)); _task.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger("/" + _hardwareInfo.SecondDigitalIoModuleName + "/PFI0", DigitalEdgeStartTriggerEdge.Rising); _task.Control(TaskAction.Verify); _writer = new AnalogMultiChannelWriter(_task.Stream); _writer.WriteMultiSample(false, AnalogOutputSamples); }
The following code includes the timing properties for my digital output task.
public void Configure() { if (_task != null) { _task.Dispose(); _task = null; } _task = new Task("DigitalOutputTask"); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line1", "do1", ChannelLineGrouping.OneChannelForEachLine); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line2", "do2", ChannelLineGrouping.OneChannelForEachLine); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line3", "do3", ChannelLineGrouping.OneChannelForEachLine); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line4", "do4", ChannelLineGrouping.OneChannelForEachLine); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line5", "do5", ChannelLineGrouping.OneChannelForEachLine); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line6", "do6", ChannelLineGrouping.OneChannelForEachLine); _task.Timing.ConfigureSampleClock("/" + _hardwareInfo.DeviceName + "/ao/SampleClock", _hardwareInfo.AnalogOutputSamplingRate, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples, DigitalWaveforms[0].Samples.Count); _task.Control(TaskAction.Verify); _writer = new DigitalMultiChannelWriter(_task.Stream); _task.Control(TaskAction.Reserve); _writer.WriteWaveform(false, DigitalWaveforms); }
I am going to run some timing analysis and will follow up with the results.
06-13-2018 01:08 AM
Alright my timing analysis is complete and I would like to share the results. I decided to whip up 2 sample applications that isolate and execute the Config functions provided in my previous reply. I took some timing measurements by modifying each Config function and utilizing the system stopwatch. I broke the measurement into 2 independent parts to get any idea of how long it is taking to configure a task and how long it is taking the write functions to complete. Below is what the analog output Config function looked like after adding the stopwatch.
public void Configure() { var configStopwatch = new Stopwatch(); configStopwatch.Start(); if (_task != null) { _task.Dispose(); _task = null; } _task = new Task("AnalogOutputTask"); _task.AOChannels.CreateVoltageChannel(_hardwareInfo.AnalogOutputModuleName + "/ao0", "ao0", -10, 10, AOVoltageUnits.Volts); _task.AOChannels.CreateVoltageChannel(_hardwareInfo.AnalogOutputModuleName + "/ao1", "ao1", -10, 10, AOVoltageUnits.Volts); _task.Timing.ConfigureSampleClock("", _hardwareInfo.AnalogOutputSamplingRate, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples, AnalogOutputSamples.GetLength(1)); _task.Triggers.StartTrigger.ConfigureDigitalEdgeTrigger("/" + _hardwareInfo.SecondDigitalIoModuleName + "/PFI0", DigitalEdgeStartTriggerEdge.Rising); _task.Control(TaskAction.Verify); _writer = new AnalogMultiChannelWriter(_task.Stream); configStopwatch.Stop(); var writeStopwatch = new Stopwatch(); writeStopwatch.Start(); _writer.WriteMultiSample(false, AnalogOutputSamples); writeStopwatch.Stop(); Debug.WriteLine(configStopwatch.ElapsedMilliseconds + "\t" + writeStopwatch.ElapsedMilliseconds); }
It should be noted that AnalogOutputSamples was a 2 dimensional array of doubles where its first dimension is 2 (to represent to analog output channels) and its second dimension is 7000 samples in length. Below is what the digital output Config function looked like after adding the stopwatch. It should be noted that DigitalWaveforms was a single dimensional array of 6 DigitalWaveform objects, each with 7000 samples in them for the timing analysis.
public void Configure() { var configStopwatch = new Stopwatch(); configStopwatch.Start(); if (_task != null) { _task.Dispose(); _task = null; } _task = new Task("DigitalOutputTask"); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line1", "do1", ChannelLineGrouping.OneChannelForEachLine); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line2", "do2", ChannelLineGrouping.OneChannelForEachLine); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line3", "do3", ChannelLineGrouping.OneChannelForEachLine); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line4", "do4", ChannelLineGrouping.OneChannelForEachLine); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line5", "do5", ChannelLineGrouping.OneChannelForEachLine); _task.DOChannels.CreateChannel(_hardwareInfo.FirstDigitalIoModuleName + "/port0/line6", "do6", ChannelLineGrouping.OneChannelForEachLine); _task.Timing.ConfigureSampleClock("/" + _hardwareInfo.DeviceName + "/ao/SampleClock", _hardwareInfo.AnalogOutputSamplingRate, SampleClockActiveEdge.Rising, SampleQuantityMode.FiniteSamples, DigitalWaveforms[0].Samples.Count); _task.Control(TaskAction.Verify); _writer = new DigitalMultiChannelWriter(_task.Stream); _task.Control(TaskAction.Reserve); configStopwatch.Stop(); var writeStopwatch = new Stopwatch(); writeStopwatch.Start(); _writer.WriteWaveform(false, DigitalWaveforms); writeStopwatch.Stop(); Debug.WriteLine(configStopwatch.ElapsedMilliseconds + "\t" + writeStopwatch.ElapsedMilliseconds); }
Below are my timing analysis results.
To summarize these results...
I hope these findings provide some insight into anything I may be doing wrong or anything I can do to improve the performance of this code.