From f0c9988d2ced1c6e7495a11292117d7d0411516b Mon Sep 17 00:00:00 2001 From: Erik Frisk <erik.frisk@liu.se> Date: Tue, 19 Jun 2018 23:24:46 +0200 Subject: [PATCH] Slight cleanup of code and added SingleFaultIsolation.m to src directory --- README.md | 2 +- code/main.m | 154 +++++++++++++++++--------------- code/src/SingleFaultIsolation.m | 14 +++ 3 files changed, 97 insertions(+), 73 deletions(-) create mode 100644 code/src/SingleFaultIsolation.m diff --git a/README.md b/README.md index e0625ce..d6fae27 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ This repository contains data and code to generate results from the paper _Residual Selection for Consistency Based Diagnosis Using Machine Learning Models_ -by Erik Frisk and Mattias Krysander, Department of Electrical Engineering, Linköping Univeristy, Sweden \ No newline at end of file +by Erik Frisk and Mattias Krysander, Department of Electrical Engineering, Linköping University, Sweden diff --git a/code/main.m b/code/main.m index d86569f..844a08c 100644 --- a/code/main.m +++ b/code/main.m @@ -1,6 +1,6 @@ % This script produces the results shown in: % -% Erik Frisk and Mattias Krysander (2018). Residaul Selection for +% Erik Frisk and Mattias Krysander (2018). Residual Selection for % Consistency Based Diagnosis Using Machine Learning Models. In Safeprocess % 2018, Warsaw, Polen. % @@ -52,47 +52,48 @@ plotResiduals(absdata) clear absdata %% Plot Fig. 5: Probability of residual alarm given a given mode -no_residuals = size(data.res,2); -all_residuals =[1:no_residuals]; % select all residuals -plotDecisionMatrix(all_residuals,data); +no_residuals = size(data.res, 2); +all_residuals = 1:no_residuals; % select all residuals +plotDecisionMatrix(all_residuals, data); clear no_residuals ans %% Plot Fig 6: Structural isolability of all available residuals load model.mat; -figure; -model.IsolabilityAnalysisFSM(data.fsm(:,[2:8]),'permute',0); +figure(16); +model.IsolabilityAnalysisFSM(data.fsm(:, 2:8), 'permute', 0); title('Structural isolability matrix using all available tests'); -ylabel('Injected fault','FontWeight', 'bold'); -xlabel('Diagnsoed fault','FontWeight', 'bold'); +ylabel('Injected fault', 'FontWeight', 'bold'); +xlabel('Diagnsoed fault', 'FontWeight', 'bold'); clear ans + %% Create thresholded residuals thdata = data; -thdata.res = abs(data.res)>=1; +thdata.res = abs(data.res) >= 1; %% Plot Fig 7: Confusion matrix obtained by consistency-based diagnosis (CBD) using all thresholded residuals -figure; -CBDPlots(thdata,model,all_residuals); +figure(17); +CBDPlots(thdata, model, all_residuals); clear all_residuals ans %% Train a random forest of 100 classification trees using the all data. trees = 100; rng(1); % For reproducibility -t = templateTree('PredictorSelection','interaction-curvature'); +t = templateTree('PredictorSelection', 'interaction-curvature'); fprintf('Building random forest classifier ... '); tic; -Mdl = fitcensemble(single(thdata.res),thdata.mode,'Method','bag',... - 'NumLearningCycles',trees,'Learners',t); +Mdl = fitcensemble(single(thdata.res), thdata.mode, 'Method', 'bag',... + 'NumLearningCycles', trees, 'Learners', t); fprintf(' Finished in %.2f sec.\n', toc); clear t trees %% Plot Fig 8: Random forest classification performance using all tests on out-of-bag data. Y = oobPredict(Mdl); -Ival = confusionmat(categorical(thdata.mode),categorical(Y)); +Ival = confusionmat(categorical(thdata.mode), categorical(Y)); nf = 8; -C = Ival./(sum(Ival')'*ones(1,nf)); +C = Ival./(sum(Ival, 2)*ones(1, nf)); -figure; +figure(18); b = bar3(C); title('Confusion matrix - Validation data set') set(gca, 'XTickLabel', data.modes, 'TickLabelInterpreter', 'none') @@ -104,8 +105,9 @@ title('Fault Isolation Performance Matrix') for finjIdx=1:nf for fdiagIdx=1:nf - text(fdiagIdx,finjIdx,C(finjIdx,fdiagIdx)+0.05,... - sprintf('%.1f',C(finjIdx,fdiagIdx)*100),'HorizontalAlignment', 'center') + text(fdiagIdx, finjIdx, C(finjIdx, fdiagIdx) + 0.05,... + sprintf('%.1f', C(finjIdx,fdiagIdx)*100), ... + 'HorizontalAlignment', 'center') end end for k = 1:length(b) @@ -114,15 +116,15 @@ for k = 1:length(b) b(k).FaceColor = 'interp'; end colormap('Summer') -view(0,90) +view(0, 90) clear Y Ival nf C b fdiagIdx finjIdx k zdata thdata %% Plot Fig 9: Random forest out-of-bag classification error as a function of the number of trees. -figure; -oobErr = oobLoss(Mdl,'mode','cumulative'); -plot(oobErr,'LineWidth',2) -xlabel( 'Number of grown trees' , 'FontWeight', 'bold'); -ylabel( 'Out-of-bag classification error' , 'FontWeight', 'bold'); +figure(19); +oobErr = oobLoss(Mdl, 'mode', 'cumulative'); +plot(oobErr, 'LineWidth', 2) +xlabel('Number of grown trees', 'FontWeight', 'bold'); +ylabel('Out-of-bag classification error', 'FontWeight', 'bold'); clear oobErr %% Estimate residual importance by permuting out-of-bag observations. @@ -132,13 +134,14 @@ importance = oobPermutedPredictorImportance(Mdl); fprintf(' Finished in %.2f sec.\n', toc); %% Plot Fig 10: Residual importance -[imp,residualRanking] = sort(importance,'descend'); +[imp,residualRanking] = sort(importance, 'descend'); -figure; -plot(imp,'LineWidth',2) -xticks([1:length(residualRanking)]) +figure(20); +plot(imp,'LineWidth', 2) +xticks(1:length(residualRanking)) axis([0 43 -0.4 1.6]) -set(gca, 'XTickLabel', residualRanking, 'TickLabelInterpreter', 'none', 'FontSize',8) +set(gca, 'XTickLabel', residualRanking, 'TickLabelInterpreter', 'none', ... + 'FontSize', 8) title('Out-of-Bag Permuted Predictor Importance Estimates'); ylabel('Estimates','FontWeight', 'bold'); xlabel('Predictors','FontWeight', 'bold'); @@ -146,80 +149,87 @@ clear imp %% Performance evaluation of selected tests using consistency based diagnosis. -no_samples = size(data.res,1); % n +no_samples = size(data.res, 1); % n no_modes = numel(data.modes); % m no_of_samples_per_mode = no_samples/no_modes; % k -structuralIsolationMatrix = model.IsolabilityAnalysisFSM(data.fsm(:,[2:8]),'permute',0); +structuralIsolationMatrix = ... + model.IsolabilityAnalysisFSM(data.fsm(:, 2:8),'permute', 0); + +stim2 = sum(((2.^(0:6)).*structuralIsolationMatrix), 2); +probabilityMaximumIsolation = zeros(42, no_modes-1); -stim2 = sum(((2.^[0:6]).*structuralIsolationMatrix)'); -probabilityMaximumIsolation = zeros(42,no_modes-1); -C ={}; +C = cell(length(residualRanking), 1); +isolationerror = zeros(length(residualRanking), 1); +mean_md = zeros(length(residualRanking), 1); +fa = zeros(length(residualRanking), 1); for i = 1:length(residualRanking) - selected_residauls = residualRanking(1:i); % select the i best residuals - dx = SingleFaultIsolation(data.res(:,selected_residauls),... - data.fsm(selected_residauls,[2:8])); % apply CBD. + selected_residuals = residualRanking(1:i); % select the i best residuals + dx = SingleFaultIsolation(data.res(:, selected_residuals),... + data.fsm(selected_residuals, (2:8))); % apply CBD. % Compute for each mode the probability of maximum isolation - dx2 = sum(((2.^[0:6]).*dx(:,[2:end]))'); + dx2 = sum(((2.^(0:6)).*dx(:, (2:end))), 2); for j = 1:no_modes-1 % not NF - probabilityMaximumIsolation(i,j) = sum(dx2([1:no_of_samples_per_mode]+... + probabilityMaximumIsolation(i,j) = sum(dx2((1:no_of_samples_per_mode)+... j*no_of_samples_per_mode)==stim2(j))/no_of_samples_per_mode; end % Compute confusion matrix of CBD using the i best residuals - C{i} = CBDPlots(data,model,selected_residauls); + C{i} = CBDPlots(data, model, selected_residuals); % Compute performance indicators isolationerror(i) = sum(sum(abs(structuralIsolationMatrix-C{i}(2:8,2:8)./((1-C{i}(2:end,1))*ones(1,7)))))/7^2; - mean_md(i) = mean(C{i}(2:end,1)); - fa(i) = 1-C{i}(1,1); + mean_md(i) = mean(C{i}(2:end, 1)); + fa(i) = 1-C{i}(1, 1); end -clear stim2 dx dx2 no_samples no_modes no_of_samples_per_mode selected_residauls C +clear stim2 dx dx2 no_samples no_modes no_of_samples_per_mode selected_residuals C clear structuralIsolationMatrix i j %% Plot Fig 11: False alarm probability, mean missed detection probability, % and aggregated isolation error as a function of selected tests. -figure; -plot([mean_md;fa;isolationerror]','LineWidth',2) +figure(21); +plot([mean_md, fa, isolationerror], 'LineWidth', 2) hold -selected_no_of_residauls = [12 14 26 27]; -plot(selected_no_of_residauls,isolationerror(selected_no_of_residauls),'x',... - 'LineWidth',2,'MarkerSize',8,'Color','k') +selected_no_of_residuals = [12 14 26 27]; +plot(selected_no_of_residuals,isolationerror(selected_no_of_residuals), ... + 'x', 'LineWidth', 2, 'MarkerSize', 8, 'Color', 'k') -legend('Missed detection probability','False alarm probability','Fault isolation errors') -xlabel('Number of selected residauls','FontWeight', 'bold') -ylabel('Probability','FontWeight', 'bold') +legend('Missed detection probability', 'False alarm probability', ... + 'Fault isolation errors') +xlabel('Number of selected residuals','FontWeight', 'bold') +ylabel('Probability', 'FontWeight', 'bold') grid on -clear mean_md isolationerror selected_no_of_residauls +clear mean_md isolationerror selected_no_of_residuals %% Plot Fig 12: Consistency based isolation performance per mode as a function of number of selected residuals. -figure; -plot([1-fa; probabilityMaximumIsolation']','LineWidth',2) +figure(22); +plot([1-fa, probabilityMaximumIsolation], 'LineWidth', 2) l = legend(data.modes{1:end}); set(l, 'Interpreter', 'none') -xlabel('Number of selected residuals','FontWeight', 'bold') -ylabel('Probability of maximum isolation performance','FontWeight', 'bold') +xlabel('Number of selected residuals', 'FontWeight', 'bold') +ylabel('Probability of maximum isolation performance', 'FontWeight', 'bold') grid on clear probabilityMaximumIsolation fa l %% Plot Fig 13: Consistency-based diagnosis results obtained when running different numbers k of most important residuals. % Plots the cases when using 10, 12, 26, and 27 residuals: -selected_no_of_residauls = [10 12 26 27]; -figure; -C ={}; -for i = 1:length(selected_no_of_residauls) - subplot(2,2,i); - selected_residauls = residualRanking(1:selected_no_of_residauls(i)); - C{i} = CBDPlots(data,model,selected_residauls); - title(['No of tests: ' num2str(selected_no_of_residauls(i))]); +selected_no_of_residuals = [10 12 26 27]; +figure(23); +C = cell(length(selected_no_of_residuals), 1); +for i = 1:length(selected_no_of_residuals) + subplot(2, 2, i); + selected_residuals = residualRanking(1:selected_no_of_residuals(i)); + C{i} = CBDPlots(data, model, selected_residuals); + title(['No of tests: ' num2str(selected_no_of_residuals(i))]); end clear C i %% Plot structural isolability using the k best residuals. Compare with previous plot. -figure; -for i = 1:length(selected_no_of_residauls) - subplot(2,2,i) - selected_residauls = residualRanking(1:selected_no_of_residauls(i)); - model.IsolabilityAnalysisFSM(data.fsm(selected_residauls,[2:8]),'permute',0); % full str isolability - title(['No of tests: ' num2str(selected_no_of_residauls(i))]) +figure(24); +for i = 1:length(selected_no_of_residuals) + subplot(2, 2, i) + selected_residuals = residualRanking(1:selected_no_of_residuals(i)); + model.IsolabilityAnalysisFSM(data.fsm(selected_residuals, (2:8)), ... + 'permute', 0); % full str isolability + title(['No of tests: ' num2str(selected_no_of_residuals(i))]) end -%clear selected_no_of_residauls selected_residauls residualRanking i ans +%clear selected_no_of_residuals selected_residuals residualRanking i ans diff --git a/code/src/SingleFaultIsolation.m b/code/src/SingleFaultIsolation.m new file mode 100644 index 0000000..7673f5a --- /dev/null +++ b/code/src/SingleFaultIsolation.m @@ -0,0 +1,14 @@ +function isol=SingleFaultIsolation( res, FSM ) + N = size(res,1); + nf = size(FSM,2); + + isol = zeros(N,nf + 1); + for k=1:N + alarms = abs(res(k,:))>=1; + if any(alarms) + isol(k,:) = [false all(FSM(alarms,:),1)]; + else + isol(k,:) = [true boolean(zeros(1,nf))]; + end + end +end \ No newline at end of file -- GitLab