Real-Time Measurement and Control

cancel
Showing results for 
Search instead for 
Did you mean: 

Need help trouble-shooting a specific sampling rate (180K) and number of samples (60K) using a NI PCIe 6363 Device via the DAQmx API

Solved!
Go to solution

This post is a narrowed scope version of a previous unresolved post titled:

 

"What are valid combinations of sampling rate and number of samples using a NI PCIe 6363 Device via the DAQmx API"

The details of the setup may be found in the original post.

 

Question:

 

Why doesn't the following setup work?

(the registered callback using DAQmxRegisterEveryNSamplesEvent is never called)

 

float64 SamplingRate = 180000.0; // 180K Hz set via DAQmxCfgSampClkTiming
uInt32 nSamples = 60000;         // 60K  set via DAQmxCfgSampClkTiming

 

Given that the following (similar) setup works fine

 

 float64 SamplingRate = 150000.0; // 150K Hz set via DAQmxCfgSampClkTiming
uInt32 nSamples = 50000;         // 50K  set via DAQmxCfgSampClkTiming

 

0 Kudos
Message 1 of 9
(4,408 Views)

Hi big.tuna,

 

I used the ContAcq-IntClk-EveryNSamplesEvent.c DAQmx API example and was unable to replicate this behavior. Does the example behave this way on your system as well?

 

Justin

Applications Engineer

0 Kudos
Message 2 of 9
(4,350 Views)

Hi Justin,

 

Thank you for the help.  Perhaps you can run my code (pasted below), but I think it is the same as your test.  I am still having problems as reported before.

Here is what I did:

 

(0) obtained and built ContAcq-IntClk-EveryNSamplesEvent.c into a console, this uses 3 Analog channels and started with 10K ADC and 1K buffer to give us 10 callbacks per second.   This worked.

(1) modified ContAcq-IntClk-EveryNSamplesEvent.c so we can test my parameters:

  (a) modified the code to use only one analog channel (as in my original test, should not be an issue)

  (b) modified the code to allow a test of either DAQmxReadBinaryI16 or DAQmxReadAnalogF64

 (c) parameterized the code to allow easy changes to the ADC rate and samples

  

I ran the code (see below for a full copy), using all configurations I mentioned:

 

configuration that does work (either with DAQmxReadBinaryI16 or DAQmxReadAnalogF64)

 float64 SamplingRate = 150000.0; 
uInt32 nSamples = 50000;         

 

here is the console trace:

Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples
Acquired 50000 samples

 

configuration that does not work: (neither with DAQmxReadBinaryI16 nor DAQmxReadAnalogF64)

float64 SamplingRate = 180000.0; 
uInt32 nSamples = 60000;        

 

here is the console trace:
DAQmx Error: Requested Every N Samples Event Interval is not supported for the given Data Transfer Mechanism and buffer size.

To keep DMA or USB Bulk as the Data Transfer Mechanism, modify the buffer size and/or the Every N Samples Event Interval so the buffer size is an even multiple of the Every N Samples Event Interval. To keep the same Every N Samples Event Interval and buffer size, change the Data Transfer Mechanism to Interrupts if supported.
Property: DAQmx_Every N Samples Acq Into Buffer Event Interval
Requested Value: 60000
Buffer Size: 100000

Task Name: _unnamedTask<0>

Status Code: -200877

 

 

Below is the complete source code used, this should allow anyone to reproduce the test.  

You should be able to drop this into a console app replacing main.cpp, and build in Visual Studio.  

You will need the NIDAQmx.lib and NIDAQmx.h

 

#include "stdafx.h"
#include "NIDAQmx.h"
#include <stdio.h>

constexpr int NI_SAMPLES = 60000;  // <- change this to 50000 for working code
constexpr double NI_ADC_RATE = (double)(3 * NI_SAMPLES);

#define _USE_INT_FOR_DATA_BUFFER_ 314 // <- comment out this line to use a double for each Analog element in the array/sample buffer

#ifdef _USE_INT_FOR_DATA_BUFFER_
static int16 NI_data[NI_SAMPLES];
#else
static float64 NI_data[NI_SAMPLES];
#endif

#define DAQmxErrChk(functionCall) if( DAQmxFailed(error=(functionCall)) ) goto Error; else

/*********************************************/
// Error handler
/*********************************************/
static void ErrorHandler(TaskHandle& taskHandle, int32 error)
{
char errBuff[2048] = { '\0' };
if (DAQmxFailed(error))
{
DAQmxGetExtendedErrorInfo(errBuff, 2048);

if (taskHandle != 0)
{
DAQmxStopTask(taskHandle);
DAQmxClearTask(taskHandle);
taskHandle = 0;
}

printf("DAQmx Error: %s\n", errBuff);
char ch = getchar();
}
}

/*********************************************/
// Callback Code
/*********************************************/
static int32 CVICALLBACK EveryNSamplesCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData)
{
int32 error = 0;
int32 read = 0;

#ifdef _USE_INT_FOR_DATA_BUFFER_
DAQmxErrChk(DAQmxReadBinaryI16(taskHandle, NI_SAMPLES, 10.0, DAQmx_Val_GroupByScanNumber, NI_data, NI_SAMPLES, &read, NULL));
#else
DAQmxErrChk(DAQmxReadAnalogF64(taskHandle, NI_SAMPLES, 10.0, DAQmx_Val_GroupByScanNumber, NI_data, NI_SAMPLES, &read, NULL));
#endif

if (read > 0)
{
printf("Acquired %d samples\n", read);
}

Error:
ErrorHandler(taskHandle, error);
return 0;
}

/*********************************************/
// Console Code
/*********************************************/
int main()
{
TaskHandle taskHandle = 0;
int32 error = 0;
DAQmxErrChk(DAQmxCreateTask("", &taskHandle));
DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandle, "Dev2/ai4", "", DAQmx_Val_Diff, -10.0, 10.0, DAQmx_Val_Volts, NULL));
DAQmxErrChk(DAQmxCfgSampClkTiming(taskHandle, "", NI_ADC_RATE, DAQmx_Val_Rising, DAQmx_Val_ContSamps, NI_SAMPLES));

DAQmxRegisterEveryNSamplesEvent(
taskHandle,
DAQmx_Val_Acquired_Into_Buffer,
NI_SAMPLES,
0,
EveryNSamplesCallback,
NULL);

DAQmxErrChk(DAQmxStartTask(taskHandle));
char ch = getchar();
DAQmxErrChk(DAQmxStopTask(taskHandle));

Error:
ErrorHandler(taskHandle, error);
}

 

 

 

0 Kudos
Message 3 of 9
(4,344 Views)

Hi big.tuna,

 

I haven't had a chance to try running your code yet, but when you say that you were able to obtain and build the example and that it worked, was that for this combination of sample rate and number of samples as well? Is it only once changes were made that it stopped working? 

0 Kudos
Message 4 of 9
(4,332 Views)

ContAcq-IntClk-EveryNSamplesEvent.c using 3 Analog channels, 10K ADC, 1K samples works (unmodified)

ContAcq-IntClk-EveryNSamplesEvent.c using 1 Analog channel, 10K ADC, 1K samples works

ContAcq-IntClk-EveryNSamplesEvent.c using 1 Analog channel, 150K ADC, 50K samples works

ContAcq-IntClk-EveryNSamplesEvent.c using 1 Analog channel, 180K ADC, 60K samples does not work

 

My previous post has the complete details, including the exact source code, and console error trace.

The console error trace may offer some clues.

 

The combination that does not work (180K ADC, 60K samples) is the problem I am trying to solve.

 

 

 

0 Kudos
Message 5 of 9
(4,330 Views)

Hi Big Tuna,

 

The console trace reveals the issue.

Requested Value: 60000
Buffer Size: 100000

I believe you are not pulling samples off of your buffer fast enough. you are sampling at 180k and requesting 60k samples, leaving 120k data points and overflowing your 100k buffer. All of the other combinations you mentioned did not exceed a 100k difference.

 

Regards,

 

Finch Train

 

0 Kudos
Message 6 of 9
(4,310 Views)

 

First, the buffer was allocated as 60K, not 100K, I do not know where the 100K buffer comes from.

 

 

Second, the ADC Rate is 180K per second, and I have requested a callback at 60K samples, so that after 0.333 seconds I am expecting a callback, which should keep up with the data collection.  I am not spending much time in the callback (which is a potential source of overrun) .

 

Third, I had originally posted other cases that worked, such as 200K ADC and 50K samples being read 4 callbacks per second.   Using the logic applied to your response, I would expect that (if the mysterious buffer was 100K) after requesting 50K samples, this should leave 150K data points (following your analysis) and overflow the 100k buffer, but this does not happen.  The 200K ADC and 50K sample buffer works fine.

 

Interestingly, some combinations work, others do not, I have not found a pattern.

 

Could you please explain why the following setup works 

ADC=200K, 50K samples -> does work

and this one does not?

ADC=180K, 60K samples -> does not work, no callbacks ever

 

 

 

The documentation for DAQmxReadBinaryI16 indicates:

numSampsPerChan

The number of samples, per channel, to read. The default value of -1 (DAQmx_Val_Auto) reads all available samples. If readArray does not contain enough space, this function returns as many samples as fit in readArray.

 

 Since I used 60K for the numSampsPerChan parameter, the same as the nSamples configured using DAQmxRegisterEveryNSamplesEvent , I would expect that this should work.

 

The documentation for DAQmxRegisterEveryNSamplesEvent indicates:

nSamples

The number of samples after which each event should occur.

 

Therefore, it appears we should get an event after 60K samples arrive, as generated by the 180K/second sampling of the analog channel, which means this should fire every 1/3 second.   The 1/N timing is exactly what I get when other combinations are used, such as ADC=200K, samples=50K

 

Notice in the sample code I provided, I setup the code to make sure the ADC is a multiple of the samples, hence:

constexpr int NI_SAMPLES = 50000;
constexpr double NI_ADC_RATE = (double)(4 * NI_SAMPLES);

0 Kudos
Message 7 of 9
(4,308 Views)
Solution
Accepted by big.tuna

Hi big.tuna,

 

Have you taken a look at the following forum post?
http://forums.ni.com/t5/Multifunction-DAQ/Error-200877/td-p/500381

From the error trace, it seems like the buffer is getting set to 100k automatically. We need to change this to a multiple of the number of samples manually with the DAQmxSetBufInputBufSize function as mentioned in the above post. 

Message 8 of 9
(4,294 Views)

Adding DAQmxSetBufInputBufSize() worked.

Thank you very much.

 

Here is the code snippet with the problem config:

 

constexpr int NI_SAMPLES = 6000;
constexpr double NI_ADC_RATE = (double)(3 * NI_SAMPLES);

 

DAQmxErrChk(DAQmxCreateTask("", &taskHandle));
DAQmxErrChk(DAQmxCreateAIVoltageChan(taskHandle, "Dev2/ai4", "", DAQmx_Val_Diff, -10.0, 10.0, DAQmx_Val_Volts, NULL));
DAQmxErrChk(DAQmxCfgSampClkTiming(taskHandle, "", NI_ADC_RATE, DAQmx_Val_Rising, DAQmx_Val_ContSamps, NI_SAMPLES));
DAQmxErrChk(DAQmxSetBufInputBufSize(taskHandle, NI_ADC_RATE));

DAQmxRegisterEveryNSamplesEvent(
taskHandle,
DAQmx_Val_Acquired_Into_Buffer,
NI_SAMPLES,
0,
EveryNSamplesCallback,
NULL);

 

 

static int32 CVICALLBACK EveryNSamplesCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData)
{
int32 error = 0;
int32 read = 0;


#ifdef _USE_INT_FOR_DATA_BUFFER_
DAQmxErrChk(DAQmxReadBinaryI16(taskHandle, NI_SAMPLES, 10.0, DAQmx_Val_GroupByScanNumber, NI_data, NI_SAMPLES, &read, NULL));
#else
DAQmxErrChk(DAQmxReadAnalogF64(taskHandle, NI_SAMPLES, 10.0, DAQmx_Val_GroupByScanNumber, NI_data, NI_SAMPLES, &read, NULL));
#endif

if (read > 0)
{
printf("Acquired %d samples\n", read);
}

Error:
ErrorHandler(taskHandle, error);
return 0;
}

0 Kudos
Message 9 of 9
(4,290 Views)