Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

Time between two shots of everyNCalback is shorter than it should be according to the sampling rate

Solved!
Go to solution

I need help with a problem I have to calculate the time of the samples I take from an NI cDAQ-9184 with an NI 9237 module.
I work in a project in which we take samples of a load cell to calculate the weight of different vehicles, in this project we are continuously taking samples and calculating for each one of them the moment of time in which it was obtained.
If I take samples at a speed of 1khz passing a buffer of 100 samples, the everyNcallback event should be fired every 100 milliseconds, however when I measure the time between shots I get about 62 milliseconds.
How can this be?
This is the code I use:

 

#include <Windows.h>
#include <stdio.h>
#include <time.h>
#include <tchar.h>

#include "NIDAQmx.h"

#define CANT_CANALES 4
#define CANT_BUFFERS 10

#define MUESTRAS_BUFFER 100
#define VELOCIDAD_MUESTREO 1000
#define MAGNITUD_MIN -0.025
#define MAGNITUD_MAX 0.025

char		AI_Dispositivo[1024] = "cDAQ9184-1BFBD04Mod2";		
float64		AI_Buffer[sizeof(float64) * MUESTRAS_BUFFER * CANT_CANALES];
TaskHandle	AI_Tarea = NULL;									

LARGE_INTEGER t_ini, t_fin;
int indice;
double Tiempos[CANT_BUFFERS];

HANDLE Handle_Espera;

double performancecounter_diff(LARGE_INTEGER *a, LARGE_INTEGER *b) {
	LARGE_INTEGER freq;
	QueryPerformanceFrequency(&freq);
	return (double)(a->QuadPart - b->QuadPart) / (double)freq.QuadPart;
}

int32 CVICALLBACK EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData) {
	int32 readAI = 0, error = 0, i;

	QueryPerformanceCounter(&t_fin);

	if (indice < CANT_BUFFERS) {
		Tiempos[indice] = performancecounter_diff(&t_fin, &t_ini);
		indice++;
	} else {
		printf("Tiempos:\n");
		for (i = 0; i < CANT_BUFFERS; i++) {
			printf("\t%f\n", Tiempos[i]);
		}
		SetEvent(Handle_Espera);
	}

	error = DAQmxReadAnalogF64(AI_Tarea, -1, 1.0, DAQmx_Val_GroupByScanNumber, AI_Buffer, MUESTRAS_BUFFER * CANT_CANALES, &readAI, NULL);
	if (error > 0) {
		printf("DAQmxReadAnalogF64 ADVERTENCIA %d\n", error);
	} else if (error < 0) {
		printf("DAQmxReadAnalogF64 ERROR %d\n", error);
	}

	if ((uInt32)readAI != nSamples) {
		printf("DAQmxReadAnalogF64 ERROR Muestras Leidas = %d Muestras disponibles = %d\n", readAI, nSamples);
	}

	QueryPerformanceCounter(&t_ini);

	return 0;
}

int main() {
	DWORD temp;

	Handle_Espera = CreateEvent(NULL, TRUE, FALSE, TEXT("Handle_Espera"));

	DAQmxCreateTask("AI_Tarea", &AI_Tarea);
	DAQmxCreateAIBridgeChan(AI_Tarea, "cDAQ9184-1BFBD04Mod2/ai0:3", "", MAGNITUD_MIN, MAGNITUD_MAX, DAQmx_Val_VoltsPerVolt, DAQmx_Val_FullBridge, DAQmx_Val_External, 9.0, 350, NULL);
	DAQmxCfgSampClkTiming(AI_Tarea, "", VELOCIDAD_MUESTREO, DAQmx_Val_Rising, DAQmx_Val_ContSamps, MUESTRAS_BUFFER);
	DAQmxRegisterEveryNSamplesEvent(AI_Tarea, DAQmx_Val_Acquired_Into_Buffer, MUESTRAS_BUFFER, 0, EveryNCallback, NULL);

	indice = 0;
	QueryPerformanceCounter(&t_ini);

	DAQmxStartTask(AI_Tarea);

	WaitForSingleObject(Handle_Espera, INFINITE);

	DAQmxStopTask(AI_Tarea);
	DAQmxWaitUntilTaskDone(AI_Tarea, -1);
	DAQmxClearTask(AI_Tarea);

	printf("Ingrese un numero para terminar: ");

	scanf_s("%d", &temp);

	return 0;
}
Result:
Tiempos:
        1.512656
        0.061836
        0.061815
        0.062108
        0.061618
        0.064241
        0.059541
        0.062228
        0.061497
        0.062573
Ingrese un numero para terminar:

From already thank you very much.

 

0 Kudos
Message 1 of 11
(3,016 Views)

Hi vbaptista

 

What is more important for your application: to receive samples at 1khz or to receive samples every 100 milliseconds?

 

Regards

0 Kudos
Message 2 of 11
(2,967 Views)

As long as the actual frequency is higher, I guess it's not a problem because I calculate the time of each sample by dividing the time difference with the previous buffer by the number of samples.
What worries me is that something is wrong.

0 Kudos
Message 3 of 11
(2,958 Views)

I found this example that could help you with more information about the function you are using to make the callback.

 

On your computer you can look for:

 

C:\Users\Public\Documents\National Instruments\CVI\Samples\DAQmx\Events\Every N Samples\Cont Acq-Int Clk-Every N Samples Event

 

It seems to me that you are benchmarking only the Callback and that is why you received less than 100 milliseconds.

 

Regards,

Astromaut

0 Kudos
Message 4 of 11
(2,929 Views)

Thanks for the example but I do not use LabView, I develop in C ++ with visual studio.

The time it takes to execute the EveryNCallback function is negligible, so my code should measure the time between each pair of calls to that function.

It is not like this?

0 Kudos
Message 5 of 11
(2,925 Views)

I found the same example for C++:

 

You can found it on:

 

C:\Users\Public\Documents\National Instruments\NI-DAQ\Examples\DAQmx ANSI C\Events\Every N Samples\Cont Acq-Int Clk-Every N Samples Event

 

Regards,

Astromaut

0 Kudos
Message 6 of 11
(2,917 Views)

Yes, that example had already seen it but it does not help me with my problem.

 

Regards

0 Kudos
Message 7 of 11
(2,912 Views)

Hi vbaptista

Could you include some comments to your code, especially on the functions you are using to measure the time? I ask this in order to understand better your application and see if I could help to identify what could be happening.

 

Regards,

Astromaut

0 Kudos
Message 8 of 11
(2,898 Views)

Thanks Astromaut for your time.

 

QueryPerformanceCounter is a windows API that is used to measure time intervals with a precision of 1 microsecond or better.
This is the link that explains about that:

 

Acquiring high-resolution time stamps

 

And from this link I took the idea to measure times using QueryPerformanceCounter:

 

How to use QueryPerformanceCounter?

 

In addition to using QueryPerformanceCounter I also used the timeGetTime function with the same results, I also tried other sampling frequencies and buffers sizes and it always gives me a shorter time than expected.

 

Here I leave the commented code:

 

#include <Windows.h>
#include <stdio.h>
#include <time.h>
#include <tchar.h>

#include "NIDAQmx.h"

#define CANT_CANALES 4
#define CANT_BUFFERS 10

#define MUESTRAS_BUFFER 100				// number of samples per channel that the buffer will have
#define VELOCIDAD_MUESTREO 1000		// sampling rate
#define MAGNITUD_MIN -0.025				// minimum value of the module NI 9237
#define MAGNITUD_MAX 0.025				// maximum value of the module NI 9237

char		AI_Dispositivo[1024] = "cDAQ9184-1BFBD04Mod2";										// name of the module NI 9237	
float64		AI_Buffer[sizeof(float64) * MUESTRAS_BUFFER * CANT_CANALES];		// analog sample buffer
TaskHandle	AI_Tarea = NULL;																							// analog task			

LARGE_INTEGER t_ini;							// time of the previous call to the EveryNCallback function
LARGE_INTEGER t_fin;							// time of the current call to the EveryNCallback function
int indice;												// position of the time array where the time interval between the current call and the previous call will be inserted
double Tiempos[CANT_BUFFERS];			// array that contains the time intervals between calls to EveryNCallback. 
																	// the times are stored in this array so that they can be displayed on the screen at the end of the process and avoid, as far as possible, affecting the measurement.

HANDLE Handle_Espera;							// handle used by WaitForSingleObject so that the main thread waits for the array of times to fill

// returns the time interval in seconds between a and b 
double performancecounter_diff(LARGE_INTEGER *a, LARGE_INTEGER *b) {
	LARGE_INTEGER freq;
	QueryPerformanceFrequency(&freq);
	return (double)(a->QuadPart - b->QuadPart) / (double)freq.QuadPart;
}

int32 CVICALLBACK EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData) {
	int32 readAI = 0, error = 0, i;

	// get de current time
	QueryPerformanceCounter(&t_fin);

	
	// if the time buffer is not yet full I keep the time difference between the last two calls in the next position
	if (indice < CANT_BUFFERS) {
		Tiempos[indice] = performancecounter_diff(&t_fin, &t_ini);
		indice++;
	} else { // if the time buffer is full, display the stored values on the screen and finish processing
		printf("Tiempos:\n");
		for (i = 0; i < CANT_BUFFERS; i++) {
			printf("\t%f\n", Tiempos[i]);
		}
		SetEvent(Handle_Espera); // finish processing
	}

	// get analog buffer
	error = DAQmxReadAnalogF64(AI_Tarea, -1, 1.0, DAQmx_Val_GroupByScanNumber, AI_Buffer, MUESTRAS_BUFFER * CANT_CANALES, &readAI, NULL);
	if (error > 0) { // warning when obtaining the samples 
		printf("DAQmxReadAnalogF64 ADVERTENCIA %d\n", error);
	} else if (error < 0) { // error when obtaining the samples
		printf("DAQmxReadAnalogF64 ERROR %d\n", error);
	}
	// this is to make sure that the time intervals correspond to the filling time of the entire buffer
	if ((uInt32)readAI != nSamples) { 
		printf("DAQmxReadAnalogF64 ERROR Muestras Leidas = %d Muestras disponibles = %d\n", readAI, nSamples);
	}

	// store the time for the next call
	QueryPerformanceCounter(&t_ini);

	return 0;
}

int main() {
	DWORD temp;

	Handle_Espera = CreateEvent(NULL, TRUE, FALSE, TEXT("Handle_Espera"));

	// creation and initialization of the task
	DAQmxCreateTask("AI_Tarea", &AI_Tarea);
	DAQmxCreateAIBridgeChan(AI_Tarea, "cDAQ9184-1BFBD04Mod2/ai0:3", "", MAGNITUD_MIN, MAGNITUD_MAX, DAQmx_Val_VoltsPerVolt, DAQmx_Val_FullBridge, DAQmx_Val_External, 9.0, 350, NULL);
	DAQmxCfgSampClkTiming(AI_Tarea, "", VELOCIDAD_MUESTREO, DAQmx_Val_Rising, DAQmx_Val_ContSamps, MUESTRAS_BUFFER);
	DAQmxRegisterEveryNSamplesEvent(AI_Tarea, DAQmx_Val_Acquired_Into_Buffer, MUESTRAS_BUFFER, 0, EveryNCallback, NULL);

	indice = 0;
	QueryPerformanceCounter(&t_ini);

	DAQmxStartTask(AI_Tarea);

	WaitForSingleObject(Handle_Espera, INFINITE);

	DAQmxStopTask(AI_Tarea);
	DAQmxWaitUntilTaskDone(AI_Tarea, -1);
	DAQmxClearTask(AI_Tarea);

	printf("Ingrese un numero para terminar: ");

	scanf_s("%d", &temp);

	return 0;
}
Result:
Tiempos:
        1.512656
        0.061836
        0.061815
        0.062108
        0.061618
        0.064241
        0.059541
        0.062228
        0.061497
        0.062573
Ingrese un numero para terminar:

Regards

0 Kudos
Message 9 of 11
(2,884 Views)
Solution
Accepted by topic author vbaptista

 

THIS is going to help make sense of it all.

 

Your 9237 device isn't capable of a sample rate as low as 1000 Hz.  When you request 1000 Hz, it will instead function at its lowest possible sample rate of 1613 Hz.  And thus, 100 samples requires (100/1613) seconds, exactly matching the 62 msec you've observed.

 

 

-Kevin P

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
Message 10 of 11
(2,880 Views)