Acquire Data from Two Devices at Different Rates

This example shows how to use the session interface to acquire data from two different DAQ devices at different rates. The example uses two National Instruments CompactDAQ analog input modules (9201 and 9211) which have different acquisition rate limits. The 9211 module is used for temperature measurements and acquires at a slower rate (10 Hz) than the 9201 module, which is used to measure voltage (100 Hz). Since all channels in a session must acquire at the same rate, to acquire from two modules at different rates you need to use two sessions. To make both sessions start simultaneously, you can use a hardware digital triggering configuration.

Hardware Setup

  • CompactDAQ chassis NI cDAQ 9178 ('cDAQ1')

  • CompactDAQ chassis NI cDAQ 9211 analog input module with thermocouple measurement type ('cDAQ1Mod1')

  • CompactDAQ chassis NI cDAQ 9201 analog input module with voltage measurement type ('cDAQ1Mod2')

  • Thermocouple probe (type K)

  • Analog voltage signal generated by a function generator instrument

Configure Data Acquisition Sessions and Channels

Create two sessions, each with an analog input channel from a 9211 module or 9201 module. The sessions acquire data at rates of 10 Hz and 100 Hz, respectively.

Configure the sessions to run in background mode, and use a callback function for the DataAvailable event to store the acquired data and timestamps in the session UserData property.

% Specify a common acquisition duration for both devices
daqDuration = 3;

% Create and configure session and channels for cDAQ 9211 module
s1 = daq.createSession('ni');
addAnalogInputChannel(s1, 'cDAQ1Mod1', 'ai0', 'Thermocouple');
s1.Channels(1).ThermocoupleType = 'K';

s1.DurationInSeconds = daqDuration;
daListener1 = addlistener(s1, 'DataAvailable', @DataAvailable_callback);
errListener1 = addlistener(s1, 'ErrorOccurred', ...
    @(~,event) disp(getReport(event.Error)));
s1.UserData.Data = [];
s1.UserData.Time = [];
s1.Rate = 10;

% Create and configure session and channels for cDAQ 9201 module
s2 = daq.createSession('ni');
addAnalogInputChannel(s2, 'cDAQ1Mod2', 'ai0', 'Voltage');
s2.DurationInSeconds = daqDuration;
daListener2 = addlistener(s2, 'DataAvailable', @DataAvailable_callback);
errListener2 = addlistener(s2, 'ErrorOccurred', ...
    @(~,event) disp(getReport(event.Error)));
s2.UserData.Data = [];
s2.UserData.Time = [];
s2.Rate = 100;
Warning: The Rate property was reduced to 14.2857 due to changes in the session

Configure Trigger Connections

To synchronize the acquisition start you can use hardware triggering and a master/slave approach. One of the sessions (master) is started manually and triggers the acquisition start of the other session (slave).

Note: If you have a CompactDAQ chassis model (such as NI 9174) which does not have PFI triggering terminals, you can use an additional digital I/O module (such as NI 9402) to provide the PFI terminals for the trigger connections.

% Configure this session (master) to export a triggering signal on the PFI0
% terminal of cDAQ1 chassis
addTriggerConnection(s1, 'cDAQ1/PFI0', 'External', 'StartTrigger');

% Configure this session (slave) to start acquisition when an external
% triggering signal is received at PFI0 terminal of cDAQ1 chassis
addTriggerConnection(s2, 'External', 'cDAQ1/PFI0', 'StartTrigger');

Start Acquisition and Wait Until Complete

The slave session must be started first and be ready for an external trigger before starting the master session.

while ~s2.IsWaitingForExternalTrigger

wait(s1, daqDuration+1)
wait(s2, daqDuration+1)

Save Data as Timetable

The acquired data and timestamps were stored in the session UserData property. Copy the data to a base workspace variable and convert it to a timetable.

data1 = array2timetable(s1.UserData.Data, ...
    'RowTimes', seconds(s1.UserData.Time),...
    'VariableNames', {s1.Channels.ID});

data2 = array2timetable(s2.UserData.Data, ...
    'RowTimes', seconds(s2.UserData.Time), ...
    'VariableNames', {s2.Channels.ID});

Plot Acquired Data

Since the acquired data from the two devices have different scales and units, create a chart with two y-axes.


yyaxis left
plot(data1.Time, data1.ai0, '-x')
ylabel('Temperature (deg. C)')
ylim([0 50])
yyaxis right
plot(data2.Time, data2.ai0, '-o')
ylabel('Voltage (V)')
xlabel('Time (s)')

Clean Up

Delete listeners and clear the two sessions to disconnect from hardware.

clear s1 s2 daListener1 daListener2 errListener1 errListener2

Local Functions

The DataAvailable_callback function is used as a shared callback for the DataAvailable event of sessions s1 and s2.

function DataAvailable_callback(src, event)
%DATAAVAILABLE_CALLBACK Callback function for session DataAvailable event
% Stores acquired data and timestamps in the session UserData property

src.UserData.Data = [src.UserData.Data; event.Data];
src.UserData.Time = [src.UserData.Time; event.TimeStamps];