LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Is it possible to generate a finite number of output buffer iterations using DAQmx?

Sal, like I said in my above post those properties do not work once you have stopped the DAQmx Task. The only time those work is while the task is actively outputting the waveform. Once you stop the output in a given location those properties default to incorrect values. Please read my above response about last time you suggested this.
-Devin
I got 99 problems but 8.6 ain't one.
0 Kudos
Message 11 of 23
(3,405 Views)
Hi Billings,

Check out my attached example. It performes non-regenerated analog output and monitors the samples per channel generated. When you stop the output, the property node that gives you the write position still works. The wait is to allow the AO to continue writing before the task is stopped. You will see that the second property node still gets values.

-Sal
0 Kudos
Message 12 of 23
(3,390 Views)
Attached example.

-Sal
0 Kudos
Message 13 of 23
(3,390 Views)
I thank you for your response, but I am getting frustrated here. Perhaps no one understands my problem.

I do not need a generic NI example. This vi does not work to solve my problem. Has anyone tried this vi? It is straight out of the examples directory. I am an experienced developer. This is not a "How do you use DAQmx" thread.

I contacted an NI engineer and he gave me the same canned response with an generic example, which only proves he never actually hooked this up on a DAQ card and monitored the DAC output on a scope. These vi's DO NOT work. It seems that DAQmx has a major lack of functionality that traditional DAQ handled simply. If we can ever figure out how to get this done in DAQmx it will definitely take a complicated program with its own execution thread.

Run this vi. The "Total Samples Generated" returns the same thing outside of the while loop as it does inside the while loop, even though some time has passed. During this time the DAQ card output numerous samples. So how can the two property nodes give you the same number? The answer is that the property nodes are only updated when the property node is called while the task is running. Once you stop the DAQ, the property node is stuck at whatever its value was the last time it was used while the task was running. I have tried this while monitoring the output of my DAQ on a scope. The final value when the vi is stopped is different every time, a "random" point in the buffer that is NOT the point given by the property node. The property node is wrong.

If you turn regeneration off and look at the property node after a DAQmx Stop command, its values reset completely once you stop the task. Also with regeneration off if, when the stop button is pressed, you give it a "wait until task done" command in the while loop it will cause an error -200290 when it gets to the end of the buffer. If you allow regeneration, any wait until done vi's will wait indefinitely so they cannot be used. The property node will show total samples generated = buffer size, but the by probing the voltage you will see that the output is stopped in the middle of the buffer, not at the end.

Please take a look at these vi's. Hook a DAQ output up to a voltmeter or oscilloscope. When you stop the vi, check the output. It's value does not match the index the property node indicates.
-Devin
I got 99 problems but 8.6 ain't one.
0 Kudos
Message 14 of 23
(3,378 Views)
billings11,

I hope that I have understood your problem correctly and can shed some light on this issue for you. Since you have a pre-defined amount of data that needs to be written, you should almost certainly use a finite acquisition. In this mode, your DAQ board will count the number of times it has updated its AO channels, and stop after a pre-programmed number of updates. This is what Traditional DAQ does when you define some number of buffer iterations. In this case, Traditional DAQ uses the buffer size and the number of iterations to determine the finite generation length. It is certainly possible to do this in DAQmx, however the finite generation size is always expressed as a number of samples to generate, rather than in terms of iterations on a buffer. What that means is that you will need to make this calculation (buffer size * number of iterations) and set that on the DAQmx Timing VI (ensure that the sample mode is set to finite). If you do this, you should see your DAQmx application work just like your traditional application.

I have attached a quick example that demonstrates this. If I have misunderstood the problem, please let me know, and I'll take another crack at it.

I hope this helps,
Dan
0 Kudos
Message 15 of 23
(3,369 Views)
billings11,

Here's a slight tweak to a prior example. I've added a counter task that counts edges of the AO sample clock. It continues to count the cycles that the other methods miss so you can use its final value to determine where your waveform left off. I've tested it successfully on an E-series board.

(I'm assuming at this point that you aren't able to pre-determine the total # of output samples needed or else you would just perform a finite generation rather than continuous.)

-Kevin P.

Message Edited by Kevin Price on 03-17-2005 08:50 AM

ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 16 of 23
(3,364 Views)
Thanks Kevin,
 
Thank you for your help.  I originally had two problems, one of which has been solved.  I can now generate a defined number of "buffer iterations" by generating finite samples.  Now my other problem is when I don't know how many buffer iterations I need to generate.  This is what you addressed in your last post.
 
Your vi does work nicely, but to tell you the truth I can't use it.  Only one problem, I cant use the counter to do that because its already being used for something else.
 
My application is not that different from a multichannel function generator like you would use in a lab.  I want to configure a waveform and run it indefinitely until some time later when I am done using it.  My counters are already being used to provide pulse triggers for external devices, like a digital oscilloscope.  One is used to provide a periodic sync pulse that the scope triggers on.  The other is used to provide basically an on/off signal for a laser.  What I have is a laser marking prototyping system for use in a lab, so I am commanding servo motors that angle mirrors with my analog outputs, then I need to tell the laser when to turn on and off, and I need to trigger measurement equipment like my scope to acquire data.  I am also using many analog inputs on the DAQ card to aqcuire many signals.  The idea is to configure a new laser marking system with careful observation of things like power dissipation, motor coil voltages, optical position vs commanded position vs detected position, etc.
 
Neat huh?  I can draw all kinds of letters and pictures on the wall, all generated in labview.  The problem is I can't dedicate ctr0 because I am using it with a BNC-2110 connector box to have a nice BNC trigger line to my scope.
 
I can't use ctr1 because it is being used to enable and disable my laser by generating pulses with defined widths sychronized with my analog output.
 
I can't ever jump from, say, 4V output to a 0V output on my analog outputs.  This is because the servos will try to rotate the motors with this extremely high acceleration to keep up with this jump in the signal.  They will saturate the driving amplifiers and the system will go unstable, slamming the motors around.  So when I stop my waveform sometime in the future, I need to figure out where I stopped and build I nice smooth structured ramp back to zero.  Anyone know of a way to stop continuous generation and know where you stopped before using DAQmx Stop.vi?
 
If you use the express vi to generate a continuous waveform, wait N seconds, then get a BuffWritePos property immediately before and after a DAQmx Stop.vi you will see the problem.  Check your real output with a meter after you stopped.  It won't match either number.  You probably already have seen this.
 
The only solution I have come up with is using T connectors to wrap each AO back to an AI.  So I have to waste 2 of my precious AI's just to tell where my output stopped on my 2 AOs.  (The AOs have the same buffer length and sample rate but have different shape waveforms.)  This is wasteful.  Obviously the DAQ card has the ability to know where it is in the buffer.  Why doesn't it tell me where it is after it has stopped the task?  I know how many points are in the buffer, so that doesn't tell me anything!  The principle of having to use extra hardware to tell me what I should already know is very unsatisfying.  Think about it, you have a DAC, you ought to know what you are telling it to output.  You have a buffer of digital data feeding the DAC, you ought to know what index you are aiming at in the buffer.  I sort of assumed this when I created the bill of materials for this project.  If I am ever to get this thing to have all the functionality it was supposed to I have to buy extra hardware now.  And I have to deliver 6 of these things.  The truth is I have just had to remove some of the original design functionality because DAQmx can't tell me what it is outputting.

Message Edited by billings11 on 09-09-2005 09:22 AM

-Devin
I got 99 problems but 8.6 ain't one.
0 Kudos
Message 17 of 23
(3,256 Views)

Yeah, that sounds like a pretty neat app.  I don't think I've investigated all the quirks & frustrations of those AO properties such as BuffWritePos (and others) nearly as thoroughly as you have -- I gave up sooner! .Smiley Wink  I also noticed that I couldn't count on the values reported back by similar DAQmx properties.  Fortunately I had simpler apps with reasonable workarounds.  Anyway, I agree with your frustration on this issue -- there absolutely should be a reliable way to determine where within an AO buffer a task "left off" when it's stopped midstream.   I recall putting my hopes in a property with a name similar to TotalSamplesGenerated.  It often looked like it worked pretty accurately, but as I recall there were circumstances where it would just revert to 0 and stay there.  I'm sure that any experimentation was with DAQmx 7.3 or earlier, so maybe this has improved now?

Unfortunately I'm not at hw now, but have you explored for any other deep-down DAQmx properties?  For example, wouldn't it also make sense to be able to query an AO output task to determine the raw I16 value sitting in the D/A register?  I quite doubt that such a property has actually been exposed though...

I wanted to point you to another thread I got into which might possibly (?) be of some use.  Here's the thread for some context:
 
Most important, here's the link offering up official info from NI that was referenced at the end of the thread:
 
The working idea is that you would write a ramping-down signal to your buffer at some point that's many samples in the future, then just let your waveforms continue outputting until they reach that ramping-down data.
 
 
One last thought that would be a significantly different approach.  Have you played around with the timed loops much?  Especially using a data acq hw timing source?  I've only worked up one little example, but the timed loop structure may hold some promise for you.  Timed loops execute at a very high priority level, so you want to have a minimal amount of "thinking" in them.  Here's an outline of an idea:
 
1. Configure for your AO DAC clock to be the timing source for your timed loop.
2. Pre-define your full AO waveforms but only pass down a small "initialization" chunk with DAQmx Write.  Feed these waveform wires into the timed loop.
3. Configure your timed loop to execute once every n AO outputs.  n should represent some modest time interval, say 25-100 msec worth of time.   Inside the timed loop, you'll pass down the next n values with DAQmx Write.   (Some error-checking and correction should be done here.  If the timed loops starts 2 cycles late, then write n+2 values, etc.)
4. When the outputs need to be stopped gracefully, you could write a ramped-down version of the next n values with DAQmx Write.  Actually, you might better write a half-buffer worth and bring them all the way to 0 volts.  Then within that same iteration of the timed loop, you set the new period for the timed loop equal to this half-buffer number.
 
This method will continually feed small chunks of data to the AO buffer, just a little bit ahead of the DAC clock.  When it's time to turn off the AO outputs gently, you simply feed ramped-down chunks.  The DAC will start generating those ramped-down chunks very soon after you've fed them to the buffer.
 
Not as straightforward as the method you've already tried that should have worked, but maybe some light at the end of the tunnel?  Again, I haven't really explored the timed loop a lot, but I was reasonably impressed with it in the little bit of monkeying around I tried.
 
-Kevin P.
 
ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 18 of 23
(3,239 Views)

I am glad to see you agree with me.  It is a very important issue, and I wish NI could do something about it soon.

I am using 7.3 now.  I can say at this point I've dug through all kinds of DAQmx properties and I can't find anything useful.  You are right, I am sure the functions to tell the actual buffer position are there, they just haven't brought them out to the labview level so we can use them.  Why not?  Certainly the property CurrWritePos should tell me the current write position whether the task is stopped or not.  I think it is some kind of flaw in implementation where the functions to get the write position are buried within a loop that is only running when the buffer is iterating.  So when you stop iterating the buffer you can't update those values anymore.  Seems like sort of a big flaw.  So the only way is to find ways of iterating the buffer once at a time by running a labview level timed while loop and updating the buffer data.   The functionality to have the card iterate its own buffer is rendered useless.

I read your suggestions and I think they do have potential as workarounds for this problem.  I suppose I have a more complicated application than usual, so I am not sure if it would be safe to use these methods or not.  I think it is worth a try, but since development time is sort of scarce for me at this point I'm not sure if I will just have to cut my functionality short.  I do think your method with the timed loop makes good sense and would work for at least some of the waveforms I am generating.

On problem is I need to generate sample rates of 1Mhz, and periodic waveforms of up to 2kHz.  I generally store exactly one period of the waveform in the buffer, and then generate continuously.  This means I can start the task from inside a state machine in labview, and then I don't have to continuously run a labview vi to keep loading new data into the buffer.  While I think your idea would definitely work for slower waveforms in my case a buffer could be completely generated in 500us, so I don't think I can keep ahead of it in a timed loop.  This isn't always the case, typically I would be running closer to 400 Hz perhaps, but I have to have the capability to generate both high speed stuff and medium speed stuff the same way.  Maybe I could load much larger buffers with several periods of the waveform.  This means I have much more data to hold in memory, and the program would be far more complicated to run your algorithm with the timed loop, but I think it could work if I put enough time into it. 

The other problem is I can't guarantee that the computer is going to keep its resources free enough to keep the timed loop running right.  At the same time I am doing this generation I am doing a ton of acquisition and data processing which can all be changed on the fly through a GUI.  It is sort of a test workbench application where a user is interacting with the software all the time.  I might all of a sudden start doing FFTs on a couple of channels of acquired data.  I am not sure where this would leave me with continuity in my generation.  Also it is a pain to have to keep an execution thread in a vi like yours when you should be able to just tell the thing to go continuous let the card run on its own.  But I guess sometimes you have to do what you have to do.  If it works for me I will be sure to post to let you know.

I will still look into the solutions you suggested.  I can see why you gave up on this issue.  I just think my particular application makes it a major issue for me and it is very difficult for me to swallow what I consider to be a MAJOR flaw in DAQmx waveform generation.  It essentially means there is no way I would ever try to do motion control or any other sensitive analog device control from an NI DAQ card again.  If I had it to do again I would still use labview for the software, but I would use something else than DAQmx with more powerful utilities for analog signal generation.
-Devin
I got 99 problems but 8.6 ain't one.
0 Kudos
Message 19 of 23
(3,279 Views)

billings11,

 

Warning -- no answers here, just commiseration.

 

When starting out in LabVIEW-based DAQ, I was impressed by NI's interface to their DAQ vi's.  I first got familiar with the traditional NI-DAQ intermediate and advanced palette for AI, and it gave me a BIG headstart when I started branching out from the pure-AI apps into other DAQ signals.  In particular, the AO configuration was almost perfectly symmetric to AI.  The new DAQmx driver is generally even better at this similarity / symmetry.  (As an old-timer, I'd sometimes prefer to be able to pass in action and attribute constants that can be selected by program logic at run-time rather than select a specific polymorphic instance of a DAQmx property node at edit-time.  But I digress...)

 

I've done little AO (or timed DO) where the waveform isn't fully known before the task starts, except some pt-by-pt running LV RT.  Still, there were times I wished I had more control over the way the DAQ driver interacted with the output buffer.  For example - with the right settings, you can read data from any arbitrary location in an AI input buffer.  Well, there are also cases where it'd be nice to specify that a new AO waveform chunk should be written to some non-default position in the output buffer. 

 

Granted, there are some hairy timing scenarios to worry about -- you could be trying to change data just as its about to be clocked at the DAC.  Over time I came to understand why NI might treat such an ability to write data to arbitrary positions in the output buffer as way too big a headache to volunteer on itself. But your post jarred that thinking. Your biggest problem came from the behavior of the DAQ driver when the task is stopped.  Now, I'm not at hw to try this out, so maybe part of this list is in fact already possible.  But here's my list of capabilities that I think should absolutely be available in this scenario:

1. Query the driver to get the index for the buffer element that was most recently placed in the DAC register.

2. Query the driver to get the actual value sitting in the DAC register right now.  Raw or scaled.

3. Write new data to the output buffer such that the very first new data element is the very next value clocked out of the DAC when the task is started again.

 

I suspect #3 may be possible using the DAQmx execution state properties.  The simplest form -- clearing and re-configuring the task -- will force the new output data to be the very first data generated.  However for an app like yours, #3 isn't enough all by itself -- you would also need #1 (or at least #2) to go with it.

 
-Kevin P.
ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 20 of 23
(3,203 Views)