03-11-2005 10:18 AM
03-14-2005 10:11 AM
03-14-2005 10:12 AM
03-16-2005 03:53 PM
03-16-2005 08:26 PM
03-17-2005 07:42 AM - edited 03-17-2005 07:42 AM
Message Edited by Kevin Price on 03-17-2005 08:50 AM
09-09-2005 09:17 AM - edited 09-09-2005 09:17 AM
Message Edited by billings11 on 09-09-2005 09:22 AM
09-09-2005 11:05 AM
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! .
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...
09-09-2005 01:01 PM
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.
09-12-2005 01:44 PM
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.