%% Set up the Import Options and import the data
opts = delimitedTextImportOptions("NumVariables", 8);

% Specify range and delimiter
opts.DataLines = [1, Inf];
opts.Delimiter = ",";

% Specify column names and types
opts.VariableNames = ["Iteration", "NoseRadius", "CuttingSpeed", "FeedRate", "DepthOfCut", "ForceRatio", "AverageSurfaceRoughness", "MaximumSurfaceRoughness"];
opts.VariableTypes = ["double", "double", "double", "double", "double", "double", "double", "double"];

% Specify file level properties
opts.ExtraColumnsRule = "ignore";
opts.EmptyLineRule = "read";

% Import the data
Data = readtable("D:\Nextcloud\siwat\Documents\Lean Manufacturing\Data.csv", opts);

%% Clear temporary variables
clear opts

% Remove Header
Data = Data(2:end,:);

inputs = [Data.NoseRadius,Data.CuttingSpeed,Data.FeedRate, Data.DepthOfCut];
outputs = [Data.ForceRatio, Data.AverageSurfaceRoughness, Data.MaximumSurfaceRoughness];

% Solve an Input-Output Fitting problem with a Neural Network
% Script generated by Neural Fitting app
% Created 19-Mar-2024 12:05:08
%
% This script assumes these variables are defined:
%
%   inputs - input data.
%   outputs - target data.

x = inputs';
t = outputs';

% Choose a Training Function
% For a list of all training functions type: help nntrain
% 'trainlm' is usually fastest.
% 'trainbr' takes longer but may be better for challenging problems.
% 'trainscg' uses less memory. Suitable in low memory situations.
trainFcn = 'trainlm';  % Levenberg-Marquardt backpropagation.

% Create a Fitting Network
hiddenLayerSize = 50;
net = fitnet(hiddenLayerSize,trainFcn);

% Choose Input and Output Pre/Post-Processing Functions
% For a list of all processing functions type: help nnprocess
net.input.processFcns = {'removeconstantrows','mapminmax'};
net.output.processFcns = {'removeconstantrows','mapminmax'};

% Setup Division of Data for Training, Validation, Testing
% For a list of all data division functions type: help nndivision
net.divideFcn = 'dividerand';  % Divide data randomly
net.divideMode = 'sample';  % Divide up every sample
net.divideParam.trainRatio = 70/100;
net.divideParam.valRatio = 15/100;
net.divideParam.testRatio = 15/100;

% Choose a Performance Function
% For a list of all performance functions type: help nnperformance
net.performFcn = 'mse';  % Mean Squared Error

% Choose Plot Functions
% For a list of all plot functions type: help nnplot
net.plotFcns = {'plotperform','plottrainstate','ploterrhist', ...
    'plotregression', 'plotfit'};

% Train the Network
[net,tr] = train(net,x,t);

% Test the Network
y = net(x);
e = gsubtract(t,y);
performance = perform(net,t,y)

% Recalculate Training, Validation and Test Performance
trainTargets = t .* tr.trainMask{1};
valTargets = t .* tr.valMask{1};
testTargets = t .* tr.testMask{1};
trainPerformance = perform(net,trainTargets,y)
valPerformance = perform(net,valTargets,y)
testPerformance = perform(net,testTargets,y)

% View the Network
view(net)

% Plots
% Uncomment these lines to enable various plots.
%figure, plotperform(tr)
%figure, plottrainstate(tr)
%figure, ploterrhist(e)
%figure, plotregression(t,y)
%figure, plotfit(net,x,t)

% Deployment
% Change the (false) values to (true) to enable the following code blocks.
% See the help for each generation function for more information.
if (false)
    % Generate MATLAB function for neural network for application
    % deployment in MATLAB scripts or with MATLAB Compiler and Builder
    % tools, or simply to examine the calculations your trained neural
    % network performs.
    genFunction(net,'myNeuralNetworkFunction');
    y = myNeuralNetworkFunction(x);
end
if (false)
    % Generate a matrix-only MATLAB function for neural network code
    % generation with MATLAB Coder tools.
    genFunction(net,'myNeuralNetworkFunction','MatrixOnly','yes');
    y = myNeuralNetworkFunction(x);
end
if (false)
    % Generate a Simulink diagram for simulation or deployment with.
    % Simulink Coder tools.
    gensim(net);
end


%% Test Model with Data
% Sample Data
NoseRadius = [0.4 0.4 0.8 0.8 0.8];
CuttingSpeed = [250 250 250 250 250];
FeedRate = [0.18 0.18 0.18 0.18 0.18];
DepthOfCut = [0.25 0.25 0.25 0.25 0.25];
% Expected Data
ForceRatio = [0.324,0.281,0.256,0.26,0.181];
SurfaceRoughness = [2.557 2.773 1.827 2.403 2.987];
MaximumSurfaceRoughness = [12.387 13.478 9.110 13.878 18.304];

% Test Model for error
prediction = [];
for i = 1:5
    test = [NoseRadius(i),CuttingSpeed(i),FeedRate(i),DepthOfCut(i)];
    test = test';
    y = net(test);
    % Print Expected and Predicted Value
    fprintf('Test %d\n',i);
    fprintf('Nose Radius: %f\n',NoseRadius(i));
    fprintf('Cutting Speed: %f\n',CuttingSpeed(i));
    fprintf('Feed Rate: %f\n',FeedRate(i));
    fprintf('Depth of Cut: %f\n',DepthOfCut(i));
    fprintf('Predicted Force Ratio: %f\n',y(1));
    fprintf('Expected Force Ratio: %f\n',ForceRatio(i));
    fprintf('Error Force Ratio: %f\n',abs(ForceRatio(i)-y(1)));
    fprintf('Predicted Surface Roughness: %f\n',y(2));
    fprintf('Expected Surface Roughness: %f\n',SurfaceRoughness(i));
    fprintf('Error Surface Roughness: %f\n',abs(SurfaceRoughness(i)-y(2)));
    fprintf('Predicted Maximum Surface Roughness: %f\n',y(3));
    fprintf('Expected Maximum Surface Roughness: %f\n',MaximumSurfaceRoughness(i));
    fprintf('Error Maximum Surface Roughness: %f\n',abs(MaximumSurfaceRoughness(i)-y(3)));
    fprintf('\n');
    prediction = [prediction,y];
end

prediction = prediction';

% Plot graph comparing the expected and predicted values
figure;
subplot(3,1,1);
plot(1:5,ForceRatio,'-o',1:5,prediction(:,1),'-o');
title('Force Ratio');
xlabel('Test');
ylabel('Force Ratio');
legend('Expected','Predicted');
subplot(3,1,2);
plot(1:5,SurfaceRoughness,'-o',1:5,prediction(:,2),'-o');
title('Surface Roughness');
xlabel('Test');
ylabel('Surface Roughness');
legend('Expected','Predicted');
subplot(3,1,3);
plot(1:5,MaximumSurfaceRoughness,'-o',1:5,prediction(:,3),'-o');
title('Maximum Surface Roughness');
xlabel('Test');
ylabel('Maximum Surface Roughness');
legend('Expected','Predicted');

