Data Acquisition Toolbox

Measuring a Noise Floor Using Custom Trigger Conditions

This example shows how to find and acquire a period of at least 2 seconds of relative quiet that occurs between two signals. This would be useful for applications that need to measure a noise floor and calculate a signal-to-noise ratio.

For this example we will show how to initiate a software trigger when using a custom set of conditions that is more complex than the standard values provided by the TriggerCondition property of Data Acquisition Toolbox™ objects.

Note: This can only be run using the 32-bit version of MATLAB® and Data Acquisition Toolbox™. To learn more about using data acquisition devices on other platforms, see this example.

First, find any running data acquisition objects and stop them. This stops all running data acquisition objects from interfering with this example. This code is usually not necessary outside this example unless there are multiple data acquisition objects running.

if (~isempty(daqfind))
    stop(daqfind)
end

Create the Analog Input Object

Before acquiring any data, we must create an analog input object and specify the channels from which to acquire data.

When executing the following code, you may need to modify it to match your acquisition hardware.

% Create the analog input object and specify the
% channel that data should be collected from.
ai = analoginput('winsound');
addchannel(ai, 1);

Define Trigger Condition Information

We must initialize a MATLAB® structure with the information needed to determine when the custom trigger condition has been met. We look for

  • A signal

  • At least 2 seconds of quiet

% Signal is defined as greater than 0.15 volts.
extraData.signalVoltage = 0.15;
extraData.signalFound = false;

% Quiet is defined as less than 0.04 volts.
extraData.quietVoltage = 0.04;
extraData.secondsOfQuietNeeded = 2;
extraData.secondsOfQuietFound = 0;
extraData.quietFound = false;

We store this information in the UserData property so that it can be accessed and modified by the timer callback.

set(ai, 'UserData', extraData);

Configure the Timer Callback

We use the TimerFcn and TimerPeriod properties to call a MATLAB function at regular intervals while the acquisition is running. We use this timer callback function to examine the incoming data to see if the trigger condition has been met.

NOTE: The timer callback function is shown at the end of this example.

% Make timer period 1/10 of our quiet period.
timerPeriod = extraData.secondsOfQuietNeeded/10;

set(ai, 'TimerFcn', @TimerCallback);
set(ai, 'TimerPeriod', timerPeriod);

Configure the Trigger Properties

We use a manual trigger and configure the object to acquire the data during the quiet period.

By setting the TriggerType property to 'manual', data logging will not begin until the trigger function is executed. The timer callback will execute the trigger when the correct conditions have been met.

In addition, we set the TriggerDelay property to a negative value to indicate that we want to log the quiet period data that occurred before the trigger was executed.

set(ai, 'TriggerType', 'manual');
set(ai, 'TriggerDelay', -extraData.secondsOfQuietNeeded);
set(ai, 'TriggerDelayUnits', 'seconds');

Configure the Amount of Data to Acquire

We set the SamplesPerTrigger property to indicate the maximum amount of data that the acquisition should log. However, the timer callback will stop the acquisition sooner, if it detects a second signal after the quiet period.

sampleRate = get(ai, 'SampleRate');
set(ai, 'SamplesPerTrigger', 10 * extraData.secondsOfQuietNeeded * sampleRate);

Start Acquisition

Now, we start the acquisition. After calling the start function, the object will be running, but no data logging will occur until the trigger function is executed. As the timer callback executes and evaluates the data, messages will be displayed indicating what has been detected.

start(ai);
try
    % Wait for trigger to occur and the acquisition to end.
    % Set the timeout to a sufficiently large value.
    wait(ai, 60 * extraData.secondsOfQuietNeeded);

    % If the acquisition ended successfully, plot the available data.
    samplesAvailable = get(ai,'SamplesAvailable');
    [data, time] = getdata(ai, samplesAvailable);
    plot(time,data);
catch
    % If the wait timed out, we end up here.
    % Display a message and stop the acquisition.
    disp(sprintf('Could not find quiet period of %d seconds.', ...
                  extraData.secondsOfQuietNeeded));
    stop(ai);
end
Warning: The number of samples requested is not available.
The number of samples returned will be reduced.
First signal found. Waiting for quiet period of 2 seconds.
Quiet period found. Logging started.

Clean Up

When finished, we delete the object and clear the variable from the workspace to free system resources.

delete(ai);
clear ai;

The Timer Callback Function

We use the timer callback function to examine the incoming data to see if our trigger condition has been met. When our trigger condition has been met, the trigger function is called to start logging.

type TimerCallback;
%% 
% The Data Acquisition Toolbox calls the timer callback function with the 
% object and event.
function TimerCallback(ai,event)

%% 
% First, we get the information needed to evaluate the trigger condition.
extraData = get(ai, 'UserData');
timerPeriod = get(ai,'TimerPeriod');
sampleRate =  get(ai,'SampleRate');

%% 
% Then, we look at the data received during the last timer period.
sampleData = peekdata(ai, timerPeriod * sampleRate);
maxValue = max(sampleData);
minValue = min(sampleData);

%% 
% Next, we analyze the data received and look for our trigger condition.

% If we have not found the first signal, look for it.
if ( ~extraData.signalFound )
    
    if ( maxValue > extraData.signalVoltage || minValue < -extraData.signalVoltage )
        
        % The first signal has been found.
        extraData.signalFound = true;
        fprintf('First signal found. Waiting for quiet period of %d seconds.\n', ...
                 extraData.secondsOfQuietNeeded);
        
    end
    
% If a signal has been found, we look for the desired period of quiet.    
elseif ( ~extraData.quietFound )
    if ( minValue > -extraData.quietVoltage && maxValue < extraData.quietVoltage ) 
    
        % Increment the seconds of quiet that we have seen.
        extraData.secondsOfQuietFound = extraData.secondsOfQuietFound + timerPeriod;
        
        if extraData.secondsOfQuietFound >= extraData.secondsOfQuietNeeded
            
            % When the desired quiet period is found, we execute the trigger.
            trigger(ai); 
            extraData.quietFound = true;
            disp('Quiet period found. Logging started.');
            
        end
    % No longer quiet. Reset the seconds of quiet that we have seen.    
    else
        extraData.secondsOfQuietFound = 0;
    end
    
% If the quiet period has been found, look for the second signal.
else
    if ( maxValue > extraData.signalVoltage || minValue < -extraData.signalVoltage )
        
        % When the second signal is found, we stop the acquisition.
        stop(ai);
        disp('Second signal found. Acquisition stopped.');
    end
end

%% 
% Finally, we save the updated information to the UserData property so 
% that it will be available for the next execution of the timer callback
% function.
set(ai, 'UserData', extraData);