From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

Analog Outputs with different timescales

Solved!
Go to solution

I am using the AO  outputs of a PCI-6731 card for a raster scanning head application and I am having some difficulty reaching the peak performance I need. I am contolling the card with the nidaqmx drivers in c++

 

Basically one output controls scanning in the Y direction (which is a scanline and is very rapid), and the other in the X (increment once per scanline, therefore much slower). The complication is that both outputs start on an external trigger, because the positioning is synchronized to a separate data acquisition card.

 

Right now what I do is:

- write the scanline waveform to output 0

- set output 1 to a given position

- tell card to output on next trigger

- pend on completion and stop the tasks

 

What I really want to do is just tell it to start and on every external trigger have the output 0 scanline waveform output and output 1 increment to the next position. This way I could do a full 2D scan with minimal software control.

 

Any ideas on how I could best accomplish that? From my understanding of the nidaqmx drivers I don't see an elegant way to do it.

 

I could potentially do some operations on the done callback, although this makes me a bit nervous because the control PC is running windows, it is by no means a real time operating system.

0 Kudos
Message 1 of 13
(5,497 Views)

I would do it like this:

 

1.  Pre-define the output values for both channels and write them to the buffer of a single AO task (I wrote a routine in LabVIEW a while back that generates the array in case it helps you, here is an example of how you might use it with a DAQmx task).

 

2.  Create a retriggerable finite counter output task at the desired rate that generates N pulses where N is the number of output samples per line.

 

3.  Use the counter's internal output as the sample clock for the AO task. Start the AO Task before the counter.  Trigger the counter from your external signal.

 

 

On each trigger signal, the counter will output N pulses which will write the next N samples of your AO buffer.  The buffer needs to be created so that N samples corresponds to a full scan on output 0 and that output 1 will increment every N samples.

 

If you do it this way, no software interaction will be required at all once the tasks have been started.

 

 

Best Regards,

John Passiak
0 Kudos
Message 2 of 13
(5,490 Views)

Hi John,

 

My only concern with that approach is the size of the buffers.

My output scanline might have something on the order of 16,000+ samples (let's call this direction y)

The slower moving output (let's call it x) will have around 512 samples. 

 

So if I have to duplicate the samples per buffer that's 512 x 16000^2 samples. If that's the only way I might have to look into having less sampling points (e.g. a rougher output wave).

0 Kudos
Message 3 of 13
(5,488 Views)

 So if I have to duplicate the samples per buffer that's 512 x 16000^2 samples. If that's the only way I might have to look into having less sampling points (e.g. a rougher output wave).


It shouldn't be 16000^2 unless I'm missing something.

 

512 * 16000 * 2 channels * 2 bytes / sample = ~32MB

 

I wouldn't think that amount of memory should cause any issues.  If you wanted to minimize memory usage you could configure non-regeneraiton on the AO task and generate/write the buffer in smaller chunks, but I wouldn't bother unless you encounter problems writing it all at once.

 

 

 

Unfortunately you cannot output two channels at different hardware-timed rates on a single 6731.  Using only one hardware-timed channel might look something like this...

 

Configure just the fast channel to be buffered (using the same retriggerable counter idea I mentioned above to reduce overhead between lines).  The buffer size would only have to be 16000 samples.  

 

Use the Every N Samples callback (N=16000) to determine when to write the slow channel (make sure to start the output task during the initialization routine so it only has to be done once).

 

My concern is that this still requires a software call and the slow channel could potentially lag behind the fast channel.  If there is some delay between lines then perhaps you can get by with doing this.

 

 

 

As a final alternative, if you have a second DAQ card, you could have one card run the fast task and one run the slow.

 

 

 

Best Regards,

John Passiak
0 Kudos
Message 4 of 13
(5,478 Views)

Yes, you're absolutely right.

 

I will give this some thought, it seems like the best way to go.

 

Out of curiousity, we're still in a phase of the project where we can change the analog output card we're using ... do you think there is a better option out there that makes it a bit easier to do this task?

0 Kudos
Message 5 of 13
(5,439 Views)

@peter_k_coder wrote:

 

Out of curiousity, we're still in a phase of the project where we can change the analog output card we're using ... do you think there is a better option out there that makes it a bit easier to do this task?


No I don't really think so, all of NI's DAQ hardware that I'm aware of only has a single timing engine for analog output.  Even if you could add a second card, you would still have to synchronize them.  I think it would be easiest to write all of the data to the single card (even if you have to do it in "chunks" to reduce memory usage).

 

 

Best Regards,

John Passiak
0 Kudos
Message 6 of 13
(5,435 Views)

I tried the above approach. After muddling through the documentation and available examples I thought I had figured it out however I unfortunately do not get a signal out of the AO channels. No errors and everything executes, but unfortunately no output signal either! Any pointers would be appreciated!

 

DAQmxCreateTask("task1", &_taskHandleA1);
DAQmxCreateCOPulseChanTicks(_taskHandleA1, "Dev3/ctr0", "", "20MHzTimebase", DAQmx_Val_Low, 0, 2, 2);
DAQmxCfgImplicitTiming(_taskHandleA1, DAQmx_Val_FiniteSamps, 1000);

DAQmxCfgDigEdgeStartTrig(_taskHandleA1, TRIGGER_INPUT, DAQmx_Val_Rising);
DAQmxSetStartTrigRetriggerable(_taskHandleA1, 1);

DAQmxCreateTask("task0", &_taskHandleA0);

DAQmxCreateAOVoltageChan(_taskHandleA0,
		_chan0Name,
		"",
		-2.0,
		2.0,
		DAQmx_Val_Volts,
		NULL);

DAQmxCreateAOVoltageChan(_taskHandleA0,
		_chan1Name,
		"",
		-2.0,
		2.0,
		DAQmx_Val_Volts, NULL);

const int numSamples = 1024;

DAQmxCfgSampClkTiming(_taskHandleA0, "/Dev3/Ctr0InternalOutput", AO_CLK_RATE,
		DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, numSamples);
	
float64 buffer[2048];
float64 voltageStep = 2.0 / (1024.0);
for (int i = 0; i < 1024; i++)
{
	buffer[i] = i * voltageStep;
	buffer[i + 1024] = i * voltageStep;
}

DAQmxWriteAnalogF64(_taskHandleA0, 1024, 0, 10.0,
		DAQmx_Val_GroupByChannel, buffer, NULL, NULL);

// start tasks
DAQmxStartTask(_taskHandleA0);
DAQmxStartTask(_taskHandleA1);
0 Kudos
Message 7 of 13
(5,411 Views)
Solution
Accepted by topic author peter_k_coder

Hmm I'm not sure exactly but there are a couple things (it's close though)...

 

The counter output frequency in your example is 5 MHz (20 MHz, 2 ticks high, 2 ticks low), which is faster than the 6731 supports for a sample clock.  I thought this would have given a hardware error... are you checking for errors once the task is running (e.g. using DAQmxIsTaskDone)?.  There is a DAQmxCreateCOPulseChanFreq if you would like to set the clock rate directly (it will use the appropriate internal timebase by default).

 

The counter task is generating 1000 pulses per trigger, this is what determines the number of samples generated per trigger (I'm assuming you want it to be 1024 aka "numSamples").

 

The analog output task should either use:

 

1)  Continuous timing if the output will repeat indefinitely as more triggers are acquired.

2)  Finite timing with (N * numSamples) samples where N is the number of lines you wish to output and numSamples is the number of samples per line.  In this case the task will complete once the N lines have been triggered.

 

 

Best Regards,

John Passiak
0 Kudos
Message 8 of 13
(5,407 Views)

Great, thanks, I got it to work. The trick was to use DAQmxCreateCOPulseChanFreq instead of the Ticks function. I tried Ticks with a slower timebase but it still didn't work, so there must be some subtlety there. Anyways, the frequency output works well enough for my needs. Thanks for your help!

0 Kudos
Message 9 of 13
(5,372 Views)

Hi John

Thanks for the this, it works well. What would be the simplest way to output a digital pulse when the slow axis changes value?

I need a digital output to synch my data acquisition card to capture at the start of each succesive line of the scan. 

Thanks.

Best regards,

Ameeth

0 Kudos
Message 10 of 13
(4,602 Views)