Measurement Studio for .NET Languages

cancel
Showing results for 
Search instead for 
Did you mean: 

problems with asynchronous acquisition and NI-DAQmx

hi,
 
I am having some problems on continuous acquisition. I'm using Visual Studio 2005 with Windows XP. 
 
I would like to collect data in every 0.2s and the sample rate is 3.2kHz. The prossess is as follows:
 
I use the method AnalogMultiChannelReader.BeginReadMultiSample to  install a callback and begin the asynchronous read operation. Inside the callback, call AnalogMultiChannelReader.EndReadMultiSample to  retrieve the data from the read.   Call AnalogMultiChannelReader.BeginReadMultiSample again inside the  callback to perform another read.
 
In order to do some calculations, in the callback function, I performed my own-defined function which takes a little while. So when I run my task, there will be an error:
Attempted to read samples that are no longer available.
The requested sample was previously available, but has since been overwritten.

Increasing the buffer size, reading the data more frequently, or specifying a fixed number of samples to read instead of reading all available samples might correct the problem.

Property: RelativeTo
Corresponding Value: Current Read Position

Property: Offset
Corresponding Value:

Task Name: _unnamedTask<1>
By the way, I've tried to set the overwrite mode by
myTask.Stream.ReadOverwriteMode = ReadOverwriteMode.OverwriteUnreadSamples
There will be the same mistake.
 
If you have any suggestions to fix the problem, they are greatly appreciated. Let me know if I can provide more information, too. Thank you for your consideration.


Message Edited by zydllh on 03-18-2008 04:58 AM
Kevin Lee
0 Kudos
Message 1 of 12
(7,661 Views)
Hi Kevin,

The message you are seeing will occur when the input task is configured to overwrite unread samples but the sample requested has since been overwritten and is unavailable.  It is important to remember that in your case, while you are performing your calculations and analysis, the underlying DAQmx circular buffer is still being filled up with data.  Allow me to explain a little more...

When a continuous operation reaches the end of the buffer, it returns to the beginning and fills up the same buffer again.  Now your application must retrieve data in blocks, from one location in the buffer, while the data enters the circular buffer at a different location, so newer data does not overwrite unread data.  Now here's the catch... 

While a circular buffer works well in many applications, two possible problems can occur with this type of acquisition: Your application might try to retrieve data from the buffer faster than data is placed into it, or your application might not retrieve data from the buffer before NI-DAQmx overwrites the data into the buffer.  When your application tries to read data from the buffer that has not yet been collected, NI-DAQmx waits for the data to be acquired and then returns the data. If your application does not read the data from the circular buffer fast enough, you receive an error, stating that some data has been overwritten and lost. If losing data in this way is not important to you, change the setting of the DaqStream.ReadOverWriteMode property.  So for example, suppose you had a Task object named inputTask. Therefore to set this property you would say something like:

inputTask.Stream.ReadOverwriteMode = ReadOverwriteMode.OverwriteUnreadSamples;

As the error mentions, you can also slow down your sampling rate or increase your buffer size to avoid this scenario. 

Hope this helps!

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 2 of 12
(7,635 Views)
Hi Jonathan,
 
Thank you for your help.
 
Base on the information mentioned in your reply, If I set ReadOverwriteMode property to OverwriteUnreadSamples, it seems that if my calculation does not perform fast enough, it could result in the error message:Attempted to read samples that are no longer available.... 
 
I am a little confused about this situation. Since the buffer has already been filled with new data,  when I perform the read operation, why can't I get the new data in the buffer?
 
Kevin
 
 
Kevin Lee
0 Kudos
Message 3 of 12
(7,632 Views)
Hi Kevin,

Are you actually getting this error message when you set that property or are you just wondering if it will occur? 

You shouldn't see this message at all when you set that property to OverwriteUnreadSamples.  When you set this property, you will be in 2 scenarios which are:

1) Your calculations take a very long time - In this case, this means that your application won't
retrieve data from the buffer before NI-DAQmx overwrites the data into the buffer. Therefore you will lose some samples since the chunk you were going to read has now been overwritten with new data.

2) Your calculations don't take long at all - Well in this case, data won't be overwritten because you are retrieving data from the buffer before DAQmx overwrites it.  Therefore you will not lose any samples. 

Make sense?

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 4 of 12
(7,624 Views)

Hi Jonathan,

Thanks for your reply.

Sorry about the unclarity I've made. I do set ReadOverwriteMode property to OverwriteUnreadSamples by myTask.Stream.ReadOverwriteMode = ReadOverwriteMode.OverwriteUnreadSamples before I call the method BeginReadMultiSample and I still get the error message: Attemp to read samples that are no longer available...

In my case, my calculations indeed take quite long time and probably the previous data are overwritten by the new ones.

But since I have already set the property, I do think the read operation could gain the new data in the buffer rather than an error message. Is there any possible that I misunderstand the property?

Thanks again.



Message Edited by zydllh on 03-21-2008 04:35 AM
Kevin Lee
0 Kudos
Message 5 of 12
(7,611 Views)
Hi Kevin,

Are you setting this propery in your callback before you call BeginReadMultiSample or outside of your callback before you initially call BeginReadMultiSample?  You should be setting it before you first call ever to BeginReadMultiSample. For example, you should be saying something like:

myTask.AIChannels.CreateVoltageChannel(.....);
myTask.Timing.ConfigureSampleClock(.....);
myTask.
Stream.ReadOverwriteMode = ReadOverwriteMode.OverwriteUnreadSamples;
.....
reader.BeginReadMultiSample(..., analogCallback,.....)

private void AnalogInCallback(IAsyncResult ar)
{
     data = analogInReader.EndReadMultiSample(ar);
    // Do your calculataions
    analogInReader.BeginReadMultiSample(...., analogCallback, ...)
}


That's a very basic outline of how you should be setting up your code.

Now if you are setting up your code that way, then let me know.

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 6 of 12
(7,607 Views)
Hi Kevin,

One other small piece of information I forgot to mention which affects your scenario is that you also need to set where in the buffer to read samples.  The place where a read begins is called the Current Read Position. Each time data is read, the Current Read Position is computed based on the settings of the ReadRelativeTo and ReadOffset properties.  So in your case, you need to make sure that you set the ReadOverwriteMode property before reading anything (i.e. either before starting the task or making the first call the read) and you need to set the ReadRelativeTo property to MostRecentSample.  So you should say something like:

myTask.Stream.ReadOverwriteMode = ReadOverwriteMode.OverwriteUnreadSamples;
myTask.Stream.ReadRelativeTo = ReadRelativeTo.MostRecentSample;


Hope this helps!

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 7 of 12
(7,600 Views)
Hi Jonathan,
 
Thanks for your reply.
 
I have set the property just like the way you mentioned:
 
myTask.AIChannels.CreateVoltageChannel(.....);
myTask.Timing.ConfigureSampleClock(.....);
myTask.
Stream.ReadOverwriteMode = ReadOverwriteMode.OverwriteUnreadSamples;
.....
reader.BeginReadMultiSample(..., analogCallback,.....)

private void AnalogInCallback(IAsyncResult ar)
{
     data = analogInReader.EndReadMultiSample(ar);
    // Do your calculataions
    analogInReader.BeginReadMultiSample(...., analogCallback, ...)
}

In this case, I got the error message mentioned before.
 
But If I  set the ReadRelativeTo property by
myTask.Stream.ReadOverwriteMode = ReadOverwriteMode.OverwriteUnreadSamples;
myTask.Stream.ReadRelativeTo = ReadRelativeTo.MostRecentSample;
It works well, no error is reported.
 
But if I configure the property this way, when I perform the read operation which samples do I get?
For example,  Suppose the buffer size is 1kS, and the last sample before read is the 50th sample. So when I do the read operation(say read 10 samples at a time), it will wait until the buffer is filled with 60 samples.But in the waiting process, the NI-DAQ is still sampling. Since MostRecentSample is changing all the time. I wonder how the read perfoms.
 
Thanks again.


Message Edited by zydllh on 03-22-2008 10:13 AM
Kevin Lee
0 Kudos
Message 8 of 12
(7,586 Views)
Hi Jonathan,
 
I have tried to gain the most 704 samples setting:
myTask.Stream.ReadOverwriteMode = ReadOverwriteMode.OverwriteUnreadSamples;
myTask.Stream.ReadRelativeTo = ReadRelativeTo.MostRecentSample;
myTask.Stream.ReadOffset = -704;
 
But I got the error message:Invalid combination of position and offset. The position and offset specified a sample prior to the first sample acquired(sample 0). Make sure any negative read offset specified will select a valid sample when combined with the read operation.
 
Is there any limitations about these properties when performing coutinous read operations?
 
Thanks
Kevin Lee
0 Kudos
Message 9 of 12
(7,577 Views)
Hi Kevin,

I first wanted to mention that all these concepts you are asking about are documented in the NI-DAQmx Help under the Buffering section.  It is very important that you read through these topics in order to properly code your DAQmx application and understand what some of these properties are actually doing.  Plus, I might be confusing you even more when I mention certain DAQmx terminology that you may or may not be familiar with.  Therefore I am strongly suggesting you to read over those topics which will help you understand why you are running into these issues.  You can open the NI-DAQmx Help by selecting Start >> All Programs >> National Instruments >> NI-DAQ >> NI-DAQmx Help. One that help is opened, switch to the Contents tab and navigate to NI-DAQmx Help >> NI-DAQmx Key Concepts >> Reading and Writing Data >> Buffering

I also wanted to mention that the code snippets I posted where intended to simply show you what properties you needed to set and how to find them.  I wasn't expecting you to take the code and use it directly since its important to understand what that code is doing and where to place it code depending upon what your needs are. The reason I am stating that is because the place in your code where you are setting the ReadRelativeTo and ReadOffset properties is incorrect in your scenario.  You need to set these properties in your callback in between the EndReadMultiSample and BeginReadMultiSample calls. I will try and be clearer in the future.  Now, onto your current issue..  There is a fundamental concept that I must explain first...

The place where a read begins is called the Current Read Position. Each time data is read, the Current Read Position is computed based on the settings of the ReadRelativeTo and ReadOffsetReadRelativeTo is Current Read Position. When there is a Reference Trigger, the default for ReadRelativeTo is First Pretrigger Sample. In either case, the default for ReadOffset is 0. Changing the settings of these two properties controls where in the buffer data is read.  Now, after placing the read position, the ReadOffset is added to determine where the read takes place.  Now in your case, the current read position is actually set to 0 before the EndReadMultiSample method is called. Thus added a value of -704 will cause that error you are seeing. Therefore you need to do some logic in your callback to decide what to set these properties to. Here is a quick code snippet you can use. 

// Read the available data from the channels
data = analogInReader.EndReadMultiSample(ar);

// Do some calculations
               
long freshSamples = myTask.Stream.TotalSamplesAcquiredPerChannel - myTask.Stream.CurrentReadPosition;

if (freshSamples < myTask.Stream.AvailableSamplesPerChannel)
{
    myTask.Stream.ReadRelativeTo = ReadRelativeTo.CurrentReadPosition;
    myTask.Stream.ReadOffset = 0;
}
else
{
    myTask.Stream.ReadRelativeTo = ReadRelativeTo.MostRecentSample;
    myTask.Stream.ReadOffset = -(int)myTask.Stream.AvailableSamplesPerChannel;
}

analogInReader.BeginReadMultiSample(...);


Hope this helps!

Best Regards,
Jonathan N.
National Instruments
0 Kudos
Message 10 of 12
(7,558 Views)