-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2f3116a
Showing
18 changed files
with
422 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.mat filter=lfs diff=lfs merge=lfs -text |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
# Wood Species Classification Using Vibration Signature | ||
|
||
Acquire live data from NI data acquisition hardware in MATLAB using the Data Acquisition Toolbox and use the Deep Learning Toolbox to classify 3 different wood species (Mexican Ebony, Hard Maple and Bloodwood) based on vibrational characteristics. | ||
This demo also uses the Wavelet Toolbox to compute continuous wavelet transform (CWT) images of the live acquired data samples. The CWT images were used to train our CNN model. | ||
|
||
![](images/classificationGui.png) | ||
|
||
## Wood Species | ||
|
||
The convolution neural network (CNN) was trained on vibrational data samples acquired from 3 different varieties of wood species known as: | ||
|
||
* Mexican Ebony | ||
* Hard Maple | ||
* Bloodwood | ||
|
||
![](images/woodSpecies.PNG) | ||
|
||
## Hardware Setup | ||
|
||
Configure the hardware - Connect NI 9234 data acquisition module with the impact hammer and accelerometers as follows: | ||
|
||
* Channel 0 - PCB 086C03 Impact Hammer | ||
* Channel 1 - PCB 352C65 Accelerometer | ||
* Channel 2 - PCB 352C65 Accelerometer | ||
* Channel 3 - PCB 352C65 Accelerometer | ||
|
||
Mount the 3 accelerometers on separate wood species blocks (Mexican Ebony, Hard Maple and Bloodwood). | ||
|
||
![](images/hardwareSetup.png) | ||
|
||
## Data Acquisition | ||
|
||
Data Acquisition Toolbox was used to acquire vibrational signals from NI 9234 DAQ module. Data Acquisition Toolbox provides functions for configuring data acquisition hardware and reading data into MATLAB for analysis. | ||
The toolbox supports a variety of DAQ hardware, including USB, PCI, PCI Express®, PXI®, and PXI-Express devices, from National Instruments™ and other vendors. | ||
|
||
![](images/overviewDiag.PNG) | ||
|
||
Thse following link provides more information about the Data Acquisition Toolbox: | ||
|
||
https://www.mathworks.com/products/data-acquisition.html | ||
|
||
## Signal Processing | ||
|
||
Vibrational data from the accelerometers mounted on wood blocks was acquired using NI 9234 DAQ module in MATLAB. Signal samples were analyzed and preprocessed in MATLAB. Continuous Wavelet Transforms (CWT) were used | ||
to generate the 2-D time-frequency maps of time series data. These time-frequency maps were used as inputs for the deep convolutional neural network (CNN). The ability of the CWT to simultaneously capture steady-state | ||
and transient signal behavior in time series data makes the wavelet-based time-frequency representation particularly robust when paired with deep CNNs. | ||
|
||
![](/images/waveletImage.PNG) | ||
|
||
For more information about Wavelet Transforms and time-frequency analysis, visit the following link: | ||
|
||
https://www.mathworks.com/help/wavelet/time-frequency-analysis.html | ||
|
||
## Goal | ||
|
||
* Configure Hardware | ||
* Strike wood block with the impact hammer | ||
* Accelerometer captures wood specific vibrational data | ||
* Classification model predicts the type of wood based on impact | ||
|
||
## Demo Video | ||
|
||
This demo was showcased in MathWorks/NI virtual event. The name of the session was - Data Acquisition and Machine Learning Using MathWorks and NI Tools. | ||
The session provides insights into a typical machine learning workflow and how one can use machine learning to classify materials followed by a live demo showcase. | ||
Link for the virtual session: | ||
|
||
https://gateway.on24.com/wcc/eh/2429684/lp/2748276/data-acquisition-and-machine-learning-using-mathworks-and-ni-tools | ||
|
||
## Demo Setup | ||
|
||
* From a list of MATLAB files in the 'wood classification demo' folder, open and run the demoSetup.m script in MATLAB. This script clears everything in MATLAB editor and sets it up for running the demo. | ||
* To start the demo, please run the startDaq.m script. | ||
|
||
Copyright 2021 The MathWorks, Inc. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Reporting Security Vulnerabilities | ||
|
||
If you believe you have discovered a security vulnerability, please report it to | ||
[[email protected]](mailto:[email protected]). Please see | ||
[MathWorks Vulnerability Disclosure Policy for Security Researchers](https://www.mathworks.com/company/aboutus/policies_statements/vulnerability-disclosure-policy.html) | ||
for additional information. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
Copyright (c) 2021, The MathWorks, Inc. | ||
All rights reserved. | ||
|
||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
|
||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
3. In all cases, the software is, and all modifications and derivatives of the software shall be, licensed to you solely for use in conjunction with MathWorks products and service offerings. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
function [classProb, A] = classifyMaterial(inputSignal) | ||
%classifyMaterial loads the trained network, computes real time | ||
%cwt transform, converts it to an image and predicts the classified output. | ||
|
||
% Copyright 2021 The MathWorks, Inc. | ||
|
||
persistent hh; | ||
inputSignal = inputSignal'; | ||
persistent trainedNet; | ||
|
||
% Check if trainedNet is empty | ||
if isempty(trainedNet) | ||
trainedNet = load('trainedNet.mat'); | ||
hh = 0; | ||
end | ||
|
||
if ~isfolder('liveImages') | ||
mkdir('liveImages') | ||
end | ||
|
||
% Compute the signalLength | ||
signalLength = numel(inputSignal); | ||
|
||
% Save the input image size in variable "imgSize" | ||
imgSize = [227 227]; | ||
imageRoot = fullfile(pwd, 'liveImages'); | ||
|
||
% Compute the cwt transform | ||
fb = cwtfilterbank('SignalLength', signalLength, 'SamplingFrequency', 51200, 'VoicesPerOctave', 48); | ||
[wt, ~] = fb.wt(inputSignal); | ||
|
||
% Convert the complex wavelet transform to an uint8 RGB image | ||
wtAbs = abs(wt); | ||
im = ind2rgb(im2uint8(rescale(wtAbs)), jet(256)); | ||
imFileName = "Image"+ "_" + hh + ".jpg"; | ||
imwrite(imresize(im, [224 224]), char(fullfile(imageRoot,imFileName))); | ||
A = imread(char(fullfile(imageRoot,imFileName))); | ||
imR = imresize(A, imgSize); | ||
hh = hh + 1; | ||
|
||
% Run the classify function of the network on the resized image | ||
classProb = classify(trainedNet.woodNet, imR); | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
%demoSetup function clears and set everything up for the wood classification | ||
%demo in MATLAB | ||
|
||
% Copyright 2021 The MathWorks, Inc. | ||
|
||
filePath = mfilename("fullpath"); | ||
changeDir = fileparts(filePath); | ||
|
||
% Change to current directory | ||
cd(changeDir) | ||
|
||
% Turn all warnings off | ||
warning('off') | ||
clc | ||
% Close all currently open scripts in the editor | ||
allscripts = matlab.desktop.editor.getAll; | ||
close(allscripts) | ||
|
||
% Open demo scripts | ||
edit('materialClassificationGui.m') | ||
edit('plotDataAvailable.m') | ||
edit('classifyMaterial.m') | ||
edit('startDaq.m') | ||
makeActive(matlab.desktop.editor.findOpenDocument('startDaq.m')) | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
function hGui = materialClassificationGui(s) | ||
%materialClassificationGui Creates a graphical user interface to display data capture. | ||
%hGui = materialClassificationGui(s) and creates a graphical user interface, by | ||
%programmatically creating a figure and adding required graphics | ||
%components for visualization of data acquired from a data acquisition | ||
%object (s). | ||
|
||
% Copyright 2021 The MathWorks, Inc. | ||
|
||
% Create a figure and configure a callback function (executes on window close) | ||
hGui.Fig = figure('Name','Material Classification', ... | ||
'NumberTitle', 'off', 'Resize', 'off', ... | ||
'Toolbar', 'None', 'Menu', 'None',... | ||
'Position', [100 50 870 600]); | ||
hGui.Fig.DeleteFcn = {@endDAQ, s}; | ||
uiBackgroundColor = hGui.Fig.Color; | ||
|
||
% Initialize the subplots | ||
pos1 = [0.050 0.5 0.42 0.42]; | ||
hGui.Axes1 = subplot('Position',pos1); | ||
title("Predicted Class: N/A"); | ||
|
||
pos2 = [0.53 0.5 0.42 0.42]; | ||
hGui.Axes2 = subplot('Position',pos2); | ||
title("N/A"); | ||
|
||
pos3 = [0.1 0.1 0.3 0.3]; | ||
hGui.Axes3 = subplot('Position',pos3); | ||
|
||
pos4 = [0.58 0.1 0.3 0.3]; | ||
hGui.Axes4 = subplot('Position',pos4); | ||
|
||
% Create a stop acquisition button and configure a callback function | ||
hGui.DAQButton = uicontrol('style', 'pushbutton', 'string', 'Stop DAQ',... | ||
'units', 'pixels', 'position', [780 5 81 38]); | ||
hGui.DAQButton.Callback = {@endDAQ, s}; | ||
|
||
hGui.txtTrigLevel = uicontrol('Style', 'text', 'String', 'Trigger Level (N)', ... | ||
'Position', [5 5 90 19], 'HorizontalAlignment', 'left', ... | ||
'BackgroundColor', uiBackgroundColor); | ||
hGui.TrigLevel = uicontrol('style', 'edit', 'string', '5',... | ||
'units', 'pixels', 'position', [105 5 56 24]); | ||
set(hGui.txtTrigLevel,'Visible','Off') | ||
set(hGui.TrigLevel,'Visible','Off') | ||
|
||
% Stop DAQ callback | ||
function endDAQ(~, ~, s) | ||
if isvalid(s) | ||
if s.Running | ||
stop(s); | ||
end | ||
end | ||
clear classifyMaterial; | ||
end | ||
|
||
end |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
function plotDataAvailable(src, ~, hGui) | ||
%plotDataAvailable function reads in data from NI 9234, extracts pre- | ||
%defined samples, calls classification function and plots the GUI | ||
|
||
% Copyright 2021 The MathWorks, Inc. | ||
|
||
global sigBuffer1 sigBuffer2 nxtBufferCnt finalTrigIndex trigData1 trigData2 triggerThreshold mEbony hMaple bWood; | ||
|
||
% Declaring variables for analyzing modalfrf(optional) | ||
%global fs frf f | ||
|
||
% Read data from NI DAQ 9234 | ||
[x, eventTimestamps] = read(src, src.ScansAvailableFcnCount, "OutputFormat", "Matrix"); | ||
|
||
% Impact hammer(channel 1) data | ||
x1 = x(:,1); | ||
|
||
%% Find the max value in each column of the channels | ||
|
||
% Accelerometers are connected to ch2, ch3 and ch4 of NI USB 9234 | ||
dataChannels = x(:,2:4); | ||
actChannel = max(dataChannels,[],1); | ||
[~,idx] = max(actChannel); | ||
x2 = x(:,idx+1); | ||
%% | ||
if eventTimestamps(1)==0 | ||
%frf = 0; | ||
%f = 0; | ||
nxtBufferCnt = 0; | ||
trigData1 = zeros(1024,1); | ||
trigData2 = zeros(1024,1); | ||
mEbony = imread('mexicanEbony.jpg'); | ||
hMaple = imread('hardMaple.jpg'); | ||
bWood = imread('bloodWood.jpg'); | ||
triggerThreshold = 25; | ||
end | ||
|
||
% FIFO for channel 1 | ||
sigBuffer1(1:end-numel(x1)) = sigBuffer1(numel(x1)+1:end); | ||
sigBuffer1(end-numel(x1)+1:end) = x1; | ||
|
||
% FIFO for channel 2 | ||
sigBuffer2(1:end-numel(x2)) = sigBuffer2(numel(x2)+1:end); | ||
sigBuffer2(end-numel(x2)+1:end) = x2; | ||
|
||
if(nxtBufferCnt == 1) | ||
%disp('Inside next buffer cntr condition as the prev buffer was in the last 1000 data samples'); | ||
finalTrigIndex = finalTrigIndex - numel(x1); | ||
|
||
% Extract 1024 samples | ||
trigData1 = sigBuffer1(finalTrigIndex - 100: finalTrigIndex + 923); | ||
trigData2 = sigBuffer2(finalTrigIndex - 100: finalTrigIndex + 923); | ||
|
||
% Set nxtBufferCnt as zero | ||
nxtBufferCnt = 0; | ||
end | ||
|
||
% Get the trigger configuration parameters from UI text input(trigconfig level is fixed to 5N and hidden) | ||
trigConfig.Level = sscanf(hGui.TrigLevel.String, '%f'); | ||
|
||
% Check for trigger threshold | ||
if( any(x1 > trigConfig.Level) ) | ||
%disp("Inside trigger Condition!") | ||
if(any(x1 > triggerThreshold)) | ||
errordlg('Impact cannot be greater than 25 Newton','Error Occured'); | ||
return | ||
end | ||
|
||
% Find first index of channel 1 which is above the threshold | ||
trigIndex = find((x1 > trigConfig.Level),1,'first'); | ||
|
||
% Final trigger index is the trigIndex in x1 plus length of sigBuffer - length of x1 | ||
finalTrigIndex = trigIndex + numel(sigBuffer1) - numel(x1); | ||
|
||
if( finalTrigIndex + 923 > numel(sigBuffer1) ) | ||
%disp("Trigger index is in last 1000 data samples"); | ||
nxtBufferCnt = 1; | ||
|
||
else | ||
% Capture channel 1 and channel 2 samples before and after trigger | ||
% If 1024 samples required | ||
trigData1 = sigBuffer1(finalTrigIndex - 100: finalTrigIndex + 923); | ||
trigData2 = sigBuffer2(finalTrigIndex - 100: finalTrigIndex + 923); | ||
|
||
% Modal frf (optional) | ||
%winlen = size(trigData2,1); | ||
%[frf, f] = modalfrf(trigData1(:), trigData2(:), fs, hann(winlen), 'Sensor', 'acc'); | ||
end | ||
% Call classifyMaterial function to predict wood type | ||
[classProb, A] = classifyMaterial(trigData2); | ||
|
||
% Plot classified wood image | ||
if (classProb == "Mexican Ebony") | ||
pos1 = [0.050 0.5 0.42 0.42]; | ||
hGui.Axes1 = subplot('Position',pos1); | ||
imagesc(hGui.Axes1, mEbony); | ||
axis off; | ||
title("Predicted Class: Mexican Ebony"); | ||
elseif (classProb == "Hard Maple") | ||
pos1 = [0.050 0.5 0.42 0.42]; | ||
hGui.Axes1 = subplot('Position',pos1); | ||
imagesc(hGui.Axes1, hMaple); | ||
axis off; | ||
title("Predicted Class: Hard Maple"); | ||
elseif (classProb == "Bloodwood") | ||
pos1 = [0.050 0.5 0.42 0.42]; | ||
hGui.Axes1 = subplot('Position',pos1); | ||
imagesc(hGui.Axes1, bWood); | ||
axis off; | ||
title("Predicted Class: Bloodwood"); | ||
end | ||
|
||
% Plot CWT image | ||
pos2 = [0.53 0.5 0.42 0.42]; | ||
hGui.Axes2 = subplot('Position',pos2); | ||
imagesc(hGui.Axes2, A); | ||
axis off; | ||
title("Continuous Wavelet Transform Image"); | ||
end | ||
|
||
% Plot impact hammer data | ||
pos3 = [0.1 0.1 0.3 0.3]; | ||
hGui.Axes3 = subplot('Position',pos3); | ||
plot(hGui.Axes3, trigData1) | ||
title(hGui.Axes3,'Impact Hammer Data','HandleVisibility','off'); | ||
ylabel('Force (Newton)','HandleVisibility','off'); | ||
xlabel('Data samples','HandleVisibility','off'); | ||
|
||
% Plot accelerometer data | ||
pos4 = [0.58 0.1 0.3 0.3]; | ||
hGui.Axes4 = subplot('Position',pos4); | ||
plot(hGui.Axes4, trigData2) | ||
title(hGui.Axes4,'Accelerometer Data','HandleVisibility','off'); | ||
ylabel('Acceleration (g)','HandleVisibility','off'); | ||
xlabel('Data samples','HandleVisibility','off'); | ||
|
||
end |
Oops, something went wrong.