From: Dave Hathaway on
I am using a Data Translation board to capture data. I want to capture data at 200Hz, but I am ending up with 140 samples/second.

My design is calling a timer every half second. I query the adaptor to see if data is available. For whatever reason, it seems to be available whenever 1000 samples are captured. That should be 5 seconds, but it is happening every 7 seconds or so. Why?

I'm posting code that is cleaned up a bit, so maybe I am missing something. Please ask, but maybe what's missing is the cause of my grief. I'm also posting some output.

I should note that I am compiling this, and can't presently run it interactively under MATLAB. It is running under the MCR. It's a hardware availability issue for now.

So questions:

Why am I not getting 200 samples per second?
How do I set the amount of data captured before it is available?

Dave

--- code ---


fprintf(handles.log,'Starting DAQ %s\n',datestr(now));

data.adaptor = 'dtol';
id = 0;
chan = 3;
data.sampleRate = 200;
data.cycleTime = .5;
ai = analoginput(data.adaptor, id);
addchannel(ai, 0:2, {'channel 0','channel 1','channel 2'});

data.ai = ai;
handles.ai = ai;
fprintf (handles.log,'samplerate = %g\n',data.sampleRate);
set(ai, 'SampleRate', data.sampleRate);
fprintf (handles.log,'TriggerRepeat\n');
set(ai, 'TriggerRepeat', inf);
fprintf (handles.log,'TriggerType\n');
set(ai, 'TriggerType', 'manual');

%% NOTE! setting the BufferingConfig crashes the program for some reason
% so it is commented out
% fprintf (handles.log,'BufferConfig [%g, %d]\n',data.sampleRate*2,20);
% set(ai, 'BufferingConfig',[data.sampleRate*2,20]);

% Initialize callback parameters. The TimerAction is initialized
% after figure has been created.
fprintf (handles.log,'TimerFcn\n');
set(ai, 'TimerFcn', @localtimer_callback);
fprintf (handles.log,'TimerPeriod=%f\n',data.cycleTime);
set(ai, 'TimerPeriod', data.cycleTime);
fprintf (handles.log,'cycletime = %g\n',data.cycleTime);

% set start time
data.starttime = now;

% save structures
data.handles = handles;
set(ai, 'UserData', data);
guidata(handles.output, handles);

% now, start it!
start(ai);
trigger(ai);


%% localtimer_callback
% The function that writes the data to the disk
function localtimer_callback(obj,event)
% Get the handles.
data = obj.UserData;
fh = data.handles.log;

timenow = event.Data.AbsTime;
fprintf(fh,'localtime_callback %s\n',datestr(timenow));
channels = 0;

if obj.SamplesAvailable > 0
fprintf (fh,'samples available @ %s\n',datestr(timenow));
[x, time] = getdata(obj);

trigger(data.ai); % trigger the data ASAP

len = size(x,1);
fprintf (fh,'samples available @ %s (len=%d)\n',datestr(timenow),len);

data.buffer(1:len,1) = time(1:len,1); % + data.starttime;
data.buffer(1:len,2) = x(1:len,1);

channels = size(x,2);
if channels>1
data.buffer(1:len,3) = x(1:len,2);
if channels>2
data.buffer(1:len,4) = x(1:len,3);
end
end

buffer = ctranspose(data.buffer);
% this program will data log, but to be safe for now, don't.
% fwrite(data.handles.fh, buffer, 'double')

data.len = len;
data.written = data.written + len;

set(data.ai, 'UserData', data);
end

tnow = timenow;

elapsed = etime(tnow, datevec(data.starttime));
set(data.handles.txtStatus,'String',...
sprintf('Written %d records in %g seconds (%g records/second)',...
data.written,elapsed,(data.written/elapsed)));


---- output -----

Starting DAQ 09-Jun-2010 15:53:07
samplerate = 200
TriggerRepeat
TriggerType
TimerFcn
TimerPeriod=0.500000
cycletime = 0.5
localtime_callback 09-Jun-2010 15:53:09
localtime_callback 09-Jun-2010 15:53:10
localtime_callback 09-Jun-2010 15:53:10
localtime_callback 09-Jun-2010 15:53:11
localtime_callback 09-Jun-2010 15:53:11
localtime_callback 09-Jun-2010 15:53:12
localtime_callback 09-Jun-2010 15:53:12
localtime_callback 09-Jun-2010 15:53:13
localtime_callback 09-Jun-2010 15:53:13
localtime_callback 09-Jun-2010 15:53:14
localtime_callback 09-Jun-2010 15:53:14
localtime_callback 09-Jun-2010 15:53:15
localtime_callback 09-Jun-2010 15:53:15
localtime_callback 09-Jun-2010 15:53:16
localtime_callback 09-Jun-2010 15:53:16
samples available @ 09-Jun-2010 15:53:16
samples available @ 09-Jun-2010 15:53:16 (len=1000)
localtime_callback 09-Jun-2010 15:53:17
localtime_callback 09-Jun-2010 15:53:17
localtime_callback 09-Jun-2010 15:53:18
localtime_callback 09-Jun-2010 15:53:18
localtime_callback 09-Jun-2010 15:53:19
localtime_callback 09-Jun-2010 15:53:19
localtime_callback 09-Jun-2010 15:53:20
localtime_callback 09-Jun-2010 15:53:20
localtime_callback 09-Jun-2010 15:53:21
localtime_callback 09-Jun-2010 15:53:21
samples available @ 09-Jun-2010 15:53:21
samples available @ 09-Jun-2010 15:53:21 (len=1000)
localtime_callback 09-Jun-2010 15:53:27
localtime_callback 09-Jun-2010 15:53:27
localtime_callback 09-Jun-2010 15:53:27
localtime_callback 09-Jun-2010 15:53:28
localtime_callback 09-Jun-2010 15:53:28
localtime_callback 09-Jun-2010 15:53:29
localtime_callback 09-Jun-2010 15:53:29
localtime_callback 09-Jun-2010 15:53:30
localtime_callback 09-Jun-2010 15:53:30
localtime_callback 09-Jun-2010 15:53:31
localtime_callback 09-Jun-2010 15:53:31
localtime_callback 09-Jun-2010 15:53:32
samples available @ 09-Jun-2010 15:53:32
samples available @ 09-Jun-2010 15:53:32 (len=1000)
localtime_callback 09-Jun-2010 15:53:32
localtime_callback 09-Jun-2010 15:53:33
localtime_callback 09-Jun-2010 15:53:33
localtime_callback 09-Jun-2010 15:53:34
localtime_callback 09-Jun-2010 15:53:34
localtime_callback 09-Jun-2010 15:53:35
localtime_callback 09-Jun-2010 15:53:35
localtime_callback 09-Jun-2010 15:53:36
localtime_callback 09-Jun-2010 15:53:36
localtime_callback 09-Jun-2010 15:53:37
samples available @ 09-Jun-2010 15:53:37
samples available @ 09-Jun-2010 15:53:37 (len=1000)
From: Dave Hathaway on
"Dave Hathaway" <david.hathaway(a)aecom.com> wrote in message <huots2$7lm$1(a)fred.mathworks.com>...
> I am using a Data Translation board to capture data. I want to capture data at 200Hz, but I am ending up with 140 samples/second.

As an update, and perhaps to stir up help, I wondered if the order of the commands were messing up the sample rate. So I inserted code to log the adapter's stored sample rate. The code in the timer callback looks like this...

function localtimer_callback(obj,event)
% Get the handles.
data = obj.UserData;
fh = data.handles.log;

timenow = event.Data.AbsTime;
fprintf(fh,'localtime_callback %s\n',datestr(timenow));

fprintf (fh,'samplerate = %g or %g\n',...
data.sampleRate, get(obj, 'SampleRate'));
fprintf (fh,'SamplesPerTrigger = %g or %g\n',...
data.samplesPerTrigger, get(obj, 'SamplesPerTrigger'));

channels = 0;

if obj.SamplesAvailable > 0
fprintf (fh,'samples available @ %s\n',datestr(timenow));

....etc

And here is the log output

localtime_callback 10-Jun-2010 12:06:52
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:52
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:53
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:53
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:54
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:54
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:55
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:55
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:56
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:56
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:57
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:57
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:58
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:58
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
localtime_callback 10-Jun-2010 12:06:59
samplerate = 200 or 199.997
SamplesPerTrigger = 400 or 400
samples available @ 10-Jun-2010 12:06:59
samples available @ 10-Jun-2010 12:06:59 (len=400)

So, I specifying 200 samples per second, and to make the data available after 400 samples are collected. There is a little loss of sample rate, 199.997 versus 200, but that is peanuts compared to taking 7 seconds to collect 400 samples.

What can be wrong?

BTW, when I do this with the winsound device, I am getting close to 4900 samples / second compared to a requested 5000, and it is getting closer each tick. I think long term it is getting close to right, but there are start up issues.

Dave
From: Dave Hathaway on
"Dave Hathaway" <david.hathaway(a)aecom.com> wrote in message <hur3di$5kh$1(a)fred.mathworks.com>...
> "Dave Hathaway" <david.hathaway(a)aecom.com> wrote in message <huots2$7lm$1(a)fred.mathworks.com>...
> > I am using a Data Translation board to capture data. I want to capture data at 200Hz, but I am ending up with 140 samples/second.
>
> As an update, and perhaps to stir up help, I wondered if the order of the commands were messing up the sample rate. So I inserted code to log the adapter's stored sample rate. The code in the timer callback looks like this...


A further update. I stuck a bunch of debugging code in there, and noticed some really odd timings. In short, I put tic/toc around the call to getdata.

tStart = tic;

[x, time] = getdata(obj);

tElapsed = toc(tStart);
fprintf(fh,'getdata time = %f\n', tElapsed);

This is what I get:

getdata time = 0.020690
getdata time = 5.041098
getdata time = 0.002076
getdata time = 4.903633

For some reason, getting every other buffer full is taking as long as the time to collect the data. I am collecting 200 samples/second and the buffer is 1024 bytes long, so collection time is about 5 seconds.

I'm not sure where the fault lies. This is mysterious to me.

Dave
From: Walter Roberson on
Dave Hathaway wrote:

> A further update. I stuck a bunch of debugging code in there, and
> noticed some really odd timings. In short, I put tic/toc around the
> call to getdata.
> tStart = tic;
>
> [x, time] = getdata(obj);
>
> tElapsed = toc(tStart);
> fprintf(fh,'getdata time = %f\n', tElapsed);
>
> This is what I get:
>
> getdata time = 0.020690
> getdata time = 5.041098
> getdata time = 0.002076
> getdata time = 4.903633
>
> For some reason, getting every other buffer full is taking as long as
> the time to collect the data. I am collecting 200 samples/second and
> the buffer is 1024 bytes long, so collection time is about 5 seconds.
>
> I'm not sure where the fault lies. This is mysterious to me.

Hmmmmm...

Suppose that by the time you issued the getdata() call, new data had started
arriving: would the getdata() call not then wait until the buffer was full
before delivering the data? I don't know if there is a way to double-buffer
the data so that there is a buffer to read the data out of while the new data
arrives.

Recently someone showed some code they were using with a serial port object to
trigger when the data buffer was ready rather than using a timer callback.
Perhaps it would be possible to use that? See
http://groups.google.ca/group/comp.soft-sys.matlab/browse_thread/thread/8c4954180a2e7f15/e22243c3f2e76a47
for sample code, and remember to set the actual buffer to be bigger than the
number of bytes triggered at so that no bytes are discarded while waiting for
the interrupt to be serviced.
From: Dave Hathaway on
Walter Roberson <roberson(a)hushmail.com> wrote in message <hurorq$61m$1(a)canopus.cc.umanitoba.ca>...
> Hmmmmm...
>
> Suppose that by the time you issued the getdata() call, new data had started
> arriving: would the getdata() call not then wait until the buffer was full
> before delivering the data? I don't know if there is a way to double-buffer
> the data so that there is a buffer to read the data out of while the new data
> arrives.
>
> Recently someone showed some code they were using with a serial port object to
> trigger when the data buffer was ready rather than using a timer callback.
> Perhaps it would be possible to use that? See
> http://groups.google.ca/group/comp.soft-sys.matlab/browse_thread/thread/8c4954180a2e7f15/e22243c3f2e76a47
> for sample code, and remember to set the actual buffer to be bigger than the
> number of bytes triggered at so that no bytes are discarded while waiting for
> the interrupt to be serviced.

I looked at the code you suggested and might try that. Thank you.

But there a couple things puzzling me:

1) I do a getdata and it takes .02 seconds. So I could see the collection being lost for those .02+ seconds between the buffer being full, my knowing it is full (the timer goes every .5 seconds), and my draining the data. But why would the getdata call itself take 5 seconds?

2) I specify a buffer twice as large as the data I am reading. My thought is that while I am reading the first half of the buffer, the second half is being filled... assuming data collection continues after the buffer fills. I'm not sure it does.

The hardware vendor is talking about there being some USB latency issue with such a slow sample rate. I don't understand that at all. Seems like any modern system should be able to handle 200 samples/second in it's sleep.

I'm still seeking a solution, and am turning to the suggested SamplesAcquired technique.

Dave
 |  Next  |  Last
Pages: 1 2
Prev: Unexplainable Mex Error
Next: OpenGL performance