Data Acquisition Toolbox

Counting Complex Events Using Analog Input Data

This example shows how to use an analog input channel from a data acquisition device to acquire the signal and then post process it in MATLAB(R) to count the number of pulses. The example uses an analog input channel from a Measurement Computing(TM) PMD-1208LS, but almost any supported data acquisition device will work with minimal changes to the code.

Although many data acquisition devices have counters built into them, sometimes the built-in counters are not sufficient. For example, your signal might be too noisy to be reliably counted using a standard counter, or your signal might not conform to the voltage requirements of the counter.

The hardware for this example is a mechanical push button switch that is switching a 5-volt signal on and off. It is difficult to count the number of times that a mechanical push button has been pressed because of bouncing. When a switch is closed it sometimes momentarily opens before closing again. While there are circuits that can minimize the bouncing effect, it is not always practical to use one. MATLAB can easily be used to debounce a switch.

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.

Create the Analog Input Object

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

% Create the analog input object.  The arguments to the ANALOGINPUT command
% might need to be changed for your particular hardware.
ai = analoginput('mcc', 0);

% Specify the channel that data should be collected from.
ch = addchannel(ai, 0);

Configure the Analog Input Object

Now that you have created the analog input object, it must be configured for this particular acquisition. For this acquisition, configure the hardware with:

  • The SampleRate property set to 1000 samples per second

  • The SamplesPerTrigger property set to 5000 samples

% Set the sample rate.
set(ai, 'SampleRate', 1000);

% Change the number of samples to acquire.
set(ai, 'SamplesPerTrigger', 5000);
disp(ai)
Display Summary of Analog Input (AI) Object Using 'PMD-1208LS'.

  Acquisition Parameters:  1000 samples per second on each channel.
                           5000 samples per trigger on each channel.
                           5 sec. of data to be logged upon START.
                           Log data to 'Memory' on trigger.

      Trigger Parameters:  1 'Immediate' trigger(s) on START.

           Engine status:  Waiting for START.
                           0 samples acquired since starting.
                           0 samples available for GETDATA.

AI object contains channel(s):

   Index:  ChannelName:  HwChannel:  InputRange:  SensorRange:  UnitsRange:  Units:   
   1       ''            0           [-20 20]     [-20 20]      [-20 20]     'Volts'  

Acquire and View the Data

To acquire the data, you issue the start command to the analog input object. You can then use the wait command to wait for the acquisition to be completed, and the getdata command to return the data to MATLAB. The getdata command can return the time that each sample was taken, in addition to the actual sample. When you start the acquisition, all parameters are verified by the hardware and possibly updated based upon the capabilities of the hardware in the current configuration.

% Start the acquisition.
start(ai)

% Wait for the acquisition to finish.  Wait a few extra seconds to account
% for any overhead in starting the acquisition.
wait(ai, 10);

% Get the data.
[data time] = getdata(ai);

% Plot the data.
plot(time, data)
Warning: SampleRate changed at start.

Find the Pulse Edges

Finding the edges of the pulses is easy in MATLAB. You simply set a threshold and then look for consecutive samples that are on opposite sides of the threshold. The easiest way to do this to create a duplicate vector of data that is offset from the original data by one sample. Because the pulse time is important, you need to find the rising and falling edges of each pulse. The output of this step is a plot where the unwanted bounces are shown with overlapping x's and o's.

% Set the threshold to 3.5 V.
threshold = 3.5;

% Create the offset data.  Need to append a NaN to the final sample since
% both vectors need to have the same length.
offsetData = [data(2:end); NaN];

% Find the rising edge.
risingEdge = find(data < threshold & offsetData > threshold);

% Find the falling edge.
fallingEdge = find(data > threshold & offsetData < threshold);

% Show the rising edges with red x's.
hold on
plot(time(risingEdge), threshold, 'rx');

% Show the falling edges with green o's.
plot(time(fallingEdge), threshold, 'go');
hold off

Find the Duration of Each Pulse

A switch bounce is represented by a very short duration pulse. To find the duration of each pulse, you need to combine the rising edge and falling edge times into a single vector. The difference of any two consecutive times shows the duration of a pulse.

% Construct a vector to hold all of the times.
pulseIndices = zeros(length(risingEdge) * 2, 1);

% Store the rising edge times.
pulseIndices(1:2:end) = risingEdge;

% Store the falling edge times.
pulseIndices(2:2:end) = fallingEdge;

% Compute the pulse durations.
pulseTimes = diff(time(pulseIndices))
pulseTimes =

    0.0719
    0.1976
    0.0399
    0.1557
    0.0190
    0.4631
    0.0549
    0.1188
    0.0379
    0.5230
    0.0669
    0.1028
    0.0579
    0.1677
    0.0489
    0.0010
    0.0110
    0.0998
    0.0709
    0.1178
    0.0818
    0.1188
    0.0719
    0.0100
    0.0020
    0.1257
    0.0519
    0.1248
    0.0709
    0.1257
    0.0629

Eliminate the Bounces

By analyzing the pulse durations, you can determine the length of pulses that should be ignored. For this example, pulses shorter that 50 ms are removed.

% Create a variable for the processed data.
processedData = data;

% Define the minimum duration of 50 ms.
minDuration = 0.050;

% Find the pulses that are less than 50 ms.
pulsesToRemove = find(pulseTimes < minDuration);

% Remove the pulses that are too short by setting their value to +5 V.
for ii = 1:length(pulsesToRemove);
    startInd = pulseIndices(pulsesToRemove(ii));
    endInd = pulseIndices(pulsesToRemove(ii)+1);
    processedData(startInd:endInd) = 5;
end

% Plot the smoothed data.
plot(time, processedData)

Count the Pulses

Now that spurious pulses have been removed, it is possible to count the number of pulses in the data signal. The edges of the pulses are determined in the same manner as before, and you only need to count the number of edges.

% Create the offset data.  Need to append a NaN to the final sample since
% both vectors need to have the same length.
offsetData = [processedData(2:end); NaN];

% Find the rising edge.
risingEdge = find( processedData < threshold & offsetData > threshold );

numPulses = length(risingEdge)
numPulses =

    14

Clean Up

When you are done with a data acquisition object, you should clean up any unneeded data acquisition objects. Delete the analog input object and clear it from the workspace.

delete(ai);

clear ai ch

Summary

This example showed how to use the analog input subsystem of a data acquisition device to count complex events. After creating a data acquisition object and acquiring and viewing the data, it was clear that a simple counting algorithm would not work. A simple filter was designed to remove the switch bounce and the filter was then applied to the acquired data. It was then possible to count the number of button presses in the acquired data using a straightforward thresholding technique.