Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

Continuous acquisition with DAQmx and logging to disk





Hi,



 



I’m trying
to build an MFC application with MSVC++6, where I would continuously acquire
samples on 8 analog channels of a USB-6008. I’m using the DAQmx C functions.  The sampling rate is rather low (100 Hz), but
it is important that all the sample values are written to disk. Also, I want to
read the digital lines every second (that part is easy by using the Timer class
in MFC).



 



So I tried
this C example code: ContAcq-IntClk.c. 
It explains how to acquire data continuously, using a callback
function.  I took a modified version of
this program where it saves the data on disk. I tried different values, but I
can’t get all the data written, there are always gaps (
dropped values).



 



What I
would like to achieve is that: when more than half of the internal buffer is
filled, the first half is written to disk. After that, when the buffer is
completely filled and start to be filled from its beginning, the second half is
written to disk and so on.
But now I'm lost, I have no idea of how to achieve that. :smileysad:



 



It would be
greatly appreciated if you could tell me how to code it in C++.



 



Thank you
in advance




Marc Melillo

marc.melillo@umontreal.ca


0 Kudos
Message 1 of 11
(6,269 Views)

Hi Marc,

 

Can you please explain what your mean by dropped values? Are you receiving any buffer errors? To achieve your goal, you can set the buffer size and then read half the values. NI-DAQmx help has information on how to use the set buffer size function. To access help, go to Start » Programs » National Instruments » NI-DAQmx C Reference Help. You can search for buffer or set buffer size once you have the help open.

 

Thank you,

Simran K
National Instruments
Applications Engineer
0 Kudos
Message 2 of 11
(6,252 Views)

Hi Simran,

 

Thank you for replying. I ran a test using a sampling rate of 200 Hz, with a buffer of 10K samples.  The callback function is called each 5K samples acquired. I put the values in Excel and made that graph:

[IMG]http://i472.photobucket.com/albums/rr88/melimelo/graphdata.jpg[/IMG]

 

The analog signal is a perfect sine wave. The x axis is not exactly the time, because it's a simple curve graph in Excel, using one column of data. The gaps in the values can be seen on the graph. There are also strange values in the data on disk: it seems that some values are "truncated", i.e. normally they values are between -5 and 2 (floating point), but some show up like -2.354529-2.354529  or 6568.  It's like some characters used to represent the values are missing.

 

Here is the source code:


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

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

int32 CVICALLBACK EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData);
int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData);

int main(void)
{
    int32       error=0;
    TaskHandle  taskHandle=0;
    char        errBuff[2048]={'\0'};

    /*********************************************/
    // DAQmx Configure Code
    /*********************************************/
    DAQmxErrChk (DAQmxCreateTask("",&taskHandle));
    DAQmxErrChk (DAQmxCreateAIVoltageChan(taskHandle,"Dev1/ai0","",DAQmx_Val_Cfg_Default,-10.0,10.0,DAQmx_Val_Volts,NULL));
    DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandle,"",200.0,DAQmx_Val_Rising,DAQmx_Val_ContSamps,10000));


    DAQmxErrChk (DAQmxRegisterEveryNSamplesEvent(taskHandle,DAQmx_Val_Acquired_Into_Buffer,5000,0,EveryNCallback,NULL));
    DAQmxErrChk (DAQmxRegisterDoneEvent(taskHandle,0,DoneCallback,NULL));

    /*********************************************/
    // DAQmx Start Code
    /*********************************************/
    DAQmxErrChk (DAQmxStartTask(taskHandle));

    printf("Acquiring samples continuously. Press Enter to interrupt\n");
    getchar();

Error:
    if( DAQmxFailed(error) )
        DAQmxGetExtendedErrorInfo(errBuff,2048);
    if( taskHandle!=0 ) {
        /*********************************************/
        // DAQmx Stop Code
        /*********************************************/
        DAQmxStopTask(taskHandle);
        DAQmxClearTask(taskHandle);
    }
    if( DAQmxFailed(error) )
        printf("DAQmx Error: %s\n",errBuff);
    printf("End of program, press Enter key to quit\n");
    getchar();
    return 0;
}

int32 CVICALLBACK EveryNCallback(TaskHandle taskHandle, int32 everyNsamplesEventType, uInt32 nSamples, void *callbackData)
{
    int32       error=0;
    char        errBuff[2048]={'\0'};
    static int  totalRead=0;
    int32       read=0;
    float64     data[5000];
    int i;
    FILE *datafile;
    datafile = fopen("testdata","a");
    /*********************************************/
    // DAQmx Read Code
    /*********************************************/
    DAQmxErrChk (DAQmxReadAnalogF64(taskHandle,5000,10.0,DAQmx_Val_GroupByScanNumber,data,5000,&read,NULL));
    if( read>0 ) {
        printf("Acquired %d samples. Total %d\r",read,totalRead+=read);
        for (i=0;i<=5000;i++){
            fprintf(datafile,"%f\n",data[i]);
        }
        fflush(stdout);
    }

Error:
    if( DAQmxFailed(error) ) {
        DAQmxGetExtendedErrorInfo(errBuff,2048);
        /*********************************************/
        // DAQmx Stop Code
        /*********************************************/
        DAQmxStopTask(taskHandle);
        DAQmxClearTask(taskHandle);
        printf("DAQmx Error: %s\n",errBuff);
    }
    return 0;
}

int32 CVICALLBACK DoneCallback(TaskHandle taskHandle, int32 status, void *callbackData)
{
    int32   error=0;
    char    errBuff[2048]={'\0'};

    // Check to see if an error stopped the task.
    DAQmxErrChk (status);

Error:
    if( DAQmxFailed(error) ) {
        DAQmxGetExtendedErrorInfo(errBuff,2048);
        DAQmxClearTask(taskHandle);
        printf("DAQmx Error: %s\n",errBuff);
    }
    return 0;
}

 

Obviously, I do something wrong, but I can't spot it. Can you help please?

 

Thank you in advance,

Marc Melillo

0 Kudos
Message 3 of 11
(6,219 Views)

Hi, I have done nearly the same, so it should be possible. Here are some suggestions:

 

You can set some flags for the buffering like DAQmxErrChk( DAQmxSetReadOverWrite(m_taskHandle,DAQmx_Val_DoNotOverwriteUnreadSamps) ); but then you must be

sure to keep up with the system.

 

In DAQmxReadAnalog you can use -1 to read all available samples?

 

And maybe you can keep the output file open, until finished?

 

-cpede

0 Kudos
Message 4 of 11
(6,211 Views)

Hi cpede,

 

Thank you for answering.  I tried the DAQmxSetReadOverWrite() function as you said, I tried also to put -1 instead of 500, I even tried to put the DAQmx read function as the very first function inside the callback function, but with no luck.  I did another test, this time using a ramp function instead of a sine wave. The ramp is not very smooth because I generated it manually by slowly turning a potentiometer.

 

 

You can clearly see on this graph that some portions are misplaced, so that leads me to a problem in the reading position in the internal buffer. BTW, that test  had 3 calls of the callback function, 25 seconds each (200Hz*5000 samples). Does this rings you a bell?

 

Again, thank you in advance

Marc Melillo

marc.melillo@umontreal.ca 

0 Kudos
Message 5 of 11
(6,191 Views)

Hi Marc,

 

Can you please run the original example without modifications and see if you receive all the data without any gaps? If you do, there could be a problem with the File I/O portion of the code. How are you writing the data to the disk?

 

Thank you,

Simran K
National Instruments
Applications Engineer
0 Kudos
Message 6 of 11
(6,170 Views)

Hi Sirman,

 

As the original ContAcq-IntClk.c file doesn't save data to disk, I took the modified version by Saha at National Instruments (can by found here). Her version works fine, but it saves just the first 100 data of the buffer, not the whole buffer as I want. And really, I can't see something wrong with my disk I/O part:

        for (i=0;i<=5000;i++){
            fprintf(datafile,"%f\n",data[i]);
        }

 

Anyway, I added these line right after the DAQmxCfgSampClkTiming() function:

 

    DAQmxErrChk (DAQmxCfgInputBuffer (taskHandle, 10000));
    DAQmxErrChk( DAQmxSetReadOverWrite(taskHandle,DAQmx_Val_DoNotOverwriteUnreadSamps) );
 

And at the beginning of the callback function, I added these three function calls, around the DAQmxReadAnalogF64() function.

 

    DAQmxErrChk (DAQmxGetReadCurrReadPos(taskHandle, &readpos));
    DAQmxErrChk (DAQmxGetReadAvailSampPerChan(taskHandle, &availdata));
    DAQmxErrChk (DAQmxReadAnalogF64(taskHandle,5000 ,10.0,DAQmx_Val_GroupByScanNumber,data,5000,&read,NULL));
    DAQmxErrChk (DAQmxGetBufInputBufSize(taskHandle, &bufsize));


In the printf statement, I added the readpos, availdata and bufsize variables. I got these values:

 

read        total       Readpos     Bufsize     Availdata

5000        5000            0       0           10000

5000       10000         5000       0           10000  

5000       15000        10000       0           10000

5000       20000        15000       0           10000

 

I'm confused with those results.  Why Bufsize (returned by the DAQmxGetBufInputBufSize() function) is 0, and not 10000 (the actual size of the internal buffer, I think)?  And why Readpos (returned by the  DAQmxGetReadCurrReadPos() function) keeps growing by a value of 5000? The input buffer being circular, I would think that the current read position would flip between 0 and 5000 (i.e. 0, 5000, 0, 5000, 0, 5000, ...). And why Availdata (returned by the DAQmxGetReadAvailSampPerChan() function) is 10000? Isn't supposed to be 5000, given that the callback function is called every 5000 samples acquired? 

 

At the risk of repeating myself, What I would like to achieve is that: when more than half of the internal buffer is filled, the first half is written to disk. After that, when the buffer is completely filled and start to be filled from its beginning, the second half is written to disk and so on.

 

Your help is greatly appreciated.

 

Thank you in advance

Marc Melillo

marc.melillo@umontreal.ca

0 Kudos
Message 7 of 11
(6,156 Views)

Hi Marc,

 

What happened when you tired the solution I mentioned in my first post? Were you able to set the buffer size and read half the buffer at a time?

 

Thank you,

Simran K
National Instruments
Applications Engineer
0 Kudos
Message 8 of 11
(6,108 Views)

Hi Sirman,

 

This is what I'm trying to do. If you look at the code in my second post,  you can see that it is supposed to read in alternance both halves of the entire buffer. And it gives me the scrambled results you can see in the graphs. Maybe I should forget about the DAQmxRegisterEveryNSamplesEvent() function, and do my own thread creation. But then I would have to know at what place in the entire buffer the writing of the data is taking place, and I would have to set the exact place to start the transfer of the data from the internal buffer to my own array. BUT, for doing that, I suppose that I would need the DAQmxGetReadCurrReadPos() and maybe the DAQmxSetReadOffset() functions. But really, I don't know how, and the strange results I get in my last post make me have serious doubts that it could be done that way.

 

Do you have any clues about this?

Thank you in advance

 

Marc Melillo

marc.melillo@umontreal.ca

0 Kudos
Message 9 of 11
(6,092 Views)

Hi Marc,

 

I looked through your code, Saha's code and the original example that comes with the driver. We need to narrow down the problem and for that we need to test the code separately. I see that your configuration settings are different from the original sample and Saha's code. I want you to run the original example code (without any modifications) and tell me if everything works properly. Once we know everything works properly with the default settings, we will try to run the code using your configuration settings. If everything works there, then we will add the saving to disk part. File I/O can slow your program and we really need to narrow down the problem to a particular area. Right now we are not even sure if acquisition is causing the problem or storing the data.

 

If you have NI-DAQmx installed, the original example is located on your computer at a path similar to C:\Documents and Settings\All Users\Documents\National Instruments\NI-DAQ\Examples\DAQmx ANSI C\Analog In\Measure Voltage\Cont Acq-Int Clk.

 

Please let me know if you have any questions.

 

Thank you,

Simran K
National Instruments
Applications Engineer
0 Kudos
Message 10 of 11
(6,048 Views)