Hi there, I'm using CVI LabWindows for a project with a U3-HV. We have a sensor that outputs digital counts. These counts must be accumulated in precisely 1-second windows. The count rate is typically in the 10k to 50k range. So timing accuracy is critical to measure counts within exactly a 1 second window.
If I understand the stream mode limitations, count rate is very limited to the U3's FIFO. But am I right in thinking that if I continue to read its FIFO as it is streaming as fast as LabWindows can, then I won't suffer overflows?
Do you guys have any sample stream projects in C? Thanks!
The maximum sample rate of stream mode is 50k, and.sample rate = scan rate * number of channels. So for a 1 channel stream the maximum scan rate is 50k (50k/1), for a 2 channel stream the maximum scan rate is 25k (50k/2), etc..
As for preventing overflow, running as fast as LabWindows can will probably be enough. In general try to read samples faster than the stream's sample rate to help prevent overflow. The UD driver has its own stream buffer which is configurable, so you could wait for say 1 second of data and read it in one stream read call. Note that the U3 hardware also has its own stream buffer which the UD driver is constantly reading from in the background. For hardware and UD driver stream details look at this documentation:
https://labjack.com/support/datasheets/u3/operation/stream-mode
https://labjack.com/support/datasheets/u3/high-level-driver/example-pseu...
Our C examples provides a stream example:
https://labjack.com/support/software/examples/ud/vc6
Thanks for the help! One thing I'm struggling with on your C example is changing from an analog input to digital capture counter mode. My input signal is already TTL. Section 3.2.1 talks about this, but there aren't any syntax examples for this. Also, I don't see any of the "special streaming channels" from that 3.2.1 table abstracted as macros in the UD header file. I sorta expected them to be in there by value. No big deal.
Another thing I'm not getting is the relative asynchronous checking. If my LabWindows software is to check faster than the rate at which the LabJack is streaming, how do I know the data is fresh or old?
To change a line from analog to digital or vise versa, use a request with a LJ_ioPUT_ANALOG_ENABLE_BIT(single line) or LJ_ioPUT_ANALOG_ENABLE_PORT (all FIO and EIO lines). This is documented here along with pseudocode:
https://labjack.com/support/datasheets/u3/high-level-driver/example-pseu...
To enable a counter look at our timer/counter example. Also, it is documented here in the datasheet:
https://labjack.com/support/datasheets/u3/high-level-driver/example-pseu...
As for streaming a counter, there isn't a constant for those channels but you use two channels to read the 1 counter value which are 210/211 and 224. That is discussed here:
https://labjack.com/support/datasheets/u3/operation/stream-mode/digital-...
As for you last question, when using stream mode the U3 hardware is continuously streaming data at the rate you configured and placing the data in a FIFO buffer which your application is reading from. So basically you are reading and removing the oldest data from the buffer first, and you know the time between the scans based on the scan rate you configured
I don't know, the longer I read this stuff, the more my eyes get fuzzy. I'm reading nothing from the sample VC6 code, modified for Counter 1 input. Here's what I have for setup:
//For U3 revision 1.3, this is the first pin available.
AddRequest (lngHandle, LJ_ioPUT_CONFIG, LJ_chTIMER_COUNTER_PIN_OFFSET, 4, 0, 0);
//Make sure Counter0 is disabled.
AddRequest (lngHandle, LJ_ioPUT_COUNTER_ENABLE, 0, 0, 0, 0);
//Enable Counter1. It will use the next available line, FIO6.
AddRequest (lngHandle, LJ_ioPUT_COUNTER_ENABLE, 1, 1, 0, 0);
// now send the messages
GoOne(lngHandle);
The lack of any psuedo code in section 3.2.1 for the special channels is really hurting. I'm completely guessing at syntax, which is kinda the opposite of fun. Best I can figure is:
eGet(lngHandle, LJ_ioGET_STREAM_DATA, 211, &numScansRequested, padblData);
eGet(lngHandle, LJ_ioGET_STREAM_DATA, 224, &numScansRequested, padblData);
But I get "Unable to start stream".
Then I noticed at the top: "Note that you must always have at least 1 AIN channel in the stream list for the U3." Is this my problem?
How are you configuring your stream? Make sure you configure your counter first before you configure and start stream mode (your counter code looks correct). Your stream would look something like this if only streaming Counter 1 (going off the C examples):
//Configure the stream:
//Set the scan rate.
lngErrorcode = AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chSTREAM_SCAN_FREQUENCY, scanRate, 0, 0);
ErrorHandler(lngErrorcode, __LINE__, 0);
//Give the driver a 5 second buffer (scanRate * 2 channels * 5 seconds).
lngErrorcode = AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chSTREAM_BUFFER_SIZE, scanRate*2*5, 0, 0);
ErrorHandler(lngErrorcode, __LINE__, 0);
//Configure reads to retrieve whatever data is available without waiting (wait mode LJ_swNONE).
//See comments below to change this program to use LJ_swSLEEP mode.
lngErrorcode = AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chSTREAM_WAIT_MODE, LJ_swNONE, 0, 0);
ErrorHandler(lngErrorcode, __LINE__, 0);
lngErrorcode = AddRequest(lngHandle, LJ_ioCLEAR_STREAM_CHANNELS, 0, 0, 0, 0);
ErrorHandler(lngErrorcode, __LINE__, 0);
lngErrorcode = AddRequest(lngHandle, LJ_ioADD_STREAM_CHANNEL, 211, 0, 0, 0); //Counter 1 (LSW - lower 16-bits of count)
ErrorHandler(lngErrorcode, __LINE__, 0);
lngErrorcode = AddRequest(lngHandle, LJ_ioADD_STREAM_CHANNEL, 224, 0, 0, 0); //Counter 1 (MSW - upper 16-bits of count)
ErrorHandler(lngErrorcode, __LINE__, 0);
//Execute the list of requests.
lngErrorcode = GoOne(lngHandle);
ErrorHandler(lngErrorcode, __LINE__, 0);
//Get all the results just to check for errors.
//Look at the example ...
//Start the stream.
lngErrorcode = eGet(lngHandle, LJ_ioSTART_STREAM, 0, &dblValue, 0);
ErrorHandler(lngErrorcode, __LINE__, 0);
Then your stream read loop to get the reading would look like (look at example for error checking and preinitializing the stream arrays):
//...
//Read the data, all channels interleaved. For example {211Reading, 224Reading, 211Reading, 224Reading, 211Reading, 224Reading, ...}
lngErrorcode = eGet(lngHandle, LJ_ioGET_STREAM_DATA, LJ_chALL_CHANNELS, &numScansRequested, padblData);
ErrorHandler(lngErrorcode, __LINE__, 0);
Or:
//Read the channel 211 data.
lngErrorcode = eGet(lngHandle, LJ_ioGET_STREAM_DATA, LJ_chALL_CHANNELS, &numScansRequested, padblData211);
ErrorHandler(lngErrorcode, __LINE__, 0);
//Read the channel 224 data.
lngErrorcode = eGet(lngHandle, LJ_ioGET_STREAM_DATA, LJ_chALL_CHANNELS, &numScansRequested, padblData224);
ErrorHandler(lngErrorcode, __LINE__, 0);
Note that to get the 32-bit counter value, it looks something like this using the channel 211 and 224 readings from the same scan:
counterValue = 211Value + 224Value*65536;
If that doesn't help to resolve the issue, please provide more code showing how you configure your stream.
Last, where did you find the "Note that you must always have at least 1 AIN channel in the stream list for the U3." message? I don't see that in the example or the UD documentation for stream mode? When I tested now, streaming just channels 211 and 224 with the latest U3 firmware worked without issue.
Thanks for all your help, I do appreciate it!
That note is somewhat buried. I found it on one of your U3 web pages, for section 3.2.1. Though apparently it was excised from the official datasheet. My PDF doesn't include that line.
In talking more about my project internally, my colleagues steered me in a possible new direction for this. It is also adequate to merely count these pulses at a known rate. It's not critical to count exactly for 1 second, as much as it is important that the start and stop time of counting is absolutely known, which gives us the same information (count rate). All the other specs remain the same (10-50k counts per second), single channel of TTL counter input.
Does this new info suggest a different solution to you guys? I'm not sure there's a better/easier method than the streaming mode. The only other way I can see this is to start a timer and counter at the same time, and then arbitrarily stop them both some milliseconds later, assuming a timer and counter can start and stop in a single function call.
Thoughts?
Consider 2 approaches:
1. Do a single command-response read to get the initial count and also initial system timer value:
https://labjack.com/support/datasheets/u3/hardware-description/timers-co...
Then approximately 10 seconds later do another single command-response read to get the final count and system timer value. The time difference might not be exactly 10 seconds, but it will be about 10 seconds, and you know the exact time difference according to the U3 clock because of the system timer reads.
2. Use stream mode to acquire 10001 (or more) reads of the counter at 1000 scans/second. You know that scan #0 and scan #10000 are exactly 10 seconds apart according to the U3 clock.
Either of these methods are equally accurate. In both cases you know the number of counts that occurred over a know time period according to the U3 clock. The same clock is the basis for stream and system timer, so both these methods are equally accurate.
The problem, however, is that the U3 clock is not particularly accurate. It is RC based, not quartz, and is only 1.5% accurate:
https://labjack.com/support/datasheets/u3/appendix-a
To get a quartz based clock consider the U6 or T7.
If you had a known high accuracy signal, 10 kHz for example, you could use another counter to count that at the same and thus establish more accurate time.
To get high time accuracy with U3 counting, you need to count over a long enough time that you can use software timestamps and the jitter in those timestamps is small relative to the total count interval.
http://forums.labjack.com/index.php?showtopic=1105
Thanks for your help. I have your proposed option #1 working now. However, I'm getting two curious results with my system internal timer values.
Curious Result #1
I'm getting timer values that are larger when sampled first. In other words, I have something like this:
// init capture
ReadCounterTimer(&countStart, &timeStart);
// delay
countdown = 60
while (--countdown > 0)
{
Delay(1); // 1 second delay
}
// get final values
ReadCounterTimer(&countEnd, &timeEnd);
// calculate:
countTotal = countEnd - countStart;
timeTotal = timeEnd - timeStart;
unitData.countRate = countTotal/timeTotal * 48e6;
Yet my value of countTotal turns out negative. ?? Now if I use the LJControlPanel test window, it sure looks to me like successive timer reads are larger in value.
Curious Result #2
With the above setup, I'm calculating nearly exactly 30 LabJack seconds, rather than the expected 60 as driven by my software. Is there a DIV2 somewhere?
We probably need to see your code for "ReadCounterTimer" to find the issue.
I did a test with LJLogUD and it works fine for me. First I used Config Defaults in LJControlPanel to configure my U3-HV as shown in the screenshot (don't forget to click Write Values). Then I closed LJCP, power-cycled my U3, and then opened LJLogUD (as shown in 2nd screenshot). To read the timer in LJLogUD I have to use the pseudo analog input channel numbers 200 (lower 16 bits of Timer0) and 224 (upper 16 bits).
Following is some of my data collected once per second. 1st column is my read of 200 + 224*2^16. 2nd column is the difference from the previous and you can see it is about 4M each time:
682837287
686845450 4008163
690845623 4000173
694849297 4003674
698854008 4004711
702856633 4002625
706862258 4005625
710862381 4000123
714864986 4002605
718869599 4004613
Ok, I think I sorta see what I did wrong. I tried to get too cute with a union-based typedef which does the MSW & LSW concatenation and conversion for me. It looks like this:
typedef union
{
unsigned long long word : 64; // the entire 64-bit word
unsigned int ints[2]; // most and least significant words
} dbl64;
But, what I found is that since the LabJack functions all return doubles, there must have been some very arcane data type conversion happening. I just sucked it up and did what you did for conversion on the upper word. Works fine now, no negatives.
Ok, I have another dumb question. Using your same setup (48MHz clock, offset = 4, etc.), I get similar results for 1 second counting windows, which is ~4M ticks per second.
How then does this correlate to my software timer of 1 second? It would appear that with time base 48MHz, there's some internal div for which I need to divide my results by 4M?
But I'm not using the 48MH_DIV timescale. No divisor.
The U3 system timer runs at a 4 MHz frequency, so as you are seeing 1 second is 4M ticks (1 tick = 250 nanoseconds). The system timer is not affected by the timer clock and its divisor. We document the system timer here which mentions this:
https://labjack.com/support/datasheets/u3/hardware-description/timers-co...