How can I achieve continuous analog output using the Data Acquisition Toolbox 2.11 (R2007b)?

7 views (last 30 days)
I have a large data set that I want to output from a data acquisition device in a continuous manner (by dividing it into small chunks) using the Data Acquisition Toolbox. Note that I do not want to output the same piece of data repeatedly, but rather, iterate through my large data set and output it in small intervals without any breaks in the output.
Currently, I am using the "SamplesOutputFcn" callback associated with the data acquisition device that works only with a single chunk of data:
%sample data size
datasize = 150000;
%sample output rate
fs=96000;
% Build sample data
t=linspace(0,2*pi,131072);
data=sin(100*t);
data=data';
% Construct analog output object
ao=analogoutput('winsound',0);
addchannel(ao,1);
%Set properties for analog output object
set(ao, 'BufferingMode', 'Auto')
set(ao,'TriggerType','Immediate');
set(ao,'SampleRate',fs);
% Configure callback to regularly queue chunks of data
set(ao,'SamplesOutputFcn',{'queuedata',data});
set(ao,'SamplesOutputFcnCount',datasize);
% Queue the data in the analog output buffer and start data output
putdata(ao,data);
start(ao)
The SamplesOutputFcn callback (queuedata) written is as follows:
function queuedata(obj,event,data)
putdata(obj,data);
start(obj)
end
However, when I execute the above code, there are breaks in the data every N number of samples where:
N = datasize
I would like to achieve truly continuous analog output without any breaks in the data.

Accepted Answer

MathWorks Support Team
MathWorks Support Team on 18 Oct 2013
By setting the "SamplesAcquiredFcnCount" property of the analog output device to be the same as the length of the data being queued, it is almost guaranteed that there will be gaps in the output.
One alternative is to set the "SamplesAcquiredFcnCount" to be less than the length of data being queued, such that data is put into the analog output device queue before the queue is emptied. For example, you may change the previous program in the following manner:
set(ao,'SamplesOutputFcnCount',0.9*datasize);
A more reliable option is to use the "TimerFcn" callback. The nature of TimerFcn callbacks is that there is only one of them queued up at any given time. While the SamplesAcquiredFcn callbacks are guaranteed to run, they start taking longer to execute than the frequency with which they are called, and eventually they will queue up and wait.
TimerFcn's on the other hand are discarded if there is already one in the queue. Following is an example that uses the TimerFcn property to achieve continuous analog output. This example uses the Windows sound card via the WINSOUND adaptor:
%%Create ANALOGOUTPUT device and add 1 channel to it (mono)
ao=analogoutput('winsound',0);
addchannel(ao,1);
%%Configure Analog Output
set(ao, 'BufferingMode', 'Auto')
set(ao,'TriggerType','Immediate');
%Define output samples per second as necessary
set(ao,'SampleRate',fs);
%%configure callback to quuee another chunk of data
% set(ao,'SamplesOutputFcn',{'qmoredata',data});
% set(ao,'SamplesOutputFcnCount',bufsize);
% Use a TimerFcn to queue the next chunk of data
set(ao,'TimerFcn',{'qmoredataForTimerFcn',data});
% Set the Timer to fire when 90% of the buffer has been output
set(ao,'TimerPeriod',(bufsize/ao.SampleRate)*0.9);
%run the machine
putdata(ao,data);
start(ao)
% Examine how much data is in the queue.
for ii=1:100
ao.SamplesAvailable
pause(1)
end
stop(ao)
% Delete ANALOGOUTPUT object when you are done
delete(ao)
clear ao
You may notice that the callback is triggered a little before the buffer runs out of data. It is very important not to starve the running ANALOGOUTPUT object as it will stop and you will notice a discontinuity (or space) between each data output (as in the case of the SamplesOutputFcn used previously). A FOR loop is used at the end of the main program that shows how many samples are available.
The following is example code that illustrates the working of the "qmoredataForTimerFcn" callback (referenced in the code above):
function qmoredataForTimerFcn(obj,event,data)
% We would like to make sure we are not going to over run the buffer
% If we do, the PUDATA function become a blocking function
% That is, we will no longer have access to the command line
% Use any ONE of the next two IF statements.
% This one guarantees that we will never get more than twice the amount
% of data we have to queue.
% if (obj.SamplesAvailable + length(data)) >= length(data)*2
% This one will continue to add to the queue until adding more would
% cause PUTDATA to block.
if (obj.SamplesAvailable + length(data)) >= obj.MaxSamplesQueued
return
end
% Else, It is safe to put the data.
putdata(obj,data);
% Restart the object only if it is not already running.
if strcmp(obj.Running, 'Off')
start(obj)
end
end
In this example, we look at how many samples are still in the engine's queue and how many we have been requested to add to the queue. If the sum is greater than what we require, we return without queuing more data.
Two criteria can be used to ensure that we do not queue more data that necessary:
1. Twice the length of the data.
2. MaxSamplesQueued.
Note that with the second approach, queueing more data than MaxSamplesQueued will cause the PUTDATA function to block the command line. Therefore, if there is room in the queue, we queue the new data and then restart the object only if it had stopped.
You can tweak the TimerPeriod property and the samples available threshold to suit your particular application and data acquisition device.

More Answers (0)

Categories

Find more on Simulink Functions in Help Center and File Exchange

Products


Release

R2007b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!