├── ECG_MMF.m ├── GenDrift.m ├── GenNoise.m ├── GenStrel.m ├── LICENSE.txt ├── Project_Review.pdf ├── README.md ├── closing.m ├── dataset ├── 100m.mat ├── 101m.mat ├── 102m.mat ├── 103m.mat ├── 104m.mat ├── 105m.mat ├── 106m.mat ├── 107m.mat ├── 108m.mat ├── 109m.mat ├── 111m.mat ├── 112m.mat ├── 113m.mat ├── 114m.mat ├── 115m.mat ├── 116m.mat ├── 117m.mat ├── 118m.mat ├── 119m.mat ├── 121m.mat ├── 122m.mat ├── 123m.mat ├── 124m.mat ├── 200m.mat ├── 201m.mat ├── 202m.mat ├── 203m.mat ├── 205m.mat ├── 207m.mat ├── 208m.mat ├── 209m.mat ├── 210m.mat ├── 212m.mat ├── 213m.mat ├── 214m.mat ├── 215m.mat ├── 217m.mat ├── 219m.mat ├── 220m.mat ├── 221m.mat ├── 222m.mat ├── 223m.mat ├── 228m.mat ├── 230m.mat ├── 231m.mat ├── 232m.mat ├── 233m.mat └── 234m.mat ├── dilatation.m ├── erosion.m └── opening.m /ECG_MMF.m: -------------------------------------------------------------------------------- 1 | %% Load Dataset and apply butterworth filter on it 2 | clc; % Clear the command window. 3 | close all; % Close all figures (except those of imtool.) 4 | clear; % Erase all existing variables. 5 | workspace; % Make sure the workspace panel is showing. 6 | format long g; 7 | format compact; 8 | fontSize = 15; 9 | markerSize = 8; 10 | % load all the data 11 | G = 200; % Gain 12 | Fs = 360; % [Hz] 13 | L = 3600; % lenght of ECG signals 14 | T = linspace(0,L/Fs,L); % time axis 15 | F = linspace(-Fs/2, Fs/2, L); % Frequency axis 16 | files = dir(fullfile("dataset/","*.mat")); % all dataset files 17 | numData = numel(files); % number of data 18 | ECGs = zeros(numData,L); % prealloc 19 | % load and store data 20 | for i = 1:numData 21 | load(fullfile("dataset/",files(i).name)); % load all data 22 | ECGs(i,:) = val/G; 23 | end 24 | % Plot the signal/s you want 25 | figure(1); plot(T, ECGs(1,:)); grid on; 26 | title("ECG Signal","FontSize",fontSize); 27 | xlabel("Time (sec)", "FontSize", fontSize); 28 | ylabel("voltage [mV]", "FontSize", fontSize); 29 | % Define a Butterworth Filter 30 | [b,a] = butter(3,[1 30]/(Fs/2),"bandpass"); 31 | FLT_ECGs = zeros(numData,L); % prealloc 32 | % filter all signals 33 | for i = 1:numData 34 | FLT_ECGs(i,:) = filtfilt(b,a,ECGs(i,:)); 35 | end 36 | % Plot the Filterd signals you want 37 | figure(2); plot(T, FLT_ECGs(1,:)); grid on; 38 | title("Clean ECG signal","FontSize",fontSize); 39 | xlabel("Time (sec)", "FontSize", fontSize); 40 | ylabel("voltage [mV]", "FontSize", fontSize); 41 | clear a b files val; 42 | 43 | %% Add random generated Noise to all the signals 44 | close all; 45 | % Prealloc 46 | NS_ECGs = zeros(numData, L); 47 | SNR = zeros(1,numData); 48 | % Add noise to all signals 49 | for i = 1:numData 50 | % generate random snr for all signals 51 | SNR(i) = 1 + (10 - 1).*rand(1); 52 | % additive white gaussian noise 53 | NS_ECGs(i,:) = awgn(FLT_ECGs(i,:),SNR(i),'measured'); 54 | end 55 | % Plot the Noisy Signal of the signals 56 | figure(1); plot(T, NS_ECGs(1,:), "b-"); grid on; 57 | title("Noisy ECG Signal", "FontSize", fontSize); 58 | xlabel("Time (sec)", "FontSize", fontSize); 59 | ylabel("Voltage (Hz)", "FontSize", fontSize); 60 | clear SNR; 61 | 62 | %% Add random generated Baseline drift to all signals 63 | close all; 64 | % prealloc 65 | DFT_ECGs = zeros(numData,L); 66 | % Call funtion to generate drift 67 | drift = GenDrift(numData,L); 68 | % Apply drift to all signals 69 | for i = 1:numData 70 | DFT_ECGs(i,:) = NS_ECGs(i,:) + drift(i,:); 71 | end 72 | % Plot the Filterd signal/s you want 73 | figure(1); plot(T, DFT_ECGs(1,:), "b-"); grid on; 74 | title("Drifted ECG signal", "FontSize", fontSize); 75 | xlabel("Time (sec)", "FontSize", fontSize); 76 | ylabel("Voltage (Hz)", "FontSize", fontSize); 77 | clear drift; 78 | 79 | %% Baseline correction 80 | close all; 81 | % Defining the two structuring element 82 | Bo = ones(1,0.2*Fs+1); % Bo = strel('line',0.2*Fs,0); 83 | Bc = ones(1,round(1.5*0.2*Fs+1)); % Bc = strel('line',1.5*0.2*Fs,0); 84 | % Prealloc 85 | peaksSuppression = zeros(numData,L); 86 | pitsSuppression = zeros(numData,L); 87 | detectedDrift = zeros(numData,L); 88 | Correction = zeros(numData,L); 89 | finalBaseline = zeros(numData,L); 90 | % Opening and Closing application to all signals 91 | for i=1:numData 92 | % Opening: erosion B dilatation B 93 | peaksSuppression(i,:) = opening(DFT_ECGs(i,:), Bo); % peaksSuppression(i,:) = imopen(DFT_ECGs(i,:), Bo); 94 | % closing: dilatation B erosion B 95 | pitsSuppression(i,:) = closing(DFT_ECGs(i,:), Bc); % pitsSuppression(i,:) = imclose(DFT_ECGs(i,:), Bo); 96 | end 97 | % Plot the representation of Op. and Cls. operation 98 | figure(1); subplot(2,1,1); hold on; 99 | plot(T, peaksSuppression(1,:),"g-","LineWidth",3); 100 | plot(T, DFT_ECGs(1,:), "b-","LineWidth",0.5); 101 | title("Opening operation", "FontSize", fontSize); 102 | xlabel("Time (sec)", "FontSize", fontSize); 103 | ylabel("Voltage (Hz)", "FontSize", fontSize); 104 | legend("Opening","Signal"); 105 | grid on; hold off; 106 | subplot(2,1,2); hold on; 107 | plot(T, pitsSuppression(1,:),"g-","LineWidth",3); 108 | plot(T, DFT_ECGs(1,:), "b-","LineWidth",0.5); 109 | title("Closing operation", "FontSize", fontSize); 110 | xlabel("Time (sec)", "FontSize", fontSize); 111 | ylabel("Voltage (Hz)", "FontSize", fontSize); 112 | legend("Closing","Signal"); 113 | grid on; hold off; 114 | % Detection and Correction of the Wandering Baseline 115 | % Apply Op. and Cls. to detect the drift 116 | for i=1:numData 117 | peaksSuppression(i,:) = opening(DFT_ECGs(i,:), Bo); % peaksSuppression(i,:) = imopen(DFT_ECGs(i,:), Bo); 118 | pitsSuppression(i,:) = closing(peaksSuppression(i,:), Bc); % pitsSuppression(i,:) = imclose(peaksSuppression(i,:), Bc); 119 | % Detected drift of all sinals 120 | detectedDrift(i,:) = pitsSuppression(i,:); 121 | end 122 | % Correction subtracting the drift from signals 123 | for i=1:numData 124 | % Signal With Baseline drift corrected 125 | Correction(i,:) = DFT_ECGs(i,:) - detectedDrift(i,:); 126 | % Finale Baseline result 127 | finalBaseline(i,:) = closing(opening(Correction(i,:),Bo),Bc); % finalBaseline(i,:) = imclose(imopen(Correction(i,:), Bo),Bc); 128 | end 129 | % Plot Corrected Signal and Baseline 130 | figure(2); subplot(2,1,1); hold on; 131 | plot(T, detectedDrift(1,:),"g-","LineWidth",3); 132 | plot(T, DFT_ECGs(1,:), "b-","LineWidth",0.5); 133 | title("Detected Baseline Drift", "FontSize", fontSize); 134 | xlabel("Time (sec)", "FontSize", fontSize); 135 | ylabel("Voltage (Hz)", "FontSize", fontSize); 136 | legend("Baseline","Signal"); 137 | grid on; hold off; 138 | subplot(2,1,2); hold on; 139 | plot(T, finalBaseline(1,:),"g-","LineWidth",3); 140 | plot(T, Correction(1,:), "b-","LineWidth",0.5); 141 | title("Drift Correction", "FontSize", fontSize); 142 | xlabel("Time (sec)", "FontSize", fontSize); 143 | ylabel("Voltage (Hz)", "FontSize", fontSize); 144 | legend("Baseline","Signal"); 145 | grid on; hold off; 146 | 147 | %% Noise Suppression with MMF Algorithm 148 | close all; 149 | % Prealloc 150 | dilatation_1 = zeros(numData,L); 151 | erosion_1 = zeros(numData,L); 152 | dilatation_2 = zeros(numData,L); 153 | erosion_2 = zeros(numData,L); 154 | MMF_denoise = zeros(numData,L); 155 | % Defining the two structuring element 156 | B1 = [0 1 5 1 0]; B2 = [1 1 1 1 1]; 157 | % Apply the Algorithm for all signals 158 | % 1/2*((Fbc dilatation B1 erosion B2) + (Fbc erosion B1 dilatation B2)) 159 | for i = 1:numData 160 | dilatation_1(i,:) = dilatation(Correction(i,:), B1); % dilatation 161 | erosion_1(i,:) = erosion(dilatation_1(i,:), B2); % erosion 162 | erosion_2(i,:) = erosion(Correction(i,:), B1); % erosion 163 | dilatation_2(i,:) = dilatation(erosion_2(i,:), B2); % dilatation 164 | MMF_denoise(i,:) = (erosion_1(i,:) + dilatation_2(i,:))/2; % average 165 | end 166 | % Plot denoised signal with MMF algorithm 167 | figure(1); plot(T, MMF_denoise(1,:), "b-"); grid on; 168 | title("MMF Denoised Ecg signal", "FontSize", fontSize); 169 | xlabel("Time (sec)", "FontSize", fontSize); 170 | ylabel("Voltage (Hz)", "FontSize", fontSize); 171 | clear dilatation_1 dilatation_2 erosion_1 erosion_2; 172 | 173 | %% Noise Suppressione with MF Algorithm 174 | % Prealloc 175 | MF_op_cl = zeros(numData,L); 176 | MF_cl_op = zeros(numData,L); 177 | MF_denoise = zeros(numData,L); 178 | % Defining the structuring element 179 | B = [0 1 5 1 0]; 180 | % Apply the Algorithm for all signals 181 | % 1/2*((Fbc opening B closing B) + (Fbc closing B opening B)) 182 | for i = 1:numData 183 | % op. and cl. 184 | MF_op_cl(i,:) = closing(opening(Correction(i,:),B),B); 185 | % cl. and op. 186 | MF_cl_op(i,:) = opening(closing(Correction(i,:),B),B); 187 | % average 188 | MF_denoise(i,:) = (MF_op_cl(i,:) + MF_cl_op(i,:))/2; 189 | end 190 | % Plot denoised signal with Chu's MF algorithm 191 | figure(2); plot(T, MF_denoise(1,:), "b-"); grid on; 192 | title("CHU's MF Denoised Ecg signal", "FontSize", fontSize); 193 | xlabel("Time (sec)", "FontSize", fontSize); 194 | ylabel("Voltage (Hz)", "FontSize", fontSize); 195 | clear MF_op_cl MF_cl_op; 196 | 197 | %% Evaluation of the algorithms 198 | close all; 199 | % Prealloc 200 | MMF_NSR = zeros(1,numData); 201 | MF_NSR = zeros(1,numData); 202 | MMF_SDR = zeros(1,numData); 203 | MF_SDR = zeros(1,numData); 204 | % Compute NSR and SDR of the two method 205 | for i = 1:numData 206 | % NSR (Noise Suppression Ratio) bigger the better 207 | MMF_NSR(i) = sum(abs(fft(MMF_denoise(i,:))))/sum(abs(fft(FLT_ECGs(i,:)))); % MMF's NSR of all signals 208 | MF_NSR(i) = sum(abs(fft(MF_denoise(i,:))))/sum(abs(fft(FLT_ECGs(i,:)))); % MF's NSR of all signals 209 | % SDR (Signal Distortion Ratio) smaller the better 210 | MMF_SDR(i) = sum(abs(fft(FLT_ECGs(i,:) - MMF_denoise(i,:))))/sum(abs(fft(MMF_denoise(i,:)))); % MMF's SDR of all signal 211 | MF_SDR(i) = sum(abs(fft(FLT_ECGs(i,:) - MF_denoise(i,:))))/sum(abs(fft(MF_denoise(i,:)))); % MF's SDR of all signal 212 | end 213 | % Graphical Representation of the NSR 214 | figure(1); hold on; grid on; 215 | plot(MF_NSR,'-^r','LineWidth',1,'MarkerSize',markerSize); 216 | plot(MMF_NSR,'-ob','LineWidth',1,'MarkerSize',markerSize); 217 | hold off; xticks(0:50); 218 | title("Comparison of NSRs", "FontSize", fontSize); 219 | xlabel("Signals", "FontSize", fontSize); 220 | ylabel("NSR", "FontSize", fontSize); 221 | legend("Chu's MF Algorithm", "MMF Algorithm", "FontSize", fontSize); 222 | 223 | % Graphical Representation of the SDR 224 | figure(2); hold on; grid on; 225 | plot(MF_SDR,'-^r','LineWidth',1,'MarkerSize',markerSize); 226 | plot(MMF_SDR,'-ob','LineWidth',1,'MarkerSize',markerSize); 227 | hold off; xticks(0:50); 228 | title("comparison of SDRs", "FontSize", fontSize); 229 | xlabel("Signals", "FontSize", fontSize); 230 | ylabel("SDR", "FontSize", fontSize); 231 | legend("Chu's MF Algorithm","MMF Algorithm", "FontSize", fontSize); 232 | 233 | %% Evaluation changing the dimension of the structuring element 234 | close all; 235 | % Define the dim. of strel 236 | N = 100; 237 | % Prealloc 238 | S1 = cell(1,N); % strel one 239 | S2 = cell(1,N); % strel two 240 | dataset = cell(1,N); % dataset as cell array 241 | snr = zeros(1,N); 242 | % Generate Structuring Elements 243 | for i = 1:N 244 | S1(i) = {GenStrel(i)}; % strel 1 245 | S2(i) = {ones(1,length(S1{i}))}; % strel 2 246 | dataset(i) = {FLT_ECGs}; 247 | snr(i) = 1 + (30 - 1).*rand(1); % define random snr 248 | end 249 | % Generate increasing noise 250 | snr = sort(snr,"descend"); 251 | noisy_dataset = cell(1,N); 252 | % Add noise to dataset 253 | for i = 1:N 254 | noisy_dataset(i) = {awgn(dataset{i},snr(i),'measured')}; 255 | end 256 | 257 | % Apply MMF algorithm with various strel length 258 | curr_mmf = zeros(numData,L); 259 | all_mmf = cell(1,N); 260 | dl_er = zeros(numData,L); 261 | er_dl = zeros(numData,L); 262 | for j=1:N 263 | s1 = S1{j}; 264 | s2 = S2{j}; 265 | for i=1:numData % Compute the Algorithm 266 | dl_er(i,:) = erosion(dilatation(noisy_dataset{j}(i,:), s1), s2); 267 | er_dl(i,:) = dilatation(erosion(noisy_dataset{j}(i,:), s1), s2); 268 | curr_mmf(i,:) = (dl_er(i,:) + er_dl(i,:))/2; 269 | all_mmf(j) = {curr_mmf}; 270 | end 271 | end 272 | clear curr_mmf dl_er er_dl; % clear no more necessary variable 273 | 274 | % Prealloc 275 | curr_nsr = zeros(1,numData); 276 | all_mmf_nsr = cell(1,N); 277 | curr_sdr = zeros(1,numData); 278 | all_mmf_sdr = cell(1,N); 279 | % Compute NSRs and SDRs 280 | for j=1:N 281 | current_dataset = all_mmf{j}; % select current dataset 282 | for i=1:numData 283 | % MMF NSR: 284 | curr_nsr(i) = sum(abs(fft(current_dataset(i,:))))/sum(abs(fft(FLT_ECGs(i,:)))); % current dataset NSR values 285 | all_mmf_nsr(j) = {curr_nsr}; % all values of NSRs per dataset defined as strel grows 286 | % MMF SDR: 287 | curr_sdr(i) = sum(abs(fft(FLT_ECGs(i,:)-current_dataset(i,:))))/sum(abs(fft(current_dataset(i,:)))); 288 | all_mmf_sdr(j) = {curr_sdr}; % nsr di tutti e 48 i messaggi, uno per ogni strel 289 | end 290 | end 291 | clear current_dataset curr_nsr curr_sdr; % clear no more necessary variable 292 | 293 | % Prealloc 294 | op_cl = zeros(numData,L); 295 | cl_op = zeros(numData,L); 296 | curr_mf = zeros(numData,L); 297 | all_mf = cell(1,N); 298 | % Apply Chu's MF algorithm with various strel length 299 | for j=1:N 300 | s1 = S1{j}; 301 | % Compute the MF Algorithm 302 | for i=1:numData 303 | op_cl(i,:) = closing(opening(noisy_dataset{j}(i,:),s1),s1); 304 | cl_op(i,:) = opening(closing(noisy_dataset{j}(i,:),s1),s1); 305 | curr_mf(i,:) = (op_cl(i,:) + cl_op(i,:))/2; 306 | all_mf(j) = {curr_mf}; 307 | end 308 | end 309 | clear curr_mf op_cl cl_op all_mmf s1 s2; % clear no more necessary variable 310 | 311 | % Prealloc 312 | curr_nsr = zeros(1,numData); 313 | all_mf_nsr = cell(1,N); 314 | curr_sdr = zeros(1,numData); 315 | all_mf_sdr = cell(1,N); 316 | % Compute NSRs and SDRs 317 | for j=1:N 318 | current_dataset = all_mf{j}; % select current dataset 319 | for i=1:numData 320 | % MMF NSR: 321 | curr_nsr(i) = sum(abs(fft(current_dataset(i,:))))/sum(abs(fft(FLT_ECGs(i,:)))); % current dataset NSR values 322 | all_mf_nsr(j) = {curr_nsr}; % all values of NSRs per dataset defined as strel grows 323 | % MMF SDR: 324 | curr_sdr(i) = sum(abs(fft(FLT_ECGs(i,:)-current_dataset(i,:))))/sum(abs(fft(current_dataset(i,:)))); 325 | all_mf_sdr(j) = {curr_sdr}; % nsr di tutti e 48 i messaggi, uno per ogni strel 326 | end 327 | end 328 | clear current_dataset curr_nsr curr_sdr all_mf; % clear no more necessary variable 329 | 330 | % Defining mean of all mmf and mf result and confront it 331 | mean_mmf_nsr = cellfun(@(x) mean(x, "all"), all_mmf_nsr); 332 | mean_mmf_sdr = cellfun(@(x) mean(x, "all"), all_mmf_sdr); 333 | mean_mf_nsr = cellfun(@(x) mean(x, "all"), all_mf_nsr); 334 | mean_mf_sdr = cellfun(@(x) mean(x, "all"), all_mf_sdr); 335 | % Evaluation 336 | % Graphical Representation of the NSR 337 | figure(1); hold on; grid on; 338 | plot(mean_mf_nsr,'-^r','LineWidth',1); 339 | plot(mean_mmf_nsr,'-ob','LineWidth',1); 340 | hold off; 341 | get(gca,'XTickLabel'); set(gca,'XTickLabel',(1:2:2*N-1)); 342 | xticks(1:2*N-1); 343 | title("NSRs as Strel grows", "FontSize", fontSize); 344 | xlabel("strel growing", "FontSize", fontSize); 345 | ylabel("NSR", "FontSize", fontSize); 346 | legend("Chu's MF Algorithm", "MMF Algorithm"); 347 | % Graphical Representation of the SDR 348 | figure(2); hold on; grid on; 349 | plot(mean_mf_sdr,'-^r','LineWidth',1); 350 | plot(mean_mmf_sdr,'-ob','LineWidth',1); 351 | get(gca,'XTickLabel'); set(gca,'XTickLabel',(1:2:2*N-1)); 352 | hold off; xticks(1:2*N-1); 353 | title("SDRs as Strel grows", "FontSize", fontSize); 354 | xlabel("strel growing", "FontSize", fontSize); 355 | ylabel("SDR", "FontSize", fontSize); 356 | legend("Chu's MF Algorithm","MMF Algorithm"); 357 | -------------------------------------------------------------------------------- /GenDrift.m: -------------------------------------------------------------------------------- 1 | function [drift] = GenDrift(Data,L) 2 | % Generate Random values to define a random drift 3 | % Argoments: 4 | % - Data: number of data in the dataset 5 | % - L: length of the signals 6 | % Method: r = a + (b-a).*rand(N,1) 7 | % to obtain random value 8 | % between the interval [a b] 9 | 10 | % Prealloc data 11 | A = zeros(1,Data); 12 | N = zeros(1,Data); 13 | minDriftOffset = zeros(1,Data); 14 | maxDriftOffset = zeros(1,Data); 15 | drift = zeros(Data,L); 16 | 17 | % Vaiable for random genreation of data - Values ​​can be changed 18 | % Amplitude range 19 | aA = 0.1; bA = 0.8; 20 | % Sinusoid period range 21 | aN = 1; bN = 3; 22 | % Slanted Line slope range 23 | aMin = 0; bMin = 0.5; 24 | aMax = 0.5; bMax = 3; 25 | % Generate random values 26 | for i = 1:Data 27 | A(i) = aA + (bA-aA).*rand(1); 28 | N(i) = aN + (bN-aN).*rand(1); 29 | minDriftOffset(i) = aMin + (bMin-aMin).*rand(1); 30 | maxDriftOffset(i) = aMax + (bMax-aMax).*rand(1); 31 | X = linspace(0,2*pi,L); 32 | cos_wave = A(i)*cos(X./N(i)); 33 | slantedLine = linspace(minDriftOffset(i),maxDriftOffset(i),L); 34 | drift(i,:) = cos_wave + slantedLine; 35 | end 36 | 37 | end 38 | 39 | 40 | -------------------------------------------------------------------------------- /GenNoise.m: -------------------------------------------------------------------------------- 1 | function [noise] = GenNoise(N,L) 2 | % Generate random Gaussian noise as a mixture model 3 | % INPUT: 4 | % - N: number of data in the dataset (row) 5 | % - L: length of the signals (column) 6 | % Method: r = a + (b-a).*rand(N,1) 7 | % to obtain random value 8 | % between the interval [a b] 9 | 10 | % Prealloc data 11 | E = zeros(1,N); % Epsilon (weight) 12 | Sigma1 = zeros(1,N); % Standard deviation of G1 13 | Sigma2 = zeros(1,N); % Standard deviation of G2 14 | noise = zeros(N,L); % output noise 15 | 16 | % Epsilon Range 17 | aE = 0.1; bE = 0.5; 18 | 19 | % As Sigma1 and Sigma2 increase, the noise amplitude increases 20 | % Standard Deviation Range for Sigma1 21 | aS1 = 0.01; bS1 = 0.03; 22 | 23 | % Generate random variables to gen. noise 24 | for i = 1:N 25 | E(i) = aE + (bE-aE).*rand(1); % Generate epsilon 26 | Sigma1(i) = aS1 + (bS1-aS1).*rand(1); % Generate Sigma1 27 | 28 | % Standard Deviation Range for Sigma2 29 | aS2 = 2*Sigma1(i); bS2 = 20*Sigma1(i); 30 | Sigma2(i) = aS2 + (bS2-aS2).*rand(1); % Generate Sigma2 31 | end 32 | 33 | % Generate noise 34 | for i = 1:N 35 | % Generate Gaussian noise with standard deviation Sigma1 36 | G1 = Sigma1(i) .* randn(L,1); 37 | % Generate Gaussian noise with standard deviation Sigma2 38 | G2 = Sigma2(i) .* randn(L,1); 39 | % Combine them according to the mixture model 40 | noise(i,:) = (1 - E(i)) * G1' + E(i) * G2'; 41 | end 42 | 43 | % Sort the noise in ascending order 44 | noise = sort(noise, 2); % Sort along each row 45 | 46 | end 47 | -------------------------------------------------------------------------------- /GenStrel.m: -------------------------------------------------------------------------------- 1 | function [strel] = GenStrel(N) 2 | % Genstrel generate a structuring element 3 | % ARGOMENT: 4 | % - N: define the length of strel. 5 | % (2*N)-1 is the dimension of the strel 6 | 7 | % Gamma control the shape of strel 8 | gamma = zeros(1,N); % Prealloc 9 | 10 | % Height parameter, alias the peak value of strel(n) 11 | h = 5; 12 | % Structuring Element 13 | strel = zeros(1,2*N-1); % Prealloc 14 | 15 | % generate random value for gamma [0.1-0.99] 16 | for i = 1:length(gamma) 17 | gamma(i) = 0.01 + (0.99-0.01).*rand(1); 18 | end 19 | 20 | % Sort the first half of the array 21 | gamma = sort(gamma); 22 | 23 | % fill the array from index 1 to N 24 | for n = 1:N 25 | strel(n) = floor(h*gamma(n)); 26 | strel(N) = h; 27 | end 28 | 29 | % fill the array from index N+1 till the end 30 | for n = N+1:2*N-1 31 | strel(n) = strel(2*N-n); 32 | end 33 | 34 | % Condition to build a correct structuring element 35 | if length(strel) == 1 36 | strel(1) = 1; 37 | end 38 | 39 | for i=1:length(strel(N)) 40 | if strel(1) > 1 41 | strel(1) = 0; 42 | strel(length(strel)) = 0; 43 | end 44 | end 45 | 46 | for i = 2:length(strel)-1 47 | if strel(i) < 1 48 | strel(i) = 1; 49 | strel(length(strel)-1) = 1; 50 | end 51 | end 52 | 53 | end 54 | 55 | % %% Gen strel with only 1 element for test 56 | % strel = zeros(1,2*N-1); % Prealloc 57 | % % Fill the array from index 1 to N 58 | % for n = 1:N 59 | % strel(n) = 1; 60 | % end 61 | % % Fill the array from index N+1 till the end 62 | % for n = N+1:2*N-1 63 | % strel(n) = strel(2*N-n); 64 | % end -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Matteo Farè 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Project_Review.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/Project_Review.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ABSTRACT # 2 | ECG signal conditioning by morphological Filtering 3 | 4 | ## MATLAB (v.R2022a) Requirements ## 5 | - **Communications Toolbox** 6 | - (**Image Processing Toolbox**, if you want to use the build-in functions like: imopen, imclose, imerode and imdilate to process the signal) 7 | 8 | ## STRUCTURE ## 9 | - **ECG_MMF.m**: main class of the project. 10 | - **GenDrift.m**, **GenNoise.m** and **GenStrel.m**: generation of structures and artifacts useful for the project. 11 | - **erosion.m**, **dilatation.m**, **closing.m** and **opening.m**: definition of the morphological processes. 12 | 13 | ## INFO ## 14 | The directory '*dataset*' contains a series of ECG signals recovered from the [physionet database](https://physionet.org/content/mitdb/1.0.0/) 15 | 16 | The functions '*erosion.m*', '*dilatation.m*', '*closing.m*' and '*opening.m*' are used to process the signals. The functions '*GenDrift.m*', '*GenStrel.m*' are used to generate respectively a baseline drift in the signal and to generate a bunch of Structuring Element to operate on signals. 17 | 18 | If you do not want to use the **Communication Toolbox** with the '*awgn*' (Add White Gaussian Noise) function, instead you can adopt the '*GenNoise*' function to generate noise. 19 | 20 | ## DOCUMENTATION ## 21 | To built this project I have used the following papers: 22 | - [ECG signal conditioning by morphological filtering](https://www.sciencedirect.com/science/article/abs/pii/S0010482502000343?via%3Dihub) 23 | - [Impulsive noise suppression and background normalization of electrocardiogram signals using morphological operators](https://www.sciencedirect.com/science/article/abs/pii/S0010482502000343?via%3Dihub) 24 | 25 | The pdf file named as *'Progect_Review'* consist in a simple presentation of the project. 26 | -------------------------------------------------------------------------------- /closing.m: -------------------------------------------------------------------------------- 1 | function [output] = closing(input,strel) 2 | % Closing operation on a 1-D signal 3 | % INPUT: 4 | % input = signal in input 5 | % strel = structuring element in input 6 | 7 | % OPENING = INPUT dilatation STREL erosion STREL 8 | output = erosion(dilatation(input,strel),strel); 9 | end -------------------------------------------------------------------------------- /dataset/100m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/100m.mat -------------------------------------------------------------------------------- /dataset/101m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/101m.mat -------------------------------------------------------------------------------- /dataset/102m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/102m.mat -------------------------------------------------------------------------------- /dataset/103m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/103m.mat -------------------------------------------------------------------------------- /dataset/104m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/104m.mat -------------------------------------------------------------------------------- /dataset/105m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/105m.mat -------------------------------------------------------------------------------- /dataset/106m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/106m.mat -------------------------------------------------------------------------------- /dataset/107m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/107m.mat -------------------------------------------------------------------------------- /dataset/108m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/108m.mat -------------------------------------------------------------------------------- /dataset/109m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/109m.mat -------------------------------------------------------------------------------- /dataset/111m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/111m.mat -------------------------------------------------------------------------------- /dataset/112m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/112m.mat -------------------------------------------------------------------------------- /dataset/113m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/113m.mat -------------------------------------------------------------------------------- /dataset/114m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/114m.mat -------------------------------------------------------------------------------- /dataset/115m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/115m.mat -------------------------------------------------------------------------------- /dataset/116m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/116m.mat -------------------------------------------------------------------------------- /dataset/117m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/117m.mat -------------------------------------------------------------------------------- /dataset/118m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/118m.mat -------------------------------------------------------------------------------- /dataset/119m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/119m.mat -------------------------------------------------------------------------------- /dataset/121m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/121m.mat -------------------------------------------------------------------------------- /dataset/122m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/122m.mat -------------------------------------------------------------------------------- /dataset/123m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/123m.mat -------------------------------------------------------------------------------- /dataset/124m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/124m.mat -------------------------------------------------------------------------------- /dataset/200m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/200m.mat -------------------------------------------------------------------------------- /dataset/201m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/201m.mat -------------------------------------------------------------------------------- /dataset/202m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/202m.mat -------------------------------------------------------------------------------- /dataset/203m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/203m.mat -------------------------------------------------------------------------------- /dataset/205m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/205m.mat -------------------------------------------------------------------------------- /dataset/207m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/207m.mat -------------------------------------------------------------------------------- /dataset/208m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/208m.mat -------------------------------------------------------------------------------- /dataset/209m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/209m.mat -------------------------------------------------------------------------------- /dataset/210m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/210m.mat -------------------------------------------------------------------------------- /dataset/212m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/212m.mat -------------------------------------------------------------------------------- /dataset/213m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/213m.mat -------------------------------------------------------------------------------- /dataset/214m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/214m.mat -------------------------------------------------------------------------------- /dataset/215m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/215m.mat -------------------------------------------------------------------------------- /dataset/217m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/217m.mat -------------------------------------------------------------------------------- /dataset/219m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/219m.mat -------------------------------------------------------------------------------- /dataset/220m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/220m.mat -------------------------------------------------------------------------------- /dataset/221m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/221m.mat -------------------------------------------------------------------------------- /dataset/222m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/222m.mat -------------------------------------------------------------------------------- /dataset/223m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/223m.mat -------------------------------------------------------------------------------- /dataset/228m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/228m.mat -------------------------------------------------------------------------------- /dataset/230m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/230m.mat -------------------------------------------------------------------------------- /dataset/231m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/231m.mat -------------------------------------------------------------------------------- /dataset/232m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/232m.mat -------------------------------------------------------------------------------- /dataset/233m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/233m.mat -------------------------------------------------------------------------------- /dataset/234m.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sabaudian/ECG_MMF_Project/926c61f6e9644eb96576de57440ed267935b1685/dataset/234m.mat -------------------------------------------------------------------------------- /dilatation.m: -------------------------------------------------------------------------------- 1 | function [output] = dilatation(input,strel) 2 | % Dilatation operation on a 1-D signal 3 | % INPUT: 4 | % insputSignal = the signal 5 | % strel = structuring element in input 6 | 7 | % Get sizes 8 | M = length(strel); 9 | N = length(input); 10 | 11 | % Strel being odd 12 | if mod(M,2) == 0 13 | error('strel lenght must be odd') 14 | end 15 | 16 | % Pad signal 17 | hw = floor(M/2); 18 | input = padarray(input,[0 hw],'replicate','both'); 19 | 20 | % Perform dilatation 21 | output = zeros(1,N); 22 | for n = (1:N)+hw % hw+1:hw+N 23 | output(n-hw) = max(input(n-hw:n+hw) + strel); 24 | end 25 | end -------------------------------------------------------------------------------- /erosion.m: -------------------------------------------------------------------------------- 1 | function [output] = erosion(input,strel) 2 | % Erosion operation on a 1-D signal 3 | % INPUT: 4 | % input = signal in input 5 | % strel = structuring element in input 6 | 7 | % Get sizes 8 | M = length(strel); 9 | N = length(input); 10 | 11 | % Strel being odd 12 | if mod(M,2) == 0 13 | error('strel lenght must be odd') 14 | end 15 | 16 | % Pad signal 17 | hw = floor(M/2); 18 | input = padarray(input,[0 hw],'replicate','both'); 19 | 20 | % Perform erosion 21 | output = zeros(1,N); 22 | for n = (1:N)+hw % hw+1:hw+N 23 | output(n-hw) = min(input(n-hw:n+hw) - strel); 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /opening.m: -------------------------------------------------------------------------------- 1 | function [output] = opening(input,strel) 2 | % Opening operation on a 1-D signal 3 | % INPUT: 4 | % input = signal in input 5 | % strel = structuring element in input 6 | 7 | % OPENING = INPUT erosion STREL dilatation STREL 8 | output =dilatation(erosion(input,strel),strel); 9 | end --------------------------------------------------------------------------------