Impulse Response Measurement Using a NI USB-4431 Device
This example shows how to measure an impulse response using a National Instruments (NI) USB-4431 sound and vibration device. You set up the device, create an excitation signal to play, and simultaneously record the response. Finally, you compute the response from the recording and plot the results.
For this example, you need Audio Toolbox™ and Data Acquisition Toolbox™. You also need to have installed the NI drivers (recommended) or the MATLAB NI support package.
Device Setup
Verify if the NI USB-4431 is connected and the proper drivers are installed using the daqlist
command.
daqlist("ni")
ans=1×4 table
DeviceID Description Model DeviceInfo
________ ___________________________________ __________ ________________________________________
"Dev1" "National Instruments(TM) USB-4431" "USB-4431" 1×1 daq.ni.DeviceSpecializations.USB4431
Next, knowing that this device only supports clocked operations, you can disable the warning.
ws = warning("off","daq:Session:clockedOnlyChannelsAdded"); % restore warning state when cleared oc = onCleanup(@() warning(ws));
Setup the NI device with a sampling rate of 48 kHz, one input, and one output.
To do so, create a daq
object for NI devices and set Rate
to 48 kHz.
FS = 48e3; dq = daq("ni"); dq.Rate = FS; dev = "Dev1";
Add one input and one output. In this example, the microphone has its own pre-amplifier, so set the measurement type to Voltage
. The output is connected to a powered loudspeaker and the measurement type is set to Voltage
.
addinput(dq,dev,"ai0","Voltage"); addoutput(dq,dev,"ao0","Voltage");
Stimulus Signal
Create an exponential swept sine going from 20 Hz to 24 kHz over a period of 3 seconds, followed by one second of silence. This limits the maximum impulse response length to one second. You can also set the output level, in this case -18 dB.
irDur = 1; sweepDur = 3; outputLevel = -18; sweepRange = [20 24000]; exc = sweeptone( ... sweepDur, irDur, FS, ... ExcitationLevel=outputLevel, ... SweepFrequencyRange=sweepRange);
Response Measurement
Using the readwrite
method of the daq
object (dq
), play the swept sine stimulus (exc
) and simultaneously record the response.
data = readwrite(dq,exc);
dq = []; % release
Compute the Impulse Response
Use the impzest
function to compute the impulse response (ir
) from the stimulus (exc
) and its response.
response = data.Variables; ir = impzest(exc,response);
Create the corresponding time vector.
t_sec = (0:length(ir)-1).'/FS;
Display the Results
Plot the first 10 milliseconds, in this case, 480 samples.
totalDur = sweepDur*FS; n = 480; plot(t_sec(1:n), ir(1:n)) title("Impulse Response") ylabel("Amplitude") xlabel("Time (s)") grid on
Impulse Response Measurer App
Another way of writing the code above is to start from a script generated from the Impulse Response Measurer app. Start the app by entering impulseResponseMeasurer
at the command prompt. You can also click the app icon on the Apps tab of the MATLAB® Toolstrip. Even without a supported device connected, you can set the Method Settings, Display Settings and a linear or log scale for magnitude and phase responses (using the toolbar that appears when hovering the mouse over these plots). Then, click Generate Script. A new document will appear in the editor with code for an audio device, that you will modify to use the NI USB-4431.
Script Customization
First, you may want to make this a function by adding function capture = irm_usb4431
to the top of the file, and an end
statement before the first embedded function.
The function to interface with the NI device can take a complete signal, without proceeding frame by frame. Consequently, remove the code for "Allocate the input/output buffers
" and "Copy the excitation to the output buffer
".
The code required to "Setup the audio device
" can be replaced by code to setup the NI USB-4431 device. Set the sample rate of the device and add an output and at least one input.
dq = daq("ni"); dq.Rate = 48e3; % Sampling rate addinput(dq,"Dev1","ai0","Voltage"); addoutput(dq,"Dev1","ao0","Voltage");
The playback and capture loop can be replaced by a readwrite
statement. Get the results from data.Variables
instead of the buffer. Also get the handle from the first figure to facilitate zooming in.
Now run the customized function irm_usb4431
to obtain the capture data and plot the results and zoom in.
[capture,ax1] = irm_usb4431(); xlim(ax1,[0 10e-3]);
The data is also available programmatically.
capture
capture = struct with fields:
ImpulseResponse: [1×1 struct]
MagnitudeResponse: [1×1 struct]
PhaseResponse: [1×1 struct]
For example, plot the first 480 samples of the impulse response.
figure % new figure plot(capture.ImpulseResponse.Time(1:480), capture.ImpulseResponse.Amplitude(1:480)) title("Impulse Response") ylabel("Amplitude") xlabel("Time (s)") grid on