Main Content

Acoustics-Based Machine Fault Recognition Code Generation

This example demonstrates code generation for Acoustics-Based Machine Fault Recognition (Audio Toolbox) using a long short-term memory (LSTM) network and spectral descriptors. This example uses MATLAB® Coder™ with deep learning support to generate a MEX (MATLAB executable) function that leverages C++ code. The input data consists of acoustics time-series recordings from faulty or healthy air compressors and the output is the state of the mechanical machine predicted by the LSTM network. For details on audio preprocessing and network training, see Acoustics-Based Machine Fault Recognition (Audio Toolbox).

Prepare Input Dataset

Specify a sample rate fs of 16 kHz and a windowLength of 512 samples, as defined in Acoustics-Based Machine Fault Recognition (Audio Toolbox). Set numFrames to 100.

fs = 16000;
windowLength = 512;
numFrames = 100;

To run the example on a test signal, generate a pink noise signal. To test the performance of the system on a real dataset, download the air compressor dataset [1].

downloadDataset = true;

if ~downloadDataset
    pinkNoiseSignal = pinknoise(windowLength*numFrames,'single');
else
    % Download AirCompressorDataset.zip 
    component = 'audio';
    filename = 'AirCompressorDataset/AirCompressorDataset.zip';
    localfile = matlab.internal.examples.downloadSupportFile(component,filename);
    
    % Unzip the downloaded zip file to the downloadFolder
    downloadFolder = fileparts(localfile);
    if ~exist(fullfile(downloadFolder,'AirCompressorDataset'),'dir')
        unzip(localfile,downloadFolder)
    end
    
    % Create an audioDatastore object dataStore, to manage, the data.
    dataStore = audioDatastore(downloadFolder,IncludeSubfolders=true,LabelSource="foldernames",OutputDataType="single");

    % Use countEachLabel to get the number of samples of each category in the dataset.
    countEachLabel(dataStore)
end
ans=8×2 table
      Label      Count
    _________    _____

    Bearing       225 
    Flywheel      225 
    Healthy       225 
    LIV           225 
    LOV           225 
    NRV           225 
    Piston        225 
    Riderbelt     225 

Recognize Machine Fault in MATLAB

To run the streaming classifier in MATLAB, use the pretrained network in AirCompressorFaultRecognition.mat and wrapper file recognizeAirCompressorFault.m developed in Acoustics-Based Machine Fault Recognition (Audio Toolbox). When you open this example, the files are placed in your current folder.

Create a dsp.AsyncBuffer (DSP System Toolbox) object to read audio in a streaming fashion and a dsp.AsyncBuffer (DSP System Toolbox) object to accumulate scores.

audioSource = dsp.AsyncBuffer;
scoreBuffer = dsp.AsyncBuffer;

Get the labels that the network outputs correspond to.

model = load('AirCompressorFaultRecognitionModel.mat');
labels = string(model.labels);

Initialize signalToBeTested to pinkNoiseSignal or select a signal from the drop-down list to test the file of your choice from the dataset.

if ~downloadDataset
    signalToBeTested = pinkNoiseSignal;
else
    [allFiles,~] = splitEachLabel(dataStore,1);
    allData = readall(allFiles);
    signalToBeTested = allData(5);
    signalToBeTested = cell2mat(signalToBeTested);
end

Stream one audio frame at a time to represent the system as it would be deployed in a real-time embedded system. Use recognizeAirCompressorFault developed in Acoustics-Based Machine Fault Recognition (Audio Toolbox) to compute audio features and perform deep learning classification.

write(audioSource,signalToBeTested);
resetNetworkState = true;

while audioSource.NumUnreadSamples >= windowLength

    % Get a frame of audio data
    x = read(audioSource,windowLength);

    % Apply streaming classifier function
    score = recognizeAirCompressorFault(x,resetNetworkState);
    
    % Store score for analysis
    write(scoreBuffer,extractdata(score)');
    
    resetNetworkState = false;
end

Compute the recognized fault from scores and display it.

scores = read(scoreBuffer);
[~,labelIndex] = max(scores(end,:),[],2);
detectedFault = labels(labelIndex)
detectedFault = 
"LOV"

Plot the scores of each label for each frame.

plot(scores)
legend("" + labels,Location="northwest") 
xlabel("Time Step")
ylabel("Score")
str = sprintf("Predicted Scores Over Time Steps.\nPredicted Class: %s",detectedFault);
title(str)

Figure contains an axes object. The axes object with title Predicted Scores Over Time Steps. Predicted Class: LOV, xlabel Time Step, ylabel Score contains 8 objects of type line. These objects represent Bearing, Flywheel, Healthy, LIV, LOV, NRV, Piston, Riderbelt.

Generate MATLAB Executable

Create a code generation configuration object to generate an executable. Specify the target language as C++.

cfg = coder.config('mex');
cfg.TargetLang = 'C++';

Create an audio data frame of length windowLength.

audioFrame = ones(windowLength,1,"single");

Call the codegen (MATLAB Coder) function from MATLAB Coder to generate C++ code for the recognizeAirCompressorFault function. Specify the configuration object and prototype arguments. A MEX-file named recognizeAirCompressorFault_mex is generated to your current folder.

codegen -config cfg recognizeAirCompressorFault -args {audioFrame,resetNetworkState} -report
Code generation successful: View report

Perform Machine Fault Recognition Using MATLAB Executable

Initialize signalToBeTested to pinkNoiseSignal or select a signal from the drop-down list to test the file of your choice from the dataset.

if ~downloadDataset
    signalToBeTested = pinkNoiseSignal;
else
    [allFiles,~] = splitEachLabel(dataStore,1);
    allData = readall(allFiles);
    signalToBeTested = allData(3);
    signalToBeTested = cell2mat(signalToBeTested);
end

Stream one audio frame at a time to represent the system as it would be deployed in a real-time embedded system. Use generated recognizeAirCompressorFault_mex to compute audio features and perform deep learning classification.

write(audioSource,signalToBeTested);
resetNetworkState = true;

while audioSource.NumUnreadSamples >= windowLength

    % Get a frame of audio data
    x = read(audioSource,windowLength);

    % Apply streaming classifier function
    score = recognizeAirCompressorFault_mex(x,resetNetworkState);
    
    % Store score for analysis
    write(scoreBuffer,extractdata(score)');

    resetNetworkState = false;
end

Compute the recognized fault from scores and display it.

scores = read(scoreBuffer);
[~,labelIndex] = max(scores(end,:),[],2);
detectedFault = labels(labelIndex)
detectedFault = 
"Healthy"

Plot the scores of each label for each frame.

plot(scores)
legend(labels,Location="northwest")
xlabel("Time Step")
ylabel("Score")
str = sprintf("Predicted Scores Over Time Steps.\nPredicted Class: %s",detectedFault);
title(str)

Figure contains an axes object. The axes object with title Predicted Scores Over Time Steps. Predicted Class: Healthy, xlabel Time Step, ylabel Score contains 8 objects of type line. These objects represent Bearing, Flywheel, Healthy, LIV, LOV, NRV, Piston, Riderbelt.

Evaluate Execution Time of Alternative MEX Function Workflow

Use tic and toc to measure the execution time of MATLAB function recognizeAirCompressorFault and MATLAB executable (MEX) recognizeAirCompressorFault_mex.

Create a dsp.AsyncBuffer (DSP System Toolbox) object to record execution time.

timingBufferMATLAB = dsp.AsyncBuffer;
timingBufferMEX = dsp.AsyncBuffer;

Use same recording that you chose in previous section as input to recognizeAirCompressorFault function and its MEX equivalent recognizeAirCompressorFault_mex.

write(audioSource,signalToBeTested);

Measure the execution time of the MATLAB code.

resetNetworkState = true;
while audioSource.NumUnreadSamples >= windowLength

    % Get a frame of audio data
    x = read(audioSource,windowLength);

    % Apply streaming classifier function
    tic
    scoreMATLAB = recognizeAirCompressorFault(x,resetNetworkState);
    write(timingBufferMATLAB,toc);

    % Apply streaming classifier MEX function
    tic
    scoreMEX = recognizeAirCompressorFault_mex(x,resetNetworkState);
    write(timingBufferMEX,toc);

    resetNetworkState = false;

end

Plot the execution time for each frame and analyze the profile. The first call of recognizeAirCompressorFault_mex consumes around four times of the budget as it includes loading of network and resetting of the states. However, in a real, deployed system, that initialization time is only incurred once. The execution time of the MATLAB function is around 10 ms and that of MEX function is ~1 ms, which is well below the 32 ms budget for real-time performance.

budget = (windowLength/fs)*1000;
timingMATLAB = read(timingBufferMATLAB)*1000;
timingMEX = read(timingBufferMEX)*1000;
frameNumber = 1:numel(timingMATLAB);
perfGain = timingMATLAB./timingMEX;
plot(frameNumber,timingMATLAB,frameNumber,timingMEX,LineWidth=2)
grid on
yline(budget,'',"Budget",LineWidth=2)
legend("MATLAB Function","MEX Function",Location="northwest")
xlabel("Time Step")
ylabel("Execution Time (in ms)")
title("Execution Time Profile of MATLAB and MEX Function")

Figure contains an axes object. The axes object with title Execution Time Profile of MATLAB and MEX Function, xlabel Time Step, ylabel Execution Time (in ms) contains 3 objects of type line, constantline. These objects represent MATLAB Function, MEX Function.

Compute the performance gain of MEX over MATLAB function excluding the first call.

PerformanceGain = sum(timingMATLAB(2:end))/sum(timingMEX(2:end))
PerformanceGain = 19.4074

This example ends here. For deploying machine fault recognition on Raspberry Pi, see Acoustics-Based Machine Fault Recognition Code Generation on Raspberry Pi (Audio Toolbox).

References

[1] Verma, Nishchal K., et al. "Intelligent Condition Based Monitoring Using Acoustic Signals for Air Compressors." IEEE Transactions on Reliability, vol. 65, no. 1, Mar. 2016, pp. 291–309. DOI.org (Crossref), doi:10.1109/TR.2015.2459684.