02-07-2018 06:49 AM
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.
Solved! Go to Solution.
02-08-2018 07:00 PM
Hi vbaptista
What is more important for your application: to receive samples at 1khz or to receive samples every 100 milliseconds?
Regards
02-09-2018 10:49 AM
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.
02-14-2018 08:58 AM
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
02-14-2018 12:04 PM
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?
02-14-2018 04:45 PM
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
02-15-2018 05:16 AM
Yes, that example had already seen it but it does not help me with my problem.
Regards
02-15-2018 03:00 PM
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
02-16-2018 07:44 AM
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
02-16-2018 09:39 AM
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