I write software that supports the use of a range of DAQmx devices, and one of the features of the software involves the use of a counter input to measure the duration between edges on an input signal. The incomplete sample detection feature of some DAQmx devices, whereby the first edge detected does not return a sample on some newer boards, has made it difficult to support a range of devices automatically. The feature itself is fine for my purposes, but the fact that behaviour is different on different models presents a problem.
Since I am not interested in this first incomplete sample, I am happy to discard it. However, my code needs to know whether the incomplete sample has already been discarded, or whether it needs to discard it itself.
Is there a way to tell, programmatically, whether a given device supports incomplete sample detection? I am using the DAQmx C API via a Python wrapper, so I've been looking at various DAQmx C functions to see if I can get at this information without having to have a human manually compile a list from reading documentation.
The description of the feature here lists a range of devices that have the feature, but it is not clear to me how to introspect this. For example, I can get the model number using either DAQmxGetDevProductNum or DAQmxGetDevProductType, but this is too specific - there are 547 or so possible results, a list which which be too long to compile manually. On the other hand I can get the series using DAQmxGetDevProductCategory. This has a manageable number of possible results, but I am unsure still whether this is sufficient to determine if a device supports incomplete sample detection. It sounds like all the X series devices do, so if DAQmxGetDevProductCategory returns DAQmx_Val_XSeriesDAQ, then I can be assured that the device supports incomplete sample detection. But the documentation I linked to above says that "Bus powered M series USB devices" support the feature. Is the USB 6008 a bus-powered M series device? It's bus powered and USB, but is it M series? I suspect not, since the documentation doesn't say it is. DAQmxGetDevProductCategory returns DAQmx_Val_USBDAQ. But can I be sure from the result of DAQmxGetDevProductCategory alone? Does DAQmx_Val_USBDAQ imply "not M-series?"
For the USB 6229 DAQmxGetDevProductCategory returns DAQmx_Val_MSeriesDAQ, so this one is an M-series. I know because we have one that it is not bus-powered, but I don't see a way of getting at this other than manually reading the documentation for a device I don't have.
For my software to work with a range of existing and future devices without requiring a human to figure out this (fairly obscure) difference and input it manually to the software, I need a way to get at the existence or otherwise of this feature automatically.
So, is the result of DAQmxGetDevProductCategory sufficient to determine whether a device has incomplete sample detection? If so, what is the mapping? If not, is there another way to determine this programmatically?
Any information would be appreciated.
Solved! Go to Solution.
First I'll point other readers to our prior remarks on the data acq idea exchange, so people can support our different but related requests if they choose.
Most of our test systems don't commonly interchange DAQ devices. The main situation where I needed to programmatically determine whether my board had "incomplete sample detection" mode, I already knew I was only dealing with a small subset of possible boards -- namely, E-series, M-series, or X-series MIO boards. For that subset, the product category property was sufficient for me to check, I didn't need anything more universal.
For the more general case, I have a clunky, ugly idea that just might work. The basic plan is to generate a test signal and measure it, using the result to make the determination.
For sure this will need some refinements in the details, but the essential steps are:
1. From list of device's counters, set up one for single pulse generation.
2. Set up another counter for buffered period measurement using Implicit timing.
3. Configure signal routing to measure periods of the generated (single) pulse.
4. Start the period measurement task
5. Start the pulse generation task and wait for it to finish. It makes 1 edge.
6. Query the period measurement task for # available samples. If 0 (and there's been no errors), you have a device exerting "incomplete sample detection". If 1, you have a device that is *not* exerting that behavior.
I quickly tried this out and got it working fine for an X-series and a really old E-series that was on the shelf. Further, I committed the pulse task explicitly before starting either task. Committing puts the output into the defined idle state, preventing any possible spurious transitions. Along the same lines, I didn't stop or clear either task until after the pulse was definitely done and until after I'd queried the period task for # samples. I also added a "trick" that should prevent the pulse from reaching any output pins, out of respect for whatever might be connected.
I imagine there's some other details to work out for certain other devices, including cDAQ. It'd be nice to generate the pulse with a simple DO task, but I don't know a programmatic way to figure out the association between PFI pin # (needed for counter config) and port/line designation (needed for DO config).
Have a look at the attachment below. Even though it's LabVIEW, I think it's mostly follow-able. Post back with any questions about the meaning of specific functional blocks or the sequencing.
Fantastic. Thank you very much Kevin, for the detailed (and tested!) solution.
I had in mind to do something like this, but had not figured out how to do the required internal routing. I think this will do nicely until NI makes directly accessing or configuring incomplete sample detection programmatically available. I was leaning toward the edge-counting workaround that you mentioned in the idea exchange post, but the inability to programmatically map PFIs to corresponding counters was impeding me there too.
Off topic, but I was considering a similar hack to figure out the PFI to port/line mapping: one at a time for each DO line, create an output task, and then for each PFI try to do something with it and see if you get an 'already reserved' error. I didn't get super far with this because 'do something with a PFI' depends on the devices's capabilities. Still less of a hack than the next idea of programmatically opening the help file, extracting the pinout diagram and running OCR on it...
Your method won't work on devices that have a single counter only, but the only one of these I have doesn't support semiperiod measurement, and so can't be used with my software anyway. I don't know if there are boards with a single counter that supports semiperiod measurement, so for now I'll just throw an error about this.
I've translated your LabVIEW code to Python with the PyDAQmx wrapper (attached), and it seems to be working, though I haven't yet tested it on a device that *does* have incomplete sample detection.
Thanks again for this, I think I'll tentatively declare this problem solved for my software 🙂
Couple items of follow up for future readers that land on this thread:
- yeah, the posted LabVIEW code method depends on a 2-counter device. The only 1 counter devices I happen to be aware of are low cost USB devices which *only* support edge counting. My check for support of period measurement mode had those in mind.
- I had a very brief chance to try it out on a cDAQ-9174 chassis and it doesn't work right there either. One issue is that counter physical channel names have a leading underscore character. Another seems to be (didn't have enough time to really get into it) that this kind of internal usage of the chassis' counters may not be supported unless the chassis is populated with a digital module that enables counter usage. I didn't have any such module handy to explore with.
- there's a real value to the ability to at least query or (better yet IMHO) turn this feature on or off. If you'd like this ability too, please consider adding kudos to the idea exchange entry linked in msg #2.
In my app (where I happened to have a decent workaround due to the limited subset of possible boards), the counter in question was used in period measurement mode on a potentially varying frequency signal that acted as the shared clock for other DAQ tasks. The purpose was to have accurate timestamps for the sample clock edges when the sample clock might vary in frequency over the course of run time. The 1st AI sample always corresponded to the 1st clock edge. But the first period measurement might correspond to either the 1st or 2nd clock edge, depending on the "incomplete sample detection" feature. The data would have been out of time alignment had I not taken extra steps to handle the different counter types in distinct ways.
I've added Kudos to the idea exchange entry, and yes, encourage anyone else with related issues to do so as well.
As I've continued to work on making my code work on as wide a range of devices as possible, I've realised being able to turn off incomplete sample detection is really what would be ideal for my use case. As it stands, the minimum pulse time detectable by a semiperiod measurement varies by device (depending on available timebases), and so I need to now get that information and feed it back to the code that generates these pulses, to ensure they're not too short. The pulses are far between though, and so if I were doing a full period measurement, I presume it wouldn't matter how long the high time of these pulses was, as the time between rising edges would be long enough for any device to deal with.
But I need to do something in software immediately after the very first pulse, and thus need to do a semiperiod measurement if I don't want the whole pulse to be discarded incomplete sample detection - with incomplete sample detection at least I get the falling edge of the pulse still, which is good enough for me. But having to do a semiperiod measurement imposes device-specific limits on how short the pulse can be, which just makes my code more complex.
If the pulses can be rare and far between, the "equivalency" method becomes significantly less equivalent. I think I see why that's not a good workaround for you.
I think I'll go add another followup on the idea exchange to more carefully distinguish cases where "equivalency" is insufficient compared to the idea being proposed. Additions or corrections are welcomed.
One more thought on this automatic discovery process.
There's a new-ish set of measurement options in DAQmx known as Pulse measurements. In a quick trial run here, it appears that Pulse measurements are supported on X-series boards but not M-series or E-series. (True across a couple real devices and several additional simulated devices.) This corresponds to the "incomplete sample detection" feature.
I'm not sure it's a perfect proxy, but it might be a better (and simpler) starting point for weeding out candidates one way or the other. "Pulse:Time" measurements are designated as Measurement Type = 15865.